Sie befinden sich hier: Termine » Prüfungsfragen und Altklausuren » Hauptstudiumsprüfungen » Lehrstuhl 4 » PRÜFUNGSPROTOKOLL   (Übersicht)

PRÜFUNGSPROTOKOLL

Fach: Betriebssysteme (MPStuBS)
Prüfer: PD Daniel Lohmann
Beisitzer: M. Sc. Christian Dietrich
Datum: März 2016

Es gab einen DIN-A3-Zettel, den Daniel im Laufe der Prüfung voll gemalt hat. Manchmal musste ich auch was drauf schreiben.

Vorbereitung

Das ganze Zeugs, was auf den Folien steht, sollte man zwar mal gehört haben, aber man muss fast nichts auswendig können. Es geht mehr ums Verstehen. Auswendig können sollte man aber zum Beispiel den Stack, den toc-settle erzeugt. Überhaupt sind alle kniffligen Stellen im Übungsbetrieb wichtig, die sollte man drauf haben.

Einstieg

Zum Einstieg wurde ich von Daniel gefragt, wozu man denn ein BS braucht. Man beachte, dass er nicht mehr seine Standardfrage gestellt hat, was denn ein BS ist. Ich wollte erst die Antworten aus den alten Protokollen abspulen - dann wurde ich aber unterbrochen und ich sollte beantworten wofür man es denn braucht. Also hab ich gesagt, dass man die CPU multiplexen muss, wenn man mehr Fäden als Prozessorkerne hat. Und dass ich den Speicher vor unerlaubtem Zugriff schützen muss. In dem Zusammenhang wollte er noch das Stichwort Supervisor-Modus haben. Dann sind wir noch drauf gekommen, dass ein BS ja die Maschine erst richtig hochfährt und dabei auch den Fäden jeweils einen Stack im Speicher zur Verfügung stellt.

Unterbrechungen 1

Dann hat er aufs Papier einen Zeitstrahl gemalt und darauf lief dann ein Faden ab. Dann hieß es: „Wenn der Faden jetzt die Unterbrechungen ausschaltet - kann er dann die CPU monopolisieren? Für immer? Er macht die Interrupts aus und danach kann er nicht mehr verdrängt werden, weil es ja keine Unterbrechungen mehr gibt. Oder?“ Aus dem Zusammenhang war früher oder später klar, dass ich das widerlegen sollte. Obwohl das eine einfache Frage ist, waren meine Antworten eher so halbrichtig. Daniel hat dann gemeint, dass das Ausschalten der Interrupts ein Trap ins Betriebsystem sei, und dieses entscheide dann, ob der Faden überhaupt weiter machen darf, oder ob er verdrängt wird.

Scheduling

Anschließend kam so die Frage, was es denn da überhaupt so für Arten gibt, beim Scheduling. Da habe ich gesagt dass es eben kooperatives und präemptives Scheduling gibt. Beim kooperativen vertraut man darauf, dass die Fäden die CPU auch wieder freiwillig abgeben werden. Beim präemptiven werden die Fäden einfach „mit Gewalt“ von der CPU verdrängt.

Dann konnte ich mir aussuchen, welches der beiden Verfahren wir genauer besprechen. Oder vielleicht auch nur mit welchem wir anfangen. Weil das Thema aber eh nicht meine Stärke war, habe ich gesagt, dass ich da keine Präferenz habe. ich konnte beide gleich gut und gleich schlecht.

Anschließend hat Daniel alles mögliche auf dem Papier entwickelt. Wir hatten die Methode resume() - in dieser gab es aber fast keine Methodenaufrufe mehr, das meiste war „geinlined“ damit alles da drin statt findet. Dann hatten wir auch noch toc-go und toc-switch durchgesprochen. Dabei sollte ich sagen, welche Register denn da immer hin und her kopiert werden. Ich habe gesagt, dass es die nicht-flüchtigen sind. „Warum muss man die anderen, die flüchtigen, denn nicht sichern?“ wollte Daniel noch wissen. „Das macht doch der Compiler“ habe ich dann gesagt.

Irgendwann sollte ich dann auch noch den Stack hinmalen, den toc-settle erzeugt:

Adresse vom zu startenden Faden
0xcafebabe
Adresse von kickoff

Dazu habe ich erklärt, dass als Rücksprungadresse die von kickoff gelesen wird und man dann dort hinspringt. Daniel hat dann eingehakt, ob das denn schon bei toc-settle passiere, dass ich dann in kickoff springe. Nein, habe ich gesagt, dass ist nicht so, denn toc-settle bereitet den stack ja nur vor. Eingetragen in das Stackpointerregister wird der dann erst in toc-go und dann beim ret von toc-go springe ich in kickoff.
Über der Adresse von kickoff liegt dann im Stack eine Pseudo-Rücksprungadresse, die nie angesprungen werden darf - aber wir brauchen sie, damit der Stack eben so aufgebaut ist, wie ein Stack eben immer aufgebaut ist, daher muss da halt ne Rücksprungadresse liegen. Darüber liegt dann das Argument von kickoff und das ist dann der zu startende Faden. kickoff sollte ich dann auch noch hin malen. Habe ich dann wie in der Übung gemacht. Der Beisitzer meinte aber, Datentypen seien egal, und es müsste nicht so genau sein, es geht nur ums Prinzip:

void kickoff(Thread* object){
object→action();
while(true){}
}

Unterbrechungen 2

Ich weiß nicht mehr wie es genau weiter ging. Irgendwann kam dann die Frage: „OK, der Computer ist komplett ausgeschaltet. Jetzt schalte ich ihn ein und die Maschine fährt hoch. Sind die Interrupts in diesem Moment eigentlich ein oder aus?“ Also habe ich gesagt, dass sie ausgeschaltet sind. Anschließend ging es darum, wo man sie denn einschaltet. Also hab ich gesagt, dass man alles vorbereitet, dann holt man sich den ersten Faden, dann macht man die Unterbrechungen an und lässt den Faden los laufen. Dann ging es darum, an welcher Stelle von all den Dingen, die wir jetzt auf dem Papier stehen hatten, man die genau einschaltet. Dabei haben wir keinen guard und kein enter/leave verwendet, sondern sti und cli. Da jetzt alles etwas anders aussah als ich es aus der Übung gewohnt war, kam ich dann durcheinander (der Code hatte im Prinzip die gleiche Funktion wie in der Übung, sah aber doch anders aus, weil wir meistens „geinlined“ haben anstelle von Funktionsaufrufen). Richtig war natürlich, dass man sie in kickoff einschaltet, unmittelbar vor object→action(). Denn hier springt man in die Anwendung rein, der Anwendungsprogrammierer soll sich aber damit nicht beschäftigen, also macht man es unmittelbar davor. Also so:

void kickoff(Thread* object){
sti(); object→action();
while(true){}
}

Das ist der Falll, wenn ein Faden zum ersten Mal läuft. Wenn er schon mal gelaufen ist, kommt man aber nicht in kickoff raus, sondern in resume. Also muss man in resume, nach dem Aufruf von toc-switch auch noch mal sti() ausführen. Vorher ging es noch darum, wo man in resume cli() aufruft. Da gleich am Anfang von resume auf eine Warteschlange zugegriffen wurde und dieser Zugriff geschützt sein muss habe ich gleich am Anfang von resume() das cli() hin gemacht.

active-Zeiger

Es ging dann auch noch um die Frage, wo ich denn den active-Zeiger aktualisiere. Der zeigt ja immer auf den Faden, der aktuell läuft. Macht man das vor oder nach toc-switch? Richtig ist, dass man es unmittelbar davor macht. Denn der Wert, den ich in den active-Zeiger schreiben will, liegt auf dem Stapel. Nach toc-switch habe ich aber einen ganz anderen Stapel.