On Fri, Jan 06, 2017 at 02:26:02AM -0500, Jeff King wrote: > You'll notice that it actually calls wait() on the pager. That's due to > a3da882120 (pager: do wait_for_pager on signal death, 2009-01-22), which > IIRC was addressing a very similar problem. We want to stop feeding the > pager when we get a signal, but we don't want the main process to > actually exit, or the pager loses the controlling terminal. > > In our new scenario we have an extra process, though. The git-log child > will wait on the pager, but the parent process can't. It doesn't know > about it. I think that it in turn needs to wait on the child when it > dies, and then the whole chain will stand still until the pager exits. And here's a patch to do that. It seems to work. I'll sleep on it and then write up a commit message tomorrow if it still makes sense. diff --git a/run-command.c b/run-command.c index ca905a9e80..db47c429b7 100644 --- a/run-command.c +++ b/run-command.c @@ -29,6 +29,8 @@ static int installed_child_cleanup_handler; static void cleanup_children(int sig, int in_signal) { + struct child_to_clean *children_to_wait_for = NULL; + while (children_to_clean) { struct child_to_clean *p = children_to_clean; children_to_clean = p->next; @@ -45,6 +47,17 @@ static void cleanup_children(int sig, int in_signal) } kill(p->pid, sig); + p->next = children_to_wait_for; + children_to_wait_for = p; + } + + while (children_to_wait_for) { + struct child_to_clean *p = children_to_wait_for; + children_to_wait_for = p->next; + + while (waitpid(p->pid, NULL, 0) < 0 && errno == EINTR) + ; /* spin waiting for process exit or error */ + if (!in_signal) free(p); }