zsh-users
 help / color / mirror / code / Atom feed
* process substitution and Ctrl-C
@ 2010-08-19 12:41 Vincent Lefevre
  2010-08-19 13:07 ` Peter Stephenson
  2010-08-19 15:32 ` Bart Schaefer
  0 siblings, 2 replies; 11+ messages in thread
From: Vincent Lefevre @ 2010-08-19 12:41 UTC (permalink / raw)
  To: zsh-users

Hi,

In the following example:

  { repeat 10 { date >&2; /bin/sleep 1 } } 2>>(cat -n; loop)

where "loop" is a program that consumes CPU time, is it normal that
when one interrupts the command with Ctrl-C, the substituted process
isn't killed? (I can see "loop" taking CPU time.)

The zsh man page says that the command is run asynchronously, but
this notion is never clearly defined.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 12:41 process substitution and Ctrl-C Vincent Lefevre
@ 2010-08-19 13:07 ` Peter Stephenson
  2010-08-19 17:15   ` Peter Stephenson
  2010-08-19 15:32 ` Bart Schaefer
  1 sibling, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2010-08-19 13:07 UTC (permalink / raw)
  Cc: zsh-users

On Thu, 19 Aug 2010 14:41:42 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> In the following example:
> 
>   { repeat 10 { date >&2; /bin/sleep 1 } } 2>>(cat -n; loop)
> 
> where "loop" is a program that consumes CPU time, is it normal that
> when one interrupts the command with Ctrl-C, the substituted process
> isn't killed? (I can see "loop" taking CPU time.)

Without looking at the code, I wouldn't be at all surprised: unless we did
something special, SIGINT would go only to foreground processes, which
wouldn't include the process substitution.  Logically, you might have
thought that passing the SIGINT as received by the shell on to associated
processes (which are recorded in a part of the job record) should be
possible, but this sort of thing is fairly well down my personal list of
priorities.

-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 12:41 process substitution and Ctrl-C Vincent Lefevre
  2010-08-19 13:07 ` Peter Stephenson
@ 2010-08-19 15:32 ` Bart Schaefer
  2010-08-19 20:37   ` Peter Stephenson
  2010-08-19 21:17   ` Vincent Lefevre
  1 sibling, 2 replies; 11+ messages in thread
From: Bart Schaefer @ 2010-08-19 15:32 UTC (permalink / raw)
  To: zsh-users

On Aug 19,  2:41pm, Vincent Lefevre wrote:
} 
} In the following example:
} 
}   { repeat 10 { date >&2; /bin/sleep 1 } } 2>>(cat -n; loop)
} 
} where "loop" is a program that consumes CPU time, is it normal that
} when one interrupts the command with Ctrl-C, the substituted process
} isn't killed? (I can see "loop" taking CPU time.)

The assumption is that process substitution consumes stdin and exits
after its stdin is closed.  Otherwise, why would you need to redirect
into it?

However, there may be a good reason for changing this.  If I try

    echo >>(cat; sleep 100)

then the shell is effectively frozen until "sleep 100" finishes, because
"echo" is already gone and the process substitution is not interruptible,
so nothing is paying attention to ^C or ^Z etc.  This appears to happen
with any builtin as the input to the process substitution, including a
brace construct like the one you used above; e.g. I tried:

    { tty } >>(cat; sleep 100)

and it hangs there for 100 seconds.  However, it doesn't happen with an
external command; e.g.

    tty >>(cat; sleep 100)

exits immediately, even before the sleep finishes, though the sleep is
left running.

} The zsh man page says that the command is run asynchronously, but
} this notion is never clearly defined.

For better or worse, the zsh man page has never been very good about
fully defining concepts that are "well known" from other shells.  It
was written from the standpoint of "you've already used (c)sh for a
while and know what all of this means, I'm just going to tell you what
is different about doing it in zsh."

So if you refer to (say) the bash manual:

   A shell allows execution of GNU commands, both synchronously and
   asynchronously. The shell waits for synchronous commands to complete
   before accepting more input; asynchronous commands continue to
   execute in parallel with the shell while it reads and executes
   additional commands.

   Command substitution, commands grouped with parentheses, and
   asynchronous commands are invoked in a subshell environment that is
   a duplicate of the shell environment, except that traps caught by
   the shell are reset to the values that the shell inherited from its
   parent at invocation.

   When job control is not in effect, asynchronous commands ignore
   `SIGINT' and `SIGQUIT' in addition to these inherited handlers.
   Commands run as a result of command substitution ignore the
   keyboard-generated job control signals `SIGTTIN', `SIGTTOU', and
   `SIGTSTP'.

What gets fuzzy, even in the bash manual, is the distinction between
an "asynchronous command" and a "background job":

   If a command is terminated by the control operator `&', the shell
   executes the command asynchronously in a subshell. This is known as
   executing the command in the BACKGROUND. The shell does not wait for
   the command to finish, and the return status is 0 (true). When job
   control is not active, the standard input for asynchronous commands,
   in the absence of any explicit redirections, is redirected from
   `/dev/null'.

   Background processes are those whose process group ID differs from
   the terminal's; such processes are immune to keyboard-generated
   signals. Only foreground processes are allowed to read from or write
   to the terminal. Background processes which attempt to read from
   (write to) the terminal are sent a `SIGTTIN' (`SIGTTOU') signal by
   the terminal driver, which, unless caught, suspends the process.

Zsh process substitution (and, I think, just about everything that zsh
runs "asynchronously") behave in almost every way like background jobs,
and therefore don't receive keyboard-generated signals.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 13:07 ` Peter Stephenson
@ 2010-08-19 17:15   ` Peter Stephenson
  2010-08-19 20:18     ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2010-08-19 17:15 UTC (permalink / raw)
  To: zsh-users

On Thu, 19 Aug 2010 14:07:30 +0100
Peter Stephenson <Peter.Stephenson@csr.com> wrote:
> On Thu, 19 Aug 2010 14:41:42 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
> > In the following example:
> > 
> >   { repeat 10 { date >&2; /bin/sleep 1 } } 2>>(cat -n; loop)
> > 
> > where "loop" is a program that consumes CPU time, is it normal that
> > when one interrupts the command with Ctrl-C, the substituted process
> > isn't killed? (I can see "loop" taking CPU time.)
> 
> Without looking at the code, I wouldn't be at all surprised: unless
> we did something special, SIGINT would go only to foreground
> processes, which wouldn't include the process substitution.
> Logically, you might have thought that passing the SIGINT as received
> by the shell on to associated processes (which are recorded in a part
> of the job record) should be possible, but this sort of thing is
> fairly well down my personal list of priorities.

I managed to get to the point where I had zero time to spare.  That's up
significantly from the usual amount, so I looked at this.

In fact we're jumping through a fairly large and stable hoop not all that
far above the ground to behave as if "we" got SIGINT.  "We" here is just
the main shell.  You might think, logically, that any process attached to
any job marked as running in the current shell should also get the signal
passed, if we're going to maintain the fiction.  This is a slightly smaller
hoop held a little further over the ground, but I don't see any fundamental
reason why we shouldn't jump through it.  Anyway, the following seems to do
the trick here.

Index: Src/jobs.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/jobs.c,v
retrieving revision 1.78
diff -p -u -r1.78 jobs.c
--- Src/jobs.c	18 Aug 2010 21:21:17 -0000	1.78
+++ Src/jobs.c	19 Aug 2010 17:08:33 -0000
@@ -496,6 +496,27 @@ update_job(Job jn)
 		breaks = loops;
 		errflag = 1;
 	    }
+	    if (errflag) {
+		/*
+		 * As we're pretending we got the signal, we need to
+		 * pretend anything attached to a CURSH process
+		 * got it, too.
+		 */
+		int i, j;
+		for (i = 1; i <= maxjob; i++) {
+		    if ((jobtab[i].stat & (STAT_CURSH|STAT_DONE)) ==
+			STAT_CURSH) {
+			for (j = 0; j < 2; j++) {
+			    pn = j ? jobtab[i].auxprocs : jobtab[i].procs;
+			    for (; pn; pn = pn->next) {
+				if (pn->status == SP_RUNNING) {
+				    kill(pn->pid, sig);
+				}
+			    }
+			}
+		    }
+		}
+	    }
 	}
     }
 }


-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 17:15   ` Peter Stephenson
@ 2010-08-19 20:18     ` Peter Stephenson
  0 siblings, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2010-08-19 20:18 UTC (permalink / raw)
  To: zsh-users

I'm now wondering if we should do the same in the case where the shell
actually does get the SIGINT and abort processing as a result?  Theories
welcome.

Index: Src/jobs.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/jobs.c,v
retrieving revision 1.78
diff -p -u -r1.78 jobs.c
--- Src/jobs.c	18 Aug 2010 21:21:17 -0000	1.78
+++ Src/jobs.c	19 Aug 2010 20:16:53 -0000
@@ -320,6 +320,36 @@ update_process(Process pn, int status)
 }
 #endif
 
+/*
+ * Called when the current shell is behaving as if it received
+ * a interactively generated signal (sig).
+ * 
+ * As we got the signal or are pretending we did, we need to pretend
+ * anything attached to a CURSH process got it, too.
+ */
+/**/
+void
+check_cursh_sig(int sig)
+{
+    int i, j;
+
+    if (!errflag)
+	return;
+    for (i = 1; i <= maxjob; i++) {
+	if ((jobtab[i].stat & (STAT_CURSH|STAT_DONE)) ==
+	    STAT_CURSH) {
+	    for (j = 0; j < 2; j++) {
+		Process pn = j ? jobtab[i].auxprocs : jobtab[i].procs;
+		for (; pn; pn = pn->next) {
+		    if (pn->status == SP_RUNNING) {
+			kill(pn->pid, sig);
+		    }
+		}
+	    }
+	}
+    }
+}
+
 /* Update status of job, possibly printing it */
 
 /**/
@@ -496,6 +526,7 @@ update_job(Job jn)
 		breaks = loops;
 		errflag = 1;
 	    }
+	    check_cursh_sig(sig);
 	}
     }
 }
Index: Src/signals.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/signals.c,v
retrieving revision 1.58
diff -p -u -r1.58 signals.c
--- Src/signals.c	12 May 2010 10:07:01 -0000	1.58
+++ Src/signals.c	19 Aug 2010 20:16:53 -0000
@@ -580,6 +580,7 @@ zhandler(int sig)
                 breaks = loops;
                 errflag = 1;
 		inerrflush();
+		check_cursh_sig(SIGINT);
             }
         }
         break;

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 15:32 ` Bart Schaefer
@ 2010-08-19 20:37   ` Peter Stephenson
  2010-08-19 21:17   ` Vincent Lefevre
  1 sibling, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2010-08-19 20:37 UTC (permalink / raw)
  To: zsh-users

On Thu, 19 Aug 2010 08:32:37 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> If I try
> 
>     echo >>(cat; sleep 100)
> 
> then the shell is effectively frozen until "sleep 100" finishes, because
> "echo" is already gone and the process substitution is not interruptible,
> so nothing is paying attention to ^C or ^Z etc.

(This should have gone to zsh-workers ages ago but still hasn't.)

This is a separate problem.  It's not so much that the echo has gone as
that there are no processes in the tty process group to get the signal,
because the substitution is treated as asynchronous for the purposes of
job handling.  (In fact, I've decided I don't understand what
"asynchronous" means in this case, either.  We seem to have spent
chunks of the last twenty years making process substitution less and
less like an asynchronous process; first we started waiting for it to
finish, now we're passing signals to it.)

Any reactions to the following patch?  This makes the substitution
process always get the same signal as the rest of the command line.  If
that's an external process that would be interrupted, so you wouldn't
see the freeze, but even there without the patch the "sleep" carries
merrily on --- similar to Vincent's case.

The alternative is to make it synchronous only if the current job is
running within the shell.  I no longer really have any idea what the
intention is.

I'm assuming the other use of >(...), when not part of a redirection,
want identical treatment to whatever happens here.

Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.181
diff -p -u -r1.181 exec.c
--- Src/exec.c	15 Jul 2010 18:44:13 -0000	1.181
+++ Src/exec.c	19 Aug 2010 20:26:24 -0000
@@ -3828,7 +3828,7 @@ getproc(char *cmd, char **eptr)
 	zerr("can't open %s: %e", pnam, errno);
 	_exit(1);
     }
-    entersubsh(ESUB_ASYNC|ESUB_PGRP);
+    entersubsh(ESUB_PGRP);
     redup(fd, out);
 #else /* PATH_DEV_FD */
     int pipes[2];
@@ -3855,7 +3855,7 @@ getproc(char *cmd, char **eptr)
 	}
 	return pnam;
     }
-    entersubsh(ESUB_ASYNC|ESUB_PGRP);
+    entersubsh(ESUB_PGRP);
     redup(pipes[out], out);
     closem(FDT_UNUSED);   /* this closes pipes[!out] as well */
 #endif /* PATH_DEV_FD */
@@ -3905,7 +3905,7 @@ getpipe(char *cmd, int nullexec)
 	    addproc(pid, NULL, 1, &bgtime);
 	return pipes[!out];
     }
-    entersubsh(ESUB_ASYNC|ESUB_PGRP);
+    entersubsh(ESUB_PGRP);
     redup(pipes[out], out);
     closem(FDT_UNUSED);	/* this closes pipes[!out] as well */
     cmdpush(CS_CMDSUBST);

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 15:32 ` Bart Schaefer
  2010-08-19 20:37   ` Peter Stephenson
@ 2010-08-19 21:17   ` Vincent Lefevre
  2010-08-20  8:19     ` Bart Schaefer
  1 sibling, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2010-08-19 21:17 UTC (permalink / raw)
  To: zsh-users

On 2010-08-19 08:32:37 -0700, Bart Schaefer wrote:
> On Aug 19,  2:41pm, Vincent Lefevre wrote:
> } 
> } In the following example:
> } 
> }   { repeat 10 { date >&2; /bin/sleep 1 } } 2>>(cat -n; loop)
> } 
> } where "loop" is a program that consumes CPU time, is it normal that
> } when one interrupts the command with Ctrl-C, the substituted process
> } isn't killed? (I can see "loop" taking CPU time.)
> 
> The assumption is that process substitution consumes stdin and exits
> after its stdin is closed.  Otherwise, why would you need to redirect
> into it?

However there's a race condition, IMHO. In fact, even without a signal
to the main process. For instance, if you consider:

  ls >>(cat -n)

then the zsh prompt for the next command is displayed before "cat -n"
finishes. Does this mean that process substitution should not be used
for filtering, except when an end marker is used (as in the example
at the end of my message)? Now,

  { ls } >>(cat -n)

seems to work (as you said), and this can be seen with:

  { ls } >>(sleep 2; cat -n)

but no longer if the main process is interrupted with Ctrl-C.
For instance:

  { ls } >>(while read line; do sleep 1; echo $line; done)

outputs one line each second, and the main process is blocked as
wanted; but if one does a Ctrl-C, the main process is terminated
and one gets the prompt while the substituted process still outputs
the remaining lines each second. I don't think this is the behavior
that one expects.

In fact, I noticed the problem with the Ctrl-C due to a bug in one
of my scripts:

filter()
{
  unset brpipe
  while true
  do
    unset line
    while read -r -t 0.1 -k -u 0 ch
    do
      line="$line$ch"
      [[ $ch = $'\012' ]] && break
    done
    case $line in
      svnwrapper:term$'\012')
        break ;;
      *Broken\ pipe$'\012') brpipe=1 ;;
      ?*) printf "%s" "$line" >&2 ;;
    esac
  done
  [[ -z $brpipe ]] || kill -PIPE $$
}

{ svn "$@"; st=$?; echo "svnwrapper:term" >&2 } 2>>(filter)
exit $st

The problem here is that I didn't do the difference between a timeout
(due to -t 0.1) and an end of file: in the case of a Ctrl-C while svn
was running, the end marker svnwrapper:term would no longer be output
and filter() would start to take CPU time in an infinite loop. I've
fixed the script by using -t 0.1 as of the second iteration only:

[...]
    unset line timeout
    while read -r $timeout -k -u 0 ch
    do
      line="$line$ch"
      [[ $ch = $'\012' ]] && break
      timeout=(-t 0.1)
    done
[...]

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-19 21:17   ` Vincent Lefevre
@ 2010-08-20  8:19     ` Bart Schaefer
  2010-08-20 11:52       ` Vincent Lefevre
  0 siblings, 1 reply; 11+ messages in thread
From: Bart Schaefer @ 2010-08-20  8:19 UTC (permalink / raw)
  To: zsh-users

Answering a whole bunch of messages at once ...

On Aug 19,  6:15pm, Peter Stephenson wrote:
}
} In fact we're jumping through a fairly large and stable hoop not all that
} the main shell.  You might think, logically, that any process attached to
} any job marked as running in the current shell should also get the signal
} passed, if we're going to maintain the fiction.

On Aug 19,  9:18pm, Peter Stephenson wrote:
}
} I'm now wondering if we should do the same in the case where the shell
} actually does get the SIGINT and abort processing as a result?

What I'm now wondering is whether there's a reason it was the other way,
more significant than just Paul never having gotten around to figuring
out how to fit it into the job code.  I begin to believe not, see below.

On Aug 19,  9:37pm, Peter Stephenson wrote:
}
} >     echo >>(cat; sleep 100)
} > 
} > then the shell is effectively frozen until "sleep 100" finishes
} 
} This is a separate problem.  It's not so much that the echo has gone as
} that there are no processes in the tty process group to get the signal,
} because the substitution is treated as asynchronous for the purposes of
} job handling.

Well, OK, but the main shell could still get the signal ...  That's
what would happen if "echo" were replaced by a loop construct, as is
demonstrated by Vincent's original example.

} (In fact, I've decided I don't understand what "asynchronous" means
} in this case, either. We seem to have spent chunks of the last twenty
} years making process substitution less and less like an asynchronous
} process; first we started waiting for it to finish, now we're passing
} signals to it.)

I just had a peek back at some really old code.  (Next paragraph may be
indecipherable to anyone not on zsh-workers, and to some of them.)

Mid-90s, job handling in entersubsh() was a lot simpler, and there was
no distinction corresponding to the current meanings of the ESUB_PGRP
and ESUB_ASYNC bitflags passed to entersubsh().  There was no provision
for tracking the process substitution in the job table, and the only
way to run process substitution in parallel with the foreground job
that was writing to it, was to background it.  This is essential for
doing things like "foo >>(bar) 2>>(baz)"; if the >>(bar) had not been
backgrounded, 2>>(baz) could not have run until it finished.

What has happened over time is that the shell has become capable of
running those jobs in parallel without losing track of them, which I
think means it's now OK to wait for them and make them interruptible,
given that [as best I can tell] >>({...}&) provides the old behavior.

However ...

} Any reactions to the following patch?  This makes the substitution
} process always get the same signal as the rest of the command line.
[...]
} -    entersubsh(ESUB_ASYNC|ESUB_PGRP);
} +    entersubsh(ESUB_PGRP);

I'm a little worried about this, because leaving off ESUB_ASYNC may
cause entersubsh() to attempt to attach a new process group leader to
the terminal, and I can't tell what consequences that may have for
the foreground job.  Maybe there no circumstance in which this would
happen, e.g. thisjob is always -1 when in this context.

} The alternative is to make it synchronous only if the current job is
} running within the shell.  I no longer really have any idea what the
} intention is.

Again we're confusing (or overloading?) the meaning of "synchronous".
The process substitution can't really be synchronous in the sense of
sequential with respect to the rest of the job.  The intention is to
run in parallel so that multios can send data to many processes at
once.  I think the rest of the behavior was ill-defined side-effect.

} I'm assuming the other use of >(...), when not part of a redirection,
} want identical treatment to whatever happens here.

That makes sense to me at the moment ...

On Aug 19, 11:17pm, Vincent Lefevre wrote:
}
} > The assumption is that process substitution consumes stdin and exits
} > after its stdin is closed.  Otherwise, why would you need to redirect
} > into it?
} 
} However there's a race condition, IMHO. In fact, even without a signal
} to the main process. For instance, if you consider:
} 
}   ls >>(cat -n)
} 
} then the zsh prompt for the next command is displayed before "cat -n"
} finishes. Does this mean that process substitution should not be used
} for filtering, except when an end marker is used (as in the example
} at the end of my message)?

I'm not sure what question you're asking, but process substitutions
share the stdout file descriptor of the command of which they are a
part, so if you use them in one of the commands in a pipeline they
become part of the stream feeding the right side of the pipe; and the
fact that the command writing to *them* has exited does not affect
what happens downstream.

On the other hand foo >>(bar) | baz is a multio and baz will get as
stdin the stdout of both foo and bar, in no particular order, so you
have to be careful to use { foo >>(bar) } | baz or unsetopt multios.

}   { ls } >>(cat -n)
} 
} seems to work (as you said)

If I understand what you mean to exemplify, that isn't exactly the
part of the behavior to which I was referring.

} For instance:
} 
}   { ls } >>(while read line; do sleep 1; echo $line; done)
} 
} outputs one line each second, and the main process is blocked as
} wanted; but if one does a Ctrl-C, the main process is terminated
} and one gets the prompt while the substituted process still outputs
} the remaining lines each second. I don't think this is the behavior
} that one expects.

As noted above, that's the only behavior that could be accomodated in
the original code base ... so it _is_ what someone who has been using
zsh since 1993-ish would expect. :-)


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-20  8:19     ` Bart Schaefer
@ 2010-08-20 11:52       ` Vincent Lefevre
  2010-08-20 15:24         ` Bart Schaefer
  0 siblings, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2010-08-20 11:52 UTC (permalink / raw)
  To: zsh-users

On 2010-08-20 01:19:05 -0700, Bart Schaefer wrote:
> The process substitution can't really be synchronous in the sense of
> sequential with respect to the rest of the job.  The intention is to
> run in parallel so that multios can send data to many processes at
> once.  I think the rest of the behavior was ill-defined side-effect.

I don't think this is specific to process substitution. This should
also be the case for pipelines, such as:

  prg1 | prg2 | prg3 | prg4

All of the should be run in parallel to avoid a possible deadlock
due to buffering (and this should also be faster on today's desktop
machines, which have several cores). But as far as I can see, a
Ctrl-C interrupts all of them.

> On Aug 19, 11:17pm, Vincent Lefevre wrote:
> } However there's a race condition, IMHO. In fact, even without a signal
> } to the main process. For instance, if you consider:
> } 
> }   ls >>(cat -n)
> } 
> } then the zsh prompt for the next command is displayed before "cat -n"
> } finishes. Does this mean that process substitution should not be used
> } for filtering, except when an end marker is used (as in the example
> } at the end of my message)?
> 
> I'm not sure what question you're asking, [...]

What I mean here is: the problem is that the main shell doesn't wait
for "cat -n" to finish. This means that on a typical machine, the zsh
prompt will here be displayed before the "cat -n" output. This should
be more clear with:

  ls >>(sleep 2; cat -n)

I would like the same behavior as:

  { ls } >>(sleep 2; cat -n)

> } For instance:
> } 
> }   { ls } >>(while read line; do sleep 1; echo $line; done)
> } 
> } outputs one line each second, and the main process is blocked as
> } wanted; but if one does a Ctrl-C, the main process is terminated
> } and one gets the prompt while the substituted process still outputs
> } the remaining lines each second. I don't think this is the behavior
> } that one expects.
> 
> As noted above, that's the only behavior that could be accomodated in
> the original code base ... so it _is_ what someone who has been using
> zsh since 1993-ish would expect. :-)

I think the average user would expect process substitution to behave
a bit like pipes w.r.t. signals, e.g. like:

  ls | while read line; do sleep 1; echo $line; done

The fact that the right part is in the foreground doesn't matter.
One can see that everything is killed with a more complex one:

  { echo foo; sleep 5; echo bar } | \
  { while read line; do sleep 1; echo $line; done; echo blah >&2 } | \
  { sleep 10; read a; echo $a; sleep 2; cat }

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-20 11:52       ` Vincent Lefevre
@ 2010-08-20 15:24         ` Bart Schaefer
  2010-08-21  0:04           ` Vincent Lefevre
  0 siblings, 1 reply; 11+ messages in thread
From: Bart Schaefer @ 2010-08-20 15:24 UTC (permalink / raw)
  To: zsh-users

On Aug 20,  1:52pm, Vincent Lefevre wrote:
} Subject: Re: process substitution and Ctrl-C
}
} On 2010-08-20 01:19:05 -0700, Bart Schaefer wrote:
} > The process substitution can't really be synchronous in the sense of
} > sequential with respect to the rest of the job.
} 
} I don't think this is specific to process substitution. This should
} also be the case for pipelines [...]  But as far as I can see, a
} Ctrl-C interrupts all of them.

Yes, obviously.  The difference is that a pipeline is organized as a
process group whose leader's PID is recorded in the job table, so even
historically, it was all managed together as one job.  Conversely, a
process substitution (again historically) went into the background;
the closest pipeline analogy would be

    prg1 | ( exec prg2 & )

Subsequent changes mean this behavior is no longer necessary, it was
merely preserved so that the new code behaved like the old code.  I'm
not arguing that it should have been that way or should stay that way,
I'm just providing context.

} > On Aug 19, 11:17pm, Vincent Lefevre wrote:
} > } then the zsh prompt for the next command is displayed before "cat -n"
} > } finishes. Does this mean that process substitution should not be used
} > } for filtering, except when an end marker is used (as in the example
} > } at the end of my message)?
} > 
} > I'm not sure what question you're asking, [...]
} 
} What I mean here is: the problem is that the main shell doesn't wait
} for "cat -n" to finish.

Yes, I get that; what I don't follow is what that has to do with using
process substitution for filtering and whether or not there's an "end
marker".  Filtering implies that there's a downstream consumer of the
output of the filter, and using an end marker or not won't have any
effect on what's seen downstream.  If you botch handling EOF from the
upstream in the middle of a pipeline, you'll get the same problem you
had with your process substitution (except that you'll be able to
interrupt the pipeline, even in older zsh).

The reason the manual explicitly calls out that process substitutions
are run asynchronously is to warn you about the ( prg2 & ) behavior.
We're discussing whether to change that and I think PWS's last patch
does so, but in the meantime if you don't want the backgrounding effect,
you're correct, you can't use a process substitution as if it were the
tail of a pipeline.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: process substitution and Ctrl-C
  2010-08-20 15:24         ` Bart Schaefer
@ 2010-08-21  0:04           ` Vincent Lefevre
  0 siblings, 0 replies; 11+ messages in thread
From: Vincent Lefevre @ 2010-08-21  0:04 UTC (permalink / raw)
  To: zsh-users

On 2010-08-20 08:24:18 -0700, Bart Schaefer wrote:
> Yes, I get that; what I don't follow is what that has to do with using
> process substitution for filtering and whether or not there's an "end
> marker".

True, in fact I was just seeing the side effect of using { ... } for
the main process.

The end marker can still be useful so that the filter knows when
to stop reading. This is useful if the main process can execute
processes and some of them can remain running in background while
still connected to the pipe (this is the case wih svn + ssh).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-08-21  0:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-19 12:41 process substitution and Ctrl-C Vincent Lefevre
2010-08-19 13:07 ` Peter Stephenson
2010-08-19 17:15   ` Peter Stephenson
2010-08-19 20:18     ` Peter Stephenson
2010-08-19 15:32 ` Bart Schaefer
2010-08-19 20:37   ` Peter Stephenson
2010-08-19 21:17   ` Vincent Lefevre
2010-08-20  8:19     ` Bart Schaefer
2010-08-20 11:52       ` Vincent Lefevre
2010-08-20 15:24         ` Bart Schaefer
2010-08-21  0:04           ` Vincent Lefevre

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).