Zephyr Project API  3.3.0
A Scalable Open Source RTOS
rtio_spsc.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8#ifndef ZEPHYR_RTIO_SPSC_H_
9#define ZEPHYR_RTIO_SPSC_H_
10
11#include <stdint.h>
12#include <stdbool.h>
13#include <zephyr/sys/atomic.h>
14
58struct rtio_spsc {
59 /* private value only the producer thread should mutate */
60 unsigned long acquire;
61
62 /* private value only the consumer thread should mutate */
63 unsigned long consume;
64
65 /* producer mutable, consumer readable */
66 atomic_t in;
67
68 /* consumer mutable, producer readable */
69 atomic_t out;
70
71 /* mask used to automatically wrap values */
72 const unsigned long mask;
73};
74
82#define RTIO_SPSC_INITIALIZER(name, type, sz) \
83 { ._spsc = { \
84 .acquire = 0, \
85 .consume = 0, \
86 .in = ATOMIC_INIT(0), \
87 .out = ATOMIC_INIT(0), \
88 .mask = sz - 1, \
89 } \
90 }
91
99#define RTIO_SPSC_DECLARE(name, type, sz) \
100 struct rtio_spsc_ ## name { \
101 struct rtio_spsc _spsc; \
102 type buffer[sz]; \
103 }
104
112#define RTIO_SPSC_DEFINE(name, type, sz) \
113 RTIO_SPSC_DECLARE(name, type, sz) name = RTIO_SPSC_INITIALIZER(name, type, sz);
114
120#define rtio_spsc_size(spsc) ((spsc)->_spsc.mask + 1)
121
129#define z_rtio_spsc_mask(spsc, i) ((i) & (spsc)->_spsc.mask)
130
139#define rtio_spsc_reset(spsc) \
140 ({ \
141 (spsc)->_spsc.consume = 0; \
142 (spsc)->_spsc.acquire = 0; \
143 atomic_set(&(spsc)->_spsc.in, 0); \
144 atomic_set(&(spsc)->_spsc.out, 0); \
145 })
146
154#define rtio_spsc_acquire(spsc) \
155 ({ \
156 unsigned long idx = atomic_get(&(spsc)->_spsc.in) + (spsc)->_spsc.acquire; \
157 bool acq = (idx - atomic_get(&(spsc)->_spsc.out)) < rtio_spsc_size(spsc); \
158 if (acq) { \
159 (spsc)->_spsc.acquire += 1; \
160 } \
161 acq ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx)]) : NULL; \
162 })
163
171#define rtio_spsc_produce(spsc) \
172 ({ \
173 if ((spsc)->_spsc.acquire > 0) { \
174 (spsc)->_spsc.acquire -= 1; \
175 atomic_add(&(spsc)->_spsc.in, 1); \
176 } \
177 })
178
187#define rtio_spsc_produce_all(spsc) \
188 ({ \
189 if ((spsc)->_spsc.acquire > 0) { \
190 unsigned long acquired = (spsc)->_spsc.acquire; \
191 (spsc)->_spsc.acquire = 0; \
192 atomic_add(&(spsc)->_spsc.in, acquired); \
193 } \
194 })
195
203#define rtio_spsc_drop_all(spsc) \
204 do { \
205 (spsc)->_spsc.acquire = 0; \
206 } while (false)
207
215#define rtio_spsc_consume(spsc) \
216 ({ \
217 unsigned long idx = atomic_get(&(spsc)->_spsc.out) + (spsc)->_spsc.consume; \
218 bool has_consumable = (idx != atomic_get(&(spsc)->_spsc.in)); \
219 if (has_consumable) { \
220 (spsc)->_spsc.consume += 1; \
221 } \
222 has_consumable ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx)]) : NULL; \
223 })
224
230#define rtio_spsc_release(spsc) \
231 ({ \
232 if ((spsc)->_spsc.consume > 0) { \
233 (spsc)->_spsc.consume -= 1; \
234 atomic_add(&(spsc)->_spsc.out, 1); \
235 } \
236 })
237
238
244#define rtio_spsc_release_all(spsc) \
245 ({ \
246 if ((spsc)->_spsc.consume > 0) { \
247 unsigned long consumed = (spsc)->_spsc.consume; \
248 (spsc)->_spsc.consume = 0; \
249 atomic_add(&(spsc)->_spsc.out, consumed); \
250 } \
251 })
252
258#define rtio_spsc_acquirable(spsc) \
259 ({ \
260 (((spsc)->_spsc.in + (spsc)->_spsc.acquire) - (spsc)->_spsc.out) - \
261 rtio_spsc_size(spsc); \
262 })
263
269#define rtio_spsc_consumable(spsc) \
270 ({ (spsc)->_spsc.in - (spsc)->_spsc.out - (spsc)->_spsc.consume; })
271
279#define rtio_spsc_peek(spsc) \
280 ({ \
281 unsigned long idx = atomic_get(&(spsc)->_spsc.out) + (spsc)->_spsc.consume; \
282 bool has_consumable = (idx != atomic_get(&(spsc)->_spsc.in)); \
283 has_consumable ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx)]) : NULL; \
284 })
285
295#define rtio_spsc_next(spsc, item) \
296 ({ \
297 unsigned long idx = ((item) - (spsc)->buffer); \
298 bool has_next = z_rtio_spsc_mask(spsc, (idx + 1)) != \
299 (z_rtio_spsc_mask(spsc, atomic_get(&(spsc)->_spsc.in))); \
300 has_next ? &((spsc)->buffer[z_rtio_spsc_mask((spsc), idx + 1)]) : NULL; \
301 })
302
311#define rtio_spsc_prev(spsc, item) \
312 ({ \
313 unsigned long idx = ((item) - &(spsc)->buffer[0]) / sizeof((spsc)->buffer[0]); \
314 bool has_prev = idx != z_rtio_spsc_mask(spsc, atomic_get(&(spsc)->_spsc.out)); \
315 has_prev ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx - 1)]) : NULL; \
316 })
317
322#endif /* ZEPHYR_RTIO_SPSC_H_ */
long atomic_t
Definition: atomic.h:22