linuxshelltelnetjob-control

Does linux kill background processes if we close the terminal from which it has started?


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:


Solution

  • Who should kill jobs?

    Normally, foreground and background jobs are killed by SIGHUP sent by kernel or shell in different circumstances.


    When does kernel send 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:

    Note that kernel does not send SIGHUP to background process group if it contains no stopped processes.


    When does bash send SIGHUP?

    Bash sends SIGHUP to all jobs (foreground and background):

    See more details here.

    Notes:

    More details here.


    What about other shells?

    Usually, shells propagate SIGHUP. Generating SIGHUP at normal exit is less common.


    Telnet or SSH

    Under telnet or SSH, the following should happen when connection is closed (e.g. when you close telnet window on PC):

    1. client is killed;
    2. server detects that client connection is closed;
    3. server closes master side of pty;
    4. kernel detects that master pty is closed and sends SIGHUP to bash;
    5. bash receives SIGHUP, sends SIGHUP to all jobs and terminates;
    6. each job receives SIGHUP and terminates.

    Problem

    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:

    1. normally, bash receives SIGHUP and immediately kills background jobs (as expected) and terminates;
    2. but sometimes, 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!


    Solution

    It is possible to configure bash to send SIGHUP on normal exit (including EOF) too:


    Why does the race occur?

    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.


    Reference