Skip to content

Commit 9db6abb

Browse files
committed
doc: misc: Add documentation for MPSC Packet Buffer
Add documentation for Multi Producer Single Consumer Packet Buffer. Signed-off-by: Krzysztof Chruscinski <[email protected]>
1 parent ad4fc07 commit 9db6abb

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

doc/reference/data_structures/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ needed will be provided by the user.
3030

3131
slist.rst
3232
dlist.rst
33+
mpsc_pbuf.rst
3334
rbtree.rst
3435
ring_buffers.rst
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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

Comments
 (0)