• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
atomic_test_bit(const atomic_t * target,int bit)288 static inline int atomic_test_bit(const atomic_t *target, int bit)
289 {
290     atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
291     return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
292 }
293 
294 /**
295  * @brief Atomically test and clear a bit.
296  *
297  * Atomically clear bit number @a bit of @a target and return its old value.
298  * The target may be a single atomic variable or an array of them.
299  *
300  * @param target Address of atomic variable or array.
301  * @param bit Bit number (starting from 0).
302  *
303  * @return 1 if the bit was set, 0 if it wasn't.
304  */
atomic_test_and_clear_bit(atomic_t * target,int bit)305 static inline int atomic_test_and_clear_bit(atomic_t *target, int bit)
306 {
307     atomic_val_t mask = ATOMIC_MASK(bit);
308     atomic_val_t old;
309     old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
310     return (old & mask) != 0;
311 }
312 
313 /**
314  * @brief Atomically set a bit.
315  *
316  * Atomically set bit number @a bit of @a target and return its old value.
317  * The target may be a single atomic variable or an array of them.
318  *
319  * @param target Address of atomic variable or array.
320  * @param bit Bit number (starting from 0).
321  *
322  * @return 1 if the bit was set, 0 if it wasn't.
323  */
atomic_test_and_set_bit(atomic_t * target,int bit)324 static inline int atomic_test_and_set_bit(atomic_t *target, int bit)
325 {
326     atomic_val_t mask = ATOMIC_MASK(bit);
327     atomic_val_t old;
328     old = atomic_or(ATOMIC_ELEM(target, bit), mask);
329     return (old & mask) != 0;
330 }
331 
332 /**
333  * @brief Atomically clear a bit.
334  *
335  * Atomically clear bit number @a bit of @a target.
336  * The target may be a single atomic variable or an array of them.
337  *
338  * @param target Address of atomic variable or array.
339  * @param bit Bit number (starting from 0).
340  *
341  * @return N/A
342  */
atomic_clear_bit(atomic_t * target,int bit)343 static inline void atomic_clear_bit(atomic_t *target, int bit)
344 {
345     atomic_val_t mask = ATOMIC_MASK(bit);
346     atomic_and(ATOMIC_ELEM(target, bit), ~mask);
347 }
348 
349 /**
350  * @brief Atomically set a bit.
351  *
352  * Atomically set bit number @a bit of @a target.
353  * The target may be a single atomic variable or an array of them.
354  *
355  * @param target Address of atomic variable or array.
356  * @param bit Bit number (starting from 0).
357  *
358  * @return N/A
359  */
atomic_set_bit(atomic_t * target,int bit)360 static inline void atomic_set_bit(atomic_t *target, int bit)
361 {
362     atomic_val_t mask = ATOMIC_MASK(bit);
363     atomic_or(ATOMIC_ELEM(target, bit), mask);
364 }
365 
366 /**
367 * @brief Atomically set a bit to a given value.
368 *
369 * Atomically set bit number @a bit of @a target to value @a val.
370 * The target may be a single atomic variable or an array of them.
371 *
372 * @param target Address of atomic variable or array.
373 * @param bit Bit number (starting from 0).
374 * @param val true for 1, false for 0.
375 *
376 * @return N/A
377 */
atomic_set_bit_to(atomic_t * target,int bit,bool val)378 static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
379 {
380     atomic_val_t mask = ATOMIC_MASK(bit);
381 
382     if (val) {
383         (void)atomic_or(ATOMIC_ELEM(target, bit), mask);
384     } else {
385         (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
386     }
387 }
388 
389 /**
390  * @}
391  */
392 
393 #ifdef __cplusplus
394 }
395 #endif
396 
397 #endif /* __ATOMIC_H__ */
398