Use a C based SIGCHLD handler

Running python code in signal handlers makes me nervous
This commit is contained in:
Kovid Goyal
2017-10-23 12:42:03 +05:30
parent 32a1886b31
commit 8672a29503
2 changed files with 28 additions and 17 deletions

View File

@@ -9,6 +9,8 @@
#include "modes.h" #include "modes.h"
#include <stddef.h> #include <stddef.h>
#include <termios.h> #include <termios.h>
#include <signal.h>
#include <sys/wait.h>
#ifdef WITH_PROFILER #ifdef WITH_PROFILER
#include <gperftools/profiler.h> #include <gperftools/profiler.h>
#endif #endif
@@ -81,6 +83,28 @@ pyset_iutf8(PyObject UNUSED *self, PyObject *args) {
Py_RETURN_NONE; 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 #ifdef WITH_PROFILER
static PyObject* static PyObject*
start_profiler(PyObject UNUSED *self, PyObject *args) { start_profiler(PyObject UNUSED *self, PyObject *args) {
@@ -105,6 +129,7 @@ static PyMethodDef module_methods[] = {
{"redirect_std_streams", (PyCFunction)redirect_std_streams, METH_VARARGS, ""}, {"redirect_std_streams", (PyCFunction)redirect_std_streams, METH_VARARGS, ""},
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""}, {"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
{"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""}, {"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""},
{"install_sigchld_handler", (PyCFunction)install_sigchld_handler, METH_NOARGS, ""},
#ifdef WITH_PROFILER #ifdef WITH_PROFILER
{"start_profiler", (PyCFunction)start_profiler, METH_VARARGS, ""}, {"start_profiler", (PyCFunction)start_profiler, METH_VARARGS, ""},
{"stop_profiler", (PyCFunction)stop_profiler, METH_NOARGS, ""}, {"stop_profiler", (PyCFunction)stop_profiler, METH_NOARGS, ""},

View File

@@ -3,7 +3,6 @@
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import argparse import argparse
import errno
import locale import locale
import os import os
import signal import signal
@@ -25,8 +24,8 @@ from .fast_data_types import (
GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_PROFILE, GLFW_SAMPLES, GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_PROFILE, GLFW_SAMPLES,
GLFW_STENCIL_BITS, GLFWWindow, change_wcwidth, check_for_extensions, GLFW_STENCIL_BITS, GLFWWindow, change_wcwidth, check_for_extensions,
clear_buffers, glewInit, glfw_init, glfw_init_hint_string, clear_buffers, glewInit, glfw_init, glfw_init_hint_string,
glfw_swap_interval, glfw_terminate, glfw_window_hint, set_logical_dpi, glfw_swap_interval, glfw_terminate, glfw_window_hint,
set_options install_sigchld_handler, set_logical_dpi, set_options
) )
from .layout import all_layouts from .layout import all_layouts
from .utils import color_as_int, detach, get_logical_dpi, safe_print 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) 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(): def main():
try: try:
sys.setswitchinterval(1000.0) # we have only a single python thread sys.setswitchinterval(1000.0) # we have only a single python thread
@@ -302,7 +288,7 @@ def main():
try: try:
with setup_profiling(args): with setup_profiling(args):
# Avoid needing to launch threads to reap zombies # Avoid needing to launch threads to reap zombies
signal.signal(signal.SIGCHLD, reap_zombies) install_sigchld_handler()
run_app(opts, args) run_app(opts, args)
signal.signal(signal.SIGCHLD, signal.SIG_DFL) signal.signal(signal.SIGCHLD, signal.SIG_DFL)
finally: finally: