diff --git a/src/SDL.c b/src/SDL.c index 4a879893f2..f9eaa0f1c3 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -189,6 +189,8 @@ static bool SDL_MainIsReady = false; static bool SDL_MainIsReady = true; #endif static SDL_ThreadID SDL_MainThreadID = 0; +static SDL_ThreadID SDL_EventsThreadID = 0; +static SDL_ThreadID SDL_VideoThreadID = 0; static bool SDL_bInMainQuit = false; static Uint8 SDL_SubsystemRefCount[32]; @@ -266,14 +268,16 @@ void SDL_SetMainReady(void) bool SDL_IsMainThread(void) { - if (SDL_MainThreadID == 0) { - // Not initialized yet? - return true; + if (SDL_VideoThreadID) { + return (SDL_GetCurrentThreadID() == SDL_VideoThreadID); } - if (SDL_MainThreadID == SDL_GetCurrentThreadID()) { - return true; + if (SDL_EventsThreadID) { + return (SDL_GetCurrentThreadID() == SDL_EventsThreadID); } - return false; + if (SDL_MainThreadID) { + return (SDL_GetCurrentThreadID() == SDL_MainThreadID); + } + return true; } // Initialize all the subsystems that require initialization before threads start @@ -281,6 +285,11 @@ void SDL_InitMainThread(void) { static bool done_info = false; + // If we haven't done it by now, mark this as the main thread + if (SDL_MainThreadID == 0) { + SDL_MainThreadID = SDL_GetCurrentThreadID(); + } + SDL_InitTLSData(); SDL_InitEnvironment(); SDL_InitTicks(); @@ -335,6 +344,11 @@ bool SDL_InitSubSystem(SDL_InitFlags flags) if (flags & SDL_INIT_EVENTS) { if (SDL_ShouldInitSubsystem(SDL_INIT_EVENTS)) { SDL_IncrementSubsystemRefCount(SDL_INIT_EVENTS); + + // Note which thread initialized events + // This is the thread which should be pumping events + SDL_EventsThreadID = SDL_GetCurrentThreadID(); + if (!SDL_InitEvents()) { SDL_DecrementSubsystemRefCount(SDL_INIT_EVENTS); goto quit_and_error; @@ -354,12 +368,16 @@ bool SDL_InitSubSystem(SDL_InitFlags flags) goto quit_and_error; } + SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO); + // We initialize video on the main thread // On Apple platforms this is a requirement. // On other platforms, this is the definition. - SDL_MainThreadID = SDL_GetCurrentThreadID(); + SDL_VideoThreadID = SDL_GetCurrentThreadID(); +#ifdef SDL_PLATFORM_APPLE + SDL_assert(SDL_VideoThreadID == SDL_MainThreadID); +#endif - SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO); if (!SDL_VideoInit(NULL)) { SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO); SDL_PushError(); @@ -609,6 +627,7 @@ void SDL_QuitSubSystem(SDL_InitFlags flags) if (SDL_ShouldQuitSubsystem(SDL_INIT_VIDEO)) { SDL_QuitRender(); SDL_VideoQuit(); + SDL_VideoThreadID = 0; // video implies events SDL_QuitSubSystem(SDL_INIT_EVENTS); } @@ -619,6 +638,7 @@ void SDL_QuitSubSystem(SDL_InitFlags flags) if (flags & SDL_INIT_EVENTS) { if (SDL_ShouldQuitSubsystem(SDL_INIT_EVENTS)) { SDL_QuitEvents(); + SDL_EventsThreadID = 0; } SDL_DecrementSubsystemRefCount(SDL_INIT_EVENTS); } diff --git a/src/SDL_internal.h b/src/SDL_internal.h index 7f8439e159..13d431e103 100644 --- a/src/SDL_internal.h +++ b/src/SDL_internal.h @@ -265,6 +265,7 @@ extern "C" { #include "SDL_utils_c.h" #include "SDL_hashtable.h" + /* SDL_ExitProcess is not declared in any public header, although it is shared between some parts of SDL, because we don't want anything calling it without an extremely good reason. */ diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 7551e4a649..5560ecb74b 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -1494,6 +1494,9 @@ void SDL_PumpEventMaintenance(void) // Run the system dependent event loops static void SDL_PumpEventsInternal(bool push_sentinel) { + // This should only be called on the main thread, check in debug builds + SDL_assert(SDL_IsMainThread()); + // Free any temporary memory from old events SDL_FreeTemporaryMemory(); diff --git a/src/main/SDL_main_callbacks.c b/src/main/SDL_main_callbacks.c index 6c4a67acd7..9bed41379e 100644 --- a/src/main/SDL_main_callbacks.c +++ b/src/main/SDL_main_callbacks.c @@ -147,13 +147,19 @@ void SDL_QuitMainCallbacks(SDL_AppResult result) SDL_Quit(); } -void SDL_CheckDefaultArgcArgv(int *argc, char ***argv) +static void SDL_CheckDefaultArgcArgv(int *argc, char ***argv) { - if (!argv) - { + if (!*argv) { static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' }; static char *argvdummy[2] = { dummyargv0, NULL }; *argc = 1; *argv = argvdummy; } } + +int SDL_CallMainFunction(int argc, char *argv[], SDL_main_func mainFunction) +{ + SDL_CheckDefaultArgcArgv(&argc, &argv); + SDL_SetMainReady(); + return mainFunction(argc, argv); +} diff --git a/src/main/SDL_main_callbacks.h b/src/main/SDL_main_callbacks.h index 2408414909..58962a849e 100644 --- a/src/main/SDL_main_callbacks.h +++ b/src/main/SDL_main_callbacks.h @@ -27,10 +27,7 @@ SDL_AppResult SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func app SDL_AppResult SDL_IterateMainCallbacks(bool pump_events); void SDL_QuitMainCallbacks(SDL_AppResult result); -// (not a callback thing, but convenient to stick this in here.) -// If *_argv is NULL, update *_argc and *_argv to point at a static array of { "SDL_app", NULL }. -void SDL_CheckDefaultArgcArgv(int *_argc, char ***_argv); +// Check args and call the main function +extern int SDL_CallMainFunction(int argc, char *argv[], SDL_main_func mainFunction); #endif // SDL_main_callbacks_h_ - - diff --git a/src/main/SDL_runapp.c b/src/main/SDL_runapp.c index 83ac590cb5..df0750529d 100644 --- a/src/main/SDL_runapp.c +++ b/src/main/SDL_runapp.c @@ -28,8 +28,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved) { (void)reserved; - SDL_CheckDefaultArgcArgv(&argc, &argv); - return mainFunction(argc, argv); + return SDL_CallMainFunction(argc, argv, mainFunction); } #endif diff --git a/src/main/emscripten/SDL_sysmain_runapp.c b/src/main/emscripten/SDL_sysmain_runapp.c index 04a8a91de4..74e4a0e628 100644 --- a/src/main/emscripten/SDL_sysmain_runapp.c +++ b/src/main/emscripten/SDL_sysmain_runapp.c @@ -37,8 +37,6 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv { (void)reserved; - SDL_CheckDefaultArgcArgv(&argc, &argv); - // Move any URL params that start with "SDL_" over to environment // variables, so the hint system can pick them up, etc, much like a user // can set them from a shell prompt on a desktop machine. Ignore all @@ -59,7 +57,7 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv } }, SDL_setenv_unsafe); - return mainFunction(argc, argv); + return SDL_CallMainFunction(argc, argv, mainFunction); } #endif diff --git a/src/main/gdk/SDL_sysmain_runapp.cpp b/src/main/gdk/SDL_sysmain_runapp.cpp index 3eeac97dfb..5c8ca466c4 100644 --- a/src/main/gdk/SDL_sysmain_runapp.cpp +++ b/src/main/gdk/SDL_sysmain_runapp.cpp @@ -24,6 +24,7 @@ extern "C" { #include "../../core/gdk/SDL_gdk.h" #include "../../core/windows/SDL_windows.h" #include "../../events/SDL_events_c.h" +#include "../SDL_main_callbacks.h" } #include #include @@ -65,14 +66,12 @@ int SDL_RunApp(int argc, char **argv, SDL_main_func mainFunction, void *reserved SDL_SetError("[GDK] Unable to get titleid. Will not call XblInitialize. Check MicrosoftGame.config!"); } - SDL_SetMainReady(); - if (!GDK_RegisterChangeNotifications()) { return -1; } // Run the application main() code - result = mainFunction(argc, argv); + result = SDL_CallMainFunction(argc, argv, mainFunction); GDK_UnregisterChangeNotifications(); diff --git a/src/main/n3ds/SDL_sysmain_runapp.c b/src/main/n3ds/SDL_sysmain_runapp.c index 4cb6adeb95..d6842b7d3b 100644 --- a/src/main/n3ds/SDL_sysmain_runapp.c +++ b/src/main/n3ds/SDL_sysmain_runapp.c @@ -31,14 +31,11 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv { int result; - SDL_CheckDefaultArgcArgv(&argc, &argv); - // init osSetSpeedupEnable(true); romfsInit(); - SDL_SetMainReady(); - result = mainFunction(argc, argv); + result = SDL_CallMainFunction(argc, argv, mainFunction); // quit romfsExit(); diff --git a/src/main/ps2/SDL_sysmain_runapp.c b/src/main/ps2/SDL_sysmain_runapp.c index e92bc70241..ce97ad0c0c 100644 --- a/src/main/ps2/SDL_sysmain_runapp.c +++ b/src/main/ps2/SDL_sysmain_runapp.c @@ -68,21 +68,17 @@ static void deinit_drivers(void) int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserved) { - int res; + int result; (void)reserved; - SDL_CheckDefaultArgcArgv(&argc, &argv); - prepare_IOP(); init_drivers(); - SDL_SetMainReady(); - - res = mainFunction(argc, argv); + result = SDL_CallMainFunction(argc, argv, mainFunction); deinit_drivers(); - return res; + return result; } #endif // SDL_PLATFORM_PS2 diff --git a/src/main/psp/SDL_sysmain_runapp.c b/src/main/psp/SDL_sysmain_runapp.c index 3b4eb0f8b1..dabf7ac77f 100644 --- a/src/main/psp/SDL_sysmain_runapp.c +++ b/src/main/psp/SDL_sysmain_runapp.c @@ -74,13 +74,9 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void * reserv { (void)reserved; - SDL_CheckDefaultArgcArgv(&argc, &argv); - sdl_psp_setup_callbacks(); - SDL_SetMainReady(); - - return mainFunction(argc, argv); + return SDL_CallMainFunction(argc, argv, mainFunction); } #endif // SDL_PLATFORM_PSP diff --git a/src/main/windows/SDL_sysmain_runapp.c b/src/main/windows/SDL_sysmain_runapp.c index a53042049b..39b3820c8f 100644 --- a/src/main/windows/SDL_sysmain_runapp.c +++ b/src/main/windows/SDL_sysmain_runapp.c @@ -23,6 +23,7 @@ #ifdef SDL_PLATFORM_WIN32 #include "../../core/windows/SDL_windows.h" +#include "../SDL_main_callbacks.h" /* Win32-specific SDL_RunApp(), which does most of the SDL_main work, based on SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98 */ @@ -37,8 +38,7 @@ int MINGW32_FORCEALIGN SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunc if (args_error) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", args_error, NULL); } else { - SDL_SetMainReady(); - result = mainFunction(argc, argv); + result = SDL_CallMainFunction(argc, argv, mainFunction); if (heap_allocated) { HeapFree(GetProcessHeap(), 0, heap_allocated); } diff --git a/src/video/uikit/SDL_uikitappdelegate.m b/src/video/uikit/SDL_uikitappdelegate.m index 9b8b3bcbe5..e2c304b9ca 100644 --- a/src/video/uikit/SDL_uikitappdelegate.m +++ b/src/video/uikit/SDL_uikitappdelegate.m @@ -42,8 +42,6 @@ static int exit_status; int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved) { - SDL_CheckDefaultArgcArgv(&argc, &argv); - // store arguments forward_main = mainFunction; forward_argc = argc; @@ -483,7 +481,7 @@ API_AVAILABLE(ios(13.0)) [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; SDL_SetiOSEventPump(true); - exit_status = forward_main(forward_argc, forward_argv); + exit_status = SDL_CallMainFunction(forward_argc, forward_argv, forward_main); SDL_SetiOSEventPump(false); if (launchWindow) { @@ -553,7 +551,7 @@ API_AVAILABLE(ios(13.0)) // run the user's application, passing argc and argv SDL_SetiOSEventPump(true); - exit_status = forward_main(forward_argc, forward_argv); + exit_status = SDL_CallMainFunction(forward_argc, forward_argv, forward_main); SDL_SetiOSEventPump(false); if (launchWindow) {