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

@@ -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;
}
/* Joystick must be haptic */
if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
SDL_SetError("Haptic: Joystick isn't a haptic device.");
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;
SDL_LockJoysticks();
{
/* Must be a valid joystick */
if (!SDL_PrivateJoystickValid(joystick)) {
SDL_SetError("Haptic: Joystick isn't valid.");
SDL_UnlockJoysticks();
return NULL;
}
hapticlist = hapticlist->next;
}
/* Create the haptic device */
haptic = (SDL_Haptic *)SDL_malloc((sizeof *haptic));
if (haptic == NULL) {
SDL_OutOfMemory();
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;
}
/* 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;
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;
}
/* 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);
SDL_UnlockJoysticks();
return NULL;
}
}
SDL_UnlockJoysticks();
/* Add haptic to list */
++haptic->ref_count;