Moved atomic API implementation out of headers.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 24 Nov 2013 21:04:51 -0500
changeset 8088e5d77d5e0fe2
parent 8087 f9912ddfe17b
child 8089 de8b6fdf6544
Moved atomic API implementation out of headers.
include/SDL_atomic.h
src/atomic/SDL_atomic.c
     1.1 --- a/include/SDL_atomic.h	Sun Nov 24 21:15:58 2013 -0500
     1.2 +++ b/include/SDL_atomic.h	Sun Nov 24 21:04:51 2013 -0500
     1.3 @@ -64,13 +64,6 @@
     1.4  
     1.5  #include "begin_code.h"
     1.6  
     1.7 -/* Need to do this here because intrin.h has C++ code in it */
     1.8 -/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
     1.9 -#if defined(_MSC_VER) && (_MSC_VER >= 1500)
    1.10 -#include <intrin.h>
    1.11 -#define HAVE_MSC_ATOMICS 1
    1.12 -#endif
    1.13 -
    1.14  /* Set up for C function definitions, even when using C++ */
    1.15  #ifdef __cplusplus
    1.16  extern "C" {
    1.17 @@ -181,57 +174,11 @@
    1.18  #define SDL_MemoryBarrierAcquire()  SDL_CompilerBarrier()
    1.19  #endif
    1.20  
    1.21 -
    1.22 -/* Platform specific optimized versions of the atomic functions,
    1.23 - * you can disable these by defining SDL_DISABLE_ATOMIC_INLINE
    1.24 - */
    1.25 -#if defined(SDL_ATOMIC_DISABLED) && SDL_ATOMIC_DISABLED
    1.26 -#define SDL_DISABLE_ATOMIC_INLINE
    1.27 -#endif
    1.28 -#ifndef SDL_DISABLE_ATOMIC_INLINE
    1.29 -
    1.30 -#ifdef HAVE_MSC_ATOMICS
    1.31 -
    1.32 -#define SDL_AtomicSet(a, v)     _InterlockedExchange((long*)&(a)->value, (v))
    1.33 -#define SDL_AtomicAdd(a, v)     _InterlockedExchangeAdd((long*)&(a)->value, (v))
    1.34 -#define SDL_AtomicCAS(a, oldval, newval) (_InterlockedCompareExchange((long*)&(a)->value, (newval), (oldval)) == (oldval))
    1.35 -#define SDL_AtomicSetPtr(a, v)  _InterlockedExchangePointer((a), (v))
    1.36 -#if _M_IX86
    1.37 -#define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchange((long*)(a), (long)(newval), (long)(oldval)) == (long)(oldval))
    1.38 -#else
    1.39 -#define SDL_AtomicCASPtr(a, oldval, newval) (_InterlockedCompareExchangePointer((a), (newval), (oldval)) == (oldval))
    1.40 -#endif
    1.41 -
    1.42 -#elif defined(__MACOSX__)
    1.43 -#include <libkern/OSAtomic.h>
    1.44 -
    1.45 -#define SDL_AtomicCAS(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((oldval), (newval), &(a)->value)
    1.46 -#ifdef __LP64__
    1.47 -#define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap64Barrier((int64_t)(oldval), (int64_t)(newval), (int64_t*)(a))
    1.48 -#else
    1.49 -#define SDL_AtomicCASPtr(a, oldval, newval) OSAtomicCompareAndSwap32Barrier((int32_t)(oldval), (int32_t)(newval), (int32_t*)(a))
    1.50 -#endif
    1.51 -
    1.52 -#elif defined(HAVE_GCC_ATOMICS)
    1.53 -
    1.54 -#define SDL_AtomicSet(a, v)     __sync_lock_test_and_set(&(a)->value, v)
    1.55 -#define SDL_AtomicAdd(a, v)     __sync_fetch_and_add(&(a)->value, v)
    1.56 -#define SDL_AtomicSetPtr(a, v)  __sync_lock_test_and_set(a, v)
    1.57 -#define SDL_AtomicCAS(a, oldval, newval) __sync_bool_compare_and_swap(&(a)->value, oldval, newval)
    1.58 -#define SDL_AtomicCASPtr(a, oldval, newval) __sync_bool_compare_and_swap(a, oldval, newval)
    1.59 -
    1.60 -#endif
    1.61 -
    1.62 -#endif /* !SDL_DISABLE_ATOMIC_INLINE */
    1.63 -
    1.64 -
    1.65  /**
    1.66   * \brief A type representing an atomic integer value.  It is a struct
    1.67   *        so people don't accidentally use numeric operations on it.
    1.68   */
    1.69 -#ifndef SDL_atomic_t_defined
    1.70  typedef struct { int value; } SDL_atomic_t;
    1.71 -#endif
    1.72  
    1.73  /**
    1.74   * \brief Set an atomic variable to a new value if it is currently an old value.
    1.75 @@ -240,37 +187,19 @@
    1.76   *
    1.77   * \note If you don't know what this function is for, you shouldn't use it!
    1.78  */
    1.79 -#ifndef SDL_AtomicCAS
    1.80  extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
    1.81 -#endif
    1.82  
    1.83  /**
    1.84   * \brief Set an atomic variable to a value.
    1.85   *
    1.86   * \return The previous value of the atomic variable.
    1.87   */
    1.88 -#ifndef SDL_AtomicSet
    1.89 -SDL_FORCE_INLINE int SDL_AtomicSet(SDL_atomic_t *a, int v)
    1.90 -{
    1.91 -    int value;
    1.92 -    do {
    1.93 -        value = a->value;
    1.94 -    } while (!SDL_AtomicCAS(a, value, v));
    1.95 -    return value;
    1.96 -}
    1.97 -#endif
    1.98 +extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v);
    1.99  
   1.100  /**
   1.101   * \brief Get the value of an atomic variable
   1.102   */
   1.103 -#ifndef SDL_AtomicGet
   1.104 -SDL_FORCE_INLINE int SDL_AtomicGet(SDL_atomic_t *a)
   1.105 -{
   1.106 -    int value = a->value;
   1.107 -    SDL_CompilerBarrier();
   1.108 -    return value;
   1.109 -}
   1.110 -#endif
   1.111 +extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a);
   1.112  
   1.113  /**
   1.114   * \brief Add to an atomic variable.
   1.115 @@ -279,16 +208,7 @@
   1.116   *
   1.117   * \note This same style can be used for any number operation
   1.118   */
   1.119 -#ifndef SDL_AtomicAdd
   1.120 -SDL_FORCE_INLINE int SDL_AtomicAdd(SDL_atomic_t *a, int v)
   1.121 -{
   1.122 -    int value;
   1.123 -    do {
   1.124 -        value = a->value;
   1.125 -    } while (!SDL_AtomicCAS(a, value, (value + v)));
   1.126 -    return value;
   1.127 -}
   1.128 -#endif
   1.129 +extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v);
   1.130  
   1.131  /**
   1.132   * \brief Increment an atomic variable used as a reference count.
   1.133 @@ -314,38 +234,19 @@
   1.134   *
   1.135   * \note If you don't know what this function is for, you shouldn't use it!
   1.136  */
   1.137 -#ifndef SDL_AtomicCASPtr
   1.138 -extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void* *a, void *oldval, void *newval);
   1.139 -#endif
   1.140 +extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
   1.141  
   1.142  /**
   1.143   * \brief Set a pointer to a value atomically.
   1.144   *
   1.145   * \return The previous value of the pointer.
   1.146   */
   1.147 -#ifndef SDL_AtomicSetPtr
   1.148 -SDL_FORCE_INLINE void* SDL_AtomicSetPtr(void* *a, void* v)
   1.149 -{
   1.150 -    void* value;
   1.151 -    do {
   1.152 -        value = *a;
   1.153 -    } while (!SDL_AtomicCASPtr(a, value, v));
   1.154 -    return value;
   1.155 -}
   1.156 -#endif
   1.157 +extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v);
   1.158  
   1.159  /**
   1.160   * \brief Get the value of a pointer atomically.
   1.161   */
   1.162 -#ifndef SDL_AtomicGetPtr
   1.163 -SDL_FORCE_INLINE void* SDL_AtomicGetPtr(void* *a)
   1.164 -{
   1.165 -    void* value = *a;
   1.166 -    SDL_CompilerBarrier();
   1.167 -    return value;
   1.168 -}
   1.169 -#endif
   1.170 -
   1.171 +extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a);
   1.172  
   1.173  /* Ends C function definitions when using C++ */
   1.174  #ifdef __cplusplus
     2.1 --- a/src/atomic/SDL_atomic.c	Sun Nov 24 21:15:58 2013 -0500
     2.2 +++ b/src/atomic/SDL_atomic.c	Sun Nov 24 21:04:51 2013 -0500
     2.3 @@ -22,13 +22,14 @@
     2.4  
     2.5  #include "SDL_atomic.h"
     2.6  
     2.7 -/* Note that we undefine the atomic operations here, in case they are
     2.8 -   defined as compiler intrinsics while building SDL but the library user
     2.9 -   doesn't have that compiler.  That way we always have a working set of
    2.10 -   atomic operations built into the library.
    2.11 -*/
    2.12 -#undef SDL_AtomicCAS
    2.13 -#undef SDL_AtomicCASPtr
    2.14 +#if defined(_MSC_VER) && (_MSC_VER >= 1500)
    2.15 +#include <intrin.h>
    2.16 +#define HAVE_MSC_ATOMICS 1
    2.17 +#endif
    2.18 +
    2.19 +#if defined(__MACOSX__)  /* !!! FIXME: should we favor gcc atomics? */
    2.20 +#include <libkern/OSAtomic.h>
    2.21 +#endif
    2.22  
    2.23  /*
    2.24    If any of the operations are not provided then we must emulate some
    2.25 @@ -53,6 +54,11 @@
    2.26    Contributed by Bob Pendleton, bob@pendleton.com
    2.27  */
    2.28  
    2.29 +#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__)
    2.30 +#define EMULATE_CAS 1
    2.31 +#endif
    2.32 +
    2.33 +#if EMULATE_CAS
    2.34  static SDL_SpinLock locks[32];
    2.35  
    2.36  static SDL_INLINE void
    2.37 @@ -70,10 +76,19 @@
    2.38  
    2.39      SDL_AtomicUnlock(&locks[index]);
    2.40  }
    2.41 +#endif
    2.42  
    2.43 -DECLSPEC SDL_bool SDLCALL
    2.44 +
    2.45 +SDL_bool
    2.46  SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
    2.47  {
    2.48 +#ifdef HAVE_MSC_ATOMICS
    2.49 +    return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval);
    2.50 +#elif defined(__MACOSX__)  /* !!! FIXME: should we favor gcc atomics? */
    2.51 +    return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
    2.52 +#elif defined(HAVE_GCC_ATOMICS)
    2.53 +    return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
    2.54 +#elif EMULATE_CAS
    2.55      SDL_bool retval = SDL_FALSE;
    2.56  
    2.57      enterLock(a);
    2.58 @@ -84,11 +99,25 @@
    2.59      leaveLock(a);
    2.60  
    2.61      return retval;
    2.62 +#else
    2.63 +    #error Please define your platform.
    2.64 +#endif
    2.65  }
    2.66  
    2.67 -DECLSPEC SDL_bool SDLCALL
    2.68 +SDL_bool
    2.69  SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
    2.70  {
    2.71 +#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
    2.72 +    return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval);
    2.73 +#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
    2.74 +    return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval);
    2.75 +#elif defined(__MACOSX__) && defined(__LP64__)   /* !!! FIXME: should we favor gcc atomics? */
    2.76 +    return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
    2.77 +#elif defined(__MACOSX__) && !defined(__LP64__)  /* !!! FIXME: should we favor gcc atomics? */
    2.78 +    return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
    2.79 +#elif defined(HAVE_GCC_ATOMICS)
    2.80 +    return __sync_bool_compare_and_swap(a, oldval, newval);
    2.81 +#elif EMULATE_CAS
    2.82      SDL_bool retval = SDL_FALSE;
    2.83  
    2.84      enterLock(a);
    2.85 @@ -99,10 +128,80 @@
    2.86      leaveLock(a);
    2.87  
    2.88      return retval;
    2.89 +#else
    2.90 +    #error Please define your platform.
    2.91 +#endif
    2.92  }
    2.93  
    2.94 -#if defined(__GNUC__) && defined(__arm__) && \
    2.95 -   (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__))
    2.96 +int
    2.97 +SDL_AtomicSet(SDL_atomic_t *a, int v)
    2.98 +{
    2.99 +#ifdef HAVE_MSC_ATOMICS
   2.100 +    return _InterlockedExchange((long*)&a->value, v);
   2.101 +#elif defined(HAVE_GCC_ATOMICS)
   2.102 +    return __sync_lock_test_and_set(&a->value, v);
   2.103 +#else
   2.104 +    int value;
   2.105 +    do {
   2.106 +        value = a->value;
   2.107 +    } while (!SDL_AtomicCAS(a, value, v));
   2.108 +    return value;
   2.109 +#endif
   2.110 +}
   2.111 +
   2.112 +void*
   2.113 +SDL_AtomicSetPtr(void **a, void *v)
   2.114 +{
   2.115 +#ifdef HAVE_MSC_ATOMICS
   2.116 +    return _InterlockedExchangePointer(a, v);
   2.117 +#elif defined(HAVE_GCC_ATOMICS)
   2.118 +    return __sync_lock_test_and_set(a, v);
   2.119 +#else
   2.120 +    void *value;
   2.121 +    do {
   2.122 +        value = *a;
   2.123 +    } while (!SDL_AtomicCASPtr(a, value, v));
   2.124 +    return value;
   2.125 +#endif
   2.126 +}
   2.127 +
   2.128 +int
   2.129 +SDL_AtomicAdd(SDL_atomic_t *a, int v)
   2.130 +{
   2.131 +#ifdef HAVE_MSC_ATOMICS
   2.132 +    return _InterlockedExchangeAdd((long*)&a->value, v);
   2.133 +#elif defined(HAVE_GCC_ATOMICS)
   2.134 +    return __sync_fetch_and_add(&a->value, v);
   2.135 +#else
   2.136 +    int value;
   2.137 +    do {
   2.138 +        value = a->value;
   2.139 +    } while (!SDL_AtomicCAS(a, value, (value + v)));
   2.140 +    return value;
   2.141 +#endif
   2.142 +}
   2.143 +
   2.144 +int
   2.145 +SDL_AtomicGet(SDL_atomic_t *a)
   2.146 +{
   2.147 +    int value;
   2.148 +    do {
   2.149 +        value = a->value;
   2.150 +    } while (!SDL_AtomicCAS(a, value, value));
   2.151 +    return value;
   2.152 +}
   2.153 +
   2.154 +void *
   2.155 +SDL_AtomicGetPtr(void **a)
   2.156 +{
   2.157 +    void *value;
   2.158 +    do {
   2.159 +        value = *a;
   2.160 +    } while (!SDL_AtomicCASPtr(a, value, value));
   2.161 +    return value;
   2.162 +}
   2.163 +
   2.164 +#ifdef __thumb__
   2.165  __asm__(
   2.166  "   .align 2\n"
   2.167  "   .globl _SDL_MemoryBarrierRelease\n"
   2.168 @@ -113,6 +212,6 @@
   2.169  "   mcr p15, 0, r0, c7, c10, 5\n"
   2.170  "   bx lr\n"
   2.171  );
   2.172 -#endif /* __GNUC__ && __arm__ && ARMV6 */
   2.173 +#endif
   2.174  
   2.175  /* vi: set ts=4 sw=4 expandtab: */