Open Source im professionellen Einsatz

Kernel- und Treiberprogrammierung mit dem Kernel 2.6 - Folge 46

Kern-Technik

,

Das Notifier-Subsystem ist die Nachrichtenzentrale des Linux-Kernels. Nur wenig Code ist nötig, um Entwickler mit den neusten Informationen zu versorgen.

Linus Torvalds steht fest zu seinem monolithischen Betriebssystemkern. Auch wenn es sich per definitionem um einen großen Code-Klumpen handelt, ist das System in Wahrheit modular und aus vielen Quellcode-Häppchen aufgebaut. Um diese Modularität zu verwirklichen, durchwirken die Entwickler den Kern mit vielen Schnittstellen, etwa für die Integration von neuem Code, den Datenaustausch mit dem Userspace, das Ankoppeln von Hardware und Vereinbarungen darüber, wie sie Zeit verwalten. Eine der unberechtigterweise bisher wenig beachteten Schnittstellen, das Notifier-Subsystem, regelt das zentrale Informations- und Ereignismanagement.

Ähnlich einem RSS-Feed versorgt der Kernel seine Abonnenten, also Subsysteme des Kernels oder Gerätetreiber, mit Neuigkeiten, etwa über einen bevorstehenden Shutdown, das Ändern des Prozessortakts oder darüber, dass er ein Kommunikations-Interface hoch- oder runterfährt. Der Empfänger sichert daraufhin Daten, passt die Berechnung von Zeitdifferenzen an oder sucht alternative Wege zur Datenübertragung.

Bitte um Rückruf

Das Notifier-Subsystem stellt den generischen Mechanismus zur Verfügung, über den Provider Nachrichten, Informationen respektive Ereignisse publizieren und Konsumenten diese Informationen ereignisorientiert empfangen. Sobald der Provider eine Nachricht über das Notifier-Subsystem publiziert, ruft dieses beim Empfänger eine Callback-Funktion auf.

Technisch betrachtet haben die Entwickler das Notifier-Subsystem einfach realisiert (siehe Abbildung 1): Der Kernel verwaltet für jede Informationsquelle eine Liste, eine Notifier-Chain. In sie hängt er die Callback-Funktionen über definierte Routinen ein und aus.

Stellt der Provider einen zu publizierenden neuen Systemzustand fest, beginnt das Notifier-Subsystem damit, die Callback-Funktionen der Reihe nach aufzurufen. Dabei hat der Provider die Möglichkeit, dem Callback einen Nachrichtentyp (Kommando, Ereignis, Datentyp »int«) und eine Adresse (Datentyp »void *«) zu übergeben. Als Ergebnis erhält er ein Bitfeld, mit dem er sich über den erfolgreichen Ablauf oder eventuelle Fehler informiert. Der Empfänger darf auch per Returnwert darum bitten, noch in der Chain befindliche und bisher nicht aufgerufene Callbacks zu canceln.

Abbildung 1: Im Zentrum des Subsystems steht die Notifier-Chain, in der der Kernel Callback-Funktionen nach Priorität sortiert ablegt. Jeder Rückruf hat einen der vier Typen »raw«, »atomic«, »blocking« oder »srcu«.

Abbildung 1: Im Zentrum des Subsystems steht die Notifier-Chain, in der der Kernel Callback-Funktionen nach Priorität sortiert ablegt. Jeder Rückruf hat einen der vier Typen »raw«, »atomic«, »blocking« oder »srcu«.

Quartett der Ketten

Die Situation verkompliziert, dass Kernelcode in verschiedenen Kontexten abläuft. Code auf Kernelebene darf dynamisch Speicher anfordern und sich beispielsweise schlafen legen. Auf der Ebene von Soft-IRQs und in Interrupt-Handlern ist das nicht erlaubt (siehe Abbildung 2). Die Konsequenz: Code, der dort abläuft, darf kritische Abschnitte keinesfalls über Semaphore schützen, da sie wartende Instanzen schlafen legen. Folglich könnten unterschiedliche Kontexte die Funktion zum Ein- und auch zum Aushängen einer Callback-Funktion aufrufen.

Linux stellt dazu passend gleich vier Notifier-Chain-Typen zur Verfügung und überlässt es dem Programmierer, den für seine Aufgabe optimalen Typ auszuwählen. Neben der Raw-Variante, die einfach nur den Mechanismus zum Einhängen, zum Aushängen und zum Aufruf der Callback-Funktion zur Verfügung stellt, gibt es noch die Atomic-, die Blocking- und die SRCU-Notifier-Chain. Letzteres Synchronisationselement steht für den etwas sperrigen Namen Sleepable Read Copy Update.

Die letzten drei Verfahren bringen neben der Grundfunktionalität noch Schutzmechanismen für die kritischen Abschnitte mit. Kritisch ist dabei das Ein- und Aushängen einer neuen Callback-Funktion in die Notifier-Chain und schließlich das Abarbeiten der Rückrufe selbst. Technisch unterscheiden sich die Chain-Typen also dadurch, wie sie kritische Abschnitte schützen. Die Atomic-Variante verwendet als Schutzelement ein Spinlock, das parallele Abläufe mit Hilfe von Interruptsperren und aktiven Warteschleifen, dem so genannten Spinning, verhindert. Diese Variante hat nur wenig Overhead.

Jede Kernelfunktion darf die Funktionen »atomic_notifier_chain_register()« zum Ein- und »atomic_notifier_chain_unregister()« zum Aushängen aus jedem Kontext heraus aufrufen. Insbesondere ist das auch aus einer Interrupt-Service-Routine (ISR) oder einem Tasklet heraus erlaubt. Tabelle 1 beschreibt die erlaubten Aufrufe des Notifier-Subsystems.

Tabelle 1: Funktionen
des Notifier-Subsystems

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook