1 // Copyright 2014 The Chromium Authors
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 atomicops.h instead.
7 // This implementation uses C++11 atomics' member functions. The code base is
8 // currently written assuming atomicity revolves around accesses instead of
9 // C++11's memory locations. The burden is on the programmer to ensure that all
10 // memory locations accessed atomically are never accessed non-atomically (tsan
11 // should help with this).
13 // TODO(jfb) Modify the atomicops.h API and user code to declare atomic
14 // locations as truly atomic. See the static_assert below.
16 // Of note in this implementation:
17 // * All NoBarrier variants are implemented as relaxed.
18 // * All Barrier variants are implemented as sequentially-consistent.
19 // * Compare exchange's failure ordering is always the same as the success one
20 // (except for release, which fails as relaxed): using a weaker ordering is
21 // only valid under certain uses of compare exchange.
22 // * Atomic increment is expected to return the post-incremented value, whereas
23 // C11 fetch add returns the previous value. The implementation therefore
24 // needs to increment twice (which the compiler should be able to detect and
27 #ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
28 #define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
32 #include "build/build_config.h"
37 // This implementation is transitional and maintains the original API for
38 // atomicops.h. This requires casting memory locations to the atomic types, and
39 // assumes that the API and the C++11 implementation are layout-compatible,
40 // which isn't true for all implementations or hardware platforms. The static
41 // assertion should detect this issue, were it to fire then this header
44 // TODO(jfb) If this header manages to stay committed then the API should be
45 // modified, and all call sites updated.
46 typedef volatile std::atomic<Atomic32>* AtomicLocation32;
47 static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
48 "incompatible 32-bit atomic layout");
50 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
53 ((AtomicLocation32)ptr)
54 ->compare_exchange_strong(old_value,
56 std::memory_order_relaxed,
57 std::memory_order_relaxed);
61 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
63 return ((AtomicLocation32)ptr)
64 ->exchange(new_value, std::memory_order_relaxed);
67 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
70 ((AtomicLocation32)ptr)
71 ->fetch_add(increment, std::memory_order_relaxed);
74 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
76 return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
79 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
82 ((AtomicLocation32)ptr)
83 ->compare_exchange_strong(old_value,
85 std::memory_order_acquire,
86 std::memory_order_acquire);
90 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
93 ((AtomicLocation32)ptr)
94 ->compare_exchange_strong(old_value,
96 std::memory_order_release,
97 std::memory_order_relaxed);
101 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
102 ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
105 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
106 ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
109 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
110 return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
113 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
114 return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
117 #if defined(ARCH_CPU_64_BITS)
119 typedef volatile std::atomic<Atomic64>* AtomicLocation64;
120 static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
121 "incompatible 64-bit atomic layout");
123 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
125 Atomic64 new_value) {
126 ((AtomicLocation64)ptr)
127 ->compare_exchange_strong(old_value,
129 std::memory_order_relaxed,
130 std::memory_order_relaxed);
134 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
135 Atomic64 new_value) {
136 return ((AtomicLocation64)ptr)
137 ->exchange(new_value, std::memory_order_relaxed);
140 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
141 Atomic64 increment) {
143 ((AtomicLocation64)ptr)
144 ->fetch_add(increment, std::memory_order_relaxed);
147 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
148 Atomic64 increment) {
149 return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
152 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
154 Atomic64 new_value) {
155 ((AtomicLocation64)ptr)
156 ->compare_exchange_strong(old_value,
158 std::memory_order_acquire,
159 std::memory_order_acquire);
163 inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
165 Atomic64 new_value) {
166 ((AtomicLocation64)ptr)
167 ->compare_exchange_strong(old_value,
169 std::memory_order_release,
170 std::memory_order_relaxed);
174 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
175 ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
178 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
179 ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
182 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
183 return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
186 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
187 return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
190 #endif // defined(ARCH_CPU_64_BITS)
191 } // namespace subtle
194 #endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_