|
1
|
1 /*
|
|
|
2 Simple DirectMedia Layer
|
|
|
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
|
|
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 * # CategoryAtomic
|
|
|
24 *
|
|
|
25 * Atomic operations.
|
|
|
26 *
|
|
|
27 * IMPORTANT: If you are not an expert in concurrent lockless programming, you
|
|
|
28 * should not be using any functions in this file. You should be protecting
|
|
|
29 * your data structures with full mutexes instead.
|
|
|
30 *
|
|
|
31 * ***Seriously, here be dragons!***
|
|
|
32 *
|
|
|
33 * You can find out a little more about lockless programming and the subtle
|
|
|
34 * issues that can arise here:
|
|
|
35 * https://learn.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming
|
|
|
36 *
|
|
|
37 * There's also lots of good information here:
|
|
|
38 *
|
|
|
39 * - https://www.1024cores.net/home/lock-free-algorithms
|
|
|
40 * - https://preshing.com/
|
|
|
41 *
|
|
|
42 * These operations may or may not actually be implemented using processor
|
|
|
43 * specific atomic operations. When possible they are implemented as true
|
|
|
44 * processor specific atomic operations. When that is not possible the are
|
|
|
45 * implemented using locks that *do* use the available atomic operations.
|
|
|
46 *
|
|
|
47 * All of the atomic operations that modify memory are full memory barriers.
|
|
|
48 */
|
|
|
49
|
|
|
50 #ifndef SDL_atomic_h_
|
|
|
51 #define SDL_atomic_h_
|
|
|
52
|
|
|
53 #include <SDL3/SDL_stdinc.h>
|
|
|
54 #include <SDL3/SDL_platform_defines.h>
|
|
|
55
|
|
|
56 #include <SDL3/SDL_begin_code.h>
|
|
|
57
|
|
|
58 /* Set up for C function definitions, even when using C++ */
|
|
|
59 #ifdef __cplusplus
|
|
|
60 extern "C" {
|
|
|
61 #endif
|
|
|
62
|
|
|
63 /**
|
|
|
64 * An atomic spinlock.
|
|
|
65 *
|
|
|
66 * The atomic locks are efficient spinlocks using CPU instructions, but are
|
|
|
67 * vulnerable to starvation and can spin forever if a thread holding a lock
|
|
|
68 * has been terminated. For this reason you should minimize the code executed
|
|
|
69 * inside an atomic lock and never do expensive things like API or system
|
|
|
70 * calls while holding them.
|
|
|
71 *
|
|
|
72 * They are also vulnerable to starvation if the thread holding the lock is
|
|
|
73 * lower priority than other threads and doesn't get scheduled. In general you
|
|
|
74 * should use mutexes instead, since they have better performance and
|
|
|
75 * contention behavior.
|
|
|
76 *
|
|
|
77 * The atomic locks are not safe to lock recursively.
|
|
|
78 *
|
|
|
79 * Porting Note: The spin lock functions and type are required and can not be
|
|
|
80 * emulated because they are used in the atomic emulation code.
|
|
|
81 */
|
|
|
82 typedef int SDL_SpinLock;
|
|
|
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 * \param lock a pointer to a lock variable.
|
|
|
91 * \returns true if the lock succeeded, false if the lock is already held.
|
|
|
92 *
|
|
|
93 * \threadsafety It is safe to call this function from any thread.
|
|
|
94 *
|
|
|
95 * \since This function is available since SDL 3.2.0.
|
|
|
96 *
|
|
|
97 * \sa SDL_LockSpinlock
|
|
|
98 * \sa SDL_UnlockSpinlock
|
|
|
99 */
|
|
|
100 extern SDL_DECLSPEC bool SDLCALL SDL_TryLockSpinlock(SDL_SpinLock *lock);
|
|
|
101
|
|
|
102 /**
|
|
|
103 * Lock a spin lock by setting it to a non-zero value.
|
|
|
104 *
|
|
|
105 * ***Please note that spinlocks are dangerous if you don't know what you're
|
|
|
106 * doing. Please be careful using any sort of spinlock!***
|
|
|
107 *
|
|
|
108 * \param lock a pointer to a lock variable.
|
|
|
109 *
|
|
|
110 * \threadsafety It is safe to call this function from any thread.
|
|
|
111 *
|
|
|
112 * \since This function is available since SDL 3.2.0.
|
|
|
113 *
|
|
|
114 * \sa SDL_TryLockSpinlock
|
|
|
115 * \sa SDL_UnlockSpinlock
|
|
|
116 */
|
|
|
117 extern SDL_DECLSPEC void SDLCALL SDL_LockSpinlock(SDL_SpinLock *lock);
|
|
|
118
|
|
|
119 /**
|
|
|
120 * Unlock a spin lock by setting it to 0.
|
|
|
121 *
|
|
|
122 * Always returns immediately.
|
|
|
123 *
|
|
|
124 * ***Please note that spinlocks are dangerous if you don't know what you're
|
|
|
125 * doing. Please be careful using any sort of spinlock!***
|
|
|
126 *
|
|
|
127 * \param lock a pointer to a lock variable.
|
|
|
128 *
|
|
|
129 * \threadsafety It is safe to call this function from any thread.
|
|
|
130 *
|
|
|
131 * \since This function is available since SDL 3.2.0.
|
|
|
132 *
|
|
|
133 * \sa SDL_LockSpinlock
|
|
|
134 * \sa SDL_TryLockSpinlock
|
|
|
135 */
|
|
|
136 extern SDL_DECLSPEC void SDLCALL SDL_UnlockSpinlock(SDL_SpinLock *lock);
|
|
|
137
|
|
|
138
|
|
|
139 #ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
|
|
140
|
|
|
141 /**
|
|
|
142 * Mark a compiler barrier.
|
|
|
143 *
|
|
|
144 * A compiler barrier prevents the compiler from reordering reads and writes
|
|
|
145 * to globally visible variables across the call.
|
|
|
146 *
|
|
|
147 * This macro only prevents the compiler from reordering reads and writes, it
|
|
|
148 * does not prevent the CPU from reordering reads and writes. However, all of
|
|
|
149 * the atomic operations that modify memory are full memory barriers.
|
|
|
150 *
|
|
|
151 * \threadsafety Obviously this macro is safe to use from any thread at any
|
|
|
152 * time, but if you find yourself needing this, you are probably
|
|
|
153 * dealing with some very sensitive code; be careful!
|
|
|
154 *
|
|
|
155 * \since This macro is available since SDL 3.2.0.
|
|
|
156 */
|
|
|
157 #define SDL_CompilerBarrier() DoCompilerSpecificReadWriteBarrier()
|
|
|
158
|
|
|
159 #elif defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__)
|
|
|
160 void _ReadWriteBarrier(void);
|
|
|
161 #pragma intrinsic(_ReadWriteBarrier)
|
|
|
162 #define SDL_CompilerBarrier() _ReadWriteBarrier()
|
|
|
163 #elif (defined(__GNUC__) && !defined(SDL_PLATFORM_EMSCRIPTEN)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
|
|
164 /* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */
|
|
|
165 #define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
|
|
|
166 #elif defined(__WATCOMC__)
|
|
|
167 extern __inline void SDL_CompilerBarrier(void);
|
|
|
168 #pragma aux SDL_CompilerBarrier = "" parm [] modify exact [];
|
|
|
169 #else
|
|
|
170 #define SDL_CompilerBarrier() \
|
|
|
171 { SDL_SpinLock _tmp = 0; SDL_LockSpinlock(&_tmp); SDL_UnlockSpinlock(&_tmp); }
|
|
|
172 #endif
|
|
|
173
|
|
|
174 /**
|
|
|
175 * Insert a memory release barrier (function version).
|
|
|
176 *
|
|
|
177 * Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
|
|
178 * version, which might be useful if you need to use this functionality from a
|
|
|
179 * scripting language, etc. Also, some of the macro versions call this
|
|
|
180 * function behind the scenes, where more heavy lifting can happen inside of
|
|
|
181 * SDL. Generally, though, an app written in C/C++/etc should use the macro
|
|
|
182 * version, as it will be more efficient.
|
|
|
183 *
|
|
|
184 * \threadsafety Obviously this function is safe to use from any thread at any
|
|
|
185 * time, but if you find yourself needing this, you are probably
|
|
|
186 * dealing with some very sensitive code; be careful!
|
|
|
187 *
|
|
|
188 * \since This function is available since SDL 3.2.0.
|
|
|
189 *
|
|
|
190 * \sa SDL_MemoryBarrierRelease
|
|
|
191 */
|
|
|
192 extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierReleaseFunction(void);
|
|
|
193
|
|
|
194 /**
|
|
|
195 * Insert a memory acquire barrier (function version).
|
|
|
196 *
|
|
|
197 * Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
|
|
198 * version, which might be useful if you need to use this functionality from a
|
|
|
199 * scripting language, etc. Also, some of the macro versions call this
|
|
|
200 * function behind the scenes, where more heavy lifting can happen inside of
|
|
|
201 * SDL. Generally, though, an app written in C/C++/etc should use the macro
|
|
|
202 * version, as it will be more efficient.
|
|
|
203 *
|
|
|
204 * \threadsafety Obviously this function is safe to use from any thread at any
|
|
|
205 * time, but if you find yourself needing this, you are probably
|
|
|
206 * dealing with some very sensitive code; be careful!
|
|
|
207 *
|
|
|
208 * \since This function is available since SDL 3.2.0.
|
|
|
209 *
|
|
|
210 * \sa SDL_MemoryBarrierAcquire
|
|
|
211 */
|
|
|
212 extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
|
|
|
213
|
|
|
214
|
|
|
215 #ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
|
|
216
|
|
|
217 /**
|
|
|
218 * Insert a memory release barrier (macro version).
|
|
|
219 *
|
|
|
220 * Memory barriers are designed to prevent reads and writes from being
|
|
|
221 * reordered by the compiler and being seen out of order on multi-core CPUs.
|
|
|
222 *
|
|
|
223 * A typical pattern would be for thread A to write some data and a flag, and
|
|
|
224 * for thread B to read the flag and get the data. In this case you would
|
|
|
225 * insert a release barrier between writing the data and the flag,
|
|
|
226 * guaranteeing that the data write completes no later than the flag is
|
|
|
227 * written, and you would insert an acquire barrier between reading the flag
|
|
|
228 * and reading the data, to ensure that all the reads associated with the flag
|
|
|
229 * have completed.
|
|
|
230 *
|
|
|
231 * In this pattern you should always see a release barrier paired with an
|
|
|
232 * acquire barrier and you should gate the data reads/writes with a single
|
|
|
233 * flag variable.
|
|
|
234 *
|
|
|
235 * For more information on these semantics, take a look at the blog post:
|
|
|
236 * http://preshing.com/20120913/acquire-and-release-semantics
|
|
|
237 *
|
|
|
238 * This is the macro version of this functionality; if possible, SDL will use
|
|
|
239 * compiler intrinsics or inline assembly, but some platforms might need to
|
|
|
240 * call the function version of this, SDL_MemoryBarrierReleaseFunction to do
|
|
|
241 * the heavy lifting. Apps that can use the macro should favor it over the
|
|
|
242 * function.
|
|
|
243 *
|
|
|
244 * \threadsafety Obviously this macro is safe to use from any thread at any
|
|
|
245 * time, but if you find yourself needing this, you are probably
|
|
|
246 * dealing with some very sensitive code; be careful!
|
|
|
247 *
|
|
|
248 * \since This macro is available since SDL 3.2.0.
|
|
|
249 *
|
|
|
250 * \sa SDL_MemoryBarrierAcquire
|
|
|
251 * \sa SDL_MemoryBarrierReleaseFunction
|
|
|
252 */
|
|
|
253 #define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
|
|
254
|
|
|
255 /**
|
|
|
256 * Insert a memory acquire barrier (macro version).
|
|
|
257 *
|
|
|
258 * Please see SDL_MemoryBarrierRelease for the details on what memory barriers
|
|
|
259 * are and when to use them.
|
|
|
260 *
|
|
|
261 * This is the macro version of this functionality; if possible, SDL will use
|
|
|
262 * compiler intrinsics or inline assembly, but some platforms might need to
|
|
|
263 * call the function version of this, SDL_MemoryBarrierAcquireFunction, to do
|
|
|
264 * the heavy lifting. Apps that can use the macro should favor it over the
|
|
|
265 * function.
|
|
|
266 *
|
|
|
267 * \threadsafety Obviously this macro is safe to use from any thread at any
|
|
|
268 * time, but if you find yourself needing this, you are probably
|
|
|
269 * dealing with some very sensitive code; be careful!
|
|
|
270 *
|
|
|
271 * \since This macro is available since SDL 3.2.0.
|
|
|
272 *
|
|
|
273 * \sa SDL_MemoryBarrierRelease
|
|
|
274 * \sa SDL_MemoryBarrierAcquireFunction
|
|
|
275 */
|
|
|
276 #define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
|
|
277
|
|
|
278 #elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
|
|
|
279 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
|
|
|
280 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
|
|
|
281 #elif defined(__GNUC__) && defined(__aarch64__)
|
|
|
282 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
|
|
283 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
|
|
284 #elif defined(__GNUC__) && defined(__arm__)
|
|
|
285 #if 0 /* defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) */
|
|
|
286 /* Information from:
|
|
|
287 https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
|
|
|
288
|
|
|
289 The Linux kernel provides a helper function which provides the right code for a memory barrier,
|
|
|
290 hard-coded at address 0xffff0fa0
|
|
|
291 */
|
|
|
292 typedef void (*SDL_KernelMemoryBarrierFunc)();
|
|
|
293 #define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
|
|
294 #define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
|
|
295 #else
|
|
|
296 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
|
|
|
297 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
|
|
298 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
|
|
299 #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
|
|
|
300 #ifdef __thumb__
|
|
|
301 /* The mcr instruction isn't available in thumb mode, use real functions */
|
|
|
302 #define SDL_MEMORY_BARRIER_USES_FUNCTION
|
|
|
303 #define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
|
|
304 #define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
|
|
305 #else
|
|
|
306 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
|
|
307 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
|
|
308 #endif /* __thumb__ */
|
|
|
309 #else
|
|
|
310 #define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
|
|
|
311 #define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
|
|
|
312 #endif /* SDL_PLATFORM_LINUX || SDL_PLATFORM_ANDROID */
|
|
|
313 #endif /* __GNUC__ && __arm__ */
|
|
|
314 #else
|
|
|
315 #if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
|
|
316 /* This is correct for all CPUs on Solaris when using Solaris Studio 12.1+. */
|
|
|
317 #include <mbarrier.h>
|
|
|
318 #define SDL_MemoryBarrierRelease() __machine_rel_barrier()
|
|
|
319 #define SDL_MemoryBarrierAcquire() __machine_acq_barrier()
|
|
|
320 #else
|
|
|
321 /* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
|
|
|
322 #define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
|
|
|
323 #define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
|
|
|
324 #endif
|
|
|
325 #endif
|
|
|
326
|
|
|
327 /* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
|
|
|
328 #ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
|
|
329
|
|
|
330 /**
|
|
|
331 * A macro to insert a CPU-specific "pause" instruction into the program.
|
|
|
332 *
|
|
|
333 * This can be useful in busy-wait loops, as it serves as a hint to the CPU as
|
|
|
334 * to the program's intent; some CPUs can use this to do more efficient
|
|
|
335 * processing. On some platforms, this doesn't do anything, so using this
|
|
|
336 * macro might just be a harmless no-op.
|
|
|
337 *
|
|
|
338 * Note that if you are busy-waiting, there are often more-efficient
|
|
|
339 * approaches with other synchronization primitives: mutexes, semaphores,
|
|
|
340 * condition variables, etc.
|
|
|
341 *
|
|
|
342 * \threadsafety This macro is safe to use from any thread.
|
|
|
343 *
|
|
|
344 * \since This macro is available since SDL 3.2.0.
|
|
|
345 */
|
|
|
346 #define SDL_CPUPauseInstruction() DoACPUPauseInACompilerAndArchitectureSpecificWay
|
|
|
347
|
|
|
348 #elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
|
|
349 #define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
|
|
|
350 #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
|
|
351 #define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
|
|
|
352 #elif (defined(__powerpc__) || defined(__powerpc64__))
|
|
|
353 #define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
|
|
|
354 #elif (defined(__riscv) && __riscv_xlen == 64)
|
|
|
355 #define SDL_CPUPauseInstruction() __asm__ __volatile__(".insn i 0x0F, 0, x0, x0, 0x010");
|
|
|
356 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
|
357 #define SDL_CPUPauseInstruction() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
|
|
|
358 #elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
|
|
359 #define SDL_CPUPauseInstruction() __yield()
|
|
|
360 #elif defined(__WATCOMC__) && defined(__386__)
|
|
|
361 extern __inline void SDL_CPUPauseInstruction(void);
|
|
|
362 #pragma aux SDL_CPUPauseInstruction = ".686p" ".xmm2" "pause"
|
|
|
363 #else
|
|
|
364 #define SDL_CPUPauseInstruction()
|
|
|
365 #endif
|
|
|
366
|
|
|
367
|
|
|
368 /**
|
|
|
369 * A type representing an atomic integer value.
|
|
|
370 *
|
|
|
371 * This can be used to manage a value that is synchronized across multiple
|
|
|
372 * CPUs without a race condition; when an app sets a value with
|
|
|
373 * SDL_SetAtomicInt all other threads, regardless of the CPU it is running on,
|
|
|
374 * will see that value when retrieved with SDL_GetAtomicInt, regardless of CPU
|
|
|
375 * caches, etc.
|
|
|
376 *
|
|
|
377 * This is also useful for atomic compare-and-swap operations: a thread can
|
|
|
378 * change the value as long as its current value matches expectations. When
|
|
|
379 * done in a loop, one can guarantee data consistency across threads without a
|
|
|
380 * lock (but the usual warnings apply: if you don't know what you're doing, or
|
|
|
381 * you don't do it carefully, you can confidently cause any number of
|
|
|
382 * disasters with this, so in most cases, you _should_ use a mutex instead of
|
|
|
383 * this!).
|
|
|
384 *
|
|
|
385 * This is a struct so people don't accidentally use numeric operations on it
|
|
|
386 * directly. You have to use SDL atomic functions.
|
|
|
387 *
|
|
|
388 * \since This struct is available since SDL 3.2.0.
|
|
|
389 *
|
|
|
390 * \sa SDL_CompareAndSwapAtomicInt
|
|
|
391 * \sa SDL_GetAtomicInt
|
|
|
392 * \sa SDL_SetAtomicInt
|
|
|
393 * \sa SDL_AddAtomicInt
|
|
|
394 */
|
|
|
395 typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt;
|
|
|
396
|
|
|
397 /**
|
|
|
398 * Set an atomic variable to a new value if it is currently an old value.
|
|
|
399 *
|
|
|
400 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
401 * it!***
|
|
|
402 *
|
|
|
403 * \param a a pointer to an SDL_AtomicInt variable to be modified.
|
|
|
404 * \param oldval the old value.
|
|
|
405 * \param newval the new value.
|
|
|
406 * \returns true if the atomic variable was set, false otherwise.
|
|
|
407 *
|
|
|
408 * \threadsafety It is safe to call this function from any thread.
|
|
|
409 *
|
|
|
410 * \since This function is available since SDL 3.2.0.
|
|
|
411 *
|
|
|
412 * \sa SDL_GetAtomicInt
|
|
|
413 * \sa SDL_SetAtomicInt
|
|
|
414 */
|
|
|
415 extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval);
|
|
|
416
|
|
|
417 /**
|
|
|
418 * Set an atomic variable to a value.
|
|
|
419 *
|
|
|
420 * This function also acts as a full memory barrier.
|
|
|
421 *
|
|
|
422 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
423 * it!***
|
|
|
424 *
|
|
|
425 * \param a a pointer to an SDL_AtomicInt variable to be modified.
|
|
|
426 * \param v the desired value.
|
|
|
427 * \returns the previous value of the atomic variable.
|
|
|
428 *
|
|
|
429 * \threadsafety It is safe to call this function from any thread.
|
|
|
430 *
|
|
|
431 * \since This function is available since SDL 3.2.0.
|
|
|
432 *
|
|
|
433 * \sa SDL_GetAtomicInt
|
|
|
434 */
|
|
|
435 extern SDL_DECLSPEC int SDLCALL SDL_SetAtomicInt(SDL_AtomicInt *a, int v);
|
|
|
436
|
|
|
437 /**
|
|
|
438 * Get the value of an atomic variable.
|
|
|
439 *
|
|
|
440 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
441 * it!***
|
|
|
442 *
|
|
|
443 * \param a a pointer to an SDL_AtomicInt variable.
|
|
|
444 * \returns the current value of an atomic variable.
|
|
|
445 *
|
|
|
446 * \threadsafety It is safe to call this function from any thread.
|
|
|
447 *
|
|
|
448 * \since This function is available since SDL 3.2.0.
|
|
|
449 *
|
|
|
450 * \sa SDL_SetAtomicInt
|
|
|
451 */
|
|
|
452 extern SDL_DECLSPEC int SDLCALL SDL_GetAtomicInt(SDL_AtomicInt *a);
|
|
|
453
|
|
|
454 /**
|
|
|
455 * Add to an atomic variable.
|
|
|
456 *
|
|
|
457 * This function also acts as a full memory barrier.
|
|
|
458 *
|
|
|
459 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
460 * it!***
|
|
|
461 *
|
|
|
462 * \param a a pointer to an SDL_AtomicInt variable to be modified.
|
|
|
463 * \param v the desired value to add.
|
|
|
464 * \returns the previous value of the atomic variable.
|
|
|
465 *
|
|
|
466 * \threadsafety It is safe to call this function from any thread.
|
|
|
467 *
|
|
|
468 * \since This function is available since SDL 3.2.0.
|
|
|
469 *
|
|
|
470 * \sa SDL_AtomicDecRef
|
|
|
471 * \sa SDL_AtomicIncRef
|
|
|
472 */
|
|
|
473 extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v);
|
|
|
474
|
|
|
475 #ifndef SDL_AtomicIncRef
|
|
|
476
|
|
|
477 /**
|
|
|
478 * Increment an atomic variable used as a reference count.
|
|
|
479 *
|
|
|
480 * ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
|
|
481 *
|
|
|
482 * \param a a pointer to an SDL_AtomicInt to increment.
|
|
|
483 * \returns the previous value of the atomic variable.
|
|
|
484 *
|
|
|
485 * \threadsafety It is safe to call this macro from any thread.
|
|
|
486 *
|
|
|
487 * \since This macro is available since SDL 3.2.0.
|
|
|
488 *
|
|
|
489 * \sa SDL_AtomicDecRef
|
|
|
490 */
|
|
|
491 #define SDL_AtomicIncRef(a) SDL_AddAtomicInt(a, 1)
|
|
|
492 #endif
|
|
|
493
|
|
|
494 #ifndef SDL_AtomicDecRef
|
|
|
495
|
|
|
496 /**
|
|
|
497 * Decrement an atomic variable used as a reference count.
|
|
|
498 *
|
|
|
499 * ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
|
|
500 *
|
|
|
501 * \param a a pointer to an SDL_AtomicInt to decrement.
|
|
|
502 * \returns true if the variable reached zero after decrementing, false
|
|
|
503 * otherwise.
|
|
|
504 *
|
|
|
505 * \threadsafety It is safe to call this macro from any thread.
|
|
|
506 *
|
|
|
507 * \since This macro is available since SDL 3.2.0.
|
|
|
508 *
|
|
|
509 * \sa SDL_AtomicIncRef
|
|
|
510 */
|
|
|
511 #define SDL_AtomicDecRef(a) (SDL_AddAtomicInt(a, -1) == 1)
|
|
|
512 #endif
|
|
|
513
|
|
|
514 /**
|
|
|
515 * A type representing an atomic unsigned 32-bit value.
|
|
|
516 *
|
|
|
517 * This can be used to manage a value that is synchronized across multiple
|
|
|
518 * CPUs without a race condition; when an app sets a value with
|
|
|
519 * SDL_SetAtomicU32 all other threads, regardless of the CPU it is running on,
|
|
|
520 * will see that value when retrieved with SDL_GetAtomicU32, regardless of CPU
|
|
|
521 * caches, etc.
|
|
|
522 *
|
|
|
523 * This is also useful for atomic compare-and-swap operations: a thread can
|
|
|
524 * change the value as long as its current value matches expectations. When
|
|
|
525 * done in a loop, one can guarantee data consistency across threads without a
|
|
|
526 * lock (but the usual warnings apply: if you don't know what you're doing, or
|
|
|
527 * you don't do it carefully, you can confidently cause any number of
|
|
|
528 * disasters with this, so in most cases, you _should_ use a mutex instead of
|
|
|
529 * this!).
|
|
|
530 *
|
|
|
531 * This is a struct so people don't accidentally use numeric operations on it
|
|
|
532 * directly. You have to use SDL atomic functions.
|
|
|
533 *
|
|
|
534 * \since This struct is available since SDL 3.2.0.
|
|
|
535 *
|
|
|
536 * \sa SDL_CompareAndSwapAtomicU32
|
|
|
537 * \sa SDL_GetAtomicU32
|
|
|
538 * \sa SDL_SetAtomicU32
|
|
|
539 */
|
|
|
540 typedef struct SDL_AtomicU32 { Uint32 value; } SDL_AtomicU32;
|
|
|
541
|
|
|
542 /**
|
|
|
543 * Set an atomic variable to a new value if it is currently an old value.
|
|
|
544 *
|
|
|
545 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
546 * it!***
|
|
|
547 *
|
|
|
548 * \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
|
|
549 * \param oldval the old value.
|
|
|
550 * \param newval the new value.
|
|
|
551 * \returns true if the atomic variable was set, false otherwise.
|
|
|
552 *
|
|
|
553 * \threadsafety It is safe to call this function from any thread.
|
|
|
554 *
|
|
|
555 * \since This function is available since SDL 3.2.0.
|
|
|
556 *
|
|
|
557 * \sa SDL_GetAtomicU32
|
|
|
558 * \sa SDL_SetAtomicU32
|
|
|
559 */
|
|
|
560 extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval);
|
|
|
561
|
|
|
562 /**
|
|
|
563 * Set an atomic variable to a value.
|
|
|
564 *
|
|
|
565 * This function also acts as a full memory barrier.
|
|
|
566 *
|
|
|
567 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
568 * it!***
|
|
|
569 *
|
|
|
570 * \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
|
|
571 * \param v the desired value.
|
|
|
572 * \returns the previous value of the atomic variable.
|
|
|
573 *
|
|
|
574 * \threadsafety It is safe to call this function from any thread.
|
|
|
575 *
|
|
|
576 * \since This function is available since SDL 3.2.0.
|
|
|
577 *
|
|
|
578 * \sa SDL_GetAtomicU32
|
|
|
579 */
|
|
|
580 extern SDL_DECLSPEC Uint32 SDLCALL SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v);
|
|
|
581
|
|
|
582 /**
|
|
|
583 * Get the value of an atomic variable.
|
|
|
584 *
|
|
|
585 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
586 * it!***
|
|
|
587 *
|
|
|
588 * \param a a pointer to an SDL_AtomicU32 variable.
|
|
|
589 * \returns the current value of an atomic variable.
|
|
|
590 *
|
|
|
591 * \threadsafety It is safe to call this function from any thread.
|
|
|
592 *
|
|
|
593 * \since This function is available since SDL 3.2.0.
|
|
|
594 *
|
|
|
595 * \sa SDL_SetAtomicU32
|
|
|
596 */
|
|
|
597 extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAtomicU32(SDL_AtomicU32 *a);
|
|
|
598
|
|
|
599 /**
|
|
|
600 * Add to an atomic variable.
|
|
|
601 *
|
|
|
602 * This function also acts as a full memory barrier.
|
|
|
603 *
|
|
|
604 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
605 * it!***
|
|
|
606 *
|
|
|
607 * \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
|
|
608 * \param v the desired value to add or subtract.
|
|
|
609 * \returns the previous value of the atomic variable.
|
|
|
610 *
|
|
|
611 * \threadsafety It is safe to call this function from any thread.
|
|
|
612 *
|
|
|
613 * \since This function is available since SDL 3.4.0.
|
|
|
614 */
|
|
|
615 extern SDL_DECLSPEC Uint32 SDLCALL SDL_AddAtomicU32(SDL_AtomicU32 *a, int v);
|
|
|
616
|
|
|
617 /**
|
|
|
618 * Set a pointer to a new value if it is currently an old value.
|
|
|
619 *
|
|
|
620 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
621 * it!***
|
|
|
622 *
|
|
|
623 * \param a a pointer to a pointer.
|
|
|
624 * \param oldval the old pointer value.
|
|
|
625 * \param newval the new pointer value.
|
|
|
626 * \returns true if the pointer was set, false otherwise.
|
|
|
627 *
|
|
|
628 * \threadsafety It is safe to call this function from any thread.
|
|
|
629 *
|
|
|
630 * \since This function is available since SDL 3.2.0.
|
|
|
631 *
|
|
|
632 * \sa SDL_CompareAndSwapAtomicInt
|
|
|
633 * \sa SDL_GetAtomicPointer
|
|
|
634 * \sa SDL_SetAtomicPointer
|
|
|
635 */
|
|
|
636 extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval);
|
|
|
637
|
|
|
638 /**
|
|
|
639 * Set a pointer to a value atomically.
|
|
|
640 *
|
|
|
641 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
642 * it!***
|
|
|
643 *
|
|
|
644 * \param a a pointer to a pointer.
|
|
|
645 * \param v the desired pointer value.
|
|
|
646 * \returns the previous value of the pointer.
|
|
|
647 *
|
|
|
648 * \threadsafety It is safe to call this function from any thread.
|
|
|
649 *
|
|
|
650 * \since This function is available since SDL 3.2.0.
|
|
|
651 *
|
|
|
652 * \sa SDL_CompareAndSwapAtomicPointer
|
|
|
653 * \sa SDL_GetAtomicPointer
|
|
|
654 */
|
|
|
655 extern SDL_DECLSPEC void * SDLCALL SDL_SetAtomicPointer(void **a, void *v);
|
|
|
656
|
|
|
657 /**
|
|
|
658 * Get the value of a pointer atomically.
|
|
|
659 *
|
|
|
660 * ***Note: If you don't know what this function is for, you shouldn't use
|
|
|
661 * it!***
|
|
|
662 *
|
|
|
663 * \param a a pointer to a pointer.
|
|
|
664 * \returns the current value of a pointer.
|
|
|
665 *
|
|
|
666 * \threadsafety It is safe to call this function from any thread.
|
|
|
667 *
|
|
|
668 * \since This function is available since SDL 3.2.0.
|
|
|
669 *
|
|
|
670 * \sa SDL_CompareAndSwapAtomicPointer
|
|
|
671 * \sa SDL_SetAtomicPointer
|
|
|
672 */
|
|
|
673 extern SDL_DECLSPEC void * SDLCALL SDL_GetAtomicPointer(void **a);
|
|
|
674
|
|
|
675 /* Ends C function definitions when using C++ */
|
|
|
676 #ifdef __cplusplus
|
|
|
677 }
|
|
|
678 #endif
|
|
|
679
|
|
|
680 #include <SDL3/SDL_close_code.h>
|
|
|
681
|
|
|
682 #endif /* SDL_atomic_h_ */
|