Zephyr API Documentation
3.7.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
spsc_lockfree.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2023 Intel Corporation
3
*
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
#ifndef ZEPHYR_SYS_SPSC_LOCKFREE_H_
8
#define ZEPHYR_SYS_SPSC_LOCKFREE_H_
9
10
#include <
stdint.h
>
11
#include <
stdbool.h
>
12
#include <
zephyr/toolchain/common.h
>
13
#include <
zephyr/sys/atomic.h
>
14
#include <
zephyr/sys/util_macro.h
>
15
59
struct
spsc {
60
/* private value only the producer thread should mutate */
61
unsigned
long
acquire;
62
63
/* private value only the consumer thread should mutate */
64
unsigned
long
consume;
65
66
/* producer mutable, consumer readable */
67
atomic_t
in;
68
69
/* consumer mutable, producer readable */
70
atomic_t
out;
71
72
/* mask used to automatically wrap values */
73
const
unsigned
long
mask;
74
};
75
82
#define SPSC_INITIALIZER(sz, buf) \
83
{ \
84
._spsc = \
85
{ \
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 SPSC_DECLARE(name, type) \
102
static struct spsc_##name { \
103
struct spsc _spsc; \
104
type * const buffer; \
105
}
106
114
#define SPSC_DEFINE(name, type, sz) \
115
BUILD_ASSERT(IS_POWER_OF_TWO(sz)); \
116
static type __spsc_buf_##name[sz]; \
117
SPSC_DECLARE(name, type) name = SPSC_INITIALIZER(sz, __spsc_buf_##name);
118
124
#define spsc_size(spsc) ((spsc)->_spsc.mask + 1)
125
133
#define z_spsc_mask(spsc, i) ((i) & (spsc)->_spsc.mask)
134
139
#define z_spsc_in(spsc) (unsigned long)atomic_get(&(spsc)->_spsc.in)
140
145
#define z_spsc_out(spsc) (unsigned long)atomic_get(&(spsc)->_spsc.out)
146
155
#define spsc_reset(spsc) \
156
({ \
157
(spsc)->_spsc.consume = 0; \
158
(spsc)->_spsc.acquire = 0; \
159
atomic_set(&(spsc)->_spsc.in, 0); \
160
atomic_set(&(spsc)->_spsc.out, 0); \
161
})
162
170
#define spsc_acquire(spsc) \
171
({ \
172
unsigned long idx = z_spsc_in(spsc) + (spsc)->_spsc.acquire; \
173
bool spsc_acq = (idx - z_spsc_out(spsc)) < spsc_size(spsc); \
174
if (spsc_acq) { \
175
(spsc)->_spsc.acquire += 1; \
176
} \
177
spsc_acq ? &((spsc)->buffer[z_spsc_mask(spsc, idx)]) : NULL; \
178
})
179
187
#define spsc_produce(spsc) \
188
({ \
189
if ((spsc)->_spsc.acquire > 0) { \
190
(spsc)->_spsc.acquire -= 1; \
191
atomic_add(&(spsc)->_spsc.in, 1); \
192
} \
193
})
194
203
#define spsc_produce_all(spsc) \
204
({ \
205
if ((spsc)->_spsc.acquire > 0) { \
206
unsigned long acquired = (spsc)->_spsc.acquire; \
207
(spsc)->_spsc.acquire = 0; \
208
atomic_add(&(spsc)->_spsc.in, acquired); \
209
} \
210
})
211
219
#define spsc_drop_all(spsc) \
220
do { \
221
(spsc)->_spsc.acquire = 0; \
222
} while (false)
223
231
#define spsc_consume(spsc) \
232
({ \
233
unsigned long idx = z_spsc_out(spsc) + (spsc)->_spsc.consume; \
234
bool has_consumable = (idx != z_spsc_in(spsc)); \
235
if (has_consumable) { \
236
(spsc)->_spsc.consume += 1; \
237
} \
238
has_consumable ? &((spsc)->buffer[z_spsc_mask(spsc, idx)]) : NULL; \
239
})
240
246
#define spsc_release(spsc) \
247
({ \
248
if ((spsc)->_spsc.consume > 0) { \
249
(spsc)->_spsc.consume -= 1; \
250
atomic_add(&(spsc)->_spsc.out, 1); \
251
} \
252
})
253
259
#define spsc_release_all(spsc) \
260
({ \
261
if ((spsc)->_spsc.consume > 0) { \
262
unsigned long consumed = (spsc)->_spsc.consume; \
263
(spsc)->_spsc.consume = 0; \
264
atomic_add(&(spsc)->_spsc.out, consumed); \
265
} \
266
})
267
273
#define spsc_acquirable(spsc) \
274
({ (((spsc)->_spsc.in + (spsc)->_spsc.acquire) - (spsc)->_spsc.out) - spsc_size(spsc); })
275
281
#define spsc_consumable(spsc) ({ (spsc)->_spsc.in - (spsc)->_spsc.out - (spsc)->_spsc.consume; })
282
290
#define spsc_peek(spsc) \
291
({ \
292
unsigned long idx = z_spsc_out(spsc) + (spsc)->_spsc.consume; \
293
bool has_consumable = (idx != z_spsc_in(spsc)); \
294
has_consumable ? &((spsc)->buffer[z_spsc_mask(spsc, idx)]) : NULL; \
295
})
296
306
#define spsc_next(spsc, item) \
307
({ \
308
unsigned long idx = ((item) - (spsc)->buffer); \
309
bool has_next = \
310
z_spsc_mask(spsc, (idx + 1)) != (z_spsc_mask(spsc, z_spsc_in(spsc))); \
311
has_next ? &((spsc)->buffer[z_spsc_mask((spsc), idx + 1)]) : NULL; \
312
})
313
322
#define spsc_prev(spsc, item) \
323
({ \
324
unsigned long idx = ((item) - &(spsc)->buffer[0]) / sizeof((spsc)->buffer[0]); \
325
bool has_prev = idx != z_spsc_mask(spsc, z_spsc_out(spsc)); \
326
has_prev ? &((spsc)->buffer[z_spsc_mask(spsc, idx - 1)]) : NULL; \
327
})
328
333
#endif
/* ZEPHYR_SYS_SPSC_LOCKFREE_H_ */
atomic_t
long atomic_t
Definition
atomic_types.h:15
common.h
Common toolchain abstraction.
stdbool.h
stdint.h
atomic.h
util_macro.h
Macro utilities.
zephyr
sys
spsc_lockfree.h
Generated on Sat Sep 7 2024 21:06:08 for Zephyr API Documentation by
1.12.0