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