Moved atomic API implementation out of headers.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 24 Nov 2013 21:04:51 -0500
changeset 8088 e5d77d5e0fe2
parent 8087 f9912ddfe17b
child 8089 de8b6fdf6544
Moved atomic API implementation out of headers.
include/SDL_atomic.h
src/atomic/SDL_atomic.c
--- a/include/SDL_atomic.h	Sun Nov 24 21:15:58 2013 -0500
+++ b/include/SDL_atomic.h	Sun Nov 24 21:04:51 2013 -0500
@@ -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 <intrin.h>
-#define HAVE_MSC_ATOMICS 1
-#endif
-
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -181,57 +174,11 @@
 #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 <libkern/OSAtomic.h>
-
-#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 @@
  *
  * \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 @@
  *
  * \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 @@
  *
  * \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
--- a/src/atomic/SDL_atomic.c	Sun Nov 24 21:15:58 2013 -0500
+++ b/src/atomic/SDL_atomic.c	Sun Nov 24 21:04:51 2013 -0500
@@ -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 <intrin.h>
+#define HAVE_MSC_ATOMICS 1
+#endif
+
+#if defined(__MACOSX__)  /* !!! FIXME: should we favor gcc atomics? */
+#include <libkern/OSAtomic.h>
+#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 @@
 
     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 @@
     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 @@
     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
 }
 
-#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__))
+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;
+}
+
+#ifdef __thumb__
 __asm__(
 "   .align 2\n"
 "   .globl _SDL_MemoryBarrierRelease\n"
@@ -113,6 +212,6 @@
 "   mcr p15, 0, r0, c7, c10, 5\n"
 "   bx lr\n"
 );
-#endif /* __GNUC__ && __arm__ && ARMV6 */
+#endif
 
 /* vi: set ts=4 sw=4 expandtab: */