SDL 2.0
|
Go to the source code of this file.
Data Structures | |
struct | SDL_atomic_t |
SDL AtomicLock | |
CategoryAtomicAtomic operations. IMPORTANT: If you are not an expert in concurrent lockless programming, you should not be using any functions in this file. You should be protecting your data structures with full mutexes instead. Seriously, here be dragons! You can find out a little more about lockless programming and the subtle issues that can arise here: https://learn.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming There's also lots of good information here: These operations may or may not actually be implemented using processor specific atomic operations. When possible they are implemented as true processor specific atomic operations. When that is not possible the are implemented using locks that do use the available atomic operations. All of the atomic operations that modify memory are full memory barriers. The atomic locks are efficient spinlocks using CPU instructions, but are vulnerable to starvation and can spin forever if a thread holding a lock has been terminated. For this reason you should minimize the code executed inside an atomic lock and never do expensive things like API or system calls while holding them. The atomic locks are not safe to lock recursively. Porting Note: The spin lock functions and type are required and can not be emulated because they are used in the atomic emulation code. | |
#define | SDL_CompilerBarrier() { SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); } |
#define | SDL_MemoryBarrierRelease() SDL_CompilerBarrier() |
#define | SDL_MemoryBarrierAcquire() SDL_CompilerBarrier() |
#define | SDL_CPUPauseInstruction() |
#define | SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1) |
Increment an atomic variable used as a reference count. | |
#define | SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1) |
Decrement an atomic variable used as a reference count. | |
typedef int | SDL_SpinLock |
SDL_bool | SDL_AtomicTryLock (SDL_SpinLock *lock) |
void | SDL_AtomicLock (SDL_SpinLock *lock) |
void | SDL_AtomicUnlock (SDL_SpinLock *lock) |
void | SDL_MemoryBarrierReleaseFunction (void) |
void | SDL_MemoryBarrierAcquireFunction (void) |
SDL_bool | SDL_AtomicCAS (SDL_atomic_t *a, int oldval, int newval) |
int | SDL_AtomicSet (SDL_atomic_t *a, int v) |
int | SDL_AtomicGet (SDL_atomic_t *a) |
int | SDL_AtomicAdd (SDL_atomic_t *a, int v) |
SDL_bool | SDL_AtomicCASPtr (void **a, void *oldval, void *newval) |
void * | SDL_AtomicSetPtr (void **a, void *v) |
void * | SDL_AtomicGetPtr (void **a) |
#define SDL_AtomicDecRef | ( | a | ) | (SDL_AtomicAdd(a, -1) == 1) |
Decrement an atomic variable used as a reference count.
Definition at line 344 of file SDL_atomic.h.
#define SDL_AtomicIncRef | ( | a | ) | SDL_AtomicAdd(a, 1) |
Increment an atomic variable used as a reference count.
Definition at line 334 of file SDL_atomic.h.
#define SDL_CompilerBarrier | ( | ) | { SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); } |
The compiler barrier prevents the compiler from reordering reads and writes to globally visible variables across the call.
Definition at line 149 of file SDL_atomic.h.
#define SDL_CPUPauseInstruction | ( | ) |
Definition at line 246 of file SDL_atomic.h.
#define SDL_MemoryBarrierAcquire | ( | ) | SDL_CompilerBarrier() |
Definition at line 227 of file SDL_atomic.h.
#define SDL_MemoryBarrierRelease | ( | ) | SDL_CompilerBarrier() |
Definition at line 226 of file SDL_atomic.h.
typedef int SDL_SpinLock |
Definition at line 80 of file SDL_atomic.h.
|
extern |
Add to an atomic variable.
This function also acts as a full memory barrier.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to an SDL_atomic_t variable to be modified. |
v | the desired value to add. |
|
extern |
Set an atomic variable to a new value if it is currently an old value.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to an SDL_atomic_t variable to be modified. |
oldval | the old value. |
newval | the new value. |
|
extern |
Set a pointer to a new value if it is currently an old value.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to a pointer. |
oldval | the old pointer value. |
newval | the new pointer value. |
|
extern |
Get the value of an atomic variable.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to an SDL_atomic_t variable. |
|
extern |
Get the value of a pointer atomically.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to a pointer. |
|
extern |
Lock a spin lock by setting it to a non-zero value.
Please note that spinlocks are dangerous if you don't know what you're doing. Please be careful using any sort of spinlock!
lock | a pointer to a lock variable. |
|
extern |
Set an atomic variable to a value.
This function also acts as a full memory barrier.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to an SDL_atomic_t variable to be modified. |
v | the desired value. |
|
extern |
Set a pointer to a value atomically.
Note: If you don't know what this function is for, you shouldn't use it!
a | a pointer to a pointer. |
v | the desired pointer value. |
|
extern |
Try to lock a spin lock by setting it to a non-zero value.
Please note that spinlocks are dangerous if you don't know what you're doing. Please be careful using any sort of spinlock!
lock | a pointer to a lock variable. |
|
extern |
Unlock a spin lock by setting it to 0.
Always returns immediately.
Please note that spinlocks are dangerous if you don't know what you're doing. Please be careful using any sort of spinlock!
lock | a pointer to a lock variable. |
|
extern |
|
extern |
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