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