Descendants de processus

20

J'essaie de construire un conteneur de processus. Le conteneur déclenchera d'autres programmes. Par exemple - un script bash qui lance l'exécution de tâches en arrière-plan avec l'utilisation «&».

La caractéristique importante que je recherche est la suivante: lorsque je tue le conteneur, tout ce qui a été généré doit être tué. Pas seulement les enfants directs, mais aussi leurs descendants.

Quand j'ai commencé ce projet, j'ai cru à tort que lorsque vous tuiez un processus, ses enfants étaient automatiquement tués également. J'ai demandé conseil à des gens qui avaient la même idée incorrecte. Bien qu'il soit possible d'attraper un signal et de transmettre la mise à mort aux enfants, ce n'est pas ce que je recherche ici.

Je crois que ce que je veux être réalisable, car lorsque vous fermez un xterm, tout ce qui s'y déroulait est tué à moins qu'il ne soit rien. Cela inclut les processus orphelins. C'est ce que je cherche à recréer.

J'ai une idée que ce que je recherche concerne des sessions Unix.

S'il existait un moyen fiable d'identifier tous les descendants d'un processus, il serait utile de pouvoir également leur envoyer des signaux arbitraires. par exemple SIGUSR1.

Craig Turner
la source
Eh bien, tuer le processus parent envoie SIGHUPà ses processus enfants directs. Le gestionnaire par défaut du signal de raccrochage interrompt l'exécution du processus, donc la route par défaut est de tuer tous les descendants. En savoir plus sur les processus et les groupes de processus.
alex
La fermeture du xterm tue tout ce qui s'est produit dans le xterm parce que le TTY est détruit. Si vous pouvez trouver un moyen de créer un tty que les processus enfants peuvent utiliser, vous pouvez alors détruire le TTY et accomplir la même chose. Tout processus qui n'a pas fermé ce TTY (nohup & friends) obtiendra un SIGHUP.
Patrick

Réponses:

23

Si vous envoyez un signal à un processus, ce processus est tué. Je me demande comment la rumeur selon laquelle tuer un processus tue également d'autres processus a commencé, cela semble particulièrement contre-intuitif.

Il existe cependant des moyens de tuer plusieurs processus. Mais vous n'enverrez pas de signal à un processus. Vous pouvez tuer un groupe de processus entier en envoyant un signal à -1234 où 1234 est le PGID (ID de groupe de processus), qui est le PID du leader du groupe de processus. Lorsque vous exécutez un pipeline , l'ensemble du pipeline démarre en tant que groupe de processus (les applications peuvent changer cela en appelant setpgidou setpgrp).

Lorsque vous démarrez des processus en arrière-plan ( foo &), ils se trouvent dans leur propre groupe de processus. Les groupes de processus sont utilisés pour gérer l'accès au terminal; normalement, seul le groupe de processus de premier plan a accès au terminal. Les jobs d'arrière-plan restent dans la même session , mais il n'y a aucune possibilité de tuer une session entière ou même d'énumérer les groupes de processus ou les processus dans une session, donc cela n'aide pas beaucoup.

Lorsque vous fermez un terminal, le noyau envoie le signal SIGHUPà tous les processus qui l'ont comme terminal de contrôle . Ces processus forment une session , mais toutes les sessions n'ont pas de terminal de contrôle. Pour votre projet, une possibilité est donc de commencer tous les processus dans leur propre terminal, créé par le script , écran , etc. Tuer le processus d'émulation de terminal pour tuer les processus contenus ( en supposant qu'ils ont pas fait sécession avec setsid).

Vous pouvez fournir plus d'isolement en exécutant les processus en tant que leur propre utilisateur, qui ne fait rien d'autre. Ensuite, il est facile de tuer tous les processus: exécutez kill(l' appel système ou l' utilitaire ) en tant qu'utilisateur et utilisez -1 comme argument PID pour tuer, ce qui signifie «tous les processus de cet utilisateur».

Vous pouvez fournir encore plus d'isolement, mais avec beaucoup plus de configuration en exécutant les processus contenus dans un conteneur réel .

Gilles 'SO- arrête d'être méchant'
la source
Si vous programmez vos propres processus, vous pouvez utiliser quelque chose comme :,prctl(PR_SET_PDEATHSIG, SIGHUP); plus d'infos: man7.org/linux/man-pages/man2/prctl.2.html
Alexis Wilke
Gilles, vous mentionnez ceci - "Lorsque vous fermez un terminal, le noyau envoie le signal SIGHUP à tous les processus qui l'ont comme terminal de contrôle". À partir de cela, je suppose que le terminal envoie SIGHUP au chef de session (shell) qui le transmet à tous les groupes de processus de la session. Lequel des deux aurait raison?
iruvar
4

Dans le script parent, piègez le signal de mise à mort et faites-le tuer tous les enfants. Par exemple,

#!/bin/bash
# kill the parent and children together
trap "kill 0" EXIT
# create all the children
for n in $(seq 1 100)
do
    ( echo "begin $n"; sleep 60; echo "end $n" ) &
done
# wait for the children to complete
wait
Andrew Gilmartin
la source
2

Un moyen fiable d'identifier tous les descendants d'un processus consiste à utiliser la commande pstree <pid>où pid est l'ID de votre processus parent.

Lisez la page de manuel pstree ici .

Pour signaler tous les membres d'un groupe de processus: killpg(<pgrp>, <sig>);
où pgrp est le numéro du groupe de processus et sig est le signal.

Pour attendre des enfants dans un groupe de processus spécifié: waitpid(-<pgrp>, &status, ...);

Une alternative à ce que vous faites est d'exécuter votre conteneur de processus dans un nouveau shell bash. Créez le nouveau shell bash avec la commande bash, puis exécutez vos processus. Lorsque vous souhaitez terminer tous les processus, quittez le shell avec la commande exit.

Chris Ting
la source
Je pense que killpg me permettra de faire ce que je dois faire. Merci.
Craig Turner
1

Utilisation

unshare -fp --kill-child -- yourprogram

Si vous tuez unshare, tous les processus enfants (qui yourprogramont pu apparaître) seront tués.

C'est désormais possible avec util-linux 2.32; J'ai implémenté cela en amont . Il nécessite soit des espaces de noms utilisateur (option de configuration du noyau CONFIG_USER_NS=y), soit des privilèges root. Voir aussi ici .

nh2
la source
0

La commande rkill du package pslist envoie le signal donné (ou SIGTERMpar défaut) au processus spécifié et à tous ses descendants:

rkill [-SIG] pid/name...
Onlyjob
la source
0

Une autre option pour tuer tous les descendants du shell: jobs -p | xargs -n 1 pkill -P

Doug Fawley
la source