Ziel der vorliegenden Arbeit war es, durch den Entwurf und die
Implementierung der UNIX-Prozeßverwaltung als einer sehr kritischen
und wichtigen Komponente die Grundlage für eine UNIX-Emulation auf L3
zu legen. Dazu sollten unter Beachtung von Kompatibilität auf
Bibliotheksebene und höchstmöglicher Effizienz UNIX-Prozesse auf
L3-Tasks und Threads abgebildet werden. Dieses Kapitel gibt einen
Überblick über die erzielten Resultate und einen Ausblick auf die
weitere Entwicklung der Emulation. 7.1 Stand der Arbeit
Im Verlaufe der Arbeit entstand der im vorangegangenen beschriebene Entwurf und eine prototypische Implementation. Hauptpunkt der Arbeit war die Prozeßverwaltung, die durch das Zusammenspiel zwischen Emulationsbibliothek und Prozeßserver realisiert wird.
Prozeßserver und Emulationsbibliothek sind in der gegenwärtigen Fassung auf die Aspekte der Programmentwicklung ausgelegt, enthalten also noch viele Sequenzen, die einzig und allein dem Test des Ablaufs der Emulation dienen. So wurde beispielsweise ein Mechanismus implementiert, der Systemrufe und ihre Parameter sowie Testausschriften der Bibliothek auf dem Testmonitor protokolliert und so ein Verfolgen des Ablaufs ermöglicht. Dadurch sind noch keine verläßlichen Aussagen zur Effizienz möglich.
Einer der Meilensteine des Projekts war, eine Shell zum Laufen zu bringen. Dies ist mit den implementierten Funktionen möglich. Die Shell akzeptiert Eingaben, erzeugt Sohn-Prozesse über fork() und behandelt Ein/Ausgabeumleitung korrekt. Zur Charakterisierung des Standes sei erwähnt, das eine Eingabe von
echo text > test.txt
von der Shell korrekt abgearbeitet wird, d. h. eine Folge von Aufrufen
von fork(), wait(), open(), sigsetmask() u.a.m. abgearbeitet
wird. 7.2 Erfahrungen der Entwicklung
Ein großes Problem der Arbeit war die Einarbeitung in L3 sowie die Schaffung einer Entwicklungsumgebung. Die hier auftretenden Probleme wurden erheblich unterschätzt. Am Anfang der Arbeit stand die Beschaffung von Informationen über Funktionalität und Strukturen des L3-Kerns. Darauf aufbauend wurde eine Dokumentation erarbeitet und eine Bibliothek für die verschiedenen Kern-Dienste und Protokolle implementiert. Das erarbeitete Wissen und die implementierte Funktionalität deckt inzwischen einen großen Teil der L3-Funktionalität ab. Ergänzt um die im Laufe der Arbeit gewonnenen Erkenntnisse kann das als Grundlage für die nachfolgenden Arbeiten dienen.
Ein anderer Aspekt der Arbeit war der Nachweis der Eignung von L3 für
die Umsetzung eines solchen Projekts. Es hat sich gezeigt, daß sich
mit Hilfe der vorhandenen Abstraktionen und Funktionen eine
UNIX-Emulation entwerfen und umsetzen läßt. Dabei wurde auch das Ziel
erreicht, die Emulation bis auf zwei Ausnahmen ohne Kernmodifikation
umzusetzen. Diese Ausnahmen beseitigten lediglich einige
Inkonsistenzen im Entwurf des Kerns. 7.3 Aspekte der weiteren Entwicklung
Abschließend sollen noch ein paar Gedanken zur weiteren Entwicklung der
Emulation dargelegt werden. 7.3.1 Entwicklung in nächster Zeit
Auf kurze Sicht soll die Prozeßverwaltung in ihrer Funktionalität vervollständigt und in einen stabilen Zustand überführt werden. Dabei muß auch über eine Umsetzung nach C++ nachgedacht werden. Die Wahl der Programmiersprache C für die Entwicklung der Prozeßverwaltung war primär eine Entscheidung anhand der verfügbaren Hilfsmittel. Da jetzt alle Möglichkeiten zum Einrichten einer richtigen Cross-Entwicklungsumgebung vorhanden sind, steht dieser Umsetzung nichts mehr im Wege.
Die implementierte Variante setzt primär auf einen sicheren Ablauf und ist deshalb im Effizienzverhalten sicherlich noch nicht optimal. Die hier vorhandenen Reserven müssen bei der Vervollständigung der Funktionalität ausgenutzt werden. Dabei sind speziell folgende Punkte von Interesse:
Das Optimum ist hier das Ausnutzen eines einzigen Datenraums. Die implementierte Struktur geht von einem eigenen Datenraum für die Halde aus. Dieser läßt sich aber wie beschrieben auch im Standarddatenraum unterbringen.
Auf dem Pentium ist es möglich, durch eine andere Art der Adreßraumimplementierung einen Geschwindigkeitsgewinn beim Adreßraumwechsel zu erzielen. Diese Adreßräume sind dann allerdings nur noch ein Megabyte groß. Hier muß die Struktur der Emulationstask angepaßt werden. Zusätzlich muß auch das Erzeugen eines solchen Adreßraums möglich sein, wozu der Supervisor überarbeitet werden muß.
Eine der aufwendigsten Teile der fork()-Operation ist die Erzeugung der neuen Task. Diese ließe sich durch Emulations-Tasks einsparen, wenn sich die Emulationstasks bei einem exit() nicht beenden, sondern auf ein neues auszuführendes Programm warten. Der Prozeßserver hätte dann einen Pool von Emulationstasks in der Hand, mit denen er durch das Senden eines neuen Standarddatenraums neue UNIX-Prozesse realisieren kann. Dabei muß allerdings die setuid-Semantik berücksichtigt werden, damit hier keine Sicherheitslücken entstehen.
Einer der nächsten Meilensteine ist dann die Integration des Fileservers[25] und des in der Entwicklung befindlichen Terminalservers. Die in der jetzigen Emulation genutzten Server sind Prototypen bzw. direkt in der Bibliothek kodierte Aufrufe der L3-Terminalserver.
Einer der Punkte, die beim Entwurf und der Implementierung etwas vernachlässigt wurden, ist die Problematik von Fehlern in der Emulation, die durch fehlerhafte Parameter eines Systemrufs hervorgerufen werden. Zum Beispiel übergibt read() die Adresse eines Puffers, in den die angeforderten Daten geschrieben werden sollen. Ist diese Adresse nicht oder nur read only gemappt, führt das zu einem Fehler in der Emulation. Hier sind prinzipiell zwei Ansätze möglich:
Beide Möglichkeiten gestatten der Bibliothek die Rückgabe des Wertes
EFAULT, der bedeutet, daß die Parameter in einem Bereich außerhalb
des verfügbaren Adreßbereichs liegen.
7.3.2 Entwicklung auf lange Sicht
Auf lange Sicht müssen die fehlenden Funktionskomplexe der Emulation durch Server bereitgestellt werden. Dazu gehören:
Hier müßten die L3-Implementationen der verschiedenen Dienste wie Telnet oder Ftp und die darunterliegenden Protokolltreiber für TCP/IP analysiert werden. Darauf aufbauend müßte ein Entwurf einer Protokollarchitektur auf L3 gemacht werden.
Ein wichtiger Interprozeßkommunikationsmechanismus in UNIX sind die Sockets. Hier müßte ein Entwurf eines Socket-Servers vorgenommen werden, der zumindest als Anlaufpunkt für zwei kommunikationswillige Prozesse dient. Ist die Verbindung hergestellt, ist es eventuell möglich, die Kommunikation zwischen den beiden Prozessen ohne den Server abzuwickeln.
Einer der bedeutendsten Mechanismen sind die Pipes. Sie können evtl. mit Hilfe der UNIX-Domainsocket realisiert werden.
Weiterhin können Betrachtungen zum Thema Einsatz des externen Pagers im Rahmen der UNIX-Emulation angestellt werden. Denkbar ist ein Entwurf eines Exec-Servers, der
Ein fork() wird in der Regel direkt von einem exec() gefolgt. Die Shell erzeugt beispielsweise einen Sohnprozeß, der Sohn setzt einige Signalbehandlungsroutinen, leitet Ein-/Ausgabe um und führt ein neues Programm aus. Dabei entstehen Seitenfehler auf ein oder zwei Seiten, die zu einem entsharen der Seiten führen. Hier könnte unter Umständen eine Optimierung zur Reduzierung der zu kopierenden Seiten eingebaut werden. Hinzu kommt, das kein Datenraum mehr transferiert werden müßte, da die Id des Datenraumes nur noch eine interne Id des Execservers ist.