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); } }