Ich verwende Ubuntu 14.04 und habe dieses Verhalten, das ich anscheinend nicht verstehen kann:
- Führen Sie den
yes
Befehl aus (in der Standard-Shell: Bash ) - Geben Sie ein, CtrlZum anzuhalten
yes
- Ausführen
jobs
. Ausgabe:
[1]+ Stopped yes
- Lauf
kill -9 %1
um anzuhaltenyes
. Ausgabe:
[1]+ Stopped yes
- Ausführen
jobs
. Ausgabe:
[1]+ Stopped yes
Dies ist unter Ubuntu, 3.16.0-30-generic
das in einer parallelen virtuellen Maschine ausgeführt wird.
Warum hat mein kill -9
Befehl den Befehl yes nicht beendet ? Ich dachte, SIGKILL kann nicht gefangen oder ignoriert werden? Und wie kann ich den Befehl yes beenden ?
shell
job-control
s1m0n
quelle
quelle
uname -a
) bitteLinux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
. Ich verwende Ubuntu in Parallels Desktop.(signal)
damit Sie den Unterschied erkennen können.Antworten:
Signale werden für angehaltene Prozesse blockiert. In einem Terminal:
In einem zweiten Terminal:
Im ersten Terminal:
Jedoch
SIGKILL
kann nicht gesperrt werden. Wenn Siekillall -9 yes
vom zweiten Terminal aus dasselbe tun, erhalten Sie dies sofort imyes
Terminal:Wenn
kill -9 %1
der Prozess nicht sofort beendetbash
wird, wird das Signal entweder erst dann gesendet, wenn Siefg
den Prozess abgeschlossen haben, oder Sie haben einen Fehler im Kernel entdeckt.quelle
SIGTSTP
(die blockierbare Version vonSIGSTOP
) an den aktiven Prozess gesendet . Dies versetzt den Prozess in einen eingefrorenen Zustand, in dem der Kernel ihn nicht plant.SIGCONT
Dies verhindert auch die Signalverarbeitung (mit Ausnahme des Signals, das den Prozess auftaut) und verhindert daher, dass der Prozess sofort abgebrochen wird.SIGTERM
ist blockiert, ist es aberSIGKILL
nicht. Wie auch immer, laut einem Kommentar von OP scheint das Problem darin zu bestehen, dassjobs
nicht erkannt wird, dass der Prozess gestorben ist, und nicht, dass der Prozess nicht von beendet wurdekill -9 %1
.SIGKILL
es nicht blockiert werden kann, gibt es keine Garantie dafür, dass es innerhalb einer sinnvollen Zeit geliefert wird. Wenn ein Prozess bis zum Blockieren von E / A angehalten wird, kommt er beispielsweiseSIGKILL
erst an, wenn der Prozess aktiviert ist. Dies kann möglicherweise niemals der Fall sein, wenn keine E / A auftreten.Keine Panik.
Es ist nichts Ungewöhnliches los. Hier gibt es keinen Kernel-Bug. Dies ist ein völlig normales Verhalten der Bourne Again-Shell und eines Multitasking-Betriebssystems.
Die Sache, an die man sich erinnern sollte, ist, dass sich ein Prozess selbst tötet , selbst als Reaktion darauf
SIGKILL
. Was hier passiert ist, dass die Bourne Again-Shell sich um Dinge kümmert, bevor der Prozess, den sie gerade gesagt hat, um sich selbst zu töten, dazu führt, sich selbst zu töten.Überlegen Sie, was ab dem Punkt passiert, an dem
yes
gestoppt wurdeSIGTSTP
und Sie denkill
Befehl gerade mit der Bourne Again-Shell ausgeführt haben:SIGKILL
an denyes
Prozess.yes
Prozess soll ausgeführt werden und beendet sich sofort von selbst.Der Grund, warum Sie eine Sache sehen und andere Menschen eine andere sehen, ist ein einfaches Rennen zwischen zwei betriebsbereiten Prozessen, deren Gewinner ganz auf Dinge zurückzuführen ist, die sowohl von Maschine zu Maschine als auch im Laufe der Zeit variieren. Die Systemlast macht einen Unterschied, ebenso wie die Tatsache, dass Ihre CPU virtuell ist.
Im interessanten Fall ist das Detail von Schritt 2 das Folgende:
kill
Befehls markiert es den Eintrag in seiner Jobtabelle als eine Benachrichtigung erforderlich, die am nächsten verfügbaren Punkt gedruckt wird.kill
Befehl wird beendet, und kurz vor dem erneuten Drucken der Eingabeaufforderung wird überprüft, ob Benachrichtigungsnachrichten zu Aufträgen gedruckt werden sollen.yes
Prozess hatte noch keine Chance, sich selbst zu töten. Was die Shell betrifft, befindet sich der Job immer noch im gestoppten Zustand. Daher druckt die Shell eine Jobstatuszeile "Gestoppt" für diesen Job und setzt das Flag "Benachrichtigung ausstehend" zurück.yes
Prozess wird geplant und tötet sich selbst.Die wichtigen Punkte sind:
SIGKILL
ist nicht magisch. Prozesse suchen nach ausstehenden Signalen, wenn sie vom Kernelmodus in den Anwendungsmodus zurückkehren. Dies geschieht am Ende von Seitenfehlern, (nicht verschachtelten) Interrupts und Systemaufrufen. Das einzig Besondere ist, dass der Kernel nicht zulässt, dass die Aktion als ReaktionSIGKILL
etwas anderes als sofortiger und bedingungsloser Selbstmord ist, ohne dass der Anwendungsmodus wiederhergestellt wird. Wichtig ist , müssen Prozesse sowohl Kernel-to-Application-Modus Übergänge werden zu machen und geplant werden , um zu reagieren auf Signale laufen.set -o notify
). Sie werden gedruckt, wenn die Shell als nächstes einen Punkt in ihrem Ausführungszyklus erreicht, an dem überprüft wird, ob Benachrichtigungen ausstehen.kill
und einmal vomSIGCHLD
Signalhandler. Dies bedeutet, dass zwei Nachrichten angezeigt werden können, wenn die Shell ausgeführt wird, bevor deryes
Prozess neu geplant wird, um sich selbst zu töten. eine Nachricht "Gestoppt" und eine Nachricht "Getötet"./bin/kill
Programm keinen Zugriff auf die interne Jobtabelle der Shell. Sie werden ein solches Verhalten also nicht sehen/bin/kill
. Das Flag für ausstehende Benachrichtigungen wird vomSIGCHLD
Handler nur einmal gesetzt .kill
denyes
Prozess von einer anderen Shell ausführen.quelle
jobs
und die Shell sieht den Prozess immer noch als lebendig an. Das wäre eine ungewöhnlich lange geplante Rennbedingung. :)jobs
ausführen, nachkill
denen alle immer noch anzeigen, dass der Prozess gerade gestoppt wurde. Sie haben mich jedoch dazu inspiriert, weiter zu experimentieren, und ich habe[1]+ Terminated yes
Folgendes entdeckt: Die Nachricht wird gedruckt, sobald ich einen anderen externen Befehl ausführe (keine eingebaute Shell wieecho
oderjobs
). So kann ichjobs
so viel laufen , wie ich möchte, und es wird weiter gedruckt[1]+ Stopped yes
. Aber sobald ichls
zum Beispiel[1]+ Terminated yes
jobs
nicht bemerkt wird, dass der Prozess tatsächlich gestorben ist ... Ich bin mir nicht sicher, was ich über die Aktualisierung des Status durch Ausführen eines anderen Befehls tun soll.Auf Ihrem System kann etwas Ungewöhnliches passieren. Bei mir funktioniert Ihr Rezept sowohl mit als auch ohne
-9
:Holen Sie sich die PID mit
jobs -p
und versuchen Sie es als zu tötenroot
.quelle
kill
geht der interne Befehl Ihrer Bash die Extrameile und prüft, ob der Job eingefroren ist (möglicherweise möchten Sie versuchen, die PID des Jobs herauszufinden und ihn mit zu beenden. Aufenv kill <pid>
diese Weise verwenden Sie den eigentlichenkill
Befehl und nicht die integrierte Bash.which kill /usr/bin/kill
which
ist kein Bash-Builtin,which <anything>
gibt Ihnen also immer den Pfad zum eigentlichen Befehl. Aber versuchen zu vergleichenkill --help
vs./usr/bin/kill --help
.kill
.Was Sie beobachten, ist ein Fehler in dieser Version von Bash.
kill -9 %1
tötet den Job sofort. Sie können das mit beobachtenps
. Sie können den Bash-Prozess verfolgen, um zu sehen, wann derkill
Systemaufruf aufgerufen wird, und den Unterprozess verfolgen, um zu sehen, wann er die Signale empfängt und verarbeitet. Interessanter ist, dass Sie sehen können, was mit dem Prozess passiert.In einem anderen Terminal:
Der Unterprozess ist ein Zombie . Es ist tot: Alles, was davon übrig bleibt, ist ein Eintrag in der Prozesstabelle (aber kein Speicher, Code, geöffnete Dateien usw.). Der Eintrag bleibt so lange bestehen, bis sein Elternteil es bemerkt und seinen Exit-Status durch Aufrufen des
wait
Systemaufrufs oder eines seiner Geschwister abruft .Eine interaktive Shell soll nach toten Kindern suchen und sie ernten, bevor eine Eingabeaufforderung gedruckt wird (sofern nicht anders konfiguriert). Diese Version von Bash funktioniert unter bestimmten Umständen nicht:
Es ist zu erwarten, dass bash "Killed" meldet, sobald die Eingabeaufforderung nach dem
kill
Befehl gedruckt wird. Dies ist jedoch nicht garantiert, da eine Racebedingung vorliegt. Signale werden asynchronkill
übermittelt : Der Systemaufruf kehrt zurück, sobald der Kernel herausgefunden hat, an welche Prozesse das Signal übermittelt werden soll, ohne darauf zu warten, dass es tatsächlich übermittelt wird. Es ist möglich, und es kommt in der Praxis vor, dass bash Zeit hat, den Status seines Unterprozesses zu überprüfen, festzustellen, dass er noch nicht tot ist (wait4
keinen Kindstod meldet), und zu drucken, dass der Prozess immer noch gestoppt ist. Was falsch ist, ist, dass vor der nächsten Eingabeaufforderung das Signal übermittelt wurde (ps
meldet, dass der Prozess beendet ist), Bash jedoch noch nicht aufgerufen wurdewait4
(Wir können das nicht nur sehen, weil der Job immer noch als "Gestoppt" gemeldet wird, sondern weil der Zombie immer noch in der Prozesstabelle vorhanden ist.) Tatsächlich erntet Bash den Zombie nur beim nächsten Aufrufwait4
, wenn er einen anderen externen Befehl ausführt.Der Fehler tritt nur sporadisch auf und ich konnte ihn nicht reproduzieren, während Bash verfolgt wird (vermutlich, weil es sich um eine Race-Bedingung handelt, bei der Bash schnell reagieren muss). Wenn das Signal vor Bash-Checks geliefert wird, geschieht alles wie erwartet.
quelle