zsh-workers
 help / color / mirror / code / Atom feed
* [BUG] exec + builtin and traps
@ 2017-09-12 10:02 ` Vincent Lefevre
  2017-09-12 10:19   ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2017-09-12 10:02 UTC (permalink / raw)
  To: zsh-workers

For zsh 5.4.1, the zshbuiltins(1) man page says:

    exec [ -cl ] [ -a argv0 ] [ command [ arg ... ] ]
           Replace the current shell with command rather than forking.
           If command is a shell builtin command or a shell  function,
           the shell executes it, then immediately exits.

But consider the following script:

----------------------------------------
#!/usr/bin/env zsh

trap 'echo foo' USR1

echo $$
( sleep 1; kill -USR1 $$ ) &
exec eval sleep 2
----------------------------------------

"foo" is printed, meaning that the shell does not immediately exit
just after the command is executed, contrary to what the man page
says.

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


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 10:02 ` [BUG] exec + builtin and traps Vincent Lefevre
@ 2017-09-12 10:19   ` Peter Stephenson
  2017-09-12 10:39     ` Vincent Lefevre
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2017-09-12 10:19 UTC (permalink / raw)
  To: zsh-workers

On Tue, 12 Sep 2017 12:02:57 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> For zsh 5.4.1, the zshbuiltins(1) man page says:
> 
>     exec [ -cl ] [ -a argv0 ] [ command [ arg ... ] ]
>            Replace the current shell with command rather than forking.
>            If command is a shell builtin command or a shell  function,
>            the shell executes it, then immediately exits.

It means immediately after the command has finished executing, not while
it's executing.

> #!/usr/bin/env zsh
> 
> trap 'echo foo' USR1
> 
> echo $$
> ( sleep 1; kill -USR1 $$ ) &
> exec eval sleep 2

So in your case it's still exectuing the eval sleep 2.

I don't actually understand your interpretation --- given eval is a
builtin and the eval is going to take 2 seconds because it dispatches to
a sleep, how could the shell exit before that?

pws

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 3afe990..d6aa078 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -669,7 +669,7 @@ an empty string or whitespace) the return status is zero.
 item(tt(exec) [ tt(-cl) ] [ tt(-a) var(argv0) ] [ var(command) [ var(arg) ... ] ])(
 Replace the current shell with var(command) rather than forking.
 If var(command) is a shell builtin command or a shell function,
-the shell executes it, then immediately exits.
+the shell executes it, and exits when the command is complete.
 
 With tt(-c) clear the environment; with tt(-l) prepend tt(-) to the
 tt(argv[0]) string of the command executed (to simulate a login shell);


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 10:19   ` Peter Stephenson
@ 2017-09-12 10:39     ` Vincent Lefevre
  2017-09-12 10:50       ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2017-09-12 10:39 UTC (permalink / raw)
  To: zsh-workers

On 2017-09-12 11:19:06 +0100, Peter Stephenson wrote:
> On Tue, 12 Sep 2017 12:02:57 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
> > For zsh 5.4.1, the zshbuiltins(1) man page says:
> > 
> >     exec [ -cl ] [ -a argv0 ] [ command [ arg ... ] ]
> >            Replace the current shell with command rather than forking.
> >            If command is a shell builtin command or a shell  function,
> >            the shell executes it, then immediately exits.
> 
> It means immediately after the command has finished executing, not while
> it's executing.
> 
> > #!/usr/bin/env zsh
> > 
> > trap 'echo foo' USR1
> > 
> > echo $$
> > ( sleep 1; kill -USR1 $$ ) &
> > exec eval sleep 2
> 
> So in your case it's still exectuing the eval sleep 2.

No, by default (with TRAPS_ASYNC unset), traps are run *after* the
child process has exited:

    TRAPS_ASYNC
        While  waiting  for a program to exit, handle signals and run
        traps immediately.  Otherwise the trap is run after  a  child
        process  has  exited.  Note this does not affect the point at
        which traps are run for any case other than when the shell is
        waiting for a child process.

But if the shell immediately exits after the command has been
executed, this means that traps would not be run.

> I don't actually understand your interpretation --- given eval is a
> builtin and the eval is going to take 2 seconds because it dispatches to
> a sleep, how could the shell exit before that?

See above.

> diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
> index 3afe990..d6aa078 100644
> --- a/Doc/Zsh/builtins.yo
> +++ b/Doc/Zsh/builtins.yo
> @@ -669,7 +669,7 @@ an empty string or whitespace) the return status is zero.
>  item(tt(exec) [ tt(-cl) ] [ tt(-a) var(argv0) ] [ var(command) [ var(arg) ... ] ])(
>  Replace the current shell with var(command) rather than forking.
>  If var(command) is a shell builtin command or a shell function,
> -the shell executes it, then immediately exits.
> +the shell executes it, and exits when the command is complete.

This still does not describe the observed behavior when TRAPS_ASYNC
is unset.

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


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 10:39     ` Vincent Lefevre
@ 2017-09-12 10:50       ` Peter Stephenson
  2017-09-12 11:42         ` Vincent Lefevre
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2017-09-12 10:50 UTC (permalink / raw)
  To: zsh-workers

On Tue, 12 Sep 2017 12:39:19 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> On 2017-09-12 11:19:06 +0100, Peter Stephenson wrote:
> > On Tue, 12 Sep 2017 12:02:57 +0200
> > Vincent Lefevre <vincent@vinc17.net> wrote:
> > > For zsh 5.4.1, the zshbuiltins(1) man page says:
> > > 
> > >     exec [ -cl ] [ -a argv0 ] [ command [ arg ... ] ]
> > >            Replace the current shell with command rather than forking.
> > >            If command is a shell builtin command or a shell  function,
> > >            the shell executes it, then immediately exits.
> > 
> > It means immediately after the command has finished executing, not while
> > it's executing.
> > 
> > > #!/usr/bin/env zsh
> > > 
> > > trap 'echo foo' USR1
> > > 
> > > echo $$
> > > ( sleep 1; kill -USR1 $$ ) &
> > > exec eval sleep 2
> > 
> > So in your case it's still exectuing the eval sleep 2.
> 
> No, by default (with TRAPS_ASYNC unset), traps are run *after* the
> child process has exited:

True, but the *builtin* is an eval list, that only terminates when it
has executed an arbitrary set of other commands.  The trap is executed
at the end of this list, before control returns back to eval.  We are
not exec'ing sleep here, we are exec'ing eval, so there is time after
the *child* process is executed, as in the TRAPS_ASYNC doc you quote.

eval, unlike exec, is not an permanent handoff of control to the
following command.

pws


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 10:50       ` Peter Stephenson
@ 2017-09-12 11:42         ` Vincent Lefevre
  2017-09-12 11:51           ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2017-09-12 11:42 UTC (permalink / raw)
  To: zsh-workers

On 2017-09-12 11:50:06 +0100, Peter Stephenson wrote:
> On Tue, 12 Sep 2017 12:39:19 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
> > No, by default (with TRAPS_ASYNC unset), traps are run *after* the
> > child process has exited:
> 
> True, but the *builtin* is an eval list, that only terminates when it
> has executed an arbitrary set of other commands.  The trap is executed
> at the end of this list, before control returns back to eval.  We are
> not exec'ing sleep here, we are exec'ing eval, so there is time after
> the *child* process is executed, as in the TRAPS_ASYNC doc you quote.
> 
> eval, unlike exec, is not an permanent handoff of control to the
> following command.

OK, this was a bit confusing from the description of "eval" by POSIX,
which describes it as a way to construct a command:

  The eval utility shall construct a command by concatenating
  arguments together, separating each with a <space> character.
  The constructed command shall be read and executed by the shell.

BTW, the way zsh handles "eval" is still strange:

----------------------------------------
trap 'echo foo' USR1
( sleep 1; kill -USR1 $$; ) &
eval "wait && echo bar"
echo OK
----------------------------------------

outputs

foo
bar
OK

----------------------------------------
trap 'echo foo' USR1
( sleep 1; kill -USR1 $$; ) &
wait && echo bar
echo OK
----------------------------------------

outputs

foo
OK

All the other shells output

foo
OK

in both cases.

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


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 11:42         ` Vincent Lefevre
@ 2017-09-12 11:51           ` Peter Stephenson
  2017-09-12 12:02             ` Vincent Lefevre
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2017-09-12 11:51 UTC (permalink / raw)
  To: zsh-workers

On Tue, 12 Sep 2017 13:42:20 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> BTW, the way zsh handles "eval" is still strange:
> 
> ----------------------------------------
> trap 'echo foo' USR1
> ( sleep 1; kill -USR1 $$; ) &
> eval "wait && echo bar"
> echo OK
> ----------------------------------------
> 
> outputs
> 
> foo
> bar
> OK

That'll be another effect of NO_ASYNC_TRAPS --- the list being executed
is what's in quotes, and it's after that that the trap gets run.  I
don't think NO_ASYNC_TRAPS behaviour is standardised.

pws


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 11:51           ` Peter Stephenson
@ 2017-09-12 12:02             ` Vincent Lefevre
  2017-09-12 12:10               ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2017-09-12 12:02 UTC (permalink / raw)
  To: zsh-workers

On 2017-09-12 12:51:39 +0100, Peter Stephenson wrote:
> On Tue, 12 Sep 2017 13:42:20 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
> > BTW, the way zsh handles "eval" is still strange:
> > 
> > ----------------------------------------
> > trap 'echo foo' USR1
> > ( sleep 1; kill -USR1 $$; ) &
> > eval "wait && echo bar"
> > echo OK
> > ----------------------------------------
> > 
> > outputs
> > 
> > foo
> > bar
> > OK
> 
> That'll be another effect of NO_ASYNC_TRAPS --- the list being executed
> is what's in quotes, and it's after that that the trap gets run.

Why is "foo" (from the trap) printed before "bar", then?

> I don't think NO_ASYNC_TRAPS behaviour is standardised.

That's another reason why it would be useful to clearly document
when traps are run precisely.

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


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

* Re: [BUG] exec + builtin and traps
  2017-09-12 12:02             ` Vincent Lefevre
@ 2017-09-12 12:10               ` Peter Stephenson
  2017-09-12 14:21                 ` trap, eval and wait (was: [BUG] exec + builtin and traps) Vincent Lefevre
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2017-09-12 12:10 UTC (permalink / raw)
  To: zsh-workers

On Tue, 12 Sep 2017 14:02:37 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> Why is "foo" (from the trap) printed before "bar", then?

OK, so it's on the *sub* list after the command before the &&
(wait) has executed successfully, but before the foo is executed.

> > I don't think NO_ASYNC_TRAPS behaviour is standardised.
> 
> That's another reason why it would be useful to clearly document
> when traps are run precisely.

Yes, it's a bit obscure and not really planned --- they just happen
"sufficienly often".

pws


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

* trap, eval and wait (was: [BUG] exec + builtin and traps)
  2017-09-12 12:10               ` Peter Stephenson
@ 2017-09-12 14:21                 ` Vincent Lefevre
  2017-09-12 15:04                   ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Vincent Lefevre @ 2017-09-12 14:21 UTC (permalink / raw)
  To: zsh-workers

On 2017-09-12 13:10:54 +0100, Peter Stephenson wrote:
> On Tue, 12 Sep 2017 14:02:37 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
> > Why is "foo" (from the trap) printed before "bar", then?
> 
> OK, so it's on the *sub* list after the command before the &&
> (wait) has executed successfully, but before the foo is executed.

I still don't understand. Actually, the real issue is that "wait"
should not have terminated successfully. Perhaps, this should be
clearer with:

------------------------------------------------------------
trap 'echo foo' USR1
( sleep 1; kill -USR1 $$; sleep 1; echo child ) &
eval "wait && echo bar"
echo OK
sleep 2
------------------------------------------------------------

After 1 second, the following is printed:

foo
bar
OK

And after another second:

child

So, this means that the "wait" has ended due to the USR1 signal, not
by a process termination. But then, the fact that "wait" terminates
with the exit status 0 does not seem to be correct.

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


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

* Re: trap, eval and wait (was: [BUG] exec + builtin and traps)
  2017-09-12 14:21                 ` trap, eval and wait (was: [BUG] exec + builtin and traps) Vincent Lefevre
@ 2017-09-12 15:04                   ` Peter Stephenson
  2017-09-13  9:55                     ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2017-09-12 15:04 UTC (permalink / raw)
  To: zsh-workers

On Tue, 12 Sep 2017 16:21:45 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> trap 'echo foo' USR1
> ( sleep 1; kill -USR1 $$; sleep 1; echo child ) &
> eval "wait && echo bar"
> echo OK
> sleep 2
> ------------------------------------------------------------
> 
> After 1 second, the following is printed:
> 
> foo
> bar
> OK
> 
> And after another second:
> 
> child
> 
> So, this means that the "wait" has ended due to the USR1 signal, not
> by a process termination. But then, the fact that "wait" terminates
> with the exit status 0 does not seem to be correct.

There's a funny here (yes, I know, we're all amazed) --- wait is
actually waiting for two jobs. One of them has the flags
STAT_BUILTIN|STAT_CURSH|STAT_NOPRINT, and it turns out this is the
second one it waits for and it returns status 0. The return status from
wait only reflects the last job waited for --- I believe that much is
standard.

Quite possibly any of the above flags should mean wait ignores the job,
but I've taken STAT_NOPRINT as the most logical to test here as it
basically means "user is not interested in this".

pws

diff --git a/Src/jobs.c b/Src/jobs.c
index 66dfb5a..226e7cf 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -2217,7 +2217,8 @@ bin_fg(char *name, char **argv, Options ops, int func)
 	    return 0;
 	} else {   /* Must be BIN_WAIT, so wait for all jobs */
 	    for (job = 0; job <= maxjob; job++)
-		if (job != thisjob && jobtab[job].stat)
+		if (job != thisjob && jobtab[job].stat &&
+		    !(jobtab[job].stat & STAT_NOPRINT))
 		    retval = zwaitjob(job, 1);
 	    unqueue_signals();
 	    return retval;


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

* Re: trap, eval and wait (was: [BUG] exec + builtin and traps)
  2017-09-12 15:04                   ` Peter Stephenson
@ 2017-09-13  9:55                     ` Peter Stephenson
  0 siblings, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2017-09-13  9:55 UTC (permalink / raw)
  To: zsh-workers

On Tue, 12 Sep 2017 16:04:09 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> Quite possibly any of the above flags should mean wait ignores the job,
> but I've taken STAT_NOPRINT as the most logical to test here as it
> basically means "user is not interested in this".

I've committed this but I'm wondering if it would be sensible to add
STAT_DONE here? There's nothing to wait for if the job is done.
(This case is only for "wait" without an argument, so just wait for
everything we think is outstanding.)

By the way, unrelated to the bug (though it works around it), if you're
really interested in the status of the last background job, I think you
need to use "wait $!" anyway --- otherwise if the job is already
finished, "wait" will simply return immediately with status 0.  Waiting
for $! is the only special case available to handle the race.

pws


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

end of thread, other threads:[~2017-09-13  9:55 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20170912101045epcas2p4cae7e7df78ef035900f9c6099dc054fb@epcas2p4.samsung.com>
2017-09-12 10:02 ` [BUG] exec + builtin and traps Vincent Lefevre
2017-09-12 10:19   ` Peter Stephenson
2017-09-12 10:39     ` Vincent Lefevre
2017-09-12 10:50       ` Peter Stephenson
2017-09-12 11:42         ` Vincent Lefevre
2017-09-12 11:51           ` Peter Stephenson
2017-09-12 12:02             ` Vincent Lefevre
2017-09-12 12:10               ` Peter Stephenson
2017-09-12 14:21                 ` trap, eval and wait (was: [BUG] exec + builtin and traps) Vincent Lefevre
2017-09-12 15:04                   ` Peter Stephenson
2017-09-13  9:55                     ` Peter Stephenson

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