Existe-t-il une variante UNIX sur laquelle un processus enfant meurt avec son parent?

41

J'étudie le comportement du noyau Linux depuis un certain temps déjà, et il m'est toujours apparu que:

Lorsqu'un processus meurt, tous ses enfants sont rendus au initprocessus (PID 1) jusqu'à leur mort.

Cependant, récemment, quelqu'un avec beaucoup plus d'expérience que moi avec le noyau m'a dit que:

Lorsqu'un processus se termine, tous ses enfants meurent également (à moins que vous ne l'utilisiez, NOHUPauquel cas ils sont renvoyés init).

Maintenant, même si je n'y crois pas, j'ai quand même écrit un programme simple pour m'en assurer. Je sais que je ne devrais pas compter sur time ( sleep) pour les tests car tout dépend de la planification du processus. Pourtant, pour ce cas simple, je pense que cela suffit assez.

int main(void){
    printf("Father process spawned (%d).\n", getpid());
    sleep(5);

    if(fork() == 0){
        printf("Child process spawned (%d => %d).\n", getppid(), getpid());
        sleep(15);
        printf("Child process exiting (%d => %d).\n", getppid(), getpid());
        exit(0);
    }

    sleep(5);
    printf(stdout, "Father process exiting (%d).\n", getpid());
    return EXIT_SUCCESS;
}

Voici la sortie du programme, avec le psrésultat associé à chaque fois printf:

$ ./test &
Father process spawned (435).

$ ps -ef | grep test
myuser    435    392   tty1    ./test

Child process spawned (435 => 436).

$ ps -ef | grep test
myuser    435    392   tty1    ./test
myuser    436    435   tty1    ./test

Father process exiting (435).

$ ps -ef | grep test
myuser    436    1     tty1    ./test

Child process exiting (436).

Maintenant, comme vous pouvez le constater, cela se comporte exactement comme je l'aurais prévu. Le processus orphelin (436) est rendu à init(1) jusqu'à sa mort.

Cependant, existe-t-il un système UNIX sur lequel ce comportement ne s'applique pas par défaut? Existe-t-il un système sur lequel la mort d'un processus déclenche immédiatement la mort de tous ses enfants?

John WH Smith
la source

Réponses:

68

Lorsqu'un processus se termine, tous ses enfants meurent également (sauf si vous utilisez NOHUP, auquel cas ils reviennent à init).

C'est faux. Mort faux. La personne qui a dit cela s’est trompée ou a confondu une situation particulière avec le cas général.

La mort d'un processus peut entraîner indirectement la mort de ses enfants de deux manières . Ils sont liés à ce qui se passe quand un terminal est fermé. Lorsqu'un terminal disparaît (historiquement parce que la ligne série a été coupée à cause d'un raccrochage du modem, de nos jours généralement parce que l'utilisateur a fermé la fenêtre de l'émulateur de terminal), un signal SIGHUP est envoyé au processus de contrôle exécuté dans ce terminal - généralement, le shell initial a démarré dans ce terminal. Les obus réagissent normalement à cela en sortant. Avant de quitter, les shells destinés à une utilisation interactive envoient HUP à chaque travail qu'ils ont commencé.

Commencer une tâche à partir d'un shell avec la nohupdeuxième source de signaux HUP interrompue, car la tâche ignorera alors le signal et ne sera donc pas invitée à mourir lorsque le terminal disparaîtra. Vous pouvez également interrompre la propagation des signaux HUP entre le shell et les travaux, en utilisant notamment le shell disownintégré du shell s'il en possède un (le travail est supprimé de la liste des travaux du shell) et le double fourchonnage (le shell lance un enfant qui lance un enfant). sort immédiatement (la coquille n’a pas connaissance de son petit-fils).

Encore une fois, les travaux démarrés dans le terminal ne meurent pas parce que leur processus parent (le shell) est mort, mais parce que leur processus parent décide de les tuer quand on leur dit de les tuer. Et le shell initial du terminal ne meurt pas parce que son processus parent meurt, mais parce que son terminal disparaît (ce qui peut être ou non une coïncidence si le terminal est fourni par un émulateur de terminal qui est le processus parent du shell).

Gilles, arrête de faire le mal
la source
1
Il y a une troisième façon, quelque chose avec les groupes de contrôle. Tout ce que je sais, c'est que systemd l'utilise pour imposer des tueries propres.
o11c
5
@JanHudec Je pense que vous confondez nohupavec disown. disownest un élément intégré dans un shell qui supprime un travail en cours de la table des jobs (en prenant un argument comme %1), et l’effet secondaire utile de cela est que le shell n’envoie pas de SIGHUP au sous-processus. nohupest un utilitaire externe qui ignore SIGHUP (et fait peu d’autres choses) puis lance la commande transmise sur sa ligne de commande.
Gilles 'SO- arrête d'être méchant'
@ Gilles: Non, je ne l’étais pas, mais regarder strace nohupignore en fait le signal avant que execla commande ne soit passée .
Jan Hudec
Merci pour votre réponse! J'ai particulièrement aimé le peu de contexte historique concernant les décrochages modernes. Je commençais à m'inquiéter d'avoir mal compris le noyau pendant tout ce temps ...
John WH Smith
3
Il convient également de noter qu'un programme se ferme lorsqu'il reçoit SIGHUP, car le gestionnaire de signaux par défaut pour SIGHUP doit se fermer. Mais tout programme peut implémenter son propre gestionnaire SIGHUP, ce qui peut l’empêcher de se fermer lorsque le shell parent lui envoie SIGHUP.
Slebetman
12

Lorsqu'un processus se termine, tous ses enfants meurent également (sauf si vous utilisez NOHUP, auquel cas ils reviennent à init).

Ceci est correct si le processus est un chef de session. Lorsqu'un responsable de session décède, un SIGHUP est envoyé à tous les membres de cette session. En pratique, cela signifie ses enfants et leurs descendants.

Un processus se fait chef de session en appelant setsid. Les coquilles utilisent cela.

Dennis
la source
Je viens de faire un test à ce sujet, mais je ne pouvais pas reproduire le comportement que vous décrivez ... J'ai créé un processus, lui ai donné une nouvelle session ( fork, kill processus processus, setsid) et ajouté un autre enfant à cette nouvelle session. Cependant, lorsque le processus parent (nouveau responsable de session) est décédé, l'enfant n'a reçu aucun SIGHUP et s'est attaché jusqu'à initce qu'il se termine.
John WH Smith
Depuis la setpgid(2)page de manuel: Si une session a un terminal de contrôle et que l'indicateur CLOCAL pour ce terminal n'est pas défini et qu'un blocage de terminal se produit, le leader de la session reçoit alors un SIGHUP. Si le responsable de la session quitte la session, un signal SIGHUP est également envoyé à chaque processus du groupe de processus au premier plan du terminal de contrôle.
Ninjalj
1
@ninjalj Ensuite, je suppose que cette réponse est valide si et seulement si le responsable de la session est également le processus de contrôle d'un terminal. Un animateur de session standard, indépendant de tout terminal, ne tuera pas ses enfants. Est-ce correct?
John WH Smith
-1

Donc, ce qui est dit sur les affiches, c'est que les enfants ne meurent pas, le parent les tue (ou leur envoie un signal sur lequel ils se terminent). Ainsi, vous pouvez obtenir ce que vous demandez, si vous programmez le parent pour (1) conserver un enregistrement de tous ses enfants et (2) envoyer un signal à tous ses enfants.

C’est ce que fait le shell et votre processus parent devrait le faire. Il peut être nécessaire d’attraper le signal HUP dans le parent afin de garder le contrôle nécessaire pour tuer les enfants.

marco
la source
Plusieurs causes peuvent faire mourir le parent. Il n'y a aucun moyen d'empêcher la survie des enfants si le parent est SIGKILLed, par exemple.
Emil Jeřábek soutient Monica
-1

Il me manque un élément dans les réponses qui est légèrement lié aux parents mourants: lorsqu'un processus écrit sur un tuyau pour lequel il n'y a plus de processus de lecture, il obtient un SIGPIPE. L'action standard pour SIGPIPE est la résiliation.

Cela peut en effet provoquer la mort des processus. En fait, il s’agit de la façon habituelle de yesmourir du programme .

Si j'exécute

(yes;echo $? >&2)|head -10

sur mon système, la réponse est

y
y
y
y
y
y
y
y
y
y
141

et 141 est en effet 128 + SIGPIPE:

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers

de man 7 signal.

utilisateur86542
la source
2
Mais le processus qui lit le tuyau n’est pas nécessairement (ni même habituellement) son parent. Il s’agit donc d’un cas très différent de celui que pose la question.
Barmar