GNU/Linux >> Linux Esercitazione >  >> Linux

I processi in background ottengono un SIGHUP quando si disconnettono?

Soluzione 1:

Risposta trovata.

Per BASH, questo dipende dal huponexit opzione shell, che può essere visualizzata e/o impostata usando l'integrato shopt comando.

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 per impostazione predefinita alla ricezione di un SIGHUP. Prima di uscire, una shell interattiva invia nuovamente il SIGHUP a tutti i lavori, in esecuzione o interrotti. I lavori interrotti vengono inviati SIGCONT per garantire che ricevano il SIGHUP. Per evitare che la shell invii il segnale a un particolare lavoro, dovrebbe essere rimosso dalla tabella dei lavori con l'integrato disown (vedi COMANDI INCORPORATI DELLA SHELL sotto) o contrassegnato per non ricevere SIGHUP usando disown -h.

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

Soluzione 2:

Verrà inviato SIGHUP nei miei test:

Shell1:

[[email protected]: ~] ssh localhost
[[email protected]: ~] perl -e sleep & 
[1] 1121
[[email protected]: ~] 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

Ancora Shell1:

[[email protected]: ~] exit
zsh: you have running jobs.
[[email protected]: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.

Ancora Shell2 :

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

Perché funziona ancora?:
La programmazione avanzata nell'ambiente Unix di Stevens copre questo argomento nella sezione 9.10:Gruppi di processi orfani. La sezione più rilevante è:

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

Ciò fa sì che il figlio venga continuato, dopo aver elaborato il segnale di riaggancio. L'azione predefinita per il segnale di riaggancio è 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.

Soluzione 3:

Ho eseguito alcuni test utilizzando CentOS 7.1 e bash. Nota che questo significa huponexit è off per impostazione predefinita ed è stato disattivato per la maggior parte dei miei test.

Hai bisogno di nohup quando inizi un lavoro in un terminale, perché se chiudi quel terminale senza uscire dalla shell in modo pulito , il terminale invia a bash il segnale SIGHUP alla shell, che poi lo invia a tutti i figli. Se esci dalla shell in modo pulito, il che significa che il lavoro deve essere già in background, quindi puoi digitare exit o premi Control-D al prompt dei comandi:nessun segnale di alcun tipo viene inviato al lavoro in background da bash.

Prova:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(chiudi 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

Avvialo in background nel Terminale 1:

Terminal 1

$ ./doit.sh &
[1] 22954

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

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

Uscita nel Terminal 3:

Terminal 3

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

Tuttavia, se esci da 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 figlia è già sparita. L'SIGINT , SIG_BLOCK e SIG_SETMASK che vedi sotto sono dovute al sleep nella shell.

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

Terminale 3, uscita

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

È interessante notare che ho impostato huponexit essere in linea con shopt -s huponexit; shopt (quest'ultimo ha effettuato la revisione), quindi ha eseguito l'ultimo test e ancora una volta bash non ha inviato alcun segnale al processo in background . Ancora PIÙ interessante, come abbiamo visto ha fatto bash invia il segnale al processo in background dopo averlo ricevuto da un terminale che si è chiuso in faccia. Sembra che huponexit non aveva alcun rapporto in un modo o nell'altro.

Spero che questo rimuova qualsiasi mistero o confusione riguardante almeno l'huppiness 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).

Appendice 1

Quando eseguo una shell come exec /bin/sh , quindi esegui lo script come /bin/sh ./doit.sh & , quindi esci dalla shell in modo pulito, non vengono inviati segnali al processo in background e continua a essere eseguito fino al completamento.

Appendice 2

Quando eseguo una shell come exec /bin/csh , quindi esegui lo script come /bin/sh ./doit.sh & , quindi esci dalla shell in modo pulito, non vengono inviati segnali al processo in background e continua a essere eseguito fino al completamento.


Linux
  1. La riga di comando si sovrascrive quando i comandi diventano troppo lunghi

  2. Come uccidere tutti i processi in background in zsh?

  3. Come ottenere errno quando epoll_wait restituisce EPOLLERR?

  4. Ottieni la media del carico escludendo i processi migliorati

  5. Quando viene cancellato /tmp?

Ricevi una notifica quando viene eseguita un'attività terminale

Come avviare automaticamente la sessione dello schermo su Linux durante l'accesso

Avvio automatico della sessione Tmux sul sistema remoto quando si accede tramite SSH

Esegui processi in background in Linux usando il comando Screen

Ricevo un errore quando provo ad aggiornare Youtube-dl in 18.04?

Come inviare processi in background su Linux