Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // This file is an internal atomic implementation, use base/atomicops.h instead.
      6 //
      7 // LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
      8 
      9 #ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
     10 #define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
     11 #pragma once
     12 
     13 namespace base {
     14 namespace subtle {
     15 
     16 // 0xffff0fc0 is the hard coded address of a function provided by
     17 // the kernel which implements an atomic compare-exchange. On older
     18 // ARM architecture revisions (pre-v6) this may be implemented using
     19 // a syscall. This address is stable, and in active use (hard coded)
     20 // by at least glibc-2.7 and the Android C library.
     21 typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
     22                                            Atomic32 new_value,
     23                                            volatile Atomic32* ptr);
     24 LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
     25     (LinuxKernelCmpxchgFunc) 0xffff0fc0;
     26 
     27 typedef void (*LinuxKernelMemoryBarrierFunc)(void);
     28 LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
     29     (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
     30 
     31 
     32 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
     33                                          Atomic32 old_value,
     34                                          Atomic32 new_value) {
     35   Atomic32 prev_value = *ptr;
     36   do {
     37     if (!pLinuxKernelCmpxchg(old_value, new_value,
     38                              const_cast<Atomic32*>(ptr))) {
     39       return old_value;
     40     }
     41     prev_value = *ptr;
     42   } while (prev_value == old_value);
     43   return prev_value;
     44 }
     45 
     46 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
     47                                          Atomic32 new_value) {
     48   Atomic32 old_value;
     49   do {
     50     old_value = *ptr;
     51   } while (pLinuxKernelCmpxchg(old_value, new_value,
     52                                const_cast<Atomic32*>(ptr)));
     53   return old_value;
     54 }
     55 
     56 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
     57                                           Atomic32 increment) {
     58   return Barrier_AtomicIncrement(ptr, increment);
     59 }
     60 
     61 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
     62                                         Atomic32 increment) {
     63   for (;;) {
     64     // Atomic exchange the old value with an incremented one.
     65     Atomic32 old_value = *ptr;
     66     Atomic32 new_value = old_value + increment;
     67     if (pLinuxKernelCmpxchg(old_value, new_value,
     68                             const_cast<Atomic32*>(ptr)) == 0) {
     69       // The exchange took place as expected.
     70       return new_value;
     71     }
     72     // Otherwise, *ptr changed mid-loop and we need to retry.
     73   }
     74 
     75 }
     76 
     77 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
     78                                        Atomic32 old_value,
     79                                        Atomic32 new_value) {
     80   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
     81 }
     82 
     83 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
     84                                        Atomic32 old_value,
     85                                        Atomic32 new_value) {
     86   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
     87 }
     88 
     89 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
     90   *ptr = value;
     91 }
     92 
     93 inline void MemoryBarrier() {
     94   pLinuxKernelMemoryBarrier();
     95 }
     96 
     97 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
     98   *ptr = value;
     99   MemoryBarrier();
    100 }
    101 
    102 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
    103   MemoryBarrier();
    104   *ptr = value;
    105 }
    106 
    107 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
    108   return *ptr;
    109 }
    110 
    111 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
    112   Atomic32 value = *ptr;
    113   MemoryBarrier();
    114   return value;
    115 }
    116 
    117 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
    118   MemoryBarrier();
    119   return *ptr;
    120 }
    121 
    122 } // namespace base::subtle
    123 } // namespace base
    124 
    125 #endif  // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
    126