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. More...
 
SDL_bool SDL_AtomicCASPtr (void **a, void *oldval, void *newval)
 Set a pointer to a new value if it is currently an old value. More...
 
int SDL_AtomicSet (SDL_atomic_t *a, int v)
 Set an atomic variable to a value. More...
 
voidSDL_AtomicSetPtr (void **a, void *v)
 Set a pointer to a value atomically. More...
 
int SDL_AtomicAdd (SDL_atomic_t *a, int v)
 Add to an atomic variable. More...
 
int SDL_AtomicGet (SDL_atomic_t *a)
 Get the value of an atomic variable. More...
 
voidSDL_AtomicGetPtr (void **a)
 Get the value of a pointer atomically. More...
 
void SDL_MemoryBarrierReleaseFunction (void)
 
void SDL_MemoryBarrierAcquireFunction (void)
 

Variables

static SDL_SpinLock locks [32]
 

Macro Definition Documentation

◆ EMULATE_CAS

#define EMULATE_CAS   1

Definition at line 105 of file SDL_atomic.c.

Function Documentation

◆ enterLock()

static SDL_INLINE void enterLock ( void a)
static

Definition at line 112 of file SDL_atomic.c.

113{
114 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
115
117}
static SDL_SpinLock locks[32]
Definition: SDL_atomic.c:109
unsigned int uintptr_t
#define SDL_AtomicLock
GLuint index
GLboolean GLboolean GLboolean GLboolean a

References locks, and SDL_AtomicLock.

Referenced by SDL_AtomicCAS(), and SDL_AtomicCASPtr().

◆ leaveLock()

static SDL_INLINE void leaveLock ( void a)
static

Definition at line 120 of file SDL_atomic.c.

121{
122 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
123
125}
#define SDL_AtomicUnlock

References locks, and SDL_AtomicUnlock.

Referenced by SDL_AtomicCAS(), and SDL_AtomicCASPtr().

◆ SDL_AtomicAdd()

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.

239{
240#ifdef HAVE_MSC_ATOMICS
241 return _InterlockedExchangeAdd((long*)&a->value, v);
242#elif defined(HAVE_WATCOM_ATOMICS)
243 return _SDL_xadd_watcom(&a->value, v);
244#elif defined(HAVE_GCC_ATOMICS)
245 return __sync_fetch_and_add(&a->value, v);
246#elif defined(__SOLARIS__)
247 int pv = a->value;
248 membar_consumer();
249#if defined(_LP64)
250 atomic_add_64((volatile uint64_t*)&a->value, v);
251#elif !defined(_LP64)
252 atomic_add_32((volatile uint32_t*)&a->value, v);
253#endif
254 return pv;
255#else
256 int value;
257 do {
258 value = a->value;
259 } while (!SDL_AtomicCAS(a, value, (value + v)));
260 return value;
261#endif
262}
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.
Definition: SDL_atomic.c:130
unsigned int uint32_t
unsigned long long uint64_t
const GLdouble * v
Definition: SDL_opengl.h:2064
GLsizei const GLfloat * value

References SDL_AtomicCAS().

◆ SDL_AtomicCAS()

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.

131{
132#ifdef HAVE_MSC_ATOMICS
133 return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval);
134#elif defined(HAVE_WATCOM_ATOMICS)
135 return (SDL_bool) _SDL_cmpxchg_watcom(&a->value, newval, oldval);
136#elif defined(HAVE_GCC_ATOMICS)
137 return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
138#elif defined(__MACOSX__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
139 return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
140#elif defined(__SOLARIS__) && defined(_LP64)
141 return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)&a->value, (uint64_t)oldval, (uint64_t)newval) == oldval);
142#elif defined(__SOLARIS__) && !defined(_LP64)
143 return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)&a->value, (uint32_t)oldval, (uint32_t)newval) == oldval);
144#elif EMULATE_CAS
146
147 enterLock(a);
148 if (a->value == oldval) {
149 a->value = newval;
151 }
152 leaveLock(a);
153
154 return retval;
155#else
156 #error Please define your platform.
157#endif
158}
static SDL_INLINE void leaveLock(void *a)
Definition: SDL_atomic.c:120
static SDL_INLINE void enterLock(void *a)
Definition: SDL_atomic.c:112
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_bool retval

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

Referenced by SDL_AtomicAdd(), SDL_AtomicGet(), and SDL_AtomicSet().

◆ SDL_AtomicCASPtr()

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.

162{
163#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
164 return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval);
165#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
166 return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval);
167#elif defined(HAVE_WATCOM_ATOMICS)
168 return (SDL_bool) _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
169#elif defined(HAVE_GCC_ATOMICS)
170 return __sync_bool_compare_and_swap(a, oldval, newval);
171#elif defined(__MACOSX__) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
172 return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
173#elif defined(__MACOSX__) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
174 return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
175#elif defined(__SOLARIS__)
176 return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval);
177#elif EMULATE_CAS
179
180 enterLock(a);
181 if (*a == oldval) {
182 *a = newval;
184 }
185 leaveLock(a);
186
187 return retval;
188#else
189 #error Please define your platform.
190#endif
191}
signed int int32_t
signed long long int64_t

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

Referenced by SDL_AtomicGetPtr(), and SDL_AtomicSetPtr().

◆ SDL_AtomicGet()

int SDL_AtomicGet ( SDL_atomic_t a)

Get the value of an atomic variable.

Definition at line 265 of file SDL_atomic.c.

266{
267#ifdef HAVE_ATOMIC_LOAD_N
268 return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
269#else
270 int value;
271 do {
272 value = a->value;
273 } while (!SDL_AtomicCAS(a, value, value));
274 return value;
275#endif
276}

References SDL_AtomicCAS().

◆ SDL_AtomicGetPtr()

void * SDL_AtomicGetPtr ( void **  a)

Get the value of a pointer atomically.

Definition at line 279 of file SDL_atomic.c.

280{
281#ifdef HAVE_ATOMIC_LOAD_N
282 return __atomic_load_n(a, __ATOMIC_SEQ_CST);
283#else
284 void *value;
285 do {
286 value = *a;
287 } while (!SDL_AtomicCASPtr(a, value, value));
288 return value;
289#endif
290}
SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
Set a pointer to a new value if it is currently an old value.
Definition: SDL_atomic.c:161

References SDL_AtomicCASPtr().

◆ SDL_AtomicSet()

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.

195{
196#ifdef HAVE_MSC_ATOMICS
197 return _InterlockedExchange((long*)&a->value, v);
198#elif defined(HAVE_WATCOM_ATOMICS)
199 return _SDL_xchg_watcom(&a->value, v);
200#elif defined(HAVE_GCC_ATOMICS)
201 return __sync_lock_test_and_set(&a->value, v);
202#elif defined(__SOLARIS__) && defined(_LP64)
203 return (int) atomic_swap_64((volatile uint64_t*)&a->value, (uint64_t)v);
204#elif defined(__SOLARIS__) && !defined(_LP64)
205 return (int) atomic_swap_32((volatile uint32_t*)&a->value, (uint32_t)v);
206#else
207 int value;
208 do {
209 value = a->value;
210 } while (!SDL_AtomicCAS(a, value, v));
211 return value;
212#endif
213}

References SDL_AtomicCAS().

◆ SDL_AtomicSetPtr()

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.

217{
218#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
219 return (void *) _InterlockedExchange((long *)a, (long) v);
220#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
221 return _InterlockedExchangePointer(a, v);
222#elif defined(HAVE_WATCOM_ATOMICS)
223 return (void *) _SDL_xchg_watcom((int *)a, (long)v);
224#elif defined(HAVE_GCC_ATOMICS)
225 return __sync_lock_test_and_set(a, v);
226#elif defined(__SOLARIS__)
227 return atomic_swap_ptr(a, v);
228#else
229 void *value;
230 do {
231 value = *a;
232 } while (!SDL_AtomicCASPtr(a, value, v));
233 return value;
234#endif
235}

References SDL_AtomicCASPtr().

◆ SDL_MemoryBarrierAcquireFunction()

void SDL_MemoryBarrierAcquireFunction ( void  )

Definition at line 303 of file SDL_atomic.c.

304{
306}
#define SDL_MemoryBarrierAcquire()
Definition: SDL_atomic.h:208

References SDL_MemoryBarrierAcquire.

◆ SDL_MemoryBarrierReleaseFunction()

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 297 of file SDL_atomic.c.

298{
300}
#define SDL_MemoryBarrierRelease()
Definition: SDL_atomic.h:207

References SDL_MemoryBarrierRelease.

Variable Documentation

◆ locks

SDL_SpinLock locks[32]
static

Definition at line 109 of file SDL_atomic.c.

Referenced by enterLock(), and leaveLock().