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 <toolchain.h>
13 #include <stddef.h>
14
15 #include <zephyr/types.h>
16
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20
21 typedef int atomic_t;
22 typedef atomic_t atomic_val_t;
23 typedef void *atomic_ptr_t;
24 typedef atomic_ptr_t atomic_ptr_val_t;
25
26 /* Low-level primitives come in several styles: */
27
28 #if defined(CONFIG_ATOMIC_OPERATIONS_C)
29 /* Generic-but-slow implementation based on kernel locking and syscalls */
30 #include <sys/atomic_c.h>
31 #elif defined(CONFIG_ATOMIC_OPERATIONS_ARCH)
32 /* Some architectures need their own implementation */
33 # ifdef CONFIG_XTENSA
34 /* Not all Xtensa toolchains support GCC-style atomic intrinsics */
35 # include <arch/xtensa/atomic_xtensa.h>
36 # else
37 /* Other arch specific implementation */
38 # include <sys/atomic_arch.h>
39 # endif /* CONFIG_XTENSA */
40 #else
41 /* Default. See this file for the Doxygen reference: */
42 #include <sys/atomic_builtin.h>
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) * 8)
79 #define ATOMIC_MASK(bit) (1U << ((uint32_t)(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) (1 + ((num_bits) - 1) / 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 test a bit.
118 *
119 * This routine tests 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 * @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 * @param target Address of atomic variable or array.
141 * @param bit Bit number (starting from 0).
142 *
143 * @return true if the bit was set, false if it wasn't.
144 */
atomic_test_and_clear_bit(atomic_t * target,int bit)145 static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit)
146 {
147 atomic_val_t mask = ATOMIC_MASK(bit);
148 atomic_val_t old;
149
150 old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
151
152 return (old & mask) != 0;
153 }
154
155 /**
156 * @brief Atomically set a bit.
157 *
158 * Atomically set bit number @a bit of @a target and return its old value.
159 * The target may be a single atomic variable or an array of them.
160 *
161 * @param target Address of atomic variable or array.
162 * @param bit Bit number (starting from 0).
163 *
164 * @return true if the bit was set, false if it wasn't.
165 */
atomic_test_and_set_bit(atomic_t * target,int bit)166 static inline bool atomic_test_and_set_bit(atomic_t *target, int bit)
167 {
168 atomic_val_t mask = ATOMIC_MASK(bit);
169 atomic_val_t old;
170
171 old = atomic_or(ATOMIC_ELEM(target, bit), mask);
172
173 return (old & mask) != 0;
174 }
175
176 /**
177 * @brief Atomically clear a bit.
178 *
179 * Atomically clear bit number @a bit of @a target.
180 * The target may be a single atomic variable or an array of them.
181 *
182 * @param target Address of atomic variable or array.
183 * @param bit Bit number (starting from 0).
184 *
185 * @return N/A
186 */
atomic_clear_bit(atomic_t * target,int bit)187 static inline void atomic_clear_bit(atomic_t *target, int bit)
188 {
189 atomic_val_t mask = ATOMIC_MASK(bit);
190
191 (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
192 }
193
194 /**
195 * @brief Atomically set a bit.
196 *
197 * Atomically set bit number @a bit of @a target.
198 * The target may be a single atomic variable or an array of them.
199 *
200 * @param target Address of atomic variable or array.
201 * @param bit Bit number (starting from 0).
202 *
203 * @return N/A
204 */
atomic_set_bit(atomic_t * target,int bit)205 static inline void atomic_set_bit(atomic_t *target, int bit)
206 {
207 atomic_val_t mask = ATOMIC_MASK(bit);
208
209 (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
210 }
211
212 /**
213 * @brief Atomically set a bit to a given value.
214 *
215 * Atomically set bit number @a bit of @a target to value @a val.
216 * The target may be a single atomic variable or an array of them.
217 *
218 * @param target Address of atomic variable or array.
219 * @param bit Bit number (starting from 0).
220 * @param val true for 1, false for 0.
221 *
222 * @return N/A
223 */
atomic_set_bit_to(atomic_t * target,int bit,bool val)224 static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
225 {
226 atomic_val_t mask = ATOMIC_MASK(bit);
227
228 if (val) {
229 (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
230 } else {
231 (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
232 }
233 }
234
235 /**
236 * @}
237 */
238
239 #ifdef __cplusplus
240 } /* extern "C" */
241 #endif
242
243 #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */
244