From 7526a87ff2f9063dfe32539b4dc03ad9a2b5f429 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Tue, 7 Nov 2023 18:53:16 +0300 Subject: [PATCH] Handle subsystem dependencies recursively Existing code is erroneous, because it adds or removes dependency's ref count based on number of InitSubSystem/QuitSubSystem calls, while ref count diff should depend on number of inited or quit dependents. Recursive approach seems to be simplest solution that guarantees proper ref count. --- src/SDL.c | 66 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/src/SDL.c b/src/SDL.c index 56049adf0b..da3a4ccce5 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -160,6 +160,22 @@ static SDL_bool SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) return (((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 1)) || SDL_bInMainQuit) ? SDL_TRUE : SDL_FALSE; } +/* Private helper to either increment's existing ref counter, + * or fully init a new subsystem. */ +static SDL_bool SDL_PrivateInitOrIncrSubsystem(Uint32 subsystem) +{ + int subsystem_index = SDL_MostSignificantBitIndex32(subsystem); + SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255)); + if (subsystem_index < 0) { + return SDL_FALSE; + } + if (SDL_SubsystemRefCount[subsystem_index] > 0) { + ++SDL_SubsystemRefCount[subsystem_index]; + return SDL_TRUE; + } + return SDL_InitSubSystem(subsystem) == 0; +} + void SDL_SetMainReady(void) { SDL_MainIsReady = SDL_TRUE; @@ -182,16 +198,6 @@ int SDL_InitSubSystem(Uint32 flags) SDL_DBus_Init(); #endif - if (flags & SDL_INIT_GAMECONTROLLER) { - /* game controller implies joystick */ - flags |= SDL_INIT_JOYSTICK; - } - - if (flags & (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO)) { - /* video or joystick or audio implies events */ - flags |= SDL_INIT_EVENTS; - } - #if SDL_THREAD_OS2 SDL_OS2TLSAlloc(); /* thread/os2/SDL_systls.c */ #endif @@ -244,6 +250,11 @@ int SDL_InitSubSystem(Uint32 flags) if (flags & SDL_INIT_VIDEO) { #if !SDL_VIDEO_DISABLED if (SDL_PrivateShouldInitSubsystem(SDL_INIT_VIDEO)) { + /* video implies events */ + if (!SDL_PrivateInitOrIncrSubsystem(SDL_INIT_EVENTS)) { + goto quit_and_error; + } + if (SDL_VideoInit(NULL) < 0) { goto quit_and_error; } @@ -260,6 +271,11 @@ int SDL_InitSubSystem(Uint32 flags) if (flags & SDL_INIT_AUDIO) { #if !SDL_AUDIO_DISABLED if (SDL_PrivateShouldInitSubsystem(SDL_INIT_AUDIO)) { + /* audio implies events */ + if (!SDL_PrivateInitOrIncrSubsystem(SDL_INIT_EVENTS)) { + goto quit_and_error; + } + if (SDL_AudioInit(NULL) < 0) { goto quit_and_error; } @@ -276,6 +292,11 @@ int SDL_InitSubSystem(Uint32 flags) if (flags & SDL_INIT_JOYSTICK) { #if !SDL_JOYSTICK_DISABLED if (SDL_PrivateShouldInitSubsystem(SDL_INIT_JOYSTICK)) { + /* joystick implies events */ + if (!SDL_PrivateInitOrIncrSubsystem(SDL_INIT_EVENTS)) { + goto quit_and_error; + } + if (SDL_JoystickInit() < 0) { goto quit_and_error; } @@ -291,6 +312,11 @@ int SDL_InitSubSystem(Uint32 flags) if (flags & SDL_INIT_GAMECONTROLLER) { #if !SDL_JOYSTICK_DISABLED if (SDL_PrivateShouldInitSubsystem(SDL_INIT_GAMECONTROLLER)) { + /* game controller implies joystick */ + if (!SDL_PrivateInitOrIncrSubsystem(SDL_INIT_JOYSTICK)) { + goto quit_and_error; + } + if (SDL_GameControllerInit() < 0) { goto quit_and_error; } @@ -370,21 +396,19 @@ void SDL_QuitSubSystem(Uint32 flags) #if !SDL_JOYSTICK_DISABLED if (flags & SDL_INIT_GAMECONTROLLER) { - /* game controller implies joystick */ - flags |= SDL_INIT_JOYSTICK; - if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) { SDL_GameControllerQuit(); + /* game controller implies joystick */ + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER); } if (flags & SDL_INIT_JOYSTICK) { - /* joystick implies events */ - flags |= SDL_INIT_EVENTS; - if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) { SDL_JoystickQuit(); + /* joystick implies events */ + SDL_QuitSubSystem(SDL_INIT_EVENTS); } SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK); } @@ -401,11 +425,10 @@ void SDL_QuitSubSystem(Uint32 flags) #if !SDL_AUDIO_DISABLED if (flags & SDL_INIT_AUDIO) { - /* audio implies events */ - flags |= SDL_INIT_EVENTS; - if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) { SDL_AudioQuit(); + /* audio implies events */ + SDL_QuitSubSystem(SDL_INIT_EVENTS); } SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO); } @@ -413,11 +436,10 @@ void SDL_QuitSubSystem(Uint32 flags) #if !SDL_VIDEO_DISABLED if (flags & SDL_INIT_VIDEO) { - /* video implies events */ - flags |= SDL_INIT_EVENTS; - if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) { SDL_VideoQuit(); + /* video implies events */ + SDL_QuitSubSystem(SDL_INIT_EVENTS); } SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO); }