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