Commit 92d3fc4883b8ea814fa14450157f6b75e01e40b8

Sam Lantinga 2022-08-30T12:58:38

Fixed deadlock when shutting down the Windows joystick system

diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index cd41ca5..f9c09cf 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -130,6 +130,12 @@ SDL_JoysticksInitialized(void)
     return SDL_joysticks_initialized;
 }
 
+SDL_bool
+SDL_JoysticksQuitting(void)
+{
+    return SDL_joysticks_quitting;
+}
+
 void
 SDL_LockJoysticks(void)
 {
@@ -159,18 +165,12 @@ SDL_UnlockJoysticks(void)
     }
 }
 
-static void
+void
 SDL_AssertJoysticksLocked(void)
 {
     SDL_assert(SDL_joysticks_locked > 0);
 }
 
-SDL_bool
-SDL_JoysticksQuitting(void)
-{
-    return SDL_joysticks_quitting;
-}
-
 /*
  * Get the driver and device index for an API device index
  * This should be called while the joystick lock is held, to prevent another thread from updating the list
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index 51112a6..82311a0 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -45,6 +45,9 @@ extern SDL_bool SDL_JoysticksInitialized(void);
 /* Return whether the joystick system is shutting down */
 extern SDL_bool SDL_JoysticksQuitting(void);
 
+/* Make sure we currently have the joysticks locked */
+extern void SDL_AssertJoysticksLocked(void);
+
 /* Function to get the next available joystick instance ID */
 extern SDL_JoystickID SDL_GetNextJoystickInstanceID(void);
 
diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c
index 0b42ed6..a79e340 100644
--- a/src/joystick/windows/SDL_windowsjoystick.c
+++ b/src/joystick/windows/SDL_windowsjoystick.c
@@ -429,7 +429,12 @@ SDL_StopJoystickThread(void)
     SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
     SDL_UnlockMutex(s_mutexJoyStickEnum);
     PostThreadMessage(SDL_GetThreadID(s_joystickThread), WM_QUIT, 0, 0);
+
+    /* Unlock joysticks while the joystick thread finishes processing messages */
+    SDL_AssertJoysticksLocked();
+    SDL_UnlockJoysticks();
     SDL_WaitThread(s_joystickThread, NULL); /* wait for it to bugger off */
+    SDL_LockJoysticks();
 
     SDL_DestroyCond(s_condJoystickThread);
     s_condJoystickThread = NULL;