Um diese Frage zu beantworten, müssen Sie verstehen, wie Signale an einen Prozess gesendet werden und wie ein Prozess im Kernel vorhanden ist.
Jeder Prozess wird als task_struct
innerhalb des Kernels dargestellt (die Definition befindet sich in der sched.h
Header-Datei und beginnt hier ). Diese Struktur enthält Informationen über den Prozess. zum Beispiel die pid. Die wichtige Information befindet sich in Zeile 1566, in der das zugehörige Signal gespeichert ist. Dies wird nur eingestellt, wenn ein Signal an den Prozess gesendet wird.
Ein toter Prozess oder ein Zombie-Prozess hat noch eine task_struct
. Die Struktur bleibt bestehen, bis der übergeordnete Prozess (natürlich oder durch Adoption) wait()
nach dem Empfang aufgerufen hat SIGCHLD
, seinen untergeordneten Prozess zu ernten. Wenn ein Signal gesendet wird, signal_struct
wird das gesetzt. In diesem Fall spielt es keine Rolle, ob das Signal abfangbar ist oder nicht.
Signale werden jedes Mal ausgewertet, wenn der Prozess ausgeführt wird. Oder um genau zu sein, bevor der Prozess würde laufen. Der Prozess ist dann im TASK_RUNNING
Zustand. Der Kernel führt die schedule()
Routine aus, die den nächsten laufenden Prozess gemäß seinem Planungsalgorithmus bestimmt. Angenommen, dieser Prozess ist der nächste laufende Prozess, wird der Wert von signal_struct
ausgewertet, unabhängig davon, ob ein Wartesignal verarbeitet werden muss oder nicht. Wenn ein Signalhandler manuell definiert wird (über signal()
oder sigaction()
), wird die registrierte Funktion ausgeführt, wenn nicht die Standardaktion des Signals ausgeführt wird. Die Standardaktion hängt vom gesendeten Signal ab.
Beispielsweise SIGSTOP
ändert der Standardhandler des Signals den Status des aktuellen Prozesses in TASK_STOPPED
und wird dann ausgeführt schedule()
, um einen neuen auszuführenden Prozess auszuwählen. Hinweis, SIGSTOP
ist nicht fangbar (wie SIGKILL
), daher gibt es keine Möglichkeit, einen manuellen Signalhandler zu registrieren. Im Falle eines nicht abfangbaren Signals wird die Standardaktion immer ausgeführt.
Zu Ihrer Frage:
Ein nicht mehr funktionierender oder toter Prozess wird vom Scheduler nie wieder als in diesem TASK_RUNNING
Zustand befindlich eingestuft. Daher wird der Kernel niemals den Signalhandler (Standard oder definiert) für das entsprechende Signal ausführen, je nachdem, welches Signal es war. Daher exit_signal
wird das nie wieder eingestellt. Das Signal wird durch Einstellen des signal_struct
Eingangs task_struct
des Prozesses an den Prozess "geliefert" , aber es passiert nichts anderes, da der Prozess nie wieder ausgeführt wird. Es muss kein Code ausgeführt werden. Alles, was vom Prozess übrig bleibt, ist diese Prozessstruktur.
Wenn der übergeordnete Prozess jedoch seine untergeordneten Prozesse erntet wait()
, ist der Exit-Code, den er erhält, derjenige, als der Prozess "anfänglich" gestorben ist. Es spielt keine Rolle, ob ein Signal darauf wartet, verarbeitet zu werden.
kill
selbst 0 oder 1 zurück?Ein Zombie-Prozess ist im Grunde schon tot. Das einzige ist, dass noch niemand seinen Tod bestätigt hat, sodass er weiterhin einen Eintrag in der Prozesstabelle sowie einen Steuerblock belegt (die Struktur, die der Linux-Kernel für jeden Thread in der Aktivität beibehält). Andere Ressourcen wie obligatorische Sperren für Dateien, gemeinsam genutzte Speichersegmente, Semaphoren usw. werden zurückgefordert.
Sie können sie nicht signalisieren, da niemand auf dieses Signal reagieren kann. Selbst schwerwiegende Signale wie KILL sind nutzlos, da der Prozess seine Ausführung bereits beendet hat. Sie können es selbst versuchen:
Hier starte ich einen Prozess, der sich gabelt und schläft, bevor ich auf sein Kind warte. Das Kind schläft nur ein wenig. Sie können das Kind töten, wenn es schläft oder kurz nach dem Verlassen, um den Unterschied zu sehen:
quelle
ruby -e "loop while fork { exit! }"
... imgur.com/SoRXErm