Os processos em segundo plano obtêm um SIGHUP ao efetuar logoff?

20

Este é um acompanhamento para esta questão .

Eu fiz mais alguns testes; parece que realmente não importa se isso é feito no console físico ou via SSH, nem isso acontece apenas com o SCP; Eu também testei com cat /dev/zero > /dev/null . O comportamento é exatamente o mesmo:

  • Inicie um processo em segundo plano usando & (ou coloque-o em segundo plano depois de começar a usar CTRL-Z e bg ); isso é feito sem usar nohup .
  • Faça logoff.
  • Faça login novamente.
  • O processo ainda está lá, funcionando feliz e agora é um filho direto de init .

Posso confirmar se o SCP e o CAT são encerrados imediatamente se for enviado um SIGHUP ; Eu testei isso usando kill -HUP .

Então, realmente parece que SIGHUP não é enviado no logoff, pelo menos para processos em segundo plano (não é possível testar com um primeiro plano por razões óbvias).

Isso aconteceu comigo inicialmente com o console de serviço do VMware ESX 3.5 (que é baseado no RedHat), mas consegui replicá-lo exatamente no CentOS 5.4.

A pergunta é, novamente: um SIGHUP não deve ser enviado para processos, mesmo que estejam sendo executados em segundo plano, após o logoff? Por que isso não está acontecendo?

Editar

Eu verifiquei com strace , de acordo com a resposta de Kyle.
Como eu estava esperando, o processo não recebe nenhum sinal ao sair do shell onde foi lançado. Isso acontece quando se usa o console do servidor e via SSH.

    
por Massimo 26.02.2010 / 14:20

4 respostas

24

Resposta encontrada.

Para o BASH, isso depende da opção huponexit shell, que pode ser visualizada e / ou configurada usando o comando shopt integrado.

Parece que esta opção está desativada por padrão, pelo menos em sistemas baseados em RedHat.

Mais informações na página do manual do BASH :

The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP. To prevent the shell from sending the signal to a particular job, it should be removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to not receive SIGHUP using disown -h.

If the huponexit shell option has been set with shopt, bash sends a SIGHUP to all jobs when an interactive login shell exits.

    
por 26.02.2010 / 15:00
3

Será enviado SIGHUP nos meus testes:

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

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

Shell2 novamente :

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

Por que ainda funciona?:
Programação avançada no ambiente Unix por Stevens aborda isso na seção 9.10: Grupos de processos órfãos. A seção mais relevante é:

Since the process group is orphaned when the parent terminates, POSIX.1 requires that every process in the newly orphaned process group that is stopped (as our child is) be sent the hang-up signal (SIGHUP) followed by the continue signal (SIGCONT).

This causes the child to be continued, after processing the hang-up signal. The default action for the hang-up signal is to terminate the process, so we have to provide a signal handler to catch the signal. We therefore expect the printf in the sig_hup function to appear before the printf in the pr_ids function.

    
por 26.02.2010 / 14:30
1

Eu fiz alguns testes usando o CentOS 7.1 e o bash. Observe que isso significa huponexit is off por padrão e foi desativado na maioria dos meus testes.

Você precisa de nohup quando inicia um trabalho em um terminal, porque se você fechar esse terminal sem sair do shell corretamente , o terminal envia o sinal SIGHUP para o shell, que então envia para todas as crianças. Se você sair do shell de forma limpa, o trabalho já deve estar em segundo plano para que você possa digitar exit ou pressionar Control-D no prompt de comando - nenhum sinal de qualquer tipo será enviado para o job em segundo plano do bash.

Teste:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(terminal próximo 1, visto no 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 +++

Trabalho 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

Inicie em segundo plano no Terminal 1:

Terminal 1

$ ./doit.sh &
[1] 22954

Strace no Terminal 2; feche o Terminal 1 depois de alguns loops:

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

Saída no Terminal 3:

Terminal 3

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

No entanto, se você sair do bash , ele simplesmente sairá sem enviar nenhum sinal para a criança. O terminal sairá porque não tem mais um filho, mas é claro que não há ninguém para o HUP porque o shell filho já foi removido. Os SIGINT , SIG_BLOCK e SIG_SETMASK que você vê abaixo são devidos ao sleep no 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

Terminal 3, saída

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

Curiosamente, eu defino huponexit para estar com shopt -s huponexit; shopt (o último shopt para revisar), então executei o último teste e novamente bash não enviou nenhum sinal para o processo em segundo plano . Ainda mais interstingly, como vimos bash fez enviar o sinal para o processo de fundo depois que ele recebeu de um terminal que fechou em sua cara. Parece que huponexit não tinha um jeito ou outro.

Espero que isso elimine qualquer mistério ou confusão sobre pelo menos a besteira de bash, sobre quando e como o sinal HUP é enviado. Pelo menos meus testes foram completamente reproduzíveis para mim. Eu estaria interessado em saber se existem outras configurações que possam estar afetando o comportamento do bash.

E, como sempre, YSMV (seu shell pode variar).

Adendo 1

Quando executo um shell como exec /bin/sh , execute o script como /bin/sh ./doit.sh & e saia do shell sem problemas, nenhum sinal será enviado ao job em segundo plano e ele continuará a ser executado até a conclusão.

Adendo 2

Quando executo um shell como exec /bin/csh , execute o script como /bin/sh ./doit.sh & e saia do shell sem problemas, nenhum sinal será enviado ao job em segundo plano e ele continuará a ser executado até a conclusão.

    
por 21.10.2015 / 17:06
0

Eu uso o csh e os processos em segundo plano continuam sendo executados quando eu me desconecto.

    
por 26.02.2010 / 15:55