From 8672a295035801fa6e143cc688aba0b67cd68e34 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 23 Oct 2017 12:42:03 +0530 Subject: [PATCH] Use a C based SIGCHLD handler Running python code in signal handlers makes me nervous --- kitty/data-types.c | 25 +++++++++++++++++++++++++ kitty/main.py | 20 +++----------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/kitty/data-types.c b/kitty/data-types.c index 0648acfaf..0749ec7f7 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -9,6 +9,8 @@ #include "modes.h" #include #include +#include +#include #ifdef WITH_PROFILER #include #endif @@ -81,6 +83,28 @@ pyset_iutf8(PyObject UNUSED *self, PyObject *args) { Py_RETURN_NONE; } +static void +handle_sigchld(int UNUSED signum, siginfo_t *sinfo, void UNUSED *unused) { + if (sinfo->si_code != CLD_EXITED) return; + int sav_errno = errno, status; + while(true) { + if (waitpid(sinfo->si_pid, &status, WNOHANG) == -1) { + if (errno != EINTR) break; + } else break; + } + errno = sav_errno; +} + +static PyObject* +install_sigchld_handler(PyObject UNUSED *self) { + struct sigaction sa; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handle_sigchld; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGCHLD, &sa, NULL) == -1) return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; +} + #ifdef WITH_PROFILER static PyObject* start_profiler(PyObject UNUSED *self, PyObject *args) { @@ -105,6 +129,7 @@ static PyMethodDef module_methods[] = { {"redirect_std_streams", (PyCFunction)redirect_std_streams, METH_VARARGS, ""}, {"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""}, {"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""}, + {"install_sigchld_handler", (PyCFunction)install_sigchld_handler, METH_NOARGS, ""}, #ifdef WITH_PROFILER {"start_profiler", (PyCFunction)start_profiler, METH_VARARGS, ""}, {"stop_profiler", (PyCFunction)stop_profiler, METH_NOARGS, ""}, diff --git a/kitty/main.py b/kitty/main.py index 0366315dc..b31d3f4a5 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -3,7 +3,6 @@ # License: GPL v3 Copyright: 2016, Kovid Goyal import argparse -import errno import locale import os import signal @@ -25,8 +24,8 @@ from .fast_data_types import ( GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_PROFILE, GLFW_SAMPLES, GLFW_STENCIL_BITS, GLFWWindow, change_wcwidth, check_for_extensions, clear_buffers, glewInit, glfw_init, glfw_init_hint_string, - glfw_swap_interval, glfw_terminate, glfw_window_hint, set_logical_dpi, - set_options + glfw_swap_interval, glfw_terminate, glfw_window_hint, + install_sigchld_handler, set_logical_dpi, set_options ) from .layout import all_layouts from .utils import color_as_int, detach, get_logical_dpi, safe_print @@ -245,19 +244,6 @@ def setup_profiling(args): print('To view the graphical call data, use: kcachegrind', cg) -def reap_zombies(*a): - while True: - try: - pid, status = os.waitpid(-1, os.WNOHANG) - if pid == 0: - break - except OSError as err: - if err.errno != errno.EINTR: - break - except Exception: - break - - def main(): try: sys.setswitchinterval(1000.0) # we have only a single python thread @@ -302,7 +288,7 @@ def main(): try: with setup_profiling(args): # Avoid needing to launch threads to reap zombies - signal.signal(signal.SIGCHLD, reap_zombies) + install_sigchld_handler() run_app(opts, args) signal.signal(signal.SIGCHLD, signal.SIG_DFL) finally: