Czy procesy w tle otrzymują SIGHUP podczas wylogowywania?

21

To kontynuacja tego pytania .

Przeprowadziłem jeszcze kilka testów; wygląda na to, że to naprawdę nie ma znaczenia, czy odbywa się to na konsoli fizycznej, czy przez SSH, nie dzieje się tak tylko w przypadku SCP; Testowałem to również z cat /dev/zero > /dev/null. Zachowanie jest dokładnie takie samo:

  • Rozpocznij proces w tle za pomocą &(lub umieść go w tle po rozpoczęciu używania CTRL-Zi bg); odbywa się to bez użycianohup .
  • Wyloguj.
  • Zaloguj się ponownie.
  • Proces jest nadal obecny, przebiega szczęśliwie i jest teraz bezpośrednim dzieckiem init.

Mogę natychmiast potwierdzić zarówno SCP, jak i CAT, jeśli wyślę SIGHUP; Przetestowałem to za pomocą kill -HUP.

Wygląda więc na to, że SIGHUP nie jest wysyłany po wylogowaniu, przynajmniej do procesów w tle (z oczywistych powodów nie można go przetestować na pierwszym planie).

Zdarzyło mi się to początkowo z konsolą serwisową VMware ESX 3.5 (która jest oparta na RedHat), ale udało mi się to replikować dokładnie na CentOS 5.4.

Ponownie pojawia się pytanie: czy SIGHUP nie powinien być wysyłany do procesów, nawet jeśli działają one w tle, po wylogowaniu? Dlaczego tak się nie dzieje?


Edytować

Sprawdziłem strace, zgodnie z odpowiedzią Kyle'a.
Tak jak się spodziewałem, proces nie otrzymuje żadnego sygnału podczas wylogowywania się z powłoki, w której został uruchomiony. Dzieje się tak zarówno podczas korzystania z konsoli serwera, jak i przez SSH.

Massimo
źródło
Używając Bash na CentOS 7.1, prosta pętla skryptu powłoki otrzyma PODSUMOWANIE, jeśli pozostanie na pierwszym planie, ale terminal zabije; strace z innego terminalu pokazuje: --- 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
Podobnie skrypt w tle. Zauważ, że terminal jest zamknięty, gdy pętla czeka na sen. Pocisk NIE jest opuszczany:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
Mike S
Zobacz moją odpowiedź na testy. Co ciekawe, nie widziałem żadnych zmian w zachowaniu z powodu huponexit.
Mike S

Odpowiedzi:

26

Odpowiedź znaleziona.

W przypadku BASH zależy to od huponexitopcji powłoki, którą można wyświetlić i / lub ustawić za pomocą wbudowanego shoptpolecenia.

Wygląda na to, że ta opcja jest domyślnie wyłączona, przynajmniej w systemach opartych na RedHat.

Więcej informacji na stronie podręcznika BASH :

Powłoka wychodzi domyślnie po otrzymaniu SIGHUP. Przed wyjściem interaktywna powłoka ponownie wysyła SIGHUP do wszystkich zadań, uruchomionych lub zatrzymanych. Zatrzymane zadania są wysyłane SIGCONT, aby upewnić się, że otrzymają SIGHUP. Aby zapobiec wysyłaniu przez powłokę sygnału do określonego zadania, należy ją usunąć z tabeli zadań z wbudowanym disown (patrz POLECENIA WBUDOWANE POWŁOKI poniżej) lub zaznaczyć, aby nie odbierać POWIĘKSZENIA za pomocą disown -h.

Jeśli opcja huponexit została ustawiona w shopt, bash wysyła SIGHUP do wszystkich zadań, gdy kończy się interaktywna powłoka logowania.

Massimo
źródło
4
Zweryfikowano Gdy wykonałem „wyjście”, „wylogowanie” lub CTL-D, potomne proc (zadanie) nie otrzymało westchnienia (zarówno użytkownik root, jak i użytkownik reg). Jednak gdy wykonałem polecenie „kill -HUP $$”, aby zabić bieżącą instancję bash, procesy potomne NIE MOGĄ otrzymać westchnienia. Następnie ustawiłem huponexit i proces potomny otrzymał SIGHUP po wyjściu.
CarpeNoctem
3

W moich testach zostanie wysłany SIGHUP:

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

Shell1 Znowu:

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

Shell2 Znowu :

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

Dlaczego nadal działa ?:
Zaawansowane programowanie w środowisku Unix autorstwa Stevensa omawia to w sekcji 9.10: Osierocone grupy procesów. Najbardziej odpowiednia sekcja to:

Ponieważ grupa procesów zostaje osierocona po zakończeniu procesu macierzystego, POSIX.1 wymaga, aby każdy proces w nowo osieroconej grupie procesów, który został zatrzymany (jak nasze dziecko), był wysyłany sygnał rozłączenia (SIGHUP), a następnie sygnał kontynuacji (SIGCONT ).

To powoduje, że dziecko jest kontynuowane po przetworzeniu sygnału rozłączenia. Domyślną czynnością dla sygnału rozłączenia jest zakończenie procesu, dlatego musimy dostarczyć moduł obsługi sygnału, aby przechwycić sygnał. Dlatego oczekujemy, że printf w funkcji sig_hup pojawi się przed printf w funkcji pr_ids.

Kyle Brandt
źródło
Ale tutaj wyraźnie wysłałeś do niego SIGHUP; Mówiłem o tym, co się dzieje, kiedy wylogowujesz się z powłoki, w której rozpocząłeś proces.
Massimo
Te same wyniki, gdy wpisuję polecenie exit, chociaż pojawia się ostrzeżenie o zadaniach, ale następnie ponownie wpisuję exit. Testowałem to z ZSH.
Kyle Brandt
Używam BASH, a to prawdopodobnie zależy od powłoki. Ale BASH powinien wysłać SIGHUP do procesów potomnych podczas wylogowywania ...
Massimo,
Bash wysyła SIGCONT najwyraźniej, jeśli zadanie zostanie zatrzymane, ale potwierdzam, że nic nie wysyła, jeśli zadanie nie zostało zatrzymane.
Kyle Brandt
Używając Bash na CentOS 7.1, otrzymuję SIGTERM wysłany do mojego procesu zatrzymanego w innym oknie: 1.) Uruchom prosty skrypt powłoki (zapętlaj echo i uśpienie), 2.) Control-Z it, 3) śledź proces w kolejne okno, 4) zamknij oryginalny terminal. Narzeka, że ​​mam uruchomione zadania, a następnie po wyjściu ze strace pokazuje:$ 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 +++ Dziwne, zdecydowanie niezgodne z sekcją cytowaną przez Stevensa.
Mike S
2

Przeprowadziłem kilka testów przy użyciu CentOS 7.1 i bash. Uwaga: oznacza huponexitto offdomyślnie i był wyłączony przez większość moich testów.

Potrzebujesz, nohupkiedy zaczynasz zadanie w terminalu, ponieważ jeśli zamkniesz ten terminal bez wyjścia z powłoki , terminal wysyła bash sygnał SIGHUP do powłoki, który następnie wysyła go do wszystkich dzieci. Jeśli wyjdziesz z powłoki czysto - co oznacza, że ​​zadanie musi już znajdować się w tle, aby można było pisać exitlub naciskać klawisz Control-D w wierszu polecenia - z bash żadne sygnały nie będą wysyłane do zadania w tle.

Test:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(zamknij terminal 1, widoczny na terminalu 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 +++

Praca 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

Uruchom go w tle w Terminalu 1:

Terminal 1

$ ./doit.sh &
[1] 22954

Znajdź go w Terminalu 2; zamknij Terminal 1 po kilku pętlach:

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
...

Dane wyjściowe w terminalu 3:

Terminal 3

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

Jednak jeśli wyjdziesz bash, po prostu wyjdzie, nie wysyłając żadnego sygnału do dziecka. Terminal zakończy pracę, ponieważ nie ma już potomka, ale oczywiście nie ma nikogo, kto by HUP, ponieważ skorupa potomna już nie ma. I SIGINT, SIG_BLOCKi SIG_SETMASKwidzisz poniżej, są spowodowanesleep powłoką.

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

Zacisk 3, wyjście

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

Co ciekawe, nastawiłem huponexitsię na shopt -s huponexit; shopt(ten ostatni test do sprawdzenia), potem wykonałem ostatni test i znowu bash nie wysłał żadnego sygnału do procesu w tle . Jeszcze bardziej interstingly, jak widzieliśmy bash zrobił wysłać sygnał do procesu w tle po otrzymaniu go od terminalu, które zostały zamknięte w jego twarz. Wygląda na to, że huponexitnie miało to żadnego wpływu.

Mam nadzieję, że to usunie wszelką tajemnicę lub zamieszanie dotyczące przynajmniej hashingu Basha, kiedy i jak wysyłany jest sygnał HUP. Przynajmniej moje testy były dla mnie całkowicie powtarzalne. Chciałbym wiedzieć, czy są jakieś inne ustawienia, które mogą wpływać na zachowanie basha.

I, jak zawsze, YSMV (Your Shell May Vary).

Dodatek 1

Kiedy uruchamiam powłokę jako exec /bin/sh, a następnie uruchamiam skrypt jako /bin/sh ./doit.sh &, a następnie czysto wychodzę z powłoki, żadne sygnały nie są wysyłane do zadania w tle i kontynuuje działanie do końca.

Dodatek 2

Kiedy uruchamiam powłokę jako exec /bin/csh, a następnie uruchamiam skrypt jako /bin/sh ./doit.sh &, a następnie czysto wychodzę z powłoki, żadne sygnały nie są wysyłane do zadania w tle i kontynuuje działanie do końca.

Mike S.
źródło
0

Używam csh, a procesy wylogowywania są kontynuowane po wylogowaniu.

Chris S.
źródło