mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-08-27 09:01:34 +00:00
Create a global event lock for hardware that generates events
This prevents ABBA deadlocks caused by taking a hardware resource lock then delivering events at the same time another thread is taking a hardware resource lock from an event watch callback. Fixes https://github.com/libsdl-org/SDL/issues/15709
This commit is contained in:
@@ -75,8 +75,8 @@
|
||||
} while (0)
|
||||
|
||||
static bool SDL_gamepads_initialized;
|
||||
static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_HashTable *SDL_gamepad_names SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static SDL_HashTable *SDL_gamepad_names SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
|
||||
// The face button style of a gamepad
|
||||
typedef enum
|
||||
@@ -96,7 +96,7 @@ typedef enum
|
||||
SDL_GAMEPAD_MAPPING_PRIORITY_USER,
|
||||
} SDL_GamepadMappingPriority;
|
||||
|
||||
#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
|
||||
#define _guarded SDL_GUARDED_BY(SDL_event_lock)
|
||||
|
||||
typedef struct GamepadMapping_t
|
||||
{
|
||||
@@ -121,13 +121,13 @@ typedef struct
|
||||
#undef _guarded
|
||||
|
||||
static SDL_GUID s_zeroGUID;
|
||||
static GamepadMapping_t *s_pSupportedGamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static GamepadMapping_t *s_pDefaultMapping SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static GamepadMapping_t *s_pXInputMapping SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static MappingChangeTracker *s_mappingChangeTracker SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_HashTable *s_gamepadInstanceIDs SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static GamepadMapping_t *s_pSupportedGamepads SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static GamepadMapping_t *s_pDefaultMapping SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static GamepadMapping_t *s_pXInputMapping SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static MappingChangeTracker *s_mappingChangeTracker SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static SDL_HashTable *s_gamepadInstanceIDs SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
|
||||
#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
|
||||
#define _guarded SDL_GUARDED_BY(SDL_event_lock)
|
||||
|
||||
// The SDL gamepad structure
|
||||
struct SDL_Gamepad
|
||||
|
||||
@@ -114,19 +114,14 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef SDL_THREAD_SAFETY_ANALYSIS
|
||||
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 bool SDL_joysticks_initialized;
|
||||
static bool SDL_joysticks_quitting;
|
||||
static bool SDL_joystick_being_added;
|
||||
static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_HashTable *SDL_joystick_names SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_event_lock) = 0;
|
||||
static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static SDL_HashTable *SDL_joystick_names SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static bool SDL_joystick_allows_background_events = false;
|
||||
|
||||
static Uint32 initial_old_xboxone_controllers[] = {
|
||||
@@ -706,16 +701,13 @@ bool SDL_JoysticksQuitting(void)
|
||||
|
||||
void SDL_LockJoysticks(void)
|
||||
{
|
||||
(void)SDL_AtomicIncRef(&SDL_joystick_lock_pending);
|
||||
SDL_LockMutex(SDL_joystick_lock);
|
||||
(void)SDL_AtomicDecRef(&SDL_joystick_lock_pending);
|
||||
|
||||
SDL_LockMutex(SDL_event_lock);
|
||||
++SDL_joysticks_locked;
|
||||
}
|
||||
|
||||
bool SDL_TryLockJoysticks(void)
|
||||
{
|
||||
if (SDL_TryLockMutex(SDL_joystick_lock)) {
|
||||
if (SDL_TryLockMutex(SDL_event_lock)) {
|
||||
++SDL_joysticks_locked;
|
||||
return true;
|
||||
}
|
||||
@@ -724,34 +716,8 @@ bool SDL_TryLockJoysticks(void)
|
||||
|
||||
void SDL_UnlockJoysticks(void)
|
||||
{
|
||||
bool last_unlock = false;
|
||||
|
||||
--SDL_joysticks_locked;
|
||||
|
||||
if (!SDL_joysticks_initialized) {
|
||||
// NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks
|
||||
if (!SDL_joysticks_locked && SDL_GetAtomicInt(&SDL_joystick_lock_pending) == 0) {
|
||||
last_unlock = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* The last unlock after joysticks are uninitialized will cleanup the mutex,
|
||||
* allowing applications to lock joysticks while reinitializing the system.
|
||||
*/
|
||||
if (last_unlock) {
|
||||
SDL_Mutex *joystick_lock = SDL_joystick_lock;
|
||||
|
||||
SDL_LockMutex(joystick_lock);
|
||||
{
|
||||
SDL_UnlockMutex(SDL_joystick_lock);
|
||||
|
||||
SDL_joystick_lock = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(joystick_lock);
|
||||
SDL_DestroyMutex(joystick_lock);
|
||||
} else {
|
||||
SDL_UnlockMutex(SDL_joystick_lock);
|
||||
}
|
||||
SDL_UnlockMutex(SDL_event_lock);
|
||||
}
|
||||
|
||||
bool SDL_JoysticksLocked(void)
|
||||
@@ -892,11 +858,6 @@ bool SDL_InitJoysticks(void)
|
||||
int i;
|
||||
bool result = false;
|
||||
|
||||
// Create the joystick list lock
|
||||
if (SDL_joystick_lock == NULL) {
|
||||
SDL_joystick_lock = SDL_CreateMutex();
|
||||
}
|
||||
|
||||
if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ extern bool SDL_JoysticksQuitting(void);
|
||||
extern bool SDL_JoysticksLocked(void);
|
||||
|
||||
// Make sure we currently have the joysticks locked
|
||||
extern void SDL_AssertJoysticksLocked(void) SDL_ASSERT_CAPABILITY(SDL_joystick_lock);
|
||||
extern void SDL_AssertJoysticksLocked(void) SDL_ASSERT_CAPABILITY(SDL_event_lock);
|
||||
|
||||
// Function to return whether there are any joysticks opened by the application
|
||||
extern bool SDL_JoysticksOpened(void);
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
static char *SDL_steam_virtual_gamepad_info_file SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static Uint64 SDL_steam_virtual_gamepad_info_file_mtime SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static Uint64 SDL_steam_virtual_gamepad_info_check_time SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static SDL_SteamVirtualGamepadInfo **SDL_steam_virtual_gamepad_info SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static int SDL_steam_virtual_gamepad_info_count SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static char *SDL_steam_virtual_gamepad_info_file SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static Uint64 SDL_steam_virtual_gamepad_info_file_mtime SDL_GUARDED_BY(SDL_event_lock) = 0;
|
||||
static Uint64 SDL_steam_virtual_gamepad_info_check_time SDL_GUARDED_BY(SDL_event_lock) = 0;
|
||||
static SDL_SteamVirtualGamepadInfo **SDL_steam_virtual_gamepad_info SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static int SDL_steam_virtual_gamepad_info_count SDL_GUARDED_BY(SDL_event_lock) = 0;
|
||||
|
||||
|
||||
static Uint64 GetFileModificationTime(const char *file)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
// This is the system specific header for the SDL joystick API
|
||||
#include "SDL_joystick_c.h"
|
||||
#include "../events/SDL_events_c.h"
|
||||
|
||||
// Set up for C function definitions, even when using C++
|
||||
#ifdef __cplusplus
|
||||
@@ -78,7 +79,7 @@ typedef struct SDL_JoystickCapSenseInfo
|
||||
bool down;
|
||||
} SDL_JoystickCapSenseInfo;
|
||||
|
||||
#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
|
||||
#define _guarded SDL_GUARDED_BY(SDL_event_lock)
|
||||
|
||||
struct SDL_Joystick
|
||||
{
|
||||
|
||||
@@ -117,7 +117,7 @@ static int SDL_HIDAPI_numdrivers = 0;
|
||||
static SDL_AtomicInt SDL_HIDAPI_updating_devices;
|
||||
static bool SDL_HIDAPI_hints_changed = false;
|
||||
static Uint32 SDL_HIDAPI_change_count = 0;
|
||||
static SDL_HIDAPI_Device *SDL_HIDAPI_devices SDL_GUARDED_BY(SDL_joystick_lock);
|
||||
static SDL_HIDAPI_Device *SDL_HIDAPI_devices SDL_GUARDED_BY(SDL_event_lock);
|
||||
static int SDL_HIDAPI_numjoysticks = 0;
|
||||
static bool SDL_HIDAPI_combine_joycons = true;
|
||||
static bool initialized = false;
|
||||
|
||||
@@ -186,10 +186,10 @@ typedef struct SDL_sensorlist_item
|
||||
} SDL_sensorlist_item;
|
||||
|
||||
static bool SDL_classic_joysticks = false;
|
||||
static SDL_joylist_item *SDL_joylist SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static int numjoysticks SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static SDL_sensorlist_item *SDL_sensorlist SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_joylist_item *SDL_joylist SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static int numjoysticks SDL_GUARDED_BY(SDL_event_lock) = 0;
|
||||
static SDL_sensorlist_item *SDL_sensorlist SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
static int inotify_fd = -1;
|
||||
|
||||
static Uint64 last_joy_detect_time;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
||||
static joystick_hwdata *g_VJoys SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static joystick_hwdata *g_VJoys SDL_GUARDED_BY(SDL_event_lock) = NULL;
|
||||
|
||||
static joystick_hwdata *VIRTUAL_HWDataForInstance(SDL_JoystickID instance_id)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user