aboutsummaryrefslogtreecommitdiff
path: root/vis.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2017-05-04 21:39:43 +0200
committerMarc André Tanner <mat@brain-dump.org>2017-05-04 21:39:13 +0200
commitd9d8e81b39a77c198d344d096be55e9cd8cdd4e9 (patch)
tree99f2e0ef0dae8ee3545ba2297c9f88e739195869 /vis.c
parent71eab6d5d72145f17ab3d4c87945ac12176ae8e9 (diff)
downloadvis-d9d8e81b39a77c198d344d096be55e9cd8cdd4e9.tar.gz
vis-d9d8e81b39a77c198d344d096be55e9cd8cdd4e9.tar.xz
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 (limited to 'vis.c')
-rw-r--r--vis.c29
1 files changed, 27 insertions, 2 deletions
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;