Qu'est-ce qui détermine exactement si une tâche en arrière-plan est supprimée lorsque le shell est fermé ou supprimé?

12

Cette question est venu tout à fait un beaucoup ( vraiment beaucoup ), mais je trouve que les réponses sont généralement incomplètes. La question générale est "Pourquoi mon travail est-il / n'est-il pas tué lorsque je quitte / tue ssh?", Et voici ce que j'ai trouvé. La première question est: dans quelle mesure les informations suivantes sont-elles générales? Ce qui suit semble être vrai pour le linux Debian moderne, mais il me manque quelques bits; et que doivent savoir les autres?

  1. Tous les processus enfants, en arrière-plan ou non d'un shell ouvert sur une connexion ssh sont supprimés avec SIGHUP lorsque la connexion ssh est fermée uniquement si l' huponexitoption est définie: exécutez shopt huponexitpour voir si cela est vrai.

  2. Si huponexitc'est vrai, vous pouvez utiliser nohupou disownpour dissocier le processus du shell afin qu'il ne soit pas tué lorsque vous quittez. Ou exécutez des choses avec screen.

  3. Si huponexitfalse, qui est la valeur par défaut sur au moins certains linux ces jours-ci, les travaux en arrière-plan ne seront pas supprimés lors de la déconnexion normale.

  4. Mais même si la valeur huponexitest fausse, alors si la connexion ssh est interrompue ou tombe (différente de la déconnexion normale), les processus en arrière-plan seront toujours supprimés. Cela peut être évité par disownou nohupcomme dans (2).

  5. Il existe une certaine distinction entre (a) les processus dont le processus parent est le terminal et (b) les processus qui ont stdin, stdout ou stderr connectés au terminal . Je ne sais pas ce qui arrive aux processus qui sont (a) et non (b), ou vice versa.

Dernière question: comment éviter les comportements (3)? En d'autres termes, par défaut, dans les processus en arrière-plan Debian, ils se déroulent joyeusement par eux-mêmes après la déconnexion, mais pas après la fin de la connexion ssh. J'aimerais que la même chose se produise pour les processus, que la connexion soit fermée normalement ou interrompue. Ou est-ce une mauvaise idée?

Edit: Un autre moyen important de garder les emplois tués, qui fonctionne (?) Dans les deux cas est de les exécuter à travers l' écran . Mais, la question est plutôt de comprendre quand les choses sont tuées et quand elles ne le sont pas: parfois, les gens veulent que les emplois soient supprimés à la déconnexion, par exemple.

Plus de discussions: - Clarification sur les signaux (soupir), les travaux et le terminal de contrôle - /server/117152/do-background-processes-get-a-sighup-when-logging-off - Continuer SSH tâche / travaux en arrière-plan lors de la fermeture de SSH - Un travail mis en arrière-plan continuera-t-il à s'exécuter après la fermeture d'une session SSH? - Empêcher un processus d'arrière-plan déjà en cours d'exécution d'être arrêté après la fermeture du client SSH - Comment puis-je démarrer un processus via SSH de telle sorte qu'il continue à s'exécuter après ma déconnexion? - Impossible de maintenir le travail à distance en cours d'exécution sur OS X - Fermer la connexion SSH

petrelharp
la source

Réponses:

1

Un processus n'est pas "tué avec SIGHUP" - du moins, pas au sens strict du terme. Au contraire, lorsque la connexion est interrompue, le processus de contrôle du terminal (dans ce cas, Bash) reçoit un signal de raccrochage *, qui est généralement abrégé en "signal HUP", ou simplement SIGHUP.

Désormais, lorsqu'un processus reçoit un signal, il peut le gérer comme bon lui semble **. La valeur par défaut pour la plupart des signaux (y compris HUP) est de quitter immédiatement. Cependant, le programme est libre d'ignorer le signal à la place, ou même d'exécuter une sorte de fonction de gestionnaire de signal.

Bash choisit la dernière option. Son gestionnaire de signaux HUP vérifie si l'option "huponexit" est vraie et, dans l'affirmative, envoie SIGHUP à chacun de ses processus enfants. Ce n'est qu'une fois que c'est fini que Bash sort.

De même, chaque processus enfant est libre de faire ce qu'il veut quand il reçoit le signal: le laisser réglé sur la valeur par défaut (c'est-à-dire mourir immédiatement), l'ignorer ou exécuter un gestionnaire de signal.

Nohup modifie uniquement l'action par défaut pour le processus enfant sur "ignorer". Une fois que le processus enfant est en cours d'exécution, cependant, il est libre de modifier sa propre réponse au signal.

C'est, je pense, pourquoi certains programmes meurent même si vous les exécutez avec nohup:

  1. Nohup définit l'action par défaut sur "ignorer".
  2. Le programme doit effectuer une sorte de nettoyage à sa sortie, il installe donc un gestionnaire SIGHUP, écrasant par ailleurs l'indicateur "ignorer".
  3. Lorsque le SIGHUP arrive, le gestionnaire s'exécute, nettoie les fichiers de données du programme (ou tout ce qui devait être fait) et quitte le programme.
  4. L'utilisateur ne connaît pas ou ne se soucie pas du gestionnaire ou du nettoyage, et voit simplement que le programme s'est arrêté malgré nohup.

C'est là qu'intervient le "reniement". Un processus qui a été renié par Bash ne reçoit jamais le signal HUP, quelle que soit l'option huponexit. Ainsi, même si le programme configure son propre gestionnaire de signaux, le signal n'est jamais réellement envoyé, donc le gestionnaire ne s'exécute jamais. Notez cependant que si le programme essaie d'afficher du texte à un utilisateur déconnecté, il provoquera une erreur d'E / S, ce qui pourrait entraîner la fermeture du programme de toute façon.

* Et, oui, avant de demander, la terminologie de "raccrochage" est laissée par les jours du mainframe d'accès à distance d'UNIX.

** La plupart des signaux, de toute façon. SIGKILL, par exemple, provoque toujours l'arrêt immédiat du programme, point final.

HiddenWindshield
la source
2

Les points 1 à 4 sont corrects. Je ne sais rien du point 5. En ce qui concerne votre dernier point, une fine application, écran , vous permettra de laisser tous les processus s'exécuter à leur fin naturelle, quelle que soit la façon dont vous mettez fin à votre connexion. L'écran est dans les dépôts.

La description de l'écran par l'homme n'est pas facile à lire, mais elle indique entre autres:

Lorsque screen est appelé, il crée une fenêtre unique avec un shell (ou la commande spécifiée) puis s'écarte de votre chemin afin que vous puissiez utiliser le programme comme vous le feriez normalement. Ensuite, à tout moment, vous pouvez créer de nouvelles fenêtres (plein écran) avec d'autres programmes (y compris plus de shells), tuer les fenêtres existantes, afficher une liste de fenêtres, activer et désactiver la journalisation de la sortie, copier-coller du texte entre les fenêtres, afficher l'historique de défilement, basculer entre les fenêtres comme vous le souhaitez, etc. Toutes les fenêtres exécutent leurs programmes indépendamment les unes des autres. Les programmes continuent de s'exécuter lorsque leur fenêtre n'est actuellement pas visible et même lorsque la session d'écran entière est détachée du terminal de l'utilisateur. Lorsqu'un programme se termine, screen (par défaut) tue la fenêtre qui le contenait. Si cette fenêtre était au premier plan, l'affichage passe à la fenêtre précédente; s'il n'en reste plus, l'écran se ferme.

J'ai mis en évidence la partie la plus importante: vous pouvez détacher la fenêtre avec la commande Ctrl + a + d, puis vous pouvez tuer / déconnecter votre session, et la fenêtre maintenant détachée continuera à vivre, avec les programmes à l'intérieur toujours en cours d'exécution. Lorsque vous vous reconnectez, par exemple en lançant une nouvelle session ssh, la commande screen -r reprendra la session d'écran qui avait été détachée précédemment, avec toutes les sorties vers l'erreur standard / sortie clairement visibles.

MariusMatutiae
la source