Pourquoi un zombie attend son enfant?

11

Je fouille dans différentes sources, mais je ne trouve pas une bonne description de l'anatomie de la récolte des enfants. Ceci est un cas simple de ce que je voudrais comprendre.

$ cat <( sleep 100 & wait ) &
[1] 14247
$ ps ax -O pgid | grep $$
12126 12126 S pts/17   00:00:00 bash
14248 12126 S pts/17   00:00:00 bash
14249 12126 S pts/17   00:00:00 sleep 100
14251 14250 S pts/17   00:00:00 grep --color=auto 12126
$ kill -2 14248

$ ps ax -O pgid | grep $$
12126 12126 S pts/17   00:00:00 bash
14248 12126 Z pts/17   00:00:00 [bash] <defunct>
14249 12126 S pts/17   00:00:00 sleep 100
14255 14254 S pts/17   00:00:00 grep --color=auto 12126

Pourquoi le zombie attend l'enfant?

Pouvez-vous expliquer celui-ci? Dois-je connaître C et lire le code source de Bash pour mieux comprendre cela ou existe-t-il une documentation? J'ai déjà consulté:

GNU bash, version 4.3.42 (1) -release (x86_64-pc-linux-gnu)

Linux 4.4.0-31-generic # 50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU / Linux


la source
2
Il faut noter que cela n'a vraiment rien à voir avec bash (à part le fait que si vous choisissez d'utiliser bash comme shell, beaucoup de processus seront démarrés par lui). D'autres shells (tcsh, ksh, zsh, & c) démarrent tous les processus et exécutent essentiellement les mêmes fonctions de système d'exploitation pour les gérer.
jamesqf
@jamesqf Intéressant. Si vous souhaitez développer votre commentaire en une réponse à part entière, ce serait formidable.
1
Sauf que ce n'est pas vraiment une réponse, soulignant simplement que vous avez cherché la réponse aux mauvais endroits :-) Tout bon livre sur la programmation de systèmes * nix devrait fournir une bien meilleure réponse que ce que je pourrais écrire.
jamesqf

Réponses:

17

Le zombie n'attend pas son enfant. Comme tout processus zombie, il reste jusqu'à ce que son parent le récupère.

Vous devez afficher tous les processus impliqués pour comprendre ce qui se passe et regarder également le PPID. Utilisez cette ligne de commande:

ps -t $(tty) -O ppid,pgid

Le parent du processus que vous tuez est cat. Ce qui se passe, c'est que bash exécute la commande d'arrière-plan cat <( sleep 100 & wait )dans un sous-shell. Étant donné que la seule chose que ce sous-shell fait est de configurer une redirection puis d'exécuter une commande externe, ce sous-shell est remplacé par la commande externe. Voici le récapitulatif:

  • Le bash d'origine (12126) appelle forkpour exécuter la commande d'arrière-plan cat <( sleep 100 & wait )dans un enfant (14247).
    • L'enfant (14247) appelle pipepour créer un canal, puis forkpour créer un enfant pour exécuter la substitution de processus sleep 100 & wait.
      • Le petit-fils (14248) appelle forkà s'exécuter sleep 100en arrière-plan. Étant donné que le petit-enfant n'est pas interactif, le processus d'arrière-plan ne s'exécute pas dans un groupe de processus distinct. Puis le petit-enfant attend sleepde sortir.
    • L'enfant (14247) appelle setpgid(c'est un travail d'arrière-plan dans un shell interactif donc il obtient son propre groupe de processus), puis il execves'exécute cat. (Je suis un peu surpris que la substitution de processus ne se produise pas dans le groupe de processus d'arrière-plan.)
  • Vous tuez le petit-enfant (14248). Son parent est en cours d'exécution cat, qui ne connaît aucun processus enfant et n'a aucun appel professionnel wait. Étant donné que le parent du petit-enfant ne le récolte pas, le petit-enfant reste comme un zombie.
  • Finalement, catquitte - soit parce que vous le tuez, soit parce que sleepretourne et ferme le tuyau afin de catvoir la fin de son entrée. À ce stade, le parent du zombie meurt, donc le zombie est récupéré par init et init le récolte.

Si vous changez la commande en

{ cat <( sleep 100 & wait ); echo done; } &

cats'exécute ensuite dans un processus distinct, et non dans l'enfant du processus bash d'origine: le premier enfant doit rester derrière pour s'exécuter echo done. Dans ce cas, si vous tuez le petit-enfant, il ne reste pas un zombie, car l'enfant (qui exécute toujours bash à ce moment-là) le récolte.

Voir aussi Comment Linux gère-t-il le processus zombie et Un zombie peut-il avoir des orphelins? Les enfants orphelins seront-ils dérangés en récoltant le zombie?

Gilles 'SO- arrête d'être méchant'
la source
J'ai également été surpris par le groupe de processus. Il semble que ce soit un bug et il est maintenant corrigé dans la branche bash master.
PSkocik
"Le bash d'origine attend son enfant (14247)." Pourquoi ou de quelle manière? L'enfant est censé s'exécuter en arrière-plan et il n'y a pas d'appel explicite. Quelle est la différence entre le bash d'origine (14246) en attente de 14247 et 14247 (qui est en cours d'exécution cat) n'attendant pas 14248 (en attente sleep)? Y a-t-il un souvenir de qui attend qui, que l'enfant (14247) a perdu et que le bash original (14246) n'a pas, ou peut-être une liste de signaux comme SIGCHLD qui devrait être appelé et 14247 (en cours d'exécution bash) désabonné avec en ce qui concerne 14248?
1
@tomas Je voulais dire que le bash d'origine fait appel waità son enfant, c'est-à-dire qu'il le récolte. Je peux voir comment cela serait déroutant, j'ai supprimé cette phrase qui n'était même pas au bon moment chronologiquement. L'information qu'un processus est mort va au parent de ce processus, un processus ne peut pas «s'abonner» pour recevoir des informations sur la mort d'un autre processus.
Gilles 'SO- arrête d'être méchant'
6

Zombie n'attend pas l'enfant. Au lieu de cela, zombie est le processus qui est déjà mort (par lui-même, ou a été tué - comme dans votre exemple), a eu son code, ses données et sa pile désalloués, et ne contient désormais que son code de sortie, en attendant que son parent appelle wait(2)pour le récupérer (et donc enfin nettoyer complètement l'entrée de processus de la table de processus)

Dans votre exemple, lorsque le sommeil se termine (ou est tué), le parent lira les états de sortie et récoltera les zombies. Voir ci-dessus wait(2)pour les détails.

Matija Nalis
la source