Kann ein Prozess unter Linux vorübergehend eingefroren werden?

53

Ich habe mich gefragt, ob es eine Möglichkeit gibt, einen Prozess für eine bestimmte Zeitspanne einzufrieren.

Was ich meine ist, dass: Ist es für eine Anwendung (wahrscheinlich als Root ausgeführt) möglich, die Ausführung eines anderen bereits ausgeführten Prozesses (ein beliebiger Prozess, sowohl die GUI als auch die Befehlszeile) anzuhalten und später fortzusetzen? Mit anderen Worten, ich möchte nicht, dass bestimmte Prozesse für eine bestimmte Zeit vom Linux-Scheduler geplant werden.

Pal Szasz
quelle

Antworten:

81

Sehen Sie hier

Es gibt zwei Signale, die die Ausführung eines Prozesses unterbrechen können. Man ist "anmutig" und man ist "kraftvoll".

Die "anmutige" ist SIGTSTP, und ihr Zweck ist es, den Prozess "nett" zu bitten, die Ausführung auszusetzen, wenn es sich danach anfühlt, bis er ein A erhält SIGCONT. In diesem Fall SIGTSTPkann der Prozess SIGTSTP ignorieren und trotzdem weiter ausgeführt werden. Dies erfordert daher die Zusammenarbeit mit einem Programm, das für die Verarbeitung von SIGTSTP ausgelegt ist.

Die "erzwungene" ist SIGSTOP, und ihr Zweck ist es, alle User-Space-Threads, die mit diesem Prozess verbunden sind, anzuhalten. Es ist für den Prozess genauso unmöglich, zu ignorieren SIGSTOPwie für ihn zu ignorieren SIGKILL(letzterer beendet den Prozess mit Gewalt).

Um ein beliebiges Signal, einschließlich aller der hier genannten zu senden, können Sie Programme wie kill, killalloder pkill; oder verwenden Sie den Systemaufruf kill(2). In den Manpages Ihres Betriebssystems finden Sie plattform- / architektur- / versionsabhängige Details und Errata zu den oben genannten Themen. Beachten Sie, dass das Wort "kill" in all diesen Befehlen und dem syscall eine falsche Bezeichnung ist. Diese Befehle dienen nicht ausschließlich zum Beenden von Prozessen. Sie können das tun, indem sie bestimmte der Signale senden; Signale können jedoch auch für andere Funktionen als zum Beenden eines Prozesses verwendet werden. SIGSTOPHält zum Beispiel nur den Prozess an und es ist nur eines von mehreren Signalen, die auf diese Weise gesendet werden können.

Um eine Bedingung für die automatische Wiederaufnahme des Prozesses nach Ablauf einer bestimmten Zeitspanne hinzuzufügen, müssen Sie einen Überwachungsprozess verwenden, der noch ausgeführt wird und einen Timer festlegt, um den Überwachungsprozess zu aktivieren, der dann kill(2)erneut und erneut aufruft Sendet das SIGCONTSignal an den gestoppten Prozess, um den Kernel aufzufordern, die Ausführung fortzusetzen. Beachten Sie, dass Linux über mehrere Zeitsteuerungsmechanismen mit unterschiedlichen Genauigkeits- und Präzisionsgraden verfügt. Wenn Ihr System sehr ausgelastet ist, wird Ihr Überwachungsprozess möglicherweise erst aktiviert, wenn der Timer abgelaufen ist. Dies kann zu einer Verzögerung des Aufwachvorgangs führen.

Wenn Sie von einer sehr genauen Genauigkeit der Unterbrechung und der Wiederaufnahme des unterbrochenen Prozesses abhängen, müssen Sie möglicherweise Ihr Überwachungsprogramm mit Echtzeitberechtigungen ausführen ( Informationen dazu, wie Sie Ihren Prozess in Echtzeit ausführen, finden Sie in dieser Manpage auf sched_setscheduler(2)). Sie können auch hochauflösende Zeitgeber verwenden, eine Funktion des Linux-Kernels (die nur verfügbar ist, wenn Ihre Hardware sie unterstützt), und Echtzeit-Zeitplanung verwenden, um eine sehr genaue Zeitgabe mit einer Genauigkeit von weniger als einer Millisekunde zu erzielen Wecken und senden Sie das Signal, um den überwachten Prozess sehr schnell wieder aufzunehmen.

Sie haben nicht angegeben, mit welchen Technologien Sie dies implementieren möchten. Zumindest benötigen Sie mindestens Bash-Skripte, obwohl Sie auf diese Weise kein genaues Timing erhalten. Hier ist ein Bash "Skript" (ungetestet, also seien Sie vorsichtig), das nur ein Konzeptnachweis für Ihre Anfrage ist. Wenn Sie ein genaues Timing benötigen, müssen Sie ein Programm schreiben, wahrscheinlich in C / C ++ oder einer anderen Muttersprache, und Echtzeit-Zeitplanung und -Hrtimer verwenden.

#!/bin/bash
#This is the process you want to suspend.
screen -mdS child bash -c "cat /dev/urandom | base64"
#This is the process ID of the child process
THEPID=$(screen -list | grep child | cut -f1 -d'.' | sed 's/\W//g')
#Send SIGSTOP to the child process.
kill -SIGSTOP ${THEPID}
#Now it is suspended. This process will sleep for 10 seconds asynchronously, then resume the process.
screen -mdS monitor bash -c "sleep 10; kill -SIGCONT ${THEPID}"

Beachten Sie, dass das Skript beendet und das steuernde Skript beendet wird. Aufgrund der screenSteuerung des Überwachungsprozesses wird es jedoch 10 Sekunden lang im Hintergrund ausgeführt (basierend auf dem Argument, das an übergeben wurde sleep). Anschließend wird der untergeordnete Prozess aktiviert und fortgesetzt. Dies wird jedoch noch lange dauern, bis das Kontrollskript beendet ist. Wenn Sie synchron warten möchten, bis die Zeit abgelaufen ist, lassen Sie einfach den zweiten Aufruf aus, screenund codieren Sie den Ruhezustand und den Kill fest in das Kontrollskript.

Sie können testen, ob der Prozess tatsächlich angehalten wird, indem Sie ausführen

screen -rS child

Nachdem Sie dieses Skript gestartet haben. Auf der Konsole wird nichts angezeigt. Nachdem der Timer abgelaufen ist (10 Sekunden), wird Ihr Bildschirm mit Base64-Daten (zufällige Zeichen von 0-9 und AF) überflutet. Drücken Sie zum Beenden Strg + C.

allquixotic
quelle
Sehr gute, sehr vollständige Antwort, einschließlich PoC-Bash-Snippet. Nett!
fgysin
Wenn ein Prozess mitten in einer Netzwerksitzung wie einer TCP-Verbindung eingefroren wird und fortgesetzt wird, kann diese Netzwerksitzung dann beschädigt werden oder unterbrochen werden? Gibt es dafür ein definiertes Verhalten?
CMCDragonkai
@cmcdragonkai, da der angehaltene Prozess nicht ausgeführt werden kann und von keinem fd gelesen oder darauf geschrieben werden kann. Der Kernel überträgt jedoch so lange Bytes, bis sein Puffer in einer TCP-Sitzung voll ist, dh keine Übertragung zwischen Kernel- und Benutzerbereich. Einfrieren von Prozessen ist anders https://www.kernel.org/doc/Documentation/power/freezing-of-tasks.txt
Nizam Mohamed
Ich habe festgestellt, dass TCP-Verbindungen fortgesetzt werden können, nachdem der Prozess wieder in den Vordergrund gebracht wurde (Timeouts sind anwendungsspezifisch, es gibt TCP-Keepalive, aber auch Keepalive auf Anwendungsebene). Einfriervorgänge scheinen zu bedeuten, wenn sich der Computer im Ruhezustand oder im Energiesparmodus befindet. Ist das richtig?
CMCDragonkai
Dieses Skript hat keine Auswirkungen auf nicht kooperative Codes: gist.github.com/ceremcem/864dd94b52ffe7b18da29558df4f1f5b
feierlich
14

Ja, Sie können dies tun, indem Sie ein STOP- Signal an einen Prozess senden , um ihn anzuhalten , und anschließend ein CONT, um fortzufahren.

Verwendungszweck:

kill -STOP <pid>

kill -CONT <pid>

quelle
11

Wenn Sie eine entsprechend lockere Definition von "Einfrieren" haben, können Sie den reniceBefehl auschecken.

Mit Renice können Sie die Planungspriorität laufender Prozesse ändern.

Der normale Wert für "nice" für den Prozess ist 0. Wenn Sie den Wert für "nice" erhöhen, wird der Prozess besser, wie in "Warum gehen Sie nicht zuerst" beschrieben. Während das Verringern des netten Werts einen Prozess weniger schön macht, wie in "Geh mir aus dem Weg, ich habe es eilig". Der schöne Wertebereich liegt zwischen -20 und 19.

Jeder kann seine eigenen Prozesse verbessern. Nur root kann einen Prozess weniger schön machen oder die Prozessschönheit eines anderen Benutzers ändern.

Wenn Sie einen process-nice-Wert auf 19 setzen, wird er nur ausgeführt, wenn nichts anderes auf dem System gewünscht wird.

Hier ist ein Beispiel, das auf meiner lokalen Linux-Box ausgeführt wird.

Verwenden ps -lund Blick auf der NI - Säule ein Verfahren Nice - Wert zu sehen.

-> ps -l
FS UID PID PPID C PRI NI ADR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 75 0 - 16547 Wartepunkte / 0 Bash
0 T 29190 1105 402 0 75 0 - 23980 Endpunkte / 0 vim
0 R 29190 794 402 0 76 0 - 15874 - Pkt / 0 Ps

Wird renice +10der vim-Prozess ausgeführt, wird er mit einer niedrigeren Priorität ausgeführt.

-> renice +10 -p 1105
1105: alte Priorität 0, neue Priorität 10

-> ps -l
FS UID PID PPID C PRI NI ADR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 76 0 - 16547 Wartepunkte / 0 Bash
0 T 29190 1105 402 0 95 10 - 23980 Endpunkte / 0 vim
0 R 29190 1998 402 0 78 0 - 15874 - Pkt / 0 Ps

Unter der Annahme, dass Sie "Einfrieren" strecken können, um "niemanden im System stören" zu bedeuten, könnten Sie folgende Skripte erstellen:

renice 20 -p <pid of interest>
Schlaf <bestimmte Zeitspanne>
renice 0 -p <pid of interest>

(Denken Sie daran, es als root auszuführen).


beachte, dass ich mir mit der obigen ps -lAusgabe einige Freiheiten genommen habe , damit die interessanten Spalten in den kleinen blauen Kästchen gut zur Geltung kommen :)

Maurice
quelle