I have an embedded system, on which I do telnet
and then I run an application in background:
./app_name &
Now if I close my terminal and do telnet
from other terminal and if I check then I can see this process is still running.
To check this I have written a small program:
#include<stdio.h>
main()
{
while(1);
}
I ran this program in my local linux pc in background and I closed the terminal.
Now, when I checked for this process from other terminal then I found that this process was also killed.
My question is:
Normally, foreground and background jobs are killed by SIGHUP
sent by kernel or shell in different circumstances.
SIGHUP
?Kernel sends SIGHUP
to controlling process:
Kernel sends SIGHUP
to other process groups:
Controlling process is the session leader that established the connection to the controlling terminal.
Typically, the controlling process is your shell. So, to sum up:
SIGHUP
to the shell when real or pseudoterminal is disconnected/closed;SIGHUP
to foreground process group when the shell terminates;SIGHUP
to orphaned process group if it contains stopped processes.Note that kernel does not send SIGHUP
to background process group if it contains no stopped processes.
bash
send SIGHUP
?Bash sends SIGHUP
to all jobs (foreground and background):
SIGHUP
, and it is an interactive shell (and job control support is enabled at compile-time);huponexit
option is set (and job control support is enabled at compile-time).See more details here.
Notes:
bash
does not send SIGHUP
to jobs removed from job list using disown
;nohup
ignore SIGHUP
.More details here.
Usually, shells propagate SIGHUP
. Generating SIGHUP
at normal exit is less common.
Under telnet or SSH, the following should happen when connection is closed (e.g. when you close telnet
window on PC):
SIGHUP
to bash
;bash
receives SIGHUP
, sends SIGHUP
to all jobs and terminates;SIGHUP
and terminates.I can reproduce your issue using bash
and telnetd
from busybox
or dropbear
SSH server: sometimes, background job doesn't receive SIGHUP
(and doesn't terminate) when client connection is closed.
It seems that a race condition occurs when server (telnetd
or dropbear
) closes master side of pty:
bash
receives SIGHUP
and immediately kills background jobs (as expected) and terminates;bash
detects EOF
on slave side of pty before handling SIGHUP
.When bash
detects EOF
, it by default terminates immediately without sending SIGHUP
. And background job remains running!
It is possible to configure bash
to send SIGHUP
on normal exit (including EOF
) too:
Ensure that bash
is started as login shell. The huponexit
works only for login shells, AFAIK.
Login shell is enabled by -l
option or leading hyphen in argv[0]
. You can configure telnetd
to run /bin/bash -l
or better /bin/login
which invokes /bin/sh
in login shell mode.
E.g.:
telnetd -l /bin/login
Enable huponexit
option.
E.g.:
shopt -s huponexit
Type this in bash
session every time or add it to .bashrc
or /etc/profile
.
bash
unblocks signals only when it's safe, and blocks them when some code section can't be safely interrupted by a signal handler.
Such critical sections invoke interruption points from time to time, and if signal is received when a critical section is executed, it's handler is delayed until next interruption point happens or critical section is exited.
You can start digging from quit.h
in the source code.
Thus, it seems that in our case bash
sometimes receives SIGHUP
when it's in a critical section. SIGHUP
handler execution is delayed, and bash
reads EOF
and terminates before exiting critical section or calling next interruption point.