1 /*
2 * Copyright (c) 1997-2015, Wind River Systems, Inc.
3 * Copyright (c) 2021 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_H_
9 #define ZEPHYR_INCLUDE_SYS_ATOMIC_H_
10
11 #include <stdbool.h>
12 #include <zephyr/toolchain.h>
13 #include <stddef.h>
14
15 #include <zephyr/types.h>
16 #include <zephyr/sys/util_macro.h>
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21
22 typedef long atomic_t;
23 typedef atomic_t atomic_val_t;
24 typedef void *atomic_ptr_t;
25 typedef atomic_ptr_t atomic_ptr_val_t;
26
27 /* Low-level primitives come in several styles: */
28
29 #if defined(CONFIG_ATOMIC_OPERATIONS_C)
30 /* Generic-but-slow implementation based on kernel locking and syscalls */
31 #include <zephyr/sys/atomic_c.h>
32 #elif defined(CONFIG_ATOMIC_OPERATIONS_ARCH)
33 /* Some architectures need their own implementation */
34 # ifdef CONFIG_XTENSA
35 /* Not all Xtensa toolchains support GCC-style atomic intrinsics */
36 # include <zephyr/arch/xtensa/atomic_xtensa.h>
37 # else
38 /* Other arch specific implementation */
39 # include <zephyr/sys/atomic_arch.h>
40 # endif /* CONFIG_XTENSA */
41 #else
42 /* Default. See this file for the Doxygen reference: */
43 #include <zephyr/sys/atomic_builtin.h>
44 #endif
45
46 /* Portable higher-level utilities: */
47
48 /**
49 * @defgroup atomic_apis Atomic Services APIs
50 * @ingroup kernel_apis
51 * @{
52 */
53
54 /**
55 * @brief Initialize an atomic variable.
56 *
57 * This macro can be used to initialize an atomic variable. For example,
58 * @code atomic_t my_var = ATOMIC_INIT(75); @endcode
59 *
60 * @param i Value to assign to atomic variable.
61 */
62 #define ATOMIC_INIT(i) (i)
63
64 /**
65 * @brief Initialize an atomic pointer variable.
66 *
67 * This macro can be used to initialize an atomic pointer variable. For
68 * example,
69 * @code atomic_ptr_t my_ptr = ATOMIC_PTR_INIT(&data); @endcode
70 *
71 * @param p Pointer value to assign to atomic pointer variable.
72 */
73 #define ATOMIC_PTR_INIT(p) (p)
74
75 /**
76 * @cond INTERNAL_HIDDEN
77 */
78
79 #define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
80 #define ATOMIC_MASK(bit) BIT((unsigned long)(bit) & (ATOMIC_BITS - 1U))
81 #define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
82
83 /**
84 * INTERNAL_HIDDEN @endcond
85 */
86
87 /**
88 * @brief This macro computes the number of atomic variables necessary to
89 * represent a bitmap with @a num_bits.
90 *
91 * @param num_bits Number of bits.
92 */
93 #define ATOMIC_BITMAP_SIZE(num_bits) (1 + ((num_bits) - 1) / ATOMIC_BITS)
94
95 /**
96 * @brief Define an array of atomic variables.
97 *
98 * This macro defines an array of atomic variables containing at least
99 * @a num_bits bits.
100 *
101 * @note
102 * If used from file scope, the bits of the array are initialized to zero;
103 * if used from within a function, the bits are left uninitialized.
104 *
105 * @cond INTERNAL_HIDDEN
106 * @note
107 * This macro should be replicated in the PREDEFINED field of the documentation
108 * Doxyfile.
109 * @endcond
110 *
111 * @param name Name of array of atomic variables.
112 * @param num_bits Number of bits needed.
113 */
114 #define ATOMIC_DEFINE(name, num_bits) \
115 atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)]
116
117 /**
118 * @brief Atomically test a bit.
119 *
120 * This routine tests whether bit number @a bit of @a target is set or not.
121 * The target may be a single atomic variable or an array of them.
122 *
123 * @note As for all atomic APIs, includes a
124 * full/sequentially-consistent memory barrier (where applicable).
125 *
126 * @param target Address of atomic variable or array.
127 * @param bit Bit number (starting from 0).
128 *
129 * @return true if the bit was set, false if it wasn't.
130 */
atomic_test_bit(const atomic_t * target,int bit)131 static inline bool atomic_test_bit(const atomic_t *target, int bit)
132 {
133 atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
134
135 return (1 & (val >> (bit & (ATOMIC_BITS - 1)))) != 0;
136 }
137
138 /**
139 * @brief Atomically test and clear a bit.
140 *
141 * Atomically clear bit number @a bit of @a target and return its old value.
142 * The target may be a single atomic variable or an array of them.
143 *
144 * @note As for all atomic APIs, includes a
145 * full/sequentially-consistent memory barrier (where applicable).
146 *
147 * @param target Address of atomic variable or array.
148 * @param bit Bit number (starting from 0).
149 *
150 * @return true if the bit was set, false if it wasn't.
151 */
atomic_test_and_clear_bit(atomic_t * target,int bit)152 static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit)
153 {
154 atomic_val_t mask = ATOMIC_MASK(bit);
155 atomic_val_t old;
156
157 old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
158
159 return (old & mask) != 0;
160 }
161
162 /**
163 * @brief Atomically set a bit.
164 *
165 * Atomically set bit number @a bit of @a target and return its old value.
166 * The target may be a single atomic variable or an array of them.
167 *
168 * @note As for all atomic APIs, includes a
169 * full/sequentially-consistent memory barrier (where applicable).
170 *
171 * @param target Address of atomic variable or array.
172 * @param bit Bit number (starting from 0).
173 *
174 * @return true if the bit was set, false if it wasn't.
175 */
atomic_test_and_set_bit(atomic_t * target,int bit)176 static inline bool atomic_test_and_set_bit(atomic_t *target, int bit)
177 {
178 atomic_val_t mask = ATOMIC_MASK(bit);
179 atomic_val_t old;
180
181 old = atomic_or(ATOMIC_ELEM(target, bit), mask);
182
183 return (old & mask) != 0;
184 }
185
186 /**
187 * @brief Atomically clear a bit.
188 *
189 * Atomically clear bit number @a bit of @a target.
190 * The target may be a single atomic variable or an array of them.
191 *
192 * @note As for all atomic APIs, includes a
193 * full/sequentially-consistent memory barrier (where applicable).
194 *
195 * @param target Address of atomic variable or array.
196 * @param bit Bit number (starting from 0).
197 */
atomic_clear_bit(atomic_t * target,int bit)198 static inline void atomic_clear_bit(atomic_t *target, int bit)
199 {
200 atomic_val_t mask = ATOMIC_MASK(bit);
201
202 (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
203 }
204
205 /**
206 * @brief Atomically set a bit.
207 *
208 * Atomically set bit number @a bit of @a target.
209 * The target may be a single atomic variable or an array of them.
210 *
211 * @note As for all atomic APIs, includes a
212 * full/sequentially-consistent memory barrier (where applicable).
213 *
214 * @param target Address of atomic variable or array.
215 * @param bit Bit number (starting from 0).
216 */
atomic_set_bit(atomic_t * target,int bit)217 static inline void atomic_set_bit(atomic_t *target, int bit)
218 {
219 atomic_val_t mask = ATOMIC_MASK(bit);
220
221 (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
222 }
223
224 /**
225 * @brief Atomically set a bit to a given value.
226 *
227 * Atomically set bit number @a bit of @a target to value @a val.
228 * The target may be a single atomic variable or an array of them.
229 *
230 * @note As for all atomic APIs, includes a
231 * full/sequentially-consistent memory barrier (where applicable).
232 *
233 * @param target Address of atomic variable or array.
234 * @param bit Bit number (starting from 0).
235 * @param val true for 1, false for 0.
236 */
atomic_set_bit_to(atomic_t * target,int bit,bool val)237 static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
238 {
239 atomic_val_t mask = ATOMIC_MASK(bit);
240
241 if (val) {
242 (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
243 } else {
244 (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
245 }
246 }
247
248 /**
249 * @}
250 */
251
252 #ifdef __cplusplus
253 } /* extern "C" */
254 #endif
255
256 #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */
257