Monolithischer Kernel (kein
Mikrokernel, aber dynamisch nachladbare Module, z.B. für ein
selten benötigtes Dateisystem)
Der eigentliche Kern
stellt bei einem Mikrokernel nur das absolut notwendige Minimum an
Funktionalität (Prozesse, Interprozesskommunikation und
Speicherverwaltung) zur Verfügung und kann deswegen klein und
kompakt implementiert werden. Auf diesen Mikrokernel aufbauend, wird
die restliche Funktionalität des Betriebssystems in
eigenständige Prozesse ausgelagert, die mit dem Mikrokernel
über eine wohldefiniertre Schnittstelle kommunizieren. Der
große Vorteil dieser Architektur ist eine auf den ersten Blick
wartungsfreundliche Struktur des Systems. Einzelne Komponenten
arbeiten unabhängig voneinander, können sich nicht
ungewollt beeinflussen und sind leichter austauschbar. Die
Entwicklung neuer Komponenten wird vereinfacht. Daraus ergibt sich
auch ein Nachteil eines Mikrokernels, denn er erzwingt die
Einhaltung der definierten Schnittstellen zwischen den einzelnen
Komponenten und erschwert damit trickreiche Optimierungen. Außerdem
ist die im Mikrokernel benötigte Interprozesskommunikation auf
heutigen Hardwarearchitekturen aufwendiger als einfache
Funktionsaufrufe. Das System wird hierdurch etwas langsamer als
traditionelle monolithische Kerne. (Hardware immer schneller, System
besser Wartbar à
Zukunft!)
Linux hingegen entstand auf der langsamen
386-Architektur. Gutes Laufzeitverhalten durch ausreizen aller
Optimierungsmöglichkeiten stand bei der Entwicklung im
Vordergrund. Das ist der Grund warum Linux in der klassischen
monolithischen Kernelarchitektur realisiert wurde. Ein weiterer
Grund ist sicherlich, dass eine Mikrokernel-Architektur ein
sorgfältiges Systemdesign bedingt, da Linux evolutionär
entstanden ist, war dies einfach nicht möglich.
Systemschnittstellen zentral (in <linux/*.h>)
Architekturabhängige Teile (in <asm/*.h>)
Entwicklung stark evolutionär, nach Vorbildern von [Tanenbaum] und [Bach]
Dies ist eine logische Einteilung, die von mir stammt und nicht mit der (Un-)Systematik des tatsächlichen Kernel-Quelltextes übereinstimmen muß!
Hilfsroutinen allgemeiner Art (z.B. memset(), memcpy(), ...)
Low-Level Synchronisationsmittel (z.B. Interrupt-Sperren, Spinlocks, Semaphore)
High-Level Scheduling (Internes
Koroutinen-Modell à Probleme
mit SMP1)
è
Koroutinen: (nur eine kann laufen!)
Transfer (self, other)
start
(other)
à
Unterbrechungsstelle ist fest (bekannt). Anzahl der Transferbefehle
im Code.
Aus der Sicht eines unter Linux ablaufenden Prozeses
stellt sich der Kern als Anbieter von Dienstleistungen dar. Einzelne
Prozesse existieren unabhängig nebeneinander und können
sich nicht direkt beeinflussen. Der eigene Speicherbereich ist vor
dem Zugriff fremder Prozesse geschützt. Die interne Sicht auf
ein Linux-System ist etwas anders. Auf dem Rechner läuft nur
ein Programm - das Betriebssystem -, welches auf alle
Ressourcen zugreifen kann. Die verschiedenen Tasks werden durch
Koroutinen realisiert, d.h. jede Task entscheidet selbst, ob und
wann sie die Steuerung an eine andere Task abgibt (dies wird auch
als kooperatives Multitasking bezeichnet). Eine Konsequenz daraus
ist, dass ein Fehler in der Kernprogrammierung das ganze System
blockieren kann.
Low-Level Kernel-Speicherverwaltung (Kernelspeicher, Pages)
Architekturabhängige Routinen für virtuelle Adressräume
Architekturunabhängige Routinen für virtuelle Adressräume
High-Level-Routinen für Paging und Swapping
Gerätetreiber-Grundfunktionen (z.B. IO-requests)
Gerätetreiber, zum Teil mit interner Hierarchie, z.B. SCSI
VFS-Layer (VFS = Virtual Filesystem Switch)
einzelne Dateisysteme, z.B. minix, ext2
Netzwerk, inzwischen stark modularisiert
ê Im Prinzip
darf jeder Kernelteil auf jeden anderen zugreifen.
è
keine exakte Hierarchie!
Es wäre möglich, zwischen diesen Subsystemen eine Abhängigkeitsrelation zu ergründen. Dabei müßte man zwischen den Soll-Abhängigkeiten eines (vielleicht einmal systematisch geplanten Grundsystems) und den Ist- Abhängigkeiten des realen Systems unterscheiden. Das reale System enthält jedoch viele intrusive Abhängigkeiten, z.B. ist es nicht möglich, eine Datenstuktur des zum VFS-Layer gehörenden Buffer Cache zu ändern, ohne sämtliche Gerãtetreiber modifizieren zu müssen (und Gerãtetreiber gibt es sehr viele in Linux, die Größenordnung geht bald in die Hunderte). Es ist im Linux-Kernel gang und gäbe, daß die interne Realisierung von Datenstrukturen z.B. eines Low-Level-Subsystems überall in höheren Schichten benutzt wird, im Extremfall sogar fast über den gesamten Kernel-Quelltext verstreut.
Aus diesem Grund habe ich auf das Aufmalen irgendwelcher Architekturbilder verzichtet, die oft in Büchern über den Linux-Kernel zu finden sind.
1Symmetric Multi Processing