From e4e0a12901321a1dd6f949fa0a385684c2a17553 Mon Sep 17 00:00:00 2001 From: Sam Lantinga 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 (cherry picked from commit 6390165fd4c193631d6780758a4aeec0d02b90eb) --- 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 c3120e724..02d7eddab 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -114,6 +114,7 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = { static #endif SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */ +static SDL_atomic_t SDL_joystick_lock_pending; static int SDL_joysticks_locked; static SDL_bool SDL_joysticks_initialized; static SDL_bool SDL_joysticks_quitting = SDL_FALSE; @@ -143,23 +144,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); } }