Skip to content
Permalink
Browse files

Moved atomic API implementation out of headers.

  • Loading branch information
icculus committed Nov 25, 2013
1 parent 6cbaf9a commit 928b494630bf8d4024120e7ee0268b3799d8513f
Showing with 117 additions and 117 deletions.
  1. +6 −105 include/SDL_atomic.h
  2. +111 −12 src/atomic/SDL_atomic.c
@@ -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 @@ 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 <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 @@ 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
@@ -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 @@ 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: */

0 comments on commit 928b494

Please sign in to comment.