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.
44 As <atomic.h> macros are usually heavily nested and often use local
45 variables to make sure side-effects are evaluated properly, use for
46 macro local variables a per-macro unique prefix. This file uses
47 __atgN_ prefix where N is different in each macro. */
51 #include <bits/atomic.h>
53 /* Wrapper macros to call pre_NN_post (mem, ...) where NN is the
54 bit width of *MEM. The calling macro puts parens around MEM
55 and following args. */
56 #define __atomic_val_bysize(pre, post, mem, ...) \
58 __typeof (*mem) __atg1_result; \
59 if (sizeof (*mem) == 1) \
60 __atg1_result = pre##_8_##post (mem, __VA_ARGS__); \
61 else if (sizeof (*mem) == 2) \
62 __atg1_result = pre##_16_##post (mem, __VA_ARGS__); \
63 else if (sizeof (*mem) == 4) \
64 __atg1_result = pre##_32_##post (mem, __VA_ARGS__); \
65 else if (sizeof (*mem) == 8) \
66 __atg1_result = pre##_64_##post (mem, __VA_ARGS__); \
71 #define __atomic_bool_bysize(pre, post, mem, ...) \
74 if (sizeof (*mem) == 1) \
75 __atg2_result = pre##_8_##post (mem, __VA_ARGS__); \
76 else if (sizeof (*mem) == 2) \
77 __atg2_result = pre##_16_##post (mem, __VA_ARGS__); \
78 else if (sizeof (*mem) == 4) \
79 __atg2_result = pre##_32_##post (mem, __VA_ARGS__); \
80 else if (sizeof (*mem) == 8) \
81 __atg2_result = pre##_64_##post (mem, __VA_ARGS__); \
88 /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
89 Return the old *MEM value. */
90 #if !defined atomic_compare_and_exchange_val_acq \
91 && defined __arch_compare_and_exchange_val_32_acq
92 # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
93 __atomic_val_bysize (__arch_compare_and_exchange_val,acq, \
98 #if !defined catomic_compare_and_exchange_val_acq \
99 && defined __arch_c_compare_and_exchange_val_32_acq
100 # define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
101 __atomic_val_bysize (__arch_c_compare_and_exchange_val,acq, \
104 # define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
105 atomic_compare_and_exchange_val_acq (mem, newval, oldval)
109 #ifndef atomic_compare_and_exchange_val_rel
110 # define atomic_compare_and_exchange_val_rel(mem, newval, oldval) \
111 atomic_compare_and_exchange_val_acq (mem, newval, oldval)
115 #ifndef catomic_compare_and_exchange_val_rel
116 # define catomic_compare_and_exchange_val_rel(mem, newval, oldval) \
117 atomic_compare_and_exchange_val_acq (mem, newval, oldval)
121 /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
122 Return zero if *MEM was changed or non-zero if no exchange happened. */
123 #ifndef atomic_compare_and_exchange_bool_acq
124 # ifdef __arch_compare_and_exchange_bool_32_acq
125 # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
126 __atomic_bool_bysize (__arch_compare_and_exchange_bool,acq, \
129 # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
130 ({ /* Cannot use __oldval here, because macros later in this file might \
131 call this macro with __oldval argument. */ \
132 __typeof (oldval) __atg3_old = (oldval); \
133 atomic_compare_and_exchange_val_acq (mem, newval, __atg3_old) \
140 #ifndef catomic_compare_and_exchange_bool_acq
141 # ifdef __arch_c_compare_and_exchange_bool_32_acq
142 # define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
143 __atomic_bool_bysize (__arch_c_compare_and_exchange_bool,acq, \
146 # define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
147 ({ /* Cannot use __oldval here, because macros later in this file might \
148 call this macro with __oldval argument. */ \
149 __typeof (oldval) __atg4_old = (oldval); \
150 catomic_compare_and_exchange_val_acq (mem, newval, __atg4_old) \
157 #ifndef atomic_compare_and_exchange_bool_rel
158 # define atomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
159 atomic_compare_and_exchange_bool_acq (mem, newval, oldval)
163 #ifndef catomic_compare_and_exchange_bool_rel
164 # define catomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
165 catomic_compare_and_exchange_bool_acq (mem, newval, oldval)
169 /* Store NEWVALUE in *MEM and return the old value. */
170 #ifndef atomic_exchange_acq
171 # define atomic_exchange_acq(mem, newvalue) \
172 ({ __typeof (*(mem)) __atg5_oldval; \
173 __typeof (mem) __atg5_memp = (mem); \
174 __typeof (*(mem)) __atg5_value = (newvalue); \
177 __atg5_oldval = *__atg5_memp; \
178 while (__builtin_expect \
179 (atomic_compare_and_exchange_bool_acq (__atg5_memp, __atg5_value, \
180 __atg5_oldval), 0)); \
185 #ifndef atomic_exchange_rel
186 # define atomic_exchange_rel(mem, newvalue) atomic_exchange_acq (mem, newvalue)
190 /* Add VALUE to *MEM and return the old value of *MEM. */
191 #ifndef atomic_exchange_and_add
192 # define atomic_exchange_and_add(mem, value) \
193 ({ __typeof (*(mem)) __atg6_oldval; \
194 __typeof (mem) __atg6_memp = (mem); \
195 __typeof (*(mem)) __atg6_value = (value); \
198 __atg6_oldval = *__atg6_memp; \
199 while (__builtin_expect \
200 (atomic_compare_and_exchange_bool_acq (__atg6_memp, \
203 __atg6_oldval), 0)); \
209 #ifndef catomic_exchange_and_add
210 # define catomic_exchange_and_add(mem, value) \
211 ({ __typeof (*(mem)) __atg7_oldv; \
212 __typeof (mem) __atg7_memp = (mem); \
213 __typeof (*(mem)) __atg7_value = (value); \
216 __atg7_oldv = *__atg7_memp; \
217 while (__builtin_expect \
218 (catomic_compare_and_exchange_bool_acq (__atg7_memp, \
228 # define atomic_max(mem, value) \
230 __typeof (*(mem)) __atg8_oldval; \
231 __typeof (mem) __atg8_memp = (mem); \
232 __typeof (*(mem)) __atg8_value = (value); \
234 __atg8_oldval = *__atg8_memp; \
235 if (__atg8_oldval >= __atg8_value) \
237 } while (__builtin_expect \
238 (atomic_compare_and_exchange_bool_acq (__atg8_memp, __atg8_value,\
239 __atg8_oldval), 0)); \
245 # define catomic_max(mem, value) \
247 __typeof (*(mem)) __atg9_oldv; \
248 __typeof (mem) __atg9_memp = (mem); \
249 __typeof (*(mem)) __atg9_value = (value); \
251 __atg9_oldv = *__atg9_memp; \
252 if (__atg9_oldv >= __atg9_value) \
254 } while (__builtin_expect \
255 (catomic_compare_and_exchange_bool_acq (__atg9_memp, \
263 # define atomic_min(mem, value) \
265 __typeof (*(mem)) __atg10_oldval; \
266 __typeof (mem) __atg10_memp = (mem); \
267 __typeof (*(mem)) __atg10_value = (value); \
269 __atg10_oldval = *__atg10_memp; \
270 if (__atg10_oldval <= __atg10_value) \
272 } while (__builtin_expect \
273 (atomic_compare_and_exchange_bool_acq (__atg10_memp, \
275 __atg10_oldval), 0)); \
281 # define atomic_add(mem, value) (void) atomic_exchange_and_add ((mem), (value))
286 # define catomic_add(mem, value) \
287 (void) catomic_exchange_and_add ((mem), (value))
291 #ifndef atomic_increment
292 # define atomic_increment(mem) atomic_add ((mem), 1)
296 #ifndef catomic_increment
297 # define catomic_increment(mem) catomic_add ((mem), 1)
301 #ifndef atomic_increment_val
302 # define atomic_increment_val(mem) (atomic_exchange_and_add ((mem), 1) + 1)
306 #ifndef catomic_increment_val
307 # define catomic_increment_val(mem) (catomic_exchange_and_add ((mem), 1) + 1)
311 /* Add one to *MEM and return true iff it's now zero. */
312 #ifndef atomic_increment_and_test
313 # define atomic_increment_and_test(mem) \
314 (atomic_exchange_and_add ((mem), 1) + 1 == 0)
318 #ifndef atomic_decrement
319 # define atomic_decrement(mem) atomic_add ((mem), -1)
323 #ifndef catomic_decrement
324 # define catomic_decrement(mem) catomic_add ((mem), -1)
328 #ifndef atomic_decrement_val
329 # define atomic_decrement_val(mem) (atomic_exchange_and_add ((mem), -1) - 1)
333 #ifndef catomic_decrement_val
334 # define catomic_decrement_val(mem) (catomic_exchange_and_add ((mem), -1) - 1)
338 /* Subtract 1 from *MEM and return true iff it's now zero. */
339 #ifndef atomic_decrement_and_test
340 # define atomic_decrement_and_test(mem) \
341 (atomic_exchange_and_add ((mem), -1) == 1)
345 /* Decrement *MEM if it is > 0, and return the old value. */
346 #ifndef atomic_decrement_if_positive
347 # define atomic_decrement_if_positive(mem) \
348 ({ __typeof (*(mem)) __atg11_oldval; \
349 __typeof (mem) __atg11_memp = (mem); \
353 __atg11_oldval = *__atg11_memp; \
354 if (__builtin_expect (__atg11_oldval <= 0, 0)) \
357 while (__builtin_expect \
358 (atomic_compare_and_exchange_bool_acq (__atg11_memp, \
359 __atg11_oldval - 1, \
360 __atg11_oldval), 0)); \
365 #ifndef atomic_add_negative
366 # define atomic_add_negative(mem, value) \
367 ({ __typeof (value) __atg12_value = (value); \
368 atomic_exchange_and_add (mem, __atg12_value) < -__atg12_value; })
372 #ifndef atomic_add_zero
373 # define atomic_add_zero(mem, value) \
374 ({ __typeof (value) __atg13_value = (value); \
375 atomic_exchange_and_add (mem, __atg13_value) == -__atg13_value; })
379 #ifndef atomic_bit_set
380 # define atomic_bit_set(mem, bit) \
381 (void) atomic_bit_test_set(mem, bit)
385 #ifndef atomic_bit_test_set
386 # define atomic_bit_test_set(mem, bit) \
387 ({ __typeof (*(mem)) __atg14_old; \
388 __typeof (mem) __atg14_memp = (mem); \
389 __typeof (*(mem)) __atg14_mask = ((__typeof (*(mem))) 1 << (bit)); \
392 __atg14_old = (*__atg14_memp); \
393 while (__builtin_expect \
394 (atomic_compare_and_exchange_bool_acq (__atg14_memp, \
395 __atg14_old | __atg14_mask,\
398 __atg14_old & __atg14_mask; })
401 /* Atomically *mem &= mask. */
403 # define atomic_and(mem, mask) \
405 __typeof (*(mem)) __atg15_old; \
406 __typeof (mem) __atg15_memp = (mem); \
407 __typeof (*(mem)) __atg15_mask = (mask); \
410 __atg15_old = (*__atg15_memp); \
411 while (__builtin_expect \
412 (atomic_compare_and_exchange_bool_acq (__atg15_memp, \
413 __atg15_old & __atg15_mask, \
418 /* Atomically *mem &= mask and return the old value of *mem. */
419 #ifndef atomic_and_val
420 # define atomic_and_val(mem, mask) \
421 ({ __typeof (*(mem)) __atg16_old; \
422 __typeof (mem) __atg16_memp = (mem); \
423 __typeof (*(mem)) __atg16_mask = (mask); \
426 __atg16_old = (*__atg16_memp); \
427 while (__builtin_expect \
428 (atomic_compare_and_exchange_bool_acq (__atg16_memp, \
429 __atg16_old & __atg16_mask,\
435 /* Atomically *mem |= mask and return the old value of *mem. */
437 # define atomic_or(mem, mask) \
439 __typeof (*(mem)) __atg17_old; \
440 __typeof (mem) __atg17_memp = (mem); \
441 __typeof (*(mem)) __atg17_mask = (mask); \
444 __atg17_old = (*__atg17_memp); \
445 while (__builtin_expect \
446 (atomic_compare_and_exchange_bool_acq (__atg17_memp, \
447 __atg17_old | __atg17_mask, \
453 # define catomic_or(mem, mask) \
455 __typeof (*(mem)) __atg18_old; \
456 __typeof (mem) __atg18_memp = (mem); \
457 __typeof (*(mem)) __atg18_mask = (mask); \
460 __atg18_old = (*__atg18_memp); \
461 while (__builtin_expect \
462 (catomic_compare_and_exchange_bool_acq (__atg18_memp, \
463 __atg18_old | __atg18_mask,\
468 /* Atomically *mem |= mask and return the old value of *mem. */
469 #ifndef atomic_or_val
470 # define atomic_or_val(mem, mask) \
471 ({ __typeof (*(mem)) __atg19_old; \
472 __typeof (mem) __atg19_memp = (mem); \
473 __typeof (*(mem)) __atg19_mask = (mask); \
476 __atg19_old = (*__atg19_memp); \
477 while (__builtin_expect \
478 (atomic_compare_and_exchange_bool_acq (__atg19_memp, \
479 __atg19_old | __atg19_mask,\
485 #ifndef atomic_full_barrier
486 # define atomic_full_barrier() __asm ("" ::: "memory")
490 #ifndef atomic_read_barrier
491 # define atomic_read_barrier() atomic_full_barrier ()
495 #ifndef atomic_write_barrier
496 # define atomic_write_barrier() atomic_full_barrier ()
501 # define atomic_delay() do { /* nothing */ } while (0)
504 #endif /* atomic.h */