Zephyr API Documentation  3.6.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
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>
14#include <zephyr/sys/atomic.h>
16
60struct rtio_spsc {
61 /* private value only the producer thread should mutate */
62 unsigned long acquire;
63
64 /* private value only the consumer thread should mutate */
65 unsigned long consume;
66
67 /* producer mutable, consumer readable */
68 atomic_t in;
69
70 /* consumer mutable, producer readable */
71 atomic_t out;
72
73 /* mask used to automatically wrap values */
74 const unsigned long mask;
75};
76
83#define RTIO_SPSC_INITIALIZER(sz, buf) \
84 { \
85 ._spsc = { \
86 .acquire = 0, \
87 .consume = 0, \
88 .in = ATOMIC_INIT(0), \
89 .out = ATOMIC_INIT(0), \
90 .mask = sz - 1, \
91 }, \
92 .buffer = buf, \
93 }
94
101#define RTIO_SPSC_DECLARE(name, type) \
102 static struct rtio_spsc_##name { \
103 struct rtio_spsc _spsc; \
104 type * const buffer; \
105 }
106
114#define RTIO_SPSC_DEFINE(name, type, sz) \
115 BUILD_ASSERT(IS_POWER_OF_TWO(sz)); \
116 static type __spsc_buf_##name[sz]; \
117 RTIO_SPSC_DECLARE(name, type) name = RTIO_SPSC_INITIALIZER(sz, __spsc_buf_##name);
118
124#define rtio_spsc_size(spsc) ((spsc)->_spsc.mask + 1)
125
133#define z_rtio_spsc_mask(spsc, i) ((i) & (spsc)->_spsc.mask)
134
135
140#define z_rtio_spsc_in(spsc) (unsigned long)atomic_get(&(spsc)->_spsc.in)
141
146#define z_rtio_spsc_out(spsc) (unsigned long)atomic_get(&(spsc)->_spsc.out)
147
156#define rtio_spsc_reset(spsc) \
157 ({ \
158 (spsc)->_spsc.consume = 0; \
159 (spsc)->_spsc.acquire = 0; \
160 atomic_set(&(spsc)->_spsc.in, 0); \
161 atomic_set(&(spsc)->_spsc.out, 0); \
162 })
163
171#define rtio_spsc_acquire(spsc) \
172 ({ \
173 unsigned long idx = z_rtio_spsc_in(spsc) + (spsc)->_spsc.acquire; \
174 bool spsc_acq = (idx - z_rtio_spsc_out(spsc)) < rtio_spsc_size(spsc); \
175 if (spsc_acq) { \
176 (spsc)->_spsc.acquire += 1; \
177 } \
178 spsc_acq ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx)]) : NULL; \
179 })
180
188#define rtio_spsc_produce(spsc) \
189 ({ \
190 if ((spsc)->_spsc.acquire > 0) { \
191 (spsc)->_spsc.acquire -= 1; \
192 atomic_add(&(spsc)->_spsc.in, 1); \
193 } \
194 })
195
204#define rtio_spsc_produce_all(spsc) \
205 ({ \
206 if ((spsc)->_spsc.acquire > 0) { \
207 unsigned long acquired = (spsc)->_spsc.acquire; \
208 (spsc)->_spsc.acquire = 0; \
209 atomic_add(&(spsc)->_spsc.in, acquired); \
210 } \
211 })
212
220#define rtio_spsc_drop_all(spsc) \
221 do { \
222 (spsc)->_spsc.acquire = 0; \
223 } while (false)
224
232#define rtio_spsc_consume(spsc) \
233 ({ \
234 unsigned long idx = z_rtio_spsc_out(spsc) + (spsc)->_spsc.consume; \
235 bool has_consumable = (idx != z_rtio_spsc_in(spsc)); \
236 if (has_consumable) { \
237 (spsc)->_spsc.consume += 1; \
238 } \
239 has_consumable ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx)]) : NULL; \
240 })
241
247#define rtio_spsc_release(spsc) \
248 ({ \
249 if ((spsc)->_spsc.consume > 0) { \
250 (spsc)->_spsc.consume -= 1; \
251 atomic_add(&(spsc)->_spsc.out, 1); \
252 } \
253 })
254
255
261#define rtio_spsc_release_all(spsc) \
262 ({ \
263 if ((spsc)->_spsc.consume > 0) { \
264 unsigned long consumed = (spsc)->_spsc.consume; \
265 (spsc)->_spsc.consume = 0; \
266 atomic_add(&(spsc)->_spsc.out, consumed); \
267 } \
268 })
269
275#define rtio_spsc_acquirable(spsc) \
276 ({ \
277 (((spsc)->_spsc.in + (spsc)->_spsc.acquire) - (spsc)->_spsc.out) - \
278 rtio_spsc_size(spsc); \
279 })
280
286#define rtio_spsc_consumable(spsc) \
287 ({ (spsc)->_spsc.in - (spsc)->_spsc.out - (spsc)->_spsc.consume; })
288
296#define rtio_spsc_peek(spsc) \
297 ({ \
298 unsigned long idx = z_rtio_spsc_out(spsc) + (spsc)->_spsc.consume; \
299 bool has_consumable = (idx != z_rtio_spsc_in(spsc)); \
300 has_consumable ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx)]) : NULL; \
301 })
302
312#define rtio_spsc_next(spsc, item) \
313 ({ \
314 unsigned long idx = ((item) - (spsc)->buffer); \
315 bool has_next = z_rtio_spsc_mask(spsc, (idx + 1)) != \
316 (z_rtio_spsc_mask(spsc, z_rtio_spsc_in(spsc))); \
317 has_next ? &((spsc)->buffer[z_rtio_spsc_mask((spsc), idx + 1)]) : NULL; \
318 })
319
328#define rtio_spsc_prev(spsc, item) \
329 ({ \
330 unsigned long idx = ((item) - &(spsc)->buffer[0]) / sizeof((spsc)->buffer[0]); \
331 bool has_prev = idx != z_rtio_spsc_mask(spsc, z_rtio_spsc_out(spsc)); \
332 has_prev ? &((spsc)->buffer[z_rtio_spsc_mask(spsc, idx - 1)]) : NULL; \
333 })
334
339#endif /* ZEPHYR_RTIO_SPSC_H_ */
long atomic_t
Definition: atomic_types.h:15
Common toolchain abstraction.
Macro utilities.