1 /+ 2 + Copyright 2022 – 2024 Aya Partridge 3 + Copyright 2018 - 2022 Michael D. Parker 4 + Distributed under the Boost Software License, Version 1.0. 5 + (See accompanying file LICENSE_1_0.txt or copy at 6 + http://www.boost.org/LICENSE_1_0.txt) 7 +/ 8 module sdl.atomic; 9 10 import bindbc.sdl.config; 11 import bindbc.sdl.codegen; 12 13 alias SDL_SpinLock = int; 14 15 version(SDL_No_Atomics){ 16 }else{ 17 import sdl.stdinc: SDL_bool; 18 19 20 version(GNU) version = ExtAsm; //GDC 21 version(LDC) version = ExtAsm; 22 23 pragma(inline, true) nothrow @nogc{ 24 void SDL_CompilerBarrier(){ 25 static if((){ 26 version(Emscripten) return false; 27 else version(ExtAsm) return true; 28 else return false; 29 }()){ 30 asm nothrow @nogc{ "" : : : "memory"; } 31 }else version(DigitalMars){ 32 asm nothrow @nogc{} 33 }else{ 34 __gshared SDL_SpinLock _tmp = 0; 35 SDL_AtomicLock(&_tmp); 36 SDL_AtomicUnlock(&_tmp); 37 } 38 39 // #if defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__) 40 // void _ReadWriteBarrier(void); 41 // #pragma intrinsic(_ReadWriteBarrier) 42 // #define SDL_CompilerBarrier() _ReadWriteBarrier() 43 // #elif (defined(__GNUC__) && !defined(__EMSCRIPTEN__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120)) 44 // /* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */ 45 // #define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory") 46 // #elif defined(__WATCOMC__) 47 // extern __inline void SDL_CompilerBarrier(void); 48 // #pragma aux SDL_CompilerBarrier = "" parm [] modify exact []; 49 // #else 50 // #define SDL_CompilerBarrier() \ 51 // { SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); } 52 // #endif 53 } 54 55 void SDL_MemoryBarrierRelease(){ 56 static if((){ 57 version(ExtAsm){ 58 version(PPC) return true; 59 else version(PPC64) return true; 60 else return false; 61 }else return false; 62 }()){ 63 asm nothrow @nogc{ "lwsync" : : : "memory"; } 64 }else static if((){ 65 version(ExtAsm){ 66 version(AArch64) return true; 67 else return false; 68 }else return false; 69 }()){ 70 asm nothrow @nogc{ "dmb ish" : : : "memory"; } 71 }else static if((){ 72 version(ExtAsm){ 73 version(ARM) return true; 74 else return false; 75 }else return false; 76 }()){ 77 asm nothrow @nogc{ "" : : : "memory"; } 78 }else{ 79 SDL_CompilerBarrier(); 80 } 81 } 82 alias SDL_MemoryBarrierAcquire = SDL_MemoryBarrierRelease; 83 84 void SDL_CPUPauseInstruction() pure{ //NOTE: added in 2.24.0 85 version(ExtAsm){ 86 static if((){ 87 version(X86) return true; 88 else version(X86_64) return true; 89 else return false; 90 }()){ 91 asm nothrow @nogc pure{ "rep nop"; } 92 }else static if((){ 93 version(ARM) return true; 94 else version(AArch64) return true; 95 else return false; 96 }()){ 97 asm nothrow @nogc pure{ "yield" : : : "memory"; } 98 }else static if((){ 99 version(PPC) return true; 100 else version(PPC64) return true; 101 else return false; 102 }()){ 103 asm nothrow @nogc pure{ "or 27,27,27"; } 104 } 105 } 106 } 107 108 int SDL_AtomicIncRef(SDL_atomic_t* a){ 109 return SDL_AtomicAdd(a, 1); 110 } 111 bool SDL_AtomicDecRef(SDL_atomic_t* a){ 112 return SDL_AtomicAdd(a, -1) == 1; 113 } 114 static if(sdlSupport < SDLSupport.v2_0_3){ 115 int SDL_AtomicSet(SDL_atomic_t* a, int v){ 116 int value; 117 do{ 118 value = a.value; 119 }while(!SDL_AtomicCAS(a, value, v)); 120 return value; 121 } 122 int SDL_AtomicGet(SDL_atomic_t* a){ 123 int value = a.value; 124 SDL_CompilerBarrier(); 125 return value; 126 } 127 int SDL_AtomicAdd(SDL_atomic_t* a, int v){ 128 int value; 129 do{ 130 value = a.value; 131 }while(!SDL_AtomicCAS(a, value, value + v)); 132 return value; 133 } 134 void* SDL_AtomicSetPtr(void** a, void* v){ 135 void* value; 136 do{ 137 value = *a; 138 }while(!SDL_AtomicCASPtr(a, value, v)); 139 return value; 140 } 141 void* SDL_AtomicGetPtr(void** a){ 142 void* value = *a; 143 SDL_CompilerBarrier(); 144 return value; 145 } 146 } 147 } 148 } 149 150 struct SDL_atomic_t{ 151 int value; 152 } 153 154 mixin(joinFnBinds((){ 155 FnBind[] ret = [ 156 {q{SDL_bool}, q{SDL_AtomicTryLock}, q{SDL_SpinLock* lock}}, 157 {q{void}, q{SDL_AtomicLock}, q{SDL_SpinLock* lock}}, 158 {q{void}, q{SDL_AtomicUnlock}, q{SDL_SpinLock* lock}}, 159 {q{SDL_bool}, q{SDL_AtomicCAS}, q{SDL_atomic_t* a, int oldVal, int newVal}}, 160 {q{SDL_bool}, q{SDL_AtomicCASPtr}, q{void** a, void* oldVal, void* newVal}}, 161 ]; 162 if(sdlSupport >= SDLSupport.v2_0_3){ 163 FnBind[] add = [ 164 {q{int}, q{SDL_AtomicSet}, q{SDL_atomic_t* a, int v}}, 165 {q{int}, q{SDL_AtomicGet}, q{SDL_atomic_t* a}}, 166 {q{int}, q{SDL_AtomicAdd}, q{SDL_atomic_t* a, int v}}, 167 {q{void*}, q{SDL_AtomicSetPtr}, q{void** a, void* v}}, 168 {q{void*}, q{SDL_AtomicGetPtr}, q{void** a}}, 169 ]; 170 ret ~= add; 171 } 172 if(sdlSupport >= SDLSupport.v2_0_6){ 173 FnBind[] add = [ 174 {q{void}, q{SDL_MemoryBarrierReleaseFunction}, q{}}, 175 {q{void}, q{SDL_MemoryBarrierAcquireFunction}, q{}}, 176 ]; 177 ret ~= add; 178 } 179 return ret; 180 }()));