Jamoma API  0.6.0.a19
CAAtomic.h
1 /* Copyright 2007 Apple Inc. All Rights Reserved.
2 
3  Disclaimer: IMPORTANT: This Apple software is supplied to you by
4  Apple Inc. ("Apple") in consideration of your agreement to the
5  following terms, and your use, installation, modification or
6  redistribution of this Apple software constitutes acceptance of these
7  terms. If you do not agree with these terms, please do not use,
8  install, modify or redistribute this Apple software.
9 
10  In consideration of your agreement to abide by the following terms, and
11  subject to these terms, Apple grants you a personal, non-exclusive
12  license, under Apple's copyrights in this original Apple software (the
13  "Apple Software"), to use, reproduce, modify and redistribute the Apple
14  Software, with or without modifications, in source and/or binary forms;
15  provided that if you redistribute the Apple Software in its entirety and
16  without modifications, you must retain this notice and the following
17  text and disclaimers in all such redistributions of the Apple Software.
18  Neither the name, trademarks, service marks or logos of Apple Inc.
19  may be used to endorse or promote products derived from the Apple
20  Software without specific prior written permission from Apple. Except
21  as expressly stated in this notice, no other rights or licenses, express
22  or implied, are granted by Apple herein, including but not limited to
23  any patent rights that may be infringed by your derivative works or by
24  other works in which the Apple Software may be incorporated.
25 
26  The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
31 
32  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39  POSSIBILITY OF SUCH DAMAGE.
40 */
41 /*
42  This file implements all Atomic operations using Interlocked functions specified in
43  Winbase.h
44 NOTE: According to Microsoft documentation, all Interlocked functions generates a
45 full barrier.
46  On Windows:
47  As the Interlocked functions returns the Old value, Extra checks and operations
48  are made after the atomic operation to return value consistent with OSX counterparts.
49 */
50 #ifndef __CAAtomic_h__
51 #define __CAAtomic_h__
52 
53 #if TARGET_OS_WIN32
54  #include <windows.h>
55  #include <intrin.h>
56 #else
57  #include <CoreFoundation/CFBase.h>
58  #include <libkern/OSAtomic.h>
59 #endif
60 
61 inline void CAMemoryBarrier()
62 {
63 #if TARGET_OS_WIN32
64  MemoryBarrier();
65 #else
66  OSMemoryBarrier();
67 #endif
68 }
69 
70 inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue)
71 {
72 #if TARGET_OS_WIN32
73  long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt);
74  // InterlockedExchangeAdd returns the original value which differs from OSX version.
75  // At this point the addition would have occured and hence returning the new value
76  // to keep it sync with OSX.
77  return lRetVal + theAmt;
78 #else
79  return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue);
80 #endif
81 }
82 
83 inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue)
84 {
85 #if TARGET_OS_WIN32
86  // InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
87  // function instead.
88  long j = _InterlockedOr((volatile long*)theValue, theMask);
89  // _InterlockedOr returns the original value which differs from OSX version.
90  // Returning the new value similar to OSX
91  return (SInt32)(j | theMask);
92 #else
93  return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue);
94 #endif
95 }
96 
97 inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue)
98 {
99 #if TARGET_OS_WIN32
100 // InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
101 // function instead.
102  long j = _InterlockedAnd((volatile long*)theValue, theMask);
103  // _InterlockedAnd returns the original value which differs from OSX version.
104  // Returning the new value similar to OSX
105  return (SInt32)(j & theMask);
106 #else
107  return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue);
108 #endif
109 }
110 
111 inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue)
112 {
113 #if TARGET_OS_WIN32
114  // InterlockedCompareExchange returns the old value. But we need to return bool value.
115  long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue);
116 // Hence we check if the new value is set and if it is we return true else false.
117 // If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen.
118  return (oldValue == lRetVal);
119 #else
120  return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue);
121 #endif
122 }
123 
124 
125 inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue)
126 {
127 #if TARGET_OS_WIN32
128  return (SInt32)InterlockedIncrement((volatile long*)theValue);
129 #else
130  return OSAtomicIncrement32((volatile int32_t *)theValue);
131 #endif
132 }
133 
134 inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue)
135 {
136 #if TARGET_OS_WIN32
137  return (SInt32)InterlockedDecrement((volatile long*)theValue);
138 #else
139  return OSAtomicDecrement32((volatile int32_t *)theValue);
140 #endif
141 }
142 
143 inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue)
144 {
145 #if TARGET_OS_WIN32
146  return CAAtomicIncrement32(theValue);
147 #else
148  return OSAtomicIncrement32Barrier((volatile int32_t *)theValue);
149 #endif
150 }
151 
152 inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue)
153 {
154 #if TARGET_OS_WIN32
155  return CAAtomicDecrement32(theValue);
156 #else
157  return OSAtomicDecrement32Barrier((volatile int32_t *)theValue);
158 #endif
159 }
160 
161 inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress)
162 {
163 #if TARGET_OS_WIN32
164  BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear);
165  return (bOldVal ? true : false);
166 #else
167  return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress);
168 #endif
169 }
170 
171 inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress)
172 {
173 #if TARGET_OS_WIN32
174  BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress);
175  return (bOldVal ? true : false);
176 #else
177  return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress);
178 #endif
179 }
180 
181 inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress)
182 {
183 #if TARGET_OS_WIN32
184  BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet);
185  return (bOldVal ? true : false);
186 #else
187  return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress);
188 #endif
189 }
190 
191 // int32_t flavors -- for C++ only since we can't overload in C
192 // CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then
193 // this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where
194 // SInt32 is defined as signed long so this would work there.
195 // So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included.
196 #if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__
197 inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue)
198 {
199  return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue);
200 }
201 
202 inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue)
203 {
204  return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue);
205 }
206 
207 inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue)
208 {
209  return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue);
210 }
211 
212 inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue)
213 {
214  return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue);
215 }
216 
217 inline int32_t CAAtomicIncrement32(volatile int32_t* theValue)
218 {
219  return CAAtomicIncrement32((volatile SInt32 *)theValue);
220 }
221 
222 inline int32_t CAAtomicDecrement32(volatile int32_t* theValue)
223 {
224  return CAAtomicDecrement32((volatile SInt32 *)theValue);
225 }
226 
227 inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue)
228 {
229  return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue);
230 }
231 
232 inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue)
233 {
234  return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue);
235 }
236 #endif // __cplusplus && !__LP64__
237 
238 #if __LP64__
239 inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue )
240 {
241  return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue );
242 }
243 #endif
244 
245 /* Spinlocks. These use memory barriers as required to synchronize access to shared
246  * memory protected by the lock. The lock operation spins, but employs various strategies
247  * to back off if the lock is held, making it immune to most priority-inversion livelocks.
248  * The try operation immediately returns false if the lock was held, true if it took the
249  * lock. The convention is that unlocked is zero, locked is nonzero.
250  */
251 #define CA_SPINLOCK_INIT 0
252 
253 typedef int32_t CASpinLock;
254 
255 bool CASpinLockTry( volatile CASpinLock *__lock );
256 void CASpinLockLock( volatile CASpinLock *__lock );
257 void CASpinLockUnlock( volatile CASpinLock *__lock );
258 
259 inline void CASpinLockLock( volatile CASpinLock *__lock )
260 {
261 #if TARGET_OS_MAC
262  OSSpinLockLock(__lock);
263 #else
264  while (CAAtomicTestAndSetBarrier(0, (void*)__lock))
265  usleep(1000); // ???
266 #endif
267 }
268 
269 inline void CASpinLockUnlock( volatile CASpinLock *__lock )
270 {
271 #if TARGET_OS_MAC
272  OSSpinLockUnlock(__lock);
273 #else
274  CAAtomicTestAndClearBarrier(0, (void*)__lock);
275 #endif
276 }
277 
278 inline bool CASpinLockTry( volatile CASpinLock *__lock )
279 {
280 #if TARGET_OS_MAC
281  return OSSpinLockTry(__lock);
282 #else
283  return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0);
284 #endif
285 }
286 
287 
288 #endif // __CAAtomic_h__