J'ai un système embarqué, sur lequel je fais telnet
puis j'exécute une application en arrière-plan:
./app_name &
Maintenant, si je ferme mon terminal et fais telnet
à partir d'un autre terminal et si je vérifie, je peux voir que ce processus est toujours en cours d'exécution.
Pour vérifier cela, j'ai écrit un petit programme:
#include<stdio.h>
main()
{
while(1);
}
J'ai exécuté ce programme sur mon PC Linux local en arrière-plan et j'ai fermé le terminal.
Maintenant, lorsque j'ai vérifié ce processus à partir d'un autre terminal, j'ai constaté que ce processus avait également été tué.
Ma question est:
Normalement, les travaux de premier plan et d'arrière-plan sont supprimés par SIGHUP
envoyé par le noyau ou Shell dans différentes circonstances.
SIGHUP
? Kernel envoie SIGHUP
à processus de contrôle :
Kernel envoie SIGHUP
à d'autres groupes de processus:
Le processus de contrôle est le chef de session qui a établi la connexion avec le terminal de contrôle.
En règle générale, le processus de contrôle est votre Shell. Pour résumer:
SIGHUP
au Shell lorsque réel ou pseudoterminal est déconnecté/fermé;SIGHUP
au groupe de processus de premier plan lorsque le shell se termine;SIGHUP
au groupe de processus orphelin s'il contient des processus arrêtés.Notez que le noyau ne le fait pas envoie SIGHUP
au groupe de processus en arrière-plan s'il ne contient aucun processus arrêté.
bash
envoie-t-il SIGHUP
? Bash envoie SIGHUP
à tout jobs (premier plan et arrière-plan):
SIGHUP
, et qu'il s'agit d'un shell interactif (et contrôle des travaux le support est activé au moment de la compilation);huponexit
est définie (et la prise en charge job control est activée au moment de la compilation).Voir plus de détails ici .
Remarques:
bash
pas envoyer SIGHUP
aux travaux supprimés de la liste des travaux à l'aide de disown
;Nohup
ignoreSIGHUP
.Plus de détails ici .
Habituellement, les shells se propagent SIGHUP
. La génération de SIGHUP
à la sortie normale est moins courante.
Sous telnet ou SSH, ce qui suit devrait se produire lorsque la connexion est fermée (par exemple lorsque vous fermez la fenêtre telnet
sur PC):
SIGHUP
à bash
;bash
reçoit SIGHUP
, envoie SIGHUP
à tous les travaux et se termine;SIGHUP
et se termine.Je peux reproduire votre problème en utilisant bash
et telnetd
depuis busybox
ou dropbear
serveur SSH: parfois, le travail d'arrière-plan ne fonctionne pas ne reçoit pas SIGHUP
(et ne se termine pas) lorsque la connexion client est fermée.
Il semble qu'une condition de concurrence critique se produit lorsque le serveur (telnetd
ou dropbear
) ferme le côté maître de pty:
bash
reçoit SIGHUP
et tue immédiatement les travaux en arrière-plan (comme prévu) et se termine;bash
détecte EOF
du côté esclave de pty avant gérant SIGHUP
.Lorsque bash
détecte EOF
, il se termine immédiatement par défaut sans envoyer SIGHUP
. Et le travail d'arrière-plan continue de fonctionner!
Il est possible de configurer bash
pour envoyer SIGHUP
en sortie normale (y compris EOF
) aussi:
Assurez-vous que bash
est démarré en tant que shell de connexion. huponexit
fonctionne uniquement pour les shells de connexion, AFAIK.
Le shell de connexion est activé par -l
option ou trait d'union dans argv[0]
. Vous pouvez configurer telnetd
pour exécuter /bin/bash -l
ou mieux /bin/login
qui invoque /bin/sh
en mode shell de connexion.
Par exemple.:
telnetd -l /bin/login
Activez l'option huponexit
.
Par exemple.:
shopt -s huponexit
Tapez-le dans la session bash
à chaque fois ou ajoutez-le à .bashrc
ou /etc/profile
.
bash
débloque les signaux uniquement lorsqu'ils sont sûrs et les bloque lorsqu'une section de code ne peut pas être interrompue en toute sécurité par un gestionnaire de signaux.
Ces sections critiques invoquent points d'interruption de temps en temps, et si un signal est reçu lorsqu'une section critique est exécutée, son gestionnaire est retardé jusqu'au prochain point d'interruption. ou la section critique est quittée.
Vous pouvez commencer à creuser à partir de quit.h
dans le code source.
Ainsi, il semble que dans notre cas bash
reçoit parfois SIGHUP
quand il est dans une section critique. SIGHUP
l'exécution du gestionnaire est retardée et bash
lit EOF
et termine avant sortie de la section critique ou appel du prochain point d'interruption.
Lorsque vous fermez le terminal, Shell envoie SIGHUP
à tous les processus d'arrière-plan - et cela les tue. Cela peut être supprimé de plusieurs manières, notamment:
Lorsque vous exécutez un programme avec Nohup
, il intercepte SIGHUP
et redirige la sortie du programme.
$ Nohup app &
disown
indique à Shell de ne pas envoyer SIGHUP
$ app &
$ disown
Cela dépend de votre Shell. Ci-dessus s'applique au moins pour bash.
Pour bien comprendre ce qui se passe, vous devez vous familiariser un peu avec unix
internes.
Lorsque vous exécutez une commande comme celle-ci
./app_name &
Le app_name
est envoyé au groupe de processus d'arrière-plan. Vous pouvez vérifier les unix
groupes de processus ici
Lorsque vous fermez bash
avec une sortie normale, il déclenche SIGHUP
un signal de raccrochage pour toutes ses tâches. Certaines informations sur le contrôle de travail unix
sont ici .
Afin de maintenir votre application en cours d'exécution lorsque vous quittez bash
, vous devez immuniser votre application contre le signal de raccrochage avec l'utilitaire Nohup
.
Nohup - exécutez une commande à l'abri des blocages, avec sortie vers un non-tty
Et enfin, c'est ainsi que vous devez le faire.
Nohup app_name & 2> /dev/null;
AFAIK dans les deux cas, le processus doit être interrompu. Pour éviter cela, vous devez émettre un Nohup comme celui-ci:
> Nohup ./my_app &
De cette façon, votre processus continuera de s'exécuter. La partie telnet est probablement due à un BUG similaire à celui-ci: