diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 518f2b7a2..f30eaa9a8 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); } }