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:
Mvis.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;