Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When did HUP stop getting sent and what can I do about it?

Back in the day when I was young and Unix was the new thing, creating a process that did not get killed when you logged out was a challenge. We used the nohup command to protect our persistent processes from the HUP signal. If we weren't careful, our processes would get killed when we logged off, or even closed the shell we started them from.

Fast forward to today and I find I am surprised that the default appears to be exactly the opposite. On both Ubuntu and Red Hat systems I find that I can put nearly any process in the background, kill the parent shell, log off, anything and it just keeps going. I see the same behavior with Bash scripts, Python scripts and C programs. I get the same behavior from xterm or ssh sessions.

For example in an xterm or ssh window, type:

while [ 1 ]; do date; sleep 10; done > /tmp/out &

Now from another window run

tail -f /tmp/out

Watch it print the date every 10 seconds, then close the original parent shell with Ctrl-D. Still running. Log out and back in. Still running.

Send it a HUP signal, it instantly dies.

I can exhibit the same behavior with a Python script or a C program. Sleep or not doesn't matter. For example, this ugly C program behaves the same:

#include <stdio.h>

void main() {
    while(1) {
        printf("*\n");
        fflush(stdout);
        int i, j, k = 0;
        for(i=0; i < 10000; i++) {
            for(j=0; j < 100000; j++) {
                k += i * j;
            }
        }
    }
}

This is completely counter to the ways of my youth. I guess I just didn't notice when it changed? Any historians out there know when this happened? Does HUP even get used for this purpose any more?

If indeed this is the current state of things, my question is: How can I arrange for a process to die when the user logs off or gets disconnected?

I've got a hack that involves watching for the ppid (parent pid) to change but surely there is something more elegant than that.

like image 851
GaryBishop Avatar asked Jan 22 '14 21:01

GaryBishop


2 Answers

I believe you're looking for the huponexit shell option. You can set this easily with

$ shopt -s huponexit

Some details from the bash man page:

The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP. To prevent the shell from sending the signal to a par- ticular job, it should be removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to not receive SIGHUP using disown -h.

If the huponexit shell option has been set with shopt, bash sends a SIGHUP to all jobs when an interactive login shell exits.

like image 91
JimB Avatar answered Sep 29 '22 12:09

JimB


I still get a SIGHUP. A simple way to test:

#!/usr/bin/env sh

echo "$$"
trap "echo HUPPED $$ > /tmp/willithup" HUP
sleep 1000

Then close the terminal emulator. Now back to your question:

Watch it print the date every 10 seconds, then close the original parent shell with Ctrl-D. Still running. Log out and back in. Still running.

The process doesn't get a HUP when its parent dies. It gets a HUP when it loses the connection to the controlling terminal or when it is explicitly sent a HUP. This happens for example when you logout of SSH.

If we weren't careful, our processes would get killed when we logged off, or even closed the shell we started them from

For the second one: the shell itself can send a HUP to all its children when it exits. However, bash for example has huponexit set to false by default. This may well be what has changed. Note that regardless of the huponexit option, when it receives a HUP the shell also sends a HUP to all its children.


In the words of Stevens:

A session can have a single controlling terminal. This is usually the terminal device (in the case of a terminal login) or pseudo terminal device (in the case of a network login) on which we log in.

If a modem (or network) disconnect is detected by the terminal interface the hang-up signal is sent to the controlling process (the session leader).


To further clarify, the initial HUP is not sent by the shell. It is sent by the terminal driver. Afterwards the shell "forwards" it to the children. So indeed, a HUP sent by the terminal driver can "cascade". From TLPI:

When a controlling process loses its terminal connection, the kernel sends it a SIGHUP signal to inform it of this fact. (A SIGCONT signal is also sent, to ensure that the process is restarted in case it had been previously stopped by a signal.) Typically, this may occur in two circumstances:

  • When a "disconnect" is detected by the terminal driver, indicating a loss of signal on a modem or terminal line.
  • When a terminal window is closed on a workstation. This occurs because the last open file descriptor for the master side of the pseudoterminal associated with the terminal window is closed.
like image 36
cnicutar Avatar answered Sep 29 '22 14:09

cnicutar