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 te
When you close the terminal, shell sends SIGHUP to all background processes – and that kills them. This can be suppressed in several ways, most notably:
When you run program with nohup it catches SIGHUP and redirect program output.
$ nohup app &
disown tells shell not to send SIGHUP
$ app &
$ disown
It is dependent on your shell. Above applies at least for bash.
AFAIK in both cases the process should be killed. In order to avoid this you have to issue a nohup like the following:
> nohup ./my_app &
This way your process will continue executing. Probably the telnet part is due to a BUG similar to this one:
https://bugzilla.redhat.com/show_bug.cgi?id=89653
In order completely understand whats happening you need to get into unix internals a little bit.
When you are running a command like this
./app_name &
The app_name is sent to background process group. You can check about unix process groups here
When you close bash with normal exit it triggers SIGHUP hangup signal to all its jobs. Some information on unix job control is here.
In order to keep your app running when you exit bash you need to make your app immune to hangup signal with nohup utility.
nohup - run a command immune to hangups, with output to a non-tty
And finally this is how you need to do it.
nohup app_name & 2> /dev/null;
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.