1 /* Internal macros for atomic operations for GNU C Library.
2 Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 /* This header defines three types of macros:
26 - atomic arithmetic and logic operation on memory. They all
27 have the prefix "atomic_".
29 - conditionally atomic operations of the same kinds. These
30 always behave identical but can be faster when atomicity
31 is not really needed since only one thread has access to
32 the memory location. In that case the code is slower in
33 the multi-thread case. The interfaces have the prefix
36 - support functions like barriers. They also have the preifx
39 Architectures must provide a few lowlevel macros (the compare
40 and exchange definitions). All others are optional. They
41 should only be provided if the architecture has specific
42 support for the operation. */
46 #include <bits/atomic.h>
48 /* Wrapper macros to call pre_NN_post (mem, ...) where NN is the
49 bit width of *MEM. The calling macro puts parens around MEM
50 and following args. */
51 #define __atomic_val_bysize(pre, post, mem, ...) \
53 __typeof (*mem) __result; \
54 if (sizeof (*mem) == 1) \
55 __result = pre##_8_##post (mem, __VA_ARGS__); \
56 else if (sizeof (*mem) == 2) \
57 __result = pre##_16_##post (mem, __VA_ARGS__); \
58 else if (sizeof (*mem) == 4) \
59 __result = pre##_32_##post (mem, __VA_ARGS__); \
60 else if (sizeof (*mem) == 8) \
61 __result = pre##_64_##post (mem, __VA_ARGS__); \
66 #define __atomic_bool_bysize(pre, post, mem, ...) \
69 if (sizeof (*mem) == 1) \
70 __result = pre##_8_##post (mem, __VA_ARGS__); \
71 else if (sizeof (*mem) == 2) \
72 __result = pre##_16_##post (mem, __VA_ARGS__); \
73 else if (sizeof (*mem) == 4) \
74 __result = pre##_32_##post (mem, __VA_ARGS__); \
75 else if (sizeof (*mem) == 8) \
76 __result = pre##_64_##post (mem, __VA_ARGS__); \
83 /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
84 Return the old *MEM value. */
85 #if !defined atomic_compare_and_exchange_val_acq \
86 && defined __arch_compare_and_exchange_val_32_acq
87 # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
88 __atomic_val_bysize (__arch_compare_and_exchange_val,acq, \
93 #if !defined catomic_compare_and_exchange_val_acq \
94 && defined __arch_c_compare_and_exchange_val_32_acq
95 # define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
96 __atomic_val_bysize (__arch_c_compare_and_exchange_val,acq, \
99 # define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
100 atomic_compare_and_exchange_val_acq (mem, newval, oldval)
104 #ifndef atomic_compare_and_exchange_val_rel
105 # define atomic_compare_and_exchange_val_rel(mem, newval, oldval) \
106 atomic_compare_and_exchange_val_acq (mem, newval, oldval)
110 #ifndef catomic_compare_and_exchange_val_rel
111 # define catomic_compare_and_exchange_val_rel(mem, newval, oldval) \
112 atomic_compare_and_exchange_val_acq (mem, newval, oldval)
116 /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
117 Return zero if *MEM was changed or non-zero if no exchange happened. */
118 #ifndef atomic_compare_and_exchange_bool_acq
119 # ifdef __arch_compare_and_exchange_bool_32_acq
120 # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
121 __atomic_bool_bysize (__arch_compare_and_exchange_bool,acq, \
124 # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
125 ({ /* Cannot use __oldval here, because macros later in this file might \
126 call this macro with __oldval argument. */ \
127 __typeof (oldval) __old = (oldval); \
128 atomic_compare_and_exchange_val_acq (mem, newval, __old) != __old; \
134 #ifndef catomic_compare_and_exchange_bool_acq
135 # ifdef __arch_c_compare_and_exchange_bool_32_acq
136 # define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
137 __atomic_bool_bysize (__arch_c_compare_and_exchange_bool,acq, \
140 # define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
141 ({ /* Cannot use __oldval here, because macros later in this file might \
142 call this macro with __oldval argument. */ \
143 __typeof (oldval) __old = (oldval); \
144 catomic_compare_and_exchange_val_acq (mem, newval, __old) != __old; \
150 #ifndef atomic_compare_and_exchange_bool_rel
151 # define atomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
152 atomic_compare_and_exchange_bool_acq (mem, newval, oldval)
156 #ifndef catomic_compare_and_exchange_bool_rel
157 # define catomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
158 catomic_compare_and_exchange_bool_acq (mem, newval, oldval)
162 /* Store NEWVALUE in *MEM and return the old value. */
163 #ifndef atomic_exchange_acq
164 # define atomic_exchange_acq(mem, newvalue) \
165 ({ __typeof (*(mem)) __oldval; \
166 __typeof (mem) __memp = (mem); \
167 __typeof (*(mem)) __value = (newvalue); \
170 __oldval = *__memp; \
171 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
179 #ifndef atomic_exchange_rel
180 # define atomic_exchange_rel(mem, newvalue) atomic_exchange_acq (mem, newvalue)
184 /* Add VALUE to *MEM and return the old value of *MEM. */
185 #ifndef atomic_exchange_and_add
186 # define atomic_exchange_and_add(mem, value) \
187 ({ __typeof (*(mem)) __oldval; \
188 __typeof (mem) __memp = (mem); \
189 __typeof (*(mem)) __value = (value); \
192 __oldval = *__memp; \
193 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
203 #ifndef catomic_exchange_and_add
204 # define catomic_exchange_and_add(mem, value) \
205 ({ __typeof (*(mem)) __oldv; \
206 __typeof (mem) __memp = (mem); \
207 __typeof (*(mem)) __value = (value); \
211 while (__builtin_expect (catomic_compare_and_exchange_bool_acq (__memp, \
222 # define atomic_max(mem, value) \
224 __typeof (*(mem)) __oldval; \
225 __typeof (mem) __memp = (mem); \
226 __typeof (*(mem)) __value = (value); \
228 __oldval = *__memp; \
229 if (__oldval >= __value) \
231 } while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
240 # define catomic_max(mem, value) \
242 __typeof (*(mem)) __oldv; \
243 __typeof (mem) __memp = (mem); \
244 __typeof (*(mem)) __value = (value); \
247 if (__oldv >= __value) \
249 } while (__builtin_expect (catomic_compare_and_exchange_bool_acq (__memp, \
258 # define atomic_min(mem, value) \
260 __typeof (*(mem)) __oldval; \
261 __typeof (mem) __memp = (mem); \
262 __typeof (*(mem)) __value = (value); \
264 __oldval = *__memp; \
265 if (__oldval <= __value) \
267 } while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
276 # define atomic_add(mem, value) (void) atomic_exchange_and_add ((mem), (value))
281 # define catomic_add(mem, value) \
282 (void) catomic_exchange_and_add ((mem), (value))
286 #ifndef atomic_increment
287 # define atomic_increment(mem) atomic_add ((mem), 1)
291 #ifndef catomic_increment
292 # define catomic_increment(mem) catomic_add ((mem), 1)
296 #ifndef atomic_increment_val
297 # define atomic_increment_val(mem) (atomic_exchange_and_add ((mem), 1) + 1)
301 #ifndef catomic_increment_val
302 # define catomic_increment_val(mem) (catomic_exchange_and_add ((mem), 1) + 1)
306 /* Add one to *MEM and return true iff it's now zero. */
307 #ifndef atomic_increment_and_test
308 # define atomic_increment_and_test(mem) \
309 (atomic_exchange_and_add ((mem), 1) + 1 == 0)
313 #ifndef atomic_decrement
314 # define atomic_decrement(mem) atomic_add ((mem), -1)
318 #ifndef catomic_decrement
319 # define catomic_decrement(mem) catomic_add ((mem), -1)
323 #ifndef atomic_decrement_val
324 # define atomic_decrement_val(mem) (atomic_exchange_and_add ((mem), -1) - 1)
328 #ifndef catomic_decrement_val
329 # define catomic_decrement_val(mem) (catomic_exchange_and_add ((mem), -1) - 1)
333 /* Subtract 1 from *MEM and return true iff it's now zero. */
334 #ifndef atomic_decrement_and_test
335 # define atomic_decrement_and_test(mem) \
336 (atomic_exchange_and_add ((mem), -1) == 1)
340 /* Decrement *MEM if it is > 0, and return the old value. */
341 #ifndef atomic_decrement_if_positive
342 # define atomic_decrement_if_positive(mem) \
343 ({ __typeof (*(mem)) __oldval; \
344 __typeof (mem) __memp = (mem); \
348 __oldval = *__memp; \
349 if (__builtin_expect (__oldval <= 0, 0)) \
352 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
361 #ifndef atomic_add_negative
362 # define atomic_add_negative(mem, value) \
363 ({ __typeof (value) __aan_value = (value); \
364 atomic_exchange_and_add (mem, __aan_value) < -__aan_value; })
368 #ifndef atomic_add_zero
369 # define atomic_add_zero(mem, value) \
370 ({ __typeof (value) __aaz_value = (value); \
371 atomic_exchange_and_add (mem, __aaz_value) == -__aaz_value; })
375 #ifndef atomic_bit_set
376 # define atomic_bit_set(mem, bit) \
377 (void) atomic_bit_test_set(mem, bit)
381 #ifndef atomic_bit_test_set
382 # define atomic_bit_test_set(mem, bit) \
383 ({ __typeof (*(mem)) __oldval; \
384 __typeof (mem) __memp = (mem); \
385 __typeof (*(mem)) __mask = ((__typeof (*(mem))) 1 << (bit)); \
388 __oldval = (*__memp); \
389 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
395 __oldval & __mask; })
398 /* Atomically *mem &= mask. */
400 # define atomic_and(mem, mask) \
402 __typeof (*(mem)) __oldval; \
403 __typeof (mem) __memp = (mem); \
404 __typeof (*(mem)) __mask = (mask); \
407 __oldval = (*__memp); \
408 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
416 /* Atomically *mem &= mask and return the old value of *mem. */
417 #ifndef atomic_and_val
418 # define atomic_and_val(mem, mask) \
419 ({ __typeof (*(mem)) __oldval; \
420 __typeof (mem) __memp = (mem); \
421 __typeof (*(mem)) __mask = (mask); \
424 __oldval = (*__memp); \
425 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
434 /* Atomically *mem |= mask and return the old value of *mem. */
436 # define atomic_or(mem, mask) \
438 __typeof (*(mem)) __oldval; \
439 __typeof (mem) __memp = (mem); \
440 __typeof (*(mem)) __mask = (mask); \
443 __oldval = (*__memp); \
444 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
453 # define catomic_or(mem, mask) \
455 __typeof (*(mem)) __oldval; \
456 __typeof (mem) __memp = (mem); \
457 __typeof (*(mem)) __mask = (mask); \
460 __oldval = (*__memp); \
461 while (__builtin_expect (catomic_compare_and_exchange_bool_acq (__memp, \
469 /* Atomically *mem |= mask and return the old value of *mem. */
470 #ifndef atomic_or_val
471 # define atomic_or_val(mem, mask) \
472 ({ __typeof (*(mem)) __oldval; \
473 __typeof (mem) __memp = (mem); \
474 __typeof (*(mem)) __mask = (mask); \
477 __oldval = (*__memp); \
478 while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp, \
487 #ifndef atomic_full_barrier
488 # define atomic_full_barrier() __asm ("" ::: "memory")
492 #ifndef atomic_read_barrier
493 # define atomic_read_barrier() atomic_full_barrier ()
497 #ifndef atomic_write_barrier
498 # define atomic_write_barrier() atomic_full_barrier ()
503 # define atomic_delay() do { /* nothing */ } while (0)
506 #endif /* atomic.h */