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);
        }

Reply via email to