2010-05-05 6 views
8

In Linux, wenn Sie einen blockierenden E/A-Anruf wie lesen oder akzeptieren machen, was passiert eigentlich?Wie funktioniert Linux-blockierende E/A tatsächlich?

Meine Gedanken: der Prozess wird aus der Run-Warteschlange genommen, in einen Warte- oder Blockierungs-Zustand in einer Warteschlange gebracht. Wenn dann eine TCP-Verbindung hergestellt wird (zum Akzeptieren) oder die Festplatte bereit ist oder etwas für eine Datei gelesen wird, wird ein Hardware-Interrupt ausgelöst, der diese Prozesse warten lässt (im Falle eines Lesens einer Datei, wie Linux wissen, welche Prozesse zu wecken, da es viele Prozesse auf verschiedene Dateien warten könnte?). Oder vielleicht anstelle von Hardware-Interrupts, fragt der einzelne Prozess selbst nach Verfügbarkeit. Nicht sicher, Hilfe?

+0

Sie schlugen so ziemlich den Nagel auf den Kopf (mit Ausnahme der letzten Bemerkung, gibt es keine Abfrage, zum größten Teil). Das Multiplexen zwischen mehreren Kellnern und Dateien erfolgt durch den Kernel, der ein unsichtbarer Prozess ist, der solche Dinge im Auftrag aller anderen Prozesse koordiniert. –

Antwort

0

dies lesen: http://www.minix3.org/doc/

Es ist eine sehr klare, sehr leicht zu verstehen Erklärung. Dies gilt im Allgemeinen auch für Linux.

0

effectivly Die Methode wird nur zurückgegeben, wenn die Datei bereit ist, zu lesen, wenn Daten auf einem Sockel ist, wenn eine Verbindung angekommen ist ...

Um sicherzustellen, dass es sofort wollen zurückkehren können Sie wahrscheinlich die verwenden Select Systemaufruf, um einen fertigen Dateideskriptor zu finden.

11

Jedes Linux-Gerät scheint etwas anders umgesetzt werden, und die bevorzugte Art und Weise scheint veröffentlichen alle paar Linux zu variieren als sicherer/schnelle Kernel Features hinzugefügt werden, aber im Allgemeinen:

  1. Der Gerätetreiber erstellt lesen und Warteschlangen für ein Gerät schreiben.
  2. Jeder Prozessthread, der auf für E/A warten möchte, wird in die entsprechende Warteschlange eingereiht. Wenn ein Interrupt auftritt, weckt der Handler einen oder mehrere wartende Threads auf. (Offensichtlich laufen die Threads nicht sofort, da wir im Interrupt Context sind, sondern zur Kernel-Scheduling-Queue hinzugefügt werden).
  3. Wenn vom Kernel eingeplant, überprüft der Thread, ob die Bedingungen richtig sind, um fortzufahren - wenn nicht , geht es zurück in die Warteschlange.

Ein typisches Beispiel (etwas vereinfacht):

In den Fahrern bei der Initialisierung:

init_waitqueue_head(&readers_wait_q); 

In der Lesefunktion eines Treibers:

if (filp->f_flags & O_NONBLOCK) 
    { 
     return -EAGAIN; 
    } 
    if (wait_event_interruptible(&readers_wait_q, read_avail != 0)) 
    { 
     /* signal interrupted the wait, return */ 
     return -ERESTARTSYS; 
    } 
    to_copy = min(user_max_read, read_avail); 
    copy_to_user(user_buf, read_ptr, to_copy); 

Dann wird die Interrupt-Handler nur Ausgaben:

wake_up_interruptible(&readers_wait_q); 

Beachten Sie, dass wait_event_interruptible() ein Makro ist, das eine Schleife versteckt, die in diesem Fall nach einer Bedingung - read_avail != 0 - sucht und wiederholt zur Warteschlange hinzufügt, wenn die Bedingung nicht erfüllt ist.

Wie erwähnt, gibt es eine Reihe von Variationen - die wichtigste ist, dass, wenn es viel Arbeit für den Interrupt-Handler zu tun gibt, es das absolute Minimum selbst tut und den Rest zu einer Arbeitswarteschlange oder Tasklet (allgemein bekannt als die "untere Hälfte" und es ist dies, das die wartenden Fäden aufwecken würde.

Siehe Linux Device Driver Buch für weitere Details - pdf verfügbar hier: http://lwn.net/Kernel/LDD3

Verwandte Themen