Line data Source code
1 0 : /*
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 1 : #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 1 : #define ATOMIC_PTR_INIT(p) (p)
71 :
72 : /**
73 : * @cond INTERNAL_HIDDEN
74 : */
75 :
76 : #define ATOMIC_BITS (sizeof(atomic_val_t) * BITS_PER_BYTE)
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 1 : #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 1 : #define ATOMIC_DEFINE(name, num_bits) \
112 : atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)]
113 :
114 : /**
115 : * @brief Atomically get and test a bit.
116 : *
117 : * Atomically get a value and then test 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 : */
127 1 : 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 clear a bit and test it.
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 : */
147 1 : 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 and test it.
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 : */
170 1 : 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 : */
191 1 : 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 : */
209 1 : 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 : */
228 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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 1 : 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_ */
|