Added Uint32 versions of the atomic functions

This commit is contained in:
Sam Lantinga 2024-09-17 03:27:11 -07:00
parent 8d223b3037
commit d0edf68774
5 changed files with 180 additions and 4 deletions

View File

@ -316,7 +316,7 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
* this!).
*
* This is a struct so people don't accidentally use numeric operations on it
* directly. You have to use SDL_Atomic* functions.
* directly. You have to use SDL atomic functions.
*
* \since This struct is available since SDL 3.0.0.
*
@ -342,7 +342,8 @@ typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt;
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_CompareAndSwapAtomicPointer
* \sa SDL_GetAtomicInt
* \sa SDL_SetAtomicInt
*/
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval);
@ -439,6 +440,91 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v);
#define SDL_AtomicDecRef(a) (SDL_AddAtomicInt(a, -1) == 1)
#endif
/**
* A type representing an atomic unsigned 32-bit value.
*
* This can be used to manage a value that is synchronized across multiple
* CPUs without a race condition; when an app sets a value with SDL_SetAtomicU32
* all other threads, regardless of the CPU it is running on, will see that
* value when retrieved with SDL_GetAtomicU32, regardless of CPU caches, etc.
*
* This is also useful for atomic compare-and-swap operations: a thread can
* change the value as long as its current value matches expectations. When
* done in a loop, one can guarantee data consistency across threads without a
* lock (but the usual warnings apply: if you don't know what you're doing, or
* you don't do it carefully, you can confidently cause any number of
* disasters with this, so in most cases, you _should_ use a mutex instead of
* this!).
*
* This is a struct so people don't accidentally use numeric operations on it
* directly. You have to use SDL atomic functions.
*
* \since This struct is available since SDL 3.0.0.
*
* \sa SDL_CompareAndSwapAtomicU32
* \sa SDL_GetAtomicU32
* \sa SDL_SetAtomicU32
* \sa SDL_AddAtomicU32
*/
typedef struct SDL_AtomicU32 { Uint32 value; } SDL_AtomicU32;
/**
* 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!***
*
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
* \param oldval the old value.
* \param newval the new value.
* \returns SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
*
* \threadsafety It is safe to call this function from any thread.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_GetAtomicU32
* \sa SDL_SetAtomicU32
*/
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval);
/**
* 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!***
*
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
* \param v the desired value.
* \returns the previous value of the atomic variable.
*
* \threadsafety It is safe to call this function from any thread.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_GetAtomicU32
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v);
/**
* Get the value of an atomic variable.
*
* ***Note: If you don't know what this function is for, you shouldn't use
* it!***
*
* \param a a pointer to an SDL_AtomicU32 variable.
* \returns the current value of an atomic variable.
*
* \threadsafety It is safe to call this function from any thread.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_SetAtomicU32
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAtomicU32(SDL_AtomicU32 *a);
/**
* Set a pointer to a new value if it is currently an old value.
*

View File

@ -128,12 +128,13 @@ SDL_bool SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval)
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(long) == sizeof(a->value));
return _InterlockedCompareExchange((long *)&a->value, (long)newval, (long)oldval) == (long)oldval;
#elif defined(HAVE_WATCOM_ATOMICS)
return _SDL_cmpxchg_watcom(&a->value, newval, oldval);
return _SDL_cmpxchg_watcom((volatile int *)&a->value, newval, oldval);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(&a->value, oldval, newval);
#elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics.
return OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
#elif defined(SDL_PLATFORM_SOLARIS)
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(uint_t) == sizeof(a->value));
return ((int)atomic_cas_uint((volatile uint_t *)&a->value, (uint_t)oldval, (uint_t)newval) == oldval);
#elif defined(EMULATE_CAS)
bool result = false;
@ -151,6 +152,37 @@ SDL_bool SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval)
#endif
}
SDL_bool SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval)
{
#ifdef HAVE_MSC_ATOMICS
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(long) == sizeof(a->value));
return _InterlockedCompareExchange((long *)&a->value, (long)newval, (long)oldval) == (long)oldval;
#elif defined(HAVE_WATCOM_ATOMICS)
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(int) == sizeof(a->value));
return _SDL_cmpxchg_watcom((volatile int *)&a->value, (int)newval, (int)oldval);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(&a->value, oldval, newval);
#elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics.
return OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*)&a->value);
#elif defined(SDL_PLATFORM_SOLARIS)
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(uint_t) == sizeof(a->value));
return ((Uint32)atomic_cas_uint((volatile uint_t *)&a->value, (uint_t)oldval, (uint_t)newval) == oldval);
#elif defined(EMULATE_CAS)
bool result = false;
enterLock(a);
if (a->value == oldval) {
a->value = newval;
result = true;
}
leaveLock(a);
return result;
#else
#error Please define your platform.
#endif
}
SDL_bool SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval)
{
#ifdef HAVE_MSC_ATOMICS
@ -191,6 +223,7 @@ int SDL_SetAtomicInt(SDL_AtomicInt *a, int v)
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(&a->value, v);
#elif defined(SDL_PLATFORM_SOLARIS)
SDL_COMPILE_TIME_ASSERT(atomic_set, sizeof(uint_t) == sizeof(a->value));
return (int)atomic_swap_uint((volatile uint_t *)&a->value, v);
#else
int value;
@ -201,6 +234,27 @@ int SDL_SetAtomicInt(SDL_AtomicInt *a, int v)
#endif
}
Uint32 SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v)
{
#ifdef HAVE_MSC_ATOMICS
SDL_COMPILE_TIME_ASSERT(atomic_set, sizeof(long) == sizeof(a->value));
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(SDL_PLATFORM_SOLARIS)
SDL_COMPILE_TIME_ASSERT(atomic_set, sizeof(uint_t) == sizeof(a->value));
return (Uint32)atomic_swap_uint((volatile uint_t *)&a->value, v);
#else
Uint32 value;
do {
value = a->value;
} while (!SDL_CompareAndSwapAtomicU32(a, value, v));
return value;
#endif
}
void *SDL_SetAtomicPointer(void **a, void *v)
{
#ifdef HAVE_MSC_ATOMICS
@ -226,7 +280,8 @@ int SDL_AddAtomicInt(SDL_AtomicInt *a, int v)
SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(long) == sizeof(a->value));
return _InterlockedExchangeAdd((long *)&a->value, v);
#elif defined(HAVE_WATCOM_ATOMICS)
return _SDL_xadd_watcom(&a->value, v);
SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(int) == sizeof(a->value));
return _SDL_xadd_watcom((volatile int *)&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_fetch_and_add(&a->value, v);
#elif defined(SDL_PLATFORM_SOLARIS)
@ -267,6 +322,32 @@ int SDL_GetAtomicInt(SDL_AtomicInt *a)
#endif
}
Uint32 SDL_GetAtomicU32(SDL_AtomicU32 *a)
{
#ifdef HAVE_ATOMIC_LOAD_N
return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
#elif defined(HAVE_MSC_ATOMICS)
SDL_COMPILE_TIME_ASSERT(atomic_get, sizeof(long) == sizeof(a->value));
return (Uint32)_InterlockedOr((long *)&a->value, 0);
#elif defined(HAVE_WATCOM_ATOMICS)
SDL_COMPILE_TIME_ASSERT(atomic_get, sizeof(int) == sizeof(a->value));
return (Uint32)_SDL_xadd_watcom((volatile int *)&a->value, 0);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_or_and_fetch(&a->value, 0);
#elif defined(SDL_PLATFORM_MACOS) // this is deprecated in 10.12 sdk; favor gcc atomics.
return OSAtomicOr32Barrier(0, (volatile uint32_t *)&a->value);
#elif defined(SDL_PLATFORM_SOLARIS)
SDL_COMPILE_TIME_ASSERT(atomic_get, sizeof(uint_t) == sizeof(a->value));
return (Uint32)atomic_or_uint_nv((volatile uint_t *)&a->value, 0);
#else
Uint32 value;
do {
value = a->value;
} while (!SDL_CompareAndSwapAtomicU32(a, value, value));
return value;
#endif
}
void *SDL_GetAtomicPointer(void **a)
{
#ifdef HAVE_ATOMIC_LOAD_N

View File

@ -63,6 +63,7 @@ SDL3_0.0.0 {
SDL_CloseStorage;
SDL_CompareAndSwapAtomicInt;
SDL_CompareAndSwapAtomicPointer;
SDL_CompareAndSwapAtomicU32;
SDL_ComposeCustomBlendMode;
SDL_ConvertAudioSamples;
SDL_ConvertEventToRenderCoordinates;
@ -215,6 +216,7 @@ SDL3_0.0.0 {
SDL_GetAssertionReport;
SDL_GetAtomicInt;
SDL_GetAtomicPointer;
SDL_GetAtomicU32;
SDL_GetAudioDeviceChannelMap;
SDL_GetAudioDeviceFormat;
SDL_GetAudioDeviceGain;
@ -780,6 +782,7 @@ SDL3_0.0.0 {
SDL_SetAssertionHandler;
SDL_SetAtomicInt;
SDL_SetAtomicPointer;
SDL_SetAtomicU32;
SDL_SetAudioDeviceGain;
SDL_SetAudioPostmixCallback;
SDL_SetAudioStreamFormat;

View File

@ -88,6 +88,7 @@
#define SDL_CloseStorage SDL_CloseStorage_REAL
#define SDL_CompareAndSwapAtomicInt SDL_CompareAndSwapAtomicInt_REAL
#define SDL_CompareAndSwapAtomicPointer SDL_CompareAndSwapAtomicPointer_REAL
#define SDL_CompareAndSwapAtomicU32 SDL_CompareAndSwapAtomicU32_REAL
#define SDL_ComposeCustomBlendMode SDL_ComposeCustomBlendMode_REAL
#define SDL_ConvertAudioSamples SDL_ConvertAudioSamples_REAL
#define SDL_ConvertEventToRenderCoordinates SDL_ConvertEventToRenderCoordinates_REAL
@ -240,6 +241,7 @@
#define SDL_GetAssertionReport SDL_GetAssertionReport_REAL
#define SDL_GetAtomicInt SDL_GetAtomicInt_REAL
#define SDL_GetAtomicPointer SDL_GetAtomicPointer_REAL
#define SDL_GetAtomicU32 SDL_GetAtomicU32_REAL
#define SDL_GetAudioDeviceChannelMap SDL_GetAudioDeviceChannelMap_REAL
#define SDL_GetAudioDeviceFormat SDL_GetAudioDeviceFormat_REAL
#define SDL_GetAudioDeviceGain SDL_GetAudioDeviceGain_REAL
@ -805,6 +807,7 @@
#define SDL_SetAssertionHandler SDL_SetAssertionHandler_REAL
#define SDL_SetAtomicInt SDL_SetAtomicInt_REAL
#define SDL_SetAtomicPointer SDL_SetAtomicPointer_REAL
#define SDL_SetAtomicU32 SDL_SetAtomicU32_REAL
#define SDL_SetAudioDeviceGain SDL_SetAudioDeviceGain_REAL
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL

View File

@ -109,6 +109,7 @@ SDL_DYNAPI_PROC(void,SDL_CloseSensor,(SDL_Sensor *a),(a),)
SDL_DYNAPI_PROC(SDL_bool,SDL_CloseStorage,(SDL_Storage *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_CompareAndSwapAtomicInt,(SDL_AtomicInt *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_CompareAndSwapAtomicPointer,(void **a, void *b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_CompareAndSwapAtomicU32,(SDL_AtomicU32 *a, Uint32 b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_BlendMode,SDL_ComposeCustomBlendMode,(SDL_BlendFactor a, SDL_BlendFactor b, SDL_BlendOperation c, SDL_BlendFactor d, SDL_BlendFactor e, SDL_BlendOperation f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_ConvertAudioSamples,(const SDL_AudioSpec *a, const Uint8 *b, int c, const SDL_AudioSpec *d, Uint8 **e, int *f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_ConvertEventToRenderCoordinates,(SDL_Renderer *a, SDL_Event *b),(a,b),return)
@ -261,6 +262,7 @@ SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),retu
SDL_DYNAPI_PROC(const SDL_AssertData*,SDL_GetAssertionReport,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetAtomicInt,(SDL_AtomicInt *a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_GetAtomicPointer,(void **a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetAtomicU32,(SDL_AtomicU32 *a),(a),return)
SDL_DYNAPI_PROC(int*,SDL_GetAudioDeviceChannelMap,(SDL_AudioDeviceID a, int *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b, int *c),(a,b,c),return)
SDL_DYNAPI_PROC(float,SDL_GetAudioDeviceGain,(SDL_AudioDeviceID a),(a),return)
@ -816,6 +818,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_SetAppMetadataProperty,(const char *a, const char *
SDL_DYNAPI_PROC(void,SDL_SetAssertionHandler,(SDL_AssertionHandler a, void *b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_SetAtomicInt,(SDL_AtomicInt *a, int b),(a,b),return)
SDL_DYNAPI_PROC(void*,SDL_SetAtomicPointer,(void **a, void *b),(a,b),return)
SDL_DYNAPI_PROC(Uint32,SDL_SetAtomicU32,(SDL_AtomicU32 *a, Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_SetAudioDeviceGain,(SDL_AudioDeviceID a, float b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_SetAudioPostmixCallback,(SDL_AudioDeviceID a, SDL_AudioPostmixCallback b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, const SDL_AudioSpec *b, const SDL_AudioSpec *c),(a,b,c),return)