Browse Source

Added support for clang thread-safety analysis

The annotations have been added to SDL_mutex.h and have been made public so applications can enable this for their own code.

Clang assumes that locking and unlocking can't fail, but SDL has the concept of a NULL mutex, so the mutex functions have been changed not to report errors if a mutex hasn't been initialized. We do have mutexes that might be accessed when they are NULL, notably in the event system, so this is an important change.

This commit cleans up a bunch of rare race conditions in the joystick and game controller code so now everything should be completely protected by the joystick lock.

To test this, change the compiler to "clang -Wthread-safety -Werror=thread-safety -DSDL_THREAD_SAFETY_ANALYSIS"
Sam Lantinga 2 years ago
parent
commit
5c29b58e95
41 changed files with 1611 additions and 1127 deletions
  1. 6 2
      include/SDL3/SDL_joystick.h
  2. 77 3
      include/SDL3/SDL_mutex.h
  3. 2 4
      src/SDL_assert.c
  4. 2 8
      src/SDL_log.c
  5. 2 2
      src/audio/SDL_audio.c
  6. 1 1
      src/dynapi/SDL_dynapi.h
  7. 81 107
      src/events/SDL_events.c
  8. 51 37
      src/haptic/SDL_haptic.c
  9. 6 0
      src/haptic/linux/SDL_syshaptic.c
  10. 610 421
      src/joystick/SDL_gamecontroller.c
  11. 438 331
      src/joystick/SDL_joystick.c
  12. 1 1
      src/joystick/SDL_joystick_c.h
  13. 41 37
      src/joystick/SDL_sysjoystick.h
  14. 2 0
      src/joystick/hidapi/SDL_hidapi_combined.c
  15. 7 0
      src/joystick/hidapi/SDL_hidapi_gamecube.c
  16. 2 0
      src/joystick/hidapi/SDL_hidapi_luna.c
  17. 4 0
      src/joystick/hidapi/SDL_hidapi_ps3.c
  18. 2 0
      src/joystick/hidapi/SDL_hidapi_ps4.c
  19. 3 1
      src/joystick/hidapi/SDL_hidapi_ps5.c
  20. 15 16
      src/joystick/hidapi/SDL_hidapi_rumble.c
  21. 7 4
      src/joystick/hidapi/SDL_hidapi_rumble.h
  22. 3 1
      src/joystick/hidapi/SDL_hidapi_shield.c
  23. 2 0
      src/joystick/hidapi/SDL_hidapi_stadia.c
  24. 2 0
      src/joystick/hidapi/SDL_hidapi_steam.c
  25. 4 2
      src/joystick/hidapi/SDL_hidapi_switch.c
  26. 3 1
      src/joystick/hidapi/SDL_hidapi_wii.c
  27. 2 0
      src/joystick/hidapi/SDL_hidapi_xbox360.c
  28. 2 0
      src/joystick/hidapi/SDL_hidapi_xbox360w.c
  29. 6 4
      src/joystick/hidapi/SDL_hidapi_xboxone.c
  30. 41 3
      src/joystick/hidapi/SDL_hidapijoystick.c
  31. 30 1
      src/joystick/linux/SDL_sysjoystick.c
  32. 40 13
      src/joystick/virtual/SDL_virtualjoystick.c
  33. 17 34
      src/sensor/SDL_sensor.c
  34. 5 5
      src/thread/generic/SDL_sysmutex.c
  35. 5 5
      src/thread/n3ds/SDL_sysmutex.c
  36. 18 18
      src/thread/ngage/SDL_sysmutex.cpp
  37. 25 22
      src/thread/psp/SDL_sysmutex.c
  38. 5 5
      src/thread/pthread/SDL_sysmutex.c
  39. 7 6
      src/thread/stdcpp/SDL_sysmutex.cpp
  40. 24 22
      src/thread/vita/SDL_sysmutex.c
  41. 10 10
      src/thread/windows/SDL_sysmutex.c

+ 6 - 2
include/SDL3/SDL_joystick.h

@@ -44,6 +44,7 @@
 #include <SDL3/SDL_stdinc.h>
 #include <SDL3/SDL_error.h>
 #include <SDL3/SDL_guid.h>
+#include <SDL3/SDL_mutex.h>
 
 #include <SDL3/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
@@ -66,6 +67,9 @@ extern "C" {
 /**
  * The joystick structure used to identify an SDL joystick
  */
+#ifdef SDL_THREAD_SAFETY_ANALYSIS
+extern SDL_mutex *SDL_joystick_lock;
+#endif
 struct _SDL_Joystick;
 typedef struct _SDL_Joystick SDL_Joystick;
 
@@ -131,7 +135,7 @@ typedef enum
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC void SDLCALL SDL_LockJoysticks(void);
+extern DECLSPEC void SDLCALL SDL_LockJoysticks(void) SDL_ACQUIRE(SDL_joystick_lock);
 
 
 /**
@@ -146,7 +150,7 @@ extern DECLSPEC void SDLCALL SDL_LockJoysticks(void);
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void);
+extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void) SDL_RELEASE(SDL_joystick_lock);
 
 /**
  * Count the number of joysticks attached to the system.

+ 77 - 3
include/SDL3/SDL_mutex.h

@@ -31,6 +31,80 @@
 #include <SDL3/SDL_stdinc.h>
 #include <SDL3/SDL_error.h>
 
+/******************************************************************************/
+/* Enable thread safety attributes only with clang.
+ * The attributes can be safely erased when compiling with other compilers.
+ */
+#if defined(SDL_THREAD_SAFETY_ANALYSIS) && \
+    defined(__clang__) && (!defined(SWIG))
+#define SDL_THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
+#else
+#define SDL_THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
+#endif
+
+#define SDL_CAPABILITY(x) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SDL_SCOPED_CAPABILITY \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define SDL_GUARDED_BY(x) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define SDL_PT_GUARDED_BY(x) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define SDL_ACQUIRED_BEFORE(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define SDL_ACQUIRED_AFTER(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define SDL_REQUIRES(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define SDL_REQUIRES_SHARED(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define SDL_ACQUIRE(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define SDL_ACQUIRE_SHARED(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define SDL_RELEASE(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define SDL_RELEASE_SHARED(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define SDL_RELEASE_GENERIC(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
+
+#define SDL_TRY_ACQUIRE(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define SDL_TRY_ACQUIRE_SHARED(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define SDL_EXCLUDES(...) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define SDL_ASSERT_CAPABILITY(x) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define SDL_ASSERT_SHARED_CAPABILITY(x) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define SDL_RETURN_CAPABILITY(x) \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define SDL_NO_THREAD_SAFETY_ANALYSIS \
+  SDL_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+/******************************************************************************/
+
+
 #include <SDL3/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
@@ -96,7 +170,7 @@ extern DECLSPEC SDL_mutex *SDLCALL SDL_CreateMutex(void);
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex);
+extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex) SDL_ACQUIRE(mutex);
 #define SDL_mutexP(m)   SDL_LockMutex(m)
 
 /**
@@ -119,7 +193,7 @@ extern DECLSPEC int SDLCALL SDL_LockMutex(SDL_mutex * mutex);
  * \sa SDL_LockMutex
  * \sa SDL_UnlockMutex
  */
-extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex);
+extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex) SDL_TRY_ACQUIRE(0, mutex);
 
 /**
  * Unlock the mutex.
@@ -138,7 +212,7 @@ extern DECLSPEC int SDLCALL SDL_TryLockMutex(SDL_mutex * mutex);
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex * mutex);
+extern DECLSPEC int SDLCALL SDL_UnlockMutex(SDL_mutex * mutex) SDL_RELEASE(mutex);
 #define SDL_mutexV(m)   SDL_UnlockMutex(m)
 
 /**

+ 2 - 4
src/SDL_assert.c

@@ -337,10 +337,8 @@ SDL_ReportAssertion(SDL_AssertData *data, const char *func, const char *file,
     }
     SDL_AtomicUnlock(&spinlock);
 
-    if (SDL_LockMutex(assertion_mutex) < 0) {
-        return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
-    }
-#endif
+    SDL_LockMutex(assertion_mutex);
+#endif /* !SDL_THREADS_DISABLED */
 
     /* doing this because Visual C is upset over assigning in the macro. */
     if (data->trigger_count == 0) {

+ 2 - 8
src/SDL_log.c

@@ -333,15 +333,9 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va
         }
     }
 
-    if (log_function_mutex) {
-        SDL_LockMutex(log_function_mutex);
-    }
-
+    SDL_LockMutex(log_function_mutex);
     SDL_log_function(SDL_log_userdata, category, priority, message);
-
-    if (log_function_mutex) {
-        SDL_UnlockMutex(log_function_mutex);
-    }
+    SDL_UnlockMutex(log_function_mutex);
 
     /* Free only if dynamically allocated */
     if (message != stack_buf) {

+ 2 - 2
src/audio/SDL_audio.c

@@ -269,14 +269,14 @@ static SDL_INLINE SDL_bool is_in_audio_device_thread(SDL_AudioDevice *device)
     return SDL_FALSE;
 }
 
-static void SDL_AudioLockDevice_Default(SDL_AudioDevice *device)
+static void SDL_AudioLockDevice_Default(SDL_AudioDevice *device) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang assumes recursive locks */
 {
     if (!is_in_audio_device_thread(device)) {
         SDL_LockMutex(device->mixer_lock);
     }
 }
 
-static void SDL_AudioUnlockDevice_Default(SDL_AudioDevice *device)
+static void SDL_AudioUnlockDevice_Default(SDL_AudioDevice *device) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang assumes recursive locks */
 {
     if (!is_in_audio_device_thread(device)) {
         SDL_UnlockMutex(device->mixer_lock);

+ 1 - 1
src/dynapi/SDL_dynapi.h

@@ -57,7 +57,7 @@
 #define SDL_DYNAMIC_API 0
 #elif defined(__riscos__) && __riscos__ /* probably not useful on RISC OS, since dlopen() can't be used when using static linking. */
 #define SDL_DYNAMIC_API 0
-#elif defined(__clang_analyzer__)
+#elif defined(__clang_analyzer__) || defined(SDL_THREAD_SAFETY_ANALYSIS)
 #define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */
 #elif defined(__VITA__)
 #define SDL_DYNAMIC_API 0 /* vitasdk doesn't support dynamic linking */

+ 81 - 107
src/events/SDL_events.c

@@ -517,9 +517,7 @@ void SDL_StopEventLoop(void)
     SDL_EventEntry *entry;
     SDL_SysWMEntry *wmmsg;
 
-    if (SDL_EventQ.lock) {
-        SDL_LockMutex(SDL_EventQ.lock);
-    }
+    SDL_LockMutex(SDL_EventQ.lock);
 
     SDL_EventQ.active = SDL_FALSE;
 
@@ -576,8 +574,9 @@ void SDL_StopEventLoop(void)
     }
     SDL_zero(SDL_EventOK);
 
+    SDL_UnlockMutex(SDL_EventQ.lock);
+
     if (SDL_EventQ.lock) {
-        SDL_UnlockMutex(SDL_EventQ.lock);
         SDL_DestroyMutex(SDL_EventQ.lock);
         SDL_EventQ.lock = NULL;
     }
@@ -621,9 +620,7 @@ int SDL_StartEventLoop(void)
 #endif
 
     SDL_EventQ.active = SDL_TRUE;
-    if (SDL_EventQ.lock) {
-        SDL_UnlockMutex(SDL_EventQ.lock);
-    }
+    SDL_UnlockMutex(SDL_EventQ.lock);
     return 0;
 }
 
@@ -717,17 +714,18 @@ static int SDL_SendWakeupEvent()
     if (_this == NULL || !_this->SendWakeupEvent) {
         return 0;
     }
-    if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
+
+    SDL_LockMutex(_this->wakeup_lock);
+    {
         if (_this->wakeup_window) {
             _this->SendWakeupEvent(_this, _this->wakeup_window);
 
             /* No more wakeup events needed until we enter a new wait */
             _this->wakeup_window = NULL;
         }
-        if (_this->wakeup_lock) {
-            SDL_UnlockMutex(_this->wakeup_lock);
-        }
     }
+    SDL_UnlockMutex(_this->wakeup_lock);
+
     return 0;
 }
 
@@ -739,16 +737,16 @@ static int SDL_PeepEventsInternal(SDL_Event *events, int numevents, SDL_eventact
 
     /* Lock the event queue */
     used = 0;
-    if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
+
+    SDL_LockMutex(SDL_EventQ.lock);
+    {
         /* Don't look after we've quit */
         if (!SDL_EventQ.active) {
-            if (SDL_EventQ.lock) {
-                SDL_UnlockMutex(SDL_EventQ.lock);
-            }
             /* We get a few spurious events at shutdown, so don't warn then */
             if (action == SDL_GETEVENT) {
                 SDL_SetError("The event system has been shut down");
             }
+            SDL_UnlockMutex(SDL_EventQ.lock);
             return -1;
         }
         if (action == SDL_ADDEVENT) {
@@ -817,12 +815,8 @@ static int SDL_PeepEventsInternal(SDL_Event *events, int numevents, SDL_eventact
                 }
             }
         }
-        if (SDL_EventQ.lock) {
-            SDL_UnlockMutex(SDL_EventQ.lock);
-        }
-    } else {
-        return SDL_SetError("Couldn't lock event queue");
     }
+    SDL_UnlockMutex(SDL_EventQ.lock);
 
     if (used > 0 && action == SDL_ADDEVENT) {
         SDL_SendWakeupEvent();
@@ -836,14 +830,12 @@ int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
     return SDL_PeepEventsInternal(events, numevents, action, minType, maxType, SDL_FALSE);
 }
 
-SDL_bool
-SDL_HasEvent(Uint32 type)
+SDL_bool SDL_HasEvent(Uint32 type)
 {
     return SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0;
 }
 
-SDL_bool
-SDL_HasEvents(Uint32 minType, Uint32 maxType)
+SDL_bool SDL_HasEvents(Uint32 minType, Uint32 maxType)
 {
     return SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0;
 }
@@ -870,12 +862,11 @@ void SDL_FlushEvents(Uint32 minType, Uint32 maxType)
 #endif
 
     /* Lock the event queue */
-    if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
+    SDL_LockMutex(SDL_EventQ.lock);
+    {
         /* Don't look after we've quit */
         if (!SDL_EventQ.active) {
-            if (SDL_EventQ.lock) {
-                SDL_UnlockMutex(SDL_EventQ.lock);
-            }
+            SDL_UnlockMutex(SDL_EventQ.lock);
             return;
         }
         for (entry = SDL_EventQ.head; entry; entry = next) {
@@ -885,10 +876,8 @@ void SDL_FlushEvents(Uint32 minType, Uint32 maxType)
                 SDL_CutEvent(entry);
             }
         }
-        if (SDL_EventQ.lock) {
-            SDL_UnlockMutex(SDL_EventQ.lock);
-        }
     }
+    SDL_UnlockMutex(SDL_EventQ.lock);
 }
 
 /* Run the system dependent event loops */
@@ -964,6 +953,7 @@ static int SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Eve
     SDL_bool need_periodic_poll = SDL_events_need_periodic_poll();
 
     for (;;) {
+        int status;
         /* Pump events on entry and each time we wake to ensure:
            a) All pending events are batch processed after waking up from a wait
            b) Waiting can be completely skipped if events are already available to be pumped
@@ -976,55 +966,55 @@ static int SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Eve
         SDL_bool add_sentinel = (SDL_AtomicGet(&SDL_sentinel_pending) == 0) ? SDL_TRUE : SDL_FALSE;
         SDL_PumpEventsInternal(add_sentinel);
 
-        if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
-            int status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
+        SDL_LockMutex(_this->wakeup_lock);
+        {
+            status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
             /* If status == 0 we are going to block so wakeup will be needed. */
             if (status == 0) {
                 _this->wakeup_window = wakeup_window;
             } else {
                 _this->wakeup_window = NULL;
             }
-            if (_this->wakeup_lock) {
-                SDL_UnlockMutex(_this->wakeup_lock);
-            }
-            if (status < 0) {
-                /* Got an error: return */
-                break;
-            }
-            if (status > 0) {
-                /* There is an event, we can return. */
-                return 1;
-            }
-            /* No events found in the queue, call WaitEventTimeout to wait for an event. */
-            if (timeoutNS > 0) {
-                Sint64 elapsed = SDL_GetTicksNS() - start;
-                if (elapsed >= timeoutNS) {
-                    /* Set wakeup_window to NULL without holding the lock. */
-                    _this->wakeup_window = NULL;
-                    return 0;
-                }
-                loop_timeoutNS = (timeoutNS - elapsed);
-            }
-            if (need_periodic_poll) {
-                if (loop_timeoutNS >= 0) {
-                    loop_timeoutNS = SDL_min(loop_timeoutNS, PERIODIC_POLL_INTERVAL_NS);
-                } else {
-                    loop_timeoutNS = PERIODIC_POLL_INTERVAL_NS;
-                }
+        }
+        SDL_UnlockMutex(_this->wakeup_lock);
+
+        if (status < 0) {
+            /* Got an error: return */
+            break;
+        }
+        if (status > 0) {
+            /* There is an event, we can return. */
+            return 1;
+        }
+        /* No events found in the queue, call WaitEventTimeout to wait for an event. */
+        if (timeoutNS > 0) {
+            Sint64 elapsed = SDL_GetTicksNS() - start;
+            if (elapsed >= timeoutNS) {
+                /* Set wakeup_window to NULL without holding the lock. */
+                _this->wakeup_window = NULL;
+                return 0;
             }
-            status = _this->WaitEventTimeout(_this, loop_timeoutNS);
-            /* Set wakeup_window to NULL without holding the lock. */
-            _this->wakeup_window = NULL;
-            if (status == 0 && need_periodic_poll && loop_timeoutNS == PERIODIC_POLL_INTERVAL_NS) {
-                /* We may have woken up to poll. Try again */
-                continue;
-            } else if (status <= 0) {
-                /* There is either an error or the timeout is elapsed: return */
-                return status;
+            loop_timeoutNS = (timeoutNS - elapsed);
+        }
+        if (need_periodic_poll) {
+            if (loop_timeoutNS >= 0) {
+                loop_timeoutNS = SDL_min(loop_timeoutNS, PERIODIC_POLL_INTERVAL_NS);
+            } else {
+                loop_timeoutNS = PERIODIC_POLL_INTERVAL_NS;
             }
-            /* An event was found and pumped into the SDL events queue. Continue the loop
-              to let SDL_PeepEvents pick it up .*/
         }
+        status = _this->WaitEventTimeout(_this, loop_timeoutNS);
+        /* Set wakeup_window to NULL without holding the lock. */
+        _this->wakeup_window = NULL;
+        if (status == 0 && need_periodic_poll && loop_timeoutNS == PERIODIC_POLL_INTERVAL_NS) {
+            /* We may have woken up to poll. Try again */
+            continue;
+        } else if (status <= 0) {
+            /* There is either an error or the timeout is elapsed: return */
+            return status;
+        }
+        /* An event was found and pumped into the SDL events queue. Continue the loop
+          to let SDL_PeepEvents pick it up .*/
     }
     return 0;
 }
@@ -1172,11 +1162,10 @@ int SDL_PushEvent(SDL_Event *event)
     }
 
     if (SDL_EventOK.callback || SDL_event_watchers_count > 0) {
-        if (SDL_event_watchers_lock == NULL || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+        SDL_LockMutex(SDL_event_watchers_lock);
+        {
             if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
-                if (SDL_event_watchers_lock) {
-                    SDL_UnlockMutex(SDL_event_watchers_lock);
-                }
+                SDL_UnlockMutex(SDL_event_watchers_lock);
                 return 0;
             }
 
@@ -1204,11 +1193,8 @@ int SDL_PushEvent(SDL_Event *event)
                     SDL_event_watchers_removed = SDL_FALSE;
                 }
             }
-
-            if (SDL_event_watchers_lock) {
-                SDL_UnlockMutex(SDL_event_watchers_lock);
-            }
         }
+        SDL_UnlockMutex(SDL_event_watchers_lock);
     }
 
     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
@@ -1220,32 +1206,25 @@ int SDL_PushEvent(SDL_Event *event)
 
 void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
 {
-    if (SDL_event_watchers_lock == NULL || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+    SDL_LockMutex(SDL_event_watchers_lock);
+    {
         /* Set filter and discard pending events */
         SDL_EventOK.callback = filter;
         SDL_EventOK.userdata = userdata;
         SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
-
-        if (SDL_event_watchers_lock) {
-            SDL_UnlockMutex(SDL_event_watchers_lock);
-        }
     }
+    SDL_UnlockMutex(SDL_event_watchers_lock);
 }
 
-SDL_bool
-SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
+SDL_bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
 {
     SDL_EventWatcher event_ok;
 
-    if (SDL_event_watchers_lock == NULL || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+    SDL_LockMutex(SDL_event_watchers_lock);
+    {
         event_ok = SDL_EventOK;
-
-        if (SDL_event_watchers_lock) {
-            SDL_UnlockMutex(SDL_event_watchers_lock);
-        }
-    } else {
-        SDL_zero(event_ok);
     }
+    SDL_UnlockMutex(SDL_event_watchers_lock);
 
     if (filter) {
         *filter = event_ok.callback;
@@ -1258,7 +1237,8 @@ SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
 
 void SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
 {
-    if (SDL_event_watchers_lock == NULL || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+    SDL_LockMutex(SDL_event_watchers_lock);
+    {
         SDL_EventWatcher *event_watchers;
 
         event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
@@ -1272,16 +1252,14 @@ void SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
             watcher->removed = SDL_FALSE;
             ++SDL_event_watchers_count;
         }
-
-        if (SDL_event_watchers_lock) {
-            SDL_UnlockMutex(SDL_event_watchers_lock);
-        }
     }
+    SDL_UnlockMutex(SDL_event_watchers_lock);
 }
 
 void SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
 {
-    if (SDL_event_watchers_lock == NULL || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+    SDL_LockMutex(SDL_event_watchers_lock);
+    {
         int i;
 
         for (i = 0; i < SDL_event_watchers_count; ++i) {
@@ -1298,16 +1276,14 @@ void SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
                 break;
             }
         }
-
-        if (SDL_event_watchers_lock) {
-            SDL_UnlockMutex(SDL_event_watchers_lock);
-        }
     }
+    SDL_UnlockMutex(SDL_event_watchers_lock);
 }
 
 void SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
 {
-    if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
+    SDL_LockMutex(SDL_EventQ.lock);
+    {
         SDL_EventEntry *entry, *next;
         for (entry = SDL_EventQ.head; entry; entry = next) {
             next = entry->next;
@@ -1315,10 +1291,8 @@ void SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
                 SDL_CutEvent(entry);
             }
         }
-        if (SDL_EventQ.lock) {
-            SDL_UnlockMutex(SDL_EventQ.lock);
-        }
     }
+    SDL_UnlockMutex(SDL_EventQ.lock);
 }
 
 Uint8 SDL_EventState(Uint32 type, int state)

+ 51 - 37
src/haptic/SDL_haptic.c

@@ -233,12 +233,17 @@ int SDL_JoystickIsHaptic(SDL_Joystick *joystick)
 {
     int ret;
 
-    /* Must be a valid joystick */
-    if (!SDL_PrivateJoystickValid(joystick)) {
-        return -1;
-    }
+    SDL_LockJoysticks();
+    {
+        /* Must be a valid joystick */
+        if (!SDL_PrivateJoystickValid(joystick)) {
+            SDL_UnlockJoysticks();
+            return -1;
+        }
 
-    ret = SDL_SYS_JoystickIsHaptic(joystick);
+        ret = SDL_SYS_JoystickIsHaptic(joystick);
+    }
+    SDL_UnlockJoysticks();
 
     if (ret > 0) {
         return SDL_TRUE;
@@ -265,44 +270,53 @@ SDL_HapticOpenFromJoystick(SDL_Joystick *joystick)
         return NULL;
     }
 
-    /* Must be a valid joystick */
-    if (!SDL_PrivateJoystickValid(joystick)) {
-        SDL_SetError("Haptic: Joystick isn't valid.");
-        return NULL;
-    }
+    SDL_LockJoysticks();
+    {
+        /* Must be a valid joystick */
+        if (!SDL_PrivateJoystickValid(joystick)) {
+            SDL_SetError("Haptic: Joystick isn't valid.");
+            SDL_UnlockJoysticks();
+            return NULL;
+        }
 
-    /* Joystick must be haptic */
-    if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
-        SDL_SetError("Haptic: Joystick isn't a haptic device.");
-        return NULL;
-    }
+        /* Joystick must be haptic */
+        if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
+            SDL_SetError("Haptic: Joystick isn't a haptic device.");
+            SDL_UnlockJoysticks();
+            return NULL;
+        }
 
-    hapticlist = SDL_haptics;
-    /* Check to see if joystick's haptic is already open */
-    while (hapticlist) {
-        if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick)) {
-            haptic = hapticlist;
-            ++haptic->ref_count;
-            return haptic;
+        hapticlist = SDL_haptics;
+        /* Check to see if joystick's haptic is already open */
+        while (hapticlist) {
+            if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick)) {
+                haptic = hapticlist;
+                ++haptic->ref_count;
+                SDL_UnlockJoysticks();
+                return haptic;
+            }
+            hapticlist = hapticlist->next;
         }
-        hapticlist = hapticlist->next;
-    }
 
-    /* Create the haptic device */
-    haptic = (SDL_Haptic *)SDL_malloc((sizeof *haptic));
-    if (haptic == NULL) {
-        SDL_OutOfMemory();
-        return NULL;
-    }
+        /* Create the haptic device */
+        haptic = (SDL_Haptic *)SDL_malloc((sizeof *haptic));
+        if (haptic == NULL) {
+            SDL_OutOfMemory();
+            SDL_UnlockJoysticks();
+            return NULL;
+        }
 
-    /* Initialize the haptic device */
-    SDL_memset(haptic, 0, sizeof(SDL_Haptic));
-    haptic->rumble_id = -1;
-    if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
-        SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed.");
-        SDL_free(haptic);
-        return NULL;
+        /* Initialize the haptic device */
+        SDL_memset(haptic, 0, sizeof(SDL_Haptic));
+        haptic->rumble_id = -1;
+        if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
+            SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed.");
+            SDL_free(haptic);
+            SDL_UnlockJoysticks();
+            return NULL;
+        }
     }
+    SDL_UnlockJoysticks();
 
     /* Add haptic to list */
     ++haptic->ref_count;

+ 6 - 0
src/haptic/linux/SDL_syshaptic.c

@@ -481,6 +481,8 @@ int SDL_SYS_HapticMouse(void)
 int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
 {
 #ifdef SDL_JOYSTICK_LINUX
+    SDL_AssertJoysticksLocked();
+
     if (joystick->driver != &SDL_LINUX_JoystickDriver) {
         return SDL_FALSE;
     }
@@ -497,6 +499,8 @@ int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
 int SDL_SYS_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
 {
 #ifdef SDL_JOYSTICK_LINUX
+    SDL_AssertJoysticksLocked();
+
     if (joystick->driver != &SDL_LINUX_JoystickDriver) {
         return 0;
     }
@@ -520,6 +524,8 @@ int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
     int ret;
     SDL_hapticlist_item *item;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->driver != &SDL_LINUX_JoystickDriver) {
         return -1;
     }

+ 610 - 421
src/joystick/SDL_gamecontroller.c

@@ -51,7 +51,7 @@
 #define SDL_CONTROLLER_SDKLE_FIELD_SIZE    SDL_strlen(SDL_CONTROLLER_SDKLE_FIELD)
 
 /* a list of currently opened game controllers */
-static SDL_GameController *SDL_gamecontrollers = NULL;
+static SDL_GameController *SDL_gamecontrollers SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
 
 typedef struct
 {
@@ -99,44 +99,53 @@ typedef enum
     SDL_CONTROLLER_MAPPING_PRIORITY_USER,
 } SDL_ControllerMappingPriority;
 
+#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
+
 typedef struct _ControllerMapping_t
 {
-    SDL_JoystickGUID guid;
-    char *name;
-    char *mapping;
-    SDL_ControllerMappingPriority priority;
-    struct _ControllerMapping_t *next;
+    SDL_JoystickGUID guid _guarded;
+    char *name _guarded;
+    char *mapping _guarded;
+    SDL_ControllerMappingPriority priority _guarded;
+    struct _ControllerMapping_t *next _guarded;
 } ControllerMapping_t;
 
+#undef _guarded
+
 static SDL_JoystickGUID s_zeroGUID;
-static ControllerMapping_t *s_pSupportedControllers = NULL;
-static ControllerMapping_t *s_pDefaultMapping = NULL;
-static ControllerMapping_t *s_pXInputMapping = NULL;
+static ControllerMapping_t *s_pSupportedControllers SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
+static ControllerMapping_t *s_pDefaultMapping SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
+static ControllerMapping_t *s_pXInputMapping SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
 static char gamecontroller_magic;
 
+#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
+
 /* The SDL game controller structure */
 struct _SDL_GameController
 {
-    const void *magic;
+    const void *magic _guarded;
 
-    SDL_Joystick *joystick; /* underlying joystick device */
-    int ref_count;
+    SDL_Joystick *joystick _guarded; /* underlying joystick device */
+    int ref_count _guarded;
 
-    const char *name;
-    ControllerMapping_t *mapping;
-    int num_bindings;
-    SDL_ExtendedGameControllerBind *bindings;
-    SDL_ExtendedGameControllerBind **last_match_axis;
-    Uint8 *last_hat_mask;
-    Uint64 guide_button_down;
+    const char *name _guarded;
+    ControllerMapping_t *mapping _guarded;
+    int num_bindings _guarded;
+    SDL_ExtendedGameControllerBind *bindings _guarded;
+    SDL_ExtendedGameControllerBind **last_match_axis _guarded;
+    Uint8 *last_hat_mask _guarded;
+    Uint64 guide_button_down _guarded;
 
-    struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
+    struct _SDL_GameController *next _guarded; /* pointer to next game controller we have allocated */
 };
 
+#undef _guarded
+
 #define CHECK_GAMECONTROLLER_MAGIC(gamecontroller, retval)                   \
     if (!gamecontroller || gamecontroller->magic != &gamecontroller_magic || \
         !SDL_PrivateJoystickValid(gamecontroller->joystick)) {               \
         SDL_InvalidParamError("gamecontroller");                             \
+        SDL_UnlockJoysticks();                                               \
         return retval;                                                       \
     }
 
@@ -237,7 +246,7 @@ static void HandleJoystickAxis(Uint64 timestamp, SDL_GameController *gamecontrol
     SDL_ExtendedGameControllerBind *last_match;
     SDL_ExtendedGameControllerBind *match = NULL;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
+    SDL_AssertJoysticksLocked();
 
     last_match = gamecontroller->last_match_axis[axis];
     for (i = 0; i < gamecontroller->num_bindings; ++i) {
@@ -290,7 +299,7 @@ static void HandleJoystickButton(Uint64 timestamp, SDL_GameController *gamecontr
 {
     int i;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
+    SDL_AssertJoysticksLocked();
 
     for (i = 0; i < gamecontroller->num_bindings; ++i) {
         SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
@@ -312,7 +321,7 @@ static void HandleJoystickHat(Uint64 timestamp, SDL_GameController *gamecontroll
     int i;
     Uint8 last_mask, changed_mask;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
+    SDL_AssertJoysticksLocked();
 
     last_mask = gamecontroller->last_hat_mask[hat];
     changed_mask = (last_mask ^ value);
@@ -347,8 +356,6 @@ static void RecenterGameController(SDL_GameController *gamecontroller)
     SDL_GameControllerAxis axis;
     Uint64 timestamp = SDL_GetTicksNS();
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
-
     for (button = (SDL_GameControllerButton)0; button < SDL_CONTROLLER_BUTTON_MAX; button++) {
         if (SDL_GameControllerGetButton(gamecontroller, button)) {
             SDL_PrivateGameControllerButton(timestamp, gamecontroller, button, SDL_RELEASED);
@@ -367,39 +374,41 @@ static void RecenterGameController(SDL_GameController *gamecontroller)
  */
 static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event *event)
 {
+    SDL_GameController *controller;
+
     switch (event->type) {
     case SDL_JOYAXISMOTION:
     {
-        SDL_GameController *controllerlist = SDL_gamecontrollers;
-        while (controllerlist) {
-            if (controllerlist->joystick->instance_id == event->jaxis.which) {
-                HandleJoystickAxis(event->common.timestamp, controllerlist, event->jaxis.axis, event->jaxis.value);
+        SDL_AssertJoysticksLocked();
+
+        for (controller = SDL_gamecontrollers; controller; controller = controller->next) {
+            if (controller->joystick->instance_id == event->jaxis.which) {
+                HandleJoystickAxis(event->common.timestamp, controller, event->jaxis.axis, event->jaxis.value);
                 break;
             }
-            controllerlist = controllerlist->next;
         }
     } break;
     case SDL_JOYBUTTONDOWN:
     case SDL_JOYBUTTONUP:
     {
-        SDL_GameController *controllerlist = SDL_gamecontrollers;
-        while (controllerlist) {
-            if (controllerlist->joystick->instance_id == event->jbutton.which) {
-                HandleJoystickButton(event->common.timestamp, controllerlist, event->jbutton.button, event->jbutton.state);
+        SDL_AssertJoysticksLocked();
+
+        for (controller = SDL_gamecontrollers; controller; controller = controller->next) {
+            if (controller->joystick->instance_id == event->jbutton.which) {
+                HandleJoystickButton(event->common.timestamp, controller, event->jbutton.button, event->jbutton.state);
                 break;
             }
-            controllerlist = controllerlist->next;
         }
     } break;
     case SDL_JOYHATMOTION:
     {
-        SDL_GameController *controllerlist = SDL_gamecontrollers;
-        while (controllerlist) {
-            if (controllerlist->joystick->instance_id == event->jhat.which) {
-                HandleJoystickHat(event->common.timestamp, controllerlist, event->jhat.hat, event->jhat.value);
+        SDL_AssertJoysticksLocked();
+
+        for (controller = SDL_gamecontrollers; controller; controller = controller->next) {
+            if (controller->joystick->instance_id == event->jhat.which) {
+                HandleJoystickHat(event->common.timestamp, controller, event->jhat.hat, event->jhat.value);
                 break;
             }
-            controllerlist = controllerlist->next;
         }
     } break;
     case SDL_JOYDEVICEADDED:
@@ -415,13 +424,13 @@ static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event *eve
     } break;
     case SDL_JOYDEVICEREMOVED:
     {
-        SDL_GameController *controllerlist = SDL_gamecontrollers;
-        while (controllerlist) {
-            if (controllerlist->joystick->instance_id == event->jdevice.which) {
-                RecenterGameController(controllerlist);
+        SDL_AssertJoysticksLocked();
+
+        for (controller = SDL_gamecontrollers; controller; controller = controller->next) {
+            if (controller->joystick->instance_id == event->jdevice.which) {
+                RecenterGameController(controller);
                 break;
             }
-            controllerlist = controllerlist->next;
         }
 
         /* We don't know if this was a game controller, so go ahead and send an event */
@@ -717,6 +726,8 @@ static ControllerMapping_t *SDL_PrivateMatchControllerMappingForGUID(SDL_Joystic
     ControllerMapping_t *mapping;
     Uint16 crc = 0;
 
+    SDL_AssertJoysticksLocked();
+
     if (match_crc) {
         SDL_GetJoystickGUIDInfo(guid, NULL, NULL, NULL, &crc);
     }
@@ -829,8 +840,7 @@ static const char *map_StringForControllerAxis[] = {
 /*
  * convert a string to its enum equivalent
  */
-SDL_GameControllerAxis
-SDL_GameControllerGetAxisFromString(const char *str)
+SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *str)
 {
     int entry;
 
@@ -889,8 +899,7 @@ static const char *map_StringForControllerButton[] = {
 /*
  * convert a string to its enum equivalent
  */
-SDL_GameControllerButton
-SDL_GameControllerGetButtonFromString(const char *str)
+SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *str)
 {
     int entry;
     if (str == NULL || str[0] == '\0') {
@@ -928,7 +937,7 @@ static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontro
     char half_axis_input = 0;
     char half_axis_output = 0;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
+    SDL_AssertJoysticksLocked();
 
     if (*szGameButton == '+' || *szGameButton == '-') {
         half_axis_output = *szGameButton++;
@@ -1023,8 +1032,6 @@ static void SDL_PrivateGameControllerParseControllerConfigString(SDL_GameControl
     int i = 0;
     const char *pchPos = pchString;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
-
     SDL_zeroa(szGameButton);
     SDL_zeroa(szJoystickButton);
 
@@ -1072,7 +1079,7 @@ static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, Con
 {
     int i;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, );
+    SDL_AssertJoysticksLocked();
 
     gamecontroller->name = pControllerMapping->name;
     gamecontroller->num_bindings = 0;
@@ -1189,23 +1196,25 @@ static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMappi
  */
 static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping)
 {
-    SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
-    while (gamecontrollerlist) {
-        if (gamecontrollerlist->mapping == pControllerMapping) {
-            /* Not really threadsafe.  Should this lock access within SDL_GameControllerEventWatcher? */
-            SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping);
+    SDL_GameController *controller;
+
+    SDL_AssertJoysticksLocked();
+
+    for (controller = SDL_gamecontrollers; controller; controller = controller->next) {
+        if (controller->mapping == pControllerMapping) {
+            SDL_PrivateLoadButtonMapping(controller, pControllerMapping);
 
             {
                 SDL_Event event;
 
                 event.type = SDL_CONTROLLERDEVICEREMAPPED;
                 event.common.timestamp = 0;
-                event.cdevice.which = gamecontrollerlist->joystick->instance_id;
+                event.cdevice.which = controller->joystick->instance_id;
                 SDL_PushEvent(&event);
             }
         }
 
-        gamecontrollerlist = gamecontrollerlist->next;
+        controller = controller->next;
     }
 }
 
@@ -1219,6 +1228,8 @@ static ControllerMapping_t *SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID,
     ControllerMapping_t *pControllerMapping;
     Uint16 crc;
 
+    SDL_AssertJoysticksLocked();
+
     pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString);
     if (pchName == NULL) {
         SDL_SetError("Couldn't parse name from %s", mappingString);
@@ -1324,6 +1335,8 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const
 {
     ControllerMapping_t *mapping;
 
+    SDL_AssertJoysticksLocked();
+
     mapping = SDL_PrivateGetControllerMappingForGUID(guid);
 #ifdef __LINUX__
     if (mapping == NULL && name) {
@@ -1430,11 +1443,10 @@ static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
     SDL_JoystickGUID guid;
     ControllerMapping_t *mapping;
 
-    SDL_LockJoysticks();
+    SDL_AssertJoysticksLocked();
 
     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
-        SDL_UnlockJoysticks();
         return NULL;
     }
 
@@ -1450,7 +1462,6 @@ static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
         }
     }
 
-    SDL_UnlockJoysticks();
     return mapping;
 }
 
@@ -1536,6 +1547,8 @@ static int SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_Co
     SDL_bool existing = SDL_FALSE;
     ControllerMapping_t *pControllerMapping;
 
+    SDL_AssertJoysticksLocked();
+
     if (mappingString == NULL) {
         return SDL_InvalidParamError("mappingString");
     }
@@ -1636,7 +1649,15 @@ static int SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_Co
  */
 int SDL_GameControllerAddMapping(const char *mappingString)
 {
-    return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
+    int retval;
+
+    SDL_LockJoysticks();
+    {
+        retval = SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API);
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -1645,14 +1666,20 @@ int SDL_GameControllerAddMapping(const char *mappingString)
 int SDL_GameControllerNumMappings(void)
 {
     int num_mappings = 0;
-    ControllerMapping_t *mapping;
 
-    for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
-        if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
-            continue;
+    SDL_LockJoysticks();
+    {
+        ControllerMapping_t *mapping;
+
+        for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
+            if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
+                continue;
+            }
+            ++num_mappings;
         }
-        ++num_mappings;
     }
+    SDL_UnlockJoysticks();
+
     return num_mappings;
 }
 
@@ -1666,6 +1693,8 @@ static char *CreateMappingString(ControllerMapping_t *mapping, SDL_JoystickGUID
     size_t needed;
     const char *platform = SDL_GetPlatform();
 
+    SDL_AssertJoysticksLocked();
+
     SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
 
     /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
@@ -1709,48 +1738,71 @@ static char *CreateMappingString(ControllerMapping_t *mapping, SDL_JoystickGUID
 /*
  *  Get the mapping at a particular index.
  */
-char *
-SDL_GameControllerMappingForIndex(int mapping_index)
+char *SDL_GameControllerMappingForIndex(int mapping_index)
 {
-    ControllerMapping_t *mapping;
+    char *retval = NULL;
 
-    for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
-        if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
-            continue;
-        }
-        if (mapping_index == 0) {
-            return CreateMappingString(mapping, mapping->guid);
+    SDL_LockJoysticks();
+    {
+        ControllerMapping_t *mapping;
+
+        for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) {
+            if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) {
+                continue;
+            }
+            if (mapping_index == 0) {
+                retval = CreateMappingString(mapping, mapping->guid);
+                break;
+            }
+            --mapping_index;
         }
-        --mapping_index;
     }
-    SDL_SetError("Mapping not available");
-    return NULL;
+    SDL_UnlockJoysticks();
+
+    if (retval == NULL) {
+        SDL_SetError("Mapping not available");
+    }
+    return retval;
 }
 
 /*
  * Get the mapping string for this GUID
  */
-char *
-SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
+char *SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
 {
-    ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(guid);
-    if (mapping) {
-        return CreateMappingString(mapping, guid);
-    } else {
-        SDL_SetError("Mapping not available");
+    char *retval;
+
+    SDL_LockJoysticks();
+    {
+        ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(guid);
+        if (mapping) {
+            retval = CreateMappingString(mapping, guid);
+        } else {
+            SDL_SetError("Mapping not available");
+            retval = NULL;
+        }
     }
-    return NULL;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Get the mapping string for this device
  */
-char *
-SDL_GameControllerMapping(SDL_GameController *gamecontroller)
+char *SDL_GameControllerMapping(SDL_GameController *gamecontroller)
 {
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+    char *retval;
 
-    return CreateMappingString(gamecontroller->mapping, gamecontroller->joystick->guid);
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+
+        retval = CreateMappingString(gamecontroller->mapping, gamecontroller->joystick->guid);
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 static void SDL_GameControllerLoadHints()
@@ -1809,6 +1861,9 @@ int SDL_GameControllerInitMappings(void)
     char szControllerMapPath[1024];
     int i = 0;
     const char *pMappingString = NULL;
+
+    SDL_AssertJoysticksLocked();
+
     pMappingString = s_ControllerMappings[i];
     while (pMappingString) {
         SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
@@ -1856,38 +1911,49 @@ int SDL_GameControllerInit(void)
 /*
  * Get the implementation dependent name of a controller
  */
-const char *
-SDL_GameControllerNameForIndex(int joystick_index)
+const char *SDL_GameControllerNameForIndex(int joystick_index)
 {
-    ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(joystick_index);
-    if (pSupportedController != NULL) {
-        if (SDL_strcmp(pSupportedController->name, "*") == 0) {
-            return SDL_JoystickNameForIndex(joystick_index);
-        } else {
-            return pSupportedController->name;
+    const char *retval = NULL;
+
+    SDL_LockJoysticks();
+    {
+        ControllerMapping_t *mapping = SDL_PrivateGetControllerMapping(joystick_index);
+        if (mapping != NULL) {
+            if (SDL_strcmp(mapping->name, "*") == 0) {
+                retval = SDL_JoystickNameForIndex(joystick_index);
+            } else {
+                retval = mapping->name;
+            }
         }
     }
-    return NULL;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Get the implementation dependent path of a controller
  */
-const char *
-SDL_GameControllerPathForIndex(int joystick_index)
+const char *SDL_GameControllerPathForIndex(int joystick_index)
 {
-    ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(joystick_index);
-    if (pSupportedController != NULL) {
-        return SDL_JoystickPathForIndex(joystick_index);
+    const char *retval = NULL;
+
+    SDL_LockJoysticks();
+    {
+        ControllerMapping_t *mapping = SDL_PrivateGetControllerMapping(joystick_index);
+        if (mapping != NULL) {
+            retval = SDL_JoystickPathForIndex(joystick_index);
+        }
     }
-    return NULL;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
  *  Get the type of a game controller.
  */
-SDL_GameControllerType
-SDL_GameControllerTypeForIndex(int joystick_index)
+SDL_GameControllerType SDL_GameControllerTypeForIndex(int joystick_index)
 {
     return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetDeviceGUID(joystick_index), SDL_JoystickNameForIndex(joystick_index));
 }
@@ -1897,58 +1963,71 @@ SDL_GameControllerTypeForIndex(int joystick_index)
  *  This can be called before any controllers are opened.
  *  If no mapping can be found, this function returns NULL.
  */
-char *
-SDL_GameControllerMappingForDeviceIndex(int joystick_index)
+char *SDL_GameControllerMappingForDeviceIndex(int joystick_index)
 {
-    char *pMappingString = NULL;
-    ControllerMapping_t *mapping;
+    char *retval = NULL;
 
     SDL_LockJoysticks();
-    mapping = SDL_PrivateGetControllerMapping(joystick_index);
-    if (mapping) {
-        SDL_JoystickGUID guid;
-        char pchGUID[33];
-        size_t needed;
-        guid = SDL_JoystickGetDeviceGUID(joystick_index);
-        SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
-        /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
-        needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
-        pMappingString = SDL_malloc(needed);
-        if (pMappingString == NULL) {
-            SDL_OutOfMemory();
-            SDL_UnlockJoysticks();
-            return NULL;
+    {
+        ControllerMapping_t *mapping = SDL_PrivateGetControllerMapping(joystick_index);
+        if (mapping != NULL) {
+            SDL_JoystickGUID guid;
+            char pchGUID[33];
+            size_t needed;
+            guid = SDL_JoystickGetDeviceGUID(joystick_index);
+            SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
+            /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
+            needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
+            retval = (char *)SDL_malloc(needed);
+            if (retval != NULL) {
+                (void)SDL_snprintf(retval, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
+            } else {
+                SDL_OutOfMemory();
+            }
         }
-        (void)SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
     }
     SDL_UnlockJoysticks();
-    return pMappingString;
+    return retval;
 }
 
 /*
  * Return 1 if the joystick with this name and GUID is a supported controller
  */
-SDL_bool
-SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
+SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
 {
-    ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
-    if (pSupportedController) {
-        return SDL_TRUE;
+    SDL_bool retval;
+
+    SDL_LockJoysticks();
+    {
+        if (SDL_PrivateGetControllerMappingForNameAndGUID(name, guid) != NULL) {
+            retval = SDL_TRUE;
+        } else {
+            retval = SDL_FALSE;
+        }
     }
-    return SDL_FALSE;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Return 1 if the joystick at this device index is a supported controller
  */
-SDL_bool
-SDL_IsGameController(int joystick_index)
+SDL_bool SDL_IsGameController(int joystick_index)
 {
-    ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(joystick_index);
-    if (pSupportedController != NULL) {
-        return SDL_TRUE;
+    SDL_bool retval;
+
+    SDL_LockJoysticks();
+    {
+        if (SDL_PrivateGetControllerMapping(joystick_index) != NULL) {
+            retval = SDL_TRUE;
+        } else {
+            retval = SDL_FALSE;
+        }
     }
-    return SDL_FALSE;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 #if defined(__LINUX__)
@@ -2050,8 +2129,7 @@ SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
  *
  * This function returns a controller identifier, or NULL if an error occurred.
  */
-SDL_GameController *
-SDL_GameControllerOpen(int joystick_index)
+SDL_GameController *SDL_GameControllerOpen(int joystick_index)
 {
     SDL_JoystickID instance_id;
     SDL_GameController *gamecontroller;
@@ -2144,86 +2222,101 @@ void SDL_GameControllerUpdate(void)
 /**
  *  Return whether a game controller has a given axis
  */
-SDL_bool
-SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
+SDL_bool SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
 {
     SDL_GameControllerButtonBind bind;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, SDL_FALSE);
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, SDL_FALSE);
+
+        bind = SDL_GameControllerGetBindForAxis(gamecontroller, axis);
+    }
+    SDL_UnlockJoysticks();
 
-    bind = SDL_GameControllerGetBindForAxis(gamecontroller, axis);
     return (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE;
 }
 
 /*
  * Get the current state of an axis control on a controller
  */
-Sint16
-SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
+Sint16 SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
 {
-    int i;
+    Sint16 retval = 0;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, 0);
+    SDL_LockJoysticks();
+    {
+        int i;
 
-    for (i = 0; i < gamecontroller->num_bindings; ++i) {
-        SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
-        if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
-            int value = 0;
-            SDL_bool valid_input_range;
-            SDL_bool valid_output_range;
-
-            if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
-                value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
-                if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
-                    valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
-                } else {
-                    valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
-                }
-                if (valid_input_range) {
-                    if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
-                        float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
-                        value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, 0);
+
+        for (i = 0; i < gamecontroller->num_bindings; ++i) {
+            SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
+            if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
+                int value = 0;
+                SDL_bool valid_input_range;
+                SDL_bool valid_output_range;
+
+                if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
+                    value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
+                    if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
+                        valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
+                    } else {
+                        valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
+                    }
+                    if (valid_input_range) {
+                        if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) {
+                            float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min);
+                            value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min));
+                        }
+                    } else {
+                        value = 0;
+                    }
+                } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
+                    value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
+                    if (value == SDL_PRESSED) {
+                        value = binding->output.axis.axis_max;
+                    }
+                } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
+                    int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
+                    if (hat_mask & binding->input.hat.hat_mask) {
+                        value = binding->output.axis.axis_max;
                     }
-                } else {
-                    value = 0;
                 }
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
-                value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
-                if (value == SDL_PRESSED) {
-                    value = binding->output.axis.axis_max;
+
+                if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
+                    valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
+                } else {
+                    valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
                 }
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
-                int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
-                if (hat_mask & binding->input.hat.hat_mask) {
-                    value = binding->output.axis.axis_max;
+                /* If the value is zero, there might be another binding that makes it non-zero */
+                if (value != 0 && valid_output_range) {
+                    retval = (Sint16)value;
+                    break;
                 }
             }
-
-            if (binding->output.axis.axis_min < binding->output.axis.axis_max) {
-                valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max);
-            } else {
-                valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min);
-            }
-            /* If the value is zero, there might be another binding that makes it non-zero */
-            if (value != 0 && valid_output_range) {
-                return (Sint16)value;
-            }
         }
     }
-    return 0;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
  *  Return whether a game controller has a given button
  */
-SDL_bool
-SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
+SDL_bool SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
 {
     SDL_GameControllerButtonBind bind;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, SDL_FALSE);
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, SDL_FALSE);
+
+        bind = SDL_GameControllerGetBindForButton(gamecontroller, button);
+    }
+    SDL_UnlockJoysticks();
 
-    bind = SDL_GameControllerGetBindForButton(gamecontroller, button);
     return (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE;
 }
 
@@ -2232,38 +2325,49 @@ SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControll
  */
 Uint8 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
 {
-    int i;
-
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, 0);
+    Uint8 retval = SDL_RELEASED;
 
-    for (i = 0; i < gamecontroller->num_bindings; ++i) {
-        SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
-        if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
-            if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
-                SDL_bool valid_input_range;
-
-                int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
-                int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
-                if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
-                    valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
-                    if (valid_input_range) {
-                        return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
-                    }
-                } else {
-                    valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
-                    if (valid_input_range) {
-                        return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
+    SDL_LockJoysticks();
+    {
+        int i;
+
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, 0);
+
+        for (i = 0; i < gamecontroller->num_bindings; ++i) {
+            SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
+            if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
+                if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
+                    SDL_bool valid_input_range;
+
+                    int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis);
+                    int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2;
+                    if (binding->input.axis.axis_min < binding->input.axis.axis_max) {
+                        valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max);
+                        if (valid_input_range) {
+                            retval = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED;
+                            break;
+                        }
+                    } else {
+                        valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min);
+                        if (valid_input_range) {
+                            retval = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED;
+                            break;
+                        }
                     }
+                } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
+                    retval = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
+                    break;
+                } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
+                    int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
+                    retval = (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
+                    break;
                 }
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
-                return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button);
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
-                int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat);
-                return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED;
             }
         }
     }
-    return SDL_RELEASED;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
@@ -2271,12 +2375,18 @@ Uint8 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameCo
  */
 int SDL_GameControllerGetNumTouchpads(SDL_GameController *gamecontroller)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+    int retval = 0;
 
-    if (joystick) {
-        return joystick->ntouchpads;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            retval = joystick->ntouchpads;
+        }
     }
-    return 0;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
@@ -2284,12 +2394,22 @@ int SDL_GameControllerGetNumTouchpads(SDL_GameController *gamecontroller)
  */
 int SDL_GameControllerGetNumTouchpadFingers(SDL_GameController *gamecontroller, int touchpad)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+    int retval = 0;
 
-    if (joystick && touchpad >= 0 && touchpad < joystick->ntouchpads) {
-        return joystick->touchpads[touchpad].nfingers;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            if (touchpad >= 0 && touchpad < joystick->ntouchpads) {
+                retval = joystick->touchpads[touchpad].nfingers;
+            } else {
+                retval = SDL_InvalidParamError("touchpad");
+            }
+        }
     }
-    return 0;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
@@ -2297,55 +2417,66 @@ int SDL_GameControllerGetNumTouchpadFingers(SDL_GameController *gamecontroller,
  */
 int SDL_GameControllerGetTouchpadFinger(SDL_GameController *gamecontroller, int touchpad, int finger, Uint8 *state, float *x, float *y, float *pressure)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+    int retval = -1;
 
-    if (joystick) {
-        if (touchpad >= 0 && touchpad < joystick->ntouchpads) {
-            SDL_JoystickTouchpadInfo *touchpad_info = &joystick->touchpads[touchpad];
-            if (finger >= 0 && finger < touchpad_info->nfingers) {
-                SDL_JoystickTouchpadFingerInfo *info = &touchpad_info->fingers[finger];
-
-                if (state) {
-                    *state = info->state;
-                }
-                if (x) {
-                    *x = info->x;
-                }
-                if (y) {
-                    *y = info->y;
-                }
-                if (pressure) {
-                    *pressure = info->pressure;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            if (touchpad >= 0 && touchpad < joystick->ntouchpads) {
+                SDL_JoystickTouchpadInfo *touchpad_info = &joystick->touchpads[touchpad];
+                if (finger >= 0 && finger < touchpad_info->nfingers) {
+                    SDL_JoystickTouchpadFingerInfo *info = &touchpad_info->fingers[finger];
+
+                    if (state) {
+                        *state = info->state;
+                    }
+                    if (x) {
+                        *x = info->x;
+                    }
+                    if (y) {
+                        *y = info->y;
+                    }
+                    if (pressure) {
+                        *pressure = info->pressure;
+                    }
+                    retval = 0;
+                } else {
+                    retval = SDL_InvalidParamError("finger");
                 }
-                return 0;
             } else {
-                return SDL_InvalidParamError("finger");
+                retval = SDL_InvalidParamError("touchpad");
             }
-        } else {
-            return SDL_InvalidParamError("touchpad");
         }
-    } else {
-        return SDL_InvalidParamError("gamecontroller");
     }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
  *  Return whether a game controller has a particular sensor.
  */
-SDL_bool
-SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType type)
+SDL_bool SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType type)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
-    int i;
+    SDL_bool retval = SDL_FALSE;
 
-    if (joystick) {
-        for (i = 0; i < joystick->nsensors; ++i) {
-            if (joystick->sensors[i].type == type) {
-                return SDL_TRUE;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            int i;
+            for (i = 0; i < joystick->nsensors; ++i) {
+                if (joystick->sensors[i].type == type) {
+                    retval = SDL_TRUE;
+                    break;
+                }
             }
         }
     }
-    return SDL_FALSE;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -2353,41 +2484,47 @@ SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType t
  */
 int SDL_GameControllerSetSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type, SDL_bool enabled)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
-    int i;
-
-    if (joystick == NULL) {
-        return -1;
-    }
-
-    for (i = 0; i < joystick->nsensors; ++i) {
-        SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
-
-        if (sensor->type == type) {
-            if (sensor->enabled == enabled) {
-                return 0;
-            }
-
-            if (enabled) {
-                if (joystick->nsensors_enabled == 0) {
-                    if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) {
-                        return -1;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            int i;
+            for (i = 0; i < joystick->nsensors; ++i) {
+                SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
+
+                if (sensor->type == type) {
+                    if (sensor->enabled == enabled) {
+                        SDL_UnlockJoysticks();
+                        return 0;
                     }
-                }
-                ++joystick->nsensors_enabled;
-            } else {
-                if (joystick->nsensors_enabled == 1) {
-                    if (joystick->driver->SetSensorsEnabled(joystick, SDL_FALSE) < 0) {
-                        return -1;
+
+                    if (enabled) {
+                        if (joystick->nsensors_enabled == 0) {
+                            if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) {
+                                SDL_UnlockJoysticks();
+                                return -1;
+                            }
+                        }
+                        ++joystick->nsensors_enabled;
+                    } else {
+                        if (joystick->nsensors_enabled == 1) {
+                            if (joystick->driver->SetSensorsEnabled(joystick, SDL_FALSE) < 0) {
+                                SDL_UnlockJoysticks();
+                                return -1;
+                            }
+                        }
+                        --joystick->nsensors_enabled;
                     }
+
+                    sensor->enabled = enabled;
+                    SDL_UnlockJoysticks();
+                    return 0;
                 }
-                --joystick->nsensors_enabled;
             }
-
-            sensor->enabled = enabled;
-            return 0;
         }
     }
+    SDL_UnlockJoysticks();
+
     return SDL_Unsupported();
 }
 
@@ -2396,17 +2533,24 @@ int SDL_GameControllerSetSensorEnabled(SDL_GameController *gamecontroller, SDL_S
  */
 SDL_bool SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
-    int i;
+    SDL_bool retval = SDL_FALSE;
 
-    if (joystick) {
-        for (i = 0; i < joystick->nsensors; ++i) {
-            if (joystick->sensors[i].type == type) {
-                return joystick->sensors[i].enabled;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            int i;
+            for (i = 0; i < joystick->nsensors; ++i) {
+                if (joystick->sensors[i].type == type) {
+                    retval = joystick->sensors[i].enabled;
+                    break;
+                }
             }
         }
     }
-    return SDL_FALSE;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -2414,21 +2558,26 @@ SDL_bool SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, S
  */
 float SDL_GameControllerGetSensorDataRate(SDL_GameController *gamecontroller, SDL_SensorType type)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
-    int i;
+    float retval = 0.0f;
 
-    if (joystick == NULL) {
-        return 0.0f;
-    }
-
-    for (i = 0; i < joystick->nsensors; ++i) {
-        SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
-
-        if (sensor->type == type) {
-            return sensor->rate;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            int i;
+            for (i = 0; i < joystick->nsensors; ++i) {
+                SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
+
+                if (sensor->type == type) {
+                    retval = sensor->rate;
+                    break;
+                }
+            }
         }
     }
-    return 0.0f;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -2436,39 +2585,48 @@ float SDL_GameControllerGetSensorDataRate(SDL_GameController *gamecontroller, SD
  */
 int SDL_GameControllerGetSensorData(SDL_GameController *gamecontroller, SDL_SensorType type, float *data, int num_values)
 {
-    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
-    int i;
-
-    if (joystick == NULL) {
-        return -1;
-    }
-
-    for (i = 0; i < joystick->nsensors; ++i) {
-        SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
-
-        if (sensor->type == type) {
-            num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
-            SDL_memcpy(data, sensor->data, num_values * sizeof(*data));
-            return 0;
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
+        if (joystick) {
+            int i;
+            for (i = 0; i < joystick->nsensors; ++i) {
+                SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
+
+                if (sensor->type == type) {
+                    num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
+                    SDL_memcpy(data, sensor->data, num_values * sizeof(*data));
+                    SDL_UnlockJoysticks();
+                    return 0;
+                }
+            }
         }
     }
+    SDL_UnlockJoysticks();
+
     return SDL_Unsupported();
 }
 
-const char *
-SDL_GameControllerName(SDL_GameController *gamecontroller)
+const char *SDL_GameControllerName(SDL_GameController *gamecontroller)
 {
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+    const char *retval = NULL;
 
-    if (SDL_strcmp(gamecontroller->name, "*") == 0) {
-        return SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller));
-    } else {
-        return gamecontroller->name;
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+
+        if (SDL_strcmp(gamecontroller->name, "*") == 0) {
+            retval = SDL_JoystickName(gamecontroller->joystick);
+        } else {
+            retval = gamecontroller->name;
+        }
     }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
-const char *
-SDL_GameControllerPath(SDL_GameController *gamecontroller)
+const char *SDL_GameControllerPath(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2478,8 +2636,7 @@ SDL_GameControllerPath(SDL_GameController *gamecontroller)
     return SDL_JoystickPath(joystick);
 }
 
-SDL_GameControllerType
-SDL_GameControllerGetType(SDL_GameController *gamecontroller)
+SDL_GameControllerType SDL_GameControllerGetType(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2512,8 +2669,7 @@ void SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller, int pl
     SDL_JoystickSetPlayerIndex(joystick, player_index);
 }
 
-Uint16
-SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
+Uint16 SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2523,8 +2679,7 @@ SDL_GameControllerGetVendor(SDL_GameController *gamecontroller)
     return SDL_JoystickGetVendor(joystick);
 }
 
-Uint16
-SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
+Uint16 SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2534,8 +2689,7 @@ SDL_GameControllerGetProduct(SDL_GameController *gamecontroller)
     return SDL_JoystickGetProduct(joystick);
 }
 
-Uint16
-SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
+Uint16 SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2545,8 +2699,7 @@ SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
     return SDL_JoystickGetProductVersion(joystick);
 }
 
-Uint16
-SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller)
+Uint16 SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2556,8 +2709,7 @@ SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller)
     return SDL_JoystickGetFirmwareVersion(joystick);
 }
 
-const char *
-SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
+const char * SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2571,30 +2723,38 @@ SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
  * Return if the controller in question is currently attached to the system,
  *  \return 0 if not plugged in, 1 if still present.
  */
-SDL_bool
-SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
+SDL_bool SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
 {
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, SDL_FALSE);
+    SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
-    return SDL_JoystickGetAttached(gamecontroller->joystick);
+    if (joystick == NULL) {
+        return SDL_FALSE;
+    }
+    return SDL_JoystickGetAttached(joystick);
 }
 
 /*
  * Get the joystick for this controller
  */
-SDL_Joystick *
-SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
+SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller)
 {
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+    SDL_Joystick *joystick;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
 
-    return gamecontroller->joystick;
+        joystick = gamecontroller->joystick;
+    }
+    SDL_UnlockJoysticks();
+
+    return joystick;
 }
 
 /*
  * Return the SDL_GameController associated with an instance id.
  */
-SDL_GameController *
-SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
+SDL_GameController *SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
 {
     SDL_GameController *gamecontroller;
 
@@ -2616,11 +2776,18 @@ SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
  */
 SDL_GameController *SDL_GameControllerFromPlayerIndex(int player_index)
 {
-    SDL_Joystick *joystick = SDL_JoystickFromPlayerIndex(player_index);
-    if (joystick) {
-        return SDL_GameControllerFromInstanceID(joystick->instance_id);
+    SDL_GameController *retval = NULL;
+
+    SDL_LockJoysticks();
+    {
+        SDL_Joystick *joystick = SDL_JoystickFromPlayerIndex(player_index);
+        if (joystick) {
+            retval = SDL_GameControllerFromInstanceID(joystick->instance_id);
+        }
     }
-    return NULL;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -2628,32 +2795,36 @@ SDL_GameController *SDL_GameControllerFromPlayerIndex(int player_index)
  */
 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
 {
-    int i;
     SDL_GameControllerButtonBind bind;
-    SDL_zero(bind);
-
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, bind);
 
-    if (axis == SDL_CONTROLLER_AXIS_INVALID) {
-        return bind;
-    }
+    SDL_zero(bind);
 
-    for (i = 0; i < gamecontroller->num_bindings; ++i) {
-        SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
-        if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
-            bind.bindType = binding->inputType;
-            if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
-                /* FIXME: There might be multiple axes bound now that we have axis ranges... */
-                bind.value.axis = binding->input.axis.axis;
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
-                bind.value.button = binding->input.button;
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
-                bind.value.hat.hat = binding->input.hat.hat;
-                bind.value.hat.hat_mask = binding->input.hat.hat_mask;
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, bind);
+
+        if (axis != SDL_CONTROLLER_AXIS_INVALID) {
+            int i;
+            for (i = 0; i < gamecontroller->num_bindings; ++i) {
+                SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
+                if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) {
+                    bind.bindType = binding->inputType;
+                    if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
+                        /* FIXME: There might be multiple axes bound now that we have axis ranges... */
+                        bind.value.axis = binding->input.axis.axis;
+                    } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
+                        bind.value.button = binding->input.button;
+                    } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
+                        bind.value.hat.hat = binding->input.hat.hat;
+                        bind.value.hat.hat_mask = binding->input.hat.hat_mask;
+                    }
+                    break;
+                }
             }
-            break;
         }
     }
+    SDL_UnlockJoysticks();
+
     return bind;
 }
 
@@ -2662,31 +2833,35 @@ SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController
  */
 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
 {
-    int i;
     SDL_GameControllerButtonBind bind;
-    SDL_zero(bind);
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, bind);
-
-    if (button == SDL_CONTROLLER_BUTTON_INVALID) {
-        return bind;
-    }
+    SDL_zero(bind);
 
-    for (i = 0; i < gamecontroller->num_bindings; ++i) {
-        SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
-        if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
-            bind.bindType = binding->inputType;
-            if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
-                bind.value.axis = binding->input.axis.axis;
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
-                bind.value.button = binding->input.button;
-            } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
-                bind.value.hat.hat = binding->input.hat.hat;
-                bind.value.hat.hat_mask = binding->input.hat.hat_mask;
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, bind);
+
+        if (button != SDL_CONTROLLER_BUTTON_INVALID) {
+            int i;
+            for (i = 0; i < gamecontroller->num_bindings; ++i) {
+                SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
+                if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) {
+                    bind.bindType = binding->inputType;
+                    if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) {
+                        bind.value.axis = binding->input.axis.axis;
+                    } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) {
+                        bind.value.button = binding->input.button;
+                    } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) {
+                        bind.value.hat.hat = binding->input.hat.hat;
+                        bind.value.hat.hat_mask = binding->input.hat.hat_mask;
+                    }
+                    break;
+                }
             }
-            break;
         }
     }
+    SDL_UnlockJoysticks();
+
     return bind;
 }
 
@@ -2710,8 +2885,7 @@ int SDL_GameControllerRumbleTriggers(SDL_GameController *gamecontroller, Uint16
     return SDL_JoystickRumbleTriggers(joystick, left_rumble, right_rumble, duration_ms);
 }
 
-SDL_bool
-SDL_GameControllerHasLED(SDL_GameController *gamecontroller)
+SDL_bool SDL_GameControllerHasLED(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2721,8 +2895,7 @@ SDL_GameControllerHasLED(SDL_GameController *gamecontroller)
     return SDL_JoystickHasLED(joystick);
 }
 
-SDL_bool
-SDL_GameControllerHasRumble(SDL_GameController *gamecontroller)
+SDL_bool SDL_GameControllerHasRumble(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2732,8 +2905,7 @@ SDL_GameControllerHasRumble(SDL_GameController *gamecontroller)
     return SDL_JoystickHasRumble(joystick);
 }
 
-SDL_bool
-SDL_GameControllerHasRumbleTriggers(SDL_GameController *gamecontroller)
+SDL_bool SDL_GameControllerHasRumbleTriggers(SDL_GameController *gamecontroller)
 {
     SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
 
@@ -2767,12 +2939,13 @@ void SDL_GameControllerClose(SDL_GameController *gamecontroller)
 {
     SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
 
+    SDL_LockJoysticks();
+
     if (gamecontroller == NULL || gamecontroller->magic != &gamecontroller_magic) {
+        SDL_UnlockJoysticks();
         return;
     }
 
-    SDL_LockJoysticks();
-
     /* First decrement ref count */
     if (--gamecontroller->ref_count > 0) {
         SDL_UnlockJoysticks();
@@ -2823,6 +2996,8 @@ void SDL_GameControllerQuitMappings(void)
 {
     ControllerMapping_t *pControllerMap;
 
+    SDL_AssertJoysticksLocked();
+
     while (s_pSupportedControllers) {
         pControllerMap = s_pSupportedControllers;
         s_pSupportedControllers = s_pSupportedControllers->next;
@@ -2855,7 +3030,7 @@ static int SDL_PrivateGameControllerAxis(Uint64 timestamp, SDL_GameController *g
 {
     int posted;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, 0);
+    SDL_AssertJoysticksLocked();
 
     /* translate the event, if desired */
     posted = 0;
@@ -2882,7 +3057,7 @@ static int SDL_PrivateGameControllerButton(Uint64 timestamp, SDL_GameController
 #if !SDL_EVENTS_DISABLED
     SDL_Event event;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, 0);
+    SDL_AssertJoysticksLocked();
 
     if (button == SDL_CONTROLLER_BUTTON_INVALID) {
         return 0;
@@ -2977,39 +3152,53 @@ int SDL_GameControllerEventState(int state)
 
 void SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick)
 {
-    SDL_GameController *controllerlist = SDL_gamecontrollers;
-    while (controllerlist) {
-        if (controllerlist->joystick == joystick) {
-            SDL_PrivateGameControllerButton(0, controllerlist, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
+    SDL_GameController *controller;
+
+    SDL_AssertJoysticksLocked();
+
+    for (controller = SDL_gamecontrollers; controller; controller = controller->next) {
+        if (controller->joystick == joystick) {
+            SDL_PrivateGameControllerButton(0, controller, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
             break;
         }
-        controllerlist = controllerlist->next;
     }
 }
 
-const char *
-SDL_GameControllerGetAppleSFSymbolsNameForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
+const char *SDL_GameControllerGetAppleSFSymbolsNameForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
 {
 #if defined(SDL_JOYSTICK_MFI)
     const char *IOS_GameControllerGetAppleSFSymbolsNameForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button);
+    const char *retval;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+
+        retval = IOS_GameControllerGetAppleSFSymbolsNameForButton(gamecontroller, button);
+    }
+    SDL_UnlockJoysticks();
 
-    return IOS_GameControllerGetAppleSFSymbolsNameForButton(gamecontroller, button);
+    return retval;
 #else
     return NULL;
 #endif
 }
 
-const char *
-SDL_GameControllerGetAppleSFSymbolsNameForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
+const char *SDL_GameControllerGetAppleSFSymbolsNameForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis)
 {
 #if defined(SDL_JOYSTICK_MFI)
     const char *IOS_GameControllerGetAppleSFSymbolsNameForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis);
+    const char *retval;
 
-    CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+    SDL_LockJoysticks();
+    {
+        CHECK_GAMECONTROLLER_MAGIC(gamecontroller, NULL);
+
+        retval = IOS_GameControllerGetAppleSFSymbolsNameForAxis(gamecontroller, axis);
+    }
+    SDL_UnlockJoysticks();
 
-    return IOS_GameControllerGetAppleSFSymbolsNameForAxis(gamecontroller, axis);
+    return retval;
 #else
     return NULL;
 #endif

+ 438 - 331
src/joystick/SDL_joystick.c

@@ -102,40 +102,37 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
         &SDL_DUMMY_JoystickDriver
 #endif
 };
+SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
+static int SDL_joysticks_locked;
 static SDL_bool SDL_joysticks_initialized;
 static SDL_bool SDL_joysticks_quitting = SDL_FALSE;
-static SDL_Joystick *SDL_joysticks = NULL;
-static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
-static int SDL_joysticks_locked;
-static SDL_atomic_t SDL_next_joystick_instance_id;
-static int SDL_joystick_player_count = 0;
-static SDL_JoystickID *SDL_joystick_players = NULL;
+static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
+static SDL_atomic_t SDL_next_joystick_instance_id SDL_GUARDED_BY(SDL_joystick_lock);
+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_bool SDL_joystick_allows_background_events = SDL_FALSE;
 static char joystick_magic;
 
 #define CHECK_JOYSTICK_MAGIC(joystick, retval)             \
     if (!joystick || joystick->magic != &joystick_magic) { \
         SDL_InvalidParamError("joystick");                 \
+        SDL_UnlockJoysticks();                             \
         return retval;                                     \
     }
 
-SDL_bool
-SDL_JoysticksInitialized(void)
+SDL_bool SDL_JoysticksInitialized(void)
 {
     return SDL_joysticks_initialized;
 }
 
-SDL_bool
-SDL_JoysticksQuitting(void)
+SDL_bool SDL_JoysticksQuitting(void)
 {
     return SDL_joysticks_quitting;
 }
 
 void SDL_LockJoysticks(void)
 {
-    if (SDL_joystick_lock) {
-        SDL_LockMutex(SDL_joystick_lock);
-    }
+    SDL_LockMutex(SDL_joystick_lock);
 
     ++SDL_joysticks_locked;
 }
@@ -144,22 +141,18 @@ void SDL_UnlockJoysticks(void)
 {
     --SDL_joysticks_locked;
 
-    if (SDL_joystick_lock) {
-        SDL_UnlockMutex(SDL_joystick_lock);
+    SDL_UnlockMutex(SDL_joystick_lock);
 
-        /* The last unlock after joysticks are uninitialized will cleanup the mutex,
-         * allowing applications to lock joysticks while reinitializing the system.
-         */
-        if (!SDL_joysticks_locked &&
-            !SDL_joysticks_initialized) {
-            SDL_DestroyMutex(SDL_joystick_lock);
-            SDL_joystick_lock = NULL;
-        }
+    /* 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;
     }
 }
 
-SDL_bool
-SDL_JoysticksLocked(void)
+SDL_bool SDL_JoysticksLocked(void)
 {
     return (SDL_joysticks_locked > 0) ? SDL_TRUE : SDL_FALSE;
 }
@@ -359,8 +352,7 @@ SDL_JoystickID SDL_GetNextJoystickInstanceID()
 /*
  * Get the implementation dependent name of a joystick
  */
-const char *
-SDL_JoystickNameForIndex(int device_index)
+const char *SDL_JoystickNameForIndex(int device_index)
 {
     SDL_JoystickDriver *driver;
     const char *name = NULL;
@@ -378,8 +370,7 @@ SDL_JoystickNameForIndex(int device_index)
 /*
  * Get the implementation dependent path of a joystick
  */
-const char *
-SDL_JoystickPathForIndex(int device_index)
+const char *SDL_JoystickPathForIndex(int device_index)
 {
     SDL_JoystickDriver *driver;
     const char *path = NULL;
@@ -426,23 +417,30 @@ static SDL_bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
         MAKE_VIDPID(0x05a0, 0x3232), /* 8Bitdo Zero Gamepad */
     };
 
+    SDL_bool retval = SDL_FALSE;
     int i;
     Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick),
                             SDL_JoystickGetProduct(joystick));
 
     /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
 
-    if (joystick->naxes == 2) {
-        /* Assume D-pad or thumbstick style axes are centered at 0 */
-        return SDL_TRUE;
-    }
+    SDL_LockJoysticks();
+    {
+        if (joystick->naxes == 2) {
+            /* Assume D-pad or thumbstick style axes are centered at 0 */
+            retval = SDL_TRUE;
+        }
 
-    for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
-        if (id == zero_centered_joysticks[i]) {
-            return SDL_TRUE;
+        for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
+            if (id == zero_centered_joysticks[i]) {
+                retval = SDL_TRUE;
+                break;
+            }
         }
     }
-    return SDL_FALSE;
+    SDL_UnlockJoysticks();
+
+    return retval;
 #endif /* __WINRT__ */
 }
 
@@ -453,8 +451,7 @@ static SDL_bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
  *
  * This function returns a joystick identifier, or NULL if an error occurred.
  */
-SDL_Joystick *
-SDL_JoystickOpen(int device_index)
+SDL_Joystick *SDL_JoystickOpen(int device_index)
 {
     SDL_JoystickDriver *driver;
     SDL_JoystickID instance_id;
@@ -567,8 +564,7 @@ SDL_JoystickOpen(int device_index)
     return joystick;
 }
 
-int SDL_JoystickAttachVirtual(SDL_JoystickType type,
-                              int naxes, int nbuttons, int nhats)
+int SDL_JoystickAttachVirtual(SDL_JoystickType type, int naxes, int nbuttons, int nhats)
 {
     SDL_VirtualJoystickDesc desc;
 
@@ -584,12 +580,12 @@ int SDL_JoystickAttachVirtual(SDL_JoystickType type,
 int SDL_JoystickAttachVirtualEx(const SDL_VirtualJoystickDesc *desc)
 {
 #if SDL_JOYSTICK_VIRTUAL
-    int result;
+    int retval;
 
     SDL_LockJoysticks();
-    result = SDL_JoystickAttachVirtualInner(desc);
+    retval = SDL_JoystickAttachVirtualInner(desc);
     SDL_UnlockJoysticks();
-    return result;
+    return retval;
 #else
     return SDL_SetError("SDL not built with virtual-joystick support");
 #endif
@@ -603,9 +599,9 @@ int SDL_JoystickDetachVirtual(int device_index)
     SDL_LockJoysticks();
     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
         if (driver == &SDL_VIRTUAL_JoystickDriver) {
-            const int result = SDL_JoystickDetachVirtualInner(device_index);
+            const int retval = SDL_JoystickDetachVirtualInner(device_index);
             SDL_UnlockJoysticks();
-            return result;
+            return retval;
         }
     }
     SDL_UnlockJoysticks();
@@ -616,8 +612,7 @@ int SDL_JoystickDetachVirtual(int device_index)
 #endif
 }
 
-SDL_bool
-SDL_JoystickIsVirtual(int device_index)
+SDL_bool SDL_JoystickIsVirtual(int device_index)
 {
 #if SDL_JOYSTICK_VIRTUAL
     SDL_JoystickDriver *driver;
@@ -640,49 +635,71 @@ SDL_JoystickIsVirtual(int device_index)
 
 int SDL_JoystickSetVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
 #if SDL_JOYSTICK_VIRTUAL
-    return SDL_JoystickSetVirtualAxisInner(joystick, axis, value);
+        retval = SDL_JoystickSetVirtualAxisInner(joystick, axis, value);
 #else
-    return SDL_SetError("SDL not built with virtual-joystick support");
+        retval = SDL_SetError("SDL not built with virtual-joystick support");
 #endif
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 int SDL_JoystickSetVirtualButton(SDL_Joystick *joystick, int button, Uint8 value)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
 #if SDL_JOYSTICK_VIRTUAL
-    return SDL_JoystickSetVirtualButtonInner(joystick, button, value);
+        retval = SDL_JoystickSetVirtualButtonInner(joystick, button, value);
 #else
-    return SDL_SetError("SDL not built with virtual-joystick support");
+        retval = SDL_SetError("SDL not built with virtual-joystick support");
 #endif
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 int SDL_JoystickSetVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
 #if SDL_JOYSTICK_VIRTUAL
-    return SDL_JoystickSetVirtualHatInner(joystick, hat, value);
+        retval = SDL_JoystickSetVirtualHatInner(joystick, hat, value);
 #else
-    return SDL_SetError("SDL not built with virtual-joystick support");
+        retval = SDL_SetError("SDL not built with virtual-joystick support");
 #endif
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Checks to make sure the joystick is valid.
  */
-SDL_bool
-SDL_PrivateJoystickValid(SDL_Joystick *joystick)
+SDL_bool SDL_PrivateJoystickValid(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
-    return SDL_TRUE;
+    SDL_AssertJoysticksLocked();
+    return (joystick && joystick->magic == &joystick_magic);
 }
 
-SDL_bool
-SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping *out)
+SDL_bool SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping *out)
 {
     SDL_JoystickDriver *driver;
     SDL_bool is_ok = SDL_FALSE;
@@ -701,9 +718,17 @@ SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping *o
  */
 int SDL_JoystickNumAxes(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
 
-    return joystick->naxes;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
+
+        retval = joystick->naxes;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -711,9 +736,17 @@ int SDL_JoystickNumAxes(SDL_Joystick *joystick)
  */
 int SDL_JoystickNumHats(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
+
+        retval = joystick->nhats;
+    }
+    SDL_UnlockJoysticks();
 
-    return joystick->nhats;
+    return retval;
 }
 
 /*
@@ -721,46 +754,66 @@ int SDL_JoystickNumHats(SDL_Joystick *joystick)
  */
 int SDL_JoystickNumButtons(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
 
-    return joystick->nbuttons;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
+
+        retval = joystick->nbuttons;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Get the current state of an axis control on a joystick
  */
-Sint16
-SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
+Sint16 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
 {
     Sint16 state;
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, 0);
 
-    if (axis < joystick->naxes) {
-        state = joystick->axes[axis].value;
-    } else {
-        SDL_SetError("Joystick only has %d axes", joystick->naxes);
-        state = 0;
+        if (axis < joystick->naxes) {
+            state = joystick->axes[axis].value;
+        } else {
+            SDL_SetError("Joystick only has %d axes", joystick->naxes);
+            state = 0;
+        }
     }
+    SDL_UnlockJoysticks();
+
     return state;
 }
 
 /*
  * Get the initial state of an axis control on a joystick
  */
-SDL_bool
-SDL_JoystickGetAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state)
+SDL_bool SDL_JoystickGetAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
+    SDL_bool retval;
 
-    if (axis >= joystick->naxes) {
-        SDL_SetError("Joystick only has %d axes", joystick->naxes);
-        return SDL_FALSE;
-    }
-    if (state) {
-        *state = joystick->axes[axis].initial_value;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
+
+        if (axis >= joystick->naxes) {
+            SDL_SetError("Joystick only has %d axes", joystick->naxes);
+            retval = SDL_FALSE;
+        } else {
+            if (state) {
+                *state = joystick->axes[axis].initial_value;
+            }
+            retval = joystick->axes[axis].has_initial_value;
+        }
     }
-    return joystick->axes[axis].has_initial_value;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
@@ -770,14 +823,19 @@ Uint8 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
 {
     Uint8 state;
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, 0);
 
-    if (hat < joystick->nhats) {
-        state = joystick->hats[hat];
-    } else {
-        SDL_SetError("Joystick only has %d hats", joystick->nhats);
-        state = 0;
+        if (hat < joystick->nhats) {
+            state = joystick->hats[hat];
+        } else {
+            SDL_SetError("Joystick only has %d hats", joystick->nhats);
+            state = 0;
+        }
     }
+    SDL_UnlockJoysticks();
+
     return state;
 }
 
@@ -788,14 +846,19 @@ Uint8 SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
 {
     Uint8 state;
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, 0);
 
-    if (button < joystick->nbuttons) {
-        state = joystick->buttons[button];
-    } else {
-        SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
-        state = 0;
+        if (button < joystick->nbuttons) {
+            state = joystick->buttons[button];
+        } else {
+            SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
+            state = 0;
+        }
     }
+    SDL_UnlockJoysticks();
+
     return state;
 }
 
@@ -803,30 +866,43 @@ Uint8 SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
  * Return if the joystick in question is currently attached to the system,
  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
  */
-SDL_bool
-SDL_JoystickGetAttached(SDL_Joystick *joystick)
+SDL_bool SDL_JoystickGetAttached(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
+    SDL_bool retval;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
 
-    return joystick->attached;
+        retval = joystick->attached;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Get the instance id for this opened joystick
  */
-SDL_JoystickID
-SDL_JoystickInstanceID(SDL_Joystick *joystick)
+SDL_JoystickID SDL_JoystickInstanceID(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    SDL_JoystickID retval;
 
-    return joystick->instance_id;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
+
+        retval = joystick->instance_id;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Return the SDL_Joystick associated with an instance id.
  */
-SDL_Joystick *
-SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
+SDL_Joystick *SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
 {
     SDL_Joystick *joystick;
 
@@ -843,8 +919,7 @@ SDL_JoystickFromInstanceID(SDL_JoystickID instance_id)
 /**
  * Return the SDL_Joystick associated with a player index.
  */
-SDL_Joystick *
-SDL_JoystickFromPlayerIndex(int player_index)
+SDL_Joystick *SDL_JoystickFromPlayerIndex(int player_index)
 {
     SDL_JoystickID instance_id;
     SDL_Joystick *joystick;
@@ -863,27 +938,42 @@ SDL_JoystickFromPlayerIndex(int player_index)
 /*
  * Get the friendly name of this joystick
  */
-const char *
-SDL_JoystickName(SDL_Joystick *joystick)
+const char *SDL_JoystickName(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, NULL);
+    const char *retval;
 
-    return joystick->name;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, NULL);
+
+        retval = joystick->name;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /*
  * Get the implementation dependent path of this joystick
  */
-const char *
-SDL_JoystickPath(SDL_Joystick *joystick)
+const char *SDL_JoystickPath(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, NULL);
+    const char *retval;
 
-    if (!joystick->path) {
-        SDL_Unsupported();
-        return NULL;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, NULL);
+
+        if (joystick->path) {
+            retval = joystick->path;
+        } else {
+            SDL_Unsupported();
+            retval = NULL;
+        }
     }
-    return joystick->path;
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 /**
@@ -891,15 +981,17 @@ SDL_JoystickPath(SDL_Joystick *joystick)
  */
 int SDL_JoystickGetPlayerIndex(SDL_Joystick *joystick)
 {
-    int player_index;
-
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
 
     SDL_LockJoysticks();
-    player_index = SDL_GetPlayerIndexForJoystickID(joystick->instance_id);
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
+
+        retval = SDL_GetPlayerIndexForJoystickID(joystick->instance_id);
+    }
     SDL_UnlockJoysticks();
 
-    return player_index;
+    return retval;
 }
 
 /**
@@ -907,166 +999,172 @@ int SDL_JoystickGetPlayerIndex(SDL_Joystick *joystick)
  */
 void SDL_JoystickSetPlayerIndex(SDL_Joystick *joystick, int player_index)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, );
-
     SDL_LockJoysticks();
-    SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id);
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, );
+
+        SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id);
+    }
     SDL_UnlockJoysticks();
 }
 
 int SDL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
 {
-    int result;
-
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
 
     SDL_LockJoysticks();
-    if (low_frequency_rumble == joystick->low_frequency_rumble &&
-        high_frequency_rumble == joystick->high_frequency_rumble) {
-        /* Just update the expiration */
-        result = 0;
-    } else {
-        result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble);
-        joystick->rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS;
-    }
-
-    if (result == 0) {
-        joystick->low_frequency_rumble = low_frequency_rumble;
-        joystick->high_frequency_rumble = high_frequency_rumble;
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
-        if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
-            joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
+        if (low_frequency_rumble == joystick->low_frequency_rumble &&
+            high_frequency_rumble == joystick->high_frequency_rumble) {
+            /* Just update the expiration */
+            retval = 0;
         } else {
-            joystick->rumble_expiration = 0;
-            joystick->rumble_resend = 0;
+            retval = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble);
+            joystick->rumble_resend = SDL_GetTicks() + SDL_RUMBLE_RESEND_MS;
+        }
+
+        if (retval == 0) {
+            joystick->low_frequency_rumble = low_frequency_rumble;
+            joystick->high_frequency_rumble = high_frequency_rumble;
+
+            if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
+                joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
+                if (!joystick->rumble_expiration) {
+                    joystick->rumble_expiration = 1;
+                }
+            } else {
+                joystick->rumble_expiration = 0;
+                joystick->rumble_resend = 0;
+            }
         }
     }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
 int SDL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
 {
-    int result;
-
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
 
     SDL_LockJoysticks();
-    if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) {
-        /* Just update the expiration */
-        result = 0;
-    } else {
-        result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
-    }
-
-    if (result == 0) {
-        joystick->left_trigger_rumble = left_rumble;
-        joystick->right_trigger_rumble = right_rumble;
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
-        if ((left_rumble || right_rumble) && duration_ms) {
-            joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
+        if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) {
+            /* Just update the expiration */
+            retval = 0;
         } else {
-            joystick->trigger_rumble_expiration = 0;
+            retval = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
+        }
+
+        if (retval == 0) {
+            joystick->left_trigger_rumble = left_rumble;
+            joystick->right_trigger_rumble = right_rumble;
+
+            if ((left_rumble || right_rumble) && duration_ms) {
+                joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
+            } else {
+                joystick->trigger_rumble_expiration = 0;
+            }
         }
     }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
-SDL_bool
-SDL_JoystickHasLED(SDL_Joystick *joystick)
+SDL_bool SDL_JoystickHasLED(SDL_Joystick *joystick)
 {
-    SDL_bool result;
-
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
+    SDL_bool retval;
 
     SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
 
-    result = (joystick->driver->GetCapabilities(joystick) & SDL_JOYCAP_LED) != 0;
-
+        retval = (joystick->driver->GetCapabilities(joystick) & SDL_JOYCAP_LED) != 0;
+    }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
-SDL_bool
-SDL_JoystickHasRumble(SDL_Joystick *joystick)
+SDL_bool SDL_JoystickHasRumble(SDL_Joystick *joystick)
 {
-    SDL_bool result;
-
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
+    SDL_bool retval;
 
     SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
 
-    result = (joystick->driver->GetCapabilities(joystick) & SDL_JOYCAP_RUMBLE) != 0;
-
+        retval = (joystick->driver->GetCapabilities(joystick) & SDL_JOYCAP_RUMBLE) != 0;
+    }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
-SDL_bool
-SDL_JoystickHasRumbleTriggers(SDL_Joystick *joystick)
+SDL_bool SDL_JoystickHasRumbleTriggers(SDL_Joystick *joystick)
 {
-    SDL_bool result;
-
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
+    SDL_bool retval;
 
     SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, SDL_FALSE);
 
-    result = (joystick->driver->GetCapabilities(joystick) & SDL_JOYCAP_RUMBLE_TRIGGERS) != 0;
-
+        retval = (joystick->driver->GetCapabilities(joystick) & SDL_JOYCAP_RUMBLE_TRIGGERS) != 0;
+    }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
 int SDL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
 {
-    int result;
+    int retval;
     SDL_bool isfreshvalue;
 
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
-
     SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
-    isfreshvalue = red != joystick->led_red ||
-                   green != joystick->led_green ||
-                   blue != joystick->led_blue;
-
-    if (isfreshvalue || SDL_GetTicks() >= joystick->led_expiration) {
-        result = joystick->driver->SetLED(joystick, red, green, blue);
-        joystick->led_expiration = SDL_GetTicks() + SDL_LED_MIN_REPEAT_MS;
-    } else {
-        /* Avoid spamming the driver */
-        result = 0;
-    }
+        isfreshvalue = red != joystick->led_red ||
+                       green != joystick->led_green ||
+                       blue != joystick->led_blue;
 
-    /* Save the LED value regardless of success, so we don't spam the driver */
-    joystick->led_red = red;
-    joystick->led_green = green;
-    joystick->led_blue = blue;
+        if (isfreshvalue || SDL_GetTicks() >= joystick->led_expiration) {
+            retval = joystick->driver->SetLED(joystick, red, green, blue);
+            joystick->led_expiration = SDL_GetTicks() + SDL_LED_MIN_REPEAT_MS;
+        } else {
+            /* Avoid spamming the driver */
+            retval = 0;
+        }
 
+        /* Save the LED value regardless of success, so we don't spam the driver */
+        joystick->led_red = red;
+        joystick->led_green = green;
+        joystick->led_blue = blue;
+    }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
 int SDL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
 {
-    int result;
-
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
+    int retval;
 
     SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, -1);
 
-    result = joystick->driver->SendEffect(joystick, data, size);
-
+        retval = joystick->driver->SendEffect(joystick, data, size);
+    }
     SDL_UnlockJoysticks();
 
-    return result;
+    return retval;
 }
 
 /*
@@ -1078,59 +1176,59 @@ void SDL_JoystickClose(SDL_Joystick *joystick)
     SDL_Joystick *joysticklistprev;
     int i;
 
-    CHECK_JOYSTICK_MAGIC(joystick, );
-
     SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, );
 
-    /* First decrement ref count */
-    if (--joystick->ref_count > 0) {
-        SDL_UnlockJoysticks();
-        return;
-    }
+        /* First decrement ref count */
+        if (--joystick->ref_count > 0) {
+            SDL_UnlockJoysticks();
+            return;
+        }
 
-    if (joystick->rumble_expiration) {
-        SDL_JoystickRumble(joystick, 0, 0, 0);
-    }
-    if (joystick->trigger_rumble_expiration) {
-        SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
-    }
+        if (joystick->rumble_expiration) {
+            SDL_JoystickRumble(joystick, 0, 0, 0);
+        }
+        if (joystick->trigger_rumble_expiration) {
+            SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
+        }
 
-    joystick->driver->Close(joystick);
-    joystick->hwdata = NULL;
-    joystick->magic = NULL;
+        joystick->driver->Close(joystick);
+        joystick->hwdata = NULL;
+        joystick->magic = NULL;
 
-    joysticklist = SDL_joysticks;
-    joysticklistprev = NULL;
-    while (joysticklist) {
-        if (joystick == joysticklist) {
-            if (joysticklistprev) {
-                /* unlink this entry */
-                joysticklistprev->next = joysticklist->next;
-            } else {
-                SDL_joysticks = joystick->next;
+        joysticklist = SDL_joysticks;
+        joysticklistprev = NULL;
+        while (joysticklist) {
+            if (joystick == joysticklist) {
+                if (joysticklistprev) {
+                    /* unlink this entry */
+                    joysticklistprev->next = joysticklist->next;
+                } else {
+                    SDL_joysticks = joystick->next;
+                }
+                break;
             }
-            break;
+            joysticklistprev = joysticklist;
+            joysticklist = joysticklist->next;
         }
-        joysticklistprev = joysticklist;
-        joysticklist = joysticklist->next;
-    }
 
-    SDL_free(joystick->name);
-    SDL_free(joystick->path);
-    SDL_free(joystick->serial);
+        SDL_free(joystick->name);
+        SDL_free(joystick->path);
+        SDL_free(joystick->serial);
 
-    /* Free the data associated with this joystick */
-    SDL_free(joystick->axes);
-    SDL_free(joystick->hats);
-    SDL_free(joystick->buttons);
-    for (i = 0; i < joystick->ntouchpads; i++) {
-        SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
-        SDL_free(touchpad->fingers);
+        /* Free the data associated with this joystick */
+        SDL_free(joystick->axes);
+        SDL_free(joystick->hats);
+        SDL_free(joystick->buttons);
+        for (i = 0; i < joystick->ntouchpads; i++) {
+            SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
+            SDL_free(touchpad->fingers);
+        }
+        SDL_free(joystick->touchpads);
+        SDL_free(joystick->sensors);
+        SDL_free(joystick);
     }
-    SDL_free(joystick->touchpads);
-    SDL_free(joystick->sensors);
-    SDL_free(joystick);
-
     SDL_UnlockJoysticks();
 }
 
@@ -1194,7 +1292,7 @@ void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers)
     int ntouchpads;
     SDL_JoystickTouchpadInfo *touchpads;
 
-    CHECK_JOYSTICK_MAGIC(joystick, );
+    SDL_AssertJoysticksLocked();
 
     ntouchpads = joystick->ntouchpads + 1;
     touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo)));
@@ -1221,7 +1319,7 @@ void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type, f
     int nsensors;
     SDL_JoystickSensorInfo *sensors;
 
-    CHECK_JOYSTICK_MAGIC(joystick, );
+    SDL_AssertJoysticksLocked();
 
     nsensors = joystick->nsensors + 1;
     sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo)));
@@ -1343,7 +1441,7 @@ void SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick)
     int i, j;
     Uint64 timestamp = SDL_GetTicksNS();
 
-    CHECK_JOYSTICK_MAGIC(joystick, );
+    SDL_AssertJoysticksLocked();
 
     /* Tell the app that everything is centered/unpressed... */
     for (i = 0; i < joystick->naxes; i++) {
@@ -1418,8 +1516,6 @@ int SDL_PrivateJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis
 
     SDL_AssertJoysticksLocked();
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
-
     /* Make sure we're not getting garbage or duplicate events */
     if (axis >= joystick->naxes) {
         return 0;
@@ -1486,8 +1582,6 @@ int SDL_PrivateJoystickHat(Uint64 timestamp, SDL_Joystick *joystick, Uint8 hat,
 
     SDL_AssertJoysticksLocked();
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
-
     /* Make sure we're not getting garbage or duplicate events */
     if (hat >= joystick->nhats) {
         return 0;
@@ -1530,7 +1624,7 @@ int SDL_PrivateJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 bu
 #if !SDL_EVENTS_DISABLED
     SDL_Event event;
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    SDL_AssertJoysticksLocked();
 
     switch (state) {
     case SDL_PRESSED:
@@ -1743,8 +1837,7 @@ static int PrefixMatch(const char *a, const char *b)
     return matchlen;
 }
 
-char *
-SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
+char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
 {
     static struct
     {
@@ -1883,8 +1976,7 @@ SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, c
     return name;
 }
 
-SDL_JoystickGUID
-SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *name, Uint8 driver_signature, Uint8 driver_data)
+SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *name, Uint8 driver_signature, Uint8 driver_data)
 {
     SDL_JoystickGUID guid;
     Uint16 *guid16 = (Uint16 *)guid.data;
@@ -1921,8 +2013,7 @@ SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version
     return guid;
 }
 
-SDL_JoystickGUID
-SDL_CreateJoystickGUIDForName(const char *name)
+SDL_JoystickGUID SDL_CreateJoystickGUIDForName(const char *name)
 {
     return SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, 0, 0, 0, name, 0, 0);
 }
@@ -1955,8 +2046,7 @@ void SDL_SetJoystickGUIDCRC(SDL_JoystickGUID *guid, Uint16 crc)
     guid16[1] = SDL_SwapLE16(crc);
 }
 
-SDL_GameControllerType
-SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, SDL_bool forUI)
+SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, SDL_bool forUI)
 {
     SDL_GameControllerType type = SDL_CONTROLLER_TYPE_UNKNOWN;
 
@@ -2051,8 +2141,7 @@ SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product, const
     return type;
 }
 
-SDL_GameControllerType
-SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name)
+SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name)
 {
     SDL_GameControllerType type;
     Uint16 vendor, product;
@@ -2076,15 +2165,13 @@ SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *nam
     return type;
 }
 
-SDL_bool
-SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_XBoxOneController;
 }
 
-SDL_bool
-SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
 {
     if (vendor_id == USB_VENDOR_MICROSOFT) {
         if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
@@ -2097,8 +2184,7 @@ SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
     return SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
 {
     if (vendor_id == USB_VENDOR_MICROSOFT) {
         if (product_id == USB_PRODUCT_XBOX_SERIES_X ||
@@ -2134,8 +2220,7 @@ SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
     return SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id)
 {
     if (vendor_id == USB_VENDOR_MICROSOFT) {
         if (product_id == USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH ||
@@ -2152,22 +2237,19 @@ SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id)
     return SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_PS4Controller;
 }
 
-SDL_bool
-SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_PS5Controller;
 }
 
-SDL_bool
-SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id)
 {
     if (vendor_id == USB_VENDOR_SONY) {
         if (product_id == USB_PRODUCT_SONY_DS5_EDGE) {
@@ -2177,86 +2259,73 @@ SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id)
     return SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_SwitchProController || eType == k_eControllerType_SwitchInputOnlyController;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_SwitchInputOnlyController;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_SwitchJoyConLeft || eType == k_eControllerType_SwitchJoyConRight;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_SwitchJoyConLeft;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_SwitchJoyConRight;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id)
 {
     return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP;
 }
 
-SDL_bool
-SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id)
 {
     return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
 }
 
-SDL_bool
-SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
+SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     return eType == k_eControllerType_SteamController || eType == k_eControllerType_SteamControllerV2;
 }
 
-SDL_bool
-SDL_IsJoystickXInput(SDL_JoystickGUID guid)
+SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid)
 {
     return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickWGI(SDL_JoystickGUID guid)
+SDL_bool SDL_IsJoystickWGI(SDL_JoystickGUID guid)
 {
     return (guid.data[14] == 'w') ? SDL_TRUE : SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
+SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
 {
     return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
+SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
 {
     return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE;
 }
 
-SDL_bool
-SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
+SDL_bool SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
 {
     return (guid.data[14] == 'v') ? SDL_TRUE : SDL_FALSE;
 }
@@ -2699,11 +2768,19 @@ int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id)
 
 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick *joystick)
 {
-    static SDL_JoystickGUID emptyGUID;
+    SDL_JoystickGUID retval;
 
-    CHECK_JOYSTICK_MAGIC(joystick, emptyGUID);
+    SDL_LockJoysticks();
+    {
+        static SDL_JoystickGUID emptyGUID;
 
-    return joystick->guid;
+        CHECK_JOYSTICK_MAGIC(joystick, emptyGUID);
+
+        retval = joystick->guid;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 Uint16 SDL_JoystickGetVendor(SDL_Joystick *joystick)
@@ -2735,16 +2812,32 @@ Uint16 SDL_JoystickGetProductVersion(SDL_Joystick *joystick)
 
 Uint16 SDL_JoystickGetFirmwareVersion(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    Uint16 retval;
 
-    return joystick->firmware_version;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, 0);
+
+        retval = joystick->firmware_version;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 const char *SDL_JoystickGetSerial(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, NULL);
+    const char *retval;
 
-    return joystick->serial;
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, NULL);
+
+        retval = joystick->serial;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 SDL_JoystickType SDL_JoystickGetType(SDL_Joystick *joystick)
@@ -2754,9 +2847,15 @@ SDL_JoystickType SDL_JoystickGetType(SDL_Joystick *joystick)
 
     type = SDL_GetJoystickGUIDType(guid);
     if (type == SDL_JOYSTICK_TYPE_UNKNOWN) {
-        if (joystick && joystick->is_game_controller) {
-            type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+        SDL_LockJoysticks();
+        {
+            CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_TYPE_UNKNOWN);
+
+            if (joystick->is_game_controller) {
+                type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+            }
         }
+        SDL_UnlockJoysticks();
     }
     return type;
 }
@@ -2776,7 +2875,7 @@ SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
 /* update the power level for this joystick */
 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, );
+    SDL_AssertJoysticksLocked();
 
     SDL_assert(joystick->ref_count); /* make sure we are calling this only for update, not for initialization */
     if (ePowerLevel != joystick->epowerlevel) {
@@ -2797,9 +2896,17 @@ void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLe
 /* return its power level */
 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick *joystick)
 {
-    CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_POWER_UNKNOWN);
+    SDL_JoystickPowerLevel retval;
+
+    SDL_LockJoysticks();
+    {
+        CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_POWER_UNKNOWN);
 
-    return joystick->epowerlevel;
+        retval = joystick->epowerlevel;
+    }
+    SDL_UnlockJoysticks();
+
+    return retval;
 }
 
 int SDL_PrivateJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure)
@@ -2809,7 +2916,7 @@ int SDL_PrivateJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick, int to
     int posted;
     Uint32 event_type;
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    SDL_AssertJoysticksLocked();
 
     if (touchpad < 0 || touchpad >= joystick->ntouchpads) {
         return 0;
@@ -2898,7 +3005,7 @@ int SDL_PrivateJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick, SDL_Sens
     int i;
     int posted = 0;
 
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
+    SDL_AssertJoysticksLocked();
 
     /* We ignore events if we don't have keyboard focus */
     if (SDL_PrivateJoystickShouldIgnoreEvent()) {

+ 1 - 1
src/joystick/SDL_joystick_c.h

@@ -47,7 +47,7 @@ extern SDL_bool SDL_JoysticksQuitting(void);
 extern SDL_bool SDL_JoysticksLocked(void);
 
 /* Make sure we currently have the joysticks locked */
-extern void SDL_AssertJoysticksLocked(void);
+extern void SDL_AssertJoysticksLocked(void) SDL_ASSERT_CAPABILITY(SDL_joystick_lock);
 
 /* Function to get the next available joystick instance ID */
 extern SDL_JoystickID SDL_GetNextJoystickInstanceID(void);

+ 41 - 37
src/joystick/SDL_sysjoystick.h

@@ -65,61 +65,65 @@ typedef struct _SDL_JoystickSensorInfo
     float data[3]; /* If this needs to expand, update SDL_ControllerSensorEvent */
 } SDL_JoystickSensorInfo;
 
+#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
+
 struct _SDL_Joystick
 {
-    const void *magic;
+    const void *magic _guarded;
 
-    SDL_JoystickID instance_id; /* Device instance, monotonically increasing from 0 */
-    char *name;                 /* Joystick name - system dependent */
-    char *path;                 /* Joystick path - system dependent */
-    char *serial;               /* Joystick serial */
-    SDL_JoystickGUID guid;      /* Joystick guid */
-    Uint16 firmware_version;    /* Firmware version, if available */
+    SDL_JoystickID instance_id _guarded; /* Device instance, monotonically increasing from 0 */
+    char *name _guarded;                 /* Joystick name - system dependent */
+    char *path _guarded;                 /* Joystick path - system dependent */
+    char *serial _guarded;               /* Joystick serial */
+    SDL_JoystickGUID guid _guarded;      /* Joystick guid */
+    Uint16 firmware_version _guarded;    /* Firmware version, if available */
 
-    int naxes; /* Number of axis controls on the joystick */
-    SDL_JoystickAxisInfo *axes;
+    int naxes _guarded; /* Number of axis controls on the joystick */
+    SDL_JoystickAxisInfo *axes _guarded;
 
-    int nhats;   /* Number of hats on the joystick */
-    Uint8 *hats; /* Current hat states */
+    int nhats _guarded;   /* Number of hats on the joystick */
+    Uint8 *hats _guarded; /* Current hat states */
 
-    int nbuttons;   /* Number of buttons on the joystick */
-    Uint8 *buttons; /* Current button states */
+    int nbuttons _guarded;   /* Number of buttons on the joystick */
+    Uint8 *buttons _guarded; /* Current button states */
 
-    int ntouchpads;                      /* Number of touchpads on the joystick */
-    SDL_JoystickTouchpadInfo *touchpads; /* Current touchpad states */
+    int ntouchpads _guarded;                      /* Number of touchpads on the joystick */
+    SDL_JoystickTouchpadInfo *touchpads _guarded; /* Current touchpad states */
 
-    int nsensors; /* Number of sensors on the joystick */
-    int nsensors_enabled;
-    SDL_JoystickSensorInfo *sensors;
+    int nsensors _guarded; /* Number of sensors on the joystick */
+    int nsensors_enabled _guarded;
+    SDL_JoystickSensorInfo *sensors _guarded;
 
-    Uint16 low_frequency_rumble;
-    Uint16 high_frequency_rumble;
-    Uint64 rumble_expiration;
-    Uint64 rumble_resend;
+    Uint16 low_frequency_rumble _guarded;
+    Uint16 high_frequency_rumble _guarded;
+    Uint64 rumble_expiration _guarded;
+    Uint64 rumble_resend _guarded;
 
-    Uint16 left_trigger_rumble;
-    Uint16 right_trigger_rumble;
-    Uint64 trigger_rumble_expiration;
+    Uint16 left_trigger_rumble _guarded;
+    Uint16 right_trigger_rumble _guarded;
+    Uint64 trigger_rumble_expiration _guarded;
 
-    Uint8 led_red;
-    Uint8 led_green;
-    Uint8 led_blue;
-    Uint64 led_expiration;
+    Uint8 led_red _guarded;
+    Uint8 led_green _guarded;
+    Uint8 led_blue _guarded;
+    Uint64 led_expiration _guarded;
 
-    SDL_bool attached;
-    SDL_bool is_game_controller;
-    SDL_bool delayed_guide_button;      /* SDL_TRUE if this device has the guide button event delayed */
-    SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
+    SDL_bool attached _guarded;
+    SDL_bool is_game_controller _guarded;
+    SDL_bool delayed_guide_button _guarded;      /* SDL_TRUE if this device has the guide button event delayed */
+    SDL_JoystickPowerLevel epowerlevel _guarded; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
 
-    struct _SDL_JoystickDriver *driver;
+    struct _SDL_JoystickDriver *driver _guarded;
 
-    struct joystick_hwdata *hwdata; /* Driver dependent information */
+    struct joystick_hwdata *hwdata _guarded; /* Driver dependent information */
 
-    int ref_count; /* Reference count for multiple opens */
+    int ref_count _guarded; /* Reference count for multiple opens */
 
-    struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */
+    struct _SDL_Joystick *next _guarded; /* pointer to next joystick we have allocated */
 };
 
+#undef _guarded
+
 /* Device bus definitions */
 #define SDL_HARDWARE_BUS_UNKNOWN   0x00
 #define SDL_HARDWARE_BUS_USB       0x03

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_combined.c

@@ -65,6 +65,8 @@ static SDL_bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SD
     char *serial = NULL, *new_serial;
     size_t serial_length = 0, new_length;
 
+    SDL_AssertJoysticksLocked();
+
     for (i = 0; i < device->num_children; ++i) {
         SDL_HIDAPI_Device *child = device->children[i];
         if (!child->driver->OpenJoystick(child, joystick)) {

+ 7 - 0
src/joystick/hidapi/SDL_hidapi_gamecube.c

@@ -409,6 +409,9 @@ static SDL_bool HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SD
 {
     SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
     Uint8 i;
+
+    SDL_AssertJoysticksLocked();
+
     for (i = 0; i < MAX_CONTROLLERS; i += 1) {
         if (joystick->instance_id == ctx->joysticks[i]) {
             joystick->nbuttons = 12;
@@ -425,6 +428,8 @@ static int HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_J
     SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
     Uint8 i, val;
 
+    SDL_AssertJoysticksLocked();
+
     if (ctx->pc_mode) {
         return SDL_Unsupported();
     }
@@ -470,6 +475,8 @@ static Uint32 HIDAPI_DriverGameCube_GetJoystickCapabilities(SDL_HIDAPI_Device *d
     SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
     Uint32 result = 0;
 
+    SDL_AssertJoysticksLocked();
+
     if (!ctx->pc_mode) {
         Uint8 i;
 

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_luna.c

@@ -97,6 +97,8 @@ static SDL_bool HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Jo
 {
     SDL_DriverLuna_Context *ctx = (SDL_DriverLuna_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     SDL_zeroa(ctx->last_state);
 
     /* Initialize the joystick capabilities */

+ 4 - 0
src/joystick/hidapi/SDL_hidapi_ps3.c

@@ -229,6 +229,8 @@ static SDL_bool HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
 {
     SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
     ctx->effects_updated = SDL_FALSE;
     ctx->rumble_left = 0;
@@ -627,6 +629,8 @@ static SDL_bool HIDAPI_DriverPS3ThirdParty_OpenJoystick(SDL_HIDAPI_Device *devic
 {
     SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
     SDL_zeroa(ctx->last_state);
 

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_ps4.c

@@ -664,6 +664,8 @@ static SDL_bool HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
 {
     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
     ctx->last_packet = SDL_GetTicks();
     ctx->report_sensors = SDL_FALSE;

+ 3 - 1
src/joystick/hidapi/SDL_hidapi_ps5.c

@@ -818,6 +818,8 @@ static SDL_bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
 {
     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
     ctx->last_packet = SDL_GetTicks();
     ctx->report_sensors = SDL_FALSE;
@@ -957,7 +959,7 @@ static int HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Jo
         SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
     }
 
-    if (SDL_HIDAPI_LockRumble() < 0) {
+    if (SDL_HIDAPI_LockRumble() != 0) {
         return -1;
     }
 

+ 15 - 16
src/joystick/hidapi/SDL_hidapi_rumble.c

@@ -44,13 +44,13 @@ typedef struct SDL_HIDAPI_RumbleContext
     SDL_atomic_t initialized;
     SDL_atomic_t running;
     SDL_Thread *thread;
-    SDL_mutex *lock;
     SDL_sem *request_sem;
     SDL_HIDAPI_RumbleRequest *requests_head;
     SDL_HIDAPI_RumbleRequest *requests_tail;
 } SDL_HIDAPI_RumbleContext;
 
-static SDL_HIDAPI_RumbleContext rumble_context;
+SDL_mutex *SDL_HIDAPI_rumble_lock;
+static SDL_HIDAPI_RumbleContext rumble_context SDL_GUARDED_BY(SDL_HIDAPI_rumble_lock);
 
 static int SDLCALL SDL_HIDAPI_RumbleThread(void *data)
 {
@@ -63,7 +63,7 @@ static int SDLCALL SDL_HIDAPI_RumbleThread(void *data)
 
         SDL_SemWait(ctx->request_sem);
 
-        SDL_LockMutex(ctx->lock);
+        SDL_LockMutex(SDL_HIDAPI_rumble_lock);
         request = ctx->requests_tail;
         if (request) {
             if (request == ctx->requests_head) {
@@ -71,7 +71,7 @@ static int SDLCALL SDL_HIDAPI_RumbleThread(void *data)
             }
             ctx->requests_tail = request->prev;
         }
-        SDL_UnlockMutex(ctx->lock);
+        SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
 
         if (request) {
             SDL_LockMutex(request->device->dev_lock);
@@ -109,7 +109,7 @@ static void SDL_HIDAPI_StopRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
         ctx->thread = NULL;
     }
 
-    SDL_LockMutex(ctx->lock);
+    SDL_LockMutex(SDL_HIDAPI_rumble_lock);
     while (ctx->requests_tail) {
         request = ctx->requests_tail;
         if (request == ctx->requests_head) {
@@ -123,16 +123,16 @@ static void SDL_HIDAPI_StopRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
         (void)SDL_AtomicDecRef(&request->device->rumble_pending);
         SDL_free(request);
     }
-    SDL_UnlockMutex(ctx->lock);
+    SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
 
     if (ctx->request_sem) {
         SDL_DestroySemaphore(ctx->request_sem);
         ctx->request_sem = NULL;
     }
 
-    if (ctx->lock) {
-        SDL_DestroyMutex(ctx->lock);
-        ctx->lock = NULL;
+    if (SDL_HIDAPI_rumble_lock) {
+        SDL_DestroyMutex(SDL_HIDAPI_rumble_lock);
+        SDL_HIDAPI_rumble_lock = NULL;
     }
 
     SDL_AtomicSet(&ctx->initialized, SDL_FALSE);
@@ -140,8 +140,8 @@ static void SDL_HIDAPI_StopRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
 
 static int SDL_HIDAPI_StartRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
 {
-    ctx->lock = SDL_CreateMutex();
-    if (!ctx->lock) {
+    SDL_HIDAPI_rumble_lock = SDL_CreateMutex();
+    if (!SDL_HIDAPI_rumble_lock) {
         SDL_HIDAPI_StopRumbleThread(ctx);
         return -1;
     }
@@ -171,7 +171,8 @@ int SDL_HIDAPI_LockRumble(void)
         }
     }
 
-    return SDL_LockMutex(ctx->lock);
+    SDL_LockMutex(SDL_HIDAPI_rumble_lock);
+    return 0;
 }
 
 SDL_bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data, int **size, int *maximum_size)
@@ -239,9 +240,7 @@ int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const
 
 void SDL_HIDAPI_UnlockRumble(void)
 {
-    SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
-
-    SDL_UnlockMutex(ctx->lock);
+    SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
 }
 
 int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size)
@@ -254,7 +253,7 @@ int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size
         return SDL_SetError("Tried to send rumble with invalid size");
     }
 
-    if (SDL_HIDAPI_LockRumble() < 0) {
+    if (SDL_HIDAPI_LockRumble() != 0) {
         return -1;
     }
 

+ 7 - 4
src/joystick/hidapi/SDL_hidapi_rumble.h

@@ -25,12 +25,15 @@
 /* Handle rumble on a separate thread so it doesn't block the application */
 
 /* Advanced API */
-int SDL_HIDAPI_LockRumble(void);
+#ifdef SDL_THREAD_SAFETY_ANALYSIS
+extern SDL_mutex *SDL_HIDAPI_rumble_lock;
+#endif
+int SDL_HIDAPI_LockRumble(void) SDL_TRY_ACQUIRE(0, SDL_HIDAPI_rumble_lock);
 SDL_bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data, int **size, int *maximum_size);
-int SDL_HIDAPI_SendRumbleAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size);
+int SDL_HIDAPI_SendRumbleAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
 typedef void (*SDL_HIDAPI_RumbleSentCallback)(void *userdata);
-int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size, SDL_HIDAPI_RumbleSentCallback callback, void *userdata);
-void SDL_HIDAPI_UnlockRumble(void);
+int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size, SDL_HIDAPI_RumbleSentCallback callback, void *userdata) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
+void SDL_HIDAPI_UnlockRumble(void) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
 
 /* Simple API, will replace any pending rumble with the new data */
 int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size);

+ 3 - 1
src/joystick/hidapi/SDL_hidapi_shield.c

@@ -144,7 +144,7 @@ static int HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd,
         return SDL_SetError("Command data exceeds HID report size");
     }
 
-    if (SDL_HIDAPI_LockRumble() < 0) {
+    if (SDL_HIDAPI_LockRumble() != 0) {
         return -1;
     }
 
@@ -171,6 +171,8 @@ static SDL_bool HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_
 {
     SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->rumble_report_pending = SDL_FALSE;
     ctx->rumble_update_pending = SDL_FALSE;
     ctx->left_motor_amplitude = 0;

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_stadia.c

@@ -93,6 +93,8 @@ static SDL_bool HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device *device, SDL_
 {
     SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     SDL_zeroa(ctx->last_state);
 
     /* Initialize the joystick capabilities */

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_steam.c

@@ -1008,6 +1008,8 @@ static SDL_bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_J
     SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
     float update_rate_in_hz = 0.0f;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->report_sensors = SDL_FALSE;
     SDL_zero(ctx->m_assembler);
     SDL_zero(ctx->m_state);

+ 4 - 2
src/joystick/hidapi/SDL_hidapi_switch.c

@@ -319,7 +319,7 @@ static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int siz
     return SDL_hid_write(ctx->device->dev, data, size);
 #else
     /* Use the rumble thread for general asynchronous writes */
-    if (SDL_HIDAPI_LockRumble() < 0) {
+    if (SDL_HIDAPI_LockRumble() != 0) {
         return -1;
     }
     return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size);
@@ -1247,6 +1247,8 @@ static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_
     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
     Uint8 input_mode;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
 
     ctx->m_bSyncWrite = SDL_TRUE;
@@ -1887,7 +1889,7 @@ static void HandleMiniControllerStateR(Uint64 timestamp, SDL_Joystick *joystick,
     SDL_PrivateJoystickAxis(timestamp, joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
 }
 
-static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
+static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet) SDL_NO_THREAD_SAFETY_ANALYSIS /* We unlock and lock the device lock to be able to change IMU state */
 {
     Uint64 timestamp = SDL_GetTicksNS();
 

+ 3 - 1
src/joystick/hidapi/SDL_hidapi_wii.c

@@ -217,7 +217,7 @@ static SDL_bool WriteOutput(SDL_DriverWii_Context *ctx, const Uint8 *data, int s
         return SDL_hid_write(ctx->device->dev, data, size) >= 0;
     } else {
         /* Use the rumble thread for general asynchronous writes */
-        if (SDL_HIDAPI_LockRumble() < 0) {
+        if (SDL_HIDAPI_LockRumble() != 0) {
             return SDL_FALSE;
         }
         return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size) >= 0;
@@ -762,6 +762,8 @@ static SDL_bool HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
 {
     SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
 
     InitializeExtension(ctx);

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_xbox360.c

@@ -172,6 +172,8 @@ static SDL_bool HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL
 {
     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->joystick = joystick;
     SDL_zeroa(ctx->last_state);
 

+ 2 - 0
src/joystick/hidapi/SDL_hidapi_xbox360w.c

@@ -171,6 +171,8 @@ static SDL_bool HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SD
 {
     SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     SDL_zeroa(ctx->last_state);
 
     /* Initialize player index (needed for setting LEDs) */

+ 6 - 4
src/joystick/hidapi/SDL_hidapi_xboxone.c

@@ -230,7 +230,7 @@ static void SendAckIfNeeded(SDL_HIDAPI_Device *device, const Uint8 *data, int si
 #ifdef DEBUG_XBOX_PROTOCOL
         HIDAPI_DumpPacket("Xbox One sending ACK packet: size = %d", ack_packet, sizeof(ack_packet));
 #endif
-        if (SDL_HIDAPI_LockRumble() < 0 ||
+        if (SDL_HIDAPI_LockRumble() != 0 ||
             SDL_HIDAPI_SendRumbleAndUnlock(device, ack_packet, sizeof(ack_packet)) != sizeof(ack_packet)) {
             SDL_SetError("Couldn't send ack packet");
         }
@@ -250,7 +250,7 @@ static SDL_bool SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_C
      * It will cancel the announce packet if sent before that, and will be
      * ignored if sent during the negotiation.
      */
-    if (SDL_HIDAPI_LockRumble() < 0 ||
+    if (SDL_HIDAPI_LockRumble() != 0 ||
         SDL_HIDAPI_SendRumbleAndUnlock(device, serial_packet, sizeof(serial_packet)) != sizeof(serial_packet)) {
         SDL_SetError("Couldn't send serial packet");
         return SDL_FALSE;
@@ -308,7 +308,7 @@ static SDL_bool SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_
 #endif
         ctx->send_time = SDL_GetTicks();
 
-        if (SDL_HIDAPI_LockRumble() < 0 ||
+        if (SDL_HIDAPI_LockRumble() != 0 ||
             SDL_HIDAPI_SendRumbleAndUnlock(device, init_packet, packet->size) != packet->size) {
             SDL_SetError("Couldn't write Xbox One initialization packet");
             return SDL_FALSE;
@@ -411,6 +411,8 @@ static SDL_bool HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL
 {
     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
 
+    SDL_AssertJoysticksLocked();
+
     ctx->low_frequency_rumble = 0;
     ctx->high_frequency_rumble = 0;
     ctx->left_trigger_rumble = 0;
@@ -474,7 +476,7 @@ static int HIDAPI_DriverXboxOne_UpdateRumble(SDL_HIDAPI_Device *device)
     /* We're no longer pending, even if we fail to send the rumble below */
     ctx->rumble_pending = SDL_FALSE;
 
-    if (SDL_HIDAPI_LockRumble() < 0) {
+    if (SDL_HIDAPI_LockRumble() != 0) {
         return -1;
     }
 

+ 41 - 3
src/joystick/hidapi/SDL_hidapijoystick.c

@@ -86,7 +86,7 @@ static int SDL_HIDAPI_numdrivers = 0;
 static SDL_SpinLock SDL_HIDAPI_spinlock;
 static SDL_bool SDL_HIDAPI_hints_changed = SDL_FALSE;
 static Uint32 SDL_HIDAPI_change_count = 0;
-static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
+static SDL_HIDAPI_Device *SDL_HIDAPI_devices SDL_GUARDED_BY(SDL_joystick_lock);
 static int SDL_HIDAPI_numjoysticks = 0;
 static SDL_bool SDL_HIDAPI_combine_joycons = SDL_TRUE;
 static SDL_bool initialized = SDL_FALSE;
@@ -259,6 +259,8 @@ static SDL_HIDAPI_Device *HIDAPI_GetDeviceByIndex(int device_index, SDL_Joystick
 {
     SDL_HIDAPI_Device *device;
 
+    SDL_AssertJoysticksLocked();
+
     for (device = SDL_HIDAPI_devices; device; device = device->next) {
         if (device->parent) {
             continue;
@@ -280,6 +282,8 @@ static SDL_HIDAPI_Device *HIDAPI_GetJoystickByInfo(const char *path, Uint16 vend
 {
     SDL_HIDAPI_Device *device;
 
+    SDL_AssertJoysticksLocked();
+
     for (device = SDL_HIDAPI_devices; device; device = device->next) {
         if (device->vendor_id == vendor_id && device->product_id == product_id &&
             SDL_strcmp(device->path, path) == 0) {
@@ -318,7 +322,7 @@ static void HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
     SDL_UnlockMutex(device->dev_lock);
 }
 
-static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, SDL_bool *removed)
+static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, SDL_bool *removed) SDL_NO_THREAD_SAFETY_ANALYSIS /* We unlock the joystick lock to be able to open the HID device on Android */
 {
     *removed = SDL_FALSE;
 
@@ -421,6 +425,8 @@ static void SDL_HIDAPI_UpdateDrivers(void)
     SDL_HIDAPI_Device *device;
     SDL_bool removed;
 
+    SDL_AssertJoysticksLocked();
+
     SDL_HIDAPI_numdrivers = 0;
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
@@ -566,6 +572,8 @@ HIDAPI_HasConnectedUSBDevice(const char *serial)
 {
     SDL_HIDAPI_Device *device;
 
+    SDL_AssertJoysticksLocked();
+
     if (serial == NULL) {
         return SDL_FALSE;
     }
@@ -590,6 +598,8 @@ void HIDAPI_DisconnectBluetoothDevice(const char *serial)
 {
     SDL_HIDAPI_Device *device;
 
+    SDL_AssertJoysticksLocked();
+
     if (serial == NULL) {
         return;
     }
@@ -617,6 +627,8 @@ HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
     int i, j;
     SDL_JoystickID joystickID;
 
+    SDL_AssertJoysticksLocked();
+
     for (i = 0; i < device->num_children; ++i) {
         SDL_HIDAPI_Device *child = device->children[i];
         for (j = child->num_joysticks; j--;) {
@@ -712,6 +724,8 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf
     SDL_HIDAPI_Device *curr, *last = NULL;
     SDL_bool removed;
 
+    SDL_AssertJoysticksLocked();
+
     for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
     }
 
@@ -805,6 +819,8 @@ static void HIDAPI_DelDevice(SDL_HIDAPI_Device *device)
     SDL_HIDAPI_Device *curr, *last;
     int i;
 
+    SDL_AssertJoysticksLocked();
+
 #ifdef DEBUG_HIDAPI
     SDL_Log("Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->version, device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->name : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED");
 #endif
@@ -844,6 +860,8 @@ static SDL_bool HIDAPI_CreateCombinedJoyCons()
     SDL_HIDAPI_Device *device, *combined;
     SDL_HIDAPI_Device *joycons[2] = { NULL, NULL };
 
+    SDL_AssertJoysticksLocked();
+
     if (!SDL_HIDAPI_combine_joycons) {
         return SDL_FALSE;
     }
@@ -1155,6 +1173,8 @@ void HIDAPI_UpdateDevices(void)
 {
     SDL_HIDAPI_Device *device;
 
+    SDL_AssertJoysticksLocked();
+
     /* Update the devices, which may change connected joysticks and send events */
 
     /* Prepare the existing device list */
@@ -1257,6 +1277,8 @@ static int HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
     SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index, &joystickID);
     struct joystick_hwdata *hwdata;
 
+    SDL_AssertJoysticksLocked();
+
     if (device == NULL || !device->driver) {
         /* This should never happen - validated before being called */
         return SDL_SetError("Couldn't find HIDAPI device at index %d\n", device_index);
@@ -1294,6 +1316,8 @@ static int HIDAPI_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_ru
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
 
@@ -1309,6 +1333,8 @@ static int HIDAPI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rum
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
 
@@ -1324,6 +1350,8 @@ static Uint32 HIDAPI_JoystickGetCapabilities(SDL_Joystick *joystick)
 {
     Uint32 result = 0;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
 
@@ -1337,6 +1365,8 @@ static int HIDAPI_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green,
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
 
@@ -1352,6 +1382,8 @@ static int HIDAPI_JoystickSendEffect(SDL_Joystick *joystick, const void *data, i
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
 
@@ -1367,6 +1399,8 @@ static int HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool ena
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
 
@@ -1383,8 +1417,10 @@ static void HIDAPI_JoystickUpdate(SDL_Joystick *joystick)
     /* This is handled in SDL_HIDAPI_UpdateDevices() */
 }
 
-static void HIDAPI_JoystickClose(SDL_Joystick *joystick)
+static void HIDAPI_JoystickClose(SDL_Joystick *joystick) SDL_NO_THREAD_SAFETY_ANALYSIS /* We unlock the device lock so rumble can complete */
 {
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         SDL_HIDAPI_Device *device = joystick->hwdata->device;
         int i;
@@ -1415,6 +1451,8 @@ static void HIDAPI_JoystickQuit(void)
 {
     int i;
 
+    SDL_AssertJoysticksLocked();
+
     shutting_down = SDL_TRUE;
 
     SDL_HIDAPI_QuitRumble();

+ 30 - 1
src/joystick/linux/SDL_sysjoystick.c

@@ -848,6 +848,8 @@ static int allocate_hatdata(SDL_Joystick *joystick)
 {
     int i;
 
+    SDL_AssertJoysticksLocked();
+
     joystick->hwdata->hats =
         (struct hwdata_hat *)SDL_malloc(joystick->nhats *
                                         sizeof(struct hwdata_hat));
@@ -904,6 +906,8 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd)
     SDL_bool use_deadzones = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_DEADZONES, SDL_FALSE);
     SDL_bool use_hat_deadzones = SDL_GetHintBoolean(SDL_HINT_LINUX_HAT_DEADZONES, SDL_TRUE);
 
+    SDL_AssertJoysticksLocked();
+
     /* See if this device uses the new unified event API */
     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
@@ -1103,6 +1107,8 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd)
    on error. Returns -1 on error, 0 on success. */
 static int PrepareJoystickHwdata(SDL_Joystick *joystick, SDL_joylist_item *item)
 {
+    SDL_AssertJoysticksLocked();
+
     joystick->hwdata->item = item;
     joystick->hwdata->guid = item->guid;
     joystick->hwdata->effect.id = -1;
@@ -1151,6 +1157,8 @@ static int LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
 {
     SDL_joylist_item *item = JoystickByDevIndex(device_index);
 
+    SDL_AssertJoysticksLocked();
+
     if (item == NULL) {
         return SDL_SetError("No such device");
     }
@@ -1181,6 +1189,8 @@ static int LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rum
 {
     struct input_event event;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata->ff_rumble) {
         struct ff_effect *effect = &joystick->hwdata->effect;
 
@@ -1227,6 +1237,8 @@ static Uint32 LINUX_JoystickGetCapabilities(SDL_Joystick *joystick)
 {
     Uint32 result = 0;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata->ff_rumble || joystick->hwdata->ff_sine) {
         result |= SDL_JOYCAP_RUMBLE;
     }
@@ -1251,7 +1263,7 @@ static int LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enab
 
 static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axis, int value)
 {
-    const int hatnum = stick->hwdata->hats_indices[hatidx];
+    int hatnum;
     struct hwdata_hat *the_hat;
     struct hat_axis_correct *correct;
     const Uint8 position_map[3][3] = {
@@ -1260,6 +1272,9 @@ static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axi
         { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
     };
 
+    SDL_AssertJoysticksLocked();
+
+    hatnum = stick->hwdata->hats_indices[hatidx];
     the_hat = &stick->hwdata->hats[hatnum];
     correct = &stick->hwdata->hat_correct[hatidx];
     /* Hopefully we detected any analog axes and left them as is rather than trying
@@ -1299,6 +1314,8 @@ static int AxisCorrect(SDL_Joystick *joystick, int which, int value)
 {
     struct axis_correct *correct;
 
+    SDL_AssertJoysticksLocked();
+
     correct = &joystick->hwdata->abs_correct[which];
     if (correct->minimum != correct->maximum) {
         if (correct->use_deadzones) {
@@ -1334,6 +1351,8 @@ static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick)
     unsigned long keyinfo[NBITS(KEY_MAX)];
     int i;
 
+    SDL_AssertJoysticksLocked();
+
     /* Poll all axis */
     for (i = ABS_X; i < ABS_MAX; i++) {
         /* We don't need to test for digital hats here, they won't have has_abs[] set */
@@ -1388,6 +1407,8 @@ static void HandleInputEvents(SDL_Joystick *joystick)
     struct input_event events[32];
     int i, len, code, hat_index;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata->fresh) {
         PollAllValues(SDL_GetTicksNS(), joystick);
         joystick->hwdata->fresh = SDL_FALSE;
@@ -1471,6 +1492,8 @@ static void HandleClassicEvents(SDL_Joystick *joystick)
     int i, len, code, hat_index;
     Uint64 timestamp = SDL_GetTicksNS();
 
+    SDL_AssertJoysticksLocked();
+
     joystick->hwdata->fresh = SDL_FALSE;
     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
         len /= sizeof(events[0]);
@@ -1511,6 +1534,8 @@ static void HandleClassicEvents(SDL_Joystick *joystick)
 
 static void LINUX_JoystickUpdate(SDL_Joystick *joystick)
 {
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata->m_bSteamController) {
         SDL_UpdateSteamController(joystick);
         return;
@@ -1526,6 +1551,8 @@ static void LINUX_JoystickUpdate(SDL_Joystick *joystick)
 /* Function to close a joystick after use */
 static void LINUX_JoystickClose(SDL_Joystick *joystick)
 {
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         if (joystick->hwdata->effect.id >= 0) {
             ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
@@ -1585,6 +1612,8 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
     SDL_joylist_item *item = JoystickByDevIndex(device_index);
     unsigned int mapped;
 
+    SDL_AssertJoysticksLocked();
+
     if (item->checked_mapping) {
         if (item->mapping) {
             SDL_memcpy(out, item->mapping, sizeof(*out));

+ 40 - 13
src/joystick/virtual/SDL_virtualjoystick.c

@@ -28,32 +28,36 @@
 #include "../SDL_sysjoystick.h"
 #include "../SDL_joystick_c.h"
 
-static joystick_hwdata *g_VJoys = NULL;
+static joystick_hwdata *g_VJoys SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
 
 static joystick_hwdata *VIRTUAL_HWDataForIndex(int device_index)
 {
-    joystick_hwdata *vjoy = g_VJoys;
-    while (vjoy) {
+    joystick_hwdata *vjoy;
+
+    SDL_AssertJoysticksLocked();
+
+    for (vjoy = g_VJoys; vjoy; vjoy = vjoy->next) {
         if (device_index == 0) {
             break;
         }
         --device_index;
-        vjoy = vjoy->next;
     }
     return vjoy;
 }
 
 static void VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
 {
-    joystick_hwdata *cur = g_VJoys;
+    joystick_hwdata *cur;
     joystick_hwdata *prev = NULL;
 
+    SDL_AssertJoysticksLocked();
+
     if (hwdata == NULL) {
         return;
     }
 
     /* Remove hwdata from SDL-global list */
-    while (cur) {
+    for (cur = g_VJoys; cur; prev = cur, cur = cur->next) {
         if (hwdata == cur) {
             if (prev) {
                 prev->next = cur->next;
@@ -62,8 +66,6 @@ static void VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
             }
             break;
         }
-        prev = cur;
-        cur = cur->next;
     }
 
     if (hwdata->joystick) {
@@ -97,6 +99,8 @@ int SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *desc)
     int axis_triggerleft = -1;
     int axis_triggerright = -1;
 
+    SDL_AssertJoysticksLocked();
+
     if (desc == NULL) {
         return SDL_InvalidParamError("desc");
     }
@@ -328,11 +332,13 @@ static int VIRTUAL_JoystickInit(void)
 
 static int VIRTUAL_JoystickGetCount(void)
 {
+    joystick_hwdata *cur;
     int count = 0;
-    joystick_hwdata *cur = g_VJoys;
-    while (cur) {
+
+    SDL_AssertJoysticksLocked();
+
+    for (cur = g_VJoys; cur; cur = cur->next) {
         ++count;
-        cur = cur->next;
     }
     return count;
 }
@@ -391,7 +397,11 @@ static SDL_JoystickID VIRTUAL_JoystickGetDeviceInstanceID(int device_index)
 
 static int VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
 {
-    joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
+    joystick_hwdata *hwdata;
+
+    SDL_AssertJoysticksLocked();
+
+    hwdata = VIRTUAL_HWDataForIndex(device_index);
     if (hwdata == NULL) {
         return SDL_SetError("No such device");
     }
@@ -408,6 +418,8 @@ static int VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_r
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         joystick_hwdata *hwdata = joystick->hwdata;
         if (hwdata->desc.Rumble) {
@@ -426,6 +438,8 @@ static int VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_ru
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         joystick_hwdata *hwdata = joystick->hwdata;
         if (hwdata->desc.RumbleTriggers) {
@@ -442,9 +456,12 @@ static int VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_ru
 
 static Uint32 VIRTUAL_JoystickGetCapabilities(SDL_Joystick *joystick)
 {
-    joystick_hwdata *hwdata = joystick->hwdata;
+    joystick_hwdata *hwdata;
     Uint32 caps = 0;
 
+    SDL_AssertJoysticksLocked();
+
+    hwdata = joystick->hwdata;
     if (hwdata) {
         if (hwdata->desc.Rumble) {
             caps |= SDL_JOYCAP_RUMBLE;
@@ -463,6 +480,8 @@ static int VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         joystick_hwdata *hwdata = joystick->hwdata;
         if (hwdata->desc.SetLED) {
@@ -481,6 +500,8 @@ static int VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data,
 {
     int result;
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         joystick_hwdata *hwdata = joystick->hwdata;
         if (hwdata->desc.SendEffect) {
@@ -506,6 +527,8 @@ static void VIRTUAL_JoystickUpdate(SDL_Joystick *joystick)
     int i;
     Uint64 timestamp = SDL_GetTicksNS();
 
+    SDL_AssertJoysticksLocked();
+
     if (joystick == NULL) {
         return;
     }
@@ -532,6 +555,8 @@ static void VIRTUAL_JoystickUpdate(SDL_Joystick *joystick)
 
 static void VIRTUAL_JoystickClose(SDL_Joystick *joystick)
 {
+    SDL_AssertJoysticksLocked();
+
     if (joystick->hwdata) {
         joystick_hwdata *hwdata = joystick->hwdata;
         hwdata->joystick = NULL;
@@ -541,6 +566,8 @@ static void VIRTUAL_JoystickClose(SDL_Joystick *joystick)
 
 static void VIRTUAL_JoystickQuit(void)
 {
+    SDL_AssertJoysticksLocked();
+
     while (g_VJoys) {
         VIRTUAL_FreeHWData(g_VJoys);
     }

+ 17 - 34
src/sensor/SDL_sensor.c

@@ -48,23 +48,19 @@ static SDL_SensorDriver *SDL_sensor_drivers[] = {
     &SDL_DUMMY_SensorDriver
 #endif
 };
-static SDL_Sensor *SDL_sensors = NULL;
-static SDL_bool SDL_updating_sensor = SDL_FALSE;
 static SDL_mutex *SDL_sensor_lock = NULL; /* This needs to support recursive locks */
-static SDL_atomic_t SDL_next_sensor_instance_id;
+static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL;
+static SDL_atomic_t SDL_next_sensor_instance_id SDL_GUARDED_BY(SDL_sensor_lock);
+static SDL_bool SDL_updating_sensor SDL_GUARDED_BY(SDL_sensor_lock) = SDL_FALSE;
 
-void SDL_LockSensors(void)
+void SDL_LockSensors(void) SDL_ACQUIRE(SDL_sensor_lock)
 {
-    if (SDL_sensor_lock) {
-        SDL_LockMutex(SDL_sensor_lock);
-    }
+    SDL_LockMutex(SDL_sensor_lock);
 }
 
-void SDL_UnlockSensors(void)
+void SDL_UnlockSensors(void) SDL_RELEASE(SDL_sensor_lock)
 {
-    if (SDL_sensor_lock) {
-        SDL_UnlockMutex(SDL_sensor_lock);
-    }
+    SDL_UnlockMutex(SDL_sensor_lock);
 }
 
 int SDL_SensorInit(void)
@@ -142,8 +138,7 @@ static SDL_bool SDL_GetDriverAndSensorIndex(int device_index, SDL_SensorDriver *
 /*
  * Get the implementation dependent name of a sensor
  */
-const char *
-SDL_SensorGetDeviceName(int device_index)
+const char *SDL_SensorGetDeviceName(int device_index)
 {
     SDL_SensorDriver *driver;
     const char *name = NULL;
@@ -158,8 +153,7 @@ SDL_SensorGetDeviceName(int device_index)
     return name;
 }
 
-SDL_SensorType
-SDL_SensorGetDeviceType(int device_index)
+SDL_SensorType SDL_SensorGetDeviceType(int device_index)
 {
     SDL_SensorDriver *driver;
     SDL_SensorType type = SDL_SENSOR_INVALID;
@@ -187,8 +181,7 @@ int SDL_SensorGetDeviceNonPortableType(int device_index)
     return type;
 }
 
-SDL_SensorID
-SDL_SensorGetDeviceInstanceID(int device_index)
+SDL_SensorID SDL_SensorGetDeviceInstanceID(int device_index)
 {
     SDL_SensorDriver *driver;
     SDL_SensorID instance_id = -1;
@@ -209,8 +202,7 @@ SDL_SensorGetDeviceInstanceID(int device_index)
  *
  * This function returns a sensor identifier, or NULL if an error occurred.
  */
-SDL_Sensor *
-SDL_SensorOpen(int device_index)
+SDL_Sensor *SDL_SensorOpen(int device_index)
 {
     SDL_SensorDriver *driver;
     SDL_SensorID instance_id;
@@ -281,8 +273,7 @@ SDL_SensorOpen(int device_index)
 /*
  * Find the SDL_Sensor that owns this instance id
  */
-SDL_Sensor *
-SDL_SensorFromInstanceID(SDL_SensorID instance_id)
+SDL_Sensor *SDL_SensorFromInstanceID(SDL_SensorID instance_id)
 {
     SDL_Sensor *sensor;
 
@@ -316,8 +307,7 @@ static int SDL_PrivateSensorValid(SDL_Sensor *sensor)
 /*
  * Get the friendly name of this sensor
  */
-const char *
-SDL_SensorGetName(SDL_Sensor *sensor)
+const char *SDL_SensorGetName(SDL_Sensor *sensor)
 {
     if (!SDL_PrivateSensorValid(sensor)) {
         return NULL;
@@ -329,8 +319,7 @@ SDL_SensorGetName(SDL_Sensor *sensor)
 /*
  * Get the type of this sensor
  */
-SDL_SensorType
-SDL_SensorGetType(SDL_Sensor *sensor)
+SDL_SensorType SDL_SensorGetType(SDL_Sensor *sensor)
 {
     if (!SDL_PrivateSensorValid(sensor)) {
         return SDL_SENSOR_INVALID;
@@ -354,8 +343,7 @@ int SDL_SensorGetNonPortableType(SDL_Sensor *sensor)
 /*
  * Get the instance id for this opened sensor
  */
-SDL_SensorID
-SDL_SensorGetInstanceID(SDL_Sensor *sensor)
+SDL_SensorID SDL_SensorGetInstanceID(SDL_Sensor *sensor)
 {
     if (!SDL_PrivateSensorValid(sensor)) {
         return -1;
@@ -434,11 +422,11 @@ void SDL_SensorQuit(void)
 {
     int i;
 
+    SDL_LockSensors();
+
     /* Make sure we're not getting called in the middle of updating sensors */
     SDL_assert(!SDL_updating_sensor);
 
-    SDL_LockSensors();
-
     /* Stop the event polling */
     while (SDL_sensors) {
         SDL_sensors->ref_count = 1;
@@ -511,15 +499,10 @@ void SDL_SensorUpdate(void)
 
     SDL_updating_sensor = SDL_TRUE;
 
-    /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
-    SDL_UnlockSensors();
-
     for (sensor = SDL_sensors; sensor; sensor = sensor->next) {
         sensor->driver->Update(sensor);
     }
 
-    SDL_LockSensors();
-
     SDL_updating_sensor = SDL_FALSE;
 
     /* If any sensors were closed while updating, free them here */

+ 5 - 5
src/thread/generic/SDL_sysmutex.c

@@ -70,7 +70,7 @@ void SDL_DestroyMutex(SDL_mutex *mutex)
 }
 
 /* Lock the mutex */
-int SDL_LockMutex(SDL_mutex *mutex)
+int SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if SDL_THREADS_DISABLED
     return 0;
@@ -78,7 +78,7 @@ int SDL_LockMutex(SDL_mutex *mutex)
     SDL_threadID this_thread;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     this_thread = SDL_ThreadID();
@@ -108,7 +108,7 @@ int SDL_TryLockMutex(SDL_mutex *mutex)
     SDL_threadID this_thread;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     this_thread = SDL_ThreadID();
@@ -131,13 +131,13 @@ int SDL_TryLockMutex(SDL_mutex *mutex)
 }
 
 /* Unlock the mutex */
-int SDL_mutexV(SDL_mutex *mutex)
+int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if SDL_THREADS_DISABLED
     return 0;
 #else
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     /* If we don't own the mutex, we can't unlock it */

+ 5 - 5
src/thread/n3ds/SDL_sysmutex.c

@@ -51,10 +51,10 @@ void SDL_DestroyMutex(SDL_mutex *mutex)
 }
 
 /* Lock the mutex */
-int SDL_LockMutex(SDL_mutex *mutex)
+int SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     RecursiveLock_Lock(&mutex->lock);
@@ -66,17 +66,17 @@ int SDL_LockMutex(SDL_mutex *mutex)
 int SDL_TryLockMutex(SDL_mutex *mutex)
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     return RecursiveLock_TryLock(&mutex->lock);
 }
 
 /* Unlock the mutex */
-int SDL_mutexV(SDL_mutex *mutex)
+int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     RecursiveLock_Unlock(&mutex->lock);

+ 18 - 18
src/thread/ngage/SDL_sysmutex.cpp

@@ -67,14 +67,28 @@ void SDL_DestroyMutex(SDL_mutex *mutex)
     }
 }
 
+/* Lock the mutex */
+int SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
+{
+    if (mutex == NULL) {
+        return 0;
+    }
+
+    RMutex rmutex;
+    rmutex.SetHandle(mutex->handle);
+    rmutex.Wait();
+
+    return 0;
+}
+
 /* Try to lock the mutex */
 #if 0
 int
-SDL_TryLockMutex(SDL_mutex * mutex)
+SDL_TryLockMutex(SDL_mutex *mutex)
 {
     if (mutex == NULL)
     {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     // Not yet implemented.
@@ -82,25 +96,11 @@ SDL_TryLockMutex(SDL_mutex * mutex)
 }
 #endif
 
-/* Lock the mutex */
-int SDL_LockMutex(SDL_mutex *mutex)
-{
-    if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
-    }
-
-    RMutex rmutex;
-    rmutex.SetHandle(mutex->handle);
-    rmutex.Wait();
-
-    return 0;
-}
-
 /* Unlock the mutex */
-int SDL_UnlockMutex(SDL_mutex *mutex)
+int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     RMutex rmutex;

+ 25 - 22
src/thread/psp/SDL_sysmutex.c

@@ -72,56 +72,58 @@ void SDL_DestroyMutex(SDL_mutex *mutex)
     }
 }
 
-/* Try to lock the mutex */
-int SDL_TryLockMutex(SDL_mutex *mutex)
+/* Lock the mutex */
+int SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if SDL_THREADS_DISABLED
     return 0;
 #else
     SceInt32 res = 0;
+
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
-    res = sceKernelTryLockLwMutex(&mutex->lock, 1);
-    switch (res) {
-    case SCE_KERNEL_ERROR_OK:
-        return 0;
-        break;
-    case SCE_KERNEL_ERROR_WAIT_TIMEOUT:
-        return SDL_MUTEX_TIMEDOUT;
-        break;
-    default:
+    res = sceKernelLockLwMutex(&mutex->lock, 1, NULL);
+    if (res != SCE_KERNEL_ERROR_OK) {
         return SDL_SetError("Error trying to lock mutex: %lx", res);
-        break;
     }
 
-    return -1;
+    return 0;
 #endif /* SDL_THREADS_DISABLED */
 }
 
-/* Lock the mutex */
-int SDL_mutexP(SDL_mutex *mutex)
+/* Try to lock the mutex */
+int SDL_TryLockMutex(SDL_mutex *mutex)
 {
 #if SDL_THREADS_DISABLED
     return 0;
 #else
     SceInt32 res = 0;
+
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
-    res = sceKernelLockLwMutex(&mutex->lock, 1, NULL);
-    if (res != SCE_KERNEL_ERROR_OK) {
+    res = sceKernelTryLockLwMutex(&mutex->lock, 1);
+    switch (res) {
+    case SCE_KERNEL_ERROR_OK:
+        return 0;
+        break;
+    case SCE_KERNEL_ERROR_WAIT_TIMEOUT:
+        return SDL_MUTEX_TIMEDOUT;
+        break;
+    default:
         return SDL_SetError("Error trying to lock mutex: %lx", res);
+        break;
     }
 
-    return 0;
+    return -1;
 #endif /* SDL_THREADS_DISABLED */
 }
 
 /* Unlock the mutex */
-int SDL_mutexV(SDL_mutex *mutex)
+int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if SDL_THREADS_DISABLED
     return 0;
@@ -129,7 +131,7 @@ int SDL_mutexV(SDL_mutex *mutex)
     SceInt32 res = 0;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     res = sceKernelUnlockLwMutex(&mutex->lock, 1);
@@ -140,6 +142,7 @@ int SDL_mutexV(SDL_mutex *mutex)
     return 0;
 #endif /* SDL_THREADS_DISABLED */
 }
+
 #endif /* SDL_THREAD_PSP */
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 5 - 5
src/thread/pthread/SDL_sysmutex.c

@@ -74,14 +74,14 @@ void SDL_DestroyMutex(SDL_mutex *mutex)
 }
 
 /* Lock the mutex */
-int SDL_LockMutex(SDL_mutex *mutex)
+int SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if FAKE_RECURSIVE_MUTEX
     pthread_t this_thread;
 #endif
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
 #if FAKE_RECURSIVE_MUTEX
@@ -117,7 +117,7 @@ int SDL_TryLockMutex(SDL_mutex *mutex)
 #endif
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     retval = 0;
@@ -153,10 +153,10 @@ int SDL_TryLockMutex(SDL_mutex *mutex)
     return retval;
 }
 
-int SDL_UnlockMutex(SDL_mutex *mutex)
+int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
 #if FAKE_RECURSIVE_MUTEX

+ 7 - 6
src/thread/stdcpp/SDL_sysmutex.cpp

@@ -55,12 +55,12 @@ SDL_DestroyMutex(SDL_mutex *mutex)
     }
 }
 
-/* Lock the semaphore */
+/* Lock the mutex */
 extern "C" int
-SDL_mutexP(SDL_mutex *mutex)
+SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     try {
@@ -75,8 +75,9 @@ SDL_mutexP(SDL_mutex *mutex)
 int SDL_TryLockMutex(SDL_mutex *mutex)
 {
     int retval = 0;
+
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     if (mutex->cpp_mutex.try_lock() == false) {
@@ -87,10 +88,10 @@ int SDL_TryLockMutex(SDL_mutex *mutex)
 
 /* Unlock the mutex */
 extern "C" int
-SDL_mutexV(SDL_mutex *mutex)
+SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     mutex->cpp_mutex.unlock();

+ 24 - 22
src/thread/vita/SDL_sysmutex.c

@@ -68,56 +68,58 @@ void SDL_DestroyMutex(SDL_mutex *mutex)
     }
 }
 
-/* Try to lock the mutex */
-int SDL_TryLockMutex(SDL_mutex *mutex)
+/* Lock the mutex */
+int SDL_LockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if SDL_THREADS_DISABLED
     return 0;
 #else
     SceInt32 res = 0;
+
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
-    res = sceKernelTryLockLwMutex(&mutex->lock, 1);
-    switch (res) {
-    case SCE_KERNEL_OK:
-        return 0;
-        break;
-    case SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN:
-        return SDL_MUTEX_TIMEDOUT;
-        break;
-    default:
+    res = sceKernelLockLwMutex(&mutex->lock, 1, NULL);
+    if (res != SCE_KERNEL_OK) {
         return SDL_SetError("Error trying to lock mutex: %x", res);
-        break;
     }
 
-    return -1;
+    return 0;
 #endif /* SDL_THREADS_DISABLED */
 }
 
-/* Lock the mutex */
-int SDL_mutexP(SDL_mutex *mutex)
+/* Try to lock the mutex */
+int SDL_TryLockMutex(SDL_mutex *mutex)
 {
 #if SDL_THREADS_DISABLED
     return 0;
 #else
     SceInt32 res = 0;
+
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
-    res = sceKernelLockLwMutex(&mutex->lock, 1, NULL);
-    if (res != SCE_KERNEL_OK) {
+    res = sceKernelTryLockLwMutex(&mutex->lock, 1);
+    switch (res) {
+    case SCE_KERNEL_OK:
+        return 0;
+        break;
+    case SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN:
+        return SDL_MUTEX_TIMEDOUT;
+        break;
+    default:
         return SDL_SetError("Error trying to lock mutex: %x", res);
+        break;
     }
 
-    return 0;
+    return -1;
 #endif /* SDL_THREADS_DISABLED */
 }
 
 /* Unlock the mutex */
-int SDL_mutexV(SDL_mutex *mutex)
+int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
 #if SDL_THREADS_DISABLED
     return 0;
@@ -125,7 +127,7 @@ int SDL_mutexV(SDL_mutex *mutex)
     SceInt32 res = 0;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     res = sceKernelUnlockLwMutex(&mutex->lock, 1);

+ 10 - 10
src/thread/windows/SDL_sysmutex.c

@@ -74,13 +74,13 @@ static void SDL_DestroyMutex_srw(SDL_mutex *mutex)
     }
 }
 
-static int SDL_LockMutex_srw(SDL_mutex *_mutex)
+static int SDL_LockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
     DWORD this_thread;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     this_thread = GetCurrentThreadId();
@@ -106,7 +106,7 @@ static int SDL_TryLockMutex_srw(SDL_mutex *_mutex)
     int retval = 0;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     this_thread = GetCurrentThreadId();
@@ -124,12 +124,12 @@ static int SDL_TryLockMutex_srw(SDL_mutex *_mutex)
     return retval;
 }
 
-static int SDL_UnlockMutex_srw(SDL_mutex *_mutex)
+static int SDL_UnlockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
 
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     if (mutex->owner == GetCurrentThreadId()) {
@@ -189,11 +189,11 @@ static void SDL_DestroyMutex_cs(SDL_mutex *mutex_)
 }
 
 /* Lock the mutex */
-static int SDL_LockMutex_cs(SDL_mutex *mutex_)
+static int SDL_LockMutex_cs(SDL_mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     EnterCriticalSection(&mutex->cs);
@@ -206,7 +206,7 @@ static int SDL_TryLockMutex_cs(SDL_mutex *mutex_)
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
     int retval = 0;
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     if (TryEnterCriticalSection(&mutex->cs) == 0) {
@@ -216,11 +216,11 @@ static int SDL_TryLockMutex_cs(SDL_mutex *mutex_)
 }
 
 /* Unlock the mutex */
-static int SDL_UnlockMutex_cs(SDL_mutex *mutex_)
+static int SDL_UnlockMutex_cs(SDL_mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
     if (mutex == NULL) {
-        return SDL_InvalidParamError("mutex");
+        return 0;
     }
 
     LeaveCriticalSection(&mutex->cs);