From cdc40ee0546f6a761c369076a9e7a11fa0ea35b4 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 12 Jun 2023 15:26:34 -0700
Subject: [PATCH] Reduce the chance of destroying the joystick mutex while it's
in use
Fixes https://github.com/libsdl-org/SDL/issues/7811
---
src/joystick/SDL_joystick.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 518f2b7a2652..f30eaa9a88d8 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -109,6 +109,7 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
static
#endif
SDL_Mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
+static SDL_AtomicInt SDL_joystick_lock_pending;
static int SDL_joysticks_locked;
static SDL_bool SDL_joysticks_initialized;
static SDL_bool SDL_joysticks_quitting = SDL_FALSE;
@@ -138,23 +139,35 @@ SDL_bool SDL_JoysticksQuitting(void)
void SDL_LockJoysticks(void)
{
+ SDL_AtomicIncRef(&SDL_joystick_lock_pending);
SDL_LockMutex(SDL_joystick_lock);
+ SDL_AtomicDecRef(&SDL_joystick_lock_pending);
++SDL_joysticks_locked;
}
void SDL_UnlockJoysticks(void)
{
+ SDL_Mutex *joystick_lock = SDL_joystick_lock;
+ SDL_bool last_unlock = SDL_FALSE;
+
--SDL_joysticks_locked;
- SDL_UnlockMutex(SDL_joystick_lock);
+ if (!SDL_joysticks_initialized) {
+ if (!SDL_joysticks_locked && SDL_AtomicGet(&SDL_joystick_lock_pending) == 0) {
+ /* NOTE: There's a small window here where another thread could lock the mutex */
+ SDL_joystick_lock = NULL;
+ last_unlock = SDL_TRUE;
+ }
+ }
+
+ SDL_UnlockMutex(joystick_lock);
/* The last unlock after joysticks are uninitialized will cleanup the mutex,
* allowing applications to lock joysticks while reinitializing the system.
*/
- if (SDL_joystick_lock && !SDL_joysticks_locked && !SDL_joysticks_initialized) {
- SDL_DestroyMutex(SDL_joystick_lock);
- SDL_joystick_lock = NULL;
+ if (last_unlock) {
+ SDL_DestroyMutex(joystick_lock);
}
}