Back to index

glibc  2.9
atomic.h
Go to the documentation of this file.
00001 /* Internal macros for atomic operations for GNU C Library.
00002    Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #ifndef _ATOMIC_H
00022 #define _ATOMIC_H    1
00023 
00024 /* This header defines three types of macros:
00025 
00026    - atomic arithmetic and logic operation on memory.  They all
00027      have the prefix "atomic_".
00028 
00029    - conditionally atomic operations of the same kinds.  These
00030      always behave identical but can be faster when atomicity
00031      is not really needed since only one thread has access to
00032      the memory location.  In that case the code is slower in
00033      the multi-thread case.  The interfaces have the prefix
00034      "catomic_".
00035 
00036    - support functions like barriers.  They also have the preifx
00037      "atomic_".
00038 
00039    Architectures must provide a few lowlevel macros (the compare
00040    and exchange definitions).  All others are optional.  They
00041    should only be provided if the architecture has specific
00042    support for the operation.
00043 
00044    As <atomic.h> macros are usually heavily nested and often use local
00045    variables to make sure side-effects are evaluated properly, use for
00046    macro local variables a per-macro unique prefix.  This file uses
00047    __atgN_ prefix where N is different in each macro.  */
00048 
00049 #include <stdlib.h>
00050 
00051 #include <bits/atomic.h>
00052 
00053 /* Wrapper macros to call pre_NN_post (mem, ...) where NN is the
00054    bit width of *MEM.  The calling macro puts parens around MEM
00055    and following args.  */
00056 #define __atomic_val_bysize(pre, post, mem, ...)                     \
00057   ({                                                                 \
00058     __typeof (*mem) __atg1_result;                                   \
00059     if (sizeof (*mem) == 1)                                          \
00060       __atg1_result = pre##_8_##post (mem, __VA_ARGS__);                    \
00061     else if (sizeof (*mem) == 2)                                     \
00062       __atg1_result = pre##_16_##post (mem, __VA_ARGS__);                   \
00063     else if (sizeof (*mem) == 4)                                     \
00064       __atg1_result = pre##_32_##post (mem, __VA_ARGS__);                   \
00065     else if (sizeof (*mem) == 8)                                     \
00066       __atg1_result = pre##_64_##post (mem, __VA_ARGS__);                   \
00067     else                                                             \
00068       abort ();                                                             \
00069     __atg1_result;                                                   \
00070   })
00071 #define __atomic_bool_bysize(pre, post, mem, ...)                           \
00072   ({                                                                 \
00073     int __atg2_result;                                                      \
00074     if (sizeof (*mem) == 1)                                          \
00075       __atg2_result = pre##_8_##post (mem, __VA_ARGS__);                    \
00076     else if (sizeof (*mem) == 2)                                     \
00077       __atg2_result = pre##_16_##post (mem, __VA_ARGS__);                   \
00078     else if (sizeof (*mem) == 4)                                     \
00079       __atg2_result = pre##_32_##post (mem, __VA_ARGS__);                   \
00080     else if (sizeof (*mem) == 8)                                     \
00081       __atg2_result = pre##_64_##post (mem, __VA_ARGS__);                   \
00082     else                                                             \
00083       abort ();                                                             \
00084     __atg2_result;                                                   \
00085   })
00086 
00087 
00088 /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
00089    Return the old *MEM value.  */
00090 #if !defined atomic_compare_and_exchange_val_acq \
00091     && defined __arch_compare_and_exchange_val_32_acq
00092 # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
00093   __atomic_val_bysize (__arch_compare_and_exchange_val,acq,                 \
00094                      mem, newval, oldval)
00095 #endif
00096 
00097 
00098 #if !defined catomic_compare_and_exchange_val_acq \
00099     && defined __arch_c_compare_and_exchange_val_32_acq
00100 # define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
00101   __atomic_val_bysize (__arch_c_compare_and_exchange_val,acq,               \
00102                      mem, newval, oldval)
00103 #else
00104 # define catomic_compare_and_exchange_val_acq(mem, newval, oldval) \
00105   atomic_compare_and_exchange_val_acq (mem, newval, oldval)
00106 #endif
00107 
00108 
00109 #ifndef atomic_compare_and_exchange_val_rel
00110 # define atomic_compare_and_exchange_val_rel(mem, newval, oldval)           \
00111   atomic_compare_and_exchange_val_acq (mem, newval, oldval)
00112 #endif
00113 
00114 
00115 #ifndef catomic_compare_and_exchange_val_rel
00116 # define catomic_compare_and_exchange_val_rel(mem, newval, oldval)          \
00117   atomic_compare_and_exchange_val_acq (mem, newval, oldval)
00118 #endif
00119 
00120 
00121 /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
00122    Return zero if *MEM was changed or non-zero if no exchange happened.  */
00123 #ifndef atomic_compare_and_exchange_bool_acq
00124 # ifdef __arch_compare_and_exchange_bool_32_acq
00125 #  define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
00126   __atomic_bool_bysize (__arch_compare_and_exchange_bool,acq,               \
00127                       mem, newval, oldval)
00128 #  else
00129 #   define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
00130   ({ /* Cannot use __oldval here, because macros later in this file might     \
00131        call this macro with __oldval argument.    */                        \
00132      __typeof (oldval) __atg3_old = (oldval);                               \
00133      atomic_compare_and_exchange_val_acq (mem, newval, __atg3_old)          \
00134        != __atg3_old;                                                       \
00135   })
00136 # endif
00137 #endif
00138 
00139 
00140 #ifndef catomic_compare_and_exchange_bool_acq
00141 # ifdef __arch_c_compare_and_exchange_bool_32_acq
00142 #  define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
00143   __atomic_bool_bysize (__arch_c_compare_and_exchange_bool,acq,                    \
00144                       mem, newval, oldval)
00145 #  else
00146 #   define catomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
00147   ({ /* Cannot use __oldval here, because macros later in this file might     \
00148        call this macro with __oldval argument.    */                        \
00149      __typeof (oldval) __atg4_old = (oldval);                               \
00150      catomic_compare_and_exchange_val_acq (mem, newval, __atg4_old)         \
00151        != __atg4_old;                                                       \
00152   })
00153 # endif
00154 #endif
00155 
00156 
00157 #ifndef atomic_compare_and_exchange_bool_rel
00158 # define atomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
00159   atomic_compare_and_exchange_bool_acq (mem, newval, oldval)
00160 #endif
00161 
00162 
00163 #ifndef catomic_compare_and_exchange_bool_rel
00164 # define catomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
00165   catomic_compare_and_exchange_bool_acq (mem, newval, oldval)
00166 #endif
00167 
00168 
00169 /* Store NEWVALUE in *MEM and return the old value.  */
00170 #ifndef atomic_exchange_acq
00171 # define atomic_exchange_acq(mem, newvalue) \
00172   ({ __typeof (*(mem)) __atg5_oldval;                                       \
00173      __typeof (mem) __atg5_memp = (mem);                             \
00174      __typeof (*(mem)) __atg5_value = (newvalue);                           \
00175                                                                      \
00176      do                                                                     \
00177        __atg5_oldval = *__atg5_memp;                                        \
00178      while (__builtin_expect                                                \
00179            (atomic_compare_and_exchange_bool_acq (__atg5_memp, __atg5_value, \
00180                                              __atg5_oldval), 0));           \
00181                                                                      \
00182      __atg5_oldval; })
00183 #endif
00184 
00185 #ifndef atomic_exchange_rel
00186 # define atomic_exchange_rel(mem, newvalue) atomic_exchange_acq (mem, newvalue)
00187 #endif
00188 
00189 
00190 /* Add VALUE to *MEM and return the old value of *MEM.  */
00191 #ifndef atomic_exchange_and_add
00192 # define atomic_exchange_and_add(mem, value) \
00193   ({ __typeof (*(mem)) __atg6_oldval;                                       \
00194      __typeof (mem) __atg6_memp = (mem);                             \
00195      __typeof (*(mem)) __atg6_value = (value);                              \
00196                                                                      \
00197      do                                                                     \
00198        __atg6_oldval = *__atg6_memp;                                        \
00199      while (__builtin_expect                                                \
00200            (atomic_compare_and_exchange_bool_acq (__atg6_memp,              \
00201                                              __atg6_oldval           \
00202                                              + __atg6_value,         \
00203                                              __atg6_oldval), 0));           \
00204                                                                      \
00205      __atg6_oldval; })
00206 #endif
00207 
00208 
00209 #ifndef catomic_exchange_and_add
00210 # define catomic_exchange_and_add(mem, value) \
00211   ({ __typeof (*(mem)) __atg7_oldv;                                         \
00212      __typeof (mem) __atg7_memp = (mem);                             \
00213      __typeof (*(mem)) __atg7_value = (value);                              \
00214                                                                      \
00215      do                                                                     \
00216        __atg7_oldv = *__atg7_memp;                                   \
00217      while (__builtin_expect                                                \
00218            (catomic_compare_and_exchange_bool_acq (__atg7_memp,             \
00219                                               __atg7_oldv                   \
00220                                               + __atg7_value,        \
00221                                               __atg7_oldv), 0));            \
00222                                                                      \
00223      __atg7_oldv; })
00224 #endif
00225 
00226 
00227 #ifndef atomic_max
00228 # define atomic_max(mem, value) \
00229   do {                                                               \
00230     __typeof (*(mem)) __atg8_oldval;                                        \
00231     __typeof (mem) __atg8_memp = (mem);                                     \
00232     __typeof (*(mem)) __atg8_value = (value);                               \
00233     do {                                                             \
00234       __atg8_oldval = *__atg8_memp;                                         \
00235       if (__atg8_oldval >= __atg8_value)                             \
00236        break;                                                        \
00237     } while (__builtin_expect                                               \
00238             (atomic_compare_and_exchange_bool_acq (__atg8_memp, __atg8_value,\
00239                                               __atg8_oldval), 0));      \
00240   } while (0)
00241 #endif
00242 
00243 
00244 #ifndef catomic_max
00245 # define catomic_max(mem, value) \
00246   do {                                                               \
00247     __typeof (*(mem)) __atg9_oldv;                                   \
00248     __typeof (mem) __atg9_memp = (mem);                                     \
00249     __typeof (*(mem)) __atg9_value = (value);                               \
00250     do {                                                             \
00251       __atg9_oldv = *__atg9_memp;                                    \
00252       if (__atg9_oldv >= __atg9_value)                                      \
00253        break;                                                        \
00254     } while (__builtin_expect                                               \
00255             (catomic_compare_and_exchange_bool_acq (__atg9_memp,            \
00256                                                __atg9_value,         \
00257                                                __atg9_oldv), 0));           \
00258   } while (0)
00259 #endif
00260 
00261 
00262 #ifndef atomic_min
00263 # define atomic_min(mem, value) \
00264   do {                                                               \
00265     __typeof (*(mem)) __atg10_oldval;                                       \
00266     __typeof (mem) __atg10_memp = (mem);                             \
00267     __typeof (*(mem)) __atg10_value = (value);                              \
00268     do {                                                             \
00269       __atg10_oldval = *__atg10_memp;                                       \
00270       if (__atg10_oldval <= __atg10_value)                                  \
00271        break;                                                        \
00272     } while (__builtin_expect                                               \
00273             (atomic_compare_and_exchange_bool_acq (__atg10_memp,            \
00274                                               __atg10_value,         \
00275                                               __atg10_oldval), 0));     \
00276   } while (0)
00277 #endif
00278 
00279 
00280 #ifndef atomic_add
00281 # define atomic_add(mem, value) (void) atomic_exchange_and_add ((mem), (value))
00282 #endif
00283 
00284 
00285 #ifndef catomic_add
00286 # define catomic_add(mem, value) \
00287   (void) catomic_exchange_and_add ((mem), (value))
00288 #endif
00289 
00290 
00291 #ifndef atomic_increment
00292 # define atomic_increment(mem) atomic_add ((mem), 1)
00293 #endif
00294 
00295 
00296 #ifndef catomic_increment
00297 # define catomic_increment(mem) catomic_add ((mem), 1)
00298 #endif
00299 
00300 
00301 #ifndef atomic_increment_val
00302 # define atomic_increment_val(mem) (atomic_exchange_and_add ((mem), 1) + 1)
00303 #endif
00304 
00305 
00306 #ifndef catomic_increment_val
00307 # define catomic_increment_val(mem) (catomic_exchange_and_add ((mem), 1) + 1)
00308 #endif
00309 
00310 
00311 /* Add one to *MEM and return true iff it's now zero.  */
00312 #ifndef atomic_increment_and_test
00313 # define atomic_increment_and_test(mem) \
00314   (atomic_exchange_and_add ((mem), 1) + 1 == 0)
00315 #endif
00316 
00317 
00318 #ifndef atomic_decrement
00319 # define atomic_decrement(mem) atomic_add ((mem), -1)
00320 #endif
00321 
00322 
00323 #ifndef catomic_decrement
00324 # define catomic_decrement(mem) catomic_add ((mem), -1)
00325 #endif
00326 
00327 
00328 #ifndef atomic_decrement_val
00329 # define atomic_decrement_val(mem) (atomic_exchange_and_add ((mem), -1) - 1)
00330 #endif
00331 
00332 
00333 #ifndef catomic_decrement_val
00334 # define catomic_decrement_val(mem) (catomic_exchange_and_add ((mem), -1) - 1)
00335 #endif
00336 
00337 
00338 /* Subtract 1 from *MEM and return true iff it's now zero.  */
00339 #ifndef atomic_decrement_and_test
00340 # define atomic_decrement_and_test(mem) \
00341   (atomic_exchange_and_add ((mem), -1) == 1)
00342 #endif
00343 
00344 
00345 /* Decrement *MEM if it is > 0, and return the old value.  */
00346 #ifndef atomic_decrement_if_positive
00347 # define atomic_decrement_if_positive(mem) \
00348   ({ __typeof (*(mem)) __atg11_oldval;                                      \
00349      __typeof (mem) __atg11_memp = (mem);                            \
00350                                                                      \
00351      do                                                                     \
00352        {                                                             \
00353         __atg11_oldval = *__atg11_memp;                              \
00354         if (__builtin_expect (__atg11_oldval <= 0, 0))                      \
00355           break;                                                     \
00356        }                                                             \
00357      while (__builtin_expect                                                \
00358            (atomic_compare_and_exchange_bool_acq (__atg11_memp,             \
00359                                              __atg11_oldval - 1,            \
00360                                              __atg11_oldval), 0));      \
00361      __atg11_oldval; })
00362 #endif
00363 
00364 
00365 #ifndef atomic_add_negative
00366 # define atomic_add_negative(mem, value)                             \
00367   ({ __typeof (value) __atg12_value = (value);                              \
00368      atomic_exchange_and_add (mem, __atg12_value) < -__atg12_value; })
00369 #endif
00370 
00371 
00372 #ifndef atomic_add_zero
00373 # define atomic_add_zero(mem, value)                                        \
00374   ({ __typeof (value) __atg13_value = (value);                              \
00375      atomic_exchange_and_add (mem, __atg13_value) == -__atg13_value; })
00376 #endif
00377 
00378 
00379 #ifndef atomic_bit_set
00380 # define atomic_bit_set(mem, bit) \
00381   (void) atomic_bit_test_set(mem, bit)
00382 #endif
00383 
00384 
00385 #ifndef atomic_bit_test_set
00386 # define atomic_bit_test_set(mem, bit) \
00387   ({ __typeof (*(mem)) __atg14_old;                                         \
00388      __typeof (mem) __atg14_memp = (mem);                            \
00389      __typeof (*(mem)) __atg14_mask = ((__typeof (*(mem))) 1 << (bit));            \
00390                                                                      \
00391      do                                                                     \
00392        __atg14_old = (*__atg14_memp);                                       \
00393      while (__builtin_expect                                                \
00394            (atomic_compare_and_exchange_bool_acq (__atg14_memp,             \
00395                                              __atg14_old | __atg14_mask,\
00396                                              __atg14_old), 0));             \
00397                                                                      \
00398      __atg14_old & __atg14_mask; })
00399 #endif
00400 
00401 /* Atomically *mem &= mask.  */
00402 #ifndef atomic_and
00403 # define atomic_and(mem, mask) \
00404   do {                                                               \
00405     __typeof (*(mem)) __atg15_old;                                   \
00406     __typeof (mem) __atg15_memp = (mem);                             \
00407     __typeof (*(mem)) __atg15_mask = (mask);                                \
00408                                                                      \
00409     do                                                               \
00410       __atg15_old = (*__atg15_memp);                                        \
00411     while (__builtin_expect                                          \
00412           (atomic_compare_and_exchange_bool_acq (__atg15_memp,              \
00413                                             __atg15_old & __atg15_mask, \
00414                                             __atg15_old), 0));       \
00415   } while (0)
00416 #endif
00417 
00418 /* Atomically *mem &= mask and return the old value of *mem.  */
00419 #ifndef atomic_and_val
00420 # define atomic_and_val(mem, mask) \
00421   ({ __typeof (*(mem)) __atg16_old;                                         \
00422      __typeof (mem) __atg16_memp = (mem);                            \
00423      __typeof (*(mem)) __atg16_mask = (mask);                               \
00424                                                                      \
00425      do                                                                     \
00426        __atg16_old = (*__atg16_memp);                                       \
00427      while (__builtin_expect                                                \
00428            (atomic_compare_and_exchange_bool_acq (__atg16_memp,             \
00429                                              __atg16_old & __atg16_mask,\
00430                                              __atg16_old), 0));             \
00431                                                                      \
00432      __atg16_old; })
00433 #endif
00434 
00435 /* Atomically *mem |= mask and return the old value of *mem.  */
00436 #ifndef atomic_or
00437 # define atomic_or(mem, mask) \
00438   do {                                                               \
00439     __typeof (*(mem)) __atg17_old;                                   \
00440     __typeof (mem) __atg17_memp = (mem);                             \
00441     __typeof (*(mem)) __atg17_mask = (mask);                                \
00442                                                                      \
00443     do                                                               \
00444       __atg17_old = (*__atg17_memp);                                        \
00445     while (__builtin_expect                                          \
00446           (atomic_compare_and_exchange_bool_acq (__atg17_memp,              \
00447                                             __atg17_old | __atg17_mask, \
00448                                             __atg17_old), 0));       \
00449   } while (0)
00450 #endif
00451 
00452 #ifndef catomic_or
00453 # define catomic_or(mem, mask) \
00454   do {                                                               \
00455     __typeof (*(mem)) __atg18_old;                                   \
00456     __typeof (mem) __atg18_memp = (mem);                             \
00457     __typeof (*(mem)) __atg18_mask = (mask);                                \
00458                                                                      \
00459     do                                                               \
00460       __atg18_old = (*__atg18_memp);                                        \
00461     while (__builtin_expect                                          \
00462           (catomic_compare_and_exchange_bool_acq (__atg18_memp,             \
00463                                              __atg18_old | __atg18_mask,\
00464                                              __atg18_old), 0));             \
00465   } while (0)
00466 #endif
00467 
00468 /* Atomically *mem |= mask and return the old value of *mem.  */
00469 #ifndef atomic_or_val
00470 # define atomic_or_val(mem, mask) \
00471   ({ __typeof (*(mem)) __atg19_old;                                         \
00472      __typeof (mem) __atg19_memp = (mem);                            \
00473      __typeof (*(mem)) __atg19_mask = (mask);                               \
00474                                                                      \
00475      do                                                                     \
00476        __atg19_old = (*__atg19_memp);                                       \
00477      while (__builtin_expect                                                \
00478            (atomic_compare_and_exchange_bool_acq (__atg19_memp,             \
00479                                              __atg19_old | __atg19_mask,\
00480                                              __atg19_old), 0));             \
00481                                                                      \
00482      __atg19_old; })
00483 #endif
00484 
00485 #ifndef atomic_full_barrier
00486 # define atomic_full_barrier() __asm ("" ::: "memory")
00487 #endif
00488 
00489 
00490 #ifndef atomic_read_barrier
00491 # define atomic_read_barrier() atomic_full_barrier ()
00492 #endif
00493 
00494 
00495 #ifndef atomic_write_barrier
00496 # define atomic_write_barrier() atomic_full_barrier ()
00497 #endif
00498 
00499 
00500 #ifndef atomic_forced_read
00501 # define atomic_forced_read(x) \
00502   ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
00503 #endif
00504 
00505 
00506 #ifndef atomic_delay
00507 # define atomic_delay() do { /* nothing */ } while (0)
00508 #endif
00509 
00510 #endif /* atomic.h */