From 9cb0e4d09d7638163db94c4b7f14acad906f9eff Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 7 Dec 2022 06:35:18 +0530 Subject: [PATCH] Block handled signals early in startup before glfw is initialized to ensure that if the graphics libraries start a thread behind our backs, that threads defaults to haveing the signals blocked unless the library explicitly unblocks them. See #4636 --- kitty/child-monitor.c | 31 ++++++++++++++++++++++++++++++- kitty/fast_data_types.pyi | 1 + kitty/main.py | 6 ++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index a5a064e09..0f0391dfd 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -120,6 +120,34 @@ set_maximum_wait(monotonic_t val) { if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = val; } +#define KITTY_HANDLED_SIGNALS SIGINT, SIGHUP, SIGTERM, SIGCHLD, SIGUSR1, SIGUSR2, 0 + +static void +mask_variadic_signals(int sentinel, ...) { + // only need to mask signals when using SIGNAL_FD as signal actions are inherited by threads + // and only on Linux do we have reports of signals not being handled presumably because libwayland starts + // a thread behind our backs. See https://github.com/kovidgoyal/kitty/issues/4636 +#ifdef HAS_SIGNAL_FD + sigset_t signals; + sigemptyset(&signals); + va_list valist; + va_start(valist, sentinel); + while (true) { + int sig = va_arg(valist, int); + if (sig == sentinel) break; + sigaddset(&signals, sig); + } + va_end(valist); + sigprocmask(SIG_BLOCK, &signals, NULL); +#endif +} + +static PyObject* +mask_kitty_signals_process_wide(PyObject *self UNUSED, PyObject *a UNUSED) { + mask_variadic_signals(0, KITTY_HANDLED_SIGNALS); + Py_RETURN_NONE; +} + static PyObject * new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { ChildMonitor *self; @@ -138,7 +166,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { return NULL; } self = (ChildMonitor *)type->tp_alloc(type, 0); - if (!init_loop_data(&self->io_loop_data, SIGINT, SIGHUP, SIGTERM, SIGCHLD, SIGUSR1, SIGUSR2, 0)) return PyErr_SetFromErrno(PyExc_OSError); + if (!init_loop_data(&self->io_loop_data, KITTY_HANDLED_SIGNALS)) return PyErr_SetFromErrno(PyExc_OSError); self->talk_fd = talk_fd; self->listen_fd = listen_fd; self->prewarm_fd = prewarm_fd; @@ -1829,6 +1857,7 @@ static PyMethodDef module_methods[] = { METHODB(monitor_pid, METH_VARARGS), METHODB(send_data_to_peer, METH_VARARGS), METHODB(cocoa_set_menubar_title, METH_VARARGS), + METHODB(mask_kitty_signals_process_wide, METH_NOARGS), {"sigqueue", (PyCFunction)sig_queue, METH_VARARGS, ""}, {NULL} /* Sentinel */ }; diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 98b2175a7..4d23f4d53 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1498,3 +1498,4 @@ def unicode_database_version() -> Tuple[int, int, int]: ... def wrapped_kitten_names() -> List[str]: ... def expand_ansi_c_escapes(test: str) -> str: ... def update_tab_bar_edge_colors(os_window_id: int) -> bool: ... +def mask_kitty_signals_process_wide() -> None: ... diff --git a/kitty/main.py b/kitty/main.py index 93702fe44..62f59d26b 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -21,8 +21,9 @@ from .constants import ( ) from .fast_data_types import ( GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, SingleKey, create_os_window, - free_font_data, glfw_init, glfw_terminate, load_png_data, set_custom_cursor, - set_default_window_icon, set_options, + free_font_data, glfw_init, glfw_terminate, load_png_data, + mask_kitty_signals_process_wide, set_custom_cursor, set_default_window_icon, + set_options, ) from .fonts.box_drawing import set_scale from .fonts.render import set_font_family @@ -102,6 +103,7 @@ def init_glfw_module(glfw_module: str, debug_keyboard: bool = False, debug_rende def init_glfw(opts: Options, debug_keyboard: bool = False, debug_rendering: bool = False) -> str: + mask_kitty_signals_process_wide() glfw_module = 'cocoa' if is_macos else ('wayland' if is_wayland(opts) else 'x11') init_glfw_module(glfw_module, debug_keyboard, debug_rendering) return glfw_module