What you're observing is a bug in this version of bash.
kill -9 %1
does kill the job immediately. You can observe that with ps
. You can trace the bash process to see when the kill
system call is called, and trace the subprocess to see when it receives and processes the signals. More interstingly, you can go and see what's happening to the process.
bash-4.3$ sleep 9999
^Z
[1]+ Stopped sleep 9999
bash-4.3$ kill -9 %1
[1]+ Stopped sleep 9999
bash-4.3$ jobs
[1]+ Stopped sleep 9999
bash-4.3$ jobs -l
[1]+ 3083 Stopped sleep 9999
bash-4.3$
In another terminal:
% ps 3083
PID TTY STAT TIME COMMAND
3083 pts/4 Z 0:00 [sleep] <defunct>
The subprocess is a zombie. It's dead: all that's left of it is an entry in the process table (but no memory, code, open files, etc.). The entry is left around until its parent takes notice and retrieves its exit status by calling the wait
system call or one of its siblings.
An interactive shell is supposed to check for dead children and reap them before printing a prompt (unless configured otherwise). This version of bash fails to do it in some circumstances:
bash-4.3$ jobs -l
[1]+ 3083 Stopped sleep 9999
bash-4.3$ true
bash-4.3$ /bin/true
[1]+ Killed sleep 9999
You might expect bash to report “Killed” as soon as it's printing the prompt after the kill
command, but that isn't guaranteed, because there's a race condition. Signals are delivered asynchronously: the kill
system call returns as soon as the kernel has figured out which process(es) to deliver the signal to, without waiting for it to be actually delivered. It's possible, and it does happen in practice, that bash has time to check on the status of its subprocess, find that it's still not dead (wait4
doesn't report any child death), and print that the process is still stopped. What is wrong is that before the next prompt, the signal has been delivered (ps
reports that the process is dead), yet bash still hasn't called wait4
(we can see that not only because it still reports the job as “Stopped”, but because the zombie is still present in the process table). In fact, bash only reaps the zombie the next time it needs to call wait4
, when it's run some other external command.
The bug is intermittent and I couldn't reproduce it while bash is traced (presumably because it's a race condition where bash needs to react fast). If the signal is delivered before bash checks, everything happens as expected.
uname -a
) please – Chris Davies Jun 12 '15 at 18:56Linux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
. I'm running Ubuntu in Parallels Desktop. – s1m0n Jun 12 '15 at 18:59(signal)
so you can tell the difference. – Jun 12 '15 at 20:21set -b
for asynchronous job-control notifications. – mikeserv Jun 13 '15 at 00:51