1 /*
2 * Copyright (c) 1997-2015, Wind River Systems, Inc.
3 * Copyright (c) 2021 Intel Corporation
4 * Copyright (c) 2023 Nordic Semiconductor ASA
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_H_
10 #define ZEPHYR_INCLUDE_SYS_ATOMIC_H_
11
12 #include <stdbool.h>
13 #include <zephyr/toolchain.h>
14 #include <stddef.h>
15
16 #include <zephyr/sys/atomic_types.h> /* IWYU pragma: export */
17 #include <zephyr/types.h>
18 #include <zephyr/sys/util.h>
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 /* Low-level primitives come in several styles: */
25
26 #if defined(CONFIG_ATOMIC_OPERATIONS_C)
27 /* Generic-but-slow implementation based on kernel locking and syscalls */
28 #include <zephyr/sys/atomic_c.h>
29 #elif defined(CONFIG_ATOMIC_OPERATIONS_ARCH)
30 /* Some architectures need their own implementation */
31 # ifdef CONFIG_XTENSA
32 /* Not all Xtensa toolchains support GCC-style atomic intrinsics */
33 # include <zephyr/arch/xtensa/atomic_xtensa.h>
34 # else
35 /* Other arch specific implementation */
36 # include <zephyr/sys/atomic_arch.h>
37 # endif /* CONFIG_XTENSA */
38 #elif defined(CONFIG_ATOMIC_OPERATIONS_BUILTIN)
39 /* Default. See this file for the Doxygen reference: */
40 #include <zephyr/sys/atomic_builtin.h>
41 #else
42 #error "CONFIG_ATOMIC_OPERATIONS_* not defined"
43 #endif
44
45 /* Portable higher-level utilities: */
46
47 /**
48 * @defgroup atomic_apis Atomic Services APIs
49 * @ingroup kernel_apis
50 * @{
51 */
52
53 /**
54 * @brief Initialize an atomic variable.
55 *
56 * This macro can be used to initialize an atomic variable. For example,
57 * @code atomic_t my_var = ATOMIC_INIT(75); @endcode
58 *
59 * @param i Value to assign to atomic variable.
60 */
61 #define ATOMIC_INIT(i) (i)
62
63 /**
64 * @brief Initialize an atomic pointer variable.
65 *
66 * This macro can be used to initialize an atomic pointer variable. For
67 * example,
68 * @code atomic_ptr_t my_ptr = ATOMIC_PTR_INIT(&data); @endcode
69 *
70 * @param p Pointer value to assign to atomic pointer variable.
71 */
72 #define ATOMIC_PTR_INIT(p) (p)
73
74 /**
75 * @cond INTERNAL_HIDDEN
76 */
77
78 #define ATOMIC_BITS (sizeof(atomic_val_t) * BITS_PER_BYTE)
79 #define ATOMIC_MASK(bit) BIT((unsigned long)(bit) & (ATOMIC_BITS - 1U))
80 #define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
81
82 /**
83 * INTERNAL_HIDDEN @endcond
84 */
85
86 /**
87 * @brief This macro computes the number of atomic variables necessary to
88 * represent a bitmap with @a num_bits.
89 *
90 * @param num_bits Number of bits.
91 */
92 #define ATOMIC_BITMAP_SIZE(num_bits) (ROUND_UP(num_bits, ATOMIC_BITS) / ATOMIC_BITS)
93
94 /**
95 * @brief Define an array of atomic variables.
96 *
97 * This macro defines an array of atomic variables containing at least
98 * @a num_bits bits.
99 *
100 * @note
101 * If used from file scope, the bits of the array are initialized to zero;
102 * if used from within a function, the bits are left uninitialized.
103 *
104 * @cond INTERNAL_HIDDEN
105 * @note
106 * This macro should be replicated in the PREDEFINED field of the documentation
107 * Doxyfile.
108 * @endcond
109 *
110 * @param name Name of array of atomic variables.
111 * @param num_bits Number of bits needed.
112 */
113 #define ATOMIC_DEFINE(name, num_bits) \
114 atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)]
115
116 /**
117 * @brief Atomically get and test a bit.
118 *
119 * Atomically get a value and then test whether bit number @a bit of @a target is set or not.
120 * The target may be a single atomic variable or an array of them.
121 *
122 * @note @atomic_api
123 *
124 * @param target Address of atomic variable or array.
125 * @param bit Bit number (starting from 0).
126 *
127 * @return true if the bit was set, false if it wasn't.
128 */
atomic_test_bit(const atomic_t * target,int bit)129 static inline bool atomic_test_bit(const atomic_t *target, int bit)
130 {
131 atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
132
133 return (1 & (val >> (bit & (ATOMIC_BITS - 1)))) != 0;
134 }
135
136 /**
137 * @brief Atomically clear a bit and test it.
138 *
139 * Atomically clear bit number @a bit of @a target and return its old value.
140 * The target may be a single atomic variable or an array of them.
141 *
142 * @note @atomic_api
143 *
144 * @param target Address of atomic variable or array.
145 * @param bit Bit number (starting from 0).
146 *
147 * @return false if the bit was already cleared, true if it wasn't.
148 */
atomic_test_and_clear_bit(atomic_t * target,int bit)149 static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit)
150 {
151 atomic_val_t mask = ATOMIC_MASK(bit);
152 atomic_val_t old;
153
154 old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
155
156 return (old & mask) != 0;
157 }
158
159 /**
160 * @brief Atomically set a bit and test it.
161 *
162 * Atomically set bit number @a bit of @a target and return its old value.
163 * The target may be a single atomic variable or an array of them.
164 *
165 * @note @atomic_api
166 *
167 * @param target Address of atomic variable or array.
168 * @param bit Bit number (starting from 0).
169 *
170 * @return true if the bit was already set, false if it wasn't.
171 */
atomic_test_and_set_bit(atomic_t * target,int bit)172 static inline bool atomic_test_and_set_bit(atomic_t *target, int bit)
173 {
174 atomic_val_t mask = ATOMIC_MASK(bit);
175 atomic_val_t old;
176
177 old = atomic_or(ATOMIC_ELEM(target, bit), mask);
178
179 return (old & mask) != 0;
180 }
181
182 /**
183 * @brief Atomically clear a bit.
184 *
185 * Atomically clear bit number @a bit of @a target.
186 * The target may be a single atomic variable or an array of them.
187 *
188 * @note @atomic_api
189 *
190 * @param target Address of atomic variable or array.
191 * @param bit Bit number (starting from 0).
192 */
atomic_clear_bit(atomic_t * target,int bit)193 static inline void atomic_clear_bit(atomic_t *target, int bit)
194 {
195 atomic_val_t mask = ATOMIC_MASK(bit);
196
197 (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
198 }
199
200 /**
201 * @brief Atomically set a bit.
202 *
203 * Atomically set bit number @a bit of @a target.
204 * The target may be a single atomic variable or an array of them.
205 *
206 * @note @atomic_api
207 *
208 * @param target Address of atomic variable or array.
209 * @param bit Bit number (starting from 0).
210 */
atomic_set_bit(atomic_t * target,int bit)211 static inline void atomic_set_bit(atomic_t *target, int bit)
212 {
213 atomic_val_t mask = ATOMIC_MASK(bit);
214
215 (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
216 }
217
218 /**
219 * @brief Atomically set a bit to a given value.
220 *
221 * Atomically set bit number @a bit of @a target to value @a val.
222 * The target may be a single atomic variable or an array of them.
223 *
224 * @note @atomic_api
225 *
226 * @param target Address of atomic variable or array.
227 * @param bit Bit number (starting from 0).
228 * @param val true for 1, false for 0.
229 */
atomic_set_bit_to(atomic_t * target,int bit,bool val)230 static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
231 {
232 atomic_val_t mask = ATOMIC_MASK(bit);
233
234 if (val) {
235 (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
236 } else {
237 (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
238 }
239 }
240
241 /**
242 * @brief Atomic compare-and-set.
243 *
244 * This routine performs an atomic compare-and-set on @a target. If the current
245 * value of @a target equals @a old_value, @a target is set to @a new_value.
246 * If the current value of @a target does not equal @a old_value, @a target
247 * is left unchanged.
248 *
249 * @note @atomic_api
250 *
251 * @param target Address of atomic variable.
252 * @param old_value Original value to compare against.
253 * @param new_value New value to store.
254 * @return true if @a new_value is written, false otherwise.
255 */
256 bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value);
257
258 /**
259 * @brief Atomic compare-and-set with pointer values
260 *
261 * This routine performs an atomic compare-and-set on @a target. If the current
262 * value of @a target equals @a old_value, @a target is set to @a new_value.
263 * If the current value of @a target does not equal @a old_value, @a target
264 * is left unchanged.
265 *
266 * @note @atomic_api
267 *
268 * @param target Address of atomic variable.
269 * @param old_value Original value to compare against.
270 * @param new_value New value to store.
271 * @return true if @a new_value is written, false otherwise.
272 */
273 bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value,
274 atomic_ptr_val_t new_value);
275
276 /**
277 * @brief Atomic addition.
278 *
279 * This routine performs an atomic addition on @a target.
280 *
281 * @note @atomic_api
282 *
283 * @param target Address of atomic variable.
284 * @param value Value to add.
285 *
286 * @return Previous value of @a target.
287 */
288 atomic_val_t atomic_add(atomic_t *target, atomic_val_t value);
289
290 /**
291 * @brief Atomic subtraction.
292 *
293 * This routine performs an atomic subtraction on @a target.
294 *
295 * @note @atomic_api
296 *
297 * @param target Address of atomic variable.
298 * @param value Value to subtract.
299 *
300 * @return Previous value of @a target.
301 */
302 atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value);
303
304 /**
305 * @brief Atomic increment.
306 *
307 * This routine performs an atomic increment by 1 on @a target.
308 *
309 * @note @atomic_api
310 *
311 * @param target Address of atomic variable.
312 *
313 * @return Previous value of @a target.
314 */
315 atomic_val_t atomic_inc(atomic_t *target);
316
317 /**
318 * @brief Atomic decrement.
319 *
320 * This routine performs an atomic decrement by 1 on @a target.
321 *
322 * @note @atomic_api
323 *
324 * @param target Address of atomic variable.
325 *
326 * @return Previous value of @a target.
327 */
328 atomic_val_t atomic_dec(atomic_t *target);
329
330 /**
331 * @brief Atomic get.
332 *
333 * This routine performs an atomic read on @a target.
334 *
335 * @note @atomic_api
336 *
337 * @param target Address of atomic variable.
338 *
339 * @return Value of @a target.
340 */
341 atomic_val_t atomic_get(const atomic_t *target);
342
343 /**
344 * @brief Atomic get a pointer value
345 *
346 * This routine performs an atomic read on @a target.
347 *
348 * @note @atomic_api
349 *
350 * @param target Address of pointer variable.
351 *
352 * @return Value of @a target.
353 */
354 atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target);
355
356 /**
357 * @brief Atomic get-and-set.
358 *
359 * This routine atomically sets @a target to @a value and returns
360 * the previous value of @a target.
361 *
362 * @note @atomic_api
363 *
364 * @param target Address of atomic variable.
365 * @param value Value to write to @a target.
366 *
367 * @return Previous value of @a target.
368 */
369 atomic_val_t atomic_set(atomic_t *target, atomic_val_t value);
370
371 /**
372 * @brief Atomic get-and-set for pointer values
373 *
374 * This routine atomically sets @a target to @a value and returns
375 * the previous value of @a target.
376 *
377 * @note @atomic_api
378 *
379 * @param target Address of atomic variable.
380 * @param value Value to write to @a target.
381 *
382 * @return Previous value of @a target.
383 */
384 atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value);
385
386 /**
387 * @brief Atomic clear.
388 *
389 * This routine atomically sets @a target to zero and returns its previous
390 * value. (Hence, it is equivalent to atomic_set(target, 0).)
391 *
392 * @note @atomic_api
393 *
394 * @param target Address of atomic variable.
395 *
396 * @return Previous value of @a target.
397 */
398 atomic_val_t atomic_clear(atomic_t *target);
399
400 /**
401 * @brief Atomic clear of a pointer value
402 *
403 * This routine atomically sets @a target to zero and returns its previous
404 * value. (Hence, it is equivalent to atomic_set(target, 0).)
405 *
406 * @note @atomic_api
407 *
408 * @param target Address of atomic variable.
409 *
410 * @return Previous value of @a target.
411 */
412 atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target);
413
414 /**
415 * @brief Atomic bitwise inclusive OR.
416 *
417 * This routine atomically sets @a target to the bitwise inclusive OR of
418 * @a target and @a value.
419 *
420 * @note @atomic_api
421 *
422 * @param target Address of atomic variable.
423 * @param value Value to OR.
424 *
425 * @return Previous value of @a target.
426 */
427 atomic_val_t atomic_or(atomic_t *target, atomic_val_t value);
428
429 /**
430 * @brief Atomic bitwise exclusive OR (XOR).
431 *
432 * @note @atomic_api
433 *
434 * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
435 * @a target and @a value.
436 *
437 * @param target Address of atomic variable.
438 * @param value Value to XOR
439 *
440 * @return Previous value of @a target.
441 */
442 atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value);
443
444 /**
445 * @brief Atomic bitwise AND.
446 *
447 * This routine atomically sets @a target to the bitwise AND of @a target
448 * and @a value.
449 *
450 * @note @atomic_api
451 *
452 * @param target Address of atomic variable.
453 * @param value Value to AND.
454 *
455 * @return Previous value of @a target.
456 */
457 atomic_val_t atomic_and(atomic_t *target, atomic_val_t value);
458
459 /**
460 * @brief Atomic bitwise NAND.
461 *
462 * This routine atomically sets @a target to the bitwise NAND of @a target
463 * and @a value. (This operation is equivalent to target = ~(target & value).)
464 *
465 * @note @atomic_api
466 *
467 * @param target Address of atomic variable.
468 * @param value Value to NAND.
469 *
470 * @return Previous value of @a target.
471 */
472 atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value);
473
474 /**
475 * @}
476 */
477
478 #ifdef __cplusplus
479 } /* extern "C" */
480 #endif
481
482 #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */
483