Warum wird der Chrom-Browser beendet, wenn ich das Terminal trotz NOHUP schließe?

12

Diese Frage ist alt und ich weiß immer noch nicht warum.


Ursprüngliche Frage im Jahr 2014:

In einem Gnome-Terminal-Tab lief ich

$ nohup chromium-browser &

Aber wenn ich die Terminal-Registerkarte schließe, wird sie chromium-browserauch beendet. Soll das nicht nohupverhindern? Gilles sagte:

Von Nohup und Disown kann gesagt werden, dass sie SIGHUP auf unterschiedliche Weise unterdrücken. nohup veranlasst das Programm, das Signal zunächst zu ignorieren (das Programm kann dies ändern). nohup versucht auch, dafür zu sorgen, dass das Programm kein steuerndes Terminal hat, damit es nicht vom Kernel SIGHUP gesendet wird, wenn das Terminal geschlossen wird. Verleugnung ist rein innerlich in der Hülle; es bewirkt, dass die Shell SIGHUP nicht sendet, wenn sie beendet wird.

Lässt Nohup Chrom-Browser SIGHUP nicht ignorieren?

Ich sehe dies auch auf anderen ausführbaren Dateien wie und Emacs (GUI-Modus). Aber nicht auf xeyes.

Dies geschieht unter Ubuntu 12.04, 32-Bit, als die Frage veröffentlicht wurde.


Update im Jahr 2015,

Jetzt starte ich Ubuntu 14.04 mit google-chromestatt chromium-browserinstalliertem. Dasselbe, was zuvor mit Chrom-Browser passiert ist, gilt jetzt auch für Google-Chrome. nohup google-chrome 2>/dev/null &speichert es nicht vor dem Schließen, wenn die Terminalregisterkarte geschlossen wird. /usr/bin/google-chromeist ein Link zu einem Bash-Skript /opt/google/chrome/google-chrome. Warum funktioniert die nohupAnwendung auf das Bash-Skript nicht? Wie können wir dafür sorgen, dass es mit Bash-Skripten funktioniert? Was ist mit Python-Skripten?

Tim
quelle
1
Sie sollten mehr über Ihre Umgebung erzählen. Ich reproduziere Ihren Testfall nicht.
Juli
Mit welchen anderen ausführbaren Dateien sehen Sie das? Probieren Sie zum Beispiel etwas Einfaches wie xeyes.
Warren Young
@ WarrenYoung: Emacs (GUI). Aber xeyes funktioniert.
Tim

Antworten:

11

Wenn Sie ein GNOME-Terminalfenster schließen, wird ein SIGHUP an die Shell gesendet, auf der es ausgeführt wurde. Die Shell sendet in der Regel ein SIGHUP an jede Prozessgruppe, von der sie weiß, dass sie erstellt wurde - auch an die Prozessgruppe, mit der sie begonnen hat nohup- und beendet diese anschließend. Wenn dies der Fall ist bash, wird das Senden eines SIGHUP an eine Prozessgruppe, die der Benutzer mit markiert hat, übersprungen disown.

Wenn Sie einen Befehl mit nohupausführen, wird SIGHUP ignoriert, aber der Prozess kann dies ändern. Wenn die Disposition von SIGHUP für einen Prozess die Standardeinstellung ist, wird der Prozess beendet, wenn SIGHUP empfangen wird.

Linux bietet einige Tools, um die Signaleinstellungen eines laufenden Prozesses zu überprüfen.

Das Chrom-Browser-Shell-Skript führt eine execder kompilierten Anwendungen aus, sodass die Prozess-ID unverändert bleibt. Um die Signaleinstellungen zu sehen, bin ich gelaufen nohup chromium-browser &und habe mir dann /proc/$!/statusdie Signalverteilung angesehen.

SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003

Das sind Hex-Zahlen. Dies zeigt, dass SIGHUP nicht abgefangen und nicht ignoriert wird. Nur SIGPIPE (das 13. Bit in SigIgn) wird ignoriert. Ich habe dies auf den folgenden Code zurückgeführt :

// 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);
}

Trotz des Kommentars werden vom übergeordneten Element ignorierte Signale nicht ignoriert. Ein SIGHUP tötet Chrom.

Die Problemumgehung besteht darin, das zu tun, worauf @ xx4h hinweist: Verwenden Sie den disownBefehl in Ihrer Bash, damit SIGHUP nicht an die chromium-browserProzessgruppe gesendet wird , wenn die Bash beendet werden muss . Sie können dazu eine Funktion schreiben:

mychromium () { /usr/bin/chromium-browser & disown $!; }
Mark Plotnick
quelle
Vielen Dank. Jetzt verstehe ich meistens, was Sie meinten. "Da das Skript diese Falle nie zurücksetzt, wird die eigentliche Chrom-Binärdatei mit der Standardeinstellung von SIGHUP aufgerufen." Wollen Sie mit "reset this trap" den Trap für SIGHUP auf den Standardwert zurücksetzen, wodurch der Vorgang beendet wird? Wie können Sie "diese Falle zurücksetzen"?
Tim
Oh, mit "setze diese Falle zurück" meinte ich "setze die Disposition dieses Signals wieder auf den Stand vor dem Setzen eines Handlers durch das Shell-Skript". Wenn die Shell dies tun trap "" 1würde, würde die Shell (und ihre Kinder) SIGHUP ignorieren. Ich werde das klären.
Mark Plotnick
Vielen Dank. Wird es nach Ihrer Abklärung überprüfen. Ich versuche jetzt, Daemon, Nohup, Disown und Background zu verstehen, also bin ich zurückgekommen, um meine alten Fragen und Antworten zu überdenken, die ich nicht verstanden habe. Die Unklarheiten in Bezug auf Nohup, Disown und Hintergrund sind größtenteils gelöst, und ich bin mit dem Konzept des Daemons und der Dämonisierung eines Prozesses (siehe unten) festgefahren. Ich freue mich wieder, wenn Sie Zeit haben, wieder zu helfen.
Tim
Ich habe mir den Chrom-App-Code angesehen, und es stellte sich heraus, dass der C ++ - Code in der Anwendung SIGHUP bedingungslos auf den Standard zurücksetzt. Die trapBefehle im Shell-Script-Wrapper verhindern dies nicht und die Ausführung nohupkann dies nicht verhindern. Ich werde meine Antwort überarbeiten, um dies widerzuspiegeln.
Mark Plotnick
3

Wenn chromium-browseretwas in der Art ist, google-chromedann denke ich, ist das wahrscheinlichste Problem, dass chromium-browser es nichtchromium ist, sondern ein Shell-Wrapper ist, der den Zustand initialisiert, dann execs chromium.

In meiner google-chromeInstallation befindet sich die Binärdatei tatsächlich in /opt/google/chromeund der Wrapper in /usr/binist nur ein Shell-Skript, das viele Umgebungen in Bezug auf xdg-*Standardwerte und absolute Pfade und ähnliches einrichtet, bevor es durch die eigentliche Binärdatei ersetzt wird.

Zu diesem Zeitpunkt werden alle Signale, die nohupursprünglich für das als untergeordnetes Element aufgerufene Skript ignoriert wurden, unwichtig. Wenn das Wrapper-Skript nicht darauf achtet , dass es anders angeordnet wird (was es nicht ist), wird die ctty vererbt.

Versuchen Sie file /usr/bin/chromium-browserzu überprüfen, ob es das Shell-Skript ist, von dem ich denke, dass es es ist. Wenn ja, überlegen Sie, ob Sie es umschreiben möchten, damit es besser zu Ihnen passt.

Ich kann sagen, dass nur google-chrome 2>/dev/null &so etwas für mich offen bleibt, aber ich kann mich nicht erinnern, ob das ein wahrscheinliches Ergebnis von Änderungen ist, die ich am Skript vorgenommen habe - es war vor über einem Jahr.

mikeserv
quelle
Vielen Dank. Dasselbe, was chromium-browserzuvor passiert ist, passiert google-chromejetzt auch. Ich habe nicht chromium-browserinstalliert. nohup google-chrome 2>/dev/null &speichert es nicht vor dem Schließen, wenn die Terminalregisterkarte geschlossen wird. google-chromeist ein Bash-Skript /opt/google/chrome/google-chrome. Warum funktioniert nohup, das auf ein Bash-Skript angewendet wird, nicht? Wie können wir dafür sorgen, dass es mit Bash-Skripten funktioniert? Was ist mit Python-Skripten?
Tim
Nun, es funktioniert mit dem Skript, aber das Skript wird nur einige Nanosekunden ausgeführt, bevor es durch die eigentliche chromeBinärdatei ersetzt wird.
mikeserv
execWollen Sie damit sagen, dass es im Skript eine aktuelle chromeBinärdatei gibt? Wie ändere ich dann das Skript? Hier ist mein/opt/google/chrome/google-chrome
Tim
@ Tim - ja - sehen Sie den Boden? exec -a "$0" "$HERE/chrome" ... || exec -a "$0" "$HERE/chrome"... Oben $HEREsteht der Wert von readlink $0 (für den Sie den Installationspfad verwenden google-chrome), aber /opt/google/chrome/chromedie Binärdatei - durch die sich das Skript selbst ersetzt.
mikeserv
@Tim: Soweit wie geht - du kannst das execwohl einfach fallen lassen . Sie werden mit einer zusätzlichen PID (über die 1000 anderen hinaus) und einem wartenden Shell-Prozess fertig, aber ich denke, das ist das Ausmaß davon. Oder Sie könnten execw / nohupvielleicht ersetzen . Alles hängt hauptsächlich davon ab, was chrometoleriert wird - aber es sollte so funktionieren.
mikeserv