From d9d8e81b39a77c198d344d096be55e9cd8cdd4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Thu, 4 May 2017 21:39:43 +0200 Subject: vis: improve job control for forked process We need to unblock SIGTERM for the child process. Also we should deliver signals to the correct process group. This is still fragile and will need to be rewritten when we finally introduce a global event loop. --- vis.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'vis.c') diff --git a/vis.c b/vis.c index bdee2e7..cfbd291 100644 --- a/vis.c +++ b/vis.c @@ -1702,11 +1702,20 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[], vis_info_show(vis, "fork failure: %s", strerror(errno)); return -1; } else if (pid == 0) { /* child i.e filter */ + sigset_t sigterm_mask; + sigemptyset(&sigterm_mask); + sigaddset(&sigterm_mask, SIGTERM); + if (sigprocmask(SIG_UNBLOCK, &sigterm_mask, NULL) == -1) { + fprintf(stderr, "failed to reset signal mask"); + exit(EXIT_FAILURE); + } + int null = open("/dev/null", O_WRONLY); if (null == -1) { fprintf(stderr, "failed to open /dev/null"); exit(EXIT_FAILURE); } + if (!interactive) dup2(pin[0], STDIN_FILENO); close(pin[0]); @@ -1757,7 +1766,7 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[], do { if (vis->interrupted) { - kill(-pid, SIGTERM); + kill(0, SIGTERM); break; } @@ -1838,8 +1847,24 @@ err: if (perr[0] != -1) close(perr[0]); - for (pid_t died; (died = waitpid(pid, &status, 0)) != -1 && pid != died;); + for (;;) { + if (vis->interrupted) + kill(0, SIGTERM); + pid_t died = waitpid(pid, &status, 0); + if ((died == -1 && errno == ECHILD) || pid == died) + break; + } + + /* clear any pending SIGTERM */ + struct sigaction sigterm_ignore, sigterm_old; + sigterm_ignore.sa_handler = SIG_IGN; + sigterm_ignore.sa_flags = 0; + sigemptyset(&sigterm_ignore.sa_mask); + sigaction(SIGTERM, &sigterm_ignore, &sigterm_old); + sigaction(SIGTERM, &sigterm_old, NULL); + + vis->interrupted = false; vis->ui->terminal_restore(vis->ui); return status; -- cgit v1.2.3