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