Home | History | Annotate | Download | only in base
      1 /* Copyright (c) 2008, Google Inc.
      2  * All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  *
     30  * ---
     31  */
     32 
     33 // Implementation of atomic operations for ppc-linux.  This file should not
     34 // be included directly.  Clients should instead include
     35 // "base/atomicops.h".
     36 
     37 #ifndef BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
     38 #define BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
     39 
     40 typedef int32_t Atomic32;
     41 
     42 #ifdef __PPC64__
     43 #define BASE_HAS_ATOMIC64 1
     44 #endif
     45 
     46 namespace base {
     47 namespace subtle {
     48 
     49 static inline void _sync(void) {
     50   __asm__ __volatile__("sync": : : "memory");
     51 }
     52 
     53 static inline void _lwsync(void) {
     54   // gcc defines __NO_LWSYNC__ when appropriate; see
     55   //    http://gcc.gnu.org/ml/gcc-patches/2006-11/msg01238.html
     56 #ifdef __NO_LWSYNC__
     57   __asm__ __volatile__("msync": : : "memory");
     58 #else
     59   __asm__ __volatile__("lwsync": : : "memory");
     60 #endif
     61 }
     62 
     63 static inline void _isync(void) {
     64   __asm__ __volatile__("isync": : : "memory");
     65 }
     66 
     67 static inline Atomic32 OSAtomicAdd32(Atomic32 amount, Atomic32 *value) {
     68   Atomic32 t;
     69   __asm__ __volatile__(
     70 "1:		lwarx   %0,0,%3\n\
     71 		add     %0,%2,%0\n\
     72 		stwcx.  %0,0,%3 \n\
     73 		bne-    1b"
     74 		: "=&r" (t), "+m" (*value)
     75 		: "r" (amount), "r" (value)
     76                 : "cc");
     77   return t;
     78 }
     79 
     80 static inline Atomic32 OSAtomicAdd32Barrier(Atomic32 amount, Atomic32 *value) {
     81   Atomic32 t;
     82   _lwsync();
     83   t = OSAtomicAdd32(amount, value);
     84   // This is based on the code snippet in the architecture manual (Vol
     85   // 2, Appendix B).  It's a little tricky: correctness depends on the
     86   // fact that the code right before this (in OSAtomicAdd32) has a
     87   // conditional branch with a data dependency on the update.
     88   // Otherwise, we'd have to use sync.
     89   _isync();
     90   return t;
     91 }
     92 
     93 static inline bool OSAtomicCompareAndSwap32(Atomic32 old_value,
     94                                             Atomic32 new_value,
     95                                             Atomic32 *value) {
     96   Atomic32 prev;
     97   __asm__ __volatile__(
     98 "1:		lwarx   %0,0,%2\n\
     99 		cmpw    0,%0,%3\n\
    100 		bne-    2f\n\
    101 		stwcx.  %4,0,%2\n\
    102 		bne-    1b\n\
    103 2:"
    104                 : "=&r" (prev), "+m" (*value)
    105                 : "r" (value), "r" (old_value), "r" (new_value)
    106                 : "cc");
    107   return prev == old_value;
    108 }
    109 
    110 static inline Atomic32 OSAtomicCompareAndSwap32Acquire(Atomic32 old_value,
    111                                                        Atomic32 new_value,
    112                                                        Atomic32 *value) {
    113   Atomic32 t;
    114   t = OSAtomicCompareAndSwap32(old_value, new_value, value);
    115   // This is based on the code snippet in the architecture manual (Vol
    116   // 2, Appendix B).  It's a little tricky: correctness depends on the
    117   // fact that the code right before this (in
    118   // OSAtomicCompareAndSwap32) has a conditional branch with a data
    119   // dependency on the update.  Otherwise, we'd have to use sync.
    120   _isync();
    121   return t;
    122 }
    123 
    124 static inline Atomic32 OSAtomicCompareAndSwap32Release(Atomic32 old_value,
    125                                                        Atomic32 new_value,
    126                                                        Atomic32 *value) {
    127   _lwsync();
    128   return OSAtomicCompareAndSwap32(old_value, new_value, value);
    129 }
    130 
    131 typedef int64_t Atomic64;
    132 
    133 inline void MemoryBarrier() {
    134   // This can't be _lwsync(); we need to order the immediately
    135   // preceding stores against any load that may follow, but lwsync
    136   // doesn't guarantee that.
    137   _sync();
    138 }
    139 
    140 // 32-bit Versions.
    141 
    142 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
    143                                          Atomic32 old_value,
    144                                          Atomic32 new_value) {
    145   Atomic32 prev_value;
    146   do {
    147     if (OSAtomicCompareAndSwap32(old_value, new_value,
    148                                  const_cast<Atomic32*>(ptr))) {
    149       return old_value;
    150     }
    151     prev_value = *ptr;
    152   } while (prev_value == old_value);
    153   return prev_value;
    154 }
    155 
    156 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
    157                                          Atomic32 new_value) {
    158   Atomic32 old_value;
    159   do {
    160     old_value = *ptr;
    161   } while (!OSAtomicCompareAndSwap32(old_value, new_value,
    162                                      const_cast<Atomic32*>(ptr)));
    163   return old_value;
    164 }
    165 
    166 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
    167                                           Atomic32 increment) {
    168   return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
    169 }
    170 
    171 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
    172                                         Atomic32 increment) {
    173   return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
    174 }
    175 
    176 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
    177                                        Atomic32 old_value,
    178                                        Atomic32 new_value) {
    179   Atomic32 prev_value;
    180   do {
    181     if (OSAtomicCompareAndSwap32Acquire(old_value, new_value,
    182                                         const_cast<Atomic32*>(ptr))) {
    183       return old_value;
    184     }
    185     prev_value = *ptr;
    186   } while (prev_value == old_value);
    187   return prev_value;
    188 }
    189 
    190 inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
    191                                        Atomic32 old_value,
    192                                        Atomic32 new_value) {
    193   Atomic32 prev_value;
    194   do {
    195     if (OSAtomicCompareAndSwap32Release(old_value, new_value,
    196                                         const_cast<Atomic32*>(ptr))) {
    197       return old_value;
    198     }
    199     prev_value = *ptr;
    200   } while (prev_value == old_value);
    201   return prev_value;
    202 }
    203 
    204 #ifdef __PPC64__
    205 
    206 // 64-bit Versions.
    207 
    208 static inline Atomic64 OSAtomicAdd64(Atomic64 amount, Atomic64 *value) {
    209   Atomic64 t;
    210   __asm__ __volatile__(
    211 "1:		ldarx   %0,0,%3\n\
    212 		add     %0,%2,%0\n\
    213 		stdcx.  %0,0,%3 \n\
    214 		bne-    1b"
    215 		: "=&r" (t), "+m" (*value)
    216 		: "r" (amount), "r" (value)
    217                 : "cc");
    218   return t;
    219 }
    220 
    221 static inline Atomic64 OSAtomicAdd64Barrier(Atomic64 amount, Atomic64 *value) {
    222   Atomic64 t;
    223   _lwsync();
    224   t = OSAtomicAdd64(amount, value);
    225   // This is based on the code snippet in the architecture manual (Vol
    226   // 2, Appendix B).  It's a little tricky: correctness depends on the
    227   // fact that the code right before this (in OSAtomicAdd64) has a
    228   // conditional branch with a data dependency on the update.
    229   // Otherwise, we'd have to use sync.
    230   _isync();
    231   return t;
    232 }
    233 
    234 static inline bool OSAtomicCompareAndSwap64(Atomic64 old_value,
    235                                             Atomic64 new_value,
    236                                             Atomic64 *value) {
    237   Atomic64 prev;
    238   __asm__ __volatile__(
    239 "1:		ldarx   %0,0,%2\n\
    240 		cmpw    0,%0,%3\n\
    241 		bne-    2f\n\
    242 		stdcx.  %4,0,%2\n\
    243 		bne-    1b\n\
    244 2:"
    245                 : "=&r" (prev), "+m" (*value)
    246                 : "r" (value), "r" (old_value), "r" (new_value)
    247                 : "cc");
    248   return prev == old_value;
    249 }
    250 
    251 static inline Atomic64 OSAtomicCompareAndSwap64Acquire(Atomic64 old_value,
    252                                                        Atomic64 new_value,
    253                                                        Atomic64 *value) {
    254   Atomic64 t;
    255   t = OSAtomicCompareAndSwap64(old_value, new_value, value);
    256   // This is based on the code snippet in the architecture manual (Vol
    257   // 2, Appendix B).  It's a little tricky: correctness depends on the
    258   // fact that the code right before this (in
    259   // OSAtomicCompareAndSwap64) has a conditional branch with a data
    260   // dependency on the update.  Otherwise, we'd have to use sync.
    261   _isync();
    262   return t;
    263 }
    264 
    265 static inline Atomic64 OSAtomicCompareAndSwap64Release(Atomic64 old_value,
    266                                                        Atomic64 new_value,
    267                                                        Atomic64 *value) {
    268   _lwsync();
    269   return OSAtomicCompareAndSwap64(old_value, new_value, value);
    270 }
    271 
    272 
    273 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
    274                                          Atomic64 old_value,
    275                                          Atomic64 new_value) {
    276   Atomic64 prev_value;
    277   do {
    278     if (OSAtomicCompareAndSwap64(old_value, new_value,
    279                                  const_cast<Atomic64*>(ptr))) {
    280       return old_value;
    281     }
    282     prev_value = *ptr;
    283   } while (prev_value == old_value);
    284   return prev_value;
    285 }
    286 
    287 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
    288                                          Atomic64 new_value) {
    289   Atomic64 old_value;
    290   do {
    291     old_value = *ptr;
    292   } while (!OSAtomicCompareAndSwap64(old_value, new_value,
    293                                      const_cast<Atomic64*>(ptr)));
    294   return old_value;
    295 }
    296 
    297 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
    298                                           Atomic64 increment) {
    299   return OSAtomicAdd64(increment, const_cast<Atomic64*>(ptr));
    300 }
    301 
    302 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
    303                                         Atomic64 increment) {
    304   return OSAtomicAdd64Barrier(increment, const_cast<Atomic64*>(ptr));
    305 }
    306 
    307 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
    308                                        Atomic64 old_value,
    309                                        Atomic64 new_value) {
    310   Atomic64 prev_value;
    311   do {
    312     if (OSAtomicCompareAndSwap64Acquire(old_value, new_value,
    313                                         const_cast<Atomic64*>(ptr))) {
    314       return old_value;
    315     }
    316     prev_value = *ptr;
    317   } while (prev_value == old_value);
    318   return prev_value;
    319 }
    320 
    321 inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
    322                                        Atomic64 old_value,
    323                                        Atomic64 new_value) {
    324   Atomic64 prev_value;
    325   do {
    326     if (OSAtomicCompareAndSwap64Release(old_value, new_value,
    327                                         const_cast<Atomic64*>(ptr))) {
    328       return old_value;
    329     }
    330     prev_value = *ptr;
    331   } while (prev_value == old_value);
    332   return prev_value;
    333 }
    334 
    335 #endif
    336 
    337 inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
    338   *ptr = value;
    339 }
    340 
    341 inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
    342   *ptr = value;
    343   // This can't be _lwsync(); we need to order the immediately
    344   // preceding stores against any load that may follow, but lwsync
    345   // doesn't guarantee that.
    346   _sync();
    347 }
    348 
    349 inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
    350   _lwsync();
    351   *ptr = value;
    352 }
    353 
    354 inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
    355   return *ptr;
    356 }
    357 
    358 inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
    359   Atomic32 value = *ptr;
    360   _lwsync();
    361   return value;
    362 }
    363 
    364 inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
    365   // This can't be _lwsync(); we need to order the immediately
    366   // preceding stores against any load that may follow, but lwsync
    367   // doesn't guarantee that.
    368   _sync();
    369   return *ptr;
    370 }
    371 
    372 #ifdef __PPC64__
    373 
    374 // 64-bit Versions.
    375 
    376 inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
    377   *ptr = value;
    378 }
    379 
    380 inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
    381   *ptr = value;
    382   // This can't be _lwsync(); we need to order the immediately
    383   // preceding stores against any load that may follow, but lwsync
    384   // doesn't guarantee that.
    385   _sync();
    386 }
    387 
    388 inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
    389   _lwsync();
    390   *ptr = value;
    391 }
    392 
    393 inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
    394   return *ptr;
    395 }
    396 
    397 inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
    398   Atomic64 value = *ptr;
    399   _lwsync();
    400   return value;
    401 }
    402 
    403 inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
    404   // This can't be _lwsync(); we need to order the immediately
    405   // preceding stores against any load that may follow, but lwsync
    406   // doesn't guarantee that.
    407   _sync();
    408   return *ptr;
    409 }
    410 
    411 #endif
    412 
    413 }   // namespace base::subtle
    414 }   // namespace base
    415 
    416 #endif  // BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
    417