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 false if the bit was already cleared, true 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 already 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