1 /*
2     DSDL
3     Copyright (C) 2025 Inochi2D Project <luna@foxgirls.gay>
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     ==========================================================================
22 
23     Simple DirectMedia Layer
24     Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
25 
26     This software is provided 'as-is', without any express or implied
27     warranty.  In no event will the authors be held liable for any damages
28     arising from the use of this software.
29 
30     Permission is granted to anyone to use this software for any purpose,
31     including commercial applications, and to alter it and redistribute it
32     freely, subject to the following restrictions:
33 
34     1. The origin of this software must not be misrepresented; you must not
35         claim that you wrote the original software. If you use this software
36         in a product, an acknowledgment in the product documentation would be
37         appreciated but is not required.
38     2. Altered source versions must be plainly marked as such, and must not be
39         misrepresented as being the original software.
40     3. This notice may not be removed or altered from any source distribution.
41 */
42 
43 /**
44     Atomics
45 
46     See_Also:
47         $(LINK2 https://wiki.libsdl.org/SDL3/CategoryAtomic, SDL3 Atomics Documentation)
48     
49     Copyright: © 2025 Inochi2D Project, © 1997-2025 Sam Lantinga
50     License: Subject to the terms of the Zlib License, as written in the LICENSE file.
51     Authors: 
52         Luna Nielsen
53 */
54 module sdl.atomic;
55 import sdl.stdc;
56 
57 extern(C) nothrow @nogc:
58 
59 // TODO: Update Docs
60 
61 /**
62     An atomic spinlock.
63 
64     The atomic locks are efficient spinlocks using CPU instructions, but are
65     vulnerable to starvation and can spin forever if a thread holding a lock
66     has been terminated. For this reason you should minimize the code executed
67     inside an atomic lock and never do expensive things like API or system
68     calls while holding them.
69 
70     They are also vulnerable to starvation if the thread holding the lock is
71     lower priority than other threads and doesn't get scheduled. In general you
72     should use mutexes instead, since they have better performance and
73     contention behavior.
74 
75     The atomic locks are not safe to lock recursively.
76 
77     Note:
78         The spin lock functions and type are required and can not be
79         emulated because they are used in the atomic emulation code.
80 */
81 alias SDL_SpinLock = int;
82 
83 
84 /**
85     Try to lock a spin lock by setting it to a non-zero value.
86 
87     ***Please note that spinlocks are dangerous if you don't know what you're
88     doing. Please be careful using any sort of spinlock!***
89 
90     Params:
91         lock =  a pointer to a lock variable.
92     
93     Returns:
94         $(D true) if the lock succeeded, $(D false) if the lock is already held.
95 
96     See_Also:
97         $(D SDL_LockSpinlock)
98         $(D SDL_UnlockSpinlock)
99 
100     Threadsafety:
101         It is safe to call this function from any thread.
102 
103     History:
104         Available since SDL 3.2.0.
105 */
106 extern bool SDL_TryLockSpinlock(SDL_SpinLock* lock);
107 
108 /**
109     Lock a spin lock by setting it to a non-zero value.
110 
111     ***Please note that spinlocks are dangerous if you don't know what you're
112     doing. Please be careful using any sort of spinlock!***
113 
114     Params:
115         lock =  a pointer to a lock variable.
116 
117     See_Also:
118         $(D SDL_TryLockSpinlock)
119         $(D SDL_UnlockSpinlock)
120 
121     Threadsafety:
122         It is safe to call this function from any thread.
123 
124     History:
125         Available since SDL 3.2.0.
126 */
127 extern void SDL_LockSpinlock(SDL_SpinLock* lock);
128 
129 /**
130     Unlock a spin lock by setting it to 0.
131 
132     Always returns immediately.
133 
134     ***Please note that spinlocks are dangerous if you don't know what you're
135     doing. Please be careful using any sort of spinlock!***
136 
137     Params:
138         lock =  a pointer to a lock variable.
139 
140     See_Also:
141         $(D SDL_LockSpinlock)
142         $(D SDL_TryLockSpinlock)
143 
144     Threadsafety:
145         It is safe to call this function from any thread.
146 
147     History:
148         Available since SDL 3.2.0.
149 */
150 extern void SDL_UnlockSpinlock(SDL_SpinLock* lock);
151 
152 
153 /**
154     Insert a memory release barrier (function version).
155 
156     Please refer to SDL_MemoryBarrierRelease for details. This is a function
157     version, which might be useful if you need to use this functionality from a
158     scripting language, etc. Also, some of the macro versions call this
159     function behind the scenes, where more heavy lifting can happen inside of
160     SDL. Generally, though, an app written in C/C++/etc should use the macro
161     version, as it will be more efficient.
162 
163     See_Also:
164         $(D SDL_MemoryBarrierRelease)
165 
166     Threadsafety:
167         Obviously this function is safe to use from any thread at any
168         time, but if you find yourself needing this, you are probably
169         dealing with some very sensitive code; be careful!
170 
171     History:
172         Available since SDL 3.2.0.
173 */
174 extern void SDL_MemoryBarrierReleaseFunction();
175 
176 /**
177     Insert a memory acquire barrier (function version).
178 
179     Please refer to SDL_MemoryBarrierRelease for details. This is a function
180     version, which might be useful if you need to use this functionality from a
181     scripting language, etc. Also, some of the macro versions call this
182     function behind the scenes, where more heavy lifting can happen inside of
183     SDL. Generally, though, an app written in C/C++/etc should use the macro
184     version, as it will be more efficient.
185 
186     See_Also:
187         $(D SDL_MemoryBarrierAcquire)
188 
189     Threadsafety:
190         Obviously this function is safe to use from any thread at any
191         time, but if you find yourself needing this, you are probably
192         dealing with some very sensitive code; be careful!
193 
194     History:
195         Available since SDL 3.2.0.
196 */
197 extern void SDL_MemoryBarrierAcquireFunction();
198 
199 /**
200     A type representing an atomic integer value.
201 
202     This can be used to manage a value that is synchronized across multiple
203     CPUs without a race condition; when an app sets a value with
204     SDL_SetAtomicInt all other threads, regardless of the CPU it is running on,
205     will see that value when retrieved with SDL_GetAtomicInt, regardless of CPU
206     caches, etc.
207 
208     This is also useful for atomic compare-and-swap operations: a thread can
209     change the value as long as its current value matches expectations. When
210     done in a loop, one can guarantee data consistency across threads without a
211     lock (but the usual warnings apply: if you don't know what you're doing, or
212     you don't do it carefully, you can confidently cause any number of
213     disasters with this, so in most cases, you _should_ use a mutex instead of
214     this!).
215 
216     This is a struct so people don't accidentally use numeric operations on it
217     directly. You have to use SDL atomic functions.
218 
219     See_Also:
220         $(D SDL_CompareAndSwapAtomicInt)
221         $(D SDL_GetAtomicInt)
222         $(D SDL_SetAtomicInt)
223         $(D SDL_AddAtomicInt)
224 
225     History:
226         Available since SDL 3.2.0.
227 */
228 struct SDL_AtomicInt {
229     int value;
230     alias value this;
231 }
232 
233 /**
234     Set an atomic variable to a new value if it is currently an old value.
235 
236     ***Note: If you don't know what this function is for, you shouldn't use
237     it!***
238 
239     Params:
240         a =         a pointer to an SDL_AtomicInt variable to be modified.
241         oldval =    the old value.
242         newval =    the new value.
243     
244     Returns:
245         $(D true) if the atomic variable was set, $(D false) otherwise.
246 
247     See_Also:
248         $(D SDL_GetAtomicInt)
249         $(D SDL_SetAtomicInt)
250 
251     Threadsafety:
252         It is safe to call this function from any thread.
253 
254     History:
255         Available since SDL 3.2.0.
256 */
257 extern bool SDL_CompareAndSwapAtomicInt(SDL_AtomicInt* a, int oldval, int newval);
258 
259 /**
260     Set an atomic variable to a value.
261 
262     This function also acts as a full memory barrier.
263 
264     ***Note: If you don't know what this function is for, you shouldn't use
265     it!***
266 
267     Params:
268         a = a pointer to an SDL_AtomicInt variable to be modified.
269         v = the desired value.
270     
271     Returns:
272         the previous value of the atomic variable.
273 
274     See_Also:
275         $(D SDL_GetAtomicInt)
276 
277     Threadsafety:
278         It is safe to call this function from any thread.
279 
280     History:
281         Available since SDL 3.2.0.
282 */
283 extern int SDL_SetAtomicInt(SDL_AtomicInt* a, int v);
284 
285 /**
286     Get the value of an atomic variable.
287 
288     ***Note: If you don't know what this function is for, you shouldn't use
289     it!***
290 
291     Params:
292         a = a pointer to an SDL_AtomicInt variable.
293     
294     Returns:
295         the current value of an atomic variable.
296 
297     See_Also:
298         $(D SDL_SetAtomicInt)
299 
300     Threadsafety:
301         It is safe to call this function from any thread.
302 
303     History:
304         Available since SDL 3.2.0.
305 */
306 extern int SDL_GetAtomicInt(SDL_AtomicInt* a);
307 
308 /**
309     Add to an atomic variable.
310 
311     This function also acts as a full memory barrier.
312 
313     ***Note: If you don't know what this function is for, you shouldn't use
314     it!***
315 
316     Params:
317         a = a pointer to an SDL_AtomicInt variable to be modified.
318         v = the desired value to add.
319     
320     Returns:
321         the previous value of the atomic variable.
322 
323     See_Also:
324         $(D SDL_AtomicDecRef)
325         $(D SDL_AtomicIncRef)
326 
327     Threadsafety:
328         It is safe to call this function from any thread.
329 
330     History:
331         Available since SDL 3.2.0.
332 */
333 extern int SDL_AddAtomicInt(SDL_AtomicInt* a, int v);
334 
335 
336 /**
337     A type representing an atomic unsigned 32-bit value.
338 
339     This can be used to manage a value that is synchronized across multiple
340     CPUs without a race condition; when an app sets a value with
341     SDL_SetAtomicU32 all other threads, regardless of the CPU it is running on,
342     will see that value when retrieved with SDL_GetAtomicU32, regardless of CPU
343     caches, etc.
344 
345     This is also useful for atomic compare-and-swap operations: a thread can
346     change the value as long as its current value matches expectations. When
347     done in a loop, one can guarantee data consistency across threads without a
348     lock (but the usual warnings apply: if you don't know what you're doing, or
349     you don't do it carefully, you can confidently cause any number of
350     disasters with this, so in most cases, you _should_ use a mutex instead of
351     this!).
352 
353     This is a struct so people don't accidentally use numeric operations on it
354     directly. You have to use SDL atomic functions.
355 
356     See_Also:
357         $(D SDL_CompareAndSwapAtomicU32)
358         $(D SDL_GetAtomicU32)
359         $(D SDL_SetAtomicU32)
360 
361     History:
362         Available since SDL 3.2.0.
363 */
364 struct SDL_AtomicU32 { 
365     Uint32 value;
366     alias value this;
367 }
368 
369 
370 /**
371     Set an atomic variable to a new value if it is currently an old value.
372 
373     ***Note: If you don't know what this function is for, you shouldn't use
374     it!***
375 
376     Params:
377         a =         a pointer to an SDL_AtomicU32 variable to be modified.
378         oldval =    the old value.
379         newval =    the new value.
380     
381     Returns:
382         $(D true) if the atomic variable was set, $(D false) otherwise.
383 
384     See_Also:
385         $(D SDL_GetAtomicU32)
386         $(D SDL_SetAtomicU32)
387 
388     Threadsafety:
389         It is safe to call this function from any thread.
390 
391     History:
392         Available since SDL 3.2.0.
393 */
394 extern bool SDL_CompareAndSwapAtomicU32(SDL_AtomicU32* a, Uint32 oldval, Uint32 newval);
395 
396 /**
397     Set an atomic variable to a value.
398 
399     This function also acts as a full memory barrier.
400 
401     ***Note: If you don't know what this function is for, you shouldn't use
402     it!***
403 
404     Params:
405         a = a pointer to an SDL_AtomicU32 variable to be modified.
406         v = the desired value.
407     
408     Returns:
409         the previous value of the atomic variable.
410 
411     See_Also:
412         $(D SDL_GetAtomicU32)
413 
414     Threadsafety:
415         It is safe to call this function from any thread.
416 
417     History:
418         Available since SDL 3.2.0.
419 */
420 extern Uint32 SDL_SetAtomicU32(SDL_AtomicU32* a, Uint32 v);
421 
422 /**
423     Get the value of an atomic variable.
424 
425     ***Note: If you don't know what this function is for, you shouldn't use
426     it!***
427 
428     Params:
429         a = a pointer to an SDL_AtomicU32 variable.
430     
431     Returns:
432         the current value of an atomic variable.
433 
434     See_Also:
435         $(D SDL_SetAtomicU32)
436 
437     Threadsafety:
438         It is safe to call this function from any thread.
439 
440     History:
441         Available since SDL 3.2.0.
442 */
443 extern Uint32 SDL_GetAtomicU32(SDL_AtomicU32* a);
444 
445 /**
446     Set a pointer to a new value if it is currently an old value.
447 
448     ***Note: If you don't know what this function is for, you shouldn't use
449     it!***
450 
451     Params:
452         a =         a pointer to a pointer.
453         oldval =    the old pointer value.
454         newval =    the new pointer value.
455     
456     Returns:
457         $(D true) if the pointer was set, $(D false) otherwise.
458 
459     See_Also:
460         $(D SDL_CompareAndSwapAtomicInt)
461         $(D SDL_GetAtomicPointer)
462         $(D SDL_SetAtomicPointer)
463 
464     Threadsafety:
465         It is safe to call this function from any thread.
466 
467     History:
468         Available since SDL 3.2.0.
469 */
470 extern bool SDL_CompareAndSwapAtomicPointer(void** a, void* oldval, void* newval);
471 
472 /**
473     Set a pointer to a value atomically.
474 
475     ***Note: If you don't know what this function is for, you shouldn't use
476     it!***
477 
478     Params:
479         a = a pointer to a pointer.
480         v = the desired pointer value.
481     
482     Returns:
483         the previous value of the pointer.
484 
485     See_Also:
486         $(D SDL_CompareAndSwapAtomicPointer)
487         $(D SDL_GetAtomicPointer)
488 
489     Threadsafety:
490         It is safe to call this function from any thread.
491 
492     History:
493         Available since SDL 3.2.0.
494 */
495 extern void* SDL_SetAtomicPointer(void** a, void* v);
496 
497 /**
498     Get the value of a pointer atomically.
499 
500     ***Note: If you don't know what this function is for, you shouldn't use
501     it!***
502 
503     Params:
504         a = a pointer to a pointer.
505     
506     Returns:
507         the current value of a pointer.
508 
509     See_Also:
510         $(D SDL_CompareAndSwapAtomicPointer)
511         $(D SDL_SetAtomicPointer)
512 
513     Threadsafety:
514         It is safe to call this function from any thread.
515 
516     History:
517         Available since SDL 3.2.0.
518 */
519 extern void* SDL_GetAtomicPointer(void** a);