Les processus d'arrière-plan obtiennent-ils un SIGHUP lors de la déconnexion?

21

Ceci fait suite à cette question .

J'ai exécuté quelques tests supplémentaires; il semble que cela n'a pas vraiment d'importance si cela se fait sur la console physique ou via SSH, cela ne se produit pas uniquement avec SCP; Je l'ai également testé avec cat /dev/zero > /dev/null. Le comportement est exactement le même:

  • Démarrez un processus en arrière-plan en utilisant &(ou mettez-le en arrière-plan après qu'il a commencé à utiliser CTRL-Zet bg); cela se fait sans utilisernohup .
  • Se déconnecter.
  • Connectez-vous à nouveau.
  • Le processus est toujours là, se déroule joyeusement et est maintenant un enfant direct de init.

Je peux confirmer à la fois SCP et CAT quitte immédiatement si envoyé un SIGHUP; J'ai testé cela en utilisant kill -HUP.

Ainsi, il semble vraiment que SIGHUP ne soit pas envoyé à la déconnexion, du moins aux processus d'arrière-plan (ne peut pas tester avec un premier plan pour des raisons évidentes).

Cela m'est arrivé initialement avec la console de service de VMware ESX 3.5 (qui est basée sur RedHat), mais j'ai pu la répliquer exactement sur CentOS 5.4.

La question est, encore une fois: un SIGHUP ne devrait-il pas être envoyé aux processus, même s'ils s'exécutent en arrière-plan, lors de la déconnexion? Pourquoi cela ne se produit-il pas?


Éditer

J'ai vérifié avec strace, selon la réponse de Kyle.
Comme je m'y attendais, le processus ne reçoit aucun signal lors de la déconnexion du shell où il a été lancé. Cela se produit à la fois lors de l'utilisation de la console du serveur et via SSH.

Massimo
la source
En utilisant Bash sur CentOS 7.1, une simple boucle de script shell obtiendra un SIGHUP s'il est laissé au premier plan, mais le terminal est tué; strace d'un autre terminal montre: --- 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
Il en sera de même pour un script d'arrière-plan. Notez que le terminal est fermé pendant que la boucle attend un sommeil. Le shell n'est PAS sorti:--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=13944, si_uid=3000090} --- +++ killed by SIGHUP +++
Mike S
Voir ma réponse pour les tests. Fait intéressant, je n'ai vu aucun changement de comportement en raison de huponexit.
Mike S

Réponses:

26

Réponse trouvée.

Pour BASH, cela dépend de l' huponexitoption shell, qui peut être affichée et / ou définie à l'aide de la shoptcommande intégrée .

Il semble que cette option soit désactivée par défaut, au moins sur les systèmes basés sur RedHat.

Plus d'informations sur la page de manuel BASH :

Le shell se ferme par défaut à réception d'un SIGHUP. Avant de quitter, un shell interactif renvoie le SIGHUP à toutes les tâches, en cours d'exécution ou arrêtées. Les travaux arrêtés sont envoyés SIGCONT pour s'assurer qu'ils reçoivent le SIGHUP. Pour empêcher le shell d'envoyer le signal à une tâche particulière, il doit être supprimé de la table des tâches avec la commande intégrée désavoué (voir COMMANDES DE CONSTRUCTION D'INTERPRÉTEUR ci-dessous) ou marqué pour ne pas recevoir SIGHUP à l'aide de la commande disown -h.

Si l'option de shell huponexit a été définie avec shopt, bash envoie un SIGHUP à toutes les tâches lorsqu'un shell de connexion interactif se ferme.

Massimo
la source
4
Vérifié. Lorsque j'effectuais une «sortie», une «déconnexion» ou CTL-D, le processus enfant (travail) ne recevait pas de soupir (à la fois utilisateur root et utilisateur reg). Cependant quand j'ai fait "kill -HUP $$" pour tuer l'instance actuelle de bash, les processus enfants DID ont reçu un soupir. J'ai ensuite défini huponexit et le processus enfant a reçu SIGHUP à la sortie.
CarpeNoctem
3

Il sera envoyé SIGHUP dans mes tests:

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 à nouveau:

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

Shell2 à nouveau :

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

Pourquoi fonctionne-t-il toujours?:
Advanced Programing in the Unix Environment by Stevens couvre ceci dans la section 9.10: Orphaned Process Groups. La section la plus pertinente étant:

Étant donné que le groupe de processus est orphelin à la fin du parent, POSIX.1 requiert que chaque processus du groupe de processus nouvellement orphelin qui est arrêté (comme notre enfant) reçoive le signal de raccrochage (SIGHUP) suivi du signal de continuation (SIGCONT ).

Cela entraîne la poursuite de l'enfant, après avoir traité le signal de raccrochage. L'action par défaut pour le signal de raccrochage est de mettre fin au processus, nous devons donc fournir un gestionnaire de signal pour intercepter le signal. Nous nous attendons donc à ce que printf dans la fonction sig_hup apparaisse avant le printf dans la fonction pr_ids.

Kyle Brandt
la source
Mais vous lui avez explicitement envoyé un SIGHUP ici; Je parlais de ce qui se passe lorsque vous vous déconnectez du shell où vous avez commencé le processus.
Massimo
Même résultat lorsque je tape exit, bien que j'obtienne un avertissement concernant les travaux, mais que je tape à nouveau exit. J'ai testé cela avec ZSH.
Kyle Brandt
J'utilise BASH, et cela dépend probablement du shell. Mais BASH devrait envoyer SIGHUP aux processus enfants lors de la déconnexion ...
Massimo
Bash envoie SIGCONT apparemment si le travail est arrêté, mais je confirme qu'il n'envoie rien si le travail n'a pas été arrêté.
Kyle Brandt
En utilisant Bash sur CentOS 7.1, j'obtiens un SIGTERM envoyé à mon processus arrêté dans une autre fenêtre: 1.) Démarrer un script shell simple (boucle avec un écho et un sommeil), 2.) Control-Z it, 3) strace le processus dans une autre fenêtre, 4) quitter le terminal d'origine. Il se plaint que j'ai des travaux en cours, puis après avoir quitté mon strace montre: $ 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 +++ Odd, certainement pas en accord avec la section citée de Stevens.
Mike S
2

J'ai exécuté quelques tests en utilisant CentOS 7.1 et bash. Notez que ce moyen huponexitest offpar défaut, et était désactivé pour la majorité de mes tests.

Vous en avez besoin nohuplorsque vous démarrez un travail dans un terminal, car si vous fermez ce terminal sans quitter proprement le shell , le terminal envoie bash le signal SIGHUP au shell, qui l'envoie ensuite à tous les enfants. Si vous quittez le shell proprement - ce qui signifie que le travail doit déjà être en arrière-plan afin que vous puissiez taper exitou appuyer sur Control-D à l'invite de commande - aucun signal d'aucune sorte n'est envoyé au travail en arrière-plan à partir de bash.

Tester:

Terminal 1

$ echo $$
16779

Terminal 2

$ strace -e signal -p16779
Process 16779 attached

(fermer la borne 1, vue dans la borne 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 +++

Emploi 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

Démarrez-le en arrière-plan dans le terminal 1:

Terminal 1

$ ./doit.sh &
[1] 22954

Strace dans le Terminal 2; fermez le terminal 1 après quelques boucles:

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

Sortie dans le terminal 3:

Terminal 3

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

Cependant, si vous sortez bash, il se ferme simplement sans envoyer de signal à l'enfant. Le terminal se fermera car il n'a plus d'enfant, mais bien sûr il n'y a personne pour HUP car le shell enfant est déjà parti. Le SIGINT, SIG_BLOCKet SIG_SETMASKvous voyez ci-dessous sont dus à sleepla coquille.

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

Borne 3, sortie

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

Fait intéressant, je me suis mis huponexiten shopt -s huponexit; shoptroute avec (ce dernier shopt à revoir), puis j'ai effectué le dernier test, et encore bash n'a envoyé aucun signal au processus d'arrière-plan . Encore plus intéressant, comme nous l'avons vu, bash a envoyé le signal au processus d'arrière-plan après l'avoir reçu d'un terminal qui s'est fermé en face. Il semble que cela n'ait huponexiteu aucune incidence dans un sens ou dans l'autre.

J'espère que cela supprime tout mystère ou confusion concernant au moins la bêtise de bash, sur quand et comment le signal HUP est envoyé. Au moins, mes tests étaient complètement reproductibles, pour moi. Je serais intéressé de savoir s'il existe d'autres paramètres susceptibles d'affecter le comportement de bash.

Et, comme toujours, YSMV (Your Shell May Vary).

Addendum 1

Lorsque j'exécute un shell en tant que exec /bin/sh, puis exécute le script en tant que /bin/sh ./doit.sh &, puis quitte correctement le shell, aucun signal n'est envoyé au travail d'arrière-plan et il continue de s'exécuter jusqu'à la fin.

Addendum 2

Lorsque j'exécute un shell en tant que exec /bin/csh, puis exécute le script en tant que /bin/sh ./doit.sh &, puis quitte correctement le shell, aucun signal n'est envoyé au travail d'arrière-plan et il continue de s'exécuter jusqu'à la fin.

Mike S
la source
0

J'utilise csh et les processus d'arrière-plan continuent de fonctionner lorsque je me déconnecte.

Chris S
la source