SDL_atomic.h: Documentation updates.

This commit is contained in:
Ryan C. Gordon 2024-04-24 16:42:16 -04:00
parent ec97857a87
commit cdb3cea76d
No known key found for this signature in database
GPG key ID: FA148B892AB48044

View file

@ -26,15 +26,8 @@
* *
* IMPORTANT: * IMPORTANT:
* If you are not an expert in concurrent lockless programming, you should * If you are not an expert in concurrent lockless programming, you should
* only be using the atomic lock and reference counting functions in this * not be using any functions in this file. You should be protecting your
* file. In all other cases you should be protecting your data structures * data structures with full mutexes instead.
* with full mutexes.
*
* The list of "safe" functions to use are:
* SDL_LockSpinlock()
* SDL_UnlockSpinlock()
* SDL_AtomicIncRef()
* SDL_AtomicDecRef()
* *
* Seriously, here be dragons! * Seriously, here be dragons!
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -70,7 +63,7 @@ extern "C" {
#endif #endif
/** /**
* \name SDL AtomicLock * An atomic spinlock.
* *
* The atomic locks are efficient spinlocks using CPU instructions, * The atomic locks are efficient spinlocks using CPU instructions,
* but are vulnerable to starvation and can spin forever if a thread * but are vulnerable to starvation and can spin forever if a thread
@ -89,8 +82,6 @@ extern "C" {
* The spin lock functions and type are required and can not be * The spin lock functions and type are required and can not be
* emulated because they are used in the atomic emulation code. * emulated because they are used in the atomic emulation code.
*/ */
/* @{ */
typedef int SDL_SpinLock; typedef int SDL_SpinLock;
/** /**
@ -142,8 +133,6 @@ extern DECLSPEC void SDLCALL SDL_LockSpinlock(SDL_SpinLock *lock);
*/ */
extern DECLSPEC void SDLCALL SDL_UnlockSpinlock(SDL_SpinLock *lock); extern DECLSPEC void SDLCALL SDL_UnlockSpinlock(SDL_SpinLock *lock);
/* @} *//* SDL AtomicLock */
#ifdef SDL_WIKI_DOCUMENTATION_SECTION #ifdef SDL_WIKI_DOCUMENTATION_SECTION
@ -274,8 +263,25 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
#endif #endif
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */ /* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
/* !!! FIXME: this should have documentation! */ #ifdef SDL_WIKI_DOCUMENTATION_SECTION
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) /**
* A macro to insert a CPU-specific "pause" instruction into the program.
*
* This can be useful in busy-wait loops, as it serves as a hint to the CPU
* as to the program's intent; some CPUs can use this to do more efficient
* processing. On some platforms, this doesn't do anything, so using this
* macro might just be a harmless no-op.
*
* Note that if you are busy-waiting, there are often more-efficient
* approaches with other synchronization primitives: mutexes, semaphores,
* condition variables, etc.
*
* \threadsafety This macro is safe to use from any thread.
*
* \since This macro is available since SDL 3.0.0.
*/
#define SDL_CPUPauseInstruction() DoACPUPauseInACompilerAndArchitectureSpecificWay
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
#define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */ #define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__) #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
#define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory") #define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
@ -298,9 +304,28 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
/** /**
* A type representing an atomic integer value. * A type representing an atomic integer value.
* *
* It is a struct so people don't accidentally use numeric operations on it. * This can be used to manage a value that is synchronized across multiple
* CPUs without a race condition; when an app sets a value with SDL_AtomicSet
* all other threads, regardless of the CPU it is running on, will see that
* value when retrieved with SDL_AtomicGet, regardless of CPU caches, etc.
*
* This is also useful for atomic compare-and-swap operations: a thread
* can change the value as long as its current value matches expectations.
* When done in a loop, one can guarantee data consistency across threads
* without a lock (but the usual warnings apply: if you don't know what
* you're doing, or you don't do it carefully, you can confidently cause
* any number of disasters with this, so in most cases, you _should_
* use a mutex instead of this!).
*
* This is a struct so people don't accidentally use numeric operations on
* it directly. You have to use SDL_Atomic* functions.
* *
* \since This struct is available since SDL 3.0.0. * \since This struct is available since SDL 3.0.0.
*
* \sa SDL_AtomicCompareAndSwap
* \sa SDL_AtomicGet
* \sa SDL_AtomicSet
* \sa SDL_AtomicAdd
*/ */
typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt; typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt;