|
| 1 | +.. _mpsc_pbuf: |
| 2 | + |
| 3 | +Multi Producer Single Consumer Packet Buffer |
| 4 | +============================================ |
| 5 | + |
| 6 | +A :dfn:`Multi Producer Single Consumer Packet Buffer (MPSC_PBUF)` is a circular |
| 7 | +buffer, whose contents are stored in first-in-first-out order. Variable size |
| 8 | +packets are stored in the buffer. Packet buffer works under assumption that there |
| 9 | +is a single context that consumes the data. However, it is possible that another |
| 10 | +context may interfere to flush the data and never come back (panic case). |
| 11 | +Packet is produced in two steps: first requested amount of data is allocated, |
| 12 | +producer fills the data and commits it. Consuming a packet is also performed in |
| 13 | +two steps: consumer claims the packet, gets pointer to it and length and later |
| 14 | +on packet is freed. This approach reduces memory copying. |
| 15 | + |
| 16 | +A :dfn:`MPSC Packet Buffer` has the following key properties: |
| 17 | + |
| 18 | +* Allocate, commit scheme used for packet producing. |
| 19 | +* Claim, free scheme used for packet consuming. |
| 20 | +* Allocator ensures that continue memory of requested length is allocated. |
| 21 | +* Following policies can be applied when requested space cannot be allocated: |
| 22 | + |
| 23 | + * **Overwrite** - oldest entries are dropped until requested amount of memory can |
| 24 | + be allocated. For each dropped packet user callback is called. |
| 25 | + * **No overwrite** - When requested amount of space cannot be allocated, |
| 26 | + allocation fails. |
| 27 | +* Dedicated, optimized API for storing short packets. |
| 28 | +* Allocation with timeout. |
| 29 | + |
| 30 | +Internals |
| 31 | +--------- |
| 32 | + |
| 33 | +Each packet in the buffer contains ``MPSC_PBUF`` specific header which is used |
| 34 | +for internal management. Header consists of 2 bit flags. In order to optimize |
| 35 | +memory usage, header can be added on top of the user header using |
| 36 | +:c:macro:`MPSC_PBUF_HDR` and remaining bits in the first word can be application |
| 37 | +specific. Header consists of following flags: |
| 38 | + |
| 39 | +* valid - bit set to one when packet contains valid user packet |
| 40 | +* busy - bit set when packet is being consumed (claimed but not free) |
| 41 | + |
| 42 | +Header state: |
| 43 | + |
| 44 | ++-------+------+----------------------+ |
| 45 | +| valid | busy | description | |
| 46 | ++-------+------+----------------------+ |
| 47 | +| 0 | 0 | space is free | |
| 48 | ++-------+------+----------------------+ |
| 49 | +| 1 | 0 | valid packet | |
| 50 | ++-------+------+----------------------+ |
| 51 | +| 1 | 1 | claimed valid packet | |
| 52 | ++-------+------+----------------------+ |
| 53 | +| 0 | 1 | internal skip packet | |
| 54 | ++-------+------+----------------------+ |
| 55 | + |
| 56 | +Packet buffer space contains free space, valid user packets and internal skip |
| 57 | +packets. Internal skip packets indicates padding, e.g. at the of the buffer. |
| 58 | + |
| 59 | +Allocation |
| 60 | +^^^^^^^^^^ |
| 61 | + |
| 62 | +Using pairs for read and write indexes, available space is determined. If |
| 63 | +space can be allocated, temporary write index is moved and pointer to a space |
| 64 | +witing buffer is returned. Packet header is reset. If allocation required |
| 65 | +wrapping of the write index, a skip packet is added to the end of buffer. If |
| 66 | +space cannot be allocated and overwrite is disabled then ``NULL`` pointer is |
| 67 | +returned or context blocks if allocation was with timeout. |
| 68 | + |
| 69 | +Allocation with overwrite |
| 70 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 71 | + |
| 72 | +If overwrite is enabled, oldest packets are dropped until requested amount of |
| 73 | +space can be allocated. When packets are dropped ``busy`` flag is checked in the |
| 74 | +header to ensure that currently consumed packet is not overwritten. In that case, |
| 75 | +skip packet is added before busy packet and packets following the busy packet |
| 76 | +are dropped. When busy packet is being freed, such situation is detected and |
| 77 | +packet is converted to skip packet to avoid double processing. |
| 78 | + |
| 79 | +Usage |
| 80 | +----- |
| 81 | + |
| 82 | +Packet header definition |
| 83 | +^^^^^^^^^^^^^^^^^^^^^^^^ |
| 84 | + |
| 85 | +Packet header details can be found in :zephyr_file:`include/sys/mpsc_packet.h`. |
| 86 | +API functions can be found in :zephyr_file:`include/sys/mpsc_pbuf.h`. Headers |
| 87 | +are split to avoid include spam when declaring the packet. |
| 88 | + |
| 89 | +User header structure must start with internal header: |
| 90 | + |
| 91 | +.. code-block:: c |
| 92 | +
|
| 93 | + #include <sys/mpsc_packet.h> |
| 94 | +
|
| 95 | + struct foo_header { |
| 96 | + MPSC_PBUF_HDR; |
| 97 | + uint32_t length: 32 - MPSC_PBUF_HDR_BITS; |
| 98 | + }; |
| 99 | +
|
| 100 | +Packet buffer configuration |
| 101 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 102 | + |
| 103 | +Configuration structure contains buffer details, configuration flags and |
| 104 | +callbacks. Following callbacks are used by the packet buffer: |
| 105 | + |
| 106 | +* Drop notification - callback called whenever a packet is dropped due to |
| 107 | + overwrite. |
| 108 | +* Get packet length - callback to determine packet length |
| 109 | + |
| 110 | +Packet producing |
| 111 | +^^^^^^^^^^^^^^^^ |
| 112 | + |
| 113 | +Standard, two step method: |
| 114 | + |
| 115 | +.. code-block:: c |
| 116 | +
|
| 117 | + foo_packet *packet = mpsc_pbuf_alloc(buffer, len, K_NO_WAIT); |
| 118 | +
|
| 119 | + fill_data(packet); |
| 120 | +
|
| 121 | + mpsc_pbuf_commit(buffer, packet); |
| 122 | +
|
| 123 | +Performance optimized storing of small packets: |
| 124 | + |
| 125 | +* 32 bit word packet |
| 126 | +* 32 bit word with pointer packet |
| 127 | + |
| 128 | +Note that since packets are written by value, they should already contain |
| 129 | +``valid`` bit set in the header. |
| 130 | + |
| 131 | +.. code-block:: c |
| 132 | +
|
| 133 | + mpsc_pbuf_put_word(buffer, data); |
| 134 | + mpsc_pbuf_put_word_ext(buffer, data, ptr); |
| 135 | +
|
| 136 | +Packet consuming |
| 137 | +^^^^^^^^^^^^^^^^ |
| 138 | + |
| 139 | +Two step method: |
| 140 | + |
| 141 | +.. code-block:: c |
| 142 | +
|
| 143 | + foo_packet *packet = mpsc_pbuf_claim(buffer); |
| 144 | +
|
| 145 | + process(packet); |
| 146 | +
|
| 147 | + mpsc_pbuf_free(buffer, packet); |
0 commit comments