From f9d49358d27f55fb9a9128f1bc18efb034becabb Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 2 Jun 2026 15:29:06 -0700
Subject: [PATCH] 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
---
include/SDL3/SDL_joystick.h | 8 ++--
src/SDL.c | 2 +
src/events/SDL_events.c | 39 ++++++++++------
src/events/SDL_events_c.h | 9 ++++
src/events/SDL_eventwatch.c | 25 ++++------
src/events/SDL_eventwatch_c.h | 1 -
src/events/SDL_touch.c | 31 ++++++-------
src/joystick/SDL_gamepad.c | 18 ++++----
src/joystick/SDL_joystick.c | 53 +++-------------------
src/joystick/SDL_joystick_c.h | 2 +-
src/joystick/SDL_steam_virtual_gamepad.c | 10 ++--
src/joystick/SDL_sysjoystick.h | 3 +-
src/joystick/hidapi/SDL_hidapijoystick.c | 2 +-
src/joystick/linux/SDL_sysjoystick.c | 8 ++--
src/joystick/virtual/SDL_virtualjoystick.c | 2 +-
src/sensor/SDL_sensor.c | 45 ++----------------
src/sensor/SDL_sensor_c.h | 10 ++--
src/sensor/SDL_syssensor.h | 3 +-
18 files changed, 99 insertions(+), 172 deletions(-)
diff --git a/include/SDL3/SDL_joystick.h b/include/SDL3/SDL_joystick.h
index f0ecc0428f240..e3bf5988c27ff 100644
--- a/include/SDL3/SDL_joystick.h
+++ b/include/SDL3/SDL_joystick.h
@@ -81,7 +81,7 @@ extern "C" {
* help Clang's thread safety analysis tools to function. Do not attempt
* to access this symbol from your app, it will not work!
*/
-extern SDL_Mutex *SDL_joystick_lock;
+extern SDL_Mutex *SDL_event_lock;
#endif
/**
@@ -186,7 +186,7 @@ typedef enum SDL_JoystickConnectionState
*
* \since This function is available since SDL 3.2.0.
*/
-extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lock);
+extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_event_lock);
/**
* Locking for atomic access to the joystick API.
@@ -201,7 +201,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystic
*
* \since This function is available since SDL 3.6.0.
*/
-extern SDL_DECLSPEC bool SDLCALL SDL_TryLockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lock);
+extern SDL_DECLSPEC bool SDLCALL SDL_TryLockJoysticks(void) SDL_TRY_ACQUIRE(true, SDL_event_lock);
/**
* Unlocking for atomic access to the joystick API.
@@ -211,7 +211,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_TryLockJoysticks(void) SDL_ACQUIRE(SDL_joys
*
* \since This function is available since SDL 3.2.0.
*/
-extern SDL_DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_lock);
+extern SDL_DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_event_lock);
/**
* Return whether a joystick is currently connected.
diff --git a/src/SDL.c b/src/SDL.c
index 02d1e4e8c1ed0..61d14bbff7b7b 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -298,6 +298,7 @@ void SDL_InitMainThread(void)
SDL_InitEnvironment();
SDL_InitTicks();
SDL_InitFilesystem();
+ SDL_CreateEventLock();
if (!done_info) {
const char *value;
@@ -316,6 +317,7 @@ void SDL_InitMainThread(void)
static void SDL_QuitMainThread(void)
{
+ SDL_DestroyEventLock();
SDL_QuitFilesystem();
SDL_QuitTicks();
SDL_QuitEnvironment();
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index e2ef1a35f3486..a0ed2fc3bfb36 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -161,6 +161,23 @@ static struct
} SDL_EventQ = { NULL, false, { 0 }, 0, NULL, NULL, NULL };
+SDL_Mutex *SDL_event_lock = NULL; // This needs to support recursive locks
+
+void SDL_CreateEventLock(void)
+{
+ if (!SDL_event_lock) {
+ SDL_event_lock = SDL_CreateMutex();
+ }
+}
+
+void SDL_DestroyEventLock(void)
+{
+ if (SDL_event_lock) {
+ SDL_DestroyMutex(SDL_event_lock);
+ SDL_event_lock = NULL;
+ }
+}
+
static void SDL_CleanupTemporaryMemory(void *data)
{
SDL_TemporaryMemoryState *state = (SDL_TemporaryMemoryState *)data;
@@ -965,8 +982,9 @@ void SDL_StopEventLoop(void)
const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
int i;
SDL_EventEntry *entry;
+ SDL_Mutex *lock = SDL_EventQ.lock;
- SDL_LockMutex(SDL_EventQ.lock);
+ SDL_LockMutex(lock);
SDL_EventQ.active = false;
@@ -1004,17 +1022,10 @@ void SDL_StopEventLoop(void)
SDL_QuitEventWatchList(&SDL_event_watchers);
SDL_QuitWindowEventWatch();
- SDL_Mutex *lock = NULL;
- if (SDL_EventQ.lock) {
- lock = SDL_EventQ.lock;
- SDL_EventQ.lock = NULL;
- }
+ SDL_EventQ.lock = NULL;
SDL_UnlockMutex(lock);
-
- if (lock) {
- SDL_DestroyMutex(lock);
- }
+ SDL_DestroyMutex(lock);
}
// This function (and associated calls) may be called more than once
@@ -1833,7 +1844,7 @@ bool SDL_PushEvent(SDL_Event *event)
void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
{
SDL_EventEntry *event, *next;
- SDL_LockMutex(SDL_event_watchers.lock);
+ SDL_LockMutex(SDL_event_lock);
{
// Set filter and discard pending events
SDL_event_watchers.filter.callback = filter;
@@ -1852,18 +1863,18 @@ void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
SDL_UnlockMutex(SDL_EventQ.lock);
}
}
- SDL_UnlockMutex(SDL_event_watchers.lock);
+ SDL_UnlockMutex(SDL_event_lock);
}
bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
{
SDL_EventWatcher event_ok;
- SDL_LockMutex(SDL_event_watchers.lock);
+ SDL_LockMutex(SDL_event_lock);
{
event_ok = SDL_event_watchers.filter;
}
- SDL_UnlockMutex(SDL_event_watchers.lock);
+ SDL_UnlockMutex(SDL_event_lock);
if (filter) {
*filter = event_ok.callback;
diff --git a/src/events/SDL_events_c.h b/src/events/SDL_events_c.h
index 377b04ec17aa2..cfb467b9ed8ef 100644
--- a/src/events/SDL_events_c.h
+++ b/src/events/SDL_events_c.h
@@ -36,6 +36,15 @@
#include "SDL_pen_c.h"
#include "SDL_windowevents_c.h"
+// The event mutex
+//
+// This mutex prevents multiple threads from watching multiple events
+// simultaneously and also protects resources like joysticks that may
+// be accessed from multiple threads and also generate events.
+extern SDL_Mutex *SDL_event_lock;
+extern void SDL_CreateEventLock(void);
+extern void SDL_DestroyEventLock(void);
+
// Start and stop the event processing loop
extern bool SDL_StartEventLoop(void);
extern void SDL_StopEventLoop(void);
diff --git a/src/events/SDL_eventwatch.c b/src/events/SDL_eventwatch.c
index 5d0ff353175ab..434f73075157a 100644
--- a/src/events/SDL_eventwatch.c
+++ b/src/events/SDL_eventwatch.c
@@ -21,25 +21,16 @@
#include "SDL_internal.h"
#include "SDL_eventwatch_c.h"
+#include "SDL_events_c.h"
bool SDL_InitEventWatchList(SDL_EventWatchList *list)
{
- if (list->lock == NULL) {
- list->lock = SDL_CreateMutex();
- if (list->lock == NULL) {
- return false;
- }
- }
return true;
}
void SDL_QuitEventWatchList(SDL_EventWatchList *list)
{
- if (list->lock) {
- SDL_DestroyMutex(list->lock);
- list->lock = NULL;
- }
if (list->watchers) {
SDL_free(list->watchers);
list->watchers = NULL;
@@ -56,13 +47,13 @@ bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event)
return true;
}
- SDL_LockMutex(list->lock);
+ SDL_LockMutex(SDL_event_lock);
{
// Make sure we only dispatch the current watcher list
int i, count = list->count;
if (filter->callback && !filter->callback(filter->userdata, event)) {
- SDL_UnlockMutex(list->lock);
+ SDL_UnlockMutex(SDL_event_lock);
return false;
}
@@ -86,7 +77,7 @@ bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event)
list->removed = false;
}
}
- SDL_UnlockMutex(list->lock);
+ SDL_UnlockMutex(SDL_event_lock);
return true;
}
@@ -95,7 +86,7 @@ bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, voi
{
bool result = true;
- SDL_LockMutex(list->lock);
+ SDL_LockMutex(SDL_event_lock);
{
SDL_EventWatcher *watchers;
@@ -113,14 +104,14 @@ bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, voi
result = false;
}
}
- SDL_UnlockMutex(list->lock);
+ SDL_UnlockMutex(SDL_event_lock);
return result;
}
void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata)
{
- SDL_LockMutex(list->lock);
+ SDL_LockMutex(SDL_event_lock);
{
int i;
@@ -139,5 +130,5 @@ void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter,
}
}
}
- SDL_UnlockMutex(list->lock);
+ SDL_UnlockMutex(SDL_event_lock);
}
diff --git a/src/events/SDL_eventwatch_c.h b/src/events/SDL_eventwatch_c.h
index 5c382a7cae54e..e004809f37cff 100644
--- a/src/events/SDL_eventwatch_c.h
+++ b/src/events/SDL_eventwatch_c.h
@@ -29,7 +29,6 @@ typedef struct SDL_EventWatcher
typedef struct SDL_EventWatchList
{
- SDL_Mutex *lock;
SDL_EventWatcher filter;
SDL_EventWatcher *watchers;
int count;
diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c
index b8ebb78aeea8c..17bcb93f0bcd7 100644
--- a/src/events/SDL_touch.c
+++ b/src/events/SDL_touch.c
@@ -25,21 +25,20 @@
#include "SDL_events_c.h"
#include "../video/SDL_sysvideo.h"
-static SDL_Mutex *SDL_touch_lock = NULL; // This needs to support recursive locks
static int SDL_touch_locked = 0;
struct SDL_Touch
{
- SDL_TouchID id SDL_GUARDED_BY(SDL_touch_lock);
- SDL_TouchDeviceType type SDL_GUARDED_BY(SDL_touch_lock);
- int num_fingers SDL_GUARDED_BY(SDL_touch_lock);
- int max_fingers SDL_GUARDED_BY(SDL_touch_lock);
- SDL_Finger **fingers SDL_GUARDED_BY(SDL_touch_lock);
- char *name SDL_GUARDED_BY(SDL_touch_lock);
+ SDL_TouchID id SDL_GUARDED_BY(SDL_event_lock);
+ SDL_TouchDeviceType type SDL_GUARDED_BY(SDL_event_lock);
+ int num_fingers SDL_GUARDED_BY(SDL_event_lock);
+ int max_fingers SDL_GUARDED_BY(SDL_event_lock);
+ SDL_Finger **fingers SDL_GUARDED_BY(SDL_event_lock);
+ char *name SDL_GUARDED_BY(SDL_event_lock);
};
-static int SDL_num_touch SDL_GUARDED_BY(SDL_touch_lock) = 0;
-static SDL_Touch **SDL_touchDevices SDL_GUARDED_BY(SDL_touch_lock) = NULL;
+static int SDL_num_touch SDL_GUARDED_BY(SDL_event_lock) = 0;
+static SDL_Touch **SDL_touchDevices SDL_GUARDED_BY(SDL_event_lock) = NULL;
// for mapping touch events to mice
static bool finger_touching = false;
@@ -49,23 +48,22 @@ static SDL_TouchID track_touchid;
// Public functions
bool SDL_InitTouch(void)
{
- SDL_touch_lock = SDL_CreateMutex();
return true;
}
-static void SDL_LockTouch(void) SDL_ACQUIRE(SDL_touch_lock)
+static void SDL_LockTouch(void) SDL_ACQUIRE(SDL_event_lock)
{
- SDL_LockMutex(SDL_touch_lock);
+ SDL_LockMutex(SDL_event_lock);
++SDL_touch_locked;
}
-static void SDL_UnlockTouch(void) SDL_RELEASE(SDL_touch_lock)
+static void SDL_UnlockTouch(void) SDL_RELEASE(SDL_event_lock)
{
--SDL_touch_locked;
- SDL_UnlockMutex(SDL_touch_lock);
+ SDL_UnlockMutex(SDL_event_lock);
}
-static void SDL_AssertTouchLocked(void) SDL_ASSERT_CAPABILITY(SDL_touch_lock)
+static void SDL_AssertTouchLocked(void) SDL_ASSERT_CAPABILITY(SDL_event_lock)
{
SDL_assert(SDL_touch_locked > 0);
}
@@ -614,9 +612,6 @@ void SDL_QuitTouch(void)
SDL_touchDevices = NULL;
}
SDL_UnlockTouch();
-
- SDL_DestroyMutex(SDL_touch_lock);
- SDL_touch_lock = NULL;
}
int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, float scale)
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index 0a660c56336e5..4fd4a4711b69f 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -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
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 79c5997e21c63..22d92fac2d8b0 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -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;
}
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index b80fb6b6512c9..69e42b02094a1 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -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);
diff --git a/src/joystick/SDL_steam_virtual_gamepad.c b/src/joystick/SDL_steam_virtual_gamepad.c
index 7d1ef1a8909d0..1a6079c669c76 100644
--- a/src/joystick/SDL_steam_virtual_gamepad.c
+++ b/src/joystick/SDL_steam_virtual_gamepad.c
@@ -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)
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 76bce9006d762..d428d50bd9574 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -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
{
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index c8bca941aa5f3..2ab43b2c83189 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -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;
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index ede0d5efdc905..1c3cdf916fea0 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -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;
diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c
index 2655dbd830f30..a5c7be9c1ad4b 100644
--- a/src/joystick/virtual/SDL_virtualjoystick.c
+++ b/src/joystick/virtual/SDL_virtualjoystick.c
@@ -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)
{
diff --git a/src/sensor/SDL_sensor.c b/src/sensor/SDL_sensor.c
index d3eb58fbf4355..9091fb44c6299 100644
--- a/src/sensor/SDL_sensor.c
+++ b/src/sensor/SDL_sensor.c
@@ -51,14 +51,9 @@ static SDL_SensorDriver *SDL_sensor_drivers[] = {
#endif
};
-#ifndef SDL_THREAD_SAFETY_ANALYSIS
-static
-#endif
-SDL_Mutex *SDL_sensor_lock = NULL; // This needs to support recursive locks
-static SDL_AtomicInt SDL_sensor_lock_pending;
static int SDL_sensors_locked;
static bool SDL_sensors_initialized;
-static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL;
+static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_event_lock) = NULL;
#define CHECK_SENSOR_MAGIC(sensor, result) \
CHECK_PARAM(!SDL_ObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR)) { \
@@ -74,43 +69,14 @@ bool SDL_SensorsInitialized(void)
void SDL_LockSensors(void)
{
- (void)SDL_AtomicIncRef(&SDL_sensor_lock_pending);
- SDL_LockMutex(SDL_sensor_lock);
- (void)SDL_AtomicDecRef(&SDL_sensor_lock_pending);
-
+ SDL_LockMutex(SDL_event_lock);
++SDL_sensors_locked;
}
void SDL_UnlockSensors(void)
{
- bool last_unlock = false;
-
--SDL_sensors_locked;
-
- if (!SDL_sensors_initialized) {
- // NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks
- if (!SDL_sensors_locked && SDL_GetAtomicInt(&SDL_sensor_lock_pending) == 0) {
- last_unlock = true;
- }
- }
-
- /* The last unlock after sensors are uninitialized will cleanup the mutex,
- * allowing applications to lock sensors while reinitializing the system.
- */
- if (last_unlock) {
- SDL_Mutex *sensor_lock = SDL_sensor_lock;
-
- SDL_LockMutex(sensor_lock);
- {
- SDL_UnlockMutex(SDL_sensor_lock);
-
- SDL_sensor_lock = NULL;
- }
- SDL_UnlockMutex(sensor_lock);
- SDL_DestroyMutex(sensor_lock);
- } else {
- SDL_UnlockMutex(SDL_sensor_lock);
- }
+ SDL_UnlockMutex(SDL_event_lock);
}
bool SDL_SensorsLocked(void)
@@ -128,11 +94,6 @@ bool SDL_InitSensors(void)
int i;
bool status;
- // Create the sensor list lock
- if (SDL_sensor_lock == NULL) {
- SDL_sensor_lock = SDL_CreateMutex();
- }
-
if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) {
return false;
}
diff --git a/src/sensor/SDL_sensor_c.h b/src/sensor/SDL_sensor_c.h
index 90c05d4ec6385..ec6a138636401 100644
--- a/src/sensor/SDL_sensor_c.h
+++ b/src/sensor/SDL_sensor_c.h
@@ -23,10 +23,6 @@
#ifndef SDL_sensor_c_h_
#define SDL_sensor_c_h_
-#ifdef SDL_THREAD_SAFETY_ANALYSIS
-extern SDL_Mutex *SDL_sensor_lock;
-#endif
-
struct SDL_SensorDriver;
// Useful functions and variables from SDL_sensor.c
@@ -42,10 +38,10 @@ extern bool SDL_SensorsInitialized(void);
extern bool SDL_SensorsLocked(void);
// Make sure we currently have the sensors locked
-extern void SDL_AssertSensorsLocked(void) SDL_ASSERT_CAPABILITY(SDL_sensor_lock);
+extern void SDL_AssertSensorsLocked(void) SDL_ASSERT_CAPABILITY(SDL_event_lock);
-extern void SDL_LockSensors(void) SDL_ACQUIRE(SDL_sensor_lock);
-extern void SDL_UnlockSensors(void) SDL_RELEASE(SDL_sensor_lock);
+extern void SDL_LockSensors(void) SDL_ACQUIRE(SDL_event_lock);
+extern void SDL_UnlockSensors(void) SDL_RELEASE(SDL_event_lock);
// Function to return whether there are any sensors opened by the application
extern bool SDL_SensorsOpened(void);
diff --git a/src/sensor/SDL_syssensor.h b/src/sensor/SDL_syssensor.h
index 6c6ccf83c7ce3..7452d9d6ea958 100644
--- a/src/sensor/SDL_syssensor.h
+++ b/src/sensor/SDL_syssensor.h
@@ -26,8 +26,9 @@
// This is the system specific header for the SDL sensor API
#include "SDL_sensor_c.h"
+#include "../events/SDL_events_c.h"
-#define _guarded SDL_GUARDED_BY(SDL_sensor_lock)
+#define _guarded SDL_GUARDED_BY(SDL_event_lock)
// The SDL sensor structure
struct SDL_Sensor