1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 // This file is an internal atomic implementation, use
8 // base/atomicops.h instead.
9 //
10 // This is a very slow fallback implementation of atomic operations
11 // that uses a mutex instead of atomic instructions.
12 //
13 // (NB: a small "optimization" here would be using a spinlock instead
14 // of a blocking mutex, but it's probably not worth the time.)
15
16 #ifndef base_atomicops_internals_mutex_h
17 #define base_atomicops_internals_mutex_h
18
19 #include "base/lock.h"
20
21 namespace base {
22 namespace subtle {
23
24 extern Lock gAtomicsMutex;
25
26 template <typename T>
Locked_CAS(volatile T * ptr,T old_value,T new_value)27 T Locked_CAS(volatile T* ptr, T old_value, T new_value) {
28 AutoLock _(gAtomicsMutex);
29
30 T current_value = *ptr;
31 if (current_value == old_value) *ptr = new_value;
32
33 return current_value;
34 }
35
36 template <typename T>
Locked_AtomicExchange(volatile T * ptr,T new_value)37 T Locked_AtomicExchange(volatile T* ptr, T new_value) {
38 AutoLock _(gAtomicsMutex);
39
40 T current_value = *ptr;
41 *ptr = new_value;
42 return current_value;
43 }
44
45 template <typename T>
Locked_AtomicIncrement(volatile T * ptr,T increment)46 T Locked_AtomicIncrement(volatile T* ptr, T increment) {
47 AutoLock _(gAtomicsMutex);
48 return *ptr += increment;
49 }
50
51 template <typename T>
Locked_Store(volatile T * ptr,T value)52 void Locked_Store(volatile T* ptr, T value) {
53 AutoLock _(gAtomicsMutex);
54 *ptr = value;
55 }
56
57 template <typename T>
Locked_Load(volatile const T * ptr)58 T Locked_Load(volatile const T* ptr) {
59 AutoLock _(gAtomicsMutex);
60 return *ptr;
61 }
62
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)63 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
64 Atomic32 old_value,
65 Atomic32 new_value) {
66 return Locked_CAS(ptr, old_value, new_value);
67 }
68
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)69 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
70 Atomic32 new_value) {
71 return Locked_AtomicExchange(ptr, new_value);
72 }
73
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)74 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
75 Atomic32 increment) {
76 return Locked_AtomicIncrement(ptr, increment);
77 }
78
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)79 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
80 Atomic32 increment) {
81 return Locked_AtomicIncrement(ptr, increment);
82 }
83
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)84 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
85 Atomic32 old_value, Atomic32 new_value) {
86 return Locked_CAS(ptr, old_value, new_value);
87 }
88
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)89 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
90 Atomic32 old_value, Atomic32 new_value) {
91 return Locked_CAS(ptr, old_value, new_value);
92 }
93
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)94 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
95 return Locked_Store(ptr, value);
96 }
97
MemoryBarrier()98 inline void MemoryBarrier() {
99 AutoLock _(gAtomicsMutex);
100 // lock/unlock work as a barrier here
101 }
102
Acquire_Store(volatile Atomic32 * ptr,Atomic32 value)103 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
104 return Locked_Store(ptr, value);
105 }
106
Release_Store(volatile Atomic32 * ptr,Atomic32 value)107 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
108 return Locked_Store(ptr, value);
109 }
110
NoBarrier_Load(volatile const Atomic32 * ptr)111 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
112 return Locked_Load(ptr);
113 }
114
Acquire_Load(volatile const Atomic32 * ptr)115 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
116 return NoBarrier_Load(ptr);
117 }
118
Release_Load(volatile const Atomic32 * ptr)119 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
120 return Locked_Load(ptr);
121 }
122
123 #ifdef ARCH_CPU_64_BITS
124
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)125 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
126 Atomic64 old_value,
127 Atomic64 new_value) {
128 return Locked_CAS(ptr, old_value, new_value);
129 }
130
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)131 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
132 Atomic64 new_value) {
133 return Locked_AtomicExchange(ptr, new_value);
134 }
135
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)136 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
137 Atomic64 increment) {
138 return Locked_AtomicIncrement(ptr, increment);
139 }
140
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)141 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
142 Atomic64 increment) {
143 return Locked_AtomicIncrement(ptr, increment);
144 }
145
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)146 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
147 return Locked_Store(ptr, value);
148 }
149
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)150 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
151 Atomic64 old_value, Atomic64 new_value) {
152 return Locked_CAS(ptr, old_value, new_value);
153 }
154
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)155 inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
156 return Locked_Store(ptr, value);
157 }
158
Release_Store(volatile Atomic64 * ptr,Atomic64 value)159 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
160 return Locked_Store(ptr, value);
161 }
162
NoBarrier_Load(volatile const Atomic64 * ptr)163 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
164 return Locked_Load(ptr);
165 }
166
Acquire_Load(volatile const Atomic64 * ptr)167 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
168 return Locked_Load(ptr);
169 }
170
Release_Load(volatile const Atomic64 * ptr)171 inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
172 return Locked_Load(ptr);
173 }
174
175 #endif // ARCH_CPU_64_BITS
176
177 #ifdef OS_MACOSX
178 // From atomicops_internals_x86_macosx.h:
179 //
180 // MacOS uses long for intptr_t, AtomicWord and Atomic32 are always
181 // different on the Mac, even when they are the same size. We need
182 // to explicitly cast from AtomicWord to Atomic32/64 to implement
183 // the AtomicWord interface.
184
NoBarrier_CompareAndSwap(volatile AtomicWord * ptr,AtomicWord old_value,AtomicWord new_value)185 inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
186 AtomicWord old_value,
187 AtomicWord new_value) {
188 return Locked_CAS(ptr, old_value, new_value);
189 }
190
NoBarrier_AtomicExchange(volatile AtomicWord * ptr,AtomicWord new_value)191 inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
192 AtomicWord new_value) {
193 return Locked_AtomicExchange(ptr, new_value);
194 }
195
NoBarrier_AtomicIncrement(volatile AtomicWord * ptr,AtomicWord increment)196 inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
197 AtomicWord increment) {
198 return Locked_AtomicIncrement(ptr, increment);
199 }
200
Barrier_AtomicIncrement(volatile AtomicWord * ptr,AtomicWord increment)201 inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
202 AtomicWord increment) {
203 return Locked_AtomicIncrement(ptr, increment);
204 }
205
Acquire_CompareAndSwap(volatile AtomicWord * ptr,AtomicWord old_value,AtomicWord new_value)206 inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
207 AtomicWord old_value,
208 AtomicWord new_value) {
209 return Locked_CAS(ptr, old_value, new_value);
210 }
211
Release_CompareAndSwap(volatile AtomicWord * ptr,AtomicWord old_value,AtomicWord new_value)212 inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
213 AtomicWord old_value,
214 AtomicWord new_value) {
215 return Locked_CAS(ptr, old_value, new_value);
216 }
217
NoBarrier_Store(volatile AtomicWord * ptr,AtomicWord value)218 inline void NoBarrier_Store(volatile AtomicWord* ptr, AtomicWord value) {
219 return Locked_Store(ptr, value);
220 }
221
Acquire_Store(volatile AtomicWord * ptr,AtomicWord value)222 inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
223 return Locked_Store(ptr, value);
224 }
225
Release_Store(volatile AtomicWord * ptr,AtomicWord value)226 inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
227 return Locked_Store(ptr, value);
228 }
229
NoBarrier_Load(volatile const AtomicWord * ptr)230 inline AtomicWord NoBarrier_Load(volatile const AtomicWord* ptr) {
231 return Locked_Load(ptr);
232 }
233
Acquire_Load(volatile const AtomicWord * ptr)234 inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
235 return Locked_Load(ptr);
236 }
237
Release_Load(volatile const AtomicWord * ptr)238 inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
239 return Locked_Load(ptr);
240 }
241
242 #endif // OS_MACOSX
243
244 } // namespace subtle
245 } // namespace base
246
247 #endif // base_atomicops_internals_mutex_h
248