2013-04
Prüfer: Dr. Daniel Lohmann
Beisitzer: Dipl.-Inf. Daniel Danner
Die Prüfungsatmosphäre war angenehm. Zu Beginn wurden einige Klassiker der BS-Prüfungsfragen gestellt, danach kamen jedoch hauptsächlich Transferfragen. Daher kann ich den Eindruck aus den anderen Prüfungsprotokollen, dass bei der Prüfung das Augenmerk hauptsächlich auf Verständnis liegt, nur bestätigen. Manchmal bin ich dabei auch auf Irrwege gekommen, jedoch konnte das durch eine Diskussion immer gelöst werden (das wurde aber nicht als negativ angesehen).
Q: Was ist ein Betriebssystem?
Q: Welche Systemressourcen denn?
CPU, Geräte, auch eher abstrakte Dinge wie Schutzmechanismen Q: Wie sieht das ideale Betriebssystem aus?
Kommt auf den Anwendungszweck an
Q: Das Betriebssystem verwaltet die CPU, welche Kontrollflüsse haben wir denn da?
Q: Wie stehen denn die Kontrollflüsse zueinander?
E_0: Anwendungen
E_1: Unterbrechungen (und höhere Ebenen)
E_1/2: Epilogebene
Unterbrechbarkeit: Kontrollflüsse aus Ebenen mit höherem Index können Kontrollflüsse aus Ebenen mit niedrigerem Index unterbrechen. Anders herum geht das nicht. Auch Kontrollflüsse aus der gleichen Ebene können sich nicht gegenseitig unterbrechen.
Run to completion: Kontrollflüsse auf Ebenen außer E_0 laufen immer bis zum Ende durch
Verdrängbarkeit: Kontrollfluss aus Ebene E_0 kann verdrängt werden, kein run to completion im strengen Sinn
Q: Warum braucht man die Epilogebene? Warum macht man nicht alles im Interruptkontrollfluss?
Interruptkontrollfluss ⇔ Interrupts gesperrt
Währenddessen können keine weiteren Interrupts behandelt werden
Interrupts können verloren gehen
Q: Und auf Anwendungsebene? Wenn ein Interrupt kommt, erstellen wir einen neuen Thread, der dann auf Anwendungsebene arbeitet.
Hier ist nicht das Problem, dass die Synchronisation nicht funktioniert.
Das Problem liegt bei der Ready-Liste; Zugriff wird synchronisiert bei:
Neuer Thread wird erzeugt
Interrupthandler wird ausgeführt
Thread wird verdrängt
Passives Warten bei mutex.lock()
> Interrupts müssen häufig gesperrt werden
Q: Was ist der Unterschied zwischen Interrupts und Traps?
Interrupts von außen (z.B. Geräte) ausgelöst, asynchron
Traps durch bestimmte Instruktion ausgelöst (z.B. Division durch Null, Page Fault)
Q: Es kommen Traps hinzu. Wie bauen wir die jetzt ins Betriebssystem ein?
Erster Ansatz: Auf E_1
Während Trap kann kein Interrupt kommen → Kein Problem, wenn Traphandler kurz ist und einen Epilog benutzt
Während ein Interrupt läuft, kann es keinen Trap geben → schlecht
Zweiter Ansatz: Auf E_2 (bzw. einer Ebene, die höher ist als jede Interrupt-Ebene
Während ein Trap läuft, kann es keinen Trap geben → auch schlecht
Dritter Ansatz: Auf E_x, einer Ebene, die die Regeln des Ebenenmodells verletzt
Alle Kontrollflüsse können unterbrochen werden (auch aus E_x)
funktioniert
> Fazit: Traps passen nicht ins Ebenenmodell
Q: Wie kann man Traps denn auf Ebene einer Programmiersprache betrachten?
Q: Es gibt ja bei Betriebssystemen verschiedene Paradigmen. Welche denn?
Bibliotheken
Stellen Funktionen zur Verfügung
Kann man benutzen oder nicht (auch irgendwelche obskuren Mischformen möglich)
Monolithen
Betriebssystem mit allen Teilen komplett im Supervisor-Modus
Bietet Schutz an
(Q: Wie sieht der aus?) Zwischen Kernel und Benutzerprogramme über Schutzringe; zwischen Benutzerprogrammen mittels MMU
Mikrokernel
Teile des Betriebssystems in Server-Prozesse ausgelagert (z.B. Scheduler)
(Q: Warum macht man das?) Möglichst wenig Code soll im Supervisor-Modus ausgeführt werden (hier wurde explizit darauf abgezielt, dass es rein sicherheitstechnische Überlegungen sind, und dass es für die Performance eher nachteilig ist)
(Q: Gibt's hier auch Schutz?) Ja, genauso wie beim Monolithen
(Q: Und der Dispatcher? Wo ist der?) Muss im Kern bleiben
Q: Warum muss der Dispatcher im Kern bleiben? Wie funktioniert der Koroutinenwechsel und welches ist die Operation, die den privilegierten Modus erfordert?
Koroutinenwechsel erfordert Sicherung der nicht-flüchtigen Register (flüchtige sichert der Compiler). Insbesondere wird hier auch der Stackpointer gesichert. Danach werden die Register der Koroutine, die nun ausgeführt werden soll, wiederhergestellt. Da Stackpointer wiederhergestellt wurde, ist die Rücksprungadresse nun eine andere, nämlich die der anderen Koroutine.
Bei Rücksprung wird auf Speicher der anderen Koroutine zugegriffen.
Wenn Dispatcher nicht im Kern laufen würde, wäre dieser Rücksprung eine Schutzverletzung.