Skip to content

Commit

Permalink
Moved atomic API implementation out of headers.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Nov 25, 2013
1 parent 6cbaf9a commit 928b494
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 117 deletions.
111 changes: 6 additions & 105 deletions include/SDL_atomic.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -64,13 +64,6 @@


#include "begin_code.h" #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++ */ /* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
Expand Down Expand Up @@ -181,57 +174,11 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquire();
#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier() #define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
#endif #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 * \brief A type representing an atomic integer value. It is a struct
* so people don't accidentally use numeric operations on it. * so people don't accidentally use numeric operations on it.
*/ */
#ifndef SDL_atomic_t_defined
typedef struct { int value; } SDL_atomic_t; typedef struct { int value; } SDL_atomic_t;
#endif


/** /**
* \brief Set an atomic variable to a new value if it is currently an old value. * \brief Set an atomic variable to a new value if it is currently an old value.
Expand All @@ -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! * \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); extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
#endif


/** /**
* \brief Set an atomic variable to a value. * \brief Set an atomic variable to a value.
* *
* \return The previous value of the atomic variable. * \return The previous value of the atomic variable.
*/ */
#ifndef SDL_AtomicSet extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v);
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


/** /**
* \brief Get the value of an atomic variable * \brief Get the value of an atomic variable
*/ */
#ifndef SDL_AtomicGet extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a);
SDL_FORCE_INLINE int SDL_AtomicGet(SDL_atomic_t *a)
{
int value = a->value;
SDL_CompilerBarrier();
return value;
}
#endif


/** /**
* \brief Add to an atomic variable. * \brief Add to an atomic variable.
Expand All @@ -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 * \note This same style can be used for any number operation
*/ */
#ifndef SDL_AtomicAdd extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v);
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


/** /**
* \brief Increment an atomic variable used as a reference count. * \brief Increment an atomic variable used as a reference count.
Expand All @@ -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! * \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);
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void* *a, void *oldval, void *newval);
#endif


/** /**
* \brief Set a pointer to a value atomically. * \brief Set a pointer to a value atomically.
* *
* \return The previous value of the pointer. * \return The previous value of the pointer.
*/ */
#ifndef SDL_AtomicSetPtr extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v);
SDL_FORCE_INLINE void* SDL_AtomicSetPtr(void* *a, void* v)
{
void* value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, v));
return value;
}
#endif


/** /**
* \brief Get the value of a pointer atomically. * \brief Get the value of a pointer atomically.
*/ */
#ifndef SDL_AtomicGetPtr extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a);
SDL_FORCE_INLINE void* SDL_AtomicGetPtr(void* *a)
{
void* value = *a;
SDL_CompilerBarrier();
return value;
}
#endif



/* Ends C function definitions when using C++ */ /* Ends C function definitions when using C++ */
#ifdef __cplusplus #ifdef __cplusplus
Expand Down
123 changes: 111 additions & 12 deletions src/atomic/SDL_atomic.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@


#include "SDL_atomic.h" #include "SDL_atomic.h"


/* Note that we undefine the atomic operations here, in case they are #if defined(_MSC_VER) && (_MSC_VER >= 1500)
defined as compiler intrinsics while building SDL but the library user #include <intrin.h>
doesn't have that compiler. That way we always have a working set of #define HAVE_MSC_ATOMICS 1
atomic operations built into the library. #endif
*/
#undef SDL_AtomicCAS #if defined(__MACOSX__) /* !!! FIXME: should we favor gcc atomics? */
#undef SDL_AtomicCASPtr #include <libkern/OSAtomic.h>
#endif


/* /*
If any of the operations are not provided then we must emulate some If any of the operations are not provided then we must emulate some
Expand All @@ -53,6 +54,11 @@
Contributed by Bob Pendleton, bob@pendleton.com 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_SpinLock locks[32];


static SDL_INLINE void static SDL_INLINE void
Expand All @@ -70,10 +76,19 @@ leaveLock(void *a)


SDL_AtomicUnlock(&locks[index]); SDL_AtomicUnlock(&locks[index]);
} }
#endif


DECLSPEC SDL_bool SDLCALL
SDL_bool
SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval) 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; SDL_bool retval = SDL_FALSE;


enterLock(a); enterLock(a);
Expand All @@ -84,11 +99,25 @@ SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
leaveLock(a); leaveLock(a);


return retval; return retval;
#else
#error Please define your platform.
#endif
} }


DECLSPEC SDL_bool SDLCALL SDL_bool
SDL_AtomicCASPtr(void **a, void *oldval, void *newval) 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; SDL_bool retval = SDL_FALSE;


enterLock(a); enterLock(a);
Expand All @@ -99,10 +128,80 @@ SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
leaveLock(a); leaveLock(a);


return retval; 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__) && \ #ifdef __thumb__
(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__))
__asm__( __asm__(
" .align 2\n" " .align 2\n"
" .globl _SDL_MemoryBarrierRelease\n" " .globl _SDL_MemoryBarrierRelease\n"
Expand All @@ -113,6 +212,6 @@ __asm__(
" mcr p15, 0, r0, c7, c10, 5\n" " mcr p15, 0, r0, c7, c10, 5\n"
" bx lr\n" " bx lr\n"
); );
#endif /* __GNUC__ && __arm__ && ARMV6 */ #endif


/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */

0 comments on commit 928b494

Please sign in to comment.