web-dev-qa-db-fra.com

Est-ce que Linux tue les processus d'arrière-plan si nous fermons le terminal à partir duquel il a démarré?

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:

  • Pourquoi un comportement indéfini pour le même type de processus?
  • De quoi il dépend?
  • Cela dépend-il de la version de Linux?
21
Chirag

Qui devrait tuer des emplois?

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.


Quand le noyau envoie-t-il SIGHUP?

Kernel envoie SIGHUP à processus de contrôle :

  • pour un vrai terminal (matériel): lorsqu'une déconnexion est détectée dans un pilote de terminal, par ex. sur raccrochage sur ligne modem;
  • pour pseudoterminal (pty): lorsque le dernier descripteur faisant référence au côté maître de pty est fermé, par ex. lorsque vous fermez la fenêtre du terminal.

Kernel envoie SIGHUP à d'autres groupes de processus:

  • à groupe de processus de premier plan, lorsque processus de contrôle se termine;
  • à groupe de processus orphelin , quand il devient orphelin et qu'il a arrêté les membres.

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:

  • le noyau envoie SIGHUP au Shell lorsque réel ou pseudoterminal est déconnecté/fermé;
  • le noyau envoie SIGHUP au groupe de processus de premier plan lorsque le shell se termine;
  • le noyau envoie 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é.


Quand bash envoie-t-il SIGHUP?

Bash envoie SIGHUP à tout jobs (premier plan et arrière-plan):

  • quand il reçoit SIGHUP, et qu'il s'agit d'un shell interactif (et contrôle des travaux le support est activé au moment de la compilation);
  • à sa sortie, il s'agit d'un shell de connexion interactif et l'option 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;
  • les processus ont commencé à utiliser Nohup ignoreSIGHUP.

Plus de détails ici .


Et les autres obus?

Habituellement, les shells se propagent SIGHUP. La génération de SIGHUP à la sortie normale est moins courante.


Telnet ou SSH

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

  1. le client est tué;
  2. le serveur détecte que la connexion client est fermée;
  3. le serveur ferme le côté maître de pty;
  4. le noyau détecte que le pty maître est fermé et envoie SIGHUP à bash;
  5. bash reçoit SIGHUP, envoie SIGHUP à tous les travaux et se termine;
  6. chaque travail reçoit SIGHUP et se termine.

Problème

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:

  1. normalement, bash reçoit SIGHUP et tue immédiatement les travaux en arrière-plan (comme prévu) et se termine;
  2. mais parfois, 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!


Solution

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


Pourquoi la course a-t-elle lieu?

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.


Référence

  • "Job Control" section dans le manuel officiel de Glibc.
  • Chapitre 34 "Groupes de processus, sessions et contrôle des travaux" du livre "L'interface de programmation Linux".
34
gavv

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:

Nohup

Lorsque vous exécutez un programme avec Nohup, il intercepte SIGHUP et redirige la sortie du programme.

$ Nohup app &

renier

disown indique à Shell de ne pas envoyer SIGHUP

$ app &
$ disown

Cela dépend-il de la version de Linux?

Cela dépend de votre Shell. Ci-dessus s'applique au moins pour bash.

5
pacholik

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;

4
deimus

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:

https://bugzilla.redhat.com/show_bug.cgi?id=8965

3
rkachach