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