• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2006, Google Inc.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 // Implementation of atomic operations for Mac OS X.  This file should not
32 // be included directly.  Clients should instead include
33 // "base/atomicops.h".
34 
35 #ifndef BASE_ATOMICOPS_INTERNALS_MACOSX_H_
36 #define BASE_ATOMICOPS_INTERNALS_MACOSX_H_
37 
38 typedef int32_t Atomic32;
39 
40 // MacOS uses long for intptr_t, AtomicWord and Atomic32 are always different
41 // on the Mac, even when they are the same size.  Similarly, on __ppc64__,
42 // AtomicWord and Atomic64 are always different.  Thus, we need explicit
43 // casting.
44 #ifdef __LP64__
45 #define AtomicWordCastType base::subtle::Atomic64
46 #else
47 #define AtomicWordCastType Atomic32
48 #endif
49 
50 #if defined(__LP64__) || defined(__i386__)
51 #define BASE_HAS_ATOMIC64 1  // Use only in tests and base/atomic*
52 #endif
53 
54 #include <libkern/OSAtomic.h>
55 
56 namespace base {
57 namespace subtle {
58 
59 #if !defined(__LP64__) && defined(__ppc__)
60 
61 // The Mac 64-bit OSAtomic implementations are not available for 32-bit PowerPC,
62 // while the underlying assembly instructions are available only some
63 // implementations of PowerPC.
64 
65 // The following inline functions will fail with the error message at compile
66 // time ONLY IF they are called.  So it is safe to use this header if user
67 // code only calls AtomicWord and Atomic32 operations.
68 //
69 // NOTE(vchen): Implementation notes to implement the atomic ops below may
70 // be found in "PowerPC Virtual Environment Architecture, Book II,
71 // Version 2.02", January 28, 2005, Appendix B, page 46.  Unfortunately,
72 // extra care must be taken to ensure data are properly 8-byte aligned, and
73 // that data are returned correctly according to Mac OS X ABI specs.
74 
OSAtomicCompareAndSwap64(int64_t oldValue,int64_t newValue,int64_t * theValue)75 inline int64_t OSAtomicCompareAndSwap64(
76     int64_t oldValue, int64_t newValue, int64_t *theValue) {
77   __asm__ __volatile__(
78       "_OSAtomicCompareAndSwap64_not_supported_for_32_bit_ppc\n\t");
79   return 0;
80 }
81 
OSAtomicAdd64(int64_t theAmount,int64_t * theValue)82 inline int64_t OSAtomicAdd64(int64_t theAmount, int64_t *theValue) {
83   __asm__ __volatile__(
84       "_OSAtomicAdd64_not_supported_for_32_bit_ppc\n\t");
85   return 0;
86 }
87 
OSAtomicCompareAndSwap64Barrier(int64_t oldValue,int64_t newValue,int64_t * theValue)88 inline int64_t OSAtomicCompareAndSwap64Barrier(
89     int64_t oldValue, int64_t newValue, int64_t *theValue) {
90   int64_t prev = OSAtomicCompareAndSwap64(oldValue, newValue, theValue);
91   OSMemoryBarrier();
92   return prev;
93 }
94 
OSAtomicAdd64Barrier(int64_t theAmount,int64_t * theValue)95 inline int64_t OSAtomicAdd64Barrier(
96     int64_t theAmount, int64_t *theValue) {
97   int64_t new_val = OSAtomicAdd64(theAmount, theValue);
98   OSMemoryBarrier();
99   return new_val;
100 }
101 #endif
102 
103 typedef int64_t Atomic64;
104 
MemoryBarrier()105 inline void MemoryBarrier() {
106   OSMemoryBarrier();
107 }
108 
109 // 32-bit Versions.
110 
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)111 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
112                                          Atomic32 old_value,
113                                          Atomic32 new_value) {
114   Atomic32 prev_value;
115   do {
116     if (OSAtomicCompareAndSwap32(old_value, new_value,
117                                  const_cast<Atomic32*>(ptr))) {
118       return old_value;
119     }
120     prev_value = *ptr;
121   } while (prev_value == old_value);
122   return prev_value;
123 }
124 
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)125 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
126                                          Atomic32 new_value) {
127   Atomic32 old_value;
128   do {
129     old_value = *ptr;
130   } while (!OSAtomicCompareAndSwap32(old_value, new_value,
131                                      const_cast<Atomic32*>(ptr)));
132   return old_value;
133 }
134 
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)135 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
136                                           Atomic32 increment) {
137   return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
138 }
139 
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)140 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
141                                           Atomic32 increment) {
142   return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
143 }
144 
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)145 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
146                                        Atomic32 old_value,
147                                        Atomic32 new_value) {
148   Atomic32 prev_value;
149   do {
150     if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
151                                         const_cast<Atomic32*>(ptr))) {
152       return old_value;
153     }
154     prev_value = *ptr;
155   } while (prev_value == old_value);
156   return prev_value;
157 }
158 
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)159 inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
160                                        Atomic32 old_value,
161                                        Atomic32 new_value) {
162   return Acquire_CompareAndSwap(ptr, old_value, new_value);
163 }
164 
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)165 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
166   *ptr = value;
167 }
168 
Acquire_Store(volatile Atomic32 * ptr,Atomic32 value)169 inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
170   *ptr = value;
171   MemoryBarrier();
172 }
173 
Release_Store(volatile Atomic32 * ptr,Atomic32 value)174 inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
175   MemoryBarrier();
176   *ptr = value;
177 }
178 
NoBarrier_Load(volatile const Atomic32 * ptr)179 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
180   return *ptr;
181 }
182 
Acquire_Load(volatile const Atomic32 * ptr)183 inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
184   Atomic32 value = *ptr;
185   MemoryBarrier();
186   return value;
187 }
188 
Release_Load(volatile const Atomic32 * ptr)189 inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
190   MemoryBarrier();
191   return *ptr;
192 }
193 
194 // 64-bit version
195 
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)196 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
197                                          Atomic64 old_value,
198                                          Atomic64 new_value) {
199   Atomic64 prev_value;
200   do {
201     if (OSAtomicCompareAndSwap64(old_value, new_value,
202                                  const_cast<Atomic64*>(ptr))) {
203       return old_value;
204     }
205     prev_value = *ptr;
206   } while (prev_value == old_value);
207   return prev_value;
208 }
209 
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)210 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
211                                          Atomic64 new_value) {
212   Atomic64 old_value;
213   do {
214     old_value = *ptr;
215   } while (!OSAtomicCompareAndSwap64(old_value, new_value,
216                                      const_cast<Atomic64*>(ptr)));
217   return old_value;
218 }
219 
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)220 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
221                                           Atomic64 increment) {
222   return OSAtomicAdd64(increment, const_cast<Atomic64*>(ptr));
223 }
224 
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)225 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
226                                         Atomic64 increment) {
227   return OSAtomicAdd64Barrier(increment, const_cast<Atomic64*>(ptr));
228 }
229 
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)230 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
231                                        Atomic64 old_value,
232                                        Atomic64 new_value) {
233   Atomic64 prev_value;
234   do {
235     if (OSAtomicCompareAndSwap64Barrier(old_value, new_value,
236                                         const_cast<Atomic64*>(ptr))) {
237       return old_value;
238     }
239     prev_value = *ptr;
240   } while (prev_value == old_value);
241   return prev_value;
242 }
243 
Release_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)244 inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
245                                        Atomic64 old_value,
246                                        Atomic64 new_value) {
247   // The lib kern interface does not distinguish between
248   // Acquire and Release memory barriers; they are equivalent.
249   return Acquire_CompareAndSwap(ptr, old_value, new_value);
250 }
251 
252 #ifdef __LP64__
253 
254 // 64-bit implementation on 64-bit platform
255 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)256 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
257   *ptr = value;
258 }
259 
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)260 inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
261   *ptr = value;
262   MemoryBarrier();
263 }
264 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)265 inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
266   MemoryBarrier();
267   *ptr = value;
268 }
269 
NoBarrier_Load(volatile const Atomic64 * ptr)270 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
271   return *ptr;
272 }
273 
Acquire_Load(volatile const Atomic64 * ptr)274 inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
275   Atomic64 value = *ptr;
276   MemoryBarrier();
277   return value;
278 }
279 
Release_Load(volatile const Atomic64 * ptr)280 inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
281   MemoryBarrier();
282   return *ptr;
283 }
284 
285 #else
286 
287 // 64-bit implementation on 32-bit platform
288 
289 #if defined(__ppc__)
290 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)291 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
292    __asm__ __volatile__(
293        "_NoBarrier_Store_not_supported_for_32_bit_ppc\n\t");
294 }
295 
NoBarrier_Load(volatile const Atomic64 * ptr)296 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
297    __asm__ __volatile__(
298        "_NoBarrier_Load_not_supported_for_32_bit_ppc\n\t");
299    return 0;
300 }
301 
302 #elif defined(__i386__)
303 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)304 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
305   __asm__ __volatile__("movq %1, %%mm0\n\t"    // Use mmx reg for 64-bit atomic
306                        "movq %%mm0, %0\n\t"  // moves (ptr could be read-only)
307                        "emms\n\t"              // Reset FP registers
308                        : "=m" (*ptr)
309                        : "m" (value)
310                        : // mark the FP stack and mmx registers as clobbered
311                          "st", "st(1)", "st(2)", "st(3)", "st(4)",
312                          "st(5)", "st(6)", "st(7)", "mm0", "mm1",
313                          "mm2", "mm3", "mm4", "mm5", "mm6", "mm7");
314 
315 }
316 
NoBarrier_Load(volatile const Atomic64 * ptr)317 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
318   Atomic64 value;
319   __asm__ __volatile__("movq %1, %%mm0\n\t"  // Use mmx reg for 64-bit atomic
320                        "movq %%mm0, %0\n\t"  // moves (ptr could be read-only)
321                        "emms\n\t"            // Reset FP registers
322                        : "=m" (value)
323                        : "m" (*ptr)
324                        : // mark the FP stack and mmx registers as clobbered
325                          "st", "st(1)", "st(2)", "st(3)", "st(4)",
326                          "st(5)", "st(6)", "st(7)", "mm0", "mm1",
327                          "mm2", "mm3", "mm4", "mm5", "mm6", "mm7");
328 
329   return value;
330 }
331 #endif
332 
333 
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)334 inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
335   NoBarrier_Store(ptr, value);
336   MemoryBarrier();
337 }
338 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)339 inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
340   MemoryBarrier();
341   NoBarrier_Store(ptr, value);
342 }
343 
Acquire_Load(volatile const Atomic64 * ptr)344 inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
345   Atomic64 value = NoBarrier_Load(ptr);
346   MemoryBarrier();
347   return value;
348 }
349 
Release_Load(volatile const Atomic64 * ptr)350 inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
351   MemoryBarrier();
352   return NoBarrier_Load(ptr);
353 }
354 #endif  // __LP64__
355 
356 }   // namespace base::subtle
357 }   // namespace base
358 
359 #endif  // BASE_ATOMICOPS_INTERNALS_MACOSX_H_
360