Merge commit '411251c6242b04119edc41ce83f09f0714e2d32b' as 'external/SDL'
This commit is contained in:
Vendored
+390
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
|
||||
#include <intrin.h>
|
||||
#define HAVE_MSC_ATOMICS 1
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_MACOS // !!! FIXME: should we favor gcc atomics?
|
||||
#include <libkern/OSAtomic.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_SOLARIS)
|
||||
#include <atomic.h>
|
||||
#endif
|
||||
|
||||
// The __atomic intrinsics showed up in different times for different compilers.
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || (defined(__clang__) && defined(HAVE_GCC_ATOMICS))
|
||||
#define HAVE_ATOMIC_LOAD_N 1
|
||||
#define HAVE_ATOMIC_EXCHANGE_N 1
|
||||
#else
|
||||
#if SDL_HAS_BUILTIN(__atomic_load_n)
|
||||
#define HAVE_ATOMIC_LOAD_N 1
|
||||
#endif
|
||||
#if SDL_HAS_BUILTIN(__atomic_exchange_n)
|
||||
#define HAVE_ATOMIC_EXCHANGE_N 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
If any of the operations are not provided then we must emulate some
|
||||
of them. That means we need a nice implementation of spin locks
|
||||
that avoids the "one big lock" problem. We use a vector of spin
|
||||
locks and pick which one to use based on the address of the operand
|
||||
of the function.
|
||||
|
||||
To generate the index of the lock we first shift by 3 bits to get
|
||||
rid on the zero bits that result from 32 and 64 bit alignment of
|
||||
data. We then mask off all but 5 bits and use those 5 bits as an
|
||||
index into the table.
|
||||
|
||||
Picking the lock this way insures that accesses to the same data at
|
||||
the same time will go to the same lock. OTOH, accesses to different
|
||||
data have only a 1/32 chance of hitting the same lock. That should
|
||||
pretty much eliminate the chances of several atomic operations on
|
||||
different data from waiting on the same "big lock". If it isn't
|
||||
then the table of locks can be expanded to a new size so long as
|
||||
the new size is a power of two.
|
||||
|
||||
Contributed by Bob Pendleton, bob@pendleton.com
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_SOLARIS)
|
||||
#define EMULATE_CAS 1
|
||||
#endif
|
||||
|
||||
#ifdef EMULATE_CAS
|
||||
static SDL_SpinLock locks[32];
|
||||
|
||||
static SDL_INLINE void enterLock(void *a)
|
||||
{
|
||||
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
|
||||
|
||||
SDL_LockSpinlock(&locks[index]);
|
||||
}
|
||||
|
||||
static SDL_INLINE void leaveLock(void *a)
|
||||
{
|
||||
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
|
||||
|
||||
SDL_UnlockSpinlock(&locks[index]);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int 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_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;
|
||||
|
||||
enterLock(a);
|
||||
if (a->value == oldval) {
|
||||
a->value = newval;
|
||||
result = true;
|
||||
}
|
||||
leaveLock(a);
|
||||
|
||||
return result;
|
||||
#else
|
||||
#error Please define your platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
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_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
|
||||
}
|
||||
|
||||
bool SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval)
|
||||
{
|
||||
#ifdef HAVE_MSC_ATOMICS
|
||||
return _InterlockedCompareExchangePointer(a, newval, oldval) == oldval;
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_bool_compare_and_swap(a, oldval, newval);
|
||||
#elif defined(SDL_PLATFORM_MACOS) && defined(__LP64__) // this is deprecated in 10.12 sdk; favor gcc atomics.
|
||||
return OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t *)a);
|
||||
#elif defined(SDL_PLATFORM_MACOS) && !defined(__LP64__) // this is deprecated in 10.12 sdk; favor gcc atomics.
|
||||
return OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t *)a);
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
return (atomic_cas_ptr(a, oldval, newval) == oldval);
|
||||
#elif defined(EMULATE_CAS)
|
||||
bool result = false;
|
||||
|
||||
enterLock(a);
|
||||
if (*a == oldval) {
|
||||
*a = newval;
|
||||
result = true;
|
||||
}
|
||||
leaveLock(a);
|
||||
|
||||
return result;
|
||||
#else
|
||||
#error Please define your platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
int SDL_SetAtomicInt(SDL_AtomicInt *a, int 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_ATOMIC_EXCHANGE_N)
|
||||
return __atomic_exchange_n(&a->value, v, __ATOMIC_SEQ_CST);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
// __sync_lock_test_and_set() is designed for locking rather than a
|
||||
// generic atomic exchange, so it only provides an acquire barrier
|
||||
// and may not store the exact value on all architectures. We prefer
|
||||
// __atomic_exchange_n() instead on all modern compilers.
|
||||
__sync_synchronize();
|
||||
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;
|
||||
do {
|
||||
value = a->value;
|
||||
} while (!SDL_CompareAndSwapAtomicInt(a, value, v));
|
||||
return value;
|
||||
#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_ATOMIC_EXCHANGE_N)
|
||||
return __atomic_exchange_n(&a->value, v, __ATOMIC_SEQ_CST);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
// __sync_lock_test_and_set() is designed for locking rather than a
|
||||
// generic atomic exchange, so it only provides an acquire barrier
|
||||
// and may not store the exact value on all architectures. We prefer
|
||||
// __atomic_exchange_n() instead on all modern compilers.
|
||||
__sync_synchronize();
|
||||
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
|
||||
return _InterlockedExchangePointer(a, v);
|
||||
#elif defined(HAVE_ATOMIC_EXCHANGE_N)
|
||||
return __atomic_exchange_n(a, v, __ATOMIC_SEQ_CST);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
// __sync_lock_test_and_set() is designed for locking rather than a
|
||||
// generic atomic exchange, so it only provides an acquire barrier
|
||||
// and may not store the exact value on all architectures. We prefer
|
||||
// __atomic_exchange_n() instead on all modern compilers.
|
||||
__sync_synchronize();
|
||||
return __sync_lock_test_and_set(a, v);
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
return atomic_swap_ptr(a, v);
|
||||
#else
|
||||
void *value;
|
||||
do {
|
||||
value = *a;
|
||||
} while (!SDL_CompareAndSwapAtomicPointer(a, value, v));
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SDL_AddAtomicInt(SDL_AtomicInt *a, int v)
|
||||
{
|
||||
#ifdef HAVE_MSC_ATOMICS
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(long) == sizeof(a->value));
|
||||
return _InterlockedExchangeAdd((long *)&a->value, v);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_fetch_and_add(&a->value, v);
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
int pv = a->value;
|
||||
membar_consumer();
|
||||
atomic_add_int((volatile uint_t *)&a->value, v);
|
||||
return pv;
|
||||
#else
|
||||
int value;
|
||||
do {
|
||||
value = a->value;
|
||||
} while (!SDL_CompareAndSwapAtomicInt(a, value, (value + v)));
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
Uint32 SDL_AddAtomicU32(SDL_AtomicU32 *a, int v)
|
||||
{
|
||||
#ifdef HAVE_MSC_ATOMICS
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_add, sizeof(long) == sizeof(a->value));
|
||||
return (Uint32)_InterlockedExchangeAdd((long *)&a->value, v);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_fetch_and_add(&a->value, v);
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
Uint32 pv = a->value;
|
||||
membar_consumer();
|
||||
atomic_add_int((volatile uint_t *)&a->value, v);
|
||||
return pv;
|
||||
#else
|
||||
Uint32 value;
|
||||
do {
|
||||
value = a->value;
|
||||
} while (!SDL_CompareAndSwapAtomicU32(a, value, (value + v)));
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SDL_GetAtomicInt(SDL_AtomicInt *a)
|
||||
{
|
||||
#ifdef HAVE_ATOMIC_LOAD_N
|
||||
return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(HAVE_MSC_ATOMICS) && (defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_get_int, sizeof(__int32) == sizeof(a->value));
|
||||
return (int)__ldar32((unsigned __int32 *)&a->value);
|
||||
#elif defined(HAVE_MSC_ATOMICS) && (defined(_M_X64) || defined(_M_IX86))
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_get_int, sizeof(int) == sizeof(a->value));
|
||||
SDL_CompilerBarrier();
|
||||
int value = *(volatile int *)&a->value;
|
||||
SDL_CompilerBarrier();
|
||||
return value;
|
||||
#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 sizeof(a->value) == sizeof(uint32_t) ? OSAtomicOr32Barrier(0, (volatile uint32_t *)&a->value) : OSAtomicAdd64Barrier(0, (volatile int64_t *)&a->value);
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
return atomic_or_uint_nv((volatile uint_t *)&a->value, 0);
|
||||
#else
|
||||
int value;
|
||||
do {
|
||||
value = a->value;
|
||||
} while (!SDL_CompareAndSwapAtomicInt(a, value, value));
|
||||
return value;
|
||||
#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) && (defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_get_u32, sizeof(__int32) == sizeof(a->value));
|
||||
return __ldar32((unsigned __int32 *)&a->value);
|
||||
#elif defined(HAVE_MSC_ATOMICS) && (defined(_M_X64) || defined(_M_IX86))
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_get_u32, sizeof(Uint32) == sizeof(a->value));
|
||||
SDL_CompilerBarrier();
|
||||
Uint32 value = *(volatile Uint32 *)&a->value;
|
||||
SDL_CompilerBarrier();
|
||||
return value;
|
||||
#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
|
||||
return __atomic_load_n(a, __ATOMIC_SEQ_CST);
|
||||
#elif defined(HAVE_MSC_ATOMICS) && (defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
SDL_COMPILE_TIME_ASSERT(atomic_get_ptr, sizeof(__int64) == sizeof(*a));
|
||||
return (void *)__ldar64((unsigned __int64 *)a);
|
||||
#elif defined(HAVE_MSC_ATOMICS) && (defined(_M_X64) || defined(_M_IX86))
|
||||
SDL_CompilerBarrier();
|
||||
void *value = *(void * volatile *)a;
|
||||
SDL_CompilerBarrier();
|
||||
return value;
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_val_compare_and_swap(a, (void *)0, (void *)0);
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
return atomic_cas_ptr(a, (void *)0, (void *)0);
|
||||
#else
|
||||
void *value;
|
||||
do {
|
||||
value = *a;
|
||||
} while (!SDL_CompareAndSwapAtomicPointer(a, value, value));
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SDL_MEMORY_BARRIER_USES_FUNCTION
|
||||
#error This file should be built in arm mode so the mcr instruction is available for memory barriers
|
||||
#endif
|
||||
|
||||
void SDL_MemoryBarrierReleaseFunction(void)
|
||||
{
|
||||
SDL_MemoryBarrierRelease();
|
||||
}
|
||||
|
||||
void SDL_MemoryBarrierAcquireFunction(void)
|
||||
{
|
||||
SDL_MemoryBarrierAcquire();
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
#include "../core/windows/SDL_windows.h"
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_SOLARIS)
|
||||
#include <atomic.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_RISCOS)
|
||||
#include <unixlib/local.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef PS2
|
||||
#include <kernel.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_MACOS)
|
||||
#include <libkern/OSAtomic.h>
|
||||
#endif
|
||||
|
||||
// This function is where all the magic happens...
|
||||
bool SDL_TryLockSpinlock(SDL_SpinLock *lock)
|
||||
{
|
||||
#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
|
||||
return __sync_lock_test_and_set(lock, 1) == 0;
|
||||
|
||||
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
|
||||
return _InterlockedExchange_acq((long *)lock, 1) == 0;
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
|
||||
return InterlockedExchange((long *)lock, 1) == 0;
|
||||
|
||||
#elif defined(__GNUC__) && defined(__arm__) && \
|
||||
(defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \
|
||||
defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
|
||||
defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \
|
||||
defined(__ARM_ARCH_5TEJ__))
|
||||
int result;
|
||||
|
||||
#ifdef SDL_PLATFORM_RISCOS
|
||||
if (__cpucap_have_rex()) {
|
||||
__asm__ __volatile__(
|
||||
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
|
||||
: "=&r"(result)
|
||||
: "r"(1), "r"(lock)
|
||||
: "cc", "memory");
|
||||
return result == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
__asm__ __volatile__(
|
||||
"swp %0, %1, [%2]\n"
|
||||
: "=&r,&r"(result)
|
||||
: "r,0"(1), "r,r"(lock)
|
||||
: "memory");
|
||||
return result == 0;
|
||||
|
||||
#elif defined(__GNUC__) && defined(__arm__)
|
||||
int result;
|
||||
__asm__ __volatile__(
|
||||
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
|
||||
: "=&r"(result)
|
||||
: "r"(1), "r"(lock)
|
||||
: "cc", "memory");
|
||||
return result == 0;
|
||||
|
||||
#elif (defined(__GNUC__) || defined(__TINYC__)) && (defined(__i386__) || defined(__x86_64__))
|
||||
int result;
|
||||
__asm__ __volatile__(
|
||||
"lock ; xchgl %0, (%1)\n"
|
||||
: "=r"(result)
|
||||
: "r"(lock), "0"(1)
|
||||
: "cc", "memory");
|
||||
return result == 0;
|
||||
|
||||
#elif defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
|
||||
// Maybe used for PowerPC, but the Intel asm or gcc atomics are favored.
|
||||
return OSAtomicCompareAndSwap32Barrier(0, 1, lock);
|
||||
|
||||
#elif defined(SDL_PLATFORM_SOLARIS) && defined(_LP64)
|
||||
// Used for Solaris with non-gcc compilers.
|
||||
return ((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0);
|
||||
|
||||
#elif defined(SDL_PLATFORM_SOLARIS) && !defined(_LP64)
|
||||
// Used for Solaris with non-gcc compilers.
|
||||
return ((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0);
|
||||
#elif defined(PS2)
|
||||
uint32_t oldintr;
|
||||
bool res = false;
|
||||
// disable interruption
|
||||
oldintr = DIntr();
|
||||
|
||||
if (*lock == 0) {
|
||||
*lock = 1;
|
||||
res = true;
|
||||
}
|
||||
// enable interruption
|
||||
if (oldintr) {
|
||||
EIntr();
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
// Terrible terrible damage
|
||||
static SDL_Mutex *_spinlock_mutex;
|
||||
|
||||
if (!_spinlock_mutex) {
|
||||
// Race condition on first lock...
|
||||
_spinlock_mutex = SDL_CreateMutex();
|
||||
}
|
||||
SDL_LockMutex(_spinlock_mutex);
|
||||
if (*lock == 0) {
|
||||
*lock = 1;
|
||||
SDL_UnlockMutex(_spinlock_mutex);
|
||||
return true;
|
||||
} else {
|
||||
SDL_UnlockMutex(_spinlock_mutex);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SDL_LockSpinlock(SDL_SpinLock *lock)
|
||||
{
|
||||
int iterations = 0;
|
||||
// FIXME: Should we have an eventual timeout?
|
||||
while (!SDL_TryLockSpinlock(lock)) {
|
||||
if (iterations < 32) {
|
||||
iterations++;
|
||||
SDL_CPUPauseInstruction();
|
||||
} else {
|
||||
// !!! FIXME: this doesn't definitely give up the current timeslice, it does different things on various platforms.
|
||||
SDL_Delay(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_UnlockSpinlock(SDL_SpinLock *lock)
|
||||
{
|
||||
#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET)
|
||||
__sync_lock_release(lock);
|
||||
|
||||
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
|
||||
_InterlockedExchange_rel((long *)lock, 0);
|
||||
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
// Used for Solaris when not using gcc.
|
||||
membar_producer();
|
||||
*lock = 0;
|
||||
|
||||
#else
|
||||
SDL_MemoryBarrierRelease();
|
||||
*lock = 0;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user