Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Subshell with multios causes hang



On Wed, 2007-05-23 at 11:12 +0100, Peter Stephenson wrote:
> On Tue, 22 May 2007 18:29:25 +0100
> Peter Stephenson <pws@xxxxxxx> wrote:
> > On Tue, 22 May 2007 12:21:43 +0100
> > John Buddery <jvb@xxxxxxxxxxxxxxxx> wrote:
> > > Essentially I run the equivalent of:
> > > 
> > >    ( echo hello ) >| /tmp/out >| /tmp/out2
> > > 
> > > and in an interactive shell (or any with job control) this hangs.
> >...
> > Wossgoingon?
> >...
> > I'll carry on looking at this when I get a chance, but for now I'm
> > confused enough to go to the beer festival.
> 
> Success, I think.  The answer started to come to me in the queue.  John
> sent me another email; the basic problem seems to be the obscure
> interaction between forking, job control and multios in this case.
> 

Excellent, works for me - thanks very much!

If you're interested while you're dealing with multios, there was one
other fault I noticed when digging around: with an input multios, there
is a race condition after the fork in closemn() between the addproc()
and the child process exiting. If the child multios exits (having sent
it's output to the buffered pipe) before the addproc(), the shell hangs
later when it tries to wait for the already-exited pid.

This can be reproduced fairly reliably with the example you posted last
year:

% echo This is the file >file
% fn() { cat; }
% fn <$(echo file file)
This is the file
This is the file
(hang at this point)

One way to fix it would be to block the child signal until the child pid was registered (patch below).
Admittedly it's a bit obscure, though - not that my last example wasn't...

Thanks,

John

Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.111
diff -u -r1.111 exec.c
--- Src/exec.c  8 May 2007 10:02:59 -0000       1.111
+++ Src/exec.c  23 May 2007 11:09:53 -0000
@@ -1549,20 +1549,24 @@
        pid_t pid;
        struct timeval bgtime;
 
+        child_block();
        if ((pid = zfork(&bgtime))) {
            for (i = 0; i < mn->ct; i++)
                zclose(mn->fds[i]);
            zclose(mn->pipe);
            if (pid == -1) { 
                mfds[fd] = NULL;
+                child_unblock();
                return;
            }
            mn->ct = 1;
            mn->fds[0] = fd;
            addproc(pid, NULL, 1, &bgtime);
+            child_unblock();
            return;
        }
        /* pid == 0 */
+        child_unblock();
        closeallelse(mn);
        if (mn->rflag) {
            /* tee process */





Messages sorted by: Reverse Date, Date, Thread, Author