Erhalten Hintergrundprozesse beim Abmelden einen SIGHUP?

21

Dies ist eine Fortsetzung dieser Frage .

Ich habe noch einige Tests durchgeführt. Anscheinend spielt es keine Rolle, ob dies an der physischen Konsole oder über SSH erfolgt, und dies geschieht auch nicht nur mit SCP. Ich habe es auch mit getestet cat /dev/zero > /dev/null. Das Verhalten ist genau das gleiche:

  • Starten Sie einen Prozess im Hintergrund mit &(oder fügen Sie ihn in den Hintergrund ein, nachdem Sie mit CTRL-Zund begonnen haben bg). Dies geschieht ohne Verwendung vonnohup .
  • Abmelden.
  • Melden Sie sich erneut an.
  • Der Prozess ist immer noch da, läuft glücklich und ist jetzt ein direktes Kind von init.

Ich kann bestätigen, dass sowohl SCP als auch CAT sofort beendet werden, wenn ein gesendet wird SIGHUP. Ich habe das mit getestet kill -HUP.

Es sieht also so aus, als würde SIGHUP nicht beim Abmelden gesendet , zumindest nicht bei Hintergrundprozessen (aus offensichtlichen Gründen kann es nicht mit einem Vordergrundprozess getestet werden).

Das passierte mir zunächst mit der Servicekonsole von VMware ESX 3.5 (die auf RedHat basiert), aber ich konnte es genau auf CentOS 5.4 replizieren.

Die Frage ist wieder: Sollte ein SIGHUP nicht an Prozesse gesendet werden, auch wenn diese beim Abmelden im Hintergrund ausgeführt werden? Warum passiert das nicht?


Bearbeiten

Ich habe stracenach Kyles Antwort gefragt.
Wie ich erwartet hatte, erhält der Prozess kein Signal, wenn er sich von der Shell abmeldet, auf der er gestartet wurde. Dies geschieht sowohl bei Verwendung der Serverkonsole als auch über SSH.

Massimo
quelle
Bei Verwendung von Bash unter CentOS 7.1 erhält eine einfache Shell-Skript-Schleife einen SIGHUP, wenn sie im Vordergrund bleibt, das Terminal jedoch beendet wird. Strace von einem anderen Terminal zeigt:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=10676, si_uid=3000090} --- rt_sigreturn() = -1 EINTR (Interrupted system call) rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
Mike S
So wird ein Hintergrundskript. Beachten Sie, dass das Terminal geschlossen ist, während die Schleife auf einen Ruhezustand wartet. Die Shell wird NICHT beendet:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
Mike S
Siehe meine Antwort für Tests. Interessanterweise habe ich aufgrund von keine Verhaltensänderung gesehen huponexit.
Mike S

Antworten:

26

Antwort gefunden.

Für BASH hängt dies von der huponexitShell-Option ab, die mit dem integrierten shoptBefehl angezeigt und / oder festgelegt werden kann .

Diese Option ist anscheinend standardmäßig deaktiviert, zumindest auf RedHat-basierten Systemen.

Mehr Infos auf der BASH-Manpage :

Die Shell wird standardmäßig nach Erhalt eines SIGHUP beendet. Vor dem Beenden sendet eine interaktive Shell das SIGHUP erneut an alle laufenden oder gestoppten Jobs. Gestoppte Jobs werden an SIGCONT gesendet, um sicherzustellen, dass sie den SIGHUP erhalten. Um zu verhindern, dass die Shell das Signal an einen bestimmten Job sendet, sollte sie mit dem verbotenen eingebauten Befehl (siehe BEFEHLE ZUM VERBAUEN DER SHELL) aus der Jobtabelle entfernt oder mit dem Befehl -h markiert werden, um SIGHUP nicht zu empfangen.

Wenn die Shell-Option huponexit mit shopt festgelegt wurde, sendet bash beim Beenden einer interaktiven Anmeldeshell ein SIGHUP an alle Jobs.

Massimo
quelle
4
Verifiziert Wenn ich ein "Exit", "Logout" oder CTL-D durchführte, erhielt der untergeordnete Proc (Job) kein Seufzen (sowohl Root- als auch Registrierungsbenutzer). Als ich jedoch "kill -HUP $$" ausgeführt habe, um die aktuelle Bash-Instanz zu beenden, haben die untergeordneten Prozesse einen Seufzer erhalten. Ich habe dann huponexit gesetzt und der untergeordnete Prozess hat beim Beenden SIGHUP erhalten.
CarpeNoctem
3

Es wird SIGHUP in meinen Tests gesendet:

Shell1:

[kbrandt@kbrandt-opadmin: ~] ssh localhost
[kbrandt@kbrandt-opadmin: ~] perl -e sleep & 
[1] 1121
[kbrandt@kbrandt-opadmin: ~] ps
  PID TTY          TIME CMD
 1034 pts/46   00:00:00 zsh
 1121 pts/46   00:00:00 perl
 1123 pts/46   00:00:00 ps

Shell2:

strace -e trace=signal -p1121

Wieder Shell1:

[kbrandt@kbrandt-opadmin: ~] exit
zsh: you have running jobs.
[kbrandt@kbrandt-opadmin: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.

Shell2 wieder :

strace -e trace=signal -p1121
Process 1121 attached - interrupt to quit
pause()                                 = ? ERESTARTNOHAND (To be restarted)
--- SIGHUP (Hangup) @ 0 (0) ---
Process 1121 detached

Warum läuft es noch ?:
Erweiterte Programmierung in der Unix-Umgebung von Stevens behandelt dies unter Abschnitt 9.10: Verwaiste Prozessgruppen. Der relevanteste Abschnitt ist:

Da die Prozessgruppe verwaist ist, wenn das übergeordnete Element beendet wird, fordert POSIX.1, dass jedem Prozess in der neu verwaisten Prozessgruppe, der gestoppt wird (wie unser Kind), das Auflegesignal (SIGHUP) gefolgt vom Fortsetzsignal (SIGCONT) gesendet wird ).

Dies bewirkt, dass das Kind nach der Verarbeitung des Auflegesignals fortgesetzt wird. Die Standardaktion für das Auflegen-Signal ist das Beenden des Vorgangs, daher müssen wir einen Signal-Handler bereitstellen, um das Signal abzufangen. Wir erwarten daher, dass das printf in der Funktion sig_hup vor dem printf in der Funktion pr_ids erscheint.

Kyle Brandt
quelle
Aber Sie haben hier ausdrücklich einen SIGHUP dazu geschickt; Ich habe darüber gesprochen, was passiert, wenn Sie sich von der Shell abmelden, in der Sie den Prozess gestartet haben.
Massimo
Gleiche Ergebnisse, wenn ich exit eingebe, obwohl ich eine Warnung über Jobs erhalte, aber dann exit erneut eingebe. Ich habe das mit ZSH getestet.
Kyle Brandt
Ich benutze BASH und das hängt wahrscheinlich von der Shell ab. Aber BASH sollte beim Abmelden SIGHUP an untergeordnete Prozesse senden ...
Massimo
Bash sendet SIGCONT anscheinend, wenn der Job gestoppt wurde, aber ich bestätige, dass es nichts sendet, wenn der Job nicht gestoppt wurde.
Kyle Brandt
Wenn ich Bash unter CentOS 7.1 verwende, wird ein SIGTERM-Befehl gesendet, der in einem anderen Fenster angehalten wird ein anderes Fenster, 4) verlasse das ursprüngliche Terminal. Es beklagt sich, dass ich Laufjobs habe, dann nach dem Verlassen meiner Strace Shows: $ strace -e signal -p1705 Process 1705 attached --- stopped by SIGTSTP --- --- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=791, si_uid=3000090} --- +++ killed by SIGTERM +++ Odd, definitiv nicht in Übereinstimmung mit dem von Stevens zitierten Abschnitt.
Mike S
2

Ich habe einige Tests mit CentOS 7.1 und bash durchgeführt. Hinweis : Um dieses Mittel huponexitist offstandardmäßig und war für die meisten meiner Tests ab.

Dies ist erforderlich, nohupwenn Sie einen Job in einem Terminal starten. Wenn Sie dieses Terminal schließen, ohne die Shell sauber zu verlassen , sendet das Terminal das SIGHUP-Signal an die Shell, die es dann an alle untergeordneten Computer sendet. Wenn Sie die Shell sauber beenden, dh der Job muss sich bereits im Hintergrund befinden, damit Sie exitan der Eingabeaufforderung Control-D eingeben oder drücken können, werden von bash keinerlei Signale an den Hintergrundjob gesendet.

Prüfung:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(Terminal 1 schließen, siehe Terminal 2):

--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16777, si_uid=3000090} ---
rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_DFL, [], SA_RESTORER, 0x7f7ace3d9a00}, {0x456880, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], SA_RESTORER, 0x7f7ace3d9a00}, 8) = 0
kill(16779, SIGHUP)                     = 0
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16779, si_uid=3000090} ---
+++ killed by SIGHUP +++

Beruf doit.sh:

#!/bin/bash

imhupped() {
        echo "HUP" >> /tmp/outfile
}

trap imhupped SIGHUP

for i in $(seq 1 6); do echo out $i >> /tmp/outfile; sleep 5; done

Starte es im Hintergrund in Terminal 1:

Terminal 1

$ ./doit.sh &
[1] 22954

Strace es in Terminal 2; Schließen Sie Terminal 1 nach einigen Schleifen:

Terminal 2

$ strace -e signal -p22954
Process 22954 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22980, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f7a5d547a00}, {0x43e4b0, [], SA_RESTORER, 0x7f7a5d547a00}, 8) = 0
...
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=21685, si_uid=3000090} ---
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=23017, si_status=SIGHUP, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
...

Ausgabe in Klemme 3:

Terminal 3

out 1
out 2
out 3
HUP
out 4
out 5
out 6

Wenn Sie jedoch beenden bash, wird es einfach beendet, ohne dass ein Signal an das Kind gesendet wird. Das Terminal wird beendet, weil es kein Kind mehr hat, aber natürlich ist niemand für HUP da die Kinderschale bereits weg ist. Die SIGINT, SIG_BLOCKund SIG_SETMASKSie sehen unten, sind auf die sleepin der Shell zurückzuführen.

Terminal 1

$ ./doit.sh &
26275

Terminal 2

$ strace -e signal -p26275
Process 26275 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26280, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0


(..."exit" is typed in bash, notice no new signals sent...)


rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26303, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn()                          = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0

Klemme 3, Ausgang

out 1
out 2
out 3
out 4
out 5
out 6

Interessanterweise machte ich mich huponexitan shopt -s huponexit; shoptdie Arbeit (letzteres sollte überprüft werden), führte dann den letzten Test durch und schickte erneut bash kein Signal an den Hintergrundprozess . Noch mehr interstingly, wie wir gesehen haben , bash hat das Signal an den Hintergrundprozess senden , nachdem sie es von einem Terminal erhalten , dass in seinem Gesicht geschlossen. Es scheint, als hätte huponexites keinen Einfluss auf die eine oder andere Richtung.

Ich hoffe, dies beseitigt jedes Rätsel oder jede Verwirrung in Bezug auf zumindest Bashs Huppiness darüber, wann und wie das HUP-Signal gesendet wird. Zumindest waren meine Tests für mich vollständig reproduzierbar. Mich würde interessieren, ob es irgendwelche anderen Einstellungen gibt, die das Verhalten von Bash beeinflussen könnten.

Und wie immer YSMV (Your Shell May Vary).

Anhang 1

Wenn ich eine Shell als exec /bin/shausführe, dann das Skript als /bin/sh ./doit.sh &, dann die Shell sauber beenden, werden keine Signale an den Hintergrundjob gesendet und die Ausführung wird bis zum Abschluss fortgesetzt.

Anhang 2

Wenn ich eine Shell als exec /bin/cshausführe, dann das Skript als /bin/sh ./doit.sh &, dann die Shell sauber beenden, werden keine Signale an den Hintergrundjob gesendet und die Ausführung wird bis zum Abschluss fortgesetzt.

Mike S
quelle
0

Ich benutze csh und Hintergrundprozesse laufen weiter, wenn ich mich abmelde.

Chris S
quelle