Beim Lesen der Manpages auf den read()
und write()
-Anrufen scheint es, dass diese Anrufe durch Signale unterbrochen werden, unabhängig davon, ob sie blockiert werden müssen oder nicht.
Insbesondere annehmen
- Ein Prozess erstellt einen Handler für ein Signal.
- Ein Gerät wird geöffnet (z. B. ein Terminal), wenn es
O_NONBLOCK
nicht eingestellt ist (dh im Sperrmodus arbeitet). - Der Prozess
read()
ruft dann das System auf, um vom Gerät zu lesen, und führt als Ergebnis einen Kernel-Steuerpfad im Kernel-Space aus. - Während der Vorgang
read()
im Kernel-Space ausgeführt wird, wird das Signal, für das der Handler zuvor installiert wurde, an diesen Prozess übergeben und sein Signal-Handler aufgerufen.
Wenn man die Manpages und die entsprechenden Abschnitte in SUSv3 'System Interfaces Volume (XSH)' liest , findet man Folgendes :
ich. Wird a read()
durch ein Signal unterbrochen, bevor es Daten liest (dh es musste blockieren, weil keine Daten verfügbar waren), gibt es -1 mit errno
dem Wert [EINTR] zurück.
ii. Wird a read()
durch ein Signal unterbrochen, nachdem es einige Daten erfolgreich gelesen hat (dh die Anforderung konnte sofort bearbeitet werden), wird die Anzahl der gelesenen Bytes zurückgegeben.
Frage A):
Geht ich zu Recht davon aus, dass in beiden Fällen (Block / kein Block) die Übermittlung und Bearbeitung des Signals für den Empfänger nicht vollständig transparent ist read()
?
Fall i. Dies erscheint verständlich, da durch das Blockieren read()
der Prozess normalerweise in den TASK_INTERRUPTIBLE
Status versetzt wird, sodass der Kernel den Prozess in den Status versetzt, wenn ein Signal übermittelt wird TASK_RUNNING
.
Wenn der read()
jedoch nicht blockieren muss (Fall ii.) Und die Anforderung im Kernelraum verarbeitet, hätte ich gedacht, dass das Eintreffen eines Signals und seine Behandlung ähnlich wie das Eintreffen und die ordnungsgemäße Behandlung einer Hardware transparent wäre unterbrechen würde. Insbesondere möchte ich , dass bei der Lieferung des Signals angenommen haben, würde der Prozess vorübergehend in platziert werden Benutzermodus sein Signal - Handler auszuführen , von dem sie schließlich die unterbrochene zu beenden zurückkehren würde die Verarbeitung read()
(im Kernel-Raum) , so dass das read()
läuft seine Natürlich bis zum Ende, danach kehrt der Prozess zu dem Punkt unmittelbar nach dem Aufruf von read()
(im Benutzerraum) zurück, wobei alle verfügbaren Bytes als Ergebnis gelesen werden.
Aber ii. scheint zu implizieren, dass das read()
unterbrochen wird, da Daten sofort verfügbar sind, aber nur einige der Daten (statt aller) zurückgeben.
Dies bringt mich zu meiner zweiten (und letzten) Frage:
Frage B):
Wenn meine Annahme unter A) richtig ist, warum wird das read()
unterbrochen, obwohl es nicht gesperrt werden muss, weil Daten verfügbar sind, um die Anforderung sofort zu erfüllen? Mit anderen Worten, warum wird der read()
Vorgang nach dem Ausführen des Signal-Handlers nicht fortgesetzt, was schließlich dazu führt, dass alle verfügbaren Daten (die schließlich verfügbar waren) zurückgegeben werden?
quelle
So beantworten Sie Frage A :
Ja, die Zustellung und Bearbeitung des Signals ist für den Empfänger nicht völlig transparent
read()
.Der
read()
Lauf auf halbem Weg belegt möglicherweise einige Ressourcen, während er durch das Signal unterbrochen wird. Und der Signal-Handler des Signals kann auch ein anderesread()
(oder ein beliebiges anderes sicheres Async-Signal-System ) aufrufen . Dasread()
durch das Signal unterbrochene Signal muss daher zuerst gestoppt werden, um die verwendeten Ressourcen freizugeben. Andernfalls greift derread()
vom Signalhandler auf die gleichen Ressourcen zu und verursacht wiedereintrittsbedingte Probleme.Weil andere Systemaufrufe als
read()
vom Signalhandler aufgerufen werden könnten und sie möglicherweise auch den gleichen Satz von Ressourcen belegen wie dies derread()
Fall ist. Um wiedereintretende Probleme zu vermeiden, ist es am einfachsten, die Unterbrechungread()
jedes Mal zu stoppen, wenn ein Signal während des Laufs auftritt.quelle