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

Re: long-standing tty related issue: wrapped Emacs not suspended



On Thu, 20 Sep 2018 14:30:05 +0200
Vincent Lefevre <vincent@xxxxxxxxxx> wrote:
> is suspended as expected. But when Emacs is wrapped in a function,
> it is not suspended. After "zsh -f":
> 
> zira% e() { emacs -nw "$@"; }
> zira% e &
> 
> I cannot quit Emacs or get the zsh prompt. I need to kill the
> terminal.

I think this one *is* the same basic issue that Thilo was talking about.
As you note, it's not new.  (With the latest code I can only get this
the way Thilo did, by suspending, putting it into the background, then
into the foreground, then I can only get things to work again with kill
-CONT from elsewhere and a bit of massaging to kill of the remaining
goo.   The code shown above actually works OK for me with a bg and fg.)

Joey's explanation --- that there's another copy of the shell in play
that's getting in the way of job control --- is the basic issue, and the
"exec" workaround is what I would have recommended trying.

However, there are a couple of interesting zsh-specific issues here.


The fact that another instance of the shell is created on the ^Z is
actually a special feature for allowing you to suspend builtins,
designed for functions and pipelines with more processing in than this
--- typically loops over external processes.  The bog-standard shell
thing to do is simply suspend the external process, and let the rest of
the shell code take care of itself, which almost certainly isn't what
you want if the function is doing something sophsiticated.

Unfortunately zsh's enhancement is not doing you any favours in this
case since you don't actually want any more shell code to run.  The
forked shell and the emacs go into different process groups, and when
you pass them around between background and foreground they lose track
of who's doing what where.  It's not clear if this is a bug because this
is entirely untrodden ground but it might be possible to get this to
work with enough fiddling.  My first simple-minded go didn't work
(though was at least having effects on the right bits of the code, just
not the effects I wanted).


The other point is that in a lot of cases zsh will exec the final
external programme anyway.  However, it doesn't do it in the case of
functions since it dosn't have enough knowledge of what needs to happen
when the programme called by the function exits.  With enough safeguards
this could probably be got to work --- though this is definitely an
optimisation rather than a bug fix and there is the danger of breaking
things.

Passing through the flag saying if this is the last chunk of code in the
list being executed by the function and its parents is the most obvious
necessary test, but I think most of the infrastructure for this already
exists.  For example, if you run

{ :; sleep 20; } &

you should find there's no additional shell instance when the sleep
is running (up to shell state that might get in the way --- I get an
extra shell when running from the top-level shell in the window but not
if I start a new one, for reasons that escape me completely).

The other thing I can think of is we'd need to test for the presence of
traps that might get called on function exit, including EXIT and DEBUG.
This is interesting because they might not actually be present when the
function starts, so we'd need a special version of the flag saying only
exec if there are no relevant traps at the last command to be executed.

I can't think of any other gotchas but there could well be some.

It's not clear this is worth the bother.

pws



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