Fix #10436
Some checks failed
CI / Linux (python=3.14 cc=clang sanitize=1) (push) Has been cancelled
CI / Linux (python=3.12 cc=gcc sanitize=0) (push) Has been cancelled
CI / Linux (python=3.13 cc=gcc sanitize=1) (push) Has been cancelled
CI / Linux package (push) Has been cancelled
CI / Bundle test (macos-latest) (push) Has been cancelled
CI / Bundle test (ubuntu-latest) (push) Has been cancelled
CI / macOS Brew (push) Has been cancelled
CI / Test ./dev.sh and benchmark (push) Has been cancelled
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (c, macos-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Has been cancelled
Depscan / Scan dependencies for vulnerabilities (push) Has been cancelled

This commit is contained in:
Kovid Goyal 2026-09-04 21:04:24 +05:30
parent b14ae3bf21
commit f3fdc21850
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 23 additions and 6 deletions

View file

@ -308,6 +308,12 @@ Detailed list of changes
files that no longer exist. The dropped files are now kept alive for
ten minutes and removed when kitty quits (:iss:`10430`)
- macOS: Fix all signal handling being permanently disabled after the first
window that used the graphics protocol is closed. This caused exited window
shells to accumulate as zombie processes and also broke reloading the config
with ``SIGUSR1`` and quitting on ``SIGINT``/``SIGTERM``/``SIGHUP``
(:iss:`10436`)
0.48.2 [2026-07-30]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

13
glfw/backend_utils.c vendored
View file

@ -329,6 +329,15 @@ finalizePollData(EventLoopData *eld) {
#endif
}
static int
display_fd_ready(EventLoopData *eld) {
// watches[0] is always the display fd. Errors count as ready: the display
// callback must complete the read rather than cancel it, so that a
// compositor disconnect is turned into a display error instead of a poll()
// that keeps returning immediately forever.
return eld->fds[0].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL);
}
int
pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func display_callback) {
int read_ok = 0;
@ -344,7 +353,7 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func displ
errno = 0;
result = pollWithTimeout(eld->fds, eld->watches_count, timeout);
int saved_errno = errno;
if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL);
if (display_callback) display_callback(result, display_fd_ready(eld), NULL);
dispatchTimers(eld);
if (result > 0) {
dispatchEvents(eld);
@ -359,7 +368,7 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func displ
errno = 0;
result = poll(eld->fds, eld->watches_count, -1);
int saved_errno = errno;
if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL);
if (display_callback) display_callback(result, display_fd_ready(eld), NULL);
dispatchTimers(eld);
if (result > 0) {
dispatchEvents(eld);

View file

@ -1826,8 +1826,8 @@ io_loop(void *data) {
ret = poll(children_fds, self->count + EXTRA_FDS, -1);
}
if (ret > 0) {
if (children_fds[0].revents && POLLIN) drain_fd(children_fds[0].fd); // wakeup
if (children_fds[1].revents && POLLIN) {
if (children_fds[0].revents & POLLIN) drain_fd(children_fds[0].fd); // wakeup
if (children_fds[1].revents & POLLIN) {
SignalSet ss = {0};
data_received = true;
read_signals(children_fds[1].fd, handle_signal, &ss);

View file

@ -88,7 +88,9 @@ init_loop_data(LoopData *ld, ...) {
static void
remove_signal_handlers(LoopData *ld) {
#ifndef HAS_SIGNAL_FD
signal_write_fd = -1;
// Only clear the global write fd if it is owned by this loop. Loops that
// handle no signals must not disable signal delivery for the loop that does.
if (ld->signal_fds[1] > -1 && signal_write_fd == ld->signal_fds[1]) signal_write_fd = -1;
CLOSE(signal_fds, 0);
CLOSE(signal_fds, 1);
#endif
@ -97,7 +99,7 @@ remove_signal_handlers(LoopData *ld) {
safe_close(ld->signal_read_fd, __FILE__, __LINE__);
sigprocmask(SIG_UNBLOCK, &ld->signals, NULL);
#endif
for (size_t i = 0; i < ld->num_handled_signals; i++) signal(ld->num_handled_signals, SIG_DFL);
for (size_t i = 0; i < ld->num_handled_signals; i++) signal(ld->handled_signals[i], SIG_DFL);
}
ld->signal_read_fd = -1;
ld->num_handled_signals = 0;