3 Abstract: Part of CoreAudio Utility Classes
6 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
7 Inc. ("Apple") in consideration of your agreement to the following
8 terms, and your use, installation, modification or redistribution of
9 this Apple software constitutes acceptance of these terms. If you do
10 not agree with these terms, please do not use, install, modify or
11 redistribute this Apple software.
13 In consideration of your agreement to abide by the following terms, and
14 subject to these terms, Apple grants you a personal, non-exclusive
15 license, under Apple's copyrights in this original Apple software (the
16 "Apple Software"), to use, reproduce, modify and redistribute the Apple
17 Software, with or without modifications, in source and/or binary forms;
18 provided that if you redistribute the Apple Software in its entirety and
19 without modifications, you must retain this notice and the following
20 text and disclaimers in all such redistributions of the Apple Software.
21 Neither the name, trademarks, service marks or logos of Apple Inc. may
22 be used to endorse or promote products derived from the Apple Software
23 without specific prior written permission from Apple. Except as
24 expressly stated in this notice, no other rights or licenses, express or
25 implied, are granted by Apple herein, including but not limited to any
26 patent rights that may be infringed by your derivative works or by other
27 works in which the Apple Software may be incorporated.
29 The Apple Software is provided by Apple on an "AS IS" basis. APPLE
30 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
35 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42 POSSIBILITY OF SUCH DAMAGE.
44 Copyright (C) 2014 Apple Inc. All Rights Reserved.
48 This file implements all Atomic operations using Interlocked functions specified in
50 NOTE: According to Microsoft documentation, all Interlocked functions generates a
53 As the Interlocked functions returns the Old value, Extra checks and operations
54 are made after the atomic operation to return value consistent with OSX counterparts.
56 #ifndef __CAAtomic_h__
57 #define __CAAtomic_h__
62 #pragma intrinsic(_InterlockedOr)
\r
63 #pragma intrinsic(_InterlockedAnd)
65 #include <CoreFoundation/CFBase.h>
66 #include <libkern/OSAtomic.h>
69 inline void CAMemoryBarrier()
78 inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue)
81 long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt);
82 // InterlockedExchangeAdd returns the original value which differs from OSX version.
83 // At this point the addition would have occured and hence returning the new value
84 // to keep it sync with OSX.
85 return lRetVal + theAmt;
87 return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue);
91 inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue)
94 // InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
96 long j = _InterlockedOr((volatile long*)theValue, theMask);
97 // _InterlockedOr returns the original value which differs from OSX version.
98 // Returning the new value similar to OSX
99 return (SInt32)(j | theMask);
101 return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue);
105 inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue)
108 // InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
110 long j = _InterlockedAnd((volatile long*)theValue, theMask);
111 // _InterlockedAnd returns the original value which differs from OSX version.
112 // Returning the new value similar to OSX
113 return (SInt32)(j & theMask);
115 return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue);
119 inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue)
122 // InterlockedCompareExchange returns the old value. But we need to return bool value.
123 long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue);
124 // Hence we check if the new value is set and if it is we return true else false.
125 // If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen.
126 return (oldValue == lRetVal);
128 return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue);
133 inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue)
136 return (SInt32)InterlockedIncrement((volatile long*)theValue);
138 return OSAtomicIncrement32((volatile int32_t *)theValue);
142 inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue)
145 return (SInt32)InterlockedDecrement((volatile long*)theValue);
147 return OSAtomicDecrement32((volatile int32_t *)theValue);
151 inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue)
154 return CAAtomicIncrement32(theValue);
156 return OSAtomicIncrement32Barrier((volatile int32_t *)theValue);
160 inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue)
163 return CAAtomicDecrement32(theValue);
165 return OSAtomicDecrement32Barrier((volatile int32_t *)theValue);
169 inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress)
172 BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear);
173 return (bOldVal ? true : false);
175 return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress);
179 inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress)
182 BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress);
183 return (bOldVal ? true : false);
185 return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress);
189 inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress)
192 BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet);
193 return (bOldVal ? true : false);
195 return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress);
199 // int32_t flavors -- for C++ only since we can't overload in C
200 // CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then
201 // this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where
202 // SInt32 is defined as signed long so this would work there.
203 // So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included.
204 #if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__
205 inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue)
207 return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue);
210 inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue)
212 return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue);
215 inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue)
217 return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue);
220 inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue)
222 return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue);
225 inline int32_t CAAtomicIncrement32(volatile int32_t* theValue)
227 return CAAtomicIncrement32((volatile SInt32 *)theValue);
230 inline int32_t CAAtomicDecrement32(volatile int32_t* theValue)
232 return CAAtomicDecrement32((volatile SInt32 *)theValue);
235 inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue)
237 return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue);
240 inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue)
242 return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue);
244 #endif // __cplusplus && !__LP64__
247 inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue )
249 return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue);
253 inline bool CAAtomicCompareAndSwapPtrBarrier(void *__oldValue, void *__newValue, volatile void ** __theValue)
256 return CAAtomicCompareAndSwap64Barrier((int64_t)__oldValue, (int64_t)__newValue, (int64_t *)__theValue);
258 return CAAtomicCompareAndSwap32Barrier((int32_t)__oldValue, (int32_t)__newValue, (int32_t *)__theValue);
262 /* Spinlocks. These use memory barriers as required to synchronize access to shared
263 * memory protected by the lock. The lock operation spins, but employs various strategies
264 * to back off if the lock is held, making it immune to most priority-inversion livelocks.
265 * The try operation immediately returns false if the lock was held, true if it took the
266 * lock. The convention is that unlocked is zero, locked is nonzero.
268 #define CA_SPINLOCK_INIT 0
270 typedef int32_t CASpinLock;
272 bool CASpinLockTry( volatile CASpinLock *__lock );
273 void CASpinLockLock( volatile CASpinLock *__lock );
274 void CASpinLockUnlock( volatile CASpinLock *__lock );
276 inline void CASpinLockLock( volatile CASpinLock *__lock )
279 OSSpinLockLock(__lock);
281 while (CAAtomicTestAndSetBarrier(0, (void*)__lock))
286 inline void CASpinLockUnlock( volatile CASpinLock *__lock )
289 OSSpinLockUnlock(__lock);
291 CAAtomicTestAndClearBarrier(0, (void*)__lock);
295 inline bool CASpinLockTry( volatile CASpinLock *__lock )
298 return OSSpinLockTry(__lock);
300 return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0);
305 #endif // __CAAtomic_h__