When a job is still running and the CHECK_JOBS is set, zsh should only
exit when it receives two exit requests in a row. However, sometimes it
honors an exit request in other conditions. One repeatable case is when
the request is a Control-D and there was only one command run since the
last exit request. The following illustrates (<C-D> stands for pressing
Control-D):
% vi
zsh: suspended vi
% exit
zsh: you have suspended jobs.
% true
% exit
zsh: you have suspended jobs.
% true
% true
% <C-D>
zsh: you have suspended jobs.
% true
% <C-D>
<shell exits>
I have accidentally logged out with my mail open several times because
of this.
Andrew
----- Forwarded message from Andrew Pimlott <andrew@pimlott.net> -----
When a job is still running and the CHECK_JOBS is set, zsh should only
exit when it receives two exit requests in a row. However, sometimes it
honors an exit request in other conditions. One repeatable case is when
the request is a Control-D and there was only one command run since the
last exit request. The following illustrates (<C-D> stands for pressing
Control-D):
% vi
zsh: suspended vi
% exit
zsh: you have suspended jobs.
% true
% exit
zsh: you have suspended jobs.
% true
% true
% <C-D>
zsh: you have suspended jobs.
% true
% <C-D>
<shell exits>
I have accidentally logged out with my mail open several times because
of this.
Andrew
----- End forwarded message -----
----- Forwarded message from Andrew Pimlott <andrew@pimlott.net> -----
When a job is still running and the CHECK_JOBS is set, zsh should only
exit when it receives two exit requests in a row. However, sometimes it
honors an exit request in other conditions. One repeatable case is when
the request is a Control-D and there was only one command run since the
last exit request. The following illustrates (<C-D> stands for pressing
Control-D):
% vi
zsh: suspended vi
% exit
zsh: you have suspended jobs.
% true
% exit
zsh: you have suspended jobs.
% true
% true
% <C-D>
zsh: you have suspended jobs.
% true
% <C-D>
<shell exits>
I have accidentally logged out with my mail open several times because
of this.
Andrew
----- End forwarded message -----
On Apr 7, 3:10pm, Clint Adams wrote: } } When a job is still running and the CHECK_JOBS is set, zsh should only } exit when it receives two exit requests in a row. However, sometimes it } honors an exit request in other conditions. One repeatable case is when } the request is a Control-D and there was only one command run since the } last exit request. The issue here seems to be that zsh doesn't actually receive a ctrl-D keystroke, but rather that there is a true end-of-file on the tty. If you try, for example, running zsh and then starting another zsh from within the first, then when you force the "inner" zsh to exit, the "outer" one sometimes exits as well. There may actually be some kind of race condition here, because sometimes only the "inner" shell exits. It might even be an xterm bug. Here's a much simpler example to reproduce the base problem: zsh -f % sleep 300 & % <C-d> zsh: you have running jobs. % true % <C-d> zsh: warning: 1 jobs SIGHUPed It only happens with <C-d>, not with the 'exit' builtin, so it may have to do with an interaction with no_ignore_eof.
Ok, but I don't think this should preclude correct behavior. My understanding is that when <C-D> is pressed, the application gets a zero-length read on the terminal, but that a subsequent read will get more keyboard input (or another zero-length read if <C-D> is pressed again). So zsh should still be able to detect each press of <C-D> reliably. Hmm, mysterious. I should have also said in my message that I think I've seen unexpected exits in other cases, but the one I posted is the only one I could reproduce. It sounds like there is a subtle bug in zsh. Right, I should have explained that I gave a longer example to show that 1) exit and <C-D> act differently and 2) running two commands between <C-D>s behaves as expected. Andrew
On Apr 9, 4:47pm, Andrew Pimlott wrote: } Subject: Re: Bug#303623: [andrew@pimlott.net: Bug#303623: zsh: CHECK_JOBS } } > The issue here seems to be that zsh doesn't actually receive a ctrl-D } > keystroke, but rather that there is a true end-of-file on the tty. } } Ok, but I don't think this should preclude correct behavior. My } understanding is that when <C-D> is pressed, the application gets a } zero-length read on the terminal If the TTY driver is interpreting the EOF character, then yes, that is what happens. However, zsh supposedly doesn't allow the TTY driver to interpret <C-d>; it puts the terminal in CBREAK mode, so it receives a literal ASCII '\04' character, so that it's able to invoke the bindkey for that, which normally runs delete-char-or-list. The do-not-exit-when-jobs-are-pending behavior relies on having read a '\04' when the input buffer is empty. It's a simulated end-of-file rather than a real one. What *appears* to be happening -- I could still be wrong -- is that on the second C-d the CBREAK setting fails to work as expected and zsh in fact gets a zero-length read. When ignoreeof is not set, this causes the shell to exit. The point being that although I agree this is not the correct behavior, the reason for the failure is not what you may think, and therefore the fix is likely to be in a more obscure part of the C code. Further, the workaround in the meantime is to setopt ignoreeof.
Ah, I see, thanks. However, a strace doesn't seem to show that
happening in this case. Here are the reads on FD 10 while reproducing
the problem:
read(10, "\4", 1) = 1
read(10, "t", 1) = 1
read(10, "r", 1) = 1
read(10, "u", 1) = 1
read(10, "e", 1) = 1
read(10, "\n", 1) = 1
read(10, "\4", 1) = 1
Andrew
found 303623 4.3.9-1 richih@roadwarrior ~ % zsh-beta -f roadwarrior% echo $ZSH_VERSION 4.3.9-dev-1-cvs1218 roadwarrior% vim zsh: suspended vim roadwarrior% exit zsh: you have suspended jobs. roadwarrior% true roadwarrior% exit zsh: you have suspended jobs. roadwarrior% true roadwarrior% true roadwarrior% zsh: you have suspended jobs. roadwarrior% true roadwarrior% Vim: Caught deadly signal HUP Vim: Finished.
Hey zsh-workers, Anyone care to take another stab at this old bug? http://bugs.debian.org/303623 The entire discussion is in the Debian bug log. Maybe someone will have a fresh idea in the new decade. ;-) I just nuked a session with a bunch of jobs running. :-( Andrew
On Apr 18, 4:44pm, Andrew Pimlott wrote:
}
} Anyone care to take another stab at this old bug?
} http://bugs.debian.org/303623
It looks like this behavior has been there since approximately the
beginning of time. If there was ever an email thread about it, that
thread pre-dates the zsh.org archives that date back to 1995.
However, I think I found some clues, in particular a comment (still
present in Src/jobs.c) that originated in an ancient version of the
shell:
/* If you immediately type "exit" after "jobs", this *
* will prevent zexit from complaining about stopped jobs */
Keep in mind that two exits (or two ctrl+d) in a row are supposed to
cause the shell to exit even if there are running jobs. In the years
that intervened, code migrated to different files and the *other*
place that sets stopmsg = 2 is now no longer in proximity to that
comment. That other place is in the handler for ctrl+d.
The rationale seems to be:
1. You type exit (or hit ^D) and the shell says you still have jobs.
2. You type "jobs" to find out what is still running.
3. There's nothing interesting in the jobs list (you just want them
to die).
4. You type exit (or ^D) again.
5. Zsh deliberately ignores the fact that you ran a command between
the two exits, and simply goes away without further complaint.
All of this because someone else 17+ years ago was annoyed that the
shell did NOT exit without complaining -- exactly the opposite of the
thing that now annoys you.
I *think*, if we no longer care to provide this particular (mis?)feature,
that it would be OK to remove the "stopmsg = 2" from builtin.c:zexit().
However, I'm not entirely confident there aren't other side-effects.
On Apr 18, 9:27pm, Bart Schaefer wrote: } } I *think*, if we no longer care to provide this particular (mis?)feature, } that it would be OK to remove the "stopmsg = 2" from builtin.c:zexit(). } However, I'm not entirely confident there aren't other side-effects. One possible side-effect being that the shell does not "try again" when it gets a *real* EOF as opposed to reading a ctrl+d. (Events in the opposite order of my speculation in the earlier discussion in that bug track.)
It should surely be possible to fix it properly, somehow, so that if you've just looked at the jobs it will still exit but if you've executed anything else it won't. However, I don't think having to type ^D twice in any case is particularly bad (though I do recall occasions in the completion system where Sven spent some time adding features to avoid a user having to type A WHOLE EXTRA CHARACTER). pws 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 More information can be found at www.csr.com. Follow CSR on Twitter at http://twitter.com/CSR_PLC and read our blog at www.csr.com/blog
On Apr 19, 9:36am, Peter Stephenson wrote: } } It should surely be possible to fix it properly, somehow, so that if } you've just looked at the jobs it will still exit but if you've executed } anything else it won't. Yes, that would be accomplished by removing stopmsg = 2 from zexit() but leaving stopmsg = 2 in bin_jobs(). However, as I mentioned in follow-up, I fear the assignment in zexit() may have an additional purpose, such as forcing the shell to get two consecutive zero-length reads on SHIN in order to kill jobs and exit. It's a little tricky to test this and I haven't had a chance yet.
Nice archeology, guys. ;) I'm grateful to you for checking this out. I bet at least a couple other people have experienced this and not known what hit them. (Your terminal window is gone, you're in shock: you probably can't reconstruct how it happened.) Regarding the idea that "if you've just looked at the jobs it will still exit", I would argue against that. It seems like a surprise case to me, and I'd prefer the extra protection and consistency. But if that's the way it's always been meant to work, I can understand it. Andrew