¿Los procesos en segundo plano obtienen un SIGHUP al cerrar sesión?

21

Este es un seguimiento de esta pregunta .

He corrido algunas pruebas más; parece que realmente no importa si esto se hace en la consola física o a través de SSH, tampoco sucede esto solo con SCP; También lo probé con cat /dev/zero > /dev/null. El comportamiento es exactamente el mismo:

  • Inicie un proceso en segundo plano usando &(o póngalo en segundo plano después de que haya comenzado a usar CTRL-Zy bg); Esto se hace sin usarnohup .
  • Desconectarse.
  • Inicie sesión nuevamente.
  • El proceso todavía está allí, funcionando felizmente, y ahora es un hijo directo de init.

Puedo confirmar que SCP y CAT se cierren inmediatamente si se me envía un SIGHUP; Probé esto usando kill -HUP.

Entonces, realmente parece que SIGHUP no se envía al cerrar sesión, al menos a procesos en segundo plano (no se puede probar con uno en primer plano por razones obvias).

Esto me sucedió inicialmente con la consola de servicio de VMware ESX 3.5 (que se basa en RedHat), pero pude replicarlo exactamente en CentOS 5.4.

La pregunta es, nuevamente: ¿no debería enviarse un SIGHUP a los procesos, incluso si se ejecutan en segundo plano, al cerrar sesión? ¿Por qué esto no está sucediendo?


Editar

Lo comprobé strace, según la respuesta de Kyle.
Como esperaba, el proceso no recibe ninguna señal al cerrar sesión desde el shell donde se inició. Esto sucede tanto cuando se usa la consola del servidor como a través de SSH.

Massimo
fuente
Usando Bash en CentOS 7.1, un simple bucle de script de shell obtendrá un SIGHUP si se deja en primer plano, pero el terminal se apagó; strace de otra terminal muestra: --- 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
También lo hará un script de fondo. Tenga en cuenta que el terminal está cerrado mientras el bucle está esperando un sueño. La cáscara NO sale:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
Mike S
Ver mi respuesta para las pruebas. Curiosamente, no vi ningún cambio en el comportamiento debido a huponexit.
Mike S

Respuestas:

26

Respuesta encontrada.

Para BASH, esto depende de la huponexitopción de shell, que se puede ver y / o configurar con el shoptcomando incorporado .

Parece que esta opción está desactivada de forma predeterminada, al menos en los sistemas basados ​​en RedHat.

Más información en la página de manual de BASH :

El shell sale por defecto al recibir un SIGHUP. Antes de salir, un shell interactivo reenvía el SIGHUP a todos los trabajos, en ejecución o detenidos. Los trabajos detenidos se envían SIGCONT para garantizar que reciban el SIGHUP. Para evitar que el shell envíe la señal a un trabajo en particular, debe eliminarse de la tabla de trabajos con el mensaje desplegado incorporado (consulte COMANDOS DE CONSTRUIR SHELL a continuación) o marcado para no recibir SIGHUP usando disown -h.

Si la opción de shell huponexit se ha configurado con shopt, bash envía un SIGHUP a todos los trabajos cuando sale un shell de inicio de sesión interactivo.

Massimo
fuente
44
Verificado Cuando realicé una "salida", "cerrar sesión" o CTL-D, el proceso secundario (trabajo) no recibiría un suspiro (usuario root y usuario normal). Sin embargo, cuando hice "kill -HUP $$" para matar la instancia actual de bash, los procesos secundarios recibieron un suspiro. Luego configuré huponexit y el proceso secundario recibió SIGHUP al salir.
CarpeNoctem
3

Se enviará SIGHUP en mis pruebas:

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

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

Shell2 nuevamente :

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

¿Por qué sigue ejecutándose ?: La programación
avanzada en el entorno Unix de Stevens cubre esto en la sección 9.10: Grupos de procesos huérfanos. La sección más relevante es:

Dado que el grupo de procesos queda huérfano cuando el padre termina, POSIX.1 requiere que cada proceso en el grupo de proceso recién huérfano que se detiene (como nuestro hijo) se envíe la señal de colgar (SIGHUP) seguido de la señal de continuación (SIGCONT )

Esto hace que el niño continúe después de procesar la señal de colgar. La acción predeterminada para la señal de colgar es finalizar el proceso, por lo que tenemos que proporcionar un controlador de señal para captar la señal. Por lo tanto, esperamos que printf en la función sig_hup aparezca antes que printf en la función pr_ids.

Kyle Brandt
fuente
Pero explícitamente le enviaste un SIGHUP aquí; Estaba hablando de lo que sucede cuando cierra sesión en el shell donde inició el proceso.
Massimo
Los mismos resultados cuando escribo exit, aunque recibo una advertencia sobre los trabajos, pero luego escribo exit nuevamente. Probé esto con ZSH.
Kyle Brandt
Estoy usando BASH, y esto probablemente depende del shell. Pero BASH debería enviar SIGHUP a los procesos secundarios al cerrar sesión ...
Massimo
Bash aparentemente envía SIGCONT si se detiene el trabajo, pero confirmo que no envía nada si el trabajo no se detuvo.
Kyle Brandt
Usando Bash en CentOS 7.1, obtengo un SIGTERM enviado a mi proceso detenido en otra ventana: 1.) Iniciar un script de shell simple (bucle con un eco y un sueño), 2.) Control-Z it, 3) estratificar el proceso en otra ventana, 4) salga de la terminal original. Se queja de que tengo puestos de trabajo, luego, después de salir de mis shows de 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 +++ Extraño, definitivamente no de acuerdo con la sección citada de Stevens.
Mike S
2

Ejecuté algunas pruebas usando CentOS 7.1 y bash. Tenga en cuenta que esto significa que huponexites offpor defecto, y estaba apagado para la mayoría de mis pruebas.

Necesitas nohupcuando comienzas un trabajo en una terminal, porque si cierras esa terminal sin salir de la shell limpiamente , la terminal envía la señal SIGHUP a la shell, que luego la envía a todos los niños. Si sale del shell limpiamente, lo que significa que el trabajo ya debe estar en segundo plano para que pueda escribir exito presionar Control-D en el símbolo del sistema, no se envían señales de ningún tipo desde bash.

Prueba:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(cierre la terminal 1, vista en la 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 +++

Trabajo 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

Comience en segundo plano en la Terminal 1:

Terminal 1

$ ./doit.sh &
[1] 22954

Estérelo en la Terminal 2; cierre la Terminal 1 después de un par de bucles:

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

Salida en la Terminal 3:

Terminal 3

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

Sin embargo, si sale bash, simplemente sale sin enviar ninguna señal al niño. El terminal saldrá porque ya no tiene un hijo, pero, por supuesto, no hay nadie en HUP porque el shell hijo ya no está. El SIGINT, SIG_BLOCKy SIG_SETMASKves a continuación se deben a la sleepen el 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, salida

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

Curiosamente, me puse huponexita estar en con shopt -s huponexit; shopt(este último shopt a revisión), y luego realizó la última prueba, y de nuevo golpe envía ninguna señal al proceso en segundo plano . Aún más interstingly, como hemos visto fiesta hicimos enviar la señal al proceso en segundo plano después de que lo recibió de un terminal que cierra en su cara. Parece que huponexitno tenía nada que ver de una forma u otra.

Espero que esto elimine cualquier misterio o confusión sobre al menos la alegría de bash, sobre cuándo y cómo se envía la señal HUP. Al menos mis pruebas fueron completamente reproducibles, para mí. Me interesaría saber si hay otras configuraciones que puedan estar afectando el comportamiento de bash.

Y, como siempre, YSMV (su caparazón puede variar).

Anexo 1

Cuando ejecuto un shell como exec /bin/sh, luego ejecuto el script como /bin/sh ./doit.sh &, luego salgo del shell limpiamente, no se envían señales al trabajo en segundo plano y continúa ejecutándose hasta su finalización.

Anexo 2

Cuando ejecuto un shell como exec /bin/csh, luego ejecuto el script como /bin/sh ./doit.sh &, luego salgo del shell limpiamente, no se envían señales al trabajo en segundo plano y continúa ejecutándose hasta su finalización.

Mike S
fuente
0

Uso csh y los procesos en segundo plano continúan ejecutándose cuando finalizo la sesión.

Chris S
fuente