Why is chromium-browser killed when I close the terminal despite nohup?

When you close a GNOME Terminal window, a SIGHUP is sent to the shell that it was running. The shell will typically send a SIGHUP to every process group that it knows it created - even ones started with nohup - and then exit. If the shell is bash, it will skip sending a SIGHUP to any process group that the user marked with disown.

Running a command with nohup makes it ignore SIGHUP, but the process can change that. When the disposition of SIGHUP for a process is the default, then if it receives a SIGHUP, the process will be terminated.

Linux provides some tools to examine a running process's signal settings.

The chromium-browser shell script does an exec of the compiled app, so its process ID remains the same. So to see its signal settings, I ran nohup chromium-browser & and then looked at /proc/$!/status to see the signal disposition.

SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003

Those are hex numbers. This shows that SIGHUP is not caught and is not ignored. Only SIGPIPE (the 13th bit in SigIgn) is ignored. I traced this to the following code:

// Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
void SetupSignalHandlers() {
  // Sanitise our signal handling state. Signals that were ignored by our
  // parent will also be ignored by us. We also inherit our parent's sigmask.
  sigset_t empty_signal_set;
  CHECK(0 == sigemptyset(&empty_signal_set));
  CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));

  struct sigaction sigact;
  memset(&sigact, 0, sizeof(sigact));
  sigact.sa_handler = SIG_DFL;
  static const int signals_to_reset[] =
      {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
       SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP};  // SIGPIPE is set below.
  for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
    CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
  }

  // Always ignore SIGPIPE.  We check the return value of write().
  CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
}

Despite the comment, signals ignored by the parent are not being ignored. A SIGHUP will kill chromium.

The workaround is to do what @xx4h points out: use the disown command in your bash so that, if bash has to exit, it does not send SIGHUP to the chromium-browser process group. You can write a function to do this:

mychromium () { /usr/bin/chromium-browser & disown $!; }

If chromium-browser is anything like google-chrome then I think the most likely issue is that chromium-browser isn't chromium but is instead a shell-wrapper which initializes state then execs chromium.

In my google-chrome installation the binary is actually located in /opt/google/chrome and the wrapper in /usr/bin is just a shell script which sets up a lot of environment concerning xdg-* defaults and absolute paths and similar before replacing itself with the binary proper.

At this point any signals which nohup might have initially ignored on behalf of the script it called as its child will cease to matter and unless the wrapper script is careful to arrange it otherwise (which it isn't) the ctty is inherited.

Try file /usr/bin/chromium-browser to check if it is the shell-script I think it is. If so, consider rewriting it to better suit you.

I can say that just doing google-chrome 2>/dev/null & keeps it open for me, but I can't recall if that is a likely result of modifications I made to the script - it was over a year ago.

Tags:

Nohup

Chrome