vis
a vi-like editor based on Plan 9's structural regular expressions
git clone https://9o.is/git/vis.git
commit c37900253fb629824090844020e487e4ad95102a parent d03eac0cb2fac7305b3ee38ba6e3741765c8812c Author: Marc André Tanner <mat@brain-dump.org> Date: Thu, 4 May 2017 21:39:43 +0200 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. Diffstat:
| M | vis.c | | | 29 | +++++++++++++++++++++++++++-- |
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git 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;