Betriebssystembau (BSB)5. Übung
https://ess.cs.tu-dortmund.de/Teaching/SS2019/BSB/
Horst Schirmeier
[email protected]://ess.cs.tu-dortmund.de/~hsc
AG Eingebettete SystemsoftwareInformatik 12, TU Dortmund
mit Material von Olaf Spinczyk, Universität Osnabrück
23.05.2019 Betriebssystembau: 5. Übung 2
Agenda● Aufgabe 4: Tipps & Tricks
● Aufgabe 5: Überblick
● PIT-Programmierung
● Präemptives Scheduling
23.05.2019 Betriebssystembau: 5. Übung 3
Agenda● Aufgabe 4: Tipps & Tricks
● Aufgabe 5: Überblick
● PIT-Programmierung
● Präemptives Scheduling
23.05.2019 Betriebssystembau: 5. Übung 4
Dispatcher
toc
Coroutine
Application
Scheduler Entrant
Chain
Queue
...
user
machine
thread object
Aufgabe 4: Überblick
Ein kooperativerScheduler (FCFS)Ein kooperativerScheduler (FCFS)
Eine erste Kontroll-flussabstraktion.Eine erste Kontroll-flussabstraktion.
23.05.2019 Betriebssystembau: 5. Übung 5
Dispatcher
toc
Coroutine
Application
Scheduler Entrant
Chain
Queue
...
user
machine
thread object
Aufgabenteil a: CoroutineKoroutinenwechsel „von Hand“
23.05.2019 Betriebssystembau: 5. Übung 6
Kooperativer FadenwechselBe
trie
bssy
stem
Anw
endu
ngen
<app1>
<app2>
resume
upca
ll ap
p1
Legende Kontrollflusserzeugung: Kontrollflusszerstörung:
explizite (Re-)Aktivierung: implizite (Re-)Aktivierung:<schedule>
<resume>
<kickoff'>
<kickoff>re
t
ret
upca
ll ap
p2
resume
ret
resume
ret
23.05.2019 Betriebssystembau: 5. Übung 7
toc – Koroutinen für C-ProgrammeStrukturelemente: void *rbx, *r12, *r13, *r14, *r15, *rbp, *rsp;
Funktionenvoid toc_settle (struct toc* regs, void* tos, void (*kickoff)(void*, void*, …), void *coroutine);
Bereitet die Struktur toc für die erste Aktivierung vor.
void toc_go (struct toc* regs);
Lädt die Prozessorregister mit den Inhalten der Struktur regs und gibtcoroutine an kickoff weiter.
void toc_switch (struct toc* regs_now, struct toc* regs_then);
Führt einen Kontextwechsel durch. Dazu müssen die aktuellenRegisterwerte in regs_now gesichert und durch die Werte von regs_thenersetzt werden.
23.05.2019 Betriebssystembau: 5. Übung 8
toc – Koroutinen für C-ProgrammeStrukturelemente: void *rbx, *r12, *r13, *r14, *r15, *rbp, *rsp;
Funktionenvoid toc_settle (struct toc* regs, void* tos, void (*kickoff)(void*, void*, …), void *coroutine);
Bereitet die Struktur toc für die erste Aktivierung vor.
void toc_go (struct toc* regs);
Lädt die Prozessorregister mit den Inhalten der Struktur regs und gibtcoroutine an kickoff weiter.
void toc_switch (struct toc* regs_now, struct toc* regs_then);
Führt einen Kontextwechsel durch. Dazu müssen die aktuellenRegisterwerte in regs_now gesichert und durch die Werte von regs_thenersetzt werden.
Aufruf aus C++ heraus erfordert Deklaration mit extern “C“!Aufruf aus C++ heraus erfordert Deklaration mit extern “C“!
● Über tos soll der Stapel initialisiert werden. Geht das mit einem Zeiger auf void?
● Über tos soll der Stapel initialisiert werden. Geht das mit einem Zeiger auf void?
23.05.2019 Betriebssystembau: 5. Übung 9
CoroutineMethodenCoroutine (void* tos);
Im Koroutinen-Konstruktor werden die Registerwerte so initialisiert, dass der
Stackpointer initial auf tos zeigt und bei der ersten Aktivierung die Ausführung
mit der Funktion kickoff beginnt.
void go ();
Diese Methode dient der ersten Aktivierung der ersten Koroutine im System.
Daher müssen hier keine Registerwerte gerettet werden.
void resume (Coroutine& next);
Mit dieser Methode wird ein Koroutinenwechsel ausgelöst.
virtual void action () = 0;
Die Methode action stellt die eigentliche Aufgabe der Koroutine dar.
23.05.2019 Betriebssystembau: 5. Übung 10
Dispatcher
toc
Coroutine
Application
Scheduler Entrant
Chain
Queue
...
user
machine
thread object
Aufgabenteil b: DispatcherKoroutinenwechselüber den Dispatcher
23.05.2019 Betriebssystembau: 5. Übung 11
Arbeitsteilung● Scheduler
– trifft strategische Entscheidungen zur Ablaufplanung– betrachtet wird immer eine Menge lauffähiger Fäden
● die Fäden sind allgemein in einer CPU-Warteschlange aufgereiht● die Sortierung erfolgt entsprechend der Scheduling-Strategie
– der aktuell laufende Prozess ist immer von der Entscheidung mit betroffen● dazu muss der laufende Faden jederzeit „greifbar“ sein● vor der Umschaltung ist ist der laufende Faden (beim Dispatching) zu vermerken
– ein ausgewählter neuer Faden wird dem Dispatcher übergeben● Dispatcher
– setzt die Entscheidungen durch undschaltet Fäden um (mit Hilfe von resume)
– merkt sich den gestarteten Faden
23.05.2019 Betriebssystembau: 5. Übung 12
DispatcherBeschreibung
Der Dispatcher verwaltet den Life-Pointer, der die jeweils aktive Koroutine angibt, und führt Prozesswechsel durch.
Methoden
Dispatcher ()
Der Konstruktor initialisiert den Life-Pointer mit Null, um anzuzeigen, dass noch keine Koroutine bekannt ist.
void go (Coroutine& first)
Mit dieser Methode wird die Koroutine first im Life-Pointer vermerkt und gestartet.
void dispatch (Coroutine& next)
Diese Methode setzt den Life-Pointer auf next und führt einen Koroutinenwechselvom alten zum neuen Life-Pointer durch.
Coroutine* active ()
Hiermit kann abgefragt werden, welche Koroutine gerade im Besitz des Prozessors ist.
23.05.2019 Betriebssystembau: 5. Übung 13
Dispatcher
toc
Coroutine
Application
Scheduler Entrant
Chain
Queue
...
user
machine
thread object
Aufgabenteil c: Kooperatives SchedulingKoroutinenwechselüber Scheduler
23.05.2019 Betriebssystembau: 5. Übung 14
EntrantBeschreibung
Die Klasse Entrant erweitert die Klasse Coroutine um die Möglichkeit, ineinfach verkettete Listen eingetragen zu werden, insbesondere auch in dieReady-Liste des Schedulers. Die Verkettungsmöglichkeit wird durch dieAbleitung von Chain erreicht.
öffentliche Methoden
Entrant (void* tos); Der Entrant-Konstruktor gibt nur den Parameter tos an den Koroutinen-Konstruktor weiter.
Vorsicht Mehrfachvererbung! Coroutine und Chain stehen in keiner Vererbungsbeziehung. Expliziter Type-Cast von einem zum anderen führt zu Problemen!
Vorsicht Mehrfachvererbung! Coroutine und Chain stehen in keiner Vererbungsbeziehung. Expliziter Type-Cast von einem zum anderen führt zu Problemen!
23.05.2019 Betriebssystembau: 5. Übung 15
SchedulerBeschreibung
Der Scheduler verwaltet die Ready-Liste (ein privates Queue Objekt der Klasse), also die Liste der lauffähigen Prozesse (Entrant Objekte). Die Liste wird von vorne nach hinten abgearbeitet. Dabei werden Prozesse, die neu im System sind oder den Prozessor abgeben, stets an das Ende der Liste angefügt.
Öffentliche Methodenvoid ready (Entrant& that)
Mit dieser Methode wird der Prozess that beim Scheduler angemeldet. Er wird an das Ende der Ready-Liste angefügt.
void schedule () Diese Methode setzt das Scheduling in Gang, indem der erste Prozess von der Ready-Liste entfernt und aktiviert wird.
void exit () Hiermit kann sich ein Prozess selbst beenden. Er wird nun nicht wieder an das Ende der Ready-Liste angefügt. Statt dessen wird nur der erste Prozess von der Ready-Liste heruntergenommen und aktiviert.
void kill (Entrant& that) Mit dieser Methode kann ein Prozess einen anderen (that) beenden. Der Prozess that wird einfach von der Ready-Liste entfernt und erhält somit nie wieder den Prozessor.
void resume () Hiermit kann ein Prozesswechsel ausgelöst werden, ohne dass der aufrufende Entrant wissen muss, welche anderen Entrant Objekte im System existieren und welcher davon sinnvollerweise aktiviert werden sollte.
23.05.2019 Betriebssystembau: 5. Übung 16
Agenda● Aufgabe 4: Tipps & Tricks
● Aufgabe 5: Überblick
● PIT-Programmierung
● Präemptives Scheduling
23.05.2019 Betriebssystembau: 5. Übung 17
Aufgabe 5: Zeitscheiben-Scheduler● Ziel: Schutz kritischer Betriebssystem-Abschnitte mit Hilfe
des Pro-/Epilog-Modells– Synchronisation der Aktivitäten innerhalb von OO-Stubs:
soll auf Verwendung des Pro-/Epilog-Modells umgestellt werden– Verwendung einer grobgranularen Locking-Strategie,
Definition einer Systemaufrufschnittstelle
● Scheduler: soll ausgelöst durch den Timer-Interrupt Threads verdrängen können
23.05.2019 Betriebssystembau: 5. Übung 18
Aufgabe 5: Zeitscheiben-Scheduler● Implementierung der Klassen
Guarded_Scheduler, Thread, PIT und Watch
● Aufruf von geschützten Methoden des Schedulers:
– globale Variable scheduler nicht länger vom Typ Scheduler,
– sondern Instanz der Klasse Guarded_Scheduler
23.05.2019 Betriebssystembau: 5. Übung 19
Aufgabe 5: Zeitscheiben-Scheduler
Queue
Chain
Keyboard WatchScheduler Entrant
thread
Guarded_Scheduler Thread
Application
PIT
guard
device
object
Guard
Locker
syscall
application
machine
Gate
23.05.2019 Betriebssystembau: 5. Übung 20
Präemptiver Fadenwechsel● CPU-Entzug durch Zeitgeberunterbrechung
– die Unterbrechung ist „nur“ ein impliziter Aufruf– Behandlungsroutine kann resume aufrufen
Achtung: So geht es normalerweise nicht, denn resume trifft eine Scheduling-Entscheidung. Bei den notwendigen Datenstrukturenist Unterbrechungssynchronisation zu beachten!
Achtung: So geht es normalerweise nicht, denn resume trifft eine Scheduling-Entscheidung. Bei den notwendigen Datenstrukturenist Unterbrechungssynchronisation zu beachten!
Betr
iebs
syst
em
<app1>
<app2>re
sum
e
<handler>
<resume>
ret
resume
ret
sti()
iret
Anw
endu
ngen
23.05.2019 Betriebssystembau: 5. Übung 21
Fadenwechsel im Epilog● Implementierung
– Scheduler-Daten (Liste der laufbereiten Fäden)werden auf der Epilogebene angesiedelt
– alle Systemfunktionen, die diese Daten manipulieren,müssen zuvor die Epilog-Sperre anfordern (enter/leave)
● Faden erzeugen, Faden beenden, freiwilliger Fadenwechsel, …● Grundregel beim Fadenwechsel
– der abgebende Faden fordert die Sperre an(ggf. implizit bei der Unterbrechungsbehandlung)
– der aktivierte Faden muss die Sperre freigeben● Tipps
– aus dem Epilog heraus nie enter Aufrufen (Doppelanforderung)– Grundregel (s.o.) gilt auch für die erste Fadenaktivierung(!)
Mehr dazu in der Übung jetzt ...Mehr dazu in der Übung jetzt ...
23.05.2019 Betriebssystembau: 5. Übung 22
Aufgabe 5: Klasse Guarded_Scheduler● implementiert die Systemaufrufschnittstelle zum Scheduler● angebotene Methoden werden direkt auf die Methoden der
Basisklasse abgebildet– Ausführung wird aber jeweils mit Hilfe eines Secure-Objekts geschützt– Es werden keine Entrant-, sondern Thread-Objekte behandelt.
● Öffentliche Methoden:– void ready (Thread& that)
● Mit dieser Methode wird der Prozess that beim Scheduler angemeldet– void exit ()
● Hiermit kann sich ein Prozess selbst beenden.– void kill (Thread& that)
● Mit dieser Methode kann ein Prozess einen anderen (that) beenden.– void resume ()
● Hiermit kann ein Prozesswechsel ausgelöst werden.
23.05.2019 Betriebssystembau: 5. Übung 23
Aufgabe 5: Klasse Guarded_Scheduler● Tipp
– Da die Methoden von Guarded_Scheduler die gleichen Namen haben wie die der Basisklasse Scheduler, verdecken sie diese normalerweise
– Verdeckung verhindern: explizites Nennen der Basisklasse bei Aufruf
– Beispiel:
Guarded_Scheduler scheduler;Application appl1, appl2;
scheduler.ready (appl1); // Methode von Guarded_Schedulerscheduler.Scheduler::ready (appl2); // Methode von Scheduler
23.05.2019 Betriebssystembau: 5. Übung 24
Aufgabe 5: Klasse Thread● implementiert die Benutzerschnittstelle eines Fadens
● Zur Zeit ist Thread nichts weiter als ein neuer Name für die Klasse Entrant …
– ... das wird sich in Aufgabe 6 noch ändern.
● Öffentliche Methoden:– Thread (void* tos)
● Der Konstruktor leitet den Parameter tos an den Konstruktor der Basisklasse Entrant weiter.
23.05.2019 Betriebssystembau: 5. Übung 25
Aufgabe 5: Klasse PIT● steuert den Programmable Interval Timer (PIT) des PCs● Öffentliche Methoden
– PIT (int us)
● Konstruktor: Timer-Initialisierung, regelmäßige Unterbrechungen in Abständen von etwa us Mikrosekunden
● Auflösung des Timerbausteins maximal 838 ns keine ganz exakte Einstellung im Mikrosekundenbereich möglich→
– int interval ()
● Gibt an, welches Unterbrechungsintervall eingestellt wurde.– void interval (int us)
● Stellt das Unterbrechungsintervall neu ein.
23.05.2019 Betriebssystembau: 5. Übung 26
Aufgabe 5: Klasse Watch● Sorgt für Behandlung der Zeitgeberunterbrechungen● Verwaltet Zeitscheiben
und löst bei Bedarf Prozesswechsel aus● Öffentliche Methoden
– Watch (int us)● Timer-Initialisierung, siehe PIT
– void windup ()● „zieht die Uhr auf“● Dazu muss sich das Watch-Objekt bei der Plugbox plugbox anmelden● ... und mit Hilfe des globalen PIC-Objekts pic die Unterbrechungen des
Timer-Bausteins (repräsentiert durch das globale Watch Objekt) zulassen– void prologue ()
● Enthält den Prolog der Unterbrechungsbehandlung.– void epilogue ()
● In dieser Methode wird der Prozesswechsel ausgelöst.
23.05.2019 Betriebssystembau: 5. Übung 27
Agenda● Aufgabe 4: Tipps & Tricks
● Aufgabe 5: Überblick
● PIT-Programmierung
● Präemptives Scheduling
23.05.2019 Betriebssystembau: 5. Übung 28
Der Timer 8254: Verwendung● PCs besitzen zwei Timer-Bausteine vom Typ 8253 oder 8254
– Mittlerweile natürlich auch im Chipsatz integriert● Diese werden mit einem Takt von 1,19318 MHz betrieben
– Unabhängig von der CPU-Frequenz!– Warum so ein „krummer“ Takt?
● 1,19318 MHz * 4 = 4,77 MHz● … die Taktfrequenz des Ur-IBM-PC!● … damals also doch nicht so unabhängig von der CPU-Frequenz
– Warum eine krumme Taktfrequenz wie 4,77 MHz für den Ur-PC?● 4,77 MHz * 3 = 14,31816 MHz● … das ist die Grundfrequenz, die für NTSC-Fernsehen benötigt wird● … also gibt es fertige, billige Quarze● … und man kann die Frequenz gleich zur Video-Erzeugung verwenden!
23.05.2019 Betriebssystembau: 5. Übung 29
Struktur des 8254
(aus dem Intel-Datenblatt zum 8254)
23.05.2019 Betriebssystembau: 5. Übung 30
Nutzung des 8254 im PC● Bezeichnung des 8254: „PIT“
– Programmable Interval Timer
● besitzt drei unabhängige Zähleinheiten
– Unterschiedliche Verwendung im PC:
● Jeder Zähler besitzt einen eigenen Ausgang (OUTx)
23.05.2019 Betriebssystembau: 5. Übung 31
Nutzung des 8254 im PC● Die verschiedenen Verwendungen der Kanäle ergeben sich
aus der Verdrahtung der Ausgänge auf den PC-Mainboard:
– OUT0 führt an Int 0 des (1.) PIC 8259
– OUT1 führt an Kanal 0 des DMA-Controllers 8237
– OUT2 führt (über ein schaltbares Gatter) an einen Verstärker
– OUT0 des 2. PIT führt an den NMI-Eingang der CPU
● Über das NMI Mask Bit
● Im PC sind „Non Maskable“-Interrupts also doch maskierbar …
23.05.2019 Betriebssystembau: 5. Übung 32
Struktur eines Zählers im 8254
(aus dem Intel-Datenblatt zum 8254)
23.05.2019 Betriebssystembau: 5. Übung 33
Programmierung des 8254● Jeder PIT kann mit Hilfe von vier Ports angesprochen werden:
● Alle Ports sind 8 Bit breit!
– Um 16-Bit-Zählerwerte in den PIT zu schreiben, muss – wieder – eine besondere Vorgehensweise zum Einsatz kommen.
23.05.2019 Betriebssystembau: 5. Übung 34
Programmierung des 8254● Zunächst muss dem 8254 über ein Steuerwort gesagt
werden, was er als nächstes tun soll:
23.05.2019 Betriebssystembau: 5. Übung 35
Programmierung des 8254● Modus: bestimmt Zähler-Arbeitsweise, und ob er mit Hilfe
seiner OUTx-Leitung externe Ereignisse auslöst● Modus 0: Herunterzählen von Startwert bis 0
– Alle 838 ns– Wenn der Zählerwert 0 ist, wird die OUTx-Leitung auf „1“ gesetzt
● Modus 2: geeignet für Erzeugung periodischer Impulse– Erreichen der 0: kurzer Impuls auf OUTx, Reinitialisierung mit
Startwert● Einstellung eines 16-Bit-Zählerwertes: drei out-Befehle
– Schreiben des Steuerwortes– Schreiben des nieder- und höherwertigen Bytes des Zählerwerts
23.05.2019 Betriebssystembau: 5. Übung 36
Spaß mit dem 8254● Zähler-„Tick“-Intervall: abhängig von Basisfrequenz
– Der Zähler teilt die Basisfrequenz dann ganzzahlig.
– z.B. initialer Zählerwert 1: f = 1,19318 MHz wird erzeugt
– z.B. initialer Zählerwert 2: f = 0,59659 MHz usw.● „Defaultwert“ für den Timer 0 im IBM PC: „0“
– PIT zählt erst herunter und vergleicht dann 2→ 16 x Herunterzählen
→ f = 1,19318 MHz / 216 ≈ 18,2 Hz
– Das ist die Standard-Interruptfrequenz im PC.● Wir können also nicht beliebige Frequenzen generieren, aber
immerhin eine ganze Menge …
23.05.2019 Betriebssystembau: 5. Übung 37
Agenda● Aufgabe 4: Tipps & Tricks
● Aufgabe 5: Überblick
● PIT-Programmierung
● Präemptives Scheduling
23.05.2019 Betriebssystembau: 5. Übung 38
Präemptives Scheduling● … soll dafür sorgen, dass kein Prozess/Faden die CPU
monopolisiert. Bei OO-StuBS gilt das nur eingeschränkt:– Faden A rechnet 18 ms und ruft dann freiwillig resume() auf– Faden B rechnet dauerhaft und gibt nie freiwillig die CPU ab
– Wer mag, darf gerne echtes Round Robin oder Virtual Round Robin in sein OO-StuBS einbauen!
20 ms Periode
resume() resume() resume()Unfair! Effektiv bekommt Bnur 10% der CPU-Zeit.Unfair! Effektiv bekommt Bnur 10% der CPU-Zeit.