Atlas - SDL_atomic.c
Home / ext / SDL2 / src / atomic Lines: 1 | Size: 9141 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 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#include "SDL_atomic.h" 24 25#if defined(_MSC_VER) && (_MSC_VER >= 1500) 26#include <intrin.h> 27#define HAVE_MSC_ATOMICS 1 28#endif 29 30#if defined(__MACOSX__) /* !!! FIXME: should we favor gcc atomics? */ 31#include <libkern/OSAtomic.h> 32#endif 33 34#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__) 35#include <atomic.h> 36#endif 37 38/* The __atomic_load_n() intrinsic showed up in different times for different compilers. */ 39#if defined(HAVE_GCC_ATOMICS) 40# if defined(__clang__) 41# if __has_builtin(__atomic_load_n) 42 /* !!! FIXME: this advertises as available in the NDK but uses an external symbol we don't have. 43 It might be in a later NDK or we might need an extra library? --ryan. */ 44# if !defined(__ANDROID__) 45# define HAVE_ATOMIC_LOAD_N 1 46# endif 47# endif 48# elif defined(__GNUC__) 49# if (__GNUC__ >= 5) 50# define HAVE_ATOMIC_LOAD_N 1 51# endif 52# endif 53#endif 54 55#if defined(__WATCOMC__) && defined(__386__) 56#define HAVE_WATCOM_ATOMICS 57extern _inline int _SDL_xchg_watcom(volatile int *a, int v); 58#pragma aux _SDL_xchg_watcom = \ 59 "xchg [ecx], eax" \ 60 parm [ecx] [eax] \ 61 value [eax] \ 62 modify exact [eax]; 63 64extern _inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, int oldval); 65#pragma aux _SDL_cmpxchg_watcom = \ 66 "lock cmpxchg [edx], ecx" \ 67 "setz al" \ 68 parm [edx] [ecx] [eax] \ 69 value [al] \ 70 modify exact [eax]; 71 72extern _inline int _SDL_xadd_watcom(volatile int *a, int v); 73#pragma aux _SDL_xadd_watcom = \ 74 "lock xadd [ecx], eax" \ 75 parm [ecx] [eax] \ 76 value [eax] \ 77 modify exact [eax]; 78#endif /* __WATCOMC__ && __386__ */ 79 80/* 81 If any of the operations are not provided then we must emulate some 82 of them. That means we need a nice implementation of spin locks 83 that avoids the "one big lock" problem. We use a vector of spin 84 locks and pick which one to use based on the address of the operand 85 of the function. 86 87 To generate the index of the lock we first shift by 3 bits to get 88 rid on the zero bits that result from 32 and 64 bit allignment of 89 data. We then mask off all but 5 bits and use those 5 bits as an 90 index into the table. 91 92 Picking the lock this way insures that accesses to the same data at 93 the same time will go to the same lock. OTOH, accesses to different 94 data have only a 1/32 chance of hitting the same lock. That should 95 pretty much eliminate the chances of several atomic operations on 96 different data from waiting on the same "big lock". If it isn't 97 then the table of locks can be expanded to a new size so long as 98 the new size is a power of two. 99 100 Contributed by Bob Pendleton, [email protected] 101*/ 102 103#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) && !defined(__SOLARIS__) && !defined(HAVE_WATCOM_ATOMICS) 104#define EMULATE_CAS 1 105#endif 106 107#if EMULATE_CAS 108static SDL_SpinLock locks[32]; 109 110static SDL_INLINE void 111enterLock(void *a) 112{ 113 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f); 114 115 SDL_AtomicLock(&locks[index]); 116} 117 118static SDL_INLINE void 119leaveLock(void *a) 120{ 121 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f); 122 123 SDL_AtomicUnlock(&locks[index]); 124} 125#endif 126 127 128SDL_bool 129SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval) 130{ 131#ifdef HAVE_MSC_ATOMICS 132 return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval); 133#elif defined(HAVE_WATCOM_ATOMICS) 134 return (SDL_bool) _SDL_cmpxchg_watcom(&a->value, newval, oldval); 135#elif defined(HAVE_GCC_ATOMICS) 136 return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval); 137#elif defined(__MACOSX__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */ 138 return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value); 139#elif defined(__SOLARIS__) && defined(_LP64) 140 return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)&a->value, (uint64_t)oldval, (uint64_t)newval) == oldval); 141#elif defined(__SOLARIS__) && !defined(_LP64) 142 return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)&a->value, (uint32_t)oldval, (uint32_t)newval) == oldval); 143#elif EMULATE_CAS 144 SDL_bool retval = SDL_FALSE; 145 146 enterLock(a); 147 if (a->value == oldval) { 148 a->value = newval; 149 retval = SDL_TRUE; 150 } 151 leaveLock(a); 152 153 return retval; 154#else 155 #error Please define your platform. 156#endif 157} 158 159SDL_bool 160SDL_AtomicCASPtr(void **a, void *oldval, void *newval) 161{ 162#if defined(HAVE_MSC_ATOMICS) && (_M_IX86) 163 return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval); 164#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86) 165 return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval); 166#elif defined(HAVE_WATCOM_ATOMICS) 167 return (SDL_bool) _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval); 168#elif defined(HAVE_GCC_ATOMICS) 169 return __sync_bool_compare_and_swap(a, oldval, newval); 170#elif defined(__MACOSX__) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */ 171 return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a); 172#elif defined(__MACOSX__) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */ 173 return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a); 174#elif defined(__SOLARIS__) 175 return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval); 176#elif EMULATE_CAS 177 SDL_bool retval = SDL_FALSE; 178 179 enterLock(a); 180 if (*a == oldval) { 181 *a = newval; 182 retval = SDL_TRUE; 183 } 184 leaveLock(a); 185 186 return retval; 187#else 188 #error Please define your platform. 189#endif 190} 191 192int 193SDL_AtomicSet(SDL_atomic_t *a, int v) 194{ 195#ifdef HAVE_MSC_ATOMICS 196 return _InterlockedExchange((long*)&a->value, v); 197#elif defined(HAVE_WATCOM_ATOMICS) 198 return _SDL_xchg_watcom(&a->value, v); 199#elif defined(HAVE_GCC_ATOMICS) 200 return __sync_lock_test_and_set(&a->value, v); 201#elif defined(__SOLARIS__) && defined(_LP64) 202 return (int) atomic_swap_64((volatile uint64_t*)&a->value, (uint64_t)v); 203#elif defined(__SOLARIS__) && !defined(_LP64) 204 return (int) atomic_swap_32((volatile uint32_t*)&a->value, (uint32_t)v); 205#else 206 int value; 207 do { 208 value = a->value; 209 } while (!SDL_AtomicCAS(a, value, v)); 210 return value; 211#endif 212} 213 214void* 215SDL_AtomicSetPtr(void **a, void *v) 216{ 217#if defined(HAVE_MSC_ATOMICS) && (_M_IX86) 218 return (void *) _InterlockedExchange((long *)a, (long) v); 219#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86) 220 return _InterlockedExchangePointer(a, v); 221#elif defined(HAVE_WATCOM_ATOMICS) 222 return (void *) _SDL_xchg_watcom((int *)a, (long)v); 223#elif defined(HAVE_GCC_ATOMICS) 224 return __sync_lock_test_and_set(a, v); 225#elif defined(__SOLARIS__) 226 return atomic_swap_ptr(a, v); 227#else 228 void *value; 229 do { 230 value = *a; 231 } while (!SDL_AtomicCASPtr(a, value, v)); 232 return value; 233#endif 234} 235 236int 237SDL_AtomicAdd(SDL_atomic_t *a, int v) 238{ 239#ifdef HAVE_MSC_ATOMICS 240 return _InterlockedExchangeAdd((long*)&a->value, v); 241#elif defined(HAVE_WATCOM_ATOMICS) 242 return _SDL_xadd_watcom(&a->value, v); 243#elif defined(HAVE_GCC_ATOMICS) 244 return __sync_fetch_and_add(&a->value, v); 245#elif defined(__SOLARIS__) 246 int pv = a->value; 247 membar_consumer(); 248#if defined(_LP64) 249 atomic_add_64((volatile uint64_t*)&a->value, v); 250#elif !defined(_LP64) 251 atomic_add_32((volatile uint32_t*)&a->value, v); 252#endif 253 return pv; 254#else 255 int value; 256 do { 257 value = a->value; 258 } while (!SDL_AtomicCAS(a, value, (value + v))); 259 return value; 260#endif 261} 262 263int 264SDL_AtomicGet(SDL_atomic_t *a) 265{ 266#ifdef HAVE_ATOMIC_LOAD_N 267 return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST); 268#else 269 int value; 270 do { 271 value = a->value; 272 } while (!SDL_AtomicCAS(a, value, value)); 273 return value; 274#endif 275} 276 277void * 278SDL_AtomicGetPtr(void **a) 279{ 280#ifdef HAVE_ATOMIC_LOAD_N 281 return __atomic_load_n(a, __ATOMIC_SEQ_CST); 282#else 283 void *value; 284 do { 285 value = *a; 286 } while (!SDL_AtomicCASPtr(a, value, value)); 287 return value; 288#endif 289} 290 291void 292SDL_MemoryBarrierReleaseFunction(void) 293{ 294 SDL_MemoryBarrierRelease(); 295} 296 297void 298SDL_MemoryBarrierAcquireFunction(void) 299{ 300 SDL_MemoryBarrierAcquire(); 301} 302 303/* vi: set ts=4 sw=4 expandtab: */ 304[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.