2012-07-04 8 views
12

Einer der Linux-Kernel-Treiber, die ich entwickle, verwendet Netzwerkkommunikation im Kernel (sock_create(), sock->ops->bind(), usw.).Simulationseffekt von select() und poll() in Kernel-Socket-Programmierung

Das Problem ist, dass es mehrere Sockets geben wird, von denen Daten empfangen werden. Also brauche ich etwas, das eine select() oder poll() im Kernel-Raum simuliert. Da diese Funktionen Dateideskriptoren verwenden, kann ich die Systemaufrufe nicht verwenden, es sei denn, ich verwende die Systemaufrufe zum Erstellen der Sockets, aber das erscheint unnötig, da ich im Kernel arbeite.

Also dachte ich über die Umwicklung der Standard sock->sk_data_ready Handler in meinem eigenen Handler (custom_sk_data_ready()), die ein Semaphor entsperren würde. Dann kann ich meine eigene kernel_select() Funktion schreiben, die versucht, den Semaphor zu sperren und eine Blockierung wartet, bis sie geöffnet ist. Auf diese Weise geht die Kernelfunktion in den Ruhezustand, bis der Semaphor durch custom_sk_data_ready() entsperrt wird. Sobald kernel_select() die Sperre erhält, entsperrt es und ruft custom_sk_data_ready() auf, um es zu sperren. Die einzige zusätzliche Initialisierung besteht darin, custom_sk_data_ready() vor dem Binden eines Sockets auszuführen, sodass der erste Aufruf an custom_select() nicht fälschlicherweise ausgelöst wird.

Ich sehe ein mögliches Problem. Wenn mehrere empfangen werden, werden mehrere Aufrufe an custom_sk_data_ready() versuchen, den Semaphor zu entsperren. Um die Mehrfachaufrufe nicht zu verlieren und den verwendeten sock zu verfolgen, muss es eine Tabelle oder eine Liste von Zeigern zu den verwendeten Sockets geben. Und custom_sk_data_ready() muss in der Tabelle/Liste markieren, an welchem ​​Socket es übergeben wurde.

Klingt diese Methode? Oder sollte ich gerade mit dem Problem des Benutzer-/Kernel-Platzes kämpfen, wenn ich die Standard-Systemaufrufe verwende?

Ausgangsbefund:

Alle Callback-Funktionen in der sock Struktur wird in einem Interrupt-Kontext genannt. Das bedeutet, dass sie nicht schlafen können. Damit der Haupt-Kernel-Thread in einer Liste von Ready-Sockets schlafen kann, werden Mutexe verwendet, aber die custom_sk_data_ready() muss sich wie ein Spinlock auf den Mutexen verhalten (wiederholt mutex_trylock() aufrufen). Dies bedeutet auch, dass jede dynamische Zuweisung das Flag GFP_ATOMIC verwenden muss.


Weitere Möglichkeit:

Für jede offene Steckdose ersetzen jede sk_data_ready() die Buchse mit einer eigenen (custom_sk_data_ready()) und einen Arbeiter (struct work_struct) und Arbeitswarteschlange (struct workqueue_struct) erstellen. Eine gemeinsame process_msg() Funktion wird für jeden Arbeiter verwendet. Erstellen Sie eine globale Liste auf Kernel-Modul-Ebene, wobei jedes Listenelement einen Zeiger auf den Socket hat und die Worker-Struktur enthält. Wenn die Daten für einen Socket bereit sind, wird custom_sk_data_ready() ausgeführt und sucht nach dem übereinstimmenden Listenelement mit dem gleichen Socket. Rufen Sie dann queue_work() mit der Arbeitswarteschlange und dem Worker des Listenelements auf. Dann wird die process_msg()-Funktion aufgerufen und kann entweder das übereinstimmende Listenelement über den Inhalt des Parameters struct work_struct * (eine Adresse) finden oder das Makro container_of() verwenden, um die Adresse der Listenstruktur abzurufen, die die Worker-Struktur enthält.

Welche Technik ist am besten?

+0

Können Sie nicht ein User-Space-Hilfsprogramm haben, das die 'Umfrage' durchführt? Multiplex Input mit 'poll' oder' select' ist mit dem Scheduler verbunden (da der Pause-Prozess im Leerlauf ist, so dass andere Prozesse laufen können), werde ich das nicht innerhalb des Kernels tun! –

+1

@BasileStarynkevitch: Deshalb versuche ich nur die Schlafblockierung von 'poll()' und 'select()' zu simulieren. Die Verwendung dieser beiden Systemaufrufe vom Kernel ist ein letzter Ausweg. Ich vermute, dass es Probleme mit dem Ausführen von 'poll()' und 'select()' in einem User-Space-Helfer gibt. Der Helfer muss Zugriff auf einen Dateideskriptor haben (was nicht in "sock_create()" erfolgt) und möglicherweise Zugriff auf einen Socket im Kernelraum haben. Nun muss die Socket-Erstellung im User-Space-Helper erfolgen und das Modul muss den Socket basierend auf dem Deskriptor der Benutzer-Space-Datei finden. Jetzt wird es komplizierter. – Joshua

+0

Sie sollten nichts davon im Kernel machen. – mpe

Antwort

3

Ihre zweite Idee klingt mehr wie es funktionieren wird.

Der CEPH-Code sieht aus, als ob er etwas Ähnliches tut, siehe net/ceph/messenger.c.

Verwandte Themen