zsh-workers
 help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: "Zsh Hackers' List" <zsh-workers@zsh.org>
Subject: Multio deadlock (Re: multios doesn't work with 2>&1)
Date: Sun, 27 Oct 2013 12:39:17 -0700	[thread overview]
Message-ID: <131027123917.ZM27930@torch.brasslantern.com> (raw)
In-Reply-To: <131027112724.ZM16426@torch.brasslantern.com>

On Oct 27, 11:27am, Bart Schaefer wrote:
}
} } echo foo >/dev/null 2>&1 | sed 's/foo/bar/'
} } 
} } gives a different bad effect, namely you get the output you want but the
} } shell hangs
} 
} The parent shell is in zwaitjob(), as is the shell that spawned sed.

That should actually say "as is the shell that was forked for echo".
The parent shell is waiting for "sed".

Here's the spot where the "echo" shell is stopped:

	/*
	 * So what's going on here then?  Well, I'm glad you asked.
	 *
	 * If we create multios for use in a subshell we do
	 * this after forking, in this function above.  That
	 * means that the current (sub)process is responsible
	 * for clearing them up.  However, the processes won't
	 * go away until we have closed the fd's talking to them.
	 * Since we're about to exit the shell there's nothing
	 * to stop us closing all fd's (including the ones 0 to 9
	 * that we usually leave alone).
	 *
	 * Then we wait for any processes.  When we forked,
	 * we cleared the jobtable and started a new job just for
	 * any oddments like this, so if there aren't any we won't
	 * need to wait.  The result of not waiting is that
	 * the multios haven't flushed the fd's properly, leading
	 * to obscure missing data.
	 *
	 * It would probably be cleaner to ensure that the
	 * parent shell handled multios, but that requires
	 * some architectural changes which are likely to be
	 * hairy.
	 */
	for (i = 0; i < 10; i++)
	    if (fdtable[i] != FDT_UNUSED)
		close(i);
	closem(FDT_UNUSED);
	if (thisjob != -1)
	    waitjobs();
	_exit(lastval);

Obviously we've not succeeded in closing all the necessary descriptors.
Here's what's still open (PID 16361 == parent, 16383 == echo, 16384 ==	/*
	 * So what's going on here then?  Well, I'm glad you asked.
	 *
	 * If we create multios for use in a subshell we do
	 * this after forking, in this function above.  That
	 * means that the current (sub)process is responsible
	 * for clearing them up.  However, the processes won't
	 * go away until we have closed the fd's talking to them.
	 * Since we're about to exit the shell there's nothing
	 * to stop us closing all fd's (including the ones 0 to 9
	 * that we usually leave alone).
	 *
	 * Then we wait for any processes.  When we forked,
	 * we cleared the jobtable and started a new job just for
	 * any oddments like this, so if there aren't any we won't
	 * need to wait.  The result of not waiting is that
	 * the multios haven't flushed the fd's properly, leading
	 * to obscure missing data.
	 *
	 * It would probably be cleaner to ensure that the
	 * parent shell handled multios, but that requires
	 * some architectural changes which are likely to be
	 * hairy.
	 */
	for (i = 0; i < 10; i++)
	    if (fdtable[i] != FDT_UNUSED)
		close(i);
	closem(FDT_UNUSED);
	if (thisjob != -1)
	    waitjobs();
	_exit(lastval);

Obviously we've not succeeded in closing all the necessary descriptors.
Here's what's still open:

zsh     16361 16361 schaefer    0u   CHR  136,3         5 /dev/pts/3
zsh     16361 16361 schaefer    1u   CHR  136,3         5 /dev/pts/3
zsh     16361 16361 schaefer    2u   CHR  136,3         5 /dev/pts/3
zsh     16361 16361 schaefer   10u   CHR  136,3         5 /dev/pts/3
zsh     16383 16383 schaefer    2w  FIFO    0,7      1227018 pipe
zsh     16384 16383 schaefer   12w  FIFO    0,7      1227016 pipe
zsh     16384 16383 schaefer   13w   CHR    1,3         2056 /dev/null
zsh     16384 16383 schaefer   14r  FIFO    0,7      1227018 pipe
sed     16385 16383 schaefer    0r  FIFO    0,7      1227016 pipe
sed     16385 16383 schaefer    1u   CHR  136,3            5 /dev/pts/3
sed     16385 16383 schaefer    2u   CHR  136,3            5 /dev/pts/3

16361 is the parent, it's clean.  16383 is echo and 16384 is the multio.
The multio is blocked reading fd 14 (1227018 pipe), which it's parent
still has open as stderr because fdtable[2] == FDT_UNUSED.

Does the following look right?  It does fix the deadlock, but we might
call close() on an already closed fd, which it appears this is trying
to avoid (maybe so as not to change errno?).

diff --git a/Src/exec.c b/Src/exec.c
index 99c7eaa..7ac1ad5 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3372,7 +3372,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 	 * hairy.
 	 */
 	for (i = 0; i < 10; i++)
-	    if (fdtable[i] != FDT_UNUSED)
+	    if (i < 3 || fdtable[i] != FDT_UNUSED)
 		close(i);
 	closem(FDT_UNUSED);
 	if (thisjob != -1)


  reply	other threads:[~2013-10-27 19:39 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20131027145917.GA5509@localhost.localdomain>
     [not found] ` <131027100137.ZM4100@torch.brasslantern.com>
2013-10-27 17:46   ` multios doesn't work with 2>&1 Peter Stephenson
2013-10-27 18:27     ` Bart Schaefer
2013-10-27 19:39       ` Bart Schaefer [this message]
2013-10-27 20:24         ` Multio deadlock (Re: multios doesn't work with 2>&1) Bart Schaefer
2013-10-27 20:33         ` Peter Stephenson
2013-10-27 21:16           ` Peter Stephenson
2013-10-27 22:31             ` Bart Schaefer
2013-10-27 22:18           ` Bart Schaefer
2013-10-27 18:11   ` multios doesn't work with 2>&1 Bart Schaefer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=131027123917.ZM27930@torch.brasslantern.com \
    --to=schaefer@brasslantern.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).