I processi in background ottengono un SIGHUP quando ci si disconnette?


21

Questo è un seguito a questa domanda .

Ho eseguito altri test; sembra davvero non importa se questo viene fatto sulla console fisica o tramite SSH, né ciò accade solo con SCP; L'ho anche provato con cat /dev/zero > /dev/null. Il comportamento è esattamente lo stesso:

  • Avvia un processo in background usando &(o mettilo in background dopo aver iniziato a usare CTRL-Ze bg); questo viene fatto senza usarenohup .
  • Disconnettersi.
  • Accedi di nuovo.
  • Il processo è ancora lì, funziona felicemente ed è ora figlio diretto di init.

Posso confermare immediatamente la chiusura di SCP e CAT se inviato a SIGHUP; Ho provato questo usando kill -HUP.

Quindi, sembra davvero che SIGHUP non venga inviato al momento della disconnessione, almeno ai processi in background (non è possibile eseguire il test con uno in primo piano per ovvi motivi).

Questo mi è successo inizialmente con la console di servizio di VMware ESX 3.5 (che si basa su RedHat), ma sono stato in grado di replicarlo esattamente su CentOS 5.4.

La domanda è di nuovo: un SIGHUP non dovrebbe essere inviato ai processi, anche se sono in esecuzione in background, al momento della disconnessione? Perché questo non sta succedendo?


modificare

Ho controllato con strace, secondo la risposta di Kyle.
Come mi aspettavo, il processo non riceve alcun segnale quando ci si disconnette dalla shell in cui è stato avviato. Ciò accade sia quando si utilizza la console del server che tramite SSH.


Usando Bash su CentOS 7.1, un semplice ciclo di script di shell otterrà un SIGHUP se viene lasciato in primo piano, ma il terminale viene ucciso; la sequenza di un altro terminale mostra: --- 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,

Così sarà uno script in background. Si noti che il terminale è chiuso mentre il loop è in attesa di sospensione. La shell NON è uscita:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
Mike S,

Vedi la mia risposta per i test. È interessante notare che non ho visto alcun cambiamento nel comportamento a causa di huponexit.
Mike S,

Risposte:


26

Risposta trovata

Per BASH, questo dipende huponexitdall'opzione shell, che può essere visualizzata e / o impostata usando il shoptcomando integrato .

Sembra che questa opzione sia disattivata per impostazione predefinita, almeno sui sistemi basati su RedHat.

Maggiori informazioni sulla pagina man di BASH :

La shell esce di default al ricevimento di un SIGHUP. Prima di uscire, una shell interattiva rinvia SIGHUP a tutti i lavori, in esecuzione o arrestati. I lavori interrotti vengono inviati a SIGCONT per garantire che ricevano il SIGHUP. Per impedire alla shell di inviare il segnale a un particolare lavoro, è necessario rimuoverlo dalla tabella dei lavori con il comando incorporato disown (vedere COMANDI INCORPORATI SHELL di seguito) o contrassegnato per non ricevere SIGHUP usando disown -h.

Se l'opzione shell huponexit è stata impostata con shopt, bash invia un SIGHUP a tutti i lavori quando esce una shell di login interattiva.


4
Verificato. Quando eseguivo un "exit", "logout" o CTL-D, il proc bambino (lavoro) non riceveva un sospiro (utente root e reg). Tuttavia, quando ho fatto "kill -HUP $$" per uccidere l'attuale istanza di bash, i processi figlio DID ricevono un sospiro. Ho quindi impostato huponexit e il processo figlio ha ricevuto SIGHUP all'uscita.
CarpeNoctem,

3

Verrà inviato SIGHUP nei miei test:

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 Ancora:

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

Shell2 di nuovo :

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

Perché continua a funzionare ?:
Advanced Programing in Unix Environment di Stevens tratta questo nella sezione 9.10: Orphaned Process Groups. La sezione più rilevante è:

Poiché il gruppo di processi è orfano quando termina il genitore, POSIX.1 richiede che a ogni processo nel gruppo di processi appena orfano che viene arrestato (come lo è nostro figlio) venga inviato il segnale di riaggancio (SIGHUP) seguito dal segnale di continuazione (SIGCONT ).

Questo fa sì che il bambino continui, dopo aver elaborato il segnale di riaggancio. L'azione predefinita per il segnale di riaggancio è di terminare il processo, quindi dobbiamo fornire un gestore di segnale per catturare il segnale. Ci aspettiamo quindi che printf nella funzione sig_hup appaia prima di printf nella funzione pr_ids.


Ma hai esplicitamente inviato un SIGHUP ad esso qui; Stavo parlando di cosa succede quando ti disconnetti dalla shell da cui hai iniziato il processo.
Massimo,

Stessi risultati quando scrivo exit, anche se ricevo un avviso sui lavori, ma poi digito exit. Ho provato questo con ZSH.
Kyle Brandt,

Sto usando BASH e questo probabilmente dipende dalla shell. Ma BASH dovrebbe inviare SIGHUP ai processi figlio quando si disconnette ...
Massimo,

Bash invia SIGCONT apparentemente se il lavoro viene interrotto, ma confermo che non invia nulla se il lavoro non viene interrotto.
Kyle Brandt,

Usando Bash su CentOS 7.1, ottengo un SIGTERM inviato al mio processo fermato in un'altra finestra: 1.) Avvia un semplice script di shell (loop con un'eco e uno sleep), 2.) Control-Z it, 3) traccia il processo in un'altra finestra, 4) uscire dal terminale originale. Si lamenta che ho dei lavori in corso, quindi dopo essere uscito dai miei show di strace: $ 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 +++ Strano, sicuramente non in accordo con la sezione citata da Stevens.
Mike S,

2

Ho eseguito alcuni test usando CentOS 7.1 e bash. Nota che questo significa che huponexitè offdi default ed era spento per la maggior parte dei miei test.

È necessario nohupquando si avvia un lavoro in un terminale, perché se si chiude quel terminale senza uscire dalla shell in modo pulito , il terminale invia il segnale SIGHUP alla shell, che quindi lo invia a tutti i bambini. Se esci dalla shell in modo pulito, il che significa che il lavoro deve essere già in background in modo da poter digitare exito premere Control-D al prompt dei comandi, nessun segnale di alcun tipo viene inviato al lavoro in background da bash.

Test:

Terminale 1

$ echo $$
16779

Terminale 2

$ strace -e signal -p16779
Process 16779 attached

(chiudere il terminale 1, visto nel terminale 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 +++

Lavoro 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

Avviarlo in background nel Terminal 1:

Terminale 1

$ ./doit.sh &
[1] 22954

Straccialo nel Terminal 2; chiudi il Terminal 1 dopo un paio di loop:

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

Uscita nel terminale 3:

Terminal 3

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

Tuttavia, se esci bash, esce semplicemente senza inviare alcun segnale al bambino. Il terminale uscirà perché non ha più un figlio, ma ovviamente non c'è nessuno su HUP perché la shell figlio è già sparita. Il SIGINT, SIG_BLOCKe SIG_SETMASKvedi sotto sono dovuti al sleepnella shell.

Terminale 1

$ ./doit.sh &
26275

Terminale 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

Terminale 3, uscita

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

È interessante notare, ho impostato huponexitper essere avanti con shopt -s huponexit; shopt(quest'ultimo shopt alla recensione), quindi eseguito l'ultimo test, e di nuovo bash inviato alcun segnale al processo in background . Ancora più interessante, come abbiamo visto bash ha inviato il segnale al processo in background dopo averlo ricevuto da un terminale che si chiudeva in faccia. Sembra come se huponexitnon avesse alcuna influenza in un modo o nell'altro.

Spero che questo rimuova ogni mistero o confusione riguardo almeno al sostegno di Bash, su quando e come viene inviato il segnale HUP. Almeno i miei test erano completamente riproducibili, per me. Sarei interessato a sapere se ci sono altre impostazioni che potrebbero influenzare il comportamento di Bash.

E, come sempre, YSMV (Your Shell May Vary).

Addendum 1

Quando eseguo una shell come exec /bin/sh, quindi eseguo lo script come /bin/sh ./doit.sh &, quindi esco dalla shell in modo pulito, nessun segnale viene inviato al processo in background e continua a funzionare fino al completamento.

Addendum 2

Quando eseguo una shell come exec /bin/csh, quindi eseguo lo script come /bin/sh ./doit.sh &, quindi esco dalla shell in modo pulito, nessun segnale viene inviato al processo in background e continua a funzionare fino al completamento.


0

Uso csh e i processi in background continuano a funzionare quando mi disconnetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.