• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 // This file is an internal atomic implementation, use atomicops.h instead.
6 //
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).
12 //
13 // TODO(jfb) Modify the atomicops.h API and user code to declare atomic
14 //           locations as truly atomic. See the static_assert below.
15 //
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
25 //    optimize).
26 
27 #ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
28 #define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
29 
30 #include <atomic>
31 
32 #include "build/build_config.h"
33 
34 namespace base {
35 namespace subtle {
36 
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
42 // shouldn't be used.
43 //
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");
49 
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)50 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
51                                          Atomic32 old_value,
52                                          Atomic32 new_value) {
53   ((AtomicLocation32)ptr)
54       ->compare_exchange_strong(old_value,
55                                 new_value,
56                                 std::memory_order_relaxed,
57                                 std::memory_order_relaxed);
58   return old_value;
59 }
60 
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)61 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
62                                          Atomic32 new_value) {
63   return ((AtomicLocation32)ptr)
64       ->exchange(new_value, std::memory_order_relaxed);
65 }
66 
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)67 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
68                                           Atomic32 increment) {
69   return increment +
70          ((AtomicLocation32)ptr)
71              ->fetch_add(increment, std::memory_order_relaxed);
72 }
73 
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)74 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
75                                         Atomic32 increment) {
76   return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
77 }
78 
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)79 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
80                                        Atomic32 old_value,
81                                        Atomic32 new_value) {
82   ((AtomicLocation32)ptr)
83       ->compare_exchange_strong(old_value,
84                                 new_value,
85                                 std::memory_order_acquire,
86                                 std::memory_order_acquire);
87   return old_value;
88 }
89 
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)90 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
91                                        Atomic32 old_value,
92                                        Atomic32 new_value) {
93   ((AtomicLocation32)ptr)
94       ->compare_exchange_strong(old_value,
95                                 new_value,
96                                 std::memory_order_release,
97                                 std::memory_order_relaxed);
98   return old_value;
99 }
100 
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)101 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
102   ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
103 }
104 
Release_Store(volatile Atomic32 * ptr,Atomic32 value)105 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
106   ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
107 }
108 
NoBarrier_Load(volatile const Atomic32 * ptr)109 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
110   return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
111 }
112 
Acquire_Load(volatile const Atomic32 * ptr)113 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
114   return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
115 }
116 
117 #if defined(ARCH_CPU_64_BITS)
118 
119 typedef volatile std::atomic<Atomic64>* AtomicLocation64;
120 static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
121               "incompatible 64-bit atomic layout");
122 
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)123 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
124                                          Atomic64 old_value,
125                                          Atomic64 new_value) {
126   ((AtomicLocation64)ptr)
127       ->compare_exchange_strong(old_value,
128                                 new_value,
129                                 std::memory_order_relaxed,
130                                 std::memory_order_relaxed);
131   return old_value;
132 }
133 
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)134 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
135                                          Atomic64 new_value) {
136   return ((AtomicLocation64)ptr)
137       ->exchange(new_value, std::memory_order_relaxed);
138 }
139 
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)140 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
141                                           Atomic64 increment) {
142   return increment +
143          ((AtomicLocation64)ptr)
144              ->fetch_add(increment, std::memory_order_relaxed);
145 }
146 
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)147 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
148                                         Atomic64 increment) {
149   return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
150 }
151 
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)152 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
153                                        Atomic64 old_value,
154                                        Atomic64 new_value) {
155   ((AtomicLocation64)ptr)
156       ->compare_exchange_strong(old_value,
157                                 new_value,
158                                 std::memory_order_acquire,
159                                 std::memory_order_acquire);
160   return old_value;
161 }
162 
Release_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)163 inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
164                                        Atomic64 old_value,
165                                        Atomic64 new_value) {
166   ((AtomicLocation64)ptr)
167       ->compare_exchange_strong(old_value,
168                                 new_value,
169                                 std::memory_order_release,
170                                 std::memory_order_relaxed);
171   return old_value;
172 }
173 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)174 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
175   ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
176 }
177 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)178 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
179   ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
180 }
181 
NoBarrier_Load(volatile const Atomic64 * ptr)182 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
183   return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
184 }
185 
Acquire_Load(volatile const Atomic64 * ptr)186 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
187   return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
188 }
189 
190 #endif  // defined(ARCH_CPU_64_BITS)
191 }  // namespace subtle
192 }  // namespace base
193 
194 #endif  // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
195