Back to index

glibc  2.9
atomic.h
Go to the documentation of this file.
00001 /* Atomic operations.  sparc32 version.
00002    Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
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 _BITS_ATOMIC_H
00022 #define _BITS_ATOMIC_H      1
00023 
00024 #include <stdint.h>
00025 
00026 typedef int8_t atomic8_t;
00027 typedef uint8_t uatomic8_t;
00028 typedef int_fast8_t atomic_fast8_t;
00029 typedef uint_fast8_t uatomic_fast8_t;
00030 
00031 typedef int16_t atomic16_t;
00032 typedef uint16_t uatomic16_t;
00033 typedef int_fast16_t atomic_fast16_t;
00034 typedef uint_fast16_t uatomic_fast16_t;
00035 
00036 typedef int32_t atomic32_t;
00037 typedef uint32_t uatomic32_t;
00038 typedef int_fast32_t atomic_fast32_t;
00039 typedef uint_fast32_t uatomic_fast32_t;
00040 
00041 typedef int64_t atomic64_t;
00042 typedef uint64_t uatomic64_t;
00043 typedef int_fast64_t atomic_fast64_t;
00044 typedef uint_fast64_t uatomic_fast64_t;
00045 
00046 typedef intptr_t atomicptr_t;
00047 typedef uintptr_t uatomicptr_t;
00048 typedef intmax_t atomic_max_t;
00049 typedef uintmax_t uatomic_max_t;
00050 
00051 
00052 /* We have no compare and swap, just test and set.
00053    The following implementation contends on 64 global locks
00054    per library and assumes no variable will be accessed using atomic.h
00055    macros from two different libraries.  */
00056 
00057 __make_section_unallocated
00058   (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits");
00059 
00060 volatile unsigned char __sparc32_atomic_locks[64]
00061   __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks"
00062                                  __sec_comment),
00063                 visibility ("hidden")));
00064 
00065 #define __sparc32_atomic_do_lock(addr) \
00066   do                                                          \
00067     {                                                         \
00068       unsigned int __old_lock;                                       \
00069       unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \
00070                         & 63;                                 \
00071       do                                                      \
00072        __asm __volatile ("ldstub %1, %0"                      \
00073                        : "=r" (__old_lock),                          \
00074                          "=m" (__sparc32_atomic_locks[__idx])      \
00075                        : "m" (__sparc32_atomic_locks[__idx])         \
00076                        : "memory");                                  \
00077       while (__old_lock);                                     \
00078     }                                                         \
00079   while (0)
00080 
00081 #define __sparc32_atomic_do_unlock(addr) \
00082   do                                                          \
00083     {                                                         \
00084       __sparc32_atomic_locks[(((long) addr >> 2)              \
00085                            ^ ((long) addr >> 12)) & 63] = 0;         \
00086       __asm __volatile ("" ::: "memory");                     \
00087     }                                                         \
00088   while (0)
00089 
00090 #define __sparc32_atomic_do_lock24(addr) \
00091   do                                                          \
00092     {                                                         \
00093       unsigned int __old_lock;                                       \
00094       do                                                      \
00095        __asm __volatile ("ldstub %1, %0"                      \
00096                        : "=r" (__old_lock), "=m" (*(addr))           \
00097                        : "m" (*(addr))                        \
00098                        : "memory");                                  \
00099       while (__old_lock);                                     \
00100     }                                                         \
00101   while (0)
00102 
00103 #define __sparc32_atomic_do_unlock24(addr) \
00104   do                                                          \
00105     {                                                         \
00106       *(char *) (addr) = 0;                                   \
00107       __asm __volatile ("" ::: "memory");                     \
00108     }                                                         \
00109   while (0)
00110 
00111 
00112 #ifndef SHARED
00113 # define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \
00114 ({                                                                   \
00115   register __typeof (*(mem)) __acev_tmp __asm ("%g6");                      \
00116   register __typeof (mem) __acev_mem __asm ("%g1") = (mem);                 \
00117   register __typeof (*(mem)) __acev_oldval __asm ("%g5");                   \
00118   __acev_tmp = (newval);                                             \
00119   __acev_oldval = (oldval);                                          \
00120   /* .word 0xcde05005 is cas [%g1], %g5, %g6.  Can't use cas here though,     \
00121      because as will then mark the object file as V8+ arch.  */                    \
00122   __asm __volatile (".word 0xcde05005"                                      \
00123                   : "+r" (__acev_tmp), "=m" (*__acev_mem)                   \
00124                   : "r" (__acev_oldval), "m" (*__acev_mem),                 \
00125                     "r" (__acev_mem) : "memory");                           \
00126   __acev_tmp; })
00127 #endif
00128 
00129 /* The only basic operation needed is compare and exchange.  */
00130 #define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \
00131   ({ __typeof (mem) __acev_memp = (mem);                      \
00132      __typeof (*mem) __acev_ret;                              \
00133      __typeof (*mem) __acev_newval = (newval);                       \
00134                                                               \
00135      __sparc32_atomic_do_lock (__acev_memp);                         \
00136      __acev_ret = *__acev_memp;                                      \
00137      if (__acev_ret == (oldval))                              \
00138        *__acev_memp = __acev_newval;                                 \
00139      __sparc32_atomic_do_unlock (__acev_memp);                       \
00140      __acev_ret; })
00141 
00142 #define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \
00143   ({ __typeof (mem) __aceb_memp = (mem);                      \
00144      int __aceb_ret;                                          \
00145      __typeof (*mem) __aceb_newval = (newval);                       \
00146                                                               \
00147      __sparc32_atomic_do_lock (__aceb_memp);                         \
00148      __aceb_ret = 0;                                          \
00149      if (*__aceb_memp == (oldval))                            \
00150        *__aceb_memp = __aceb_newval;                                 \
00151      else                                                     \
00152        __aceb_ret = 1;                                               \
00153      __sparc32_atomic_do_unlock (__aceb_memp);                       \
00154      __aceb_ret; })
00155 
00156 #define __v7_exchange_acq(mem, newval) \
00157   ({ __typeof (mem) __acev_memp = (mem);                      \
00158      __typeof (*mem) __acev_ret;                              \
00159      __typeof (*mem) __acev_newval = (newval);                       \
00160                                                               \
00161      __sparc32_atomic_do_lock (__acev_memp);                         \
00162      __acev_ret = *__acev_memp;                                      \
00163      *__acev_memp = __acev_newval;                            \
00164      __sparc32_atomic_do_unlock (__acev_memp);                       \
00165      __acev_ret; })
00166 
00167 #define __v7_exchange_and_add(mem, value) \
00168   ({ __typeof (mem) __acev_memp = (mem);                      \
00169      __typeof (*mem) __acev_ret;                              \
00170                                                               \
00171      __sparc32_atomic_do_lock (__acev_memp);                         \
00172      __acev_ret = *__acev_memp;                                      \
00173      *__acev_memp = __acev_ret + (value);                     \
00174      __sparc32_atomic_do_unlock (__acev_memp);                       \
00175      __acev_ret; })
00176 
00177 /* Special versions, which guarantee that top 8 bits of all values
00178    are cleared and use those bits as the ldstub lock.  */
00179 #define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \
00180   ({ __typeof (mem) __acev_memp = (mem);                      \
00181      __typeof (*mem) __acev_ret;                              \
00182      __typeof (*mem) __acev_newval = (newval);                       \
00183                                                               \
00184      __sparc32_atomic_do_lock24 (__acev_memp);                       \
00185      __acev_ret = *__acev_memp & 0xffffff;                           \
00186      if (__acev_ret == (oldval))                              \
00187        *__acev_memp = __acev_newval;                                 \
00188      else                                                     \
00189        __sparc32_atomic_do_unlock24 (__acev_memp);                   \
00190      __asm __volatile ("" ::: "memory");                      \
00191      __acev_ret; })
00192 
00193 #define __v7_exchange_24_rel(mem, newval) \
00194   ({ __typeof (mem) __acev_memp = (mem);                      \
00195      __typeof (*mem) __acev_ret;                              \
00196      __typeof (*mem) __acev_newval = (newval);                       \
00197                                                               \
00198      __sparc32_atomic_do_lock24 (__acev_memp);                       \
00199      __acev_ret = *__acev_memp & 0xffffff;                           \
00200      *__acev_memp = __acev_newval;                            \
00201      __asm __volatile ("" ::: "memory");                      \
00202      __acev_ret; })
00203 
00204 #ifdef SHARED
00205 
00206 /* When dynamically linked, we assume pre-v9 libraries are only ever
00207    used on pre-v9 CPU.  */
00208 # define __atomic_is_v9 0
00209 
00210 # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
00211   __v7_compare_and_exchange_val_acq (mem, newval, oldval)
00212 
00213 # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
00214   __v7_compare_and_exchange_bool_acq (mem, newval, oldval)
00215 
00216 # define atomic_exchange_acq(mem, newval) \
00217   __v7_exchange_acq (mem, newval)
00218 
00219 # define atomic_exchange_and_add(mem, value) \
00220   __v7_exchange_and_add (mem, value)
00221 
00222 # define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
00223   ({                                                          \
00224      if (sizeof (*mem) != 4)                                         \
00225        abort ();                                              \
00226      __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); })
00227 
00228 # define atomic_exchange_24_rel(mem, newval) \
00229   ({                                                          \
00230      if (sizeof (*mem) != 4)                                         \
00231        abort ();                                              \
00232      __v7_exchange_24_rel (mem, newval); })
00233 
00234 #else
00235 
00236 /* In libc.a/libpthread.a etc. we don't know if we'll be run on
00237    pre-v9 or v9 CPU.  To be interoperable with dynamically linked
00238    apps on v9 CPUs e.g. with process shared primitives, use cas insn
00239    on v9 CPUs and ldstub on pre-v9.  */
00240 
00241 /* Avoid <ldsodefs.h> include here.  */
00242 extern uint64_t _dl_hwcap __attribute__((weak));
00243 # define __ATOMIC_HWCAP_SPARC_V9   16
00244 # define __atomic_is_v9 \
00245   (__builtin_expect (&_dl_hwcap != 0, 1) \
00246    && __builtin_expect (_dl_hwcap & __ATOMIC_HWCAP_SPARC_V9, \
00247                      __ATOMIC_HWCAP_SPARC_V9))
00248 
00249 # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
00250   ({                                                          \
00251      __typeof (*mem) __acev_wret;                             \
00252      if (sizeof (*mem) != 4)                                         \
00253        abort ();                                              \
00254      if (__atomic_is_v9)                                      \
00255        __acev_wret                                            \
00256         = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
00257      else                                                     \
00258        __acev_wret                                            \
00259         = __v7_compare_and_exchange_val_acq (mem, newval, oldval);   \
00260      __acev_wret; })
00261 
00262 # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
00263   ({                                                          \
00264      int __acev_wret;                                                \
00265      if (sizeof (*mem) != 4)                                         \
00266        abort ();                                              \
00267      if (__atomic_is_v9)                                      \
00268        {                                                      \
00269         __typeof (oldval) __acev_woldval = (oldval);                 \
00270         __acev_wret                                           \
00271           = __v9_compare_and_exchange_val_32_acq (mem, newval,       \
00272                                              __acev_woldval)    \
00273             != __acev_woldval;                                       \
00274        }                                                      \
00275      else                                                     \
00276        __acev_wret                                            \
00277         = __v7_compare_and_exchange_bool_acq (mem, newval, oldval);  \
00278      __acev_wret; })
00279 
00280 # define atomic_exchange_rel(mem, newval) \
00281   ({                                                          \
00282      __typeof (*mem) __acev_wret;                             \
00283      if (sizeof (*mem) != 4)                                         \
00284        abort ();                                              \
00285      if (__atomic_is_v9)                                      \
00286        {                                                      \
00287         __typeof (mem) __acev_wmemp = (mem);                         \
00288         __typeof (*(mem)) __acev_wval = (newval);                    \
00289         do                                                    \
00290           __acev_wret = *__acev_wmemp;                               \
00291         while (__builtin_expect                               \
00292                 (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\
00293                                                   __acev_wval, \
00294                                                   __acev_wret) \
00295                  != __acev_wret, 0));                                \
00296        }                                                      \
00297      else                                                     \
00298        __acev_wret = __v7_exchange_acq (mem, newval);                \
00299      __acev_wret; })
00300 
00301 # define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
00302   ({                                                          \
00303      __typeof (*mem) __acev_wret;                             \
00304      if (sizeof (*mem) != 4)                                         \
00305        abort ();                                              \
00306      if (__atomic_is_v9)                                      \
00307        __acev_wret                                            \
00308         = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
00309      else                                                     \
00310        __acev_wret                                            \
00311         = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\
00312      __acev_wret; })
00313 
00314 # define atomic_exchange_24_rel(mem, newval) \
00315   ({                                                          \
00316      __typeof (*mem) __acev_w24ret;                                  \
00317      if (sizeof (*mem) != 4)                                         \
00318        abort ();                                              \
00319      if (__atomic_is_v9)                                      \
00320        __acev_w24ret = atomic_exchange_rel (mem, newval);            \
00321      else                                                     \
00322        __acev_w24ret = __v7_exchange_24_rel (mem, newval);           \
00323      __acev_w24ret; })
00324 
00325 #endif
00326 
00327 #endif /* bits/atomic.h */