mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-05 05:24:42 +00:00
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:
@@ -546,9 +546,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;
|
||||
|
||||
@@ -605,8 +603,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;
|
||||
}
|
||||
@@ -650,9 +649,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;
|
||||
}
|
||||
|
||||
@@ -746,17 +743,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;
|
||||
}
|
||||
|
||||
@@ -768,16 +766,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) {
|
||||
@@ -846,12 +844,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();
|
||||
@@ -865,14 +859,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;
|
||||
}
|
||||
@@ -899,12 +891,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) {
|
||||
@@ -914,10 +905,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 */
|
||||
@@ -1002,58 +991,59 @@ static int SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Eve
|
||||
/* We only want a single sentinel in the queue. We could get more than one if event is NULL,
|
||||
* since the SDL_PeepEvents() call below won't remove it in that case.
|
||||
*/
|
||||
int status;
|
||||
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 (timeout > 0) {
|
||||
Uint32 elapsed = SDL_GetTicks() - start;
|
||||
if (elapsed >= (Uint32)timeout) {
|
||||
/* Set wakeup_window to NULL without holding the lock. */
|
||||
_this->wakeup_window = NULL;
|
||||
return 0;
|
||||
}
|
||||
loop_timeout = (int)((Uint32)timeout - elapsed);
|
||||
}
|
||||
if (need_periodic_poll) {
|
||||
if (loop_timeout >= 0) {
|
||||
loop_timeout = SDL_min(loop_timeout, PERIODIC_POLL_INTERVAL_MS);
|
||||
} else {
|
||||
loop_timeout = PERIODIC_POLL_INTERVAL_MS;
|
||||
}
|
||||
}
|
||||
status = _this->WaitEventTimeout(_this, loop_timeout);
|
||||
/* Set wakeup_window to NULL without holding the lock. */
|
||||
_this->wakeup_window = NULL;
|
||||
if (status == 0 && need_periodic_poll && loop_timeout == PERIODIC_POLL_INTERVAL_MS) {
|
||||
/* 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 .*/
|
||||
}
|
||||
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 (timeout > 0) {
|
||||
Uint32 elapsed = SDL_GetTicks() - start;
|
||||
if (elapsed >= (Uint32)timeout) {
|
||||
/* Set wakeup_window to NULL without holding the lock. */
|
||||
_this->wakeup_window = NULL;
|
||||
return 0;
|
||||
}
|
||||
loop_timeout = (int)((Uint32)timeout - elapsed);
|
||||
}
|
||||
if (need_periodic_poll) {
|
||||
if (loop_timeout >= 0) {
|
||||
loop_timeout = SDL_min(loop_timeout, PERIODIC_POLL_INTERVAL_MS);
|
||||
} else {
|
||||
loop_timeout = PERIODIC_POLL_INTERVAL_MS;
|
||||
}
|
||||
}
|
||||
status = _this->WaitEventTimeout(_this, loop_timeout);
|
||||
/* Set wakeup_window to NULL without holding the lock. */
|
||||
_this->wakeup_window = NULL;
|
||||
if (status == 0 && need_periodic_poll && loop_timeout == PERIODIC_POLL_INTERVAL_MS) {
|
||||
/* 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;
|
||||
}
|
||||
@@ -1187,11 +1177,10 @@ int SDL_PushEvent(SDL_Event *event)
|
||||
event->common.timestamp = SDL_GetTicks();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1219,11 +1208,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) {
|
||||
@@ -1237,32 +1223,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;
|
||||
@@ -1275,7 +1254,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));
|
||||
@@ -1289,16 +1269,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) {
|
||||
@@ -1315,16 +1293,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;
|
||||
@@ -1332,10 +1308,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)
|
||||
@@ -1384,8 +1358,7 @@ Uint8 SDL_EventState(Uint32 type, int state)
|
||||
return current_state;
|
||||
}
|
||||
|
||||
Uint32
|
||||
SDL_RegisterEvents(int numevents)
|
||||
Uint32 SDL_RegisterEvents(int numevents)
|
||||
{
|
||||
Uint32 event_base;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user