Nachkommen verarbeiten

20

Ich versuche einen Prozesscontainer zu bauen. Der Container löst andere Programme aus. Zum Beispiel - ein Bash-Skript, das ausgeführte Hintergrundaufgaben mit '&' startet.

Das wichtige Merkmal, nach dem ich mich sehne, ist folgendes: Wenn ich den Container töte, sollte alles, was unter ihm hervorgebracht wurde, getötet werden. Nicht nur direkte Kinder, sondern auch deren Nachkommen.

Als ich dieses Projekt gestartet habe, habe ich fälschlicherweise geglaubt, dass beim Töten eines Prozesses automatisch auch seine Kinder getötet wurden. Ich habe mich von Leuten beraten lassen, die die gleiche falsche Vorstellung hatten. Es ist zwar möglich, ein Signal zu empfangen und die Tötung an Kinder weiterzugeben, aber das ist nicht das, wonach ich hier suche.

Ich glaube, was ich erreichen möchte, denn wenn Sie ein xterm schließen, wird alles, was darin lief, getötet, es sei denn, es wurde nicht ausgeführt. Dies schließt verwaiste Prozesse ein. Das ist es, was ich neu erschaffen möchte.

Ich habe eine Idee, dass ich nach Unix-Sessions Ausschau halte.

Wenn es eine zuverlässige Möglichkeit gibt, alle Nachkommen eines Prozesses zu identifizieren, wäre es nützlich, ihnen auch beliebige Signale senden zu können. zB SIGUSR1.

Craig Turner
quelle
Wenn Sie den übergeordneten Prozess beenden SIGHUP, werden die Prozesse direkt an die untergeordneten Prozesse gesendet . Der Standard-Handler für das Auflegen-Signal bricht die Prozessausführung ab. Die Standardroute besteht also darin, alle Nachkommen zu töten. Lesen Sie mehr über Prozesse und Prozessgruppen.
Alex
Durch das Schließen des xterm wird alles getötet, was im xterm erzeugt wurde, da der TTY zerstört wird. Wenn Sie eine Möglichkeit finden, ein Tty zu erstellen, das von untergeordneten Prozessen verwendet werden kann, können Sie das TTY zerstören und dasselbe ausführen. Jeder Prozess, bei dem TTY (nohup & friends) nicht abgeschlossen wurde, erhält einen SIGHUP.
Patrick

Antworten:

23

Wenn Sie ein Signal an einen Prozess senden, wird dieser Prozess abgebrochen. Ich frage mich, wie das Gerücht entstanden ist, dass das Beenden eines Prozesses auch andere Prozesse tötet. Es scheint besonders kontraintuitiv zu sein.

Es gibt jedoch Möglichkeiten, mehr als einen Prozess zu beenden. Sie senden jedoch kein Signal an einen Prozess. Sie können eine ganze Prozessgruppe beenden, indem Sie ein Signal an -1234 senden, wobei 1234 die PGID (Prozessgruppen-ID) ist, die die PID des Prozessgruppenleiters ist. Wenn Sie eine Pipeline ausführen , beginnt die gesamte Pipeline als Prozessgruppe (die Anwendungen können dies durch Aufrufen von setpgidoder ändern setpgrp).

Wenn Sie Prozesse im Hintergrund starten ( foo &), befinden sie sich in einer eigenen Prozessgruppe. Prozessgruppen werden verwendet, um den Zugriff auf das Terminal zu verwalten. Normalerweise hat nur die Vordergrundprozessgruppe Zugriff auf das Terminal. Die Hintergrundjobs verbleiben in derselben Sitzung , aber es gibt keine Möglichkeit, eine ganze Sitzung abzubrechen oder die Prozessgruppen oder -prozesse in einer Sitzung aufzulisten, was nicht viel hilft.

Wenn Sie ein Terminal schließen, sendet der Kernel das Signal SIGHUPan alle Prozesse, die es als steuerndes Terminal haben . Diese Prozesse bilden eine Sitzung , aber nicht alle Sitzungen verfügen über ein steuerndes Terminal. Für Ihr Projekt besteht daher eine Möglichkeit darin, alle Prozesse in einem eigenen Terminal zu starten, das durch ein Skript , einen Bildschirm usw. erstellt wurde. Beenden Sie den Terminal-Emulator-Prozess, um die enthaltenen Prozesse zu beenden (vorausgesetzt, sie wurden nicht getrennt setsid).

Sie können für mehr Isolation sorgen, indem Sie die Prozesse als eigene Benutzer ausführen, die nichts anderes tun. Dann ist es einfach, alle Prozesse zu beenden: Führen Sie kill(den Systemaufruf oder das Dienstprogramm ) als diesen Benutzer aus und verwenden Sie -1 als das zu beendende PID-Argument, was "alle Prozesse dieses Benutzers" bedeutet.

Sie können noch mehr Isolation, aber erheblich mehr Setup bereitstellen, indem Sie die enthaltenen Prozesse in einem tatsächlichen Container ausführen .

Gilles 'SO - hör auf böse zu sein'
quelle
Wenn Sie Ihre eigenen Prozesse programmieren, können Sie Folgendes verwenden:,prctl(PR_SET_PDEATHSIG, SIGHUP); Weitere Informationen: man7.org/linux/man-pages/man2/prctl.2.html
Alexis Wilke
Gilles, Sie erwähnen dies - "Wenn Sie ein Terminal schließen, sendet der Kernel das Signal SIGHUP an alle Prozesse, die es als steuerndes Terminal haben". Von diesem mir das Terminal bin surmising SIGHUP an den Sitzungsleiter sendet (Shell) , die leitet sie an alle Prozessgruppen innerhalb der Sitzung. Welcher der beiden wäre richtig?
Iruvar
4

Im übergeordneten Skript wird das Kill-Signal abgefangen und alle Kinder getötet. Beispielsweise,

#!/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
quelle
2

Ein zuverlässiger Weg, um alle Nachfahren eines Prozesses zu identifizieren, ist die Verwendung des Befehls, pstree <pid>bei dem pid Ihre übergeordnete Prozess-ID ist.

Lesen Sie die man - Seite auf pstree hier .

So signalisieren Sie allen Mitgliedern einer Prozessgruppe: killpg(<pgrp>, <sig>);
Dabei ist pgrp die Prozessgruppennummer und sig das Signal.

So warten Sie auf Kinder in einer bestimmten Prozessgruppe: waitpid(-<pgrp>, &status, ...);

Alternativ dazu können Sie Ihren Prozesscontainer in einer neuen Bash-Shell ausführen. Erstellen Sie die neue Bash-Shell mit dem Befehl bashund führen Sie dann Ihre Prozesse aus. Wenn Sie möchten, dass alle Prozesse beendet werden, beenden Sie die Shell mit dem Befehl exit.

Chris Ting
quelle
Ich denke, mit killpg kann ich tun, was ich tun muss. Vielen Dank.
Craig Turner
1

Verwenden

unshare -fp --kill-child -- yourprogram

Wenn Sie beenden unshare, werden alle untergeordneten Prozesse (die yourprogrammöglicherweise gestartet wurden) beendet.

Dies ist jetzt mit util-linux möglich 2.32; Ich habe das Upstream implementiert . Es erfordert entweder Benutzernamensräume (Kernel-Konfigurationsoption CONFIG_USER_NS=y) oder Root-Rechte. Siehe auch hier .

nh2
quelle
0

Der Befehl rkill aus dem Paket pslist sendet ein bestimmtes Signal (oder SIGTERMstandardmäßig) an den angegebenen Prozess und alle seine Nachkommen:

rkill [-SIG] pid/name...
Nurjob
quelle
0

Eine weitere Option zum Töten aller Nachkommen der Shell: jobs -p | xargs -n 1 pkill -P

Doug Fawley
quelle