1.. _mpsc_pbuf:
2
3Multi Producer Single Consumer Packet Buffer
4============================================
5
6A :dfn:`Multi Producer Single Consumer Packet Buffer (MPSC_PBUF)` is a circular
7buffer, whose contents are stored in first-in-first-out order. Variable size
8packets are stored in the buffer. Packet buffer works under assumption that there
9is a single context that consumes the data. However, it is possible that another
10context may interfere to flush the data and never come back (panic case).
11Packet is produced in two steps: first requested amount of data is allocated,
12producer fills the data and commits it. Consuming a packet is also performed in
13two steps: consumer claims the packet, gets pointer to it and length and later
14on packet is freed. This approach reduces memory copying.
15
16A :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 contiguous 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
30Internals
31---------
32
33Each packet in the buffer contains ``MPSC_PBUF`` specific header which is used
34for internal management. Header consists of 2 bit flags. In order to optimize
35memory 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
37specific. 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
42Header 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
56Packet buffer space contains free space, valid user packets and internal skip
57packets. Internal skip packets indicates padding, e.g. at the of the buffer.
58
59Allocation
60^^^^^^^^^^
61
62Using pairs for read and write indexes, available space is determined. If
63space can be allocated, temporary write index is moved and pointer to a space
64within buffer is returned. Packet header is reset. If allocation required
65wrapping of the write index, a skip packet is added to the end of buffer. If
66space cannot be allocated and overwrite is disabled then ``NULL`` pointer is
67returned or context blocks if allocation was with timeout.
68
69Allocation with overwrite
70^^^^^^^^^^^^^^^^^^^^^^^^^
71
72If overwrite is enabled, oldest packets are dropped until requested amount of
73space can be allocated. When packets are dropped ``busy`` flag is checked in the
74header to ensure that currently consumed packet is not overwritten. In that case,
75skip packet is added before busy packet and packets following the busy packet
76are dropped. When busy packet is being freed, such situation is detected and
77packet is converted to skip packet to avoid double processing.
78
79Usage
80-----
81
82Packet header definition
83^^^^^^^^^^^^^^^^^^^^^^^^
84
85Packet header details can be found in :zephyr_file:`include/zephyr/sys/mpsc_packet.h`.
86API functions can be found in :zephyr_file:`include/zephyr/sys/mpsc_pbuf.h`. Headers
87are split to avoid include spam when declaring the packet.
88
89User header structure must start with internal header:
90
91.. code-block:: c
92
93   #include <zephyr/sys/mpsc_packet.h>
94
95   struct foo_header {
96           MPSC_PBUF_HDR;
97           uint32_t length: 32 - MPSC_PBUF_HDR_BITS;
98   };
99
100Packet buffer configuration
101^^^^^^^^^^^^^^^^^^^^^^^^^^^
102
103Configuration structure contains buffer details, configuration flags and
104callbacks. 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
110Packet producing
111^^^^^^^^^^^^^^^^
112
113Standard, 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
123Performance optimized storing of small packets:
124
125* 32 bit word packet
126* 32 bit word with pointer packet
127
128Note 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
136Packet consuming
137^^^^^^^^^^^^^^^^
138
139Two 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);
148