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);