| .. _lifos_v2: |
| |
| LIFOs |
| ##### |
| |
| A :dfn:`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. |
| |
| .. contents:: |
| :local: |
| :depth: 2 |
| |
| Concepts |
| ******** |
| |
| Any number of LIFOs can be defined (limited only by available RAM). 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 word boundary, as the kernel reserves |
| the first word 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 (or N+8) bytes of memory. There are no alignment or reserved |
| space requirements for data items if they are added with |
| :c:func:`k_lifo_alloc_put`, instead additional memory is temporarily |
| allocated from the calling thread's resource pool. |
| |
| .. note:: |
| LIFO data items are restricted to single active instance across all LIFO |
| data queues. Any attempt to re-add a LIFO data item to a queue before |
| it has been removed from the queue to which it was previously added will |
| result in undefined behavior. |
| |
| 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 :c:struct:`k_lifo`. |
| It must then be initialized by calling :c:func:`k_lifo_init`. |
| |
| The following defines and initializes an empty LIFO. |
| |
| .. code-block:: c |
| |
| struct k_lifo my_lifo; |
| |
| k_lifo_init(&my_lifo); |
| |
| Alternatively, an empty LIFO can be defined and initialized at compile time |
| by calling :c:macro:`K_LIFO_DEFINE`. |
| |
| The following code has the same effect as the code segment above. |
| |
| .. code-block:: c |
| |
| K_LIFO_DEFINE(my_lifo); |
| |
| Writing to a LIFO |
| ================= |
| |
| A data item is added to a LIFO by calling :c:func:`k_lifo_put`. |
| |
| The following code builds on the example above, and uses the LIFO |
| to send data to one or more consumer threads. |
| |
| .. code-block:: c |
| |
| 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 :c:func:`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 :c:func:`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. |
| |
| .. code-block:: c |
| |
| 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 |
| ************* |
| |
| .. doxygengroup:: lifo_apis |