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_macro.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