mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-30 16:37:39 +00:00
Added SDL_ShouldInit() and SDL_ShouldQuit()
These are handy functions to support thread-safe initialization and shutdown.
This commit is contained in:
parent
0e2c4e407a
commit
125e592844
7 changed files with 178 additions and 52 deletions
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_thread.h>
|
||||
|
||||
/******************************************************************************/
|
||||
/* Enable thread safety attributes only with clang.
|
||||
|
@ -757,6 +758,140 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitConditionTimeout(SDL_Condition *cond,
|
|||
|
||||
/* @} *//* Condition variable functions */
|
||||
|
||||
/**
|
||||
* \name Thread-safe initialization state functions
|
||||
*/
|
||||
/* @{ */
|
||||
|
||||
/**
|
||||
* The current status of an SDL_InitState structure.
|
||||
*
|
||||
* \since This enum is available since SDL 3.0.0.
|
||||
*/
|
||||
typedef enum SDL_InitStatus
|
||||
{
|
||||
SDL_INIT_STATUS_UNINITIALIZED,
|
||||
SDL_INIT_STATUS_INITIALIZING,
|
||||
SDL_INIT_STATUS_INITIALIZED,
|
||||
SDL_INIT_STATUS_UNINITIALIZING
|
||||
} SDL_InitStatus;
|
||||
|
||||
/**
|
||||
* A structure used for thread-safe initialization and shutdown.
|
||||
*
|
||||
* Here is an example of using this:
|
||||
*
|
||||
* ```c
|
||||
* static SDL_AtomicInitState init;
|
||||
*
|
||||
* bool InitSystem(void)
|
||||
* {
|
||||
* if (!SDL_ShouldInit(&init)) {
|
||||
* // The system is initialized
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* // At this point, you should not leave this function without calling SDL_SetInitialized()
|
||||
*
|
||||
* bool initialized = DoInitTasks();
|
||||
* SDL_SetInitialized(&init, initialized);
|
||||
* return initialized;
|
||||
* }
|
||||
*
|
||||
* bool UseSubsystem(void)
|
||||
* {
|
||||
* if (SDL_ShouldInit(&init)) {
|
||||
* // Error, the subsystem isn't initialized
|
||||
* SDL_SetInitialized(&init, false);
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* // Do work using the initialized subsystem
|
||||
*
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* void QuitSystem(void)
|
||||
* {
|
||||
* if (!SDL_ShouldQuit(&init)) {
|
||||
* // The system is not initialized
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* // At this point, you should not leave this function without calling SDL_SetInitialized()
|
||||
*
|
||||
* DoQuitTasks();
|
||||
* SDL_SetInitialized(&init, false);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Note that this doesn't protect any resources created during initialization, or guarantee that nobody is using those resources during cleanup. You should use other mechanisms to protect those, if that's a concern for your code.
|
||||
*
|
||||
* \since This struct is available since SDL 3.0.0.
|
||||
*/
|
||||
typedef struct SDL_InitState
|
||||
{
|
||||
SDL_AtomicInt status;
|
||||
SDL_ThreadID thread;
|
||||
void *reserved;
|
||||
} SDL_InitState;
|
||||
|
||||
/**
|
||||
* Return whether initialization should be done.
|
||||
*
|
||||
* This function checks the passed in state and if initialization should be done, sets the status to `SDL_INIT_STATUS_INITIALIZING` and returns true. If another thread is already modifying this state, it will wait until that's done before returning.
|
||||
*
|
||||
* If this function returns true, the calling code must call SDL_SetInitialized() to complete the initialization.
|
||||
*
|
||||
* \param state the initialization state to check.
|
||||
* \returns true if initialization needs to be done, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_SetInitialized
|
||||
* \sa SDL_ShouldQuit
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ShouldInit(SDL_InitState *state);
|
||||
|
||||
/**
|
||||
* Return whether cleanup should be done.
|
||||
*
|
||||
* This function checks the passed in state and if cleanup should be done, sets the status to `SDL_INIT_STATUS_UNINITIALIZING` and returns true.
|
||||
*
|
||||
* If this function returns true, the calling code must call SDL_SetInitialized() to complete the cleanup.
|
||||
*
|
||||
* \param state the initialization state to check.
|
||||
* \returns true if cleanup needs to be done, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_SetInitialized
|
||||
* \sa SDL_ShouldInit
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ShouldQuit(SDL_InitState *state);
|
||||
|
||||
/**
|
||||
* Finish an initialization state transition.
|
||||
*
|
||||
* This function sets the status of the passed in state to `SDL_INIT_STATUS_INITIALIZED` or `SDL_INIT_STATUS_UNINITIALIZED` and allows any threads waiting for the status to proceed.
|
||||
*
|
||||
* \param state the initialization state to check.
|
||||
* \param initialized the new initialization state.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_ShouldInit
|
||||
* \sa SDL_ShouldQuit
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetInitialized(SDL_InitState *state, bool initialized);
|
||||
|
||||
/* @} *//* Thread-safe initialization state functions */
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -121,40 +121,6 @@ bool SDL_endswith(const char *string, const char *suffix)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SDL_ShouldInit(SDL_InitState *state)
|
||||
{
|
||||
while (SDL_GetAtomicInt(&state->status) != SDL_INIT_STATUS_INITIALIZED) {
|
||||
if (SDL_CompareAndSwapAtomicInt(&state->status, SDL_INIT_STATUS_UNINITIALIZED, SDL_INIT_STATUS_INITIALIZING)) {
|
||||
state->thread = SDL_GetCurrentThreadID();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wait for the other thread to complete transition
|
||||
SDL_Delay(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDL_ShouldQuit(SDL_InitState *state)
|
||||
{
|
||||
if (SDL_CompareAndSwapAtomicInt(&state->status, SDL_INIT_STATUS_INITIALIZED, SDL_INIT_STATUS_UNINITIALIZING)) {
|
||||
state->thread = SDL_GetCurrentThreadID();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDL_SetInitialized(SDL_InitState *state, bool initialized)
|
||||
{
|
||||
SDL_assert(state->thread == SDL_GetCurrentThreadID());
|
||||
|
||||
if (initialized) {
|
||||
SDL_SetAtomicInt(&state->status, SDL_INIT_STATUS_INITIALIZED);
|
||||
} else {
|
||||
SDL_SetAtomicInt(&state->status, SDL_INIT_STATUS_UNINITIALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_COMPILE_TIME_ASSERT(sizeof_object_id, sizeof(int) == sizeof(Uint32));
|
||||
|
||||
Uint32 SDL_GetNextObjectID(void)
|
||||
|
|
|
@ -47,24 +47,6 @@ extern bool SDL_endswith(const char *string, const char *suffix);
|
|||
*/
|
||||
extern int SDL_URIToLocal(const char *src, char *dst);
|
||||
|
||||
typedef enum SDL_InitStatus
|
||||
{
|
||||
SDL_INIT_STATUS_UNINITIALIZED,
|
||||
SDL_INIT_STATUS_INITIALIZING,
|
||||
SDL_INIT_STATUS_INITIALIZED,
|
||||
SDL_INIT_STATUS_UNINITIALIZING
|
||||
} SDL_InitStatus;
|
||||
|
||||
typedef struct SDL_InitState
|
||||
{
|
||||
SDL_AtomicInt status;
|
||||
SDL_ThreadID thread;
|
||||
} SDL_InitState;
|
||||
|
||||
extern bool SDL_ShouldInit(SDL_InitState *state);
|
||||
extern bool SDL_ShouldQuit(SDL_InitState *state);
|
||||
extern void SDL_SetInitialized(SDL_InitState *state, bool initialized);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_OBJECT_TYPE_UNKNOWN,
|
||||
|
|
|
@ -817,6 +817,7 @@ SDL3_0.0.0 {
|
|||
SDL_SetHapticGain;
|
||||
SDL_SetHint;
|
||||
SDL_SetHintWithPriority;
|
||||
SDL_SetInitialized;
|
||||
SDL_SetJoystickEventsEnabled;
|
||||
SDL_SetJoystickLED;
|
||||
SDL_SetJoystickPlayerIndex;
|
||||
|
@ -895,6 +896,8 @@ SDL3_0.0.0 {
|
|||
SDL_SetX11EventHook;
|
||||
SDL_SetiOSAnimationCallback;
|
||||
SDL_SetiOSEventPump;
|
||||
SDL_ShouldInit;
|
||||
SDL_ShouldQuit;
|
||||
SDL_ShowAndroidToast;
|
||||
SDL_ShowCursor;
|
||||
SDL_ShowMessageBox;
|
||||
|
|
|
@ -842,6 +842,7 @@
|
|||
#define SDL_SetHapticGain SDL_SetHapticGain_REAL
|
||||
#define SDL_SetHint SDL_SetHint_REAL
|
||||
#define SDL_SetHintWithPriority SDL_SetHintWithPriority_REAL
|
||||
#define SDL_SetInitialized SDL_SetInitialized_REAL
|
||||
#define SDL_SetJoystickEventsEnabled SDL_SetJoystickEventsEnabled_REAL
|
||||
#define SDL_SetJoystickLED SDL_SetJoystickLED_REAL
|
||||
#define SDL_SetJoystickPlayerIndex SDL_SetJoystickPlayerIndex_REAL
|
||||
|
@ -920,6 +921,8 @@
|
|||
#define SDL_SetX11EventHook SDL_SetX11EventHook_REAL
|
||||
#define SDL_SetiOSAnimationCallback SDL_SetiOSAnimationCallback_REAL
|
||||
#define SDL_SetiOSEventPump SDL_SetiOSEventPump_REAL
|
||||
#define SDL_ShouldInit SDL_ShouldInit_REAL
|
||||
#define SDL_ShouldQuit SDL_ShouldQuit_REAL
|
||||
#define SDL_ShowAndroidToast SDL_ShowAndroidToast_REAL
|
||||
#define SDL_ShowCursor SDL_ShowCursor_REAL
|
||||
#define SDL_ShowMessageBox SDL_ShowMessageBox_REAL
|
||||
|
|
|
@ -852,6 +852,7 @@ SDL_DYNAPI_PROC(bool,SDL_SetHapticAutocenter,(SDL_Haptic *a, int b),(a,b),return
|
|||
SDL_DYNAPI_PROC(bool,SDL_SetHapticGain,(SDL_Haptic *a, int b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_SetHint,(const char *a, const char *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_SetHintWithPriority,(const char *a, const char *b, SDL_HintPriority c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetInitialized,(SDL_InitState *a, bool b),(a,b),)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetJoystickEventsEnabled,(bool a),(a),)
|
||||
SDL_DYNAPI_PROC(bool,SDL_SetJoystickLED,(SDL_Joystick *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_SetJoystickPlayerIndex,(SDL_Joystick *a, int b),(a,b),return)
|
||||
|
@ -930,6 +931,8 @@ SDL_DYNAPI_PROC(void,SDL_SetWindowsMessageHook,(SDL_WindowsMessageHook a, void *
|
|||
SDL_DYNAPI_PROC(void,SDL_SetX11EventHook,(SDL_X11EventHook a, void *b),(a,b),)
|
||||
SDL_DYNAPI_PROC(bool,SDL_SetiOSAnimationCallback,(SDL_Window *a, int b, SDL_iOSAnimationCallback c, void *d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_SetiOSEventPump,(bool a),(a),)
|
||||
SDL_DYNAPI_PROC(bool,SDL_ShouldInit,(SDL_InitState *a),(a),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_ShouldQuit,(SDL_InitState *a),(a),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_ShowAndroidToast,(const char *a, int b, int c, int d, int e),(a,b,c,d,e),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_ShowCursor,(void),(),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
|
||||
|
|
|
@ -517,3 +517,37 @@ bool SDL_WaitConditionTimeout(SDL_Condition *cond, SDL_Mutex *mutex, Sint32 time
|
|||
return SDL_WaitConditionTimeoutNS(cond, mutex, timeoutNS);
|
||||
}
|
||||
|
||||
bool SDL_ShouldInit(SDL_InitState *state)
|
||||
{
|
||||
while (SDL_GetAtomicInt(&state->status) != SDL_INIT_STATUS_INITIALIZED) {
|
||||
if (SDL_CompareAndSwapAtomicInt(&state->status, SDL_INIT_STATUS_UNINITIALIZED, SDL_INIT_STATUS_INITIALIZING)) {
|
||||
state->thread = SDL_GetCurrentThreadID();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wait for the other thread to complete transition
|
||||
SDL_Delay(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDL_ShouldQuit(SDL_InitState *state)
|
||||
{
|
||||
if (SDL_CompareAndSwapAtomicInt(&state->status, SDL_INIT_STATUS_INITIALIZED, SDL_INIT_STATUS_UNINITIALIZING)) {
|
||||
state->thread = SDL_GetCurrentThreadID();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDL_SetInitialized(SDL_InitState *state, bool initialized)
|
||||
{
|
||||
SDL_assert(state->thread == SDL_GetCurrentThreadID());
|
||||
|
||||
if (initialized) {
|
||||
SDL_SetAtomicInt(&state->status, SDL_INIT_STATUS_INITIALIZED);
|
||||
} else {
|
||||
SDL_SetAtomicInt(&state->status, SDL_INIT_STATUS_UNINITIALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue