From 928b494630bf8d4024120e7ee0268b3799d8513f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 24 Nov 2013 21:04:51 -0500 Subject: [PATCH] Moved atomic API implementation out of headers. --- include/SDL_atomic.h | 111 ++---------------------------------- src/atomic/SDL_atomic.c | 123 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 117 insertions(+), 117 deletions(-) diff --git a/include/SDL_atomic.h b/include/SDL_atomic.h index 48b0053a0f444..43ba7543b6026 100644 --- a/include/SDL_atomic.h +++ b/include/SDL_atomic.h @@ -64,13 +64,6 @@ #include "begin_code.h" -/* Need to do this here because intrin.h has C++ code in it */ -/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -#include -#define HAVE_MSC_ATOMICS 1 -#endif - /* Set up for C function definitions, even when using C++ */ #ifdef __cplusplus extern "C" { @@ -181,57 +174,11 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquire(); #define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier() #endif - -/* Platform specific optimized versions of the atomic functions, - * you can disable these by defining SDL_DISABLE_ATOMIC_INLINE - */ -#if defined(SDL_ATOMIC_DISABLED) && SDL_ATOMIC_DISABLED -#define SDL_DISABLE_ATOMIC_INLINE -#endif -#ifndef SDL_DISABLE_ATOMIC_INLINE - -#ifdef HAVE_MSC_ATOMICS - -#define SDL_AtomicSet(a, v) _InterlockedExchange((long*)&(a)->value, (v)) -#define SDL_AtomicAdd(a, v) _InterlockedExchangeAdd((long*)&(a)->value, (v)) -#define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange((long*)&(a)->value, (newval), (oldval)) == (oldval)) -#define SDL_AtomicSetPtr(a, v) _InterlockedExchangePointer((a), (v)) -#if _M_IX86 -#define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval)) -#else -#define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval)) -#endif - -#elif defined(__MACOSX__) -#include - -#define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value) -#ifdef __LP64__ -#define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a)) -#else -#define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a)) -#endif - -#elif defined(HAVE_GCC_ATOMICS) - -#define SDL_AtomicSet(a, v) __sync_lock_test_and_set(&(a)->value, v) -#define SDL_AtomicAdd(a, v) __sync_fetch_and_add(&(a)->value, v) -#define SDL_AtomicSetPtr(a, v) __sync_lock_test_and_set(a, v) -#define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval) -#define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval) - -#endif - -#endif /* !SDL_DISABLE_ATOMIC_INLINE */ - - /** * \brief A type representing an atomic integer value. It is a struct * so people don't accidentally use numeric operations on it. */ -#ifndef SDL_atomic_t_defined typedef struct { int value; } SDL_atomic_t; -#endif /** * \brief Set an atomic variable to a new value if it is currently an old value. @@ -240,37 +187,19 @@ typedef struct { int value; } SDL_atomic_t; * * \note If you don't know what this function is for, you shouldn't use it! */ -#ifndef SDL_AtomicCAS extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval); -#endif /** * \brief Set an atomic variable to a value. * * \return The previous value of the atomic variable. */ -#ifndef SDL_AtomicSet -SDL_FORCE_INLINE int SDL_AtomicSet(SDL_atomic_t *a, int v) -{ - int value; - do { - value = a->value; - } while (!SDL_AtomicCAS(a, value, v)); - return value; -} -#endif +extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v); /** * \brief Get the value of an atomic variable */ -#ifndef SDL_AtomicGet -SDL_FORCE_INLINE int SDL_AtomicGet(SDL_atomic_t *a) -{ - int value = a->value; - SDL_CompilerBarrier(); - return value; -} -#endif +extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a); /** * \brief Add to an atomic variable. @@ -279,16 +208,7 @@ SDL_FORCE_INLINE int SDL_AtomicGet(SDL_atomic_t *a) * * \note This same style can be used for any number operation */ -#ifndef SDL_AtomicAdd -SDL_FORCE_INLINE int SDL_AtomicAdd(SDL_atomic_t *a, int v) -{ - int value; - do { - value = a->value; - } while (!SDL_AtomicCAS(a, value, (value + v))); - return value; -} -#endif +extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v); /** * \brief Increment an atomic variable used as a reference count. @@ -314,38 +234,19 @@ SDL_FORCE_INLINE int SDL_AtomicAdd(SDL_atomic_t *a, int v) * * \note If you don't know what this function is for, you shouldn't use it! */ -#ifndef SDL_AtomicCASPtr -extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void* *a, void *oldval, void *newval); -#endif +extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval); /** * \brief Set a pointer to a value atomically. * * \return The previous value of the pointer. */ -#ifndef SDL_AtomicSetPtr -SDL_FORCE_INLINE void* SDL_AtomicSetPtr(void* *a, void* v) -{ - void* value; - do { - value = *a; - } while (!SDL_AtomicCASPtr(a, value, v)); - return value; -} -#endif +extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v); /** * \brief Get the value of a pointer atomically. */ -#ifndef SDL_AtomicGetPtr -SDL_FORCE_INLINE void* SDL_AtomicGetPtr(void* *a) -{ - void* value = *a; - SDL_CompilerBarrier(); - return value; -} -#endif - +extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/src/atomic/SDL_atomic.c b/src/atomic/SDL_atomic.c index e9b636f3011c1..60d6f511bee09 100644 --- a/src/atomic/SDL_atomic.c +++ b/src/atomic/SDL_atomic.c @@ -22,13 +22,14 @@ #include "SDL_atomic.h" -/* Note that we undefine the atomic operations here, in case they are - defined as compiler intrinsics while building SDL but the library user - doesn't have that compiler. That way we always have a working set of - atomic operations built into the library. -*/ -#undef SDL_AtomicCAS -#undef SDL_AtomicCASPtr +#if defined(_MSC_VER) && (_MSC_VER >= 1500) +#include +#define HAVE_MSC_ATOMICS 1 +#endif + +#if defined(__MACOSX__) /* !!! FIXME: should we favor gcc atomics? */ +#include +#endif /* If any of the operations are not provided then we must emulate some @@ -53,6 +54,11 @@ Contributed by Bob Pendleton, bob@pendleton.com */ +#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) +#define EMULATE_CAS 1 +#endif + +#if EMULATE_CAS static SDL_SpinLock locks[32]; static SDL_INLINE void @@ -70,10 +76,19 @@ leaveLock(void *a) SDL_AtomicUnlock(&locks[index]); } +#endif -DECLSPEC SDL_bool SDLCALL + +SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval) { +#ifdef HAVE_MSC_ATOMICS + return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval); +#elif defined(__MACOSX__) /* !!! FIXME: should we favor gcc atomics? */ + return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value); +#elif defined(HAVE_GCC_ATOMICS) + return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval); +#elif EMULATE_CAS SDL_bool retval = SDL_FALSE; enterLock(a); @@ -84,11 +99,25 @@ SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval) leaveLock(a); return retval; +#else + #error Please define your platform. +#endif } -DECLSPEC SDL_bool SDLCALL +SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval) { +#if defined(HAVE_MSC_ATOMICS) && (_M_IX86) + return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval); +#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86) + return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval); +#elif defined(__MACOSX__) && defined(__LP64__) /* !!! FIXME: should we favor gcc atomics? */ + return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a); +#elif defined(__MACOSX__) && !defined(__LP64__) /* !!! FIXME: should we favor gcc atomics? */ + return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a); +#elif defined(HAVE_GCC_ATOMICS) + return __sync_bool_compare_and_swap(a, oldval, newval); +#elif EMULATE_CAS SDL_bool retval = SDL_FALSE; enterLock(a); @@ -99,10 +128,80 @@ SDL_AtomicCASPtr(void **a, void *oldval, void *newval) leaveLock(a); return retval; +#else + #error Please define your platform. +#endif +} + +int +SDL_AtomicSet(SDL_atomic_t *a, int v) +{ +#ifdef HAVE_MSC_ATOMICS + return _InterlockedExchange((long*)&a->value, v); +#elif defined(HAVE_GCC_ATOMICS) + return __sync_lock_test_and_set(&a->value, v); +#else + int value; + do { + value = a->value; + } while (!SDL_AtomicCAS(a, value, v)); + return value; +#endif +} + +void* +SDL_AtomicSetPtr(void **a, void *v) +{ +#ifdef HAVE_MSC_ATOMICS + return _InterlockedExchangePointer(a, v); +#elif defined(HAVE_GCC_ATOMICS) + return __sync_lock_test_and_set(a, v); +#else + void *value; + do { + value = *a; + } while (!SDL_AtomicCASPtr(a, value, v)); + return value; +#endif +} + +int +SDL_AtomicAdd(SDL_atomic_t *a, int v) +{ +#ifdef HAVE_MSC_ATOMICS + return _InterlockedExchangeAdd((long*)&a->value, v); +#elif defined(HAVE_GCC_ATOMICS) + return __sync_fetch_and_add(&a->value, v); +#else + int value; + do { + value = a->value; + } while (!SDL_AtomicCAS(a, value, (value + v))); + return value; +#endif +} + +int +SDL_AtomicGet(SDL_atomic_t *a) +{ + int value; + do { + value = a->value; + } while (!SDL_AtomicCAS(a, value, value)); + return value; +} + +void * +SDL_AtomicGetPtr(void **a) +{ + void *value; + do { + value = *a; + } while (!SDL_AtomicCASPtr(a, value, value)); + return value; } -#if defined(__GNUC__) && defined(__arm__) && \ - (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)) +#ifdef __thumb__ __asm__( " .align 2\n" " .globl _SDL_MemoryBarrierRelease\n" @@ -113,6 +212,6 @@ __asm__( " mcr p15, 0, r0, c7, c10, 5\n" " bx lr\n" ); -#endif /* __GNUC__ && __arm__ && ARMV6 */ +#endif /* vi: set ts=4 sw=4 expandtab: */