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 #include <ble_types/types.h>
12 
13 #ifdef __cplusplus
14 extern "C" {
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  */
39 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_cas(atomic_t * target,atomic_val_t old_value,atomic_val_t new_value)40 static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
41 			  atomic_val_t new_value)
42 {
43 	return __atomic_compare_exchange_n(target, &old_value, new_value,
44 					   0, __ATOMIC_SEQ_CST,
45 					   __ATOMIC_SEQ_CST);
46 }
47 #else
48 extern int atomic_cas(atomic_t *target, atomic_val_t old_value,
49 		      atomic_val_t new_value);
50 #endif
51 
52 /**
53  *
54  * @brief Atomic addition.
55  *
56  * This routine performs an atomic addition on @a target.
57  *
58  * @param target Address of atomic variable.
59  * @param value Value to add.
60  *
61  * @return Previous value of @a target.
62  */
63 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_add(atomic_t * target,atomic_val_t value)64 static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
65 {
66 	return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
67 }
68 #else
69 extern atomic_val_t atomic_add(atomic_t *target, atomic_val_t value);
70 #endif
71 
72 /**
73  *
74  * @brief Atomic subtraction.
75  *
76  * This routine performs an atomic subtraction on @a target.
77  *
78  * @param target Address of atomic variable.
79  * @param value Value to subtract.
80  *
81  * @return Previous value of @a target.
82  */
83 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_sub(atomic_t * target,atomic_val_t value)84 static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
85 {
86 	return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
87 }
88 #else
89 extern atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value);
90 #endif
91 
92 /**
93  *
94  * @brief Atomic increment.
95  *
96  * This routine performs an atomic increment by 1 on @a target.
97  *
98  * @param target Address of atomic variable.
99  *
100  * @return Previous value of @a target.
101  */
102 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_inc(atomic_t * target)103 static inline atomic_val_t atomic_inc(atomic_t *target)
104 {
105 	return atomic_add(target, 1);
106 }
107 #else
108 extern atomic_val_t atomic_inc(atomic_t *target);
109 #endif
110 
111 /**
112  *
113  * @brief Atomic decrement.
114  *
115  * This routine performs an atomic decrement by 1 on @a target.
116  *
117  * @param target Address of atomic variable.
118  *
119  * @return Previous value of @a target.
120  */
121 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_dec(atomic_t * target)122 static inline atomic_val_t atomic_dec(atomic_t *target)
123 {
124 	return atomic_sub(target, 1);
125 }
126 #else
127 extern atomic_val_t atomic_dec(atomic_t *target);
128 #endif
129 
130 /**
131  *
132  * @brief Atomic get.
133  *
134  * This routine performs an atomic read on @a target.
135  *
136  * @param target Address of atomic variable.
137  *
138  * @return Value of @a target.
139  */
140 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_get(const atomic_t * target)141 static inline atomic_val_t atomic_get(const atomic_t *target)
142 {
143 	return __atomic_load_n(target, __ATOMIC_SEQ_CST);
144 }
145 #else
146 extern atomic_val_t atomic_get(const atomic_t *target);
147 #endif
148 
149 /**
150  *
151  * @brief Atomic get-and-set.
152  *
153  * This routine atomically sets @a target to @a value and returns
154  * the previous value of @a target.
155  *
156  * @param target Address of atomic variable.
157  * @param value Value to write to @a target.
158  *
159  * @return Previous value of @a target.
160  */
161 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_set(atomic_t * target,atomic_val_t value)162 static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
163 {
164 	/* This builtin, as described by Intel, is not a traditional
165 	 * test-and-set operation, but rather an atomic exchange operation. It
166 	 * writes value into *ptr, and returns the previous contents of *ptr.
167 	 */
168 	return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
169 }
170 #else
171 extern atomic_val_t atomic_set(atomic_t *target, atomic_val_t value);
172 #endif
173 
174 /**
175  *
176  * @brief Atomic clear.
177  *
178  * This routine atomically sets @a target to zero and returns its previous
179  * value. (Hence, it is equivalent to atomic_set(target, 0).)
180  *
181  * @param target Address of atomic variable.
182  *
183  * @return Previous value of @a target.
184  */
185 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_clear(atomic_t * target)186 static inline atomic_val_t atomic_clear(atomic_t *target)
187 {
188 	return atomic_set(target, 0);
189 }
190 #else
191 extern atomic_val_t atomic_clear(atomic_t *target);
192 #endif
193 
194 /**
195  *
196  * @brief Atomic bitwise inclusive OR.
197  *
198  * This routine atomically sets @a target to the bitwise inclusive OR of
199  * @a target and @a value.
200  *
201  * @param target Address of atomic variable.
202  * @param value Value to OR.
203  *
204  * @return Previous value of @a target.
205  */
206 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_or(atomic_t * target,atomic_val_t value)207 static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
208 {
209 	return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
210 }
211 #else
212 extern atomic_val_t atomic_or(atomic_t *target, atomic_val_t value);
213 #endif
214 
215 /**
216  *
217  * @brief Atomic bitwise exclusive OR (XOR).
218  *
219  * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
220  * @a target and @a value.
221  *
222  * @param target Address of atomic variable.
223  * @param value Value to XOR
224  *
225  * @return Previous value of @a target.
226  */
227 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_xor(atomic_t * target,atomic_val_t value)228 static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
229 {
230 	return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
231 }
232 #else
233 extern atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value);
234 #endif
235 
236 /**
237  *
238  * @brief Atomic bitwise AND.
239  *
240  * This routine atomically sets @a target to the bitwise AND of @a target
241  * and @a value.
242  *
243  * @param target Address of atomic variable.
244  * @param value Value to AND.
245  *
246  * @return Previous value of @a target.
247  */
248 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_and(atomic_t * target,atomic_val_t value)249 static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
250 {
251 	return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
252 }
253 #else
254 extern atomic_val_t atomic_and(atomic_t *target, atomic_val_t value);
255 #endif
256 
257 /**
258  *
259  * @brief Atomic bitwise NAND.
260  *
261  * This routine atomically sets @a target to the bitwise NAND of @a target
262  * and @a value. (This operation is equivalent to target = ~(target & value).)
263  *
264  * @param target Address of atomic variable.
265  * @param value Value to NAND.
266  *
267  * @return Previous value of @a target.
268  */
269 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
atomic_nand(atomic_t * target,atomic_val_t value)270 static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
271 {
272 	return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
273 }
274 #else
275 extern atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value);
276 #endif
277 
278 
279 /**
280  * @brief Initialize an atomic variable.
281  *
282  * This macro can be used to initialize an atomic variable. For example,
283  * @code atomic_t my_var = ATOMIC_INIT(75); @endcode
284  *
285  * @param i Value to assign to atomic variable.
286  */
287 #define ATOMIC_INIT(i) (i)
288 
289 /**
290  * @cond INTERNAL_HIDDEN
291  */
292 
293 #define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
294 #define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
295 #define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
296 
297 /**
298  * INTERNAL_HIDDEN @endcond
299  */
300 
301 /**
302  * @brief Define an array of atomic variables.
303  *
304  * This macro defines an array of atomic variables containing at least
305  * @a num_bits bits.
306  *
307  * @note
308  * If used from file scope, the bits of the array are initialized to zero;
309  * if used from within a function, the bits are left uninitialized.
310  *
311  * @param name Name of array of atomic variables.
312  * @param num_bits Number of bits needed.
313  */
314 #define ATOMIC_DEFINE(name, num_bits) \
315 	atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS]
316 
317 /**
318  * @brief Atomically test a bit.
319  *
320  * This routine tests whether bit number @a bit of @a target is set or not.
321  * The target may be a single atomic variable or an array of them.
322  *
323  * @param target Address of atomic variable or array.
324  * @param bit Bit number (starting from 0).
325  *
326  * @return 1 if the bit was set, 0 if it wasn't.
327  */
atomic_test_bit(const atomic_t * target,int bit)328 static inline int atomic_test_bit(const atomic_t *target, int bit)
329 {
330 	atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
331 
332 	return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
333 }
334 
335 /**
336  * @brief Atomically test and clear a bit.
337  *
338  * Atomically clear bit number @a bit of @a target and return its old value.
339  * The target may be a single atomic variable or an array of them.
340  *
341  * @param target Address of atomic variable or array.
342  * @param bit Bit number (starting from 0).
343  *
344  * @return 1 if the bit was set, 0 if it wasn't.
345  */
atomic_test_and_clear_bit(atomic_t * target,int bit)346 static inline int atomic_test_and_clear_bit(atomic_t *target, int bit)
347 {
348 	atomic_val_t mask = ATOMIC_MASK(bit);
349 	atomic_val_t old;
350 
351 	old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
352 
353 	return (old & mask) != 0;
354 }
355 
356 /**
357  * @brief Atomically set a bit.
358  *
359  * Atomically set bit number @a bit of @a target and return its old value.
360  * The target may be a single atomic variable or an array of them.
361  *
362  * @param target Address of atomic variable or array.
363  * @param bit Bit number (starting from 0).
364  *
365  * @return 1 if the bit was set, 0 if it wasn't.
366  */
atomic_test_and_set_bit(atomic_t * target,int bit)367 static inline int atomic_test_and_set_bit(atomic_t *target, int bit)
368 {
369 	atomic_val_t mask = ATOMIC_MASK(bit);
370 	atomic_val_t old;
371 
372 	old = atomic_or(ATOMIC_ELEM(target, bit), mask);
373 
374 	return (old & mask) != 0;
375 }
376 
377 /**
378  * @brief Atomically clear a bit.
379  *
380  * Atomically clear bit number @a bit of @a target.
381  * The target may be a single atomic variable or an array of them.
382  *
383  * @param target Address of atomic variable or array.
384  * @param bit Bit number (starting from 0).
385  *
386  * @return N/A
387  */
atomic_clear_bit(atomic_t * target,int bit)388 static inline void atomic_clear_bit(atomic_t *target, int bit)
389 {
390 	atomic_val_t mask = ATOMIC_MASK(bit);
391 
392 	atomic_and(ATOMIC_ELEM(target, bit), ~mask);
393 }
394 
395 /**
396  * @brief Atomically set a bit.
397  *
398  * Atomically set bit number @a bit of @a target.
399  * The target may be a single atomic variable or an array of them.
400  *
401  * @param target Address of atomic variable or array.
402  * @param bit Bit number (starting from 0).
403  *
404  * @return N/A
405  */
atomic_set_bit(atomic_t * target,int bit)406 static inline void atomic_set_bit(atomic_t *target, int bit)
407 {
408 	atomic_val_t mask = ATOMIC_MASK(bit);
409 
410 	atomic_or(ATOMIC_ELEM(target, bit), mask);
411 }
412 
atomic_set_bit_to(atomic_t * target,int bit,bool val)413 static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
414 {
415 	atomic_val_t mask = ATOMIC_MASK(bit);
416 
417 	atomic_or(ATOMIC_ELEM(target, bit), mask);
418 
419     if (val)
420     {
421         atomic_or(ATOMIC_ELEM(target, bit), mask);
422     }
423     else
424     {
425         atomic_and(ATOMIC_ELEM(target, bit), ~mask);
426     }
427 }
428 
429 /**
430  * @}
431  */
432 
433 #ifdef __cplusplus
434 }
435 #endif
436 
437 #endif /* __ATOMIC_H__ */
438