Fixed rare crash trying to interrupt SDL_WaitEvent()

Fixes https://github.com/libsdl-org/SDL/issues/12797
This commit is contained in:
Sam Lantinga
2025-05-19 13:53:33 -07:00
parent 4db8fe2f9b
commit 992e4c59bd
7 changed files with 9 additions and 47 deletions

View File

@@ -1102,16 +1102,11 @@ static void SDL_SendWakeupEvent(void)
return; return;
} }
SDL_LockMutex(_this->wakeup_lock); // We only want to do this once while waiting for an event, so set it to NULL atomically here
{ SDL_Window *wakeup_window = (SDL_Window *)SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
if (_this->wakeup_window) { if (wakeup_window) {
_this->SendWakeupEvent(_this, _this->wakeup_window); _this->SendWakeupEvent(_this, wakeup_window);
// No more wakeup events needed until we enter a new wait
_this->wakeup_window = NULL;
}
} }
SDL_UnlockMutex(_this->wakeup_lock);
#endif #endif
} }
@@ -1549,18 +1544,7 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
*/ */
SDL_PumpEventsInternal(true); SDL_PumpEventsInternal(true);
SDL_LockMutex(_this->wakeup_lock); status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
{
status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
// 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;
}
}
SDL_UnlockMutex(_this->wakeup_lock);
if (status < 0) { if (status < 0) {
// Got an error: return // Got an error: return
break; break;
@@ -1573,8 +1557,6 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
if (timeoutNS > 0) { if (timeoutNS > 0) {
Sint64 elapsed = SDL_GetTicksNS() - start; Sint64 elapsed = SDL_GetTicksNS() - start;
if (elapsed >= timeoutNS) { if (elapsed >= timeoutNS) {
// Set wakeup_window to NULL without holding the lock.
_this->wakeup_window = NULL;
return 0; return 0;
} }
loop_timeoutNS = (timeoutNS - elapsed); loop_timeoutNS = (timeoutNS - elapsed);
@@ -1587,9 +1569,9 @@ static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeu
loop_timeoutNS = poll_intervalNS; loop_timeoutNS = poll_intervalNS;
} }
} }
SDL_SetAtomicPointer(&_this->wakeup_window, wakeup_window);
status = _this->WaitEventTimeout(_this, loop_timeoutNS); status = _this->WaitEventTimeout(_this, loop_timeoutNS);
// Set wakeup_window to NULL without holding the lock. SDL_SetAtomicPointer(&_this->wakeup_window, NULL);
_this->wakeup_window = NULL;
if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) { if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) {
// We may have woken up to poll. Try again // We may have woken up to poll. Try again
continue; continue;

View File

@@ -405,8 +405,7 @@ struct SDL_VideoDevice
bool checked_texture_framebuffer; bool checked_texture_framebuffer;
bool is_dummy; bool is_dummy;
bool suspend_screensaver; bool suspend_screensaver;
SDL_Window *wakeup_window; void *wakeup_window;
SDL_Mutex *wakeup_lock; // Initialized only if WaitEventTimeout/SendWakeupEvent are supported
int num_displays; int num_displays;
SDL_VideoDisplay **displays; SDL_VideoDisplay **displays;
SDL_Rect desktop_bounds; SDL_Rect desktop_bounds;

View File

@@ -4393,9 +4393,7 @@ void SDL_DestroyWindow(SDL_Window *window)
_this->current_glwin = NULL; _this->current_glwin = NULL;
} }
if (_this->wakeup_window == window) { SDL_CompareAndSwapAtomicPointer(&_this->wakeup_window, window, NULL);
_this->wakeup_window = NULL;
}
// Now invalidate magic // Now invalidate magic
SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, false); SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, false);

View File

@@ -49,9 +49,6 @@ static void Cocoa_VideoQuit(SDL_VideoDevice *_this);
static void Cocoa_DeleteDevice(SDL_VideoDevice *device) static void Cocoa_DeleteDevice(SDL_VideoDevice *device)
{ {
@autoreleasepool { @autoreleasepool {
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
CFBridgingRelease(device->internal); CFBridgingRelease(device->internal);
SDL_free(device); SDL_free(device);
} }
@@ -81,7 +78,6 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
return NULL; return NULL;
} }
device->internal = (SDL_VideoData *)CFBridgingRetain(data); device->internal = (SDL_VideoData *)CFBridgingRetain(data);
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = Cocoa_GetSystemTheme(); device->system_theme = Cocoa_GetSystemTheme();
// Set the function pointers // Set the function pointers

View File

@@ -447,9 +447,6 @@ static void Wayland_DeleteDevice(SDL_VideoDevice *device)
WAYLAND_wl_display_disconnect(data->display); WAYLAND_wl_display_disconnect(data->display);
SDL_ClearProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER); SDL_ClearProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER);
} }
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(data); SDL_free(data);
SDL_free(device); SDL_free(device);
SDL_WAYLAND_UnloadSymbols(); SDL_WAYLAND_UnloadSymbols();
@@ -576,7 +573,6 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
} }
device->internal = data; device->internal = data;
device->wakeup_lock = SDL_CreateMutex();
// Set the function pointers // Set the function pointers
device->VideoInit = Wayland_VideoInit; device->VideoInit = Wayland_VideoInit;

View File

@@ -124,9 +124,6 @@ static void WIN_DeleteDevice(SDL_VideoDevice *device)
SDL_UnloadObject(data->dxgiDLL); SDL_UnloadObject(data->dxgiDLL);
} }
#endif #endif
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->internal->rawinput); SDL_free(device->internal->rawinput);
SDL_free(device->internal); SDL_free(device->internal);
SDL_free(device); SDL_free(device);
@@ -152,7 +149,6 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
return NULL; return NULL;
} }
device->internal = data; device->internal = data;
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = WIN_GetSystemTheme(); device->system_theme = WIN_GetSystemTheme();
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)

View File

@@ -65,9 +65,6 @@ static void X11_DeleteDevice(SDL_VideoDevice *device)
X11_XCloseDisplay(data->request_display); X11_XCloseDisplay(data->request_display);
} }
SDL_free(data->windowlist); SDL_free(data->windowlist);
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->internal); SDL_free(device->internal);
SDL_free(device); SDL_free(device);
@@ -148,8 +145,6 @@ static SDL_VideoDevice *X11_CreateDevice(void)
return NULL; return NULL;
} }
device->wakeup_lock = SDL_CreateMutex();
#ifdef X11_DEBUG #ifdef X11_DEBUG
X11_XSynchronize(data->display, True); X11_XSynchronize(data->display, True);
#endif #endif