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