|
Aktuelles
Die Prüfungen finden am 02.08. statt. Als Ausweichtermin steht der 5.08. zur Verfügung.
Um einen Prüfungstermin zu bekommen, schreibt Ihr bitte eine Email an Florian und teilt ihm mit,
ob Ihr ein Fachgespräch oder eine mündliche Prüfung machen möchtet und ob Euch
die angebotenen Termine passen.
Termine
Auf dieser Seite werden während des Semesters weiterführende
Informationen sowie die jeweiligen Aufgabenzettel bereitgestellt.
Wir bemühen uns, die Seite so aktuell wie möglich zu halten.
Weitere Informationen zur Vorlesung:
Überblick
Betriebssysteme 2 umfasst folgende Themen:
Die Übungen vertiefen den Vorlesungsstoff durch praktische
Anwendung der beschriebenen Konzepte.
Veranstaltungsinhalte
Session 1: Der Weg durchs Betriebssystem
- System-Call Wrapper für den Einsprung in den Kernel:
Makros
_syscallx() mit x=0,1,2,4,5,6 in der
unistd.h für
die Konstruktion von System-Call Wrappern (Funktionsdeklaration plus
Funktionskörper).
Parameter(adress)übergabe in Registern.
Spezifizierung des Systemcalls über das EAX-Register.
Auslösen des Traps (=Softwareinterrupt) 0x80.
Setzen von errno. Definition des Rückgabewertes.
Prozessorinstruktionen SYSENTER/SYSEXIT als Alternative zum Interrupt.
Hinweis: In neueren Kernelversionen gibt es die unistd.h
in der Form nicht mehr. Stattdessen befinden sich entsprechende Makros in
den C-Libraries (siehe sysdep.h
aus der GNU C-Library 2.9)
- Einstiegspunkt im Kernel (Datei
arch/x86/kernel/entry_32.S):
Einsprungadressen
ENTRY(system_call) für Interrupt
0x80 und ENTRY(ia32_sysenter_target) für die
SYSENTER-Instruktion. Retten der Register auf dem Stack.
Aufruf von sys_SystemCallName() über die Tabelle
sys_call_table (Datei
arch/x86/kernel/syscall_table_32.S).
- Für das Kopieren von Datenbereichen, die im Systemaufruf über
Funktionszeiger identifiziert werden:
copy_to_user() kopiert
aus dem Kernelspace in den Userspace. copy_from_user() kopiert
aus dem Userspace in den Kernelspace.
- Beispiel: Systemaufruf
gettimeofday(2) -
Kernel-Implementierung mittels sys_gettimeofday() (Datei
kernel/time.c).
Hierzu weitere interessante Dateien:
-
kernel/time/timekeeping.c:
Funktionen
void do_gettimeofday() und getnstimeofday() und
Verweis über Funktionspointer auf die HW-abhängige Methode zum Lesen der Mikrosekunden-Zeiteinheiten in
timekeeping_get_ns() .
-
arch/x86/kernel/tsc.c:
Realisierung der Zeitabfrage über das Time Stamp Counter Register (TSC), siehe
static struct
clocksource clocksource_tsc und static cycle_t
read_tsc() und static int __init init_tsc_clocksource() .
-
arch/x86/include/asm/msr.h:
Definition des Makros
rdtscll() , welches das TSC-Register mit der
rdtsc -Assemblerinstruktion in __native_read_tsc() ausliest.
- Das aktuelle System Call Interface (SCI) von glibc und Linux unter
Nutzung der Intel Instruktionen
sysenter, sysexit (verfügbar
etwa ab Kernel 2.6.20)
Der Weg durch den Kernel als anschauliches Sequenzdiagram.
Hintergrundlektüre:
Kernel
command using Linux system calls von M. Tim Jones
Session 2: Linux-Kernel - Modifikation, Übersetzung, Installation
- Linux Kernel 2.6.33.2
herunterladen.
- Kernelquellen auspacken: als normaler User im eigenen Home-Verzeichnis
- Ins Verzeichnis linux-2.6.33.2 wechseln.
- Versionsnummer modifizieren, z.B. echo -bs2 > localversion-bs2.
- Konfiguration, Übersetzung, Installation und weitere Aktionen mit
make . Ein Überblick verschafft make help .
Hinweis: Eventuell muss muss die Zielarchitektur mit ARCH=... angegeben werden
(zum Beispiel: make ARCH=i386 menuconfig )
- Übernahme einer bestehenden
.config -Kernelkonfigurationsdatei
mit make oldconfig
- Kernel konfigurieren:
make menuconfig
Hinweis: Je mehr Features konfiguriert sind,
desto länger dauert der Generierungsvorgang. Es ist sinnvoll, die Konfiguration für die
Lösung der BS2-Aufgaben so klein wie möglich zu halten.
Sollen Teile des Kernels als Modul kompiliert werden, die jedoch zum Booten benötigt
werden ist eine Init-Ramdisk nötig.
- Kernel-Sources nach Bedarf modifizieren.
- Wenn neue Dateien (z.B. unter kernel/)angelegt werden,
müssen die zugehörigen Objektdateien im Makefile des
Verzeichnisses eingetragen werden.
- Kernel übersetzen:
make
- als root: Kernel-Module installieren:
make modules_install .
Die Module landen dann in der Regel unter /lib/modules/.
- als root: Kernel installieren:
make install
Hierdurch wird unter anderem das komprimierte Kernel-Image von
arch/x86/boot/bzImage nach /boot kopiert.
Ggf. ist auch noch per Hand das Anlegen einer Init-Ramdisk und das Erstellen
eines neuen Eintrags in /boot/grub/menu.lst nötig.
Auf jeden Fall sollte alles noch einmal kontrolliert werden.
- Reboot unter Auswahl des neuen Kernels - hier hilft auch
manchmal ein kleines Gebet ...
-
Um häufige Reboots zu vermeiden, ist der Emulator qemu
nützlich.
- Zur Konfiguration des Kernels für qemu kann die Datei
.config übernommen werden.
- Zum Starten eines selbstgebauten Kernels kann dieses
Makefile genutzt werden.
Das Makefile lädt automatisch ein vorinstalliertes Debian-Linux aus dem Netz
und startet euren Kernel mit diesem System. Hierzu muss sich der
übersetzte Kernel im Verzeichnis kernel/ befinden.
Nützliche Makefile-Targets sind:
make run-kernel : Starten des Systems mit dem von euch gebauten Kernel.
make debug-kernel : Starten des Systems mit dem von euch gebauten Kernel,
so dass er mit dem gdb debuggt werden kann.
make linux : Starten des Systems mit dem vorinstallierten Debian Linux-Kernel.
Session 3: Systemaufrufe: semop() (IPC-Paket) und fork()
semop()
- Alle Systemaufrufe aus dem IPC-Paket (Semaphoren, Shared Memory, Message
Queues) werden über den sys_ipc()-Aufruf im Kernel
behandelt. Beispielsweise bietet die aktuelle Version der glibc für semop()
folgenden Wrapper:
int
semop (semid, sops, nsops)
int semid;
struct sembuf *sops;
size_t nsops;
{
return INLINE_SYSCALL (ipc, 5, IPCOP_semop,
semid, (int) nsops, 0, CHECK_N (sops, nsops));
}
-
sys_i386_32.c definiert sys_ipc(). Dort wird je nach angefordertem
Dienst (Semaphoren, Shared Memory, Message Queues) in weitere
sys_xyz()-Funktionen verzweigt.
- semop() wird
in sys_semtimedop()
behandelt.
- Die eigentlichen DOWN und UP-Operationen werden ggf. auf mehreren
Semaphoren gleichzeitig (atomar) durchgeführt. Dies geschieht in
try_atomic_semop.
- Nach UP-Operationen muss ggf. ein wartender Prozess wieder rechenbereit
gemacht werden. Dies erfolgt
in update_queue(). Dort
wird der aufzuweckende Prozess bestimmt und mittels wake_up_sem_queue()
rechenbereit geschaltet. Der Standard-Dienst des Kernels hierzu ist
wake_up_process().
- Bei vergeblich versuchten DOWN-Operationen wird der semop() aufrufende
Prozess in den Wartezustand versetzt. Sein neuer Zustand ist
TASK_INTERRUPTIBLE: Schlafend, kann aber durch ein Unix-Signal wieder
aufgeweckt werden. Der Prozess wird in eine Semaphorgruppen-spezifische
Warteschlange eingetragen. schedule() wird aufgerufen, um einen
Kontextwechsel einzuleiten. Der Prozess wird später als Resultat einer
update_queue()-Durchführung aufgeweckt und setzt seine Arbeit hinter
dem schedule()-Aufruf fort.
fork()
- Architekturabhängiger
Einsprungpunkt sys_fork()
verzweigt direkt nach do_fork() unter Übergabe der
Registerinhalte
(Struktur struct
pt_regs).
- do_fork() behandelt die Erzeugung von "echten" Kindprozessen,
sowie die Erzeugung von Clones. Light-Weight Processes (LWPs) sind
ein Spezialfall der Clones: Das Cloning ermöglicht prinzipiell,
folgende ressourcen mit dem Elternprozess zu teilen:
- Virtuelle Speichertabelle
- Dateisystem (Struktur fs in der Prozesstabelle)
- Offene Dateien (Struktur files_struct)
- Signal Handler
- Tracing
- Wakeup bei mm_release
- Elternprozess des den Clone auslösenden Prozesses
- Thread-Gruppe
- Namespace-Gruppe
- SEM_UNDO Semantik
- Thread Local Storage (TLS)
- TID des Elternprozess
- UTS-Namensgruppe
- IPCS
- User Namespace
- PID-Namespace
- Network Namespace
- IO Kontext
- Die eigentliche Arbeit von do_fork() wird
in copy_process()
erledigt. Danach sind die wesentlichen Datenstrukturen für das Kind
aufgesetzt. do_fork() bestimmt die als Rückgabewert von fork() zu
vergebende virtuelle PID und
aktiviert den neuen Prozess oder Clone
über wake_up_new_task().
- copy_process() erledigt folgende Arbeiten:
- Erzeugung eines neuen Prozesstabelleneintrags (struct task_struct)
für das Kind: Viele Einträge werden einfach durch Kopie vom
Elternprozess übernommen; danach werden die Kond-spezifischen Daten
eingetragen.
- Aufbau eines neuen Stacks für das Kind
- Je nach Status der Clone-Flags werden
- Semaphore-Undo-information
- files_struct
- fs
- Signal Handler
- Anliegende Signale
- Memory Map
- Namespaces
- IO-Kontext
kopiert, oder es wird die Refernz auf die entsprechende Struktur des
Elternprozess beibehalten.
- Die Architekturabhängige
Funktion copy_thread()
Initialisiert Register und Stackpointer.
- Die neue interne PID wird vergeben.
- Das Kind wird unter seinen Geschwistern als neues Kind des Parent eingetragen.
Session 4: Scheduler Hierarchie und Completely Fair
Scheduler im Kernel 2.6.33
- Die zentrale
Scheduler-Funktion schedule()
führt die Kontextwechsel durch. Bei der Auswahl des nächsten
Prozesses, der den CPU core erhalten soll, bedient sich schedule() der
untergeordneten Scheduler-Klassen, die entsprechende Dienstfunktionen
bereitstellen müssen.
- Scheduler Klassen und die
struct sched_class Struktur mit
ihren vorgegebenen Funktionen, die von jeder Klasse zu implementieren sind.
- Das Konzept der virtuellen Laufzeit (virtual runtime) die zwischen
den rechenbereiten Prozessen fair ausgeglichen wird.
- O(1)-Eigenschaft des RT-Schedulers (sched_rt.c) für die Klassen
SCHED_FIFO und SCHED_RR.
- Scheduling Gruppen, um Fairness zwischen Gruppen von Prozessen zu
realisieren
-
Funktion
scheduler_tick() wird vom Clock Interrupt Handler aufgerufen. Die
Scheduler-Klassen bieten Dienstfunktion task_tick() an, um die beim Time
Tick notwendigen
Funktionen innerhalb der Klasse auszuführen.
- Bei der RT-Scheduler-Klasse ist dies
in task_tick_rt()
realisiert
- Für SCHED_FIFO-Prozesse hat task_tick_rt() keine Auswirkung, es sei
denn, dass die Beschränkung der genutzten CPU-Bandbreite konfiguriert
wurde.
- Bei SCHED_RR-Prozessen wird die Zeitscheibe dekrementiert. Bei Ablauf der
Zeitscheibe wird der aktive Prozess ans Ende seiner Runqueue
umgehängt, bekommt dabei wieder eine "frische" Zeitscheibe konstanter
Länge (100ms).
- Das Need-Resched-Bit wird dann gesetzt, so dass schedule() bei
nächster Gelegenheit den Kontextwechsel vornimmt.
- Funktion
sched_fork() wird bei Erzeugung eines neuen Prozesses mittels
fork()/clone() aufgerufen. Die Verwaltungsdaten für die
Scheduling-Entity werden initialisiert.
Rot-Schwarz-Bäme für die Completely Fair Scheduler Klasse
- Binärer Baum mit Knotenmarkierung rot/schwarz
- Nutzt Parent-, Left-, Right-Pointer, die auf NIL zeigen, falls kein
"echter" Parent-, Left-, Right-Knoten mehr existiert.
- Garantiert einen Grad von Balancierung, der allerdings schwächer ist
als derjenige von AVL-Bäumen: Bei Rot-Schwarz-Bäumen ist kein Pfad
von der Wurzel zum Blatt mehr als doppelt so lang wie ein anderer.
- Dieser Grad von Balancierung wird durch Einhaltung der
Rot-Schwarz-Eigenschaften beim Einfügen und Löschen erreicht:
- Jeder Knoten ist rot oder schwarz
- Jedes NIL-Blatt ist schwarz
- Wenn ein Knoten rot ist, dann sind alle seine Kinder schwarz
- Für jeden Knoten n gilt: Jeder von n ausgehende Pfad, der erst bei
einem NIL-Blatt endet, besitzt dieselbe Anzahl schwarzer Knoten.
- Rot-Schwarz-Bäume mit k Knoten haben eine maximale Höhe von
2lg(k+1).
- Zum Einfügen und Löschen werden die üblichen Algorithmen
für binäre Bäume verwendet. Danach muss aber ggf. der Baum
neu balanciert werden, um die Rot-Schwarz-Eigenschaften wieder
herzustellen. Dies erfolgt mit Hilfe von Links- und Rechts-Rotationen, sowie
durch Umfärbung von Knoten.
- Siehe Pseudocode für Rot-Schwarz
Einfügen und [18; pp. 263].
Beispiel aus dem Tutorium
für eine einfache Scheduling-Klasse.
Session 5: Das virtuelle Dateisystem (Virtual File System VFS)
- Das folgende Klassendiagramm zum VFS
stellt die Zusammenhänge zwischen den Datenstrukturen her, die beim
Ausführen eines auf Dateien oder Verzeichnissen operierenden
Systemaufrufs ausgewertet bzw. erzeugt werden - vom Prozesstabelleneintrag
des aufrufenden Prozesses bis zur die Datei/das Verzeichnis
repräsentierenden
Inode-Instanz im Kernel.
- Die vier Unix-Abstraktionen in Bezug auf Dateisysteme: Dateien,
Verzeichnisse, Inodes, Mount Points
- Die primären Objekttypen des VFS:
- Superblock Objekt (
struct super_block )
- repräsentiert ein Dateisystem nach dem Mount.
Die
zugehörigen Operationen werden aus dem Superblock-Objekt via Referenz auf
eine Instanz von struct super_operations entnommen. Diese
Operationen unterstützen alle Aktivitäten, welche das gesamte
Dateisystem betreffen, z.B.: Zurückschreiben des Superblocks auf die
Platte (write_super() ), Initialisieren eines neuen Inodes bei
Erzeugung einer neuen Datei/eines neuen Verzeichnisses in diesem Dateisystem
(alloc_inode() ), Zurückschreiben aller im Kernel vorhandenen
geänderten Daten (Superblock, Dateien oder Verzeichnisse
mit Inodes und Nutzdaten) des Dateisystems auf die Platte
(sync_fs() ). Die Operationen lassen sich in solche einteilen, die
nur auf die Dateisystemrepräsentation im Kernel einwirken
(z.B. alloc_inode(),put_inode() [Inode wird im Kernel freigegeben])
und solche, die auf das
Dateisystem auf der Platte einwirken (z.B. sync_fs(),
delete_inode() [Inode wird im Dateisystem auf der Platte gelöscht]).
Das Superblock Objekt und die Superblock-Operationen sind in
include/linux/fs.h deklariert.
- Inode Objekt (
struct inode ) - repräsentiert eine
Datei. Verzeichnisse sind unter Unix spezielle Dateien, daher wird auch ein
Directory über einen Inode repräsentiert.
Die auf dem Inode wirkenden Operationen werden über eine Referenz auf eine
Dateisystemtyp-spezifische Instanz von struct inode_operations
gefunden. Inode-Operationen betreffen immer die ganze Datei (nie den
Dateiinhalt), z.B. Öffnen/neu Anlegen der Datei in einem vorgegebenen
Verzeichnis, Erzeugen und Löschen von harten und symbolischen Links,
Umbenennen.
Das Inode Objekt und die Inode-Operationen sind in
include/linux/fs.h deklariert.
- Dentry Objekt - repräsentiert einen Verzeichniseintrag, genauer,
einen Pfadabschnitt, der ein Verzeichnis oder eine Datei in einem Verzeichnis
repräsentiert.
Auch Mount-Points werden durch Dentry-Objekte
repräsentiert. Im Pfad /mnt/d1/d2/file1.txt werden
/, mnt, d1, d2, file1.txt im Kernel durch jeweils ein Dentry-Objekt
repräsentiert. Die auf einem Dentry-Objekt wirkenden Operationen werden
über eine Referenz auf eine Instanz von struct dentry_operations
gefunden. Die Operationen ermöglichen beispielsweise das Vergleichen von
Verzeichnis- oder Dateinamen (wichtig z.B. für Dateisysteme, bei denen
Groß- und Kleinschreibung nicht unterschieden wird), sowie das Löschen
eines Verzeichniseintrags (was gleichzeitig das zugehörige Dentry-Objekt
invalidiert.
Dentry-Objekte haben keine direkte Entsprechung im Dateisystem auf der Platte:
Dort ist die Beziehung zwischen Verzeichnissen und Unterverzeichnissen oder
Dateien in den Nutzdaten der Verzeichnisse repräsentierenden Dateien
codiert. Dentry-Objekte werden in einem Kernel-Cache gehalten, um schnelle
Pfadauflösungen zu ermöglichen.
Das Dentry Objekt und die Dentry-Operationen sind in
include/linux/dcache.h deklariert.
- File Objekt - repräsentiert eine mit einem Prozess assoziierte
geöffnete Datei.
Die zum File-Objekt gehörigen Operationen sind in struct
file_operations zusammegefasst. Sie unterstützen alle
Aktivitäten, die den Dateiinhalt betreffen, auf welchen ein Prozess
zugreift. Beispiele sind llseek() (Positionieren des
Lese-/Schreibzeigers), read(), write() .
Das File Objekt und die IFile-Operationen sind in
include/linux/fs.h deklariert.
-
Dateisysteme sind typischerweise in Kernel-Modulen implementiert. Die
__init()-Funktion eines solchen Moduls ruft den Kernel-Dienst
int register_filesystem(struct file_system_type * fs) (filesystems.c)
auf und übergibt dabei die Adresse einer
ausgefüllten file_system_type-Struktur
(fs.h). Unter
den Komponenten dieser Struktur befindet sich der Funktionszeiger auf
die get-superblock Funktion
int (*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
welche jedes Dateisystem mit dieser Signatur anbieten muss, damit Mounts auf
Instanzen dieses Dateisystems durchgeführt werden können.
- Die konkrete Instanz eines Dateisystems nach dem Mount-Vorgang wird im
Kernel durch die Struktur struct vfsmount (mount.h) repräsentiert.
- Als ergänzende Literatur sind die unten angegebenen Bücher [3] (gibt
einen sehr guten Überblick der zu Grunde liegenden Konzepte des VFS; die
Darstellung ist von Linux unabhängig und bezieht sich auf Unix im
Allgemeinen) und[0,1,2] (Linux-spezifische Details)
zu empfehlen.
Session 6: Second and Third Extended File Systems - ext2/ext3
- Die Struktur von Ext2 Plattenpartitionen: Sonderrolle des Bootblocks -
Blockgruppen - Blockgruppenaufteilung in Superblock, Blockgruppendeskriptor,
Datenblock-Bitmap, Inode-Bitmap, Inode-Tabelle, Datenböcke - Inode
Struktur - Codierung von Directory-Inhalten in den Datenblöcken der
Directory-Files.
- Journalling im Ext3 Filesystem Die 3 journalling modes
- Writeback: Nur die Metadaten kommen ins Log. Damit
können Nutzdaten abgeschlossener write()-Operationen nach einem
Crash verloren sein, aber die Konsistenz des Dateisystems nach der
Recovery (=Einspielen offener Transaktionen aus dem Journal in die
Partition) ist gesichert.
- Ordered: Das Commit für die Metadaten im
Journal wird erst gegeben, nachdem die Nutzdaten auf die
Disk geschrieben wurden. Dadurch sind vor einem Crash
vergrösserte Dateilängen nur dann nach der Recovery
sichtbar, wenn auch der korrekte Dateninhalt am Dateiende eingetragen
ist. Write()-Operationen, die innerhalb einer Datei stattfinden, ohne
ihre Länge zu verändern, können genau wie beim
Writeback-Mode bei einem Crash verloren gehen bzw. zu einem
inkonsistenten Zustand der Nutzdaten führen, wenn vor dem Crash
nur ein Teil der Aktualisierung tatsächlich auf den Nutzdaten in der
Partition realisiert wurde.
- Journal: Metadaten und Nutzdaten werden ins Log
geschrieben, so dass sowohl das Dateisystem konsistent bleibt, als
auch alle abgeschlossenen write()-Operationen nach einem
Crash rekonstruierbar sind.
- Vergleich des Ext3-Journalling mit Logging und Transaktionsmanagement bei
Datenbanksystemen
- Als Literatur empfehlen wir [2; pp. 495] und [4]
Session 7: Interrupts und Interrupt Handling
- Nebenbemerkungen:
- direkter Zugriff auf Hardware-Devices,
ihre Register (I/O Ports) und ggf. ihren zusätzliche Speicher (I/O
Memory) mittels
outb(), inb(), outw(), inw(), outl(),
inl()
- Polling versus Interrupts
- Betrieb von Interface Devices ohne Interrupt Handling durch (1)
zyklisches Auslesen der Statusregister und ggf. nachfolgenden
Lese-/Schreibaufträgen an das Device, (2) DMA Devices ohne
Interrupterzeugung, (3) Dual-ported RAM Devices
- Synchrone Interrupts (Traps und Exceptions)
- Asynchrone Interrupts - von externen Devices erzeugt
- Vom HW-Interrupt bis zum Interrupt Handler: Interrupt am Device -
Interrupt Controller - Interrupt lines zur CPU -
do_IRQ() -Schnittstelle - Interrupt Vector - Interrupt Handler (=
Interrupt Service Routine ISR, Top-Half) - Monitoring über
/proc/interrupts
- Registrierung von Interrupt Handlern durch Device Driver
- ISR Interface
- ISR Context im neuen Linux vom Prozesscontext verschieden -
insbesondre mit eigenem Stack
- Shared IRQs von Devices, welche die selbe Interrupt Line benutzen,
Identifikation der zuständigen ISR
- Sperren/Freigeben von Interrupts
- Reentrant ISR sind unter Linux nicht erforderlich
- Kernel Entropy Pool und der Beitrag von Interrupts zur Erzeugung
"echter" Zufallszahlen
- Bottom-halves zur Entlastung des Interrupt Handlers durch Verlagerung
nicht zeitkritischer Aktivitäten in
- Softirqs,
- Taskletts,
- Work Queues
- Als Literatur empfehlen wir [0; pp. 75-118]
Session 8: Treiberentwicklung unter Linux
- Als Literatur empfehlen wir [17]
- Framework für Linux Kernel Modules, die Treiber realisieren, siehe [17; Chapter 2].
- Klassifikation der Treiber in Character/Block/Network Device Drivers
- Major/Minor Numbers zur Identifikation von Treibern und den
zugeordneten Hardwareschnittstellen (anwendbar für Character und Block
Devices) - dynamische Vergabe der Major/Minor Numbers - Zuordnung über
/proc/devices. Siehe [17; Chapter 3]
- Die Realisierung von Treiberoperationen als Ausprägungen des virtuellen
Dateisystems - Herstellung der Verbindung zwischen API-Aufruf
(z.B. read(), write()) und Treiberfunktionen über File Structure, File
Operations, Inode Structure - Kombination der (Treiber,Device)-spezifischen
Zustandsdaten mit den Standardinformationen über Treiber, welche im Inode
abgelegt werden
(Devicenummer dev_t i_rdev; und Kernel-Datenstrukturen für
(Character-) Devices struct cdev cdev;) - Standard-Entwurfsmuster für
open(), read(), write(). Siehe [17; Chapter 3]
- Das Beispiel eines Character Device Drivers ohne echten Hardware-Zugriff
(Beispiel 'Scull' aus [17])
ist unter
scull.tgz
zu finden. Diese Beispiel erläutert das zugrunde liegende Framework für Linux
Character Device Driver auf hervorragende Weise.
Literatur
Für die Lehrveranstaltung sind die folgenden Literaturangaben
relevant, wobei speziell [0], [1],
[2], [3] und
[4] den Vorlesungstoff vertiefen.
[0] |
Robert Love:
Linux Kernel Development, Second Edition,
Novell Press, Indianapolis, USA, 2005.
Elektronisch verfügbar als Safari Book Online unter
Link zum Buch in der SUUB
|
|
[1] |
M. Beck, H. Böme, M. Dziadzka, U. Kunitz, R. Magnus,
C. Schröter, D. Verworrner:
Linux Kernel-Programmierung -- Algorithmen und
Strukturen der Version 2.2, 5. Auflage.
Addison-Wesley, 1999 |
|
[2] |
D.P. Bovet, M. Cesati: Understanding the Linux
kernel, 1st edition.
O'Reilly & Associates, 2001.
Elektronisch verfügbar als Safari Book Online unter
Link zum Buch in der SUUB
|
|
[3] |
U. Vahalia: Unix Internals - The New Frontiers,
Prentice Hall 1996. |
Dieses Buch geht zu den einzelnen Themenbereichen mehr in die
Tiefe als Tanenbaum oder Stallings: Wenn diese beiden
Bücher nicht mehr genug Details verraten, lohnt es sich,
einen Blick in den Vahalia zu werfen. |
[4] |
Wolfgang Maurer: Linux Kernelarchitektur. Konzepte, Strukturen und Algorithmen von
Kernel 2.6,
Hanser (2005). |
siehe folgende WWW Referenz |
[5] |
A. Tanenbaum: Modern Operating Systems, 2nd edition.
Prentice Hall, 2001 |
|
[6] |
A. Tanenbaum: Moderne Betriebssysteme, Hanser 1995
|
|
[7] |
A. Tanenbaum, A. S. Woodhull: Operating Systems: Design
and Implementation, 2nd edition. Prentice Hall, 1997.
|
Dies ist eine erweitere Fassung des 1. Teils von [5] bzw. [6].
|
[8] |
A. Tanenbaum: Distributed Operating Systems, Prentice
Hall 1995. |
Dies ist eine erweiterte und aktualisierte Fassung des 2.
Teils von [5] bzw. [6]. |
[9] |
V. Toth: Programming Windows 98/NT Unleashed, Sams
Publishing, 1998. |
Eine umfangreicher Überblick über die
Systemprogrammierung unter Windows 98 und Windows NT inkl.
CD-ROM mit Beispielen. |
[10] |
W. Stallings: Operating Systems - Internals and Design
Principles, Prentice Hall 1998. |
Diese Buch ist eine Alternative zu den Büchern von
Tanenbaum. Es werden ebenfalls alle wichtigen Standardthemen,
auch in bezug auf verteilte Systeme, behandelt. |
[11] |
W.R. Stevens: Unix Network Programming, Prentice Hall
1990.
|
Eine sehr detaillierte Einführung in die
Systemprogrammierung unter UNIX anhand ausführlicher
Beispiele. Insbesondere wird auf die Standard Internet
Protokolle eingegangen sowie auf
Interprozesskommunikationsmechanismen aber auch Remote Login
sowie RPCs werden behandelt. Inzwischen gibt es eine
überarbeitete zweibändige Ausgabe von 1998.
|
[12] |
C.A.R. Hoare: Communicating Sequential Processes,
Prentice Hall 1985. |
Das Standardwerk zu CSP. |
[13] |
A.W. Roscoe: The Practice and Theory of Concurrency,
Prentice Hall 1998. |
Eine modernisierte Einführung in CSP und FDR. |
[14] |
J. Peleska: Formal Methods and the Development of
Dependable Systems, Christian-Albrechts-Universität
zu Kiel 1996.
|
In dieser Habilitationsschrift befindet sich u. a. die
Spezifikation d er HP-UX Access Control Lists (S. 149ff). Eine
Postscript-Version liegt zum Download
lokal auf den Seiten der Universität Bremen. |
[15] |
S. Maxwell: Linux Core Kernel Commentary,
The Coriolis Group, 1999 |
Kernel-Kommentierungen |
[16] |
Krzysztof R. Apt and Ersnt-Rüdiger Olderog: Verification of Sequential
and Concurrent Programs.,
Springer, 1991 |
Vollständiger Beweis der Fairness und Universalität der Schedulers aus
Session 4 |
[17] |
J. Corbet, A. Rubini and G. Kroah-Hartman: Linux Device Drivers.,
O'Reilly, 2005. Verfügbar
unter PDF-Files |
Einführung in die Treiber Entwicklung für den Linux Kernel |
[18] |
Thomas H. Cormen, Charles E. Leiserson and Ronald
L. Rivest: Introduction to Algorithms.,
The MIT Press, Cambridge Massachusetts, McGraw-Hill Book Company, New
York, 1999 |
Gute Beschreibung des Rot-Schwarz-Baum Algorithmus |
Aufgabenblätter
Als Grundlage zur Bearbeitung der Übungsblätter dient der
Linux Kernel 2.6.33.2.
|
|