Atlas - SDL_spinlock.c

Home / ext / SDL / src / atomic Lines: 7 | Size: 5583 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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 SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); 55 return _InterlockedExchange_acq((long *)lock, 1) == 0; 56 57#elif defined(_MSC_VER) 58 SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); 59 return InterlockedExchange((long *)lock, 1) == 0; 60 61#elif defined(__GNUC__) && defined(__arm__) && \ 62 (defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \ 63 defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ 64 defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \ 65 defined(__ARM_ARCH_5TEJ__)) 66 int result; 67 68#ifdef SDL_PLATFORM_RISCOS 69 if (__cpucap_have_rex()) { 70 __asm__ __volatile__( 71 "ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]" 72 : "=&r"(result) 73 : "r"(1), "r"(lock) 74 : "cc", "memory"); 75 return result == 0; 76 } 77#endif 78 79 __asm__ __volatile__( 80 "swp %0, %1, [%2]\n" 81 : "=&r,&r"(result) 82 : "r,0"(1), "r,r"(lock) 83 : "memory"); 84 return result == 0; 85 86#elif defined(__GNUC__) && defined(__arm__) 87 int result; 88 __asm__ __volatile__( 89 "ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]" 90 : "=&r"(result) 91 : "r"(1), "r"(lock) 92 : "cc", "memory"); 93 return result == 0; 94 95#elif (defined(__GNUC__) || defined(__TINYC__)) && (defined(__i386__) || defined(__x86_64__)) 96 int result; 97 __asm__ __volatile__( 98 "lock ; xchgl %0, (%1)\n" 99 : "=r"(result) 100 : "r"(lock), "0"(1) 101 : "cc", "memory"); 102 return result == 0; 103 104#elif defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) 105 // Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. 106 return OSAtomicCompareAndSwap32Barrier(0, 1, lock); 107 108#elif defined(SDL_PLATFORM_SOLARIS) && defined(_LP64) 109 // Used for Solaris with non-gcc compilers. 110 return ((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0); 111 112#elif defined(SDL_PLATFORM_SOLARIS) && !defined(_LP64) 113 // Used for Solaris with non-gcc compilers. 114 return ((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0); 115#elif defined(PS2) 116 uint32_t oldintr; 117 bool res = false; 118 // disable interruption 119 oldintr = DIntr(); 120 121 if (*lock == 0) { 122 *lock = 1; 123 res = true; 124 } 125 // enable interruption 126 if (oldintr) { 127 EIntr(); 128 } 129 return res; 130#else 131 // Terrible terrible damage 132 static SDL_Mutex *_spinlock_mutex; 133 134 if (!_spinlock_mutex) { 135 // Race condition on first lock... 136 _spinlock_mutex = SDL_CreateMutex(); 137 } 138 SDL_LockMutex(_spinlock_mutex); 139 if (*lock == 0) { 140 *lock = 1; 141 SDL_UnlockMutex(_spinlock_mutex); 142 return true; 143 } else { 144 SDL_UnlockMutex(_spinlock_mutex); 145 return false; 146 } 147#endif 148} 149 150void SDL_LockSpinlock(SDL_SpinLock *lock) 151{ 152 int iterations = 0; 153 // FIXME: Should we have an eventual timeout? 154 while (!SDL_TryLockSpinlock(lock)) { 155 if (iterations < 32) { 156 iterations++; 157 SDL_CPUPauseInstruction(); 158 } else { 159 // !!! FIXME: this doesn't definitely give up the current timeslice, it does different things on various platforms. 160 SDL_Delay(0); 161 } 162 } 163} 164 165void SDL_UnlockSpinlock(SDL_SpinLock *lock) 166{ 167#if defined(HAVE_GCC_ATOMICS) || defined(HAVE_GCC_SYNC_LOCK_TEST_AND_SET) 168 __sync_lock_release(lock); 169 170#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) 171 SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); 172 _InterlockedExchange_rel((long *)lock, 0); 173 174#elif defined(_MSC_VER) 175 _ReadWriteBarrier(); 176 *lock = 0; 177 178#elif defined(SDL_PLATFORM_SOLARIS) 179 // Used for Solaris when not using gcc. 180 *lock = 0; 181 membar_producer(); 182 183#else 184 *lock = 0; 185#endif 186} 187
[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.