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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index c3120e7..02d7edd 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);
}
}