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"
This commit is contained in:
Sam Lantinga
2022-12-13 14:03:40 -08:00
parent 582fb3901a
commit d59caffe2c
42 changed files with 1667 additions and 1174 deletions

View File

@@ -67,6 +67,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)) {

View File

@@ -408,6 +408,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;
@@ -424,6 +427,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();
}
@@ -469,6 +474,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;

View File

@@ -100,6 +100,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 */

View File

@@ -234,6 +234,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;
@@ -630,6 +632,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);

View File

@@ -668,6 +668,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;

View File

@@ -822,6 +822,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;
@@ -961,7 +963,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;
}

View File

@@ -46,13 +46,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)
{
@@ -65,7 +65,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) {
@@ -73,7 +73,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);
@@ -111,7 +111,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) {
@@ -125,16 +125,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);
@@ -142,8 +142,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;
}
@@ -173,7 +173,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)
@@ -241,9 +242,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)
@@ -256,7 +255,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;
}

View File

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

View File

@@ -148,7 +148,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;
}
@@ -175,6 +175,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;

View File

@@ -96,6 +96,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 */

View File

@@ -1012,6 +1012,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);

View File

@@ -323,7 +323,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);
@@ -1253,6 +1253,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;
@@ -1891,7 +1893,7 @@ static void HandleMiniControllerStateR(SDL_Joystick *joystick, SDL_DriverSwitch_
SDL_PrivateJoystickAxis(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 */
{
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft) {
if (ctx->device->parent || ctx->m_bVerticalMode) {

View File

@@ -221,7 +221,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;
@@ -770,6 +770,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);

View File

@@ -176,6 +176,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);

View File

@@ -175,6 +175,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) */

View File

@@ -234,7 +234,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");
}
@@ -254,7 +254,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;
@@ -312,7 +312,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;
@@ -415,6 +415,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;
@@ -478,7 +480,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;
}

View File

@@ -91,7 +91,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;
@@ -264,6 +264,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;
@@ -285,6 +287,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) {
@@ -323,7 +327,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;
@@ -426,6 +430,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];
@@ -571,6 +577,8 @@ HIDAPI_HasConnectedUSBDevice(const char *serial)
{
SDL_HIDAPI_Device *device;
SDL_AssertJoysticksLocked();
if (serial == NULL) {
return SDL_FALSE;
}
@@ -595,6 +603,8 @@ void HIDAPI_DisconnectBluetoothDevice(const char *serial)
{
SDL_HIDAPI_Device *device;
SDL_AssertJoysticksLocked();
if (serial == NULL) {
return;
}
@@ -622,6 +632,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--;) {
@@ -717,6 +729,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) {
}
@@ -810,6 +824,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
@@ -849,6 +865,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;
}
@@ -1160,6 +1178,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 */
@@ -1262,6 +1282,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);
@@ -1299,6 +1321,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;
@@ -1314,6 +1338,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;
@@ -1329,6 +1355,8 @@ static Uint32 HIDAPI_JoystickGetCapabilities(SDL_Joystick *joystick)
{
Uint32 result = 0;
SDL_AssertJoysticksLocked();
if (joystick->hwdata) {
SDL_HIDAPI_Device *device = joystick->hwdata->device;
@@ -1342,6 +1370,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;
@@ -1357,6 +1387,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;
@@ -1372,6 +1404,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;
@@ -1388,8 +1422,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;
@@ -1420,6 +1456,8 @@ static void HIDAPI_JoystickQuit(void)
{
int i;
SDL_AssertJoysticksLocked();
shutting_down = SDL_TRUE;
SDL_HIDAPI_QuitRumble();