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.
5 // This file is an internal atomic implementation, use base/atomicops.h instead.
7 // LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
9 #ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
10 #define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
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,
23 volatile Atomic32* ptr);
24 LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
25 (LinuxKernelCmpxchgFunc) 0xffff0fc0;
27 typedef void (*LinuxKernelMemoryBarrierFunc)(void);
28 LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
29 (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
32 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
35 Atomic32 prev_value = *ptr;
37 if (!pLinuxKernelCmpxchg(old_value, new_value,
38 const_cast<Atomic32*>(ptr))) {
42 } while (prev_value == old_value);
46 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
51 } while (pLinuxKernelCmpxchg(old_value, new_value,
52 const_cast<Atomic32*>(ptr)));
56 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
58 return Barrier_AtomicIncrement(ptr, increment);
61 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
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.
72 // Otherwise, *ptr changed mid-loop and we need to retry.
77 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
80 return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
83 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
86 return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
89 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
93 inline void MemoryBarrier() {
94 pLinuxKernelMemoryBarrier();
97 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
102 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
107 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
111 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
112 Atomic32 value = *ptr;
117 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
122 } // namespace base::subtle
125 #endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_