From 22decf4783fbda288feabd9b4a036d5304497660 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 1 Dec 2025 21:52:54 -0800
Subject: [PATCH] Fixed some clang thread-safety warnings
---
src/events/SDL_pen.c | 16 ++++-----
src/io/SDL_asyncio.c | 5 +--
src/joystick/SDL_gamepad.c | 4 +++
src/joystick/SDL_joystick.c | 18 ++++++++--
src/joystick/hidapi/SDL_hidapi_gip.c | 2 ++
src/joystick/hidapi/SDL_hidapi_steam_hori.c | 39 +++++++++++----------
src/joystick/hidapi/SDL_hidapi_wii.c | 2 ++
src/joystick/linux/SDL_sysjoystick.c | 4 +++
src/video/wayland/SDL_waylandmouse.c | 20 ++++-------
9 files changed, 63 insertions(+), 47 deletions(-)
diff --git a/src/events/SDL_pen.c b/src/events/SDL_pen.c
index 9a62b4014a6d7..0230249eff4bb 100644
--- a/src/events/SDL_pen.c
+++ b/src/events/SDL_pen.c
@@ -108,17 +108,9 @@ bool SDL_InitPen(void)
void SDL_QuitPen(void)
{
+ SDL_RemoveAllPenDevices(NULL, NULL);
SDL_DestroyRWLock(pen_device_rwlock);
pen_device_rwlock = NULL;
- if (pen_devices) {
- for (int i = pen_device_count; i--; ) {
- SDL_free(pen_devices[i].name);
- }
- SDL_free(pen_devices);
- pen_devices = NULL;
- }
- pen_device_count = 0;
- pen_touching = 0;
}
#if 0 // not a public API at the moment.
@@ -305,12 +297,16 @@ void SDL_RemoveAllPenDevices(void (*callback)(SDL_PenID instance_id, void *handl
if (pen_device_count > 0) {
SDL_assert(pen_devices != NULL);
for (int i = 0; i < pen_device_count; i++) {
- callback(pen_devices[i].instance_id, pen_devices[i].driverdata, userdata);
+ if (callback) {
+ callback(pen_devices[i].instance_id, pen_devices[i].driverdata, userdata);
+ }
SDL_free(pen_devices[i].name);
}
}
SDL_free(pen_devices);
pen_devices = NULL;
+ pen_device_count = 0;
+ pen_touching = 0;
SDL_UnlockRWLock(pen_device_rwlock);
}
diff --git a/src/io/SDL_asyncio.c b/src/io/SDL_asyncio.c
index 7696b7bf240a8..fb21f9171a0a9 100644
--- a/src/io/SDL_asyncio.c
+++ b/src/io/SDL_asyncio.c
@@ -219,7 +219,8 @@ static bool GetAsyncIOTaskOutcome(SDL_AsyncIOTask *task, SDL_AsyncIOOutcome *out
outcome->userdata = task->app_userdata;
// Take the completed task out of the SDL_AsyncIO that created it.
- SDL_LockMutex(asyncio->lock);
+ SDL_Mutex *lock = asyncio->lock;
+ SDL_LockMutex(lock);
LINKED_LIST_UNLINK(task, asyncio);
// see if it's time to queue a pending close request (close requested and no other pending tasks)
SDL_AsyncIOTask *closing = asyncio->closing;
@@ -232,7 +233,7 @@ static bool GetAsyncIOTaskOutcome(SDL_AsyncIOTask *task, SDL_AsyncIOOutcome *out
SDL_AddAtomicInt(&closing->queue->tasks_inflight, -1);
}
}
- SDL_UnlockMutex(task->asyncio->lock);
+ SDL_UnlockMutex(lock);
// was this the result of a closing task? Finally destroy the asyncio.
bool retval = true;
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index 03b3faec555b4..a291ec2694e7c 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -377,6 +377,8 @@ static const char *SDL_UpdateGamepadNameForID(SDL_JoystickID instance_id)
{
const char *current_name = NULL;
+ SDL_AssertJoysticksLocked();
+
GamepadMapping_t *mapping = SDL_PrivateGetGamepadMapping(instance_id, true);
if (mapping) {
if (SDL_strcmp(mapping->name, "*") == 0) {
@@ -1894,6 +1896,8 @@ static void SDL_UpdateGamepadFaceStyle(SDL_Gamepad *gamepad)
static void SDL_FixupHIDAPIMapping(SDL_Gamepad *gamepad)
{
+ SDL_AssertJoysticksLocked();
+
// Check to see if we need fixup
bool need_fixup = false;
for (int i = 0; i < gamepad->num_bindings; ++i) {
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 831cc541caf93..eb904e8a69c39 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -990,6 +990,8 @@ static const char *SDL_UpdateJoystickNameForID(SDL_JoystickID instance_id)
const char *current_name = NULL;
const SDL_SteamVirtualGamepadInfo *info;
+ SDL_AssertJoysticksLocked();
+
info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id);
if (info) {
current_name = info->name;
@@ -1078,6 +1080,8 @@ static bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
{
// printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);
+ SDL_AssertJoysticksLocked();
+
if (joystick->naxes == 2) {
// Assume D-pad or thumbstick style axes are centered at 0
return true;
@@ -1694,9 +1698,17 @@ int SDL_GetNumJoystickHats(SDL_Joystick *joystick)
*/
int SDL_GetNumJoystickBalls(SDL_Joystick *joystick)
{
- CHECK_JOYSTICK_MAGIC(joystick, -1);
+ int result;
- return joystick->nballs;
+ SDL_LockJoysticks();
+ {
+ CHECK_JOYSTICK_MAGIC(joystick, -1);
+
+ result = joystick->nballs;
+ }
+ SDL_UnlockJoysticks();
+
+ return result;
}
/*
@@ -2678,6 +2690,8 @@ static void SendSteamHandleUpdateEvents(void)
SDL_Joystick *joystick;
const SDL_SteamVirtualGamepadInfo *info;
+ SDL_AssertJoysticksLocked();
+
// Check to see if any Steam handles changed
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
bool changed = false;
diff --git a/src/joystick/hidapi/SDL_hidapi_gip.c b/src/joystick/hidapi/SDL_hidapi_gip.c
index e4d9d97f302df..b357b60f22cbd 100644
--- a/src/joystick/hidapi/SDL_hidapi_gip.c
+++ b/src/joystick/hidapi/SDL_hidapi_gip.c
@@ -2686,6 +2686,8 @@ static GIP_Attachment * HIDAPI_DriverGIP_FindAttachment(SDL_HIDAPI_Device *devic
GIP_Device *ctx = (GIP_Device *)device->context;
int i;
+ SDL_AssertJoysticksLocked();
+
for (i = 0; i < MAX_ATTACHMENTS; i++) {
if (ctx->attachments[i] && ctx->attachments[i]->joystick == joystick->instance_id) {
return ctx->attachments[i];
diff --git a/src/joystick/hidapi/SDL_hidapi_steam_hori.c b/src/joystick/hidapi/SDL_hidapi_steam_hori.c
index fc61e3f86e5d7..743ab179b8d05 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam_hori.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam_hori.c
@@ -114,18 +114,18 @@ static bool HIDAPI_DriverSteamHori_OpenJoystick(SDL_HIDAPI_Device *device, SDL_J
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_GAMEPAD_NUM_HORI_BUTTONS;
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
- joystick->nhats = 1;
-
- ctx->wireless = device->product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT;
-
- if (ctx->wireless && device->serial) {
- joystick->serial = SDL_strdup(device->serial);
- ctx->serial_needs_init = false;
- } else if (!ctx->wireless) {
- // Need to actual read from the device to init the serial
- HIDAPI_DriverSteamHori_UpdateDevice(device);
- }
-
+ joystick->nhats = 1;
+
+ ctx->wireless = device->product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT;
+
+ if (ctx->wireless && device->serial) {
+ joystick->serial = SDL_strdup(device->serial);
+ ctx->serial_needs_init = false;
+ } else if (!ctx->wireless) {
+ // Need to actual read from the device to init the serial
+ HIDAPI_DriverSteamHori_UpdateDevice(device);
+ }
+
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
@@ -275,12 +275,13 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_FL, ((data[7] & 0x80) != 0));
}
- if (!ctx->wireless && ctx->serial_needs_init) {
+ if (!ctx->wireless && ctx->serial_needs_init) {
char serial[18];
- (void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
- data[38], data[39], data[40], data[41], data[42], data[43]);
+ (void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
+ data[38], data[39], data[40], data[41], data[42], data[43]);
- joystick->serial = SDL_strdup(serial);
+ SDL_AssertJoysticksLocked();
+ joystick->serial = SDL_strdup(serial);
ctx->serial_needs_init = false;
}
@@ -320,7 +321,6 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
imu_data[1] = RemapValClamped(-1.0f * LOAD16(data[12], data[13]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale);
imu_data[2] = RemapValClamped(-1.0f * LOAD16(data[14], data[15]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale);
imu_data[0] = RemapValClamped(-1.0f * LOAD16(data[16], data[17]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale);
-
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, imu_data, 3);
@@ -334,8 +334,9 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
if (ctx->last_state[24] != data[24]) {
bool bCharging = (data[24] & 0x10) != 0;
int percent = (data[24] & 0xF) * 10;
- SDL_PowerState state;
- if (bCharging) {
+ SDL_PowerState state;
+
+ if (bCharging) {
state = SDL_POWERSTATE_CHARGING;
} else if (ctx->wireless) {
state = SDL_POWERSTATE_ON_BATTERY;
diff --git a/src/joystick/hidapi/SDL_hidapi_wii.c b/src/joystick/hidapi/SDL_hidapi_wii.c
index fb3e164a8d070..5434141046943 100644
--- a/src/joystick/hidapi/SDL_hidapi_wii.c
+++ b/src/joystick/hidapi/SDL_hidapi_wii.c
@@ -512,6 +512,8 @@ static void UpdatePowerLevelWiiU(SDL_Joystick *joystick, Uint8 extensionBatteryB
bool pluggedIn = !(extensionBatteryByte & 0x04);
Uint8 batteryLevel = extensionBatteryByte >> 4;
+ SDL_AssertJoysticksLocked();
+
if (pluggedIn) {
joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED;
} else {
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 6aa66463ef52b..f0ad06aa9d054 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -1161,6 +1161,8 @@ static SDL_JoystickID LINUX_JoystickGetDeviceInstanceID(int device_index)
static bool allocate_balldata(SDL_Joystick *joystick)
{
+ SDL_AssertJoysticksLocked();
+
joystick->hwdata->balls =
(struct hwdata_ball *)SDL_calloc(joystick->nballs, sizeof(struct hwdata_ball));
if (joystick->hwdata->balls == NULL) {
@@ -1776,6 +1778,8 @@ static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axi
static void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
{
+ SDL_AssertJoysticksLocked();
+
stick->hwdata->balls[ball].axis[axis] += value;
}
diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c
index 7e3aa255af69e..1801924897ef5 100644
--- a/src/video/wayland/SDL_waylandmouse.c
+++ b/src/video/wayland/SDL_waylandmouse.c
@@ -545,37 +545,29 @@ static void cursor_frame_done(void *data, struct wl_callback *cb, uint32_t time)
void Wayland_CursorStateSetFrameCallback(SDL_WaylandCursorState *state, void *userdata)
{
- if (cursor_thread_context.lock) {
- SDL_LockMutex(cursor_thread_context.lock);
- }
+ SDL_LockMutex(cursor_thread_context.lock);
state->frame_callback = wl_surface_frame(state->surface);
wl_callback_add_listener(state->frame_callback, &cursor_frame_listener, userdata);
- if (cursor_thread_context.lock) {
- SDL_UnlockMutex(cursor_thread_context.lock);
- }
+ SDL_UnlockMutex(cursor_thread_context.lock);
}
void Wayland_CursorStateDestroyFrameCallback(SDL_WaylandCursorState *state)
{
- if (cursor_thread_context.lock) {
- SDL_LockMutex(cursor_thread_context.lock);
- }
+ SDL_LockMutex(cursor_thread_context.lock);
if (state->frame_callback) {
wl_callback_destroy(state->frame_callback);
state->frame_callback = NULL;
}
- if (cursor_thread_context.lock) {
- SDL_UnlockMutex(cursor_thread_context.lock);
- }
+ SDL_UnlockMutex(cursor_thread_context.lock);
}
static void Wayland_CursorStateResetAnimation(SDL_WaylandCursorState *state, bool lock)
{
- if (lock && cursor_thread_context.lock) {
+ if (lock) {
SDL_LockMutex(cursor_thread_context.lock);
}
@@ -583,7 +575,7 @@ static void Wayland_CursorStateResetAnimation(SDL_WaylandCursorState *state, boo
state->current_frame_time_ms = 0;
state->current_frame = 0;
- if (lock && cursor_thread_context.lock) {
+ if (lock) {
SDL_UnlockMutex(cursor_thread_context.lock);
}
}