Sehr spät in der Pre-2.4.0-Entwicklungsserie haben die Kernel-Entwickler noch eine neue Schnittstelle hinzugefügt, die eine eingeschränkte Kommunikation zwischen Modulen ermöglicht. Diese Schnittstelle erlaubt es Modulen, Strings zu registrieren, die auf interessante Daten verweisen und dann von anderen Modulen abgefragt werden können. Wir schauen uns diese Schnittstelle anhand einer Variante unserer Module master und slave kurz an.
Wir verwenden das gleiche master-Modul, führen aber ein neues slave-Modul namens inter ein. Alles, was inter macht, ist einen String und eine Funktion unter dem Namen ime_string verfügbar zu machen (ime steht dabei für "intermodule example"). Das gesamte Modul sieht folgendermaßen aus:
staticchar*string="intersays'HelloWorld'"; voidime_function(constchar*who) { printk(KERN_INFO"inter:ime_functioncalledby%s\n",who); } intime_init(void) { inter_module_register("ime_string",THIS_MODULE,string); inter_module_register("ime_function",THIS_MODULE,ime_function); return0; } voidime_cleanup(void) { inter_module_unregister("ime_string"); inter_module_unregister("ime_function"); } |
Dieser Code verwendet die Funktion inter_module_register, die folgenden Prototyp hat:
voidinter_module_register(constchar*string,structmodule*module, constvoid*data); |
string ist der String, den andere Module verwenden, um die Daten zu finden; module ist ein Zeiger auf das Modul, dem die Daten gehören; dies wird fast immer THIS_MODULE sein. data ist schließlich ein Zeiger auf die Daten, die bereitgestellt werden sollen. Beachten Sie die Verwendung eines const-Zeigers für die Daten; es wird hier angenommen, daß er nur zum Lesen exportiert wird. inter_module_register beschwert sich (über printk), wenn der angegebene string bereits registriert ist.
Wenn die Daten nicht mehr gemeinsam genutzt werden müssen, sollte das Modul zum Aufräumen inter_module_unregister aufrufen:
voidinter_module_unregister(constchar*string); |
Es werden zwei Funktionen exportiert, mit denen auf via inter_module_register bereitgestellte Daten zugegriffen werden kann:
Diese Funktion sucht den angegebenen string und gibt den zugehörigen Datenzeiger zurück. Wenn der String nicht registriert worden ist, wird NULL zurückgegeben.
Diese Funktion verhält sich wie inter_module_get, ruft aber zusätzlich request_module mit dem angegebenen module-Namen auf und versucht es dann noch einmal.
Beide Funktionen inkrementieren darüber hinaus auch den Verwendungszähler des Moduls, das die Daten registriert hat. Ein mit inter_module_get oder inter_module_get_request geholter Zeiger bleibt also gültig, bis der explizit freigegeben wird. Zumindest wird das Modul, das den Zeiger erzeugt hat, nicht entladen; es kann natürlich immer noch selbst etwas machen, was den Zeiger ungültig werden läßt.
Wenn Sie den Zeiger nicht mehr benötigen, müssen Sie ihn freigeben, damit der Verwendungszähler des anderen Moduls korrekt dekrementiert wird. Ein einfacher Aufruf von
voidinter_module_put(constchar*string); |
gibt den Zeiger frei, der danach nicht mehr verwendet werden sollte.
In unserem Beispiel-Modul master rufen wir inter_module_get_request auf, damit das Modul inter geladen wird, und holen uns die zwei Zeiger. Der String wird einfach ausgegeben, und der Funktionszeiger wird dazu verwendet, einen Funktionsaufruf von master nach inter auszuführen. Der zusätzliche Code in master sieht folgendermaßen aus:
staticconstchar*ime_string=NULL; staticvoidmaster_test_inter(); voidmaster_test_inter() { void(*ime_func)(); ime_string=inter_module_get_request("ime_string","inter"); if(ime_string) printk(KERN_INFO"master:gotime_string'%s'\n",ime_string); else printk(KERN_INFO"master:inter_module_getfailed"); ime_func=inter_module_get("ime_function"); if(ime_func){ (*ime_func)("master"); inter_module_put("ime_function"); } } voidmaster_cleanup_module(void) { if(ime_string) inter_module_put("ime_string"); } |
Beachten Sie, daß die Aufrufe von inter_module_put bis zum Abräumen des Moduls zurückgestellt werden. Damit bleibt der Verwendungszähler von inter (mindestens) 1, bis master entladen wird.
> > Es gibt einige weitere wissenswerte Details zur Verwendung der Funktionen zur Kommunikation zwischen Modulen. Zunächst einmal stehen diese auch in Kerneln zur Verfügung, die nicht für ladbare Module konfiguriert worden sind, so daß kein Haufen von #ifdef-Zeilen notwendig ist, um diesen Fall abzufangen. Der von diesen Funktionen aufgespannte Namensraum ist global; die Namen sollten also sorgfältig gewählt werden, um Konflikte zu vermeiden. Schließlich werden gemeinsam genutzte Daten in einer einfachen verketteten Liste gespeichert; die Performance wird in Mitleidenschaft gezogen, wenn viele Abfragen gestartet oder viele Strings gespeichert werden. Diese Funktion ist für eine gelegentliche Verwendung gedacht, nicht als allgemeines Verzeichnis-Subsystem.