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