Why my process is still running after I log out?

Solution 1:

Tl;dr:

Why can the sleep process survive when I log out and the terminal is closed? In my mind, everything except daemons and nohup programs will be killed during logout. If sleep can survive in this way, does it mean that I can use this method instead of the nohup command?

Unless the bash instance spawned by ssh has the huponexit option set, no process will be terminated by any mean upon exit / log out, and when the huponexit option is set, using kill -9 on the shell is not a good alternative to using nohup on the shell's child processes; nohup on the shell's child processes will still protect them from SIGHUPs not coming from the shell, and even when that is not important nohup is still to be preferred because it allows the shell to be terminated gracefully.


In bash there's an option called huponexit, which if set will make bash SIGHUP its children upon exit / logout;

In interactive non-login bash instances, such as in a bash instance spawned by gnome-terminal, this option is ignored; whether huponexit is set or unset, bash's children will never be SIGHUPped by bash upon exit;

In interactive login bash instances, such as in a bash instance spawned by ssh, this option is not ignored (however it is unset by default); if huponexit is set, bash's children will be SIGHUPped by bash upon exit / logout; if huponexit is unset, bash's children will not be SIGHUPped by bash upon exit / logout;

So in general exiting / logging out from an interactive login bash instance, unless the huponexit option is set, won't make the shell SIGHUP its children, and exiting / logging out from an interactive non-login bash instance won't make the shell SIGHUP its children regardless;

This is, however, irrelevant in this case: using kill -9 sleep will survive regardless, because killing its parent process (bash) won't leave a chance for the latter to do anything to the former (i.e., e.g., if the current bash instance was a login bash instance and the huponexit option was set, to SIGHUP it).

Adding to this, unlike other signals (like a SIGHUP signal sent to bash), a SIGKILL signal is never propagated to a process's child processes, hence sleep is not even killed;

nohup starts a process immune to SIGHUP signals, which is something different; it will prevent the process hanging up upon the reception of a SIGHUP signal, which in this case could be received by the interactive login bash instance in case the huponexit option was set and the shell exited; so technically using nohup to start a process in an interactive login bash instance with the huponexit option unset will prevent the process from hanging up upon the reception of a SIGHUP signal, but exiting / logging out of the shell won't SIGHUP it regardless;

In general, however, when nohup is needed to prevent SIGHUP signals coming from the parent shell, there's no reason to prefer the kill -9 on the parent method to the nohup on the child method; instead, it should be the opposite.

Killing the parent using the kill -9 method doesn't leave a chance for the parent to exit gracefully, while starting the child using the nohup method allows the parent to be terminated by other signals, such as SIGHUP (to make an example which makes sense in the context of a child started using nohup), which allow it to exit gracefully.

Solution 2:

bash by default does not send down the HUP signal to child processes when exiting. More in detail (thanks @kos), it never does it for non-login shells.

You can configure bash to do it for login shells if set the option huponexit. In a terminal, do:

[romano:~] % bash -l

(this start a new "login" shell)

romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout

Now check for the sleep process:

[romano:~] % ps augx | grep sleep
romano   32231  0.0  0.0  16000  2408 pts/11   S+   15:23   0:00 grep sleep

...not running: it has received the HUP signal and exited as requested.

Solution 3:

If sleep can survive in this way, if it means that I can use this method instead of nohup command?

kill -9 is really not the way one should go. It's like shooting with a gun at the TV to turn it off. Besides the comedic component there is no advantage. Processes can't catch or ignore SIGKILL. If you don't give the process a chance to finish what it's doing and clean up, it may leave corrupted files (or other state) around and won't be able to start again. kill -9 is the last hope, when nothing else works.


Why sleep process can survive when I logout and terminal is closed. In my mind, everything except daemon and nohup program will be killed when logout.

What in your case happens:

The parent process of sleep is the currently running bash shell. When you kill -9 that bash, the bash process has not the chance to send a SIGHUP to any of its child processes, because SIGKILL (which is sent by kill -9) is not catchable by the process. The sleep process continues running. sleep now became an orphan process.

The init (PID 1) process does a mechanism called reparenting. That means that the init process now becomes the parent of that orphaned process. init is an exception, processes can become it's child as it collects processes that lost their original parent process. Btw: A daemon (like sshd) does that when "going in the background".

If that whould not happen, the orphaned process would later (when finished) become a zombie process. This is what happens when waitpid() is not called (a responsibility of the parent process which cannot be fullfilled when when that process got killed). init calls waitpid() in an specific intervall to avoid zombie childs.