1 2 // Copyright Michael D. Parker 2018. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 module bindbc.sdl.bind.sdlatomic; 8 9 version(SDL_No_Atomics) {} 10 else: 11 12 import bindbc.sdl.config; 13 import bindbc.sdl.bind.sdlstdinc : SDL_bool; 14 15 alias SDL_SpinLock = int; 16 17 struct SDL_atomic_t { 18 int value; 19 } 20 21 /* 22 The best way I can see to implement the barrier macros is to depend on 23 core.atomic.atomicFence. That should be okay even in BetterC mode since 24 it's a template. I've already got a dependency on DRuntime (e.g. core.stdc.config), 25 so I'll import it rather than copy/paste it. I'll change it if it somehow 26 becomes a problem in the future. 27 */ 28 import core.atomic : atomicFence; 29 alias SDL_CompilerBarrier = atomicFence!(); 30 alias SDL_MemoryBarrierRelease = SDL_CompilerBarrier; 31 alias SDL_MemoryBarrierAcquire = SDL_CompilerBarrier; 32 33 static if(staticBinding) { 34 extern(C) @nogc nothrow { 35 SDL_bool SDL_AtomicTryLock(SDL_SpinLock*); 36 void SDL_AtomicLock(SDL_SpinLock*); 37 void SDL_AtomicUnlock(SDL_SpinLock); 38 } 39 } 40 else { 41 extern(C) @nogc nothrow { 42 alias pSDL_AtomicTryLock = SDL_bool function(SDL_SpinLock*); 43 alias pSDL_AtomicLock = void function(SDL_SpinLock*); 44 alias pSDL_AtomicUnlock = void function(SDL_SpinLock); 45 } 46 47 __gshared { 48 pSDL_AtomicTryLock SDL_AtomicTryLock; 49 pSDL_AtomicLock SDL_AtomicLock; 50 pSDL_AtomicUnlock SDL_AtomicUnlock; 51 } 52 } 53 54 // Perhaps the following could be replace with the platform-specific intrinsics for GDC, like 55 // the GCC macros in SDL_atomic.h. I'll have to investigate. 56 static if(staticBinding) { 57 extern(C) @nogc nothrow { 58 SDL_bool SDL_AtomicCAS(SDL_atomic_t*,int,int); 59 SDL_bool SDL_AtomicCASPtr(void**,void*,void*); 60 } 61 } 62 else { 63 extern(C) @nogc nothrow { 64 alias pSDL_AtomicCAS = SDL_bool function(SDL_atomic_t*,int,int); 65 alias pSDL_AtomicCASPtr = SDL_bool function(void**,void*,void*); 66 } 67 68 __gshared { 69 pSDL_AtomicCAS SDL_AtomicCAS; 70 pSDL_AtomicCASPtr SDL_AtomicCASPtr; 71 } 72 } 73 74 int SDL_AtomicSet(SDL_atomic_t* a, int v) { 75 pragma(inline, true) 76 int value; 77 do { 78 value = a.value; 79 } while(!SDL_AtomicCAS(a, value, v)); 80 return value; 81 } 82 83 int SDL_AtomicGet(SDL_atomic_t* a) { 84 pragma(inline, true) 85 int value = a.value; 86 SDL_CompilerBarrier(); 87 return value; 88 } 89 90 int SDL_AtomicAdd(SDL_atomic_t* a, int v) { 91 pragma(inline, true) 92 int value; 93 do { 94 value = a.value; 95 } while(!SDL_AtomicCAS(a, value, value + v)); 96 return value; 97 } 98 99 int SDL_AtomicIncRef(SDL_atomic_t* a) { 100 pragma(inline, true) 101 return SDL_AtomicAdd(a, 1); 102 } 103 104 SDL_bool SDL_AtomicDecRef(SDL_atomic_t* a) { 105 pragma(inline, true) 106 return cast(SDL_bool)(SDL_AtomicAdd(a, -1) == 1); 107 } 108 109 void* SDL_AtomicSetPtr(void** a, void* v) { 110 pragma(inline, true) 111 void* value; 112 do { 113 value = *a; 114 } while(!SDL_AtomicCASPtr(a, value, v)); 115 return value; 116 } 117 118 void* SDL_AtomicGetPtr(void** a) { 119 pragma(inline, true) 120 void* value = *a; 121 SDL_CompilerBarrier(); 122 return value; 123 }