-
Notifications
You must be signed in to change notification settings - Fork 577
/
mpsc_pbuf.h
275 lines (234 loc) · 7.23 KB
/
mpsc_pbuf.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_
#define ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_
#include <zephyr/kernel.h>
#include <zephyr/sys/mpsc_packet.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Multi producer, single consumer packet buffer API
* @defgroup mpsc_buf MPSC (Multi producer, single consumer) packet buffer API
* @ingroup kernel_apis
* @{
*/
/*
* Multi producer, single consumer packet buffer allows to allocate variable
* length consecutive space for storing a packet. When space is allocated
* it can be filled by the user (except for the first 2 bits) and when packet
* is ready it is committed. It is allowed to allocate another packet before
* committing the previous one.
*
* If buffer is full and packet cannot be allocated then null is returned unless
* overwrite mode is selected. In that mode, oldest entry are dropped (user is
* notified) until allocation succeeds. It can happen that candidate for
* dropping is currently being claimed. In that case, it is omitted and next
* packet is dropped and claimed packet is marked as invalid when freeing.
*
* Reading packets is performed in two steps. First packet is claimed. Claiming
* returns pointer to the packet within the buffer. Packet is freed when no
* longer in use.
*/
/**@defgroup MPSC_PBUF_FLAGS MPSC packet buffer flags
* @{
*/
/** @brief Flag indicating that buffer size is power of 2.
*
* When buffer size is power of 2 then optimizations are applied.
*/
#define MPSC_PBUF_SIZE_POW2 BIT(0)
/** @brief Flag indicating buffer full policy.
*
* If flag is set then when allocating from a full buffer oldest packets are
* dropped. When flag is not set then allocation returns null.
*/
#define MPSC_PBUF_MODE_OVERWRITE BIT(1)
/** @brief Flag indicating that maximum buffer usage is tracked. */
#define MPSC_PBUF_MAX_UTILIZATION BIT(2)
/**@} */
/* Forward declaration */
struct mpsc_pbuf_buffer;
/** @brief Callback prototype for getting length of a packet.
*
* @param packet User packet.
*
* @return Size of the packet in 32 bit words.
*/
typedef uint32_t (*mpsc_pbuf_get_wlen)(const union mpsc_pbuf_generic *packet);
/** @brief Callback called when packet is dropped.
*
* @param buffer Packet buffer.
*
* @param packet Packet that is being dropped.
*/
typedef void (*mpsc_pbuf_notify_drop)(const struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic *packet);
/** @brief MPSC packet buffer structure. */
struct mpsc_pbuf_buffer {
/** Temporary write index. */
uint32_t tmp_wr_idx;
/** Write index. */
uint32_t wr_idx;
/** Temporary read index. */
uint32_t tmp_rd_idx;
/** Read index. */
uint32_t rd_idx;
/** Flags. */
uint32_t flags;
/** Lock. */
struct k_spinlock lock;
/** User callback called whenever packet is dropped.
*
* May be NULL if unneeded.
*/
mpsc_pbuf_notify_drop notify_drop;
/** Callback for getting packet length. */
mpsc_pbuf_get_wlen get_wlen;
/* Buffer. */
uint32_t *buf;
/* Buffer size in 32 bit words. */
uint32_t size;
/* Store max buffer usage. */
uint32_t max_usage;
struct k_sem sem;
};
/** @brief MPSC packet buffer configuration. */
struct mpsc_pbuf_buffer_config {
/* Pointer to a memory used for storing packets. */
uint32_t *buf;
/* Buffer size in 32 bit words. */
uint32_t size;
/* Callbacks. */
mpsc_pbuf_notify_drop notify_drop;
mpsc_pbuf_get_wlen get_wlen;
/* Configuration flags. */
uint32_t flags;
};
/** @brief Initialize a packet buffer.
*
* @param buffer Buffer.
*
* @param config Configuration.
*/
void mpsc_pbuf_init(struct mpsc_pbuf_buffer *buffer,
const struct mpsc_pbuf_buffer_config *config);
/** @brief Allocate a packet.
*
* If a buffer is configured to overwrite mode then if there is no space to
* allocate a new buffer, oldest packets are dropped. Otherwise allocation
* fails and null pointer is returned.
*
* @param buffer Buffer.
*
* @param wlen Number of words to allocate.
*
* @param timeout Timeout. If called from thread context it will pend for given
* timeout if packet cannot be allocated before dropping the oldest or
* returning null.
*
* @return Pointer to the allocated space or null if it cannot be allocated.
*/
union mpsc_pbuf_generic *mpsc_pbuf_alloc(struct mpsc_pbuf_buffer *buffer,
size_t wlen, k_timeout_t timeout);
/** @brief Commit a packet.
*
* @param buffer Buffer.
*
* @param packet Pointer to a packet allocated by @ref mpsc_pbuf_alloc.
*/
void mpsc_pbuf_commit(struct mpsc_pbuf_buffer *buffer,
union mpsc_pbuf_generic *packet);
/** @brief Put single word packet into a buffer.
*
* Function is optimized for storing a packet which fit into a single word.
* Note that 2 bits of that word is used by the buffer.
*
* @param buffer Buffer.
*
* @param word Packet content consisting of MPSC_PBUF_HDR with valid bit set
* and data on remaining bits.
*/
void mpsc_pbuf_put_word(struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic word);
/** @brief Put a packet consisting of a word and a pointer.
* *
* Function is optimized for storing packet consisting of a word and a pointer.
* Note that 2 bits of a first word is used by the buffer.
*
* @param buffer Buffer.
*
* @param word First word of a packet consisting of MPSC_PBUF_HDR with valid
* bit set and data on remaining bits.
*
* @param data User data.
*/
void mpsc_pbuf_put_word_ext(struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic word,
const void *data);
/** @brief Put a packet into a buffer.
*
* Copy data into a buffer.
* Note that 2 bits of a first word is used by the buffer.
*
* @param buffer Buffer.
*
* @param data First word of data must contain MPSC_PBUF_HDR with valid bit set.
*
* @param wlen Packet size in words.
*/
void mpsc_pbuf_put_data(struct mpsc_pbuf_buffer *buffer,
const uint32_t *data, size_t wlen);
/** @brief Claim the first pending packet.
*
* @param buffer Buffer.
*
* @return Pointer to the claimed packet or null if none available.
*/
const union mpsc_pbuf_generic *mpsc_pbuf_claim(struct mpsc_pbuf_buffer *buffer);
/** @brief Free a packet.
*
* @param buffer Buffer.
*
* @param packet Packet.
*/
void mpsc_pbuf_free(struct mpsc_pbuf_buffer *buffer,
const union mpsc_pbuf_generic *packet);
/** @brief Check if there are any message pending.
*
* @param buffer Buffer.
*
* @retval true if pending.
* @retval false if no message is pending.
*/
bool mpsc_pbuf_is_pending(struct mpsc_pbuf_buffer *buffer);
/** @brief Get current memory utilization.
*
* @param[in, out] buffer Buffer.
* @param[out] size Buffer size in bytes.
* @param[out] now Current buffer usage in bytes.
*/
void mpsc_pbuf_get_utilization(struct mpsc_pbuf_buffer *buffer,
uint32_t *size, uint32_t *now);
/** @brief Get maximum memory utilization.
*
* @param[in, out] buffer Buffer.
* @param[out] max Maximum buffer usage in bytes.
*
* retval 0 if utilization data collected successfully.
* retval -ENOTSUP if Collecting utilization data is not supported.
*/
int mpsc_pbuf_get_max_utilization(struct mpsc_pbuf_buffer *buffer, uint32_t *max);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_SYS_MPSC_PBUF_H_ */