1 2 // Copyright 2018 - 2021 Michael D. Parker 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* lock); 36 void SDL_AtomicLock(SDL_SpinLock* lock); 37 void SDL_AtomicUnlock(SDL_SpinLock* lock); 38 } 39 } 40 else { 41 extern(C) @nogc nothrow { 42 alias pSDL_AtomicTryLock = SDL_bool function(SDL_SpinLock* lock); 43 alias pSDL_AtomicLock = void function(SDL_SpinLock* lock); 44 alias pSDL_AtomicUnlock = void function(SDL_SpinLock* lock); 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 replaced 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* a, int oldval, int newval); 59 SDL_bool SDL_AtomicCASPtr(void** a, void* oldval, void* newval); 60 } 61 } 62 else { 63 extern(C) @nogc nothrow { 64 alias pSDL_AtomicCAS = SDL_bool function(SDL_atomic_t* a, int oldval, int newval); 65 alias pSDL_AtomicCASPtr = SDL_bool function(void** a, void* oldval, void* newval); 66 } 67 68 __gshared { 69 pSDL_AtomicCAS SDL_AtomicCAS; 70 pSDL_AtomicCASPtr SDL_AtomicCASPtr; 71 } 72 } 73 74 static if(sdlSupport >= SDLSupport.sdl203) { 75 static if(staticBinding) { 76 extern(C) @nogc nothrow { 77 int SDL_AtomicSet(SDL_atomic_t* a, int v); 78 int SDL_AtomicGet(SDL_atomic_t* a); 79 int SDL_AtomicAdd(SDL_atomic_t* a, int v); 80 void* SDL_AtomicSetPtr(void** a, void* v); 81 void* SDL_AtomicGetPtr(void** a); 82 } 83 } 84 else { 85 extern(C) @nogc nothrow { 86 alias pSDL_AtomicSet = int function(SDL_atomic_t* a, int v); 87 alias pSDL_AtomicGet = int function(SDL_atomic_t* a); 88 alias pSDL_AtomicAdd = int function(SDL_atomic_t* a, int v); 89 alias pSDL_AtomicSetPtr = void* function(void** a, void* v); 90 alias pSDL_AtomicGetPtr = void* function(void** a); 91 } 92 93 __gshared { 94 pSDL_AtomicSet SDL_AtomicSet; 95 pSDL_AtomicGet SDL_AtomicGet; 96 pSDL_AtomicAdd SDL_AtomicAdd; 97 pSDL_AtomicSetPtr SDL_AtomicSetPtr; 98 pSDL_AtomicGetPtr SDL_AtomicGetPtr; 99 } 100 } 101 } 102 else { 103 int SDL_AtomicSet(SDL_atomic_t* a, int v) { 104 pragma(inline, true) 105 int value; 106 do { 107 value = a.value; 108 } while(!SDL_AtomicCAS(a, value, v)); 109 return value; 110 } 111 112 int SDL_AtomicGet(SDL_atomic_t* a) { 113 pragma(inline, true) 114 int value = a.value; 115 SDL_CompilerBarrier(); 116 return value; 117 } 118 119 int SDL_AtomicAdd(SDL_atomic_t* a, int v) { 120 pragma(inline, true) 121 int value; 122 do { 123 value = a.value; 124 } while(!SDL_AtomicCAS(a, value, value + v)); 125 return value; 126 } 127 128 void* SDL_AtomicSetPtr(void** a, void* v) { 129 pragma(inline, true) 130 void* value; 131 do { 132 value = *a; 133 } while(!SDL_AtomicCASPtr(a, value, v)); 134 return value; 135 } 136 137 void* SDL_AtomicGetPtr(void** a) { 138 pragma(inline, true) 139 void* value = *a; 140 SDL_CompilerBarrier(); 141 return value; 142 } 143 } 144 145 int SDL_AtomicIncRef(SDL_atomic_t* a) { 146 pragma(inline, true) 147 return SDL_AtomicAdd(a, 1); 148 } 149 150 SDL_bool SDL_AtomicDecRef(SDL_atomic_t* a) { 151 pragma(inline, true) 152 return cast(SDL_bool)(SDL_AtomicAdd(a, -1) == 1); 153 }