xref: /aosp_15_r20/external/libchrome/base/atomicops_internals_portable.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker // This file is an internal atomic implementation, use atomicops.h instead.
6*635a8641SAndroid Build Coastguard Worker //
7*635a8641SAndroid Build Coastguard Worker // This implementation uses C++11 atomics' member functions. The code base is
8*635a8641SAndroid Build Coastguard Worker // currently written assuming atomicity revolves around accesses instead of
9*635a8641SAndroid Build Coastguard Worker // C++11's memory locations. The burden is on the programmer to ensure that all
10*635a8641SAndroid Build Coastguard Worker // memory locations accessed atomically are never accessed non-atomically (tsan
11*635a8641SAndroid Build Coastguard Worker // should help with this).
12*635a8641SAndroid Build Coastguard Worker //
13*635a8641SAndroid Build Coastguard Worker // TODO(jfb) Modify the atomicops.h API and user code to declare atomic
14*635a8641SAndroid Build Coastguard Worker //           locations as truly atomic. See the static_assert below.
15*635a8641SAndroid Build Coastguard Worker //
16*635a8641SAndroid Build Coastguard Worker // Of note in this implementation:
17*635a8641SAndroid Build Coastguard Worker //  * All NoBarrier variants are implemented as relaxed.
18*635a8641SAndroid Build Coastguard Worker //  * All Barrier variants are implemented as sequentially-consistent.
19*635a8641SAndroid Build Coastguard Worker //  * Compare exchange's failure ordering is always the same as the success one
20*635a8641SAndroid Build Coastguard Worker //    (except for release, which fails as relaxed): using a weaker ordering is
21*635a8641SAndroid Build Coastguard Worker //    only valid under certain uses of compare exchange.
22*635a8641SAndroid Build Coastguard Worker //  * Acquire store doesn't exist in the C11 memory model, it is instead
23*635a8641SAndroid Build Coastguard Worker //    implemented as a relaxed store followed by a sequentially consistent
24*635a8641SAndroid Build Coastguard Worker //    fence.
25*635a8641SAndroid Build Coastguard Worker //  * Release load doesn't exist in the C11 memory model, it is instead
26*635a8641SAndroid Build Coastguard Worker //    implemented as sequentially consistent fence followed by a relaxed load.
27*635a8641SAndroid Build Coastguard Worker //  * Atomic increment is expected to return the post-incremented value, whereas
28*635a8641SAndroid Build Coastguard Worker //    C11 fetch add returns the previous value. The implementation therefore
29*635a8641SAndroid Build Coastguard Worker //    needs to increment twice (which the compiler should be able to detect and
30*635a8641SAndroid Build Coastguard Worker //    optimize).
31*635a8641SAndroid Build Coastguard Worker 
32*635a8641SAndroid Build Coastguard Worker #ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
33*635a8641SAndroid Build Coastguard Worker #define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
34*635a8641SAndroid Build Coastguard Worker 
35*635a8641SAndroid Build Coastguard Worker #include <atomic>
36*635a8641SAndroid Build Coastguard Worker 
37*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
38*635a8641SAndroid Build Coastguard Worker 
39*635a8641SAndroid Build Coastguard Worker namespace base {
40*635a8641SAndroid Build Coastguard Worker namespace subtle {
41*635a8641SAndroid Build Coastguard Worker 
42*635a8641SAndroid Build Coastguard Worker // This implementation is transitional and maintains the original API for
43*635a8641SAndroid Build Coastguard Worker // atomicops.h. This requires casting memory locations to the atomic types, and
44*635a8641SAndroid Build Coastguard Worker // assumes that the API and the C++11 implementation are layout-compatible,
45*635a8641SAndroid Build Coastguard Worker // which isn't true for all implementations or hardware platforms. The static
46*635a8641SAndroid Build Coastguard Worker // assertion should detect this issue, were it to fire then this header
47*635a8641SAndroid Build Coastguard Worker // shouldn't be used.
48*635a8641SAndroid Build Coastguard Worker //
49*635a8641SAndroid Build Coastguard Worker // TODO(jfb) If this header manages to stay committed then the API should be
50*635a8641SAndroid Build Coastguard Worker //           modified, and all call sites updated.
51*635a8641SAndroid Build Coastguard Worker typedef volatile std::atomic<Atomic32>* AtomicLocation32;
52*635a8641SAndroid Build Coastguard Worker static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
53*635a8641SAndroid Build Coastguard Worker               "incompatible 32-bit atomic layout");
54*635a8641SAndroid Build Coastguard Worker 
MemoryBarrier()55*635a8641SAndroid Build Coastguard Worker inline void MemoryBarrier() {
56*635a8641SAndroid Build Coastguard Worker #if defined(__GLIBCXX__)
57*635a8641SAndroid Build Coastguard Worker   // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
58*635a8641SAndroid Build Coastguard Worker   // not defined, leading to the linker complaining about undefined references.
59*635a8641SAndroid Build Coastguard Worker   __atomic_thread_fence(std::memory_order_seq_cst);
60*635a8641SAndroid Build Coastguard Worker #else
61*635a8641SAndroid Build Coastguard Worker   std::atomic_thread_fence(std::memory_order_seq_cst);
62*635a8641SAndroid Build Coastguard Worker #endif
63*635a8641SAndroid Build Coastguard Worker }
64*635a8641SAndroid Build Coastguard Worker 
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)65*635a8641SAndroid Build Coastguard Worker inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
66*635a8641SAndroid Build Coastguard Worker                                          Atomic32 old_value,
67*635a8641SAndroid Build Coastguard Worker                                          Atomic32 new_value) {
68*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation32)ptr)
69*635a8641SAndroid Build Coastguard Worker       ->compare_exchange_strong(old_value,
70*635a8641SAndroid Build Coastguard Worker                                 new_value,
71*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_relaxed,
72*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_relaxed);
73*635a8641SAndroid Build Coastguard Worker   return old_value;
74*635a8641SAndroid Build Coastguard Worker }
75*635a8641SAndroid Build Coastguard Worker 
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)76*635a8641SAndroid Build Coastguard Worker inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
77*635a8641SAndroid Build Coastguard Worker                                          Atomic32 new_value) {
78*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation32)ptr)
79*635a8641SAndroid Build Coastguard Worker       ->exchange(new_value, std::memory_order_relaxed);
80*635a8641SAndroid Build Coastguard Worker }
81*635a8641SAndroid Build Coastguard Worker 
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)82*635a8641SAndroid Build Coastguard Worker inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
83*635a8641SAndroid Build Coastguard Worker                                           Atomic32 increment) {
84*635a8641SAndroid Build Coastguard Worker   return increment +
85*635a8641SAndroid Build Coastguard Worker          ((AtomicLocation32)ptr)
86*635a8641SAndroid Build Coastguard Worker              ->fetch_add(increment, std::memory_order_relaxed);
87*635a8641SAndroid Build Coastguard Worker }
88*635a8641SAndroid Build Coastguard Worker 
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)89*635a8641SAndroid Build Coastguard Worker inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
90*635a8641SAndroid Build Coastguard Worker                                         Atomic32 increment) {
91*635a8641SAndroid Build Coastguard Worker   return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
92*635a8641SAndroid Build Coastguard Worker }
93*635a8641SAndroid Build Coastguard Worker 
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)94*635a8641SAndroid Build Coastguard Worker inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
95*635a8641SAndroid Build Coastguard Worker                                        Atomic32 old_value,
96*635a8641SAndroid Build Coastguard Worker                                        Atomic32 new_value) {
97*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation32)ptr)
98*635a8641SAndroid Build Coastguard Worker       ->compare_exchange_strong(old_value,
99*635a8641SAndroid Build Coastguard Worker                                 new_value,
100*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_acquire,
101*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_acquire);
102*635a8641SAndroid Build Coastguard Worker   return old_value;
103*635a8641SAndroid Build Coastguard Worker }
104*635a8641SAndroid Build Coastguard Worker 
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)105*635a8641SAndroid Build Coastguard Worker inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
106*635a8641SAndroid Build Coastguard Worker                                        Atomic32 old_value,
107*635a8641SAndroid Build Coastguard Worker                                        Atomic32 new_value) {
108*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation32)ptr)
109*635a8641SAndroid Build Coastguard Worker       ->compare_exchange_strong(old_value,
110*635a8641SAndroid Build Coastguard Worker                                 new_value,
111*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_release,
112*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_relaxed);
113*635a8641SAndroid Build Coastguard Worker   return old_value;
114*635a8641SAndroid Build Coastguard Worker }
115*635a8641SAndroid Build Coastguard Worker 
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)116*635a8641SAndroid Build Coastguard Worker inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
117*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
118*635a8641SAndroid Build Coastguard Worker }
119*635a8641SAndroid Build Coastguard Worker 
Acquire_Store(volatile Atomic32 * ptr,Atomic32 value)120*635a8641SAndroid Build Coastguard Worker inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
121*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
122*635a8641SAndroid Build Coastguard Worker   MemoryBarrier();
123*635a8641SAndroid Build Coastguard Worker }
124*635a8641SAndroid Build Coastguard Worker 
Release_Store(volatile Atomic32 * ptr,Atomic32 value)125*635a8641SAndroid Build Coastguard Worker inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
126*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
127*635a8641SAndroid Build Coastguard Worker }
128*635a8641SAndroid Build Coastguard Worker 
NoBarrier_Load(volatile const Atomic32 * ptr)129*635a8641SAndroid Build Coastguard Worker inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
130*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
131*635a8641SAndroid Build Coastguard Worker }
132*635a8641SAndroid Build Coastguard Worker 
Acquire_Load(volatile const Atomic32 * ptr)133*635a8641SAndroid Build Coastguard Worker inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
134*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
135*635a8641SAndroid Build Coastguard Worker }
136*635a8641SAndroid Build Coastguard Worker 
Release_Load(volatile const Atomic32 * ptr)137*635a8641SAndroid Build Coastguard Worker inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
138*635a8641SAndroid Build Coastguard Worker   MemoryBarrier();
139*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
140*635a8641SAndroid Build Coastguard Worker }
141*635a8641SAndroid Build Coastguard Worker 
142*635a8641SAndroid Build Coastguard Worker #if defined(ARCH_CPU_64_BITS)
143*635a8641SAndroid Build Coastguard Worker 
144*635a8641SAndroid Build Coastguard Worker typedef volatile std::atomic<Atomic64>* AtomicLocation64;
145*635a8641SAndroid Build Coastguard Worker static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
146*635a8641SAndroid Build Coastguard Worker               "incompatible 64-bit atomic layout");
147*635a8641SAndroid Build Coastguard Worker 
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)148*635a8641SAndroid Build Coastguard Worker inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
149*635a8641SAndroid Build Coastguard Worker                                          Atomic64 old_value,
150*635a8641SAndroid Build Coastguard Worker                                          Atomic64 new_value) {
151*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation64)ptr)
152*635a8641SAndroid Build Coastguard Worker       ->compare_exchange_strong(old_value,
153*635a8641SAndroid Build Coastguard Worker                                 new_value,
154*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_relaxed,
155*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_relaxed);
156*635a8641SAndroid Build Coastguard Worker   return old_value;
157*635a8641SAndroid Build Coastguard Worker }
158*635a8641SAndroid Build Coastguard Worker 
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)159*635a8641SAndroid Build Coastguard Worker inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
160*635a8641SAndroid Build Coastguard Worker                                          Atomic64 new_value) {
161*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation64)ptr)
162*635a8641SAndroid Build Coastguard Worker       ->exchange(new_value, std::memory_order_relaxed);
163*635a8641SAndroid Build Coastguard Worker }
164*635a8641SAndroid Build Coastguard Worker 
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)165*635a8641SAndroid Build Coastguard Worker inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
166*635a8641SAndroid Build Coastguard Worker                                           Atomic64 increment) {
167*635a8641SAndroid Build Coastguard Worker   return increment +
168*635a8641SAndroid Build Coastguard Worker          ((AtomicLocation64)ptr)
169*635a8641SAndroid Build Coastguard Worker              ->fetch_add(increment, std::memory_order_relaxed);
170*635a8641SAndroid Build Coastguard Worker }
171*635a8641SAndroid Build Coastguard Worker 
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)172*635a8641SAndroid Build Coastguard Worker inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
173*635a8641SAndroid Build Coastguard Worker                                         Atomic64 increment) {
174*635a8641SAndroid Build Coastguard Worker   return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
175*635a8641SAndroid Build Coastguard Worker }
176*635a8641SAndroid Build Coastguard Worker 
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)177*635a8641SAndroid Build Coastguard Worker inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
178*635a8641SAndroid Build Coastguard Worker                                        Atomic64 old_value,
179*635a8641SAndroid Build Coastguard Worker                                        Atomic64 new_value) {
180*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation64)ptr)
181*635a8641SAndroid Build Coastguard Worker       ->compare_exchange_strong(old_value,
182*635a8641SAndroid Build Coastguard Worker                                 new_value,
183*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_acquire,
184*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_acquire);
185*635a8641SAndroid Build Coastguard Worker   return old_value;
186*635a8641SAndroid Build Coastguard Worker }
187*635a8641SAndroid Build Coastguard Worker 
Release_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)188*635a8641SAndroid Build Coastguard Worker inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
189*635a8641SAndroid Build Coastguard Worker                                        Atomic64 old_value,
190*635a8641SAndroid Build Coastguard Worker                                        Atomic64 new_value) {
191*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation64)ptr)
192*635a8641SAndroid Build Coastguard Worker       ->compare_exchange_strong(old_value,
193*635a8641SAndroid Build Coastguard Worker                                 new_value,
194*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_release,
195*635a8641SAndroid Build Coastguard Worker                                 std::memory_order_relaxed);
196*635a8641SAndroid Build Coastguard Worker   return old_value;
197*635a8641SAndroid Build Coastguard Worker }
198*635a8641SAndroid Build Coastguard Worker 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)199*635a8641SAndroid Build Coastguard Worker inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
200*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
201*635a8641SAndroid Build Coastguard Worker }
202*635a8641SAndroid Build Coastguard Worker 
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)203*635a8641SAndroid Build Coastguard Worker inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
204*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
205*635a8641SAndroid Build Coastguard Worker   MemoryBarrier();
206*635a8641SAndroid Build Coastguard Worker }
207*635a8641SAndroid Build Coastguard Worker 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)208*635a8641SAndroid Build Coastguard Worker inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
209*635a8641SAndroid Build Coastguard Worker   ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
210*635a8641SAndroid Build Coastguard Worker }
211*635a8641SAndroid Build Coastguard Worker 
NoBarrier_Load(volatile const Atomic64 * ptr)212*635a8641SAndroid Build Coastguard Worker inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
213*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
214*635a8641SAndroid Build Coastguard Worker }
215*635a8641SAndroid Build Coastguard Worker 
Acquire_Load(volatile const Atomic64 * ptr)216*635a8641SAndroid Build Coastguard Worker inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
217*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
218*635a8641SAndroid Build Coastguard Worker }
219*635a8641SAndroid Build Coastguard Worker 
Release_Load(volatile const Atomic64 * ptr)220*635a8641SAndroid Build Coastguard Worker inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
221*635a8641SAndroid Build Coastguard Worker   MemoryBarrier();
222*635a8641SAndroid Build Coastguard Worker   return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
223*635a8641SAndroid Build Coastguard Worker }
224*635a8641SAndroid Build Coastguard Worker 
225*635a8641SAndroid Build Coastguard Worker #endif  // defined(ARCH_CPU_64_BITS)
226*635a8641SAndroid Build Coastguard Worker }  // namespace subtle
227*635a8641SAndroid Build Coastguard Worker }  // namespace base
228*635a8641SAndroid Build Coastguard Worker 
229*635a8641SAndroid Build Coastguard Worker #endif  // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
230