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