Tatsächlich gibt es drei Abstufungen bei Systemaufrufen.
- Einige Systemaufrufe kehren sofort zurück. "Sofort" bedeutet, dass sie nur ein wenig Prozessorzeit benötigen. Es gibt keine feste Grenze, wie lange sie dauern können (außer in Echtzeitsystemen ), aber diese Anrufe kehren zurück, sobald sie lange genug geplant wurden.
Diese Anrufe werden normalerweise als nicht blockierend bezeichnet . Beispiele für nicht-blockierende Anrufe sind Anrufe , die nur ein bisschen Systemzustand lesen, oder eine einfache Änderung des Systemstatus machen, wie getpid
, gettimeofday
, getuid
oder setuid
. Einige Systemaufrufe können je nach den Umständen blockierend oder nicht blockierend sein. read
Blockiert beispielsweise niemals, wenn die Datei eine Pipe oder ein anderer Typ ist, der nicht blockierende Lesevorgänge unterstützt und das O_NONBLOCK
Flag gesetzt ist.
- Es kann eine Weile dauern, bis einige Systemaufrufe abgeschlossen sind, aber nicht für immer. Ein typisches Beispiel ist
sleep
.
- Einige Systemaufrufe werden erst zurückgegeben, wenn ein externes Ereignis eintritt. Diese Anrufe sollen blockieren . Beispielsweise
read
blockiert ein aufgerufener Dateideskriptor, und das ist es auch wait
.
Die Unterscheidung zwischen "schnellen" und "langsamen" Systemaufrufen ist aus Sicht des Kernel-Implementierers nahezu nicht blockierend oder blockierend. Es ist bekannt, dass ein schneller Systemaufruf ausgeführt werden kann, ohne zu blockieren oder zu warten. Wenn der Kernel auf einen schnellen Systemaufruf stößt, weiß er, dass er den Systemaufruf sofort ausführen und den gleichen Vorgang einplanen kann. (In einigen Betriebssystemen mit nicht präemptivem Multitasking sind schnelle Systemaufrufe möglicherweise nicht präemptiv. Dies ist in normalen Unix-Systemen nicht der Fall.) Auf der anderen Seite muss bei einem langsamen Systemaufruf möglicherweise gewartet werden, bis eine andere Aufgabe abgeschlossen ist, also der Kernel muss sich darauf vorbereiten, den aufrufenden Prozess anzuhalten und eine andere Task auszuführen.
In einigen Fällen handelt es sich um eine Grauzone. Beispielsweise wird ein Festplattenlesevorgang ( read
aus einer regulären Datei) normalerweise als nicht blockierend angesehen, da er nicht auf einen anderen Prozess wartet. Es muss nur auf die Festplatte gewartet werden. Die Beantwortung dauert normalerweise nur ein wenig, dauert jedoch nicht ewig (so wie in Fall 2 oben). Aus Sicht des Kernels muss der Prozess jedoch warten, bis der Festplattentreiber vollständig ist, sodass es sich definitiv um einen langsamen Systemaufruf handelt.
Gilles 'SO - hör auf böse zu sein'
quelle
O_NONBLOCK
Flagge beides haben . Wenn das Flag gesetzt ist, kann der Systemaufruf abgeschlossen werden, ohne auf etwas anderes zu warten, sodass er nicht blockiert, und der Kernel kann ihn als schnellen Systemaufruf behandeln.Ein langsamer Systemaufruf ist so etwas wie ein TCP-Socket read () - wenn Sie O_ASYNC (oder was auch immer) nicht gesetzt haben, kann er ewig warten.
Ein schneller Systemaufruf ist so etwas wie gettimeofday () oder getpid (), die beide Informationen an den Prozess zurückgeben, den der Kernel sofort verfügbar hat.
Datenträgerlesevorgänge fallen in die Kategorie langsamer Systemaufrufe. Wenn ein Prozess read () für eine echte Festplattendatei oder einen Dateideskriptor ausführt, muss der Kernel möglicherweise einen oder mehrere Plattenblöcke einlesen, um den Lesevorgang durchzuführen. Abhängig von der On-Disk-Struktur des zugrunde liegenden Dateisystems kann dies bedeuten, den On-Disk-Inode zu lesen, um die Plattenblocknummer eines "indirekten Blocks" zu erhalten, den indirekten Block zu lesen, um den Datenblock zu erhalten, und dann den Datenblock selbst zu lesen . Ziemlich zeitaufwendig, zumindest in Bezug auf die CPU-Zyklen pro Plattenzugriff, wahrscheinlich heute schlechter als in der guten alten Zeit.
Ich habe das schon seit Ewigkeiten nicht mehr gesehen, aber die "untere Hälfte" des alten Unix-Laufwerk-Gerätetreibercodes blockierte Signale / Interrupts, so dass die Integrität des Dateisystems auf der Festplatte einfacher aufrecht erhalten werden konnte. Gelegentlich lieferte ein fehlerhafter Treiber oder eine fehlerhafte Festplatte niemals den Festplattenblock, den ein Prozess angefordert hatte, und der Prozess schlief für immer. Sogar ein Kill -9 hat nichts getan.
quelle