LIFOs

A lifo is a kernel object that implements a traditional last in, first out (LIFO) queue, allowing threads and ISRs to add and remove data items of any size.

Concepts

Any number of lifos can be defined. Each lifo is referenced by its memory address.

A lifo has the following key properties:

  • A queue of data items that have been added but not yet removed. The queue is implemented as a simple linked list.

A lifo must be initialized before it can be used. This sets its queue to empty.

LIFO data items must be aligned on a 4-byte boundary, as the kernel reserves the first 32 bits of an item for use as a pointer to the next data item in the queue. Consequently, a data item that holds N bytes of application data requires N+4 bytes of memory. There are no alignment or reserved space requirements for data items if they are added with k_lifo_alloc_put(), instead additional memory is temporarily allocated from the calling thread’s resource pool.

A data item may be added to a lifo by a thread or an ISR. The item is given directly to a waiting thread, if one exists; otherwise the item is added to the lifo’s queue. There is no limit to the number of items that may be queued.

A data item may be removed from a lifo by a thread. If the lifo’s queue is empty a thread may choose to wait for a data item to be given. Any number of threads may wait on an empty lifo simultaneously. When a data item is added, it is given to the highest priority thread that has waited longest.

Note

The kernel does allow an ISR to remove an item from a lifo, however the ISR must not attempt to wait if the lifo is empty.

Implementation

Defining a LIFO

A lifo is defined using a variable of type struct k_lifo. It must then be initialized by calling k_lifo_init().

The following defines and initializes an empty lifo.

struct k_lifo my_lifo;

k_lifo_init(&my_lifo);

Alternatively, an empty lifo can be defined and initialized at compile time by calling K_LIFO_DEFINE.

The following code has the same effect as the code segment above.

K_LIFO_DEFINE(my_lifo);

Writing to a LIFO

A data item is added to a lifo by calling k_lifo_put().

The following code builds on the example above, and uses the lifo to send data to one or more consumer threads.

struct data_item_t {
    void *lifo_reserved;   /* 1st word reserved for use by lifo */
    ...
};

struct data_item_t tx data;

void producer_thread(int unused1, int unused2, int unused3)
{
    while (1) {
        /* create data item to send */
        tx_data = ...

        /* send data to consumers */
        k_lifo_put(&my_lifo, &tx_data);

        ...
    }
}

A data item can be added to a lifo with k_lifo_alloc_put(). With this API, there is no need to reserve space for the kernel’s use in the data item, instead additional memory will be allocated from the calling thread’s resource pool until the item is read.

Reading from a LIFO

A data item is removed from a lifo by calling k_lifo_get().

The following code builds on the example above, and uses the lifo to obtain data items from a producer thread, which are then processed in some manner.

void consumer_thread(int unused1, int unused2, int unused3)
{
    struct data_item_t  *rx_data;

    while (1) {
        rx_data = k_lifo_get(&my_lifo, K_FOREVER);

        /* process lifo data item */
        ...
    }
}

Suggested Uses

Use a lifo to asynchronously transfer data items of arbitrary size in a “last in, first out” manner.

Configuration Options

Related configuration options:

  • None.

API Reference

group lifo_apis

Defines

k_lifo_init(lifo)

Initialize a LIFO queue.

This routine initializes a LIFO queue object, prior to its first use.

Return
N/A
Parameters
  • lifo: Address of the LIFO queue.

k_lifo_put(lifo, data)

Add an element to a LIFO queue.

This routine adds a data item to lifo. A LIFO queue data item must be aligned on a 4-byte boundary, and the first 32 bits of the item are reserved for the kernel’s use.

Note
Can be called by ISRs.
Return
N/A
Parameters
  • lifo: Address of the LIFO queue.
  • data: Address of the data item.

k_lifo_alloc_put(lifo, data)

Add an element to a LIFO queue.

This routine adds a data item to lifo. There is an implicit memory allocation to create an additional temporary bookkeeping data structure from the calling thread’s resource pool, which is automatically freed when the item is removed. The data itself is not copied.

Note
Can be called by ISRs.
Parameters
  • lifo: Address of the LIFO.
  • data: Address of the data item.
Return Value
  • 0: on success
  • -ENOMEM: if there isn’t sufficient RAM in the caller’s resource pool

k_lifo_get(lifo, timeout)

Get an element from a LIFO queue.

This routine removes a data item from lifo in a “last in, first out” manner. The first 32 bits of the data item are reserved for the kernel’s use.

Note
Can be called by ISRs, but timeout must be set to K_NO_WAIT.
Return
Address of the data item if successful; NULL if returned without waiting, or waiting period timed out.
Parameters
  • lifo: Address of the LIFO queue.
  • timeout: Waiting period to obtain a data item (in milliseconds), or one of the special values K_NO_WAIT and K_FOREVER.

K_LIFO_DEFINE(name)

Statically define and initialize a LIFO queue.

The LIFO queue can be accessed outside the module where it is defined using:

extern struct k_lifo <name>; 

Parameters
  • name: Name of the fifo.