FIFOs¶
A FIFO is a kernel object that implements a traditional first in, first out (FIFO) queue, allowing threads and ISRs to add and remove data items of any size.
Concepts¶
Any number of FIFOs can be defined (limited only by available RAM). Each FIFO is referenced by its memory address.
A FIFO 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 FIFO must be initialized before it can be used. This sets its queue to empty.
FIFO 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
k_fifo_alloc_put()
, instead additional memory is temporarily
allocated from the calling thread’s resource pool.
A data item may be added to a FIFO 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 FIFO’s queue. There is no limit to the number of items that may be queued.
A data item may be removed from a FIFO by a thread. If the FIFO’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 FIFO 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 FIFO, however the ISR must not attempt to wait if the FIFO is empty.
If desired, multiple data items can be added to a FIFO in a single operation if they are chained together into a singly-linked list. This capability can be useful if multiple writers are adding sets of related data items to the FIFO, as it ensures the data items in each set are not interleaved with other data items. Adding multiple data items to a FIFO is also more efficient than adding them one at a time, and can be used to guarantee that anyone who removes the first data item in a set will be able to remove the remaining data items without waiting.
Implementation¶
Defining a FIFO¶
A FIFO is defined using a variable of type k_fifo
.
It must then be initialized by calling k_fifo_init()
.
The following code defines and initializes an empty FIFO.
struct k_fifo my_fifo;
k_fifo_init(&my_fifo);
Alternatively, an empty FIFO can be defined and initialized at compile time
by calling K_FIFO_DEFINE
.
The following code has the same effect as the code segment above.
K_FIFO_DEFINE(my_fifo);
Writing to a FIFO¶
A data item is added to a FIFO by calling k_fifo_put()
.
The following code builds on the example above, and uses the FIFO to send data to one or more consumer threads.
struct data_item_t {
void *fifo_reserved; /* 1st word reserved for use by FIFO */
...
};
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_fifo_put(&my_fifo, &tx_data);
...
}
}
Additionally, a singly-linked list of data items can be added to a FIFO
by calling k_fifo_put_list()
or k_fifo_put_slist()
.
Finally, a data item can be added to a FIFO with k_fifo_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 FIFO¶
A data item is removed from a FIFO by calling k_fifo_get()
.
The following code builds on the example above, and uses the FIFO 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_fifo_get(&my_fifo, K_FOREVER);
/* process FIFO data item */
...
}
}
Suggested Uses¶
Use a FIFO to asynchronously transfer data items of arbitrary size in a “first in, first out” manner.
API Reference¶
-
group
fifo_apis
Defines
-
k_fifo_init
(fifo)¶ Initialize a FIFO queue.
This routine initializes a FIFO queue, prior to its first use.
- Return
N/A
- Parameters
fifo
: Address of the FIFO queue.
-
k_fifo_cancel_wait
(fifo)¶ Cancel waiting on a FIFO queue.
This routine causes first thread pending on fifo, if any, to return from k_fifo_get() call with NULL value (as if timeout expired).
- Note
Can be called by ISRs.
- Return
N/A
- Parameters
fifo
: Address of the FIFO queue.
-
k_fifo_put
(fifo, data)¶ Add an element to a FIFO queue.
This routine adds a data item to fifo. A FIFO data item must be aligned on a word boundary, and the first word of the item is reserved for the kernel’s use.
- Note
Can be called by ISRs.
- Return
N/A
- Parameters
fifo
: Address of the FIFO.data
: Address of the data item.
-
k_fifo_alloc_put
(fifo, data)¶ Add an element to a FIFO queue.
This routine adds a data item to fifo. 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
fifo
: Address of the FIFO.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_fifo_put_list
(fifo, head, tail)¶ Atomically add a list of elements to a FIFO.
This routine adds a list of data items to fifo in one operation. The data items must be in a singly-linked list, with the first word of each data item pointing to the next data item; the list must be NULL-terminated.
- Note
Can be called by ISRs.
- Return
N/A
- Parameters
fifo
: Address of the FIFO queue.head
: Pointer to first node in singly-linked list.tail
: Pointer to last node in singly-linked list.
-
k_fifo_put_slist
(fifo, list)¶ Atomically add a list of elements to a FIFO queue.
This routine adds a list of data items to fifo in one operation. The data items must be in a singly-linked list implemented using a sys_slist_t object. Upon completion, the sys_slist_t object is invalid and must be re-initialized via sys_slist_init().
- Note
Can be called by ISRs.
- Return
N/A
- Parameters
fifo
: Address of the FIFO queue.list
: Pointer to sys_slist_t object.
-
k_fifo_get
(fifo, timeout)¶ Get an element from a FIFO queue.
This routine removes a data item from fifo in a “first in, first out” manner. The first word of the data item is 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
fifo
: Address of the FIFO queue.timeout
: Waiting period to obtain a data item, or one of the special values K_NO_WAIT and K_FOREVER.
-
k_fifo_is_empty
(fifo)¶ Query a FIFO queue to see if it has data available.
Note that the data might be already gone by the time this function returns if other threads is also trying to read from the FIFO.
- Note
Can be called by ISRs.
- Return
Non-zero if the FIFO queue is empty.
- Return
0 if data is available.
- Parameters
fifo
: Address of the FIFO queue.
-
k_fifo_peek_head
(fifo)¶ Peek element at the head of a FIFO queue.
Return element from the head of FIFO queue without removing it. A usecase for this is if elements of the FIFO object are themselves containers. Then on each iteration of processing, a head container will be peeked, and some data processed out of it, and only if the container is empty, it will be completely remove from the FIFO queue.
- Return
Head element, or NULL if the FIFO queue is empty.
- Parameters
fifo
: Address of the FIFO queue.
-
k_fifo_peek_tail
(fifo)¶ Peek element at the tail of FIFO queue.
Return element from the tail of FIFO queue (without removing it). A usecase for this is if elements of the FIFO queue are themselves containers. Then it may be useful to add more data to the last container in a FIFO queue.
- Return
Tail element, or NULL if a FIFO queue is empty.
- Parameters
fifo
: Address of the FIFO queue.
-
K_FIFO_DEFINE
(name)¶ Statically define and initialize a FIFO queue.
The FIFO queue can be accessed outside the module where it is defined using:
extern struct k_fifo <name>;
- Parameters
name
: Name of the FIFO queue.
-