====== Betriebssystem ====== **Prüfer**: Daniel Lohmann \\ **Beisitzer**: Daniel Danner **Themengebiete**: Betriebssysteme (MPStubs + Übung, 7.5 ECTS) **Datum**: April 2013 Papier + Stift bereitgestellt; Daniel Lohmann hat einiges von dem was ich erklärt hat aufgemalt und dann ggf. vertiefende Fragen gestellt und erweitert. Prüfer **P**, Student **S**. ==== Fragen ==== **P**: Was ist ein Betriebssystem? **S**: Definition ist schwer, kommt auch auf die Anwendung an. Bibliothek, Monolithen, Exokernel genannt und grob erklärt. **P**: Was zeichnet einen Monolithen aus? **S**: Benutzer-/Systemmodus, Speicherschutz, mehrere Anwendungen, getrennte Adressräume. (Hat etwas gedauert bis ich genau auf den Unterschied kam, hatte da vorher nicht genau drüber nachgedacht.) **P**: Was zeichnet einen Mikrokern aus? **S**: Minimierung der Trusted Code Base, möglichst viel aus dem Kernel auslagern. Dispatcher muss in den Kernel wegen Adressraumwechsel, Scheduler aber nicht. **P**: Kann ein Bibliothekssystem auch mehrere Anwendung unterstützen (also Scheduling)? **S**: (War zuerst etwas verwirrt weil das in der Vorlesung nicht explizit genannt war.) Ja, kann man implementieren. **P**: Was ist MPStubS? **S**: (Mit Hilfe.) Bibliothekssystem, da kein Speicherschutz bzw. Benutzer-/Systemmodus, alles wird zusammen gelinkt. **P**: Wie funktioniert toc_switch() zum Koroutinenwechsel? **S**: Erklärt (siehe Übung/Vorlesung), nicht-flüchtige Register tauschen, dann ret auf dem neuen Stack. **P**: Benötigt das spezielle Rechte? **S**: Nein, geht auch im Benutzermodus. **P**: Was ist das ideale Betriebssystem? **S**: Das die spezifische Anwendung möglichst effizient ausführt. Eierlegende Wollmilchsau gibt es nicht. \\ **P**: Sie sind Betriebssystemsentwickler und sollten für folgende Anwendung ein Betriebssystem erstellen, was brauchen sie? main() { printf("Hallo, Welt!"); } **S**: * Bootloader * Ausgabetreiber für den Monitor * Startup-Code der main() aufruft und auch den Stack aufsetzt (den hab ich zuerst vergessen) * nach der main() im Startup-Code ein hlt, damit der Prozessor nicht weiter läuft **P**: Der Kunde will noch ein getch(). Wie muss das System erweitert werden? **S**: * Treiber für die Tastatur * Pollen des Register im Tastatur-Controller im Loop bis ein Zeichen gelesen wurde **P**: Kunde merkt das der Lüfter immer an ist, wie kann man das beheben? **S**: * aktives Warten ist schlecht, Interrupts verwenden * Interrupt-Handler speichert Zeichen in Buffer, getch() liest aus (kurz I/O-APIC, IDT, Interrupt-Routine erklärt) * sleep in getch()-Loop **P**: Braucht man den Loop noch? **S**: Prinzipiell nein, da immer ein Zeichen geschrieben wurde. Aber wegen Spurious Interrupts ist es sinnvoll. **P**: Wo ist das Problem im Loop? **S**: Lost-Wakeup zwischen Überprüfung ob ein Zeichen gelesen wurde und sleep(). **P**: Wie behebt man das? **S**: Interrupts vorher sperren; sti und sleep() müssen aber atomar sein (sti; hlt sind atomar auf x86). **P**: Wo ist ein weiteres Problem? **S**: Gemeinsamer Zustand (Buffer Index) in Interrupt-Handler und getch(). **P**: Wie behebt man das? **S**: * hart synchronisieren: Interrupts vorher sperren, einseitige Synchronisation da der Interruptkontrollfluss nicht vom Anwendungskontrollfluss unterbrochen werden kann * weich synchronisieren: unterbrechungstransparenter Algorithmus **P**: Wie könnte ein naiver Algorithmus aussehen? **S**: interrupted flag im Handler setzen und im Loop in getch() prüfen, falls true Zeichen erneut auslesen (vgl. Time-Code in der Vorlesung). **P**: Der Sohn des Auftraggebers hat dem Vater von Multiprozessorsystemen erzählt. Keyboard-Interrupts werden nur an die zweite CPU geschickt. Was müssen wir tun? **S**: * Startup-Code muss main_ap() auf zweiter CPU starten * main_ap() einfach while(1) { hlt; } * IPI im Interrupt-Handler um Interrupt bei Keyboard-Interrupt an die erste CPU zu schicken und diese zu wecken **P**: Gibt es bei der main_ap() ein Lost-Wakeup? **S**: Nein. Denn Lost-Wakeup hat immer eine Test-Handle-Wettlaufsituation, in main_ap() wird nichts geprüft. **P**: Was geht jetzt in getch() kaputt? **S**: getch() kann jederzeit unterbrochen werden, einseitige Synchronisation reicht nicht mehr aus. **P**: Wie löst man das? **S**: Spinlock, lock()/unlock() um den kritischen Abschnitt. **P**: Wo gibt es da ein Problem mit Interrupts? **S**: Interrupts vor lock() sperren sonst gibt es Deadlock wenn getch() lock() macht und dann ein Interrupt kommt. [Noch 2-3 Minuten Zeit.] **P**: Wie implementiert man ein Spinlock? **S**: lock() { while(TAS(&x, 1) == 1) ; } unlock() { x = 0; } [Die folgenden Fragen gingen über den Stoff hinaus und waren stofflich nicht Teil der Prüfung.] **P**: Weißt du wie man TAS auf der Hardware implementiert? **S**: So grob. Über das Cache-Kohärenz Protokoll. **P**: Wo ist das Problem damit? Wann wird eine Cache-Zeile ungültig? **S**: Beim Schreiben bzw. wenn eine andere CPU den geänderten Wert lesen will? Also bei diesem TAS bei jedem Schleifendurchlauf. **P**: Wie könnte man das mit CAS besser lösen? Hinweis, CAS vergleicht und tauscht dann. **S**: CAS schreibt nur wenn der Lock nicht belegt ist, reduziert damit also das Cache-Trashing deutlich. ==== Fazit ==== Atmosphäre sehr angenehm, Fragen kamen nur von Daniel Lohmann. Note: sehr gut Ich hab bei einigen Fragen etwas zu lange gezögert und kam nicht gleich auf die Antwort. Es lohnt sich, die "Programm"-Entwicklung schon zu Hause genau durchzugehen.