|  | .. _mpsc_pbuf: | 
|  |  | 
|  | Multi Producer Single Consumer Packet Buffer | 
|  | ============================================ | 
|  |  | 
|  | A :dfn:`Multi Producer Single Consumer Packet Buffer (MPSC_PBUF)` is a circular | 
|  | buffer, whose contents are stored in first-in-first-out order. Variable size | 
|  | packets are stored in the buffer. Packet buffer works under assumption that there | 
|  | is a single context that consumes the data. However, it is possible that another | 
|  | context may interfere to flush the data and never come back (panic case). | 
|  | Packet is produced in two steps: first requested amount of data is allocated, | 
|  | producer fills the data and commits it. Consuming a packet is also performed in | 
|  | two steps: consumer claims the packet, gets pointer to it and length and later | 
|  | on packet is freed. This approach reduces memory copying. | 
|  |  | 
|  | A :dfn:`MPSC Packet Buffer` has the following key properties: | 
|  |  | 
|  | * Allocate, commit scheme used for packet producing. | 
|  | * Claim, free scheme used for packet consuming. | 
|  | * Allocator ensures that contiguous memory of requested length is allocated. | 
|  | * Following policies can be applied when requested space cannot be allocated: | 
|  |  | 
|  | * **Overwrite** - oldest entries are dropped until requested amount of memory can | 
|  | be allocated. For each dropped packet user callback is called. | 
|  | * **No overwrite** - When requested amount of space cannot be allocated, | 
|  | allocation fails. | 
|  | * Dedicated, optimized API for storing short packets. | 
|  | * Allocation with timeout. | 
|  |  | 
|  | Internals | 
|  | --------- | 
|  |  | 
|  | Each packet in the buffer contains ``MPSC_PBUF`` specific header which is used | 
|  | for internal management. Header consists of 2 bit flags. In order to optimize | 
|  | memory usage, header can be added on top of the user header using | 
|  | :c:macro:`MPSC_PBUF_HDR` and remaining bits in the first word can be application | 
|  | specific. Header consists of following flags: | 
|  |  | 
|  | * valid - bit set to one when packet contains valid user packet | 
|  | * busy - bit set when packet is being consumed (claimed but not free) | 
|  |  | 
|  | Header state: | 
|  |  | 
|  | +-------+------+----------------------+ | 
|  | | valid | busy | description          | | 
|  | +-------+------+----------------------+ | 
|  | | 0     | 0    | space is free        | | 
|  | +-------+------+----------------------+ | 
|  | | 1     | 0    | valid packet         | | 
|  | +-------+------+----------------------+ | 
|  | | 1     | 1    | claimed valid packet | | 
|  | +-------+------+----------------------+ | 
|  | | 0     | 1    | internal skip packet | | 
|  | +-------+------+----------------------+ | 
|  |  | 
|  | Packet buffer space contains free space, valid user packets and internal skip | 
|  | packets. Internal skip packets indicates padding, e.g. at the end of the buffer. | 
|  |  | 
|  | Allocation | 
|  | ^^^^^^^^^^ | 
|  |  | 
|  | Using pairs for read and write indexes, available space is determined. If | 
|  | space can be allocated, temporary write index is moved and pointer to a space | 
|  | within buffer is returned. Packet header is reset. If allocation required | 
|  | wrapping of the write index, a skip packet is added to the end of buffer. If | 
|  | space cannot be allocated and overwrite is disabled then ``NULL`` pointer is | 
|  | returned or context blocks if allocation was with timeout. | 
|  |  | 
|  | Allocation with overwrite | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | If overwrite is enabled, oldest packets are dropped until requested amount of | 
|  | space can be allocated. When packets are dropped ``busy`` flag is checked in the | 
|  | header to ensure that currently consumed packet is not overwritten. In that case, | 
|  | skip packet is added before busy packet and packets following the busy packet | 
|  | are dropped. When busy packet is being freed, such situation is detected and | 
|  | packet is converted to skip packet to avoid double processing. | 
|  |  | 
|  | Usage | 
|  | ----- | 
|  |  | 
|  | Packet header definition | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | Packet header details can be found in :zephyr_file:`include/zephyr/sys/mpsc_packet.h`. | 
|  | API functions can be found in :zephyr_file:`include/zephyr/sys/mpsc_pbuf.h`. Headers | 
|  | are split to avoid include spam when declaring the packet. | 
|  |  | 
|  | User header structure must start with internal header: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | #include <zephyr/sys/mpsc_packet.h> | 
|  |  | 
|  | struct foo_header { | 
|  | MPSC_PBUF_HDR; | 
|  | uint32_t length: 32 - MPSC_PBUF_HDR_BITS; | 
|  | }; | 
|  |  | 
|  | Packet buffer configuration | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | Configuration structure contains buffer details, configuration flags and | 
|  | callbacks. Following callbacks are used by the packet buffer: | 
|  |  | 
|  | * Drop notification - callback called whenever a packet is dropped due to | 
|  | overwrite. | 
|  | * Get packet length - callback to determine packet length | 
|  |  | 
|  | Packet producing | 
|  | ^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | Standard, two step method: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | foo_packet *packet = mpsc_pbuf_alloc(buffer, len, K_NO_WAIT); | 
|  |  | 
|  | fill_data(packet); | 
|  |  | 
|  | mpsc_pbuf_commit(buffer, packet); | 
|  |  | 
|  | Performance optimized storing of small packets: | 
|  |  | 
|  | * 32 bit word packet | 
|  | * 32 bit word with pointer packet | 
|  |  | 
|  | Note that since packets are written by value, they should already contain | 
|  | ``valid`` bit set in the header. | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | mpsc_pbuf_put_word(buffer, data); | 
|  | mpsc_pbuf_put_word_ext(buffer, data, ptr); | 
|  |  | 
|  | Packet consuming | 
|  | ^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | Two step method: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | foo_packet *packet = mpsc_pbuf_claim(buffer); | 
|  |  | 
|  | process(packet); | 
|  |  | 
|  | mpsc_pbuf_free(buffer, packet); |