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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
diff --git a/src/core/unix/SDL_poll.c b/src/core/unix/SDL_poll.c
index ec0a533..dc0abd1 100644
--- a/src/core/unix/SDL_poll.c
+++ b/src/core/unix/SDL_poll.c
@@ -83,7 +83,7 @@ SDL_IOReady(int fd, int flags, int timeoutMS)
result = select(fd + 1, rfdp, wfdp, NULL, tvp);
#endif /* HAVE_POLL */
- } while ( result < 0 && errno == EINTR );
+ } while ( result < 0 && errno == EINTR && !(flags & SDL_IOR_NO_RETRY));
return result;
}
diff --git a/src/core/unix/SDL_poll.h b/src/core/unix/SDL_poll.h
index 10497d1..7716eab 100644
--- a/src/core/unix/SDL_poll.h
+++ b/src/core/unix/SDL_poll.h
@@ -28,6 +28,7 @@
#define SDL_IOR_READ 0x1
#define SDL_IOR_WRITE 0x2
+#define SDL_IOR_NO_RETRY 0x4
extern int SDL_IOReady(int fd, int flags, int timeoutMS);
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index 51d3bd6..36baef6 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -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
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
+ d) Signals received in WaitEventTimeout() are turned into SDL events
*/
SDL_PumpEvents();
@@ -847,7 +848,6 @@ SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event,
}
if (status > 0) {
/* There is an event, we can return. */
- SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
return 1;
}
/* No events found in the queue, call WaitEventTimeout to wait for an event. */
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 607c6a2..f52b261 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -58,6 +58,7 @@
#include <sys/mman.h>
#include <poll.h>
#include <unistd.h>
+#include <errno.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.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.
* 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 (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 */
WAYLAND_wl_display_read_events(d->display);
WAYLAND_wl_display_dispatch_pending(d->display);
return 1;
- } else {
+ } else if (err == 0) {
/* No events available within the timeout */
WAYLAND_wl_display_cancel_read(d->display);
@@ -277,6 +280,17 @@ Wayland_WaitEventTimeout(_THIS, int timeout)
}
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 {
/* We already had pending events */
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index ccab1fb..6640556 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -1585,14 +1585,25 @@ X11_WaitEventTimeout(_THIS, int timeout)
} else {
return 0;
}
- } else if (timeout > 0) {
- if (SDL_IOReady(ConnectionNumber(display), SDL_IOR_READ, timeout) > 0) {
+ } else {
+ /* 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 {
+ } 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;
+ }
}
- } else {
- X11_XNextEvent(display, &xevent);
}
X11_DispatchEvent(_this, &xevent);