terminal tombe en panne avec tous les enfants, même lorsque SIGKILLed, mais les processus normaux ne font pas la même chose

Je voudrais avoir le même effet dans mon programme que le bash (terminal) quand on le tue avec SIGKILL. Comme nous soaps que nous ne pouvons pas gérer SIGKILL dans nos programmes, chaque fois que je tue mon programme, ses enfants sont assignés à un processus init, il n’ya aucun moyen de le gérer pour tuer tous les processus enfants et tuer le parent lui-même. Bien que chaque fois que nous tuons un terminal, tous les processus créés par ce dernier sont détruits, même si SIGKILL tue notre terminal.

Pour cela, j’ai fait quelques recherches et trouvé le post ci-dessous: [ https://unix.stackexchange.com/questions/54963/how-can-terminal-emulators-kill-their-children-after-recieving-a-sigkill] [ 1]

Le post est un peu déroutant, mais ce que je suis sorti du post est que si le processus que vous tuez est le leader du processus du groupe de processus, tous ses enfants seront tués.

Donc, pour simplifier, j’ai implémenté le programme ci-dessous pour tester si c’est le cas:

int main() { printf("Curent PID: %u\n", getpid()); // make a new session pid_t pid = setsid(); printf("New session ID: %u\n", pid); pid = fork(); switch(pid) { case -1: perror("UNable to fork the process\n"); exit(EXIT_FAILURE); case 0: // child process while (1) { sleep(1); } break; } while (1) { printf("Process Leader running\n"); sleep(1); } return 0; } 

Après avoir exécuté le programme ci-dessus lorsque j’ai tué le processus parent, le processus enfant n’a pas été tué. J’ai également modifié le programme ci-dessus de sorte qu’il n’appartient à aucun tty, je pensais que le leader du processus ne devrait pas être associé à un tty. Je l’ai fait de la manière suivante:

Créer un processus normal (processus parent)

Créer un processus enfant à partir du processus parent ci-dessus

À ce stade, la hiérarchie des processus ressemble à ceci: TERMINAL -> PROCESSUS PARENT -> PROCESSUS ENFANT

Terminez le processus parent.

Le processus enfant devient maintenant orphelin et est pris en charge par le processus init.

Appelez la fonction setsid () pour exécuter le processus dans une nouvelle session et créer un nouveau groupe. alors le même code ci-dessus se répète.

Pourtant, quand j’ai tué le processus, les enfants leaders étaient là. Peut-être que je n’ai pas eu cet article sur unix.stackexchange ou est-ce le comportement de sourd de LINUX. Une façon que je peux implémenter pour que tous les enfants soient tués est d’attraper chaque SIGNAL DE TERMINAISON comme SIGTERM, SIGHUP etc. et de les écrire pour tuer l’enfant en premier. Mais je ne peux rien faire sur SIGKILL.

Je suis également intéressé de savoir que si tuer le processus parent n’affecte pas le processus enfant même si le parent est le leader du processus ou autre, alors comment bash (terminal) réussit à tuer tous les processus enfants même si nous lui envoyons SIGKILL. Y at-il une logique supplémentaire écrite pour les terminaux dans le kernel LINUX.

S’il y a un moyen de tuer tous les processus enfants lorsque le parent est tué, même en utilisant le signal SIGKILL, je serais heureux de le savoir aussi.

La page de manuel de kill dit:

Des valeurs PID négatives peuvent être utilisées pour choisir des groupes de processus entiers

Dans ma compréhension de tuer tout le groupe de processus, vous devez envoyer un PID négatif.

Un autre mécanisme fait que tuer un terminal tue ses processus enfants. Les processus exécutés à partir d’un terminal ont leur stdin / stdout attachée au terminal. Lors de la mise à mort du terminal, ces connexions sont fermées et un signal (SIG_HUP) est envoyé à ces processus. Un programme habituel ne gère pas ce signal et se termine par défaut.

Les conseils de Marian sont tout à fait corrects et méritent d’être étudiés, mais si vous choisissez de suivre cette voie, vous vous retrouverez probablement avec une mise en œuvre de ce que l’on pourrait appeler le «tour d’otage».

L’astuce consiste en un processus racine qui génère un processus enfant artificiel qui passe tout son temps à l’état arrêté. Cet “otage” sera généré immédiatement avant le premier processus enfant qui fait un vrai travail dans votre programme (multi-processus).

Le processus d’otage devient le leader de son propre groupe de processus et entre ensuite dans une boucle dans laquelle il s’arrête lui-même avec “raise (SIGSTOP)”. S’il est poursuivi, il vérifie si son parent est terminé (c’est-à-dire s’il a été redéfini ou s’il ne peut pas signaler son parent avec le signal nul (ESRCH)). Si le parent est terminé, alors l’otage doit se terminer, sinon il doit être suspendu à nouveau avec un autre “raise (SIGSTOP)”.

Vous devez faire attention aux conditions de course: par exemple, pour le test de re-parenting, veillez à mettre en cache l’identifiant parent-process pour l’otage comme valeur de retour de “getpid ()” avant “fork ()” faire aussi “setpgid ()” appelle en aval de “fork ()” dans parent et enfant. Vous devez alors considérer ce que vous faites si quelqu’un “tue (., SIGKILL)” est l’otage!

Il est vrai que vous pouvez placer un gestionnaire SIGCHLD dans le parent pour le réapparaître, mais cela nécessite un soin considérable pour préserver la continuité de l’identité du groupe de processus de l’otage; Peut-être y avait-il d’autres processus enfants au moment du SIGKILL et le remplacement de l’otage devait se faire dans le groupe de processus d’origine, peut-être qu’il n’y en avait pas et le groupe de processus d’origine s’est évaporé.

Même si vous avez raison, le fait que vous ayez mis un appel “fork ()” dans un gestionnaire pour un signal asynchrone (SIGCHLD) ouvrira probablement une autre boîte de vers si votre processus principal utilise plusieurs threads.

En raison de ces difficultés, je déconseille d’utiliser l’otage à moins que le processus fils n’exécute du code sur lequel vous n’avez aucun contrôle (et de réfléchir sérieusement aux coûts de complexité et de maintenabilité même à ce moment-là). Si vous contrôlez le code des processus enfants, il est beaucoup plus simple d’utiliser un “pipe ()”.

Vous créez le canal dans le processus parent et gérez les descripteurs de fichiers pour vous assurer que le processus parent est l’éditeur unique et que chaque processus enfant alloue un descripteur de fichier au côté lecture. Si vous faites cela, alors la terminaison du processus parent (que ce soit dû à SIGKILL ou à toute autre cause) est communiquée aux processus enfants par la condition EoF du côté lecture du canal lorsque le dernier écrivain se termine.

Si vous voulez traiter spécialement SIGKILL, vous pouvez utiliser un protocole sur le canal où le processus parent envoie un message de terminaison pour informer les enfants de son statut de terminaison sur toutes les terminaisons normales et sur les signaux fatals pouvant être capturés. parent a été tué par SIGKILL dans le cas où le côté lecture du canal délivre un EoF sans message de terminaison précédent.

Sur Linux prctl(PR_SET_PDEATHSIG … organisera un processus pour qu’il reçoive un signal lorsqu’il est mort, ce paramètre est conservé sur exec mais pas hérité par les processus enfants.