Atlas - SDL_spinlock.c
Home / ext / SDL / src / atomic Lines: 7 | Size: 5427 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#if defined(SDL_PLATFORM_WINDOWS) 24#include "../core/windows/SDL_windows.h" 25#endif 26 27#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_SOLARIS) 28#include <atomic.h> 29#endif 30 31#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_RISCOS) 32#include <unixlib/local.h> 33#endif 34 35#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 36#include <xmmintrin.h> 37#endif 38 39#ifdef PS2 40#include <kernel.h> 41#endif 42 43#if !defined(HAVE_GCC_ATOMICS) && defined(SDL_PLATFORM_MACOS) 44#include <libkern/OSAtomic.h> 45#endif 46 47// This function is where all the magic happens... 48bool SDL_TryLockSpinlock(SDL_SpinLock *lock) 49{ 50#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET) 51 return __sync_lock_test_and_set(lock, 1) == 0; 52 53#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) 54 return _InterlockedExchange_acq(lock, 1) == 0; 55 56#elif defined(_MSC_VER) 57 SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); 58 return InterlockedExchange((long *)lock, 1) == 0; 59 60#elif defined(__GNUC__) && defined(__arm__) && \ 61 (defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \ 62 defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ 63 defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \ 64 defined(__ARM_ARCH_5TEJ__)) 65 int result; 66 67#ifdef SDL_PLATFORM_RISCOS 68 if (__cpucap_have_rex()) { 69 __asm__ __volatile__( 70 "ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]" 71 : "=&r"(result) 72 : "r"(1), "r"(lock) 73 : "cc", "memory"); 74 return result == 0; 75 } 76#endif 77 78 __asm__ __volatile__( 79 "swp %0, %1, [%2]\n" 80 : "=&r,&r"(result) 81 : "r,0"(1), "r,r"(lock) 82 : "memory"); 83 return result == 0; 84 85#elif defined(__GNUC__) && defined(__arm__) 86 int result; 87 __asm__ __volatile__( 88 "ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]" 89 : "=&r"(result) 90 : "r"(1), "r"(lock) 91 : "cc", "memory"); 92 return result == 0; 93 94#elif (defined(__GNUC__) || defined(__TINYC__)) && (defined(__i386__) || defined(__x86_64__)) 95 int result; 96 __asm__ __volatile__( 97 "lock ; xchgl %0, (%1)\n" 98 : "=r"(result) 99 : "r"(lock), "0"(1) 100 : "cc", "memory"); 101 return result == 0; 102 103#elif defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) 104 // Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. 105 return OSAtomicCompareAndSwap32Barrier(0, 1, lock); 106 107#elif defined(SDL_PLATFORM_SOLARIS) && defined(_LP64) 108 // Used for Solaris with non-gcc compilers. 109 return ((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0); 110 111#elif defined(SDL_PLATFORM_SOLARIS) && !defined(_LP64) 112 // Used for Solaris with non-gcc compilers. 113 return ((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0); 114#elif defined(PS2) 115 uint32_t oldintr; 116 bool res = false; 117 // disable interruption 118 oldintr = DIntr(); 119 120 if (*lock == 0) { 121 *lock = 1; 122 res = true; 123 } 124 // enable interruption 125 if (oldintr) { 126 EIntr(); 127 } 128 return res; 129#else 130 // Terrible terrible damage 131 static SDL_Mutex *_spinlock_mutex; 132 133 if (!_spinlock_mutex) { 134 // Race condition on first lock... 135 _spinlock_mutex = SDL_CreateMutex(); 136 } 137 SDL_LockMutex(_spinlock_mutex); 138 if (*lock == 0) { 139 *lock = 1; 140 SDL_UnlockMutex(_spinlock_mutex); 141 return true; 142 } else { 143 SDL_UnlockMutex(_spinlock_mutex); 144 return false; 145 } 146#endif 147} 148 149void SDL_LockSpinlock(SDL_SpinLock *lock) 150{ 151 int iterations = 0; 152 // FIXME: Should we have an eventual timeout? 153 while (!SDL_TryLockSpinlock(lock)) { 154 if (iterations < 32) { 155 iterations++; 156 SDL_CPUPauseInstruction(); 157 } else { 158 // !!! FIXME: this doesn't definitely give up the current timeslice, it does different things on various platforms. 159 SDL_Delay(0); 160 } 161 } 162} 163 164void SDL_UnlockSpinlock(SDL_SpinLock *lock) 165{ 166#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET) 167 __sync_lock_release(lock); 168 169#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) 170 _InterlockedExchange_rel(lock, 0); 171 172#elif defined(_MSC_VER) 173 _ReadWriteBarrier(); 174 *lock = 0; 175 176#elif defined(SDL_PLATFORM_SOLARIS) 177 // Used for Solaris when not using gcc. 178 *lock = 0; 179 membar_producer(); 180 181#else 182 *lock = 0; 183#endif 184} 185[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.