My Project
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
SDL_atomic.h
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 
59 #ifndef _SDL_atomic_h_
60 #define _SDL_atomic_h_
61 
62 #include "SDL_stdinc.h"
63 #include "SDL_platform.h"
64 
65 #include "begin_code.h"
66 
67 /* Need to do this here because intrin.h has C++ code in it */
68 /* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
69 #if defined(_MSC_VER) && (_MSC_VER >= 1500)
70 #include <intrin.h>
71 #define HAVE_MSC_ATOMICS 1
72 #endif
73 
74 /* Set up for C function definitions, even when using C++ */
75 #ifdef __cplusplus
76 extern "C" {
77 #endif
78 
94 /* @{ */
95 
96 typedef int SDL_SpinLock;
97 
105 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock);
106 
112 extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
113 
119 extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
120 
121 /* @} *//* SDL AtomicLock */
122 
123 
128 #if defined(_MSC_VER) && (_MSC_VER > 1200)
129 void _ReadWriteBarrier(void);
130 #pragma intrinsic(_ReadWriteBarrier)
131 #define SDL_CompilerBarrier() _ReadWriteBarrier()
132 #elif defined(__GNUC__)
133 #define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
134 #else
135 #define SDL_CompilerBarrier() \
136 { SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); }
137 #endif
138 
158 #if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
159 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
160 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
161 #elif defined(__GNUC__) && defined(__arm__)
162 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
163 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
164 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
165 #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
166 #ifdef __thumb__
167 /* The mcr instruction isn't available in thumb mode, use real functions */
168 extern DECLSPEC void SDLCALL SDL_MemoryBarrierRelease();
169 extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquire();
170 #else
171 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
172 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
173 #endif /* __thumb__ */
174 #else
175 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
176 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
177 #endif /* __GNUC__ && __arm__ */
178 #else
179 /* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
180 #define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
181 #define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
182 #endif
183 
184 
185 /* Platform specific optimized versions of the atomic functions,
186  * you can disable these by defining SDL_DISABLE_ATOMIC_INLINE
187  */
188 #if defined(SDL_ATOMIC_DISABLED) && SDL_ATOMIC_DISABLED
189 #define SDL_DISABLE_ATOMIC_INLINE
190 #endif
191 #ifndef SDL_DISABLE_ATOMIC_INLINE
192 
193 #ifdef HAVE_MSC_ATOMICS
194 
195 #define SDL_AtomicSet(a, v) _InterlockedExchange((long*)&(a)->value, (v))
196 #define SDL_AtomicAdd(a, v) _InterlockedExchangeAdd((long*)&(a)->value, (v))
197 #define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange((long*)&(a)->value, (newval), (oldval)) == (oldval))
198 #define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v))
199 #if _M_IX86
200 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval))
201 #else
202 #define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval))
203 #endif
204 
205 #elif defined(__MACOSX__)
206 #include <libkern/OSAtomic.h>
207 
208 #define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value)
209 #ifdef __LP64__
210 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a))
211 #else
212 #define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a))
213 #endif
214 
215 #elif defined(HAVE_GCC_ATOMICS)
216 
217 #define SDL_AtomicSet(a, v) __sync_lock_test_and_set(&(a)->value, v)
218 #define SDL_AtomicAdd(a, v) __sync_fetch_and_add(&(a)->value, v)
219 #define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v)
220 #define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval)
221 #define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval)
222 
223 #endif
224 
225 #endif /* !SDL_DISABLE_ATOMIC_INLINE */
226 
227 
232 #ifndef SDL_atomic_t_defined
233 typedef struct { int value; } SDL_atomic_t;
234 #endif
235 
243 #ifndef SDL_AtomicCAS
244 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
245 #endif
246 
252 #ifndef SDL_AtomicSet
253 SDL_FORCE_INLINE int SDL_AtomicSet(SDL_atomic_t *a, int v)
254 {
255  int value;
256  do {
257  value = a->value;
258  } while (!SDL_AtomicCAS(a, value, v));
259  return value;
260 }
261 #endif
262 
266 #ifndef SDL_AtomicGet
267 SDL_FORCE_INLINE int SDL_AtomicGet(SDL_atomic_t *a)
268 {
269  int value = a->value;
271  return value;
272 }
273 #endif
274 
282 #ifndef SDL_AtomicAdd
283 SDL_FORCE_INLINE int SDL_AtomicAdd(SDL_atomic_t *a, int v)
284 {
285  int value;
286  do {
287  value = a->value;
288  } while (!SDL_AtomicCAS(a, value, (value + v)));
289  return value;
290 }
291 #endif
292 
296 #ifndef SDL_AtomicIncRef
297 #define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
298 #endif
299 
306 #ifndef SDL_AtomicDecRef
307 #define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
308 #endif
309 
317 #ifndef SDL_AtomicCASPtr
318 extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void* *a, void *oldval, void *newval);
319 #endif
320 
326 #ifndef SDL_AtomicSetPtr
327 SDL_FORCE_INLINE void* SDL_AtomicSetPtr(void* *a, void* v)
328 {
329  void* value;
330  do {
331  value = *a;
332  } while (!SDL_AtomicCASPtr(a, value, v));
333  return value;
334 }
335 #endif
336 
340 #ifndef SDL_AtomicGetPtr
341 SDL_FORCE_INLINE void* SDL_AtomicGetPtr(void* *a)
342 {
343  void* value = *a;
345  return value;
346 }
347 #endif
348 
349 
350 /* Ends C function definitions when using C++ */
351 #ifdef __cplusplus
352 }
353 #endif
354 
355 #include "close_code.h"
356 
357 #endif /* _SDL_atomic_h_ */
358 
359 /* vi: set ts=4 sw=4 expandtab: */
SDL_FORCE_INLINE void * SDL_AtomicGetPtr(void **a)
Set a pointer to a new value if it is currently an old value.
Definition: SDL_atomic.h:341
#define SDL_CompilerBarrier()
Definition: SDL_atomic.h:135
DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock)
Try to lock a spin lock by setting it to a non-zero value.
#define SDL_MemoryBarrierRelease()
Definition: SDL_atomic.h:180
SDL_FORCE_INLINE int SDL_AtomicGet(SDL_atomic_t *a)
Set an atomic variable to a new value if it is currently an old value.
Definition: SDL_atomic.h:267
DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock)
Lock a spin lock by setting it to a non-zero value.
A type representing an atomic integer value. It is a struct so people don&#39;t accidentally use numeric ...
Definition: SDL_atomic.h:233
DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock)
Unlock a spin lock by setting it to 0. Always returns immediately.