xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/atomic.h (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /* atomic operations */
2 
3 /*
4  * Copyright (c) 1997-2015, Wind River Systems, Inc.
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #ifndef __ATOMIC_H__
10 #define __ATOMIC_H__
11 
12 #ifdef __cplusplus
13 extern "C"
14 {
15 #endif
16 
17 typedef int atomic_t;
18 typedef atomic_t atomic_val_t;
19 
20 /**
21  * @defgroup atomic_apis Atomic Services APIs
22  * @ingroup kernel_apis
23  * @{
24  */
25 
26 /**
27  * @brief Atomic compare-and-set.
28  *
29  * This routine performs an atomic compare-and-set on @a target. If the current
30  * value of @a target equals @a old_value, @a target is set to @a new_value.
31  * If the current value of @a target does not equal @a old_value, @a target
32  * is left unchanged.
33  *
34  * @param target Address of atomic variable.
35  * @param old_value Original value to compare against.
36  * @param new_value New value to store.
37  * @return 1 if @a new_value is written, 0 otherwise.
38  */
atomic_cas(atomic_t * target,atomic_val_t old_value,atomic_val_t new_value)39 static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
40         atomic_val_t new_value)
41 {
42     return __atomic_compare_exchange_n(target, &old_value, new_value,
43             0, __ATOMIC_SEQ_CST,
44             __ATOMIC_SEQ_CST);
45 }
46 
47 /**
48  *
49  * @brief Atomic addition.
50  *
51  * This routine performs an atomic addition on @a target.
52  *
53  * @param target Address of atomic variable.
54  * @param value Value to add.
55  *
56  * @return Previous value of @a target.
57  */
atomic_add(atomic_t * target,atomic_val_t value)58 static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
59 {
60     return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
61 }
62 
63 /**
64  *
65  * @brief Atomic subtraction.
66  *
67  * This routine performs an atomic subtraction on @a target.
68  *
69  * @param target Address of atomic variable.
70  * @param value Value to subtract.
71  *
72  * @return Previous value of @a target.
73  */
74 
atomic_sub(atomic_t * target,atomic_val_t value)75 static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
76 {
77     return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
78 }
79 
80 /**
81  *
82  * @brief Atomic increment.
83  *
84  * This routine performs an atomic increment by 1 on @a target.
85  *
86  * @param target Address of atomic variable.
87  *
88  * @return Previous value of @a target.
89  */
90 
atomic_inc(atomic_t * target)91 static inline atomic_val_t atomic_inc(atomic_t *target)
92 {
93     return atomic_add(target, 1);
94 }
95 
96 /**
97  *
98  * @brief Atomic decrement.
99  *
100  * This routine performs an atomic decrement by 1 on @a target.
101  *
102  * @param target Address of atomic variable.
103  *
104  * @return Previous value of @a target.
105  */
106 
atomic_dec(atomic_t * target)107 static inline atomic_val_t atomic_dec(atomic_t *target)
108 {
109     return atomic_sub(target, 1);
110 }
111 
112 /**
113  *
114  * @brief Atomic get.
115  *
116  * This routine performs an atomic read on @a target.
117  *
118  * @param target Address of atomic variable.
119  *
120  * @return Value of @a target.
121  */
122 
atomic_get(const atomic_t * target)123 static inline atomic_val_t atomic_get(const atomic_t *target)
124 {
125     return __atomic_load_n(target, __ATOMIC_SEQ_CST);
126 }
127 
128 /**
129  *
130  * @brief Atomic get-and-set.
131  *
132  * This routine atomically sets @a target to @a value and returns
133  * the previous value of @a target.
134  *
135  * @param target Address of atomic variable.
136  * @param value Value to write to @a target.
137  *
138  * @return Previous value of @a target.
139  */
140 
atomic_set(atomic_t * target,atomic_val_t value)141 static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
142 {
143     /* This builtin, as described by Intel, is not a traditional
144      * test-and-set operation, but rather an atomic exchange operation. It
145      * writes value into *ptr, and returns the previous contents of *ptr.
146      */
147     return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
148 }
149 
150 /**
151  *
152  * @brief Atomic clear.
153  *
154  * This routine atomically sets @a target to zero and returns its previous
155  * value. (Hence, it is equivalent to atomic_set(target, 0).)
156  *
157  * @param target Address of atomic variable.
158  *
159  * @return Previous value of @a target.
160  */
161 
atomic_clear(atomic_t * target)162 static inline atomic_val_t atomic_clear(atomic_t *target)
163 {
164     return atomic_set(target, 0);
165 }
166 
167 /**
168  *
169  * @brief Atomic bitwise inclusive OR.
170  *
171  * This routine atomically sets @a target to the bitwise inclusive OR of
172  * @a target and @a value.
173  *
174  * @param target Address of atomic variable.
175  * @param value Value to OR.
176  *
177  * @return Previous value of @a target.
178  */
179 
atomic_or(atomic_t * target,atomic_val_t value)180 static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
181 {
182     return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
183 }
184 
185 /**
186  *
187  * @brief Atomic bitwise exclusive OR (XOR).
188  *
189  * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
190  * @a target and @a value.
191  *
192  * @param target Address of atomic variable.
193  * @param value Value to XOR
194  *
195  * @return Previous value of @a target.
196  */
197 
atomic_xor(atomic_t * target,atomic_val_t value)198 static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
199 {
200     return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
201 }
202 
203 /**
204  *
205  * @brief Atomic bitwise AND.
206  *
207  * This routine atomically sets @a target to the bitwise AND of @a target
208  * and @a value.
209  *
210  * @param target Address of atomic variable.
211  * @param value Value to AND.
212  *
213  * @return Previous value of @a target.
214  */
215 
atomic_and(atomic_t * target,atomic_val_t value)216 static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
217 {
218     return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
219 }
220 
221 /**
222  *
223  * @brief Atomic bitwise NAND.
224  *
225  * This routine atomically sets @a target to the bitwise NAND of @a target
226  * and @a value. (This operation is equivalent to target = ~(target & value).)
227  *
228  * @param target Address of atomic variable.
229  * @param value Value to NAND.
230  *
231  * @return Previous value of @a target.
232  */
233 
atomic_nand(atomic_t * target,atomic_val_t value)234 static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
235 {
236     return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
237 }
238 
239     /**
240      * @brief Initialize an atomic variable.
241      *
242      * This macro can be used to initialize an atomic variable. For example,
243      * @code atomic_t my_var = ATOMIC_INIT(75); @endcode
244      *
245      * @param i Value to assign to atomic variable.
246      */
247 #define ATOMIC_INIT(i) (i)
248 
249     /**
250      * @cond INTERNAL_HIDDEN
251      */
252 
253 #define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
254 #define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
255 #define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
256 
257     /**
258      * INTERNAL_HIDDEN @endcond
259      */
260 
261     /**
262      * @brief Define an array of atomic variables.
263      *
264      * This macro defines an array of atomic variables containing at least
265      * @a num_bits bits.
266      *
267      * @note
268      * If used from file scope, the bits of the array are initialized to zero;
269      * if used from within a function, the bits are left uninitialized.
270      *
271      * @param name Name of array of atomic variables.
272      * @param num_bits Number of bits needed.
273      */
274 #define ATOMIC_DEFINE(name, num_bits) \
275 	atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS]
276 
277     /**
278      * @brief Atomically test a bit.
279      *
280      * This routine tests whether bit number @a bit of @a target is set or not.
281      * The target may be a single atomic variable or an array of them.
282      *
283      * @param target Address of atomic variable or array.
284      * @param bit Bit number (starting from 0).
285      *
286      * @return 1 if the bit was set, 0 if it wasn't.
287      */
288     static inline int
atomic_test_bit(const atomic_t * target,int bit)289     atomic_test_bit(const atomic_t *target, int bit)
290     {
291         atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
292 
293         return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
294     }
295 
296     /**
297      * @brief Atomically test and clear a bit.
298      *
299      * Atomically clear bit number @a bit of @a target and return its old value.
300      * The target may be a single atomic variable or an array of them.
301      *
302      * @param target Address of atomic variable or array.
303      * @param bit Bit number (starting from 0).
304      *
305      * @return 1 if the bit was set, 0 if it wasn't.
306      */
307     static inline int
atomic_test_and_clear_bit(atomic_t * target,int bit)308     atomic_test_and_clear_bit(atomic_t *target, int bit)
309     {
310         atomic_val_t mask = ATOMIC_MASK(bit);
311         atomic_val_t old;
312 
313         old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
314 
315         return (old & mask) != 0;
316     }
317 
318     /**
319      * @brief Atomically set a bit.
320      *
321      * Atomically set bit number @a bit of @a target and return its old value.
322      * The target may be a single atomic variable or an array of them.
323      *
324      * @param target Address of atomic variable or array.
325      * @param bit Bit number (starting from 0).
326      *
327      * @return 1 if the bit was set, 0 if it wasn't.
328      */
329     static inline int
atomic_test_and_set_bit(atomic_t * target,int bit)330     atomic_test_and_set_bit(atomic_t *target, int bit)
331     {
332         atomic_val_t mask = ATOMIC_MASK(bit);
333         atomic_val_t old;
334 
335         old = atomic_or(ATOMIC_ELEM(target, bit), mask);
336 
337         return (old & mask) != 0;
338     }
339 
340     /**
341      * @brief Atomically clear a bit.
342      *
343      * Atomically clear bit number @a bit of @a target.
344      * The target may be a single atomic variable or an array of them.
345      *
346      * @param target Address of atomic variable or array.
347      * @param bit Bit number (starting from 0).
348      *
349      * @return N/A
350      */
351     static inline void
atomic_clear_bit(atomic_t * target,int bit)352     atomic_clear_bit(atomic_t *target, int bit)
353     {
354         atomic_val_t mask = ATOMIC_MASK(bit);
355 
356         atomic_and(ATOMIC_ELEM(target, bit), ~mask);
357     }
358 
359     /**
360      * @brief Atomically set a bit.
361      *
362      * Atomically set bit number @a bit of @a target.
363      * The target may be a single atomic variable or an array of them.
364      *
365      * @param target Address of atomic variable or array.
366      * @param bit Bit number (starting from 0).
367      *
368      * @return N/A
369      */
370     static inline void
atomic_set_bit(atomic_t * target,int bit)371     atomic_set_bit(atomic_t *target, int bit)
372     {
373         atomic_val_t mask = ATOMIC_MASK(bit);
374 
375         atomic_or(ATOMIC_ELEM(target, bit), mask);
376     }
377 
378 /**
379  * @}
380  */
381 
382 #ifdef __cplusplus
383 }
384 #endif
385 
386 #endif /* __ATOMIC_H__ */
387