From 014f507c4007436c6063e9f3590e6bca834e3ec0 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 3 Jan 2021 12:13:40 -0600 Subject: [PATCH] Use specific acquire and release variants of InterlockedExchange on ARM _InterlockedExchange_rel() is required for correctness on ARM because the _ReadWriteBarrier() macro is only a compiler memory barrier, not a hardware memory barrier. Due to ARM's relaxed memory model, this means the '*lock = 0' write may be observed before the operations inside the lock, causing possible corruption of data protected by the lock. _InterlockedExchange_acq() is more efficient on ARM because it avoids an expensive full memory barrier that _InterlockedExchange() does. --- src/atomic/SDL_spinlock.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c index 425fa5350..a58a07394 100644 --- a/src/atomic/SDL_spinlock.c +++ b/src/atomic/SDL_spinlock.c @@ -72,6 +72,9 @@ SDL_AtomicTryLock(SDL_SpinLock *lock) return SDL_FALSE; } +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) + return (_InterlockedExchange_acq(lock, 1) == 0); + #elif defined(_MSC_VER) SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); return (InterlockedExchange((long*)lock, 1) == 0); @@ -173,7 +176,9 @@ SDL_AtomicLock(SDL_SpinLock *lock) void SDL_AtomicUnlock(SDL_SpinLock *lock) { -#if defined(_MSC_VER) +#if defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) + _InterlockedExchange_rel(lock, 0); +#elif defined(_MSC_VER) _ReadWriteBarrier(); *lock = 0;