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 }