From fe913d7838d382075c1dfa8bbf2e652a49b57909 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Thu, 12 Jul 2018 22:38:07 +0100 Subject: [PATCH] Only waitpid() for processes that we care about It seems as though in an AppImage there's an extra child process that dies at some early point, before we have set up a SIGCHLD handler. So when we later get a SIGCHLD from a child that we do care about, waitpid(-1, ...) tells us about the extra child - and we don't notice that the interesting child has exited. Or something like that! See also: * https://patchwork.kernel.org/patch/9949491/ in which perf hit something similar * discussion at the AppImage repository: https://github.com/AppImage/AppImageKit/issues/812#issuecomment-404662110. Fix is to be explicit about which process we are waitpid()'ing for, so we never need be distracted by children that we don't know about. Fixes #8104 --- src/nvim/os/pty_process_unix.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index bd23596ea7454d..2aeaafe4bd82cb 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -273,26 +273,24 @@ static void chld_handler(uv_signal_t *handle, int signum) int stat = 0; int pid; - do { - pid = waitpid(-1, &stat, WNOHANG); - } while (pid < 0 && errno == EINTR); - - if (pid <= 0) { - return; - } - Loop *loop = handle->loop->data; kl_iter(WatcherPtr, loop->children, current) { Process *proc = (*current)->data; - if (proc->pid == pid) { - if (WIFEXITED(stat)) { - proc->status = WEXITSTATUS(stat); - } else if (WIFSIGNALED(stat)) { - proc->status = WTERMSIG(stat); - } - proc->internal_exit_cb(proc); - break; + do { + pid = waitpid(proc->pid, &stat, WNOHANG); + } while (pid < 0 && errno == EINTR); + + if (pid <= 0) { + continue; + } + + if (WIFEXITED(stat)) { + proc->status = WEXITSTATUS(stat); + } else if (WIFSIGNALED(stat)) { + proc->status = WTERMSIG(stat); } + proc->internal_exit_cb(proc); + break; } }