SDL  2.0
SDL_atomic.c File Reference
#include "../SDL_internal.h"
#include "SDL_atomic.h"
+ Include dependency graph for SDL_atomic.c:

Go to the source code of this file.

Macros

#define EMULATE_CAS   1

Functions

static SDL_INLINE void enterLock (void *a)
static SDL_INLINE void leaveLock (void *a)
SDL_bool SDL_AtomicCAS (SDL_atomic_t *a, int oldval, int newval)
 Set an atomic variable to a new value if it is currently an old value.
SDL_bool SDL_AtomicCASPtr (void **a, void *oldval, void *newval)
 Set a pointer to a new value if it is currently an old value.
int SDL_AtomicSet (SDL_atomic_t *a, int v)
 Set an atomic variable to a value.
voidSDL_AtomicSetPtr (void **a, void *v)
 Set a pointer to a value atomically.
int SDL_AtomicAdd (SDL_atomic_t *a, int v)
 Add to an atomic variable.
int SDL_AtomicGet (SDL_atomic_t *a)
 Get the value of an atomic variable.
voidSDL_AtomicGetPtr (void **a)
 Get the value of a pointer atomically.
void SDL_MemoryBarrierReleaseFunction (void)
void SDL_MemoryBarrierAcquireFunction (void)

Variables

static SDL_SpinLock locks [32]

Macro Definition Documentation

#define EMULATE_CAS   1

Definition at line 105 of file SDL_atomic.c.

Function Documentation

static SDL_INLINE void enterLock ( void a)
static

Definition at line 112 of file SDL_atomic.c.

References SDL_AtomicLock.

Referenced by SDL_AtomicCAS(), and SDL_AtomicCASPtr().

{
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
}
static SDL_INLINE void leaveLock ( void a)
static

Definition at line 120 of file SDL_atomic.c.

References SDL_AtomicUnlock.

Referenced by SDL_AtomicCAS(), and SDL_AtomicCASPtr().

{
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
}
int SDL_AtomicAdd ( SDL_atomic_t a,
int  v 
)

Add to an atomic variable.

Returns
The previous value of the atomic variable.
Note
This same style can be used for any number operation

Definition at line 238 of file SDL_atomic.c.

References SDL_AtomicCAS, and SDL_atomic_t::value.

{
#ifdef HAVE_MSC_ATOMICS
return _InterlockedExchangeAdd((long*)&a->value, v);
#elif defined(HAVE_WATCOM_ATOMICS)
return _SDL_xadd_watcom(&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_fetch_and_add(&a->value, v);
#elif defined(__SOLARIS__)
int pv = a->value;
membar_consumer();
#if defined(_LP64)
atomic_add_64((volatile uint64_t*)&a->value, v);
#elif !defined(_LP64)
atomic_add_32((volatile uint32_t*)&a->value, v);
#endif
return pv;
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, (value + v)));
return value;
#endif
}
SDL_bool SDL_AtomicCAS ( SDL_atomic_t a,
int  oldval,
int  newval 
)

Set an atomic variable to a new value if it is currently an old value.

Returns
SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
Note
If you don't know what this function is for, you shouldn't use it!

Definition at line 130 of file SDL_atomic.c.

References enterLock(), leaveLock(), retval, SDL_FALSE, SDL_TRUE, and SDL_atomic_t::value.

{
#ifdef HAVE_MSC_ATOMICS
return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval);
#elif defined(HAVE_WATCOM_ATOMICS)
return (SDL_bool) _SDL_cmpxchg_watcom(&a->value, newval, oldval);
#elif defined(HAVE_GCC_ATOMICS)
return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
#elif defined(__MACOSX__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
#elif defined(__SOLARIS__) && defined(_LP64)
return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)&a->value, (uint64_t)oldval, (uint64_t)newval) == oldval);
#elif defined(__SOLARIS__) && !defined(_LP64)
return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)&a->value, (uint32_t)oldval, (uint32_t)newval) == oldval);
#elif EMULATE_CAS
if (a->value == oldval) {
a->value = newval;
retval = SDL_TRUE;
}
return retval;
#else
#error Please define your platform.
#endif
}
SDL_bool SDL_AtomicCASPtr ( void **  a,
void oldval,
void newval 
)

Set a pointer to a new value if it is currently an old value.

Returns
SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
Note
If you don't know what this function is for, you shouldn't use it!

Definition at line 161 of file SDL_atomic.c.

References enterLock(), leaveLock(), retval, SDL_FALSE, and SDL_TRUE.

{
#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(HAVE_WATCOM_ATOMICS)
return (SDL_bool) _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(a, oldval, newval);
#elif defined(__MACOSX__) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
#elif defined(__MACOSX__) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
#elif defined(__SOLARIS__)
return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval);
#elif EMULATE_CAS
if (*a == oldval) {
*a = newval;
retval = SDL_TRUE;
}
return retval;
#else
#error Please define your platform.
#endif
}
int SDL_AtomicGet ( SDL_atomic_t a)

Get the value of an atomic variable.

Definition at line 265 of file SDL_atomic.c.

References SDL_AtomicCAS, and SDL_atomic_t::value.

{
#ifdef HAVE_ATOMIC_LOAD_N
return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, value));
return value;
#endif
}
void* SDL_AtomicGetPtr ( void **  a)

Get the value of a pointer atomically.

Definition at line 279 of file SDL_atomic.c.

References SDL_AtomicCASPtr.

{
#ifdef HAVE_ATOMIC_LOAD_N
return __atomic_load_n(a, __ATOMIC_SEQ_CST);
#else
void *value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, value));
return value;
#endif
}
int SDL_AtomicSet ( SDL_atomic_t a,
int  v 
)

Set an atomic variable to a value.

Returns
The previous value of the atomic variable.

Definition at line 194 of file SDL_atomic.c.

References SDL_AtomicCAS, and SDL_atomic_t::value.

{
#ifdef HAVE_MSC_ATOMICS
return _InterlockedExchange((long*)&a->value, v);
#elif defined(HAVE_WATCOM_ATOMICS)
return _SDL_xchg_watcom(&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(&a->value, v);
#elif defined(__SOLARIS__) && defined(_LP64)
return (int) atomic_swap_64((volatile uint64_t*)&a->value, (uint64_t)v);
#elif defined(__SOLARIS__) && !defined(_LP64)
return (int) atomic_swap_32((volatile uint32_t*)&a->value, (uint32_t)v);
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, v));
return value;
#endif
}
void* SDL_AtomicSetPtr ( void **  a,
void v 
)

Set a pointer to a value atomically.

Returns
The previous value of the pointer.

Definition at line 216 of file SDL_atomic.c.

References SDL_AtomicCASPtr.

{
#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
return (void *) _InterlockedExchange((long *)a, (long) v);
#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
return _InterlockedExchangePointer(a, v);
#elif defined(HAVE_WATCOM_ATOMICS)
return (void *) _SDL_xchg_watcom((int *)a, (long)v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(a, v);
#elif defined(__SOLARIS__)
return atomic_swap_ptr(a, v);
#else
void *value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, v));
return value;
#endif
}
void SDL_MemoryBarrierAcquireFunction ( void  )

Definition at line 299 of file SDL_atomic.c.

References SDL_MemoryBarrierAcquire.

void SDL_MemoryBarrierReleaseFunction ( void  )

Memory barriers are designed to prevent reads and writes from being reordered by the compiler and being seen out of order on multi-core CPUs.

A typical pattern would be for thread A to write some data and a flag, and for thread B to read the flag and get the data. In this case you would insert a release barrier between writing the data and the flag, guaranteeing that the data write completes no later than the flag is written, and you would insert an acquire barrier between reading the flag and reading the data, to ensure that all the reads associated with the flag have completed.

In this pattern you should always see a release barrier paired with an acquire barrier and you should gate the data reads/writes with a single flag variable.

For more information on these semantics, take a look at the blog post: http://preshing.com/20120913/acquire-and-release-semantics

Definition at line 293 of file SDL_atomic.c.

References SDL_MemoryBarrierRelease.

Variable Documentation

SDL_SpinLock locks[32]
static

Definition at line 109 of file SDL_atomic.c.