GNU/Linux >> Tutoriales Linux >  >> Linux

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

Solución 1:

Respuesta encontrada.

Para BASH, esto depende del huponexit opción de shell, que se puede ver y/o configurar usando el shopt incorporado comando.

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 man de BASH:

El shell sale de forma predeterminada al recibir un SIGHUP. Antes de salir, un shell interactivo vuelve a enviar el SIGHUP a todos los trabajos, en ejecución o detenidos. Los trabajos detenidos se envían SIGCONT para asegurarse de que reciben 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 disown incorporado (ver COMANDOS INTEGRADOS DEL SHELL a continuación) o marcarlo para que no reciba 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.

Solución 2:

Se enviará SIGHUP en mis pruebas:

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

Shell1 de nuevo:

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

Shell2 de nuevo :

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?:
Programación avanzada en el entorno Unix de Stevens cubre esto en la sección 9.10:Grupos de procesos huérfanos. Siendo la sección más relevante:

Dado que el grupo de procesos queda huérfano cuando el padre finaliza, POSIX.1 requiere que cada proceso del grupo de procesos recién huérfano que se detiene (como nuestro hijo) reciba la señal de colgar (SIGHUP) seguida de la señal de continuar (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 debemos 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.

Solución 3:

Realicé algunas pruebas con CentOS 7.1 y bash. Tenga en cuenta que esto significa huponexit es off de forma predeterminada, y estaba desactivado para la mayoría de mis pruebas.

Necesitas nohup cuando inicia un trabajo en una terminal, porque si cierra esa terminal sin salir del shell limpiamente , la terminal envía a bash la señal SIGHUP al 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 exit o presione Control-D en el símbolo del sistema; no se envían señales de ningún tipo al trabajo en segundo plano desde bash.

Prueba:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(cerrar terminal 1, visto en 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

Inícielo en segundo plano en la Terminal 1:

Terminal 1

$ ./doit.sh &
[1] 22954

Búscalo 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 Terminal 3:

Terminal 3

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

Sin embargo, si sale de bash , simplemente sale sin enviar ninguna señal al niño. La terminal se cerrará porque ya no tiene un elemento secundario, pero, por supuesto, no hay nadie para HUP porque el shell secundario ya no está. El SIGINT , SIG_BLOCK y SIG_SETMASK que ves a continuación se deben al sleep en la concha.

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, configuré huponexit estar con shopt -s huponexit; shopt (este último compró para revisar), luego realizó la última prueba y nuevamente bash no envió ninguna señal al proceso en segundo plano . Aún MÁS interesante, como hemos visto, bash did enviar la señal al proceso de fondo después de que la recibió de una terminal que se cerró en su cara. Parece que huponexit no tenía relación en un sentido ni en el otro.

Espero que esto elimine cualquier misterio o confusión con respecto al menos a la felicidad 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 alguna otra configuración que pueda estar afectando el comportamiento de bash.

Y, como siempre, YSMV (Your Shell May Vary).

Anexo 1

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

Anexo 2

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


Linux
  1. ¿Cómo obtener el ID de proceso del proceso en segundo plano?

  2. ¿Cómo eliminar todos los procesos en segundo plano en zsh?

  3. ¿Cómo obtener errno cuando epoll_wait devuelve EPOLLERR?

  4. ¿Por qué LXC cuando hay linux-vserver?

  5. Obtenga el promedio de carga excluyendo los procesos agradables

Recibir notificación cuando se realiza una tarea de terminal

Cómo iniciar automáticamente la sesión de pantalla en Linux al iniciar sesión

Inicio automático de la sesión de Tmux en el sistema remoto al iniciar sesión a través de SSH

Ejecute procesos en segundo plano en Linux usando el comando Pantalla

Cómo enviar procesos a segundo plano en Linux

¿Cómo asigna Linux el ancho de banda entre los procesos?