x11/wayland: Fix signal handling while blocking in WaitEventTimeout()

Add a new flag to avoid suppressing EINTR in SDL_IOReady(). Pass the
flag in WaitEventTimeout() to ensure that a SIGINT will wake up
SDL_WaitEvent() without another event coming in.
This commit is contained in:
Cameron Gutman 2021-10-30 19:30:34 -05:00 committed by Sam Lantinga
parent c97c46877f
commit a559864968
5 changed files with 37 additions and 11 deletions

View File

@ -83,7 +83,7 @@ SDL_IOReady(int fd, int flags, int timeoutMS)
result = select(fd + 1, rfdp, wfdp, NULL, tvp); result = select(fd + 1, rfdp, wfdp, NULL, tvp);
#endif /* HAVE_POLL */ #endif /* HAVE_POLL */
} while ( result < 0 && errno == EINTR ); } while ( result < 0 && errno == EINTR && !(flags & SDL_IOR_NO_RETRY));
return result; return result;
} }

View File

@ -28,6 +28,7 @@
#define SDL_IOR_READ 0x1 #define SDL_IOR_READ 0x1
#define SDL_IOR_WRITE 0x2 #define SDL_IOR_WRITE 0x2
#define SDL_IOR_NO_RETRY 0x4
extern int SDL_IOReady(int fd, int flags, int timeoutMS); extern int SDL_IOReady(int fd, int flags, int timeoutMS);

View File

@ -827,6 +827,7 @@ SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event,
a) All pending events are batch processed after waking up from a wait a) All pending events are batch processed after waking up from a wait
b) Waiting can be completely skipped if events are already available to be pumped b) Waiting can be completely skipped if events are already available to be pumped
c) Periodic processing that takes place in some platform PumpEvents() functions happens c) Periodic processing that takes place in some platform PumpEvents() functions happens
d) Signals received in WaitEventTimeout() are turned into SDL events
*/ */
SDL_PumpEvents(); SDL_PumpEvents();
@ -847,7 +848,6 @@ SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event,
} }
if (status > 0) { if (status > 0) {
/* There is an event, we can return. */ /* There is an event, we can return. */
SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
return 1; return 1;
} }
/* No events found in the queue, call WaitEventTimeout to wait for an event. */ /* No events found in the queue, call WaitEventTimeout to wait for an event. */

View File

@ -58,6 +58,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <poll.h> #include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h> #include <xkbcommon/xkbcommon-compose.h>
#include "../../events/imKStoUCS.h" #include "../../events/imKStoUCS.h"
@ -259,12 +260,14 @@ Wayland_WaitEventTimeout(_THIS, int timeout)
/* wl_display_prepare_read() will return -1 if the default queue is not empty. /* wl_display_prepare_read() will return -1 if the default queue is not empty.
* If the default queue is empty, it will prepare us for our SDL_IOReady() call. */ * If the default queue is empty, it will prepare us for our SDL_IOReady() call. */
if (WAYLAND_wl_display_prepare_read(d->display) == 0) { if (WAYLAND_wl_display_prepare_read(d->display) == 0) {
if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_IOR_READ, timeout) > 0) { /* Use SDL_IOR_NO_RETRY to ensure SIGINT will break us out of our wait */
int err = SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_IOR_READ | SDL_IOR_NO_RETRY, timeout);
if (err > 0) {
/* There are new events available to read */ /* There are new events available to read */
WAYLAND_wl_display_read_events(d->display); WAYLAND_wl_display_read_events(d->display);
WAYLAND_wl_display_dispatch_pending(d->display); WAYLAND_wl_display_dispatch_pending(d->display);
return 1; return 1;
} else { } else if (err == 0) {
/* No events available within the timeout */ /* No events available within the timeout */
WAYLAND_wl_display_cancel_read(d->display); WAYLAND_wl_display_cancel_read(d->display);
@ -277,6 +280,17 @@ Wayland_WaitEventTimeout(_THIS, int timeout)
} }
return 0; return 0;
} else {
/* Error returned from poll()/select() */
WAYLAND_wl_display_cancel_read(d->display);
if (errno == EINTR) {
/* If the wait was interrupted by a signal, we may have generated a
* SDL_QUIT event. Let the caller know to call SDL_PumpEvents(). */
return 1;
} else {
return err;
}
} }
} else { } else {
/* We already had pending events */ /* We already had pending events */

View File

@ -1585,14 +1585,25 @@ X11_WaitEventTimeout(_THIS, int timeout)
} else { } else {
return 0; return 0;
} }
} else if (timeout > 0) {
if (SDL_IOReady(ConnectionNumber(display), SDL_IOR_READ, timeout) > 0) {
X11_XNextEvent(display, &xevent);
} else {
return 0;
}
} else { } else {
X11_XNextEvent(display, &xevent); /* Use SDL_IOR_NO_RETRY to ensure SIGINT will break us out of our wait */
int err = SDL_IOReady(ConnectionNumber(display), SDL_IOR_READ | SDL_IOR_NO_RETRY, timeout);
if (err > 0) {
X11_XNextEvent(display, &xevent);
} else if (err == 0) {
/* Timeout */
return 0;
} else {
/* Error returned from poll()/select() */
if (errno == EINTR) {
/* If the wait was interrupted by a signal, we may have generated a
* SDL_QUIT event. Let the caller know to call SDL_PumpEvents(). */
return 1;
} else {
return err;
}
}
} }
X11_DispatchEvent(_this, &xevent); X11_DispatchEvent(_this, &xevent);