% Studienarbeit von Markus Breilmann
%
% Universitaet Hamburg
% Fachbereich Informatik
% Arbeitsbereich DBIS
%
% Kapitel 4: Anpassungen durch die Portierung


\chapter{Portierung auf Apple Macintosh}
\label{Portierung auf Apple Macintosh}

Ziel der vorliegenden Arbeit ist die Portierung der Tycoon Maschine auf das Apple Betriebssystem. In diesem Kapitel werden die daf"ur notwendigen Anpassungen und Erweiterungen des bestehenden Systems und deren Ursachen erl"autert; es stellt damit den eigentlichen Kern der Arbeit dar.

\section{Das Apple Macintosh Betriebssystem: MacOS}
\label{MacOS}

Das Macintosh Betriebssystem kann als das erste kommerziell erfolgreiche Betriebssystem angesehen werden, das eine graphische Benutzeroberfl"ache einsetzt. Die Entwicklung reicht in die fr"uhen 80er Jahre zur"uck. Damit verbunden sind einige veraltete und propriet"are Konzepte innerhalb der Systemarchitektur. Sie verursachen einen weit h"oheren Aufwand bei der Portierung als Punkte, die gewöhnlich in der Literatur als kritisch geschildert werden (wie z.B. Sprachdialekte oder Speicherwortgr"o"sen). Diese Problemstellungen zeichneten sich bereits bei dem Entwurf des Tycoon-Systems ab, eine technisch zufriedenstellende Lösung konnte jedoch unter dem Sun Betriebssystem nicht vorweggenommen werden.

Die Apple Macintosh System-Software kann in drei Bereiche eingeteilt werden: das eigentliche Betriebssystem, die Macintosh {\sf ``Toolbox''} und zus"atzliche System-Software. Entwicklern bietet diese Umgebung eine F"ulle von Funktionen f"ur die Programmierung der graphischen Benutzeroberfl"ache, den Einsatz Apple-eigener Werkzeuge aber auch zur Bew"altigung systemnaher Aufgaben. Die Funktionen eines Aufgabenbereiches sind in sogenannten {\sf ``Managern''} zusammengefa"st. Die Funktionen zur Speicherwaltung ergeben z.B. den {\sf ``Memory Manager''}. In einigen Ausnahmen wird synonym\footnote{Die Implementation von ``Packages'' und ``Managern'' ist unterschiedlich; die Verwendung der Funktionen gestaltet sich jedoch f"ur den Anwendungsprogrammierer in beiden F"allen gleich.} auch der Ausdruck {\sf ``Package''} verwendet (z.B. {\sf ``Standard File Package''}). Es folgt ein "Uberblick "uber die wichtigsten Manager und deren Stellung in der System-Software:
\begin{itemize}
\item Betriebssystem
\begin{description}
\item [Process Manager:] Verwaltet das Starten, Koordinieren und Beenden von Applikationen.
\item [Memory Manager:] Erm"oglicht das dynamische Allozieren und Freigeben von Speicher innerhalb einer Applikationspartition.
\item [Virual Memory Manager:] Verwaltet virtuellen Speicher (Auslagern von Daten aus dem RAM auf Festplatte).
\item [File Manager:] Erlaubt den Zugriff auf das Dateisystem wie "Offnen, Lesen, Schreiben und Schlie"sen von Dateien.
\item [Time Manager:] Stellt Funktionen f"ur die periodische Abarbeitung von Routinen zur Verf"ugung.
\end{description}
\item Toolbox
\begin{description}
\item [QuickDraw:] "Ubernimmt alle Bildschirmausgaben wie Graphik und Text.
\item [Windows Manager:]  Erzeugung und Verwaltung von Fenstern
\item [Scrap Manager:] Erm"oglicht das Ausschneiden und Einf"ugen von Daten unter Applikationen
\item [Standard File Package:] Stellt Standardauswahlfenster f"ur die Dateiauswahl bereit.
\item [Menu Manager:] Erzeugt und verwaltet die Men"uleiste einer Applikation.
\item [Event Manager:] Informiert eine Applikation "uber Benutzeraktivit"aten und Programmausf"uhrung. Erlaubt die Kommunikation zwischen Applikationen.
\item [TextEdit:] Stellt einfache Text-Editor Funktionalit"at zur Verf"ugung.
\end{description}
\item andere System-Software
\begin{description}
\item [QuickTime:] Bietet Funktionen zum Abspielen von Ton- und Bildsequenzen.
\item [Interapplication Communication:] Regelt die Kommuniktion unter verschiedenen Applikationen.
\item [Communication Toolbox:] Funktionen f"ur die Kommunikation "uber Modem etc.
\item [World-Wide Support:] Unterst"utzung f"ur beliebige Schriftsysteme.
\end{description}
\end{itemize}


\section{Das Vorgehen bei der Portierung}
\label{Vorgehen bei der Portierung}

F"ur die "Ubersetzung der Tycoon Maschine und des DBIS-eigenen Objektspeichers wurde die Apple Entwicklungsumgebung ``Macintosh Programmers Workshop'' (MPW, Version ETO\#16) eingesetzt. Sie unterst"utzt sowohl die Prozessorarchitektur Motorola 68k als auch die neue PowerPC Prozessorgeneration. 
Die Portierung erforderte eine Reihe von Anpassungen und zus"atzlicher Funktionen. Der C-Pr"aprozessor bietet die M"oglichkeit, Programmcode in Abh"angigkeit von Pr"aprozessorvariablen zu "ubersetzen. Die Include-Datei {\sf ``rtstd.h''} enth"alt Anweisungen, um bei der "Ubersetzung der C-Quelltexte das Zielbetriebssystem zu ermitteln und entsprechende Schalter zu setzen. Im Falle des MacOS wird die Pr"aprozessorvariable {\sf ``rtstd\_LIB\_MPW''} definiert. Zus"atzlich wird bei der "Ubersetzung f"ur die PowerPC-Architektur durch die MPW-Entwicklungsumgebung die Variable {\sf ``powerc''} definiert. Die Abbildung \ref{sourcePraeprozessor} zeigt ein Beispiel f"ur den Einsatz des C-Pr"aprozessors f"ur bedingte "Ubersetzung.

\begin{figure}
\begin{verbatim}
#ifdef rtstd_LIB_MPW
# include <FCntl.h>
# include "rtmac.h"
#else
# include <sys/types.h>
# include <sys/time.h>
# include <sys/uio.h>
#endif
\end{verbatim}
\caption{Der Einsatz von Präprozessorkommandos}
\label{sourcePraeprozessor}
\end{figure}

Alle zus"atzlichen Funktionen, die f"ur die Macintosh-Applikation n"otig wurden, sind im Modul {\sf ``rtmac''} zusammengefa"st.

\section{Tycoon als Macintosh-Applikation : Eine Konsole f"ur Textein-/-ausgabe}
\label{Abs. Unix-Console}

Die Ein-/Ausgabe von Text erfolgt unter X-Windows (Unix) "uber eine sogenannte Konsole: die Streams {\sf ``STDIN''}, {\sf ``STDOUT''} und {\sf ``STDERR''} sind dazu mit einem Fenster bzw. der Tastatur verbunden. Eingaben "uber die Tastatur werden in das Fenster geleitet und k"onnen "uber den Stream {\sf ``STDIN''} gelesen werden. Ausgaben "uber die Streams {\sf ``STDOUT''} und {\sf ``STDERR''} werden ebenfalls in dem genannten Fenster dargestellt. Jedes Unix-Programm kann diese Funktionalit"at automatisch nutzen, ohne da"s zus"atzlicher Programmieraufwand n"otig wird.

Bei der Portierung des Tycoon-Systems auf das Apple Macintosh Betriebssystem st"o"st man in diesem Zusammenhang auf mehrere Probleme. X-Windows ist eine Erg"anzung des Unix-Betriebssystems, um dem Anwender eine graphische Benutzeroberfl"ache zu bieten. Sowohl X-Windows als auch MacOS verfolgen einen ereignisorientierten Ansatz bei der Kommunikation mit dem Benutzer: eine Aktion des Benutzers l"ost eine Reaktion der graphischen Oberfl"ache bzw. der Applikation aus. Ein gro"ser Unterschied liegt jedoch in der Instanz, die derartige Ereignisse verarbeitet. X-Windows stellt nicht nur die Konsole-Funktionalit"at zur Verf"ugung, sondern "ubernimmt f"ur die Applikation die Behandlung aller Ereignisse wie Tastatureingaben, Verschieben des Fensters oder des sichtbaren Textes innerhalb des Fensters. Damit bleibt der Einsatz einer graphischen Benutzeroberfl"ache f"ur die Applikation und somit den Programmierer transparent, der Datenaustausch mit dem Benutzer erfolgt "uber die Standardschnittstelle Streams. Diese Schnittstelle wird von Tycoon intensiv genutzt.

Unter dem Apple Macintosh Betriebssystem mu"s das Anwendungsprogramm selbst m"ogliche Ereignisse erkennen und entsprechende Reaktionen ausl"osen. Da zu diesen Ereignissen auch Eingaben "uber die Tastatur z"ahlen, fehlt die Funktionalit"at der Streams STDIN, STDOUT und STDERR, wie sie von Unix bekannt ist. Die Verarbeitung der Eingabe mu"s vollst"andig durch die jeweilige Applikation gehandhabt werden, wozu auch die Ausgabe auf dem Bildschirm bzw. in ein Fenster z"ahlt.

Aus diesem Umstand ergibt sich f"ur die Portierung, da"s zum einen Funktionen in das Tycoon-System integriert werden m"ussen, die Ereignisse der Benutzeroberfl"ache verarbeiten, zum anderen mu"s das von Unix bekannte Stream-Verhalten nachgebildet werden.

Die MPW Entwicklungsumgebung umfa"st die sogenannte SIOW-Bibliothek (``Simple Input/Output Window''),  die zu einer beliebigen Applikation gebunden werden kann. Diese Bibliothek erzeugt, wie der Name vermuten l"a"st, ein einfaches Texteditorfenster und "ubernimmt die Behandlung der damit verbundenen Ereignisse. Sie bietet aber nicht die notwendige Funktionalit"at bez"uglich der Textein-/-ausgabe-Streams. Dar"uber hinaus entspricht das Verhalten eines Texteditors nicht exakt dem einer Konsole, da Text an beliebigen Stellen eingef"ugt werden kann. Diese Punkte machen den Einsatz einer eigenst"andigen L"osung notwendig.

F"ur die Verwaltung der Benutzeroberfl"ache wurde auf der Grundlage einer Apple Beispielapplikation ein eingeschr"ankter Texteditor realisiert, dessen F"ahigkeiten an die einer Unix-Konsole angepa"st wurden:
\begin{itemize} 
\item Eingaben sind lediglich an der Einf"ugemarke in der untersten Zeile m"oglich. 
\item Texte an einer beliebigen Stelle des Textfensters k"onnen in die Zwischenablage kopiert werden.
\item Texte aus der Zwischenablage k"onnen an der Stelle der Einf"ugemarke eingesetzt werden.
\item Eingaben werden mit der Taste ``Return'' oder ``Enter'' abgeschlossen/best"atigt.
\end{itemize}
Dieser Texteditor wird im folgenden als ``Tycoon-Konsole'' bezeichnet.

Das Kernst"uck einer typische Apple Applikation bildet die sogenannte ``Event-Loop''. Dies ist eine Endlosschleife, in der alle erforderlichen Ereignisse wie Benutzereingaben usw. erkannt und entsprechende Funktionen f"ur deren Bearbeitung aufgerufen werden. Dieser Ansatz l"auft dem des Tycoon-Systems zuwider, bei dem der Byte-Code-Interpreter ebenfalls durch eine Endlosschleife realisiert ist. Es sto"sen also zwei konkurrierende Sichten aufeinander, bei denen einmal der Benutzerinteraktion, im anderen Fall der Berechnung mehr Bedeutung  einger"aumt wird.

Bei der Portierung wurde der Tycoon-Ansatz gew"ahlt, um eine Kopplung zu erm"oglichen: die Ereignisschleife (``Event-Loop'') wurde zu einer Funktion aufgel"ost, die bei jedem Aufruf lediglich einmal durchlaufen wird. Diese Funktion hei"st {\sf ``rtmac\_sample''} und wird aus der Tycoon-Interpreterschleife aufgerufen. Sie umfa"st eine Reihe von Vergleichsoperationen und gibt f"ur kurze Zeit die Kontrolle des Programmes an das Betriebssystem ab. Dies ist notwendig, damit wichtige Systemfunktionen ausgef"uhrt werden k"onnen oder die Kontrolle an eine andere Applikation "ubergeben werden kann. Aus diesem Umstand ergibt sich eine hoher Zeitbedarf der Funktion {\sf ``rtmac\_sample''}, der sich negativ auf die Abarbeitung von Tycoon-Programmen durch den Interpreter auswirkt. Als L"osung wurde ein Mechanismus eingef"uhrt, der {\sf ``rtmac\_sample''} lediglich nach einer bestimmten Anzahl von Byte-Codes aufruft. Diese Zahl wurde heuristisch bestimmt und stellt einen Kompromi"s zwischen Rechenleistung des Tycoon-Interpreters und Reaktionsf"ahigkeit der Tycoon-Applikation auf Benutzerereignisse dar.

Das Tycoon-System ben"otigt an mehreren Stellen die Information, ob f"ur einen Stream neue, unbearbeitete Daten anliegen. Die Funktion {\sf ``rtfile\_ready''} beschafft diese Information "uber verschiedene Stream- oder Dateioperationen: f"ur Dateien wird die Anzahl unverarbeiteter Bytes als Differenz von Dateil"ange und aktueller Dateiposition ermittelt; f"ur STDIN wird die C-Funktion {\sf ``select''} ausgef"uhrt, die den Bool'schen Wert ``true'' liefert, falls neue Daten anstehen. Die {\sf ``select''}-Funktion geh"ort nicht zum C-Sprachumfang der MPW Entwicklungsumgebung. Die Tycoon-Konsole mu"s also nicht nur das bekannte Verhalten von Streams nachbilden, sondern auch eine Funktion bereitstellen, die unbearbeitete Eingaben erkennt.

Die Tycoon-Konsole setzt auf mehreren Managern des Macintosh Betriebssystemes auf. Der Event-Manager stellt die Ereignisse bereit, die in der Funktion {\sf ``rtmac\_sample''} verarbeitet werden. Ein Tastendruck z.B. stellt ein solches Ereignis dar. Der TextEdit-Manager (TE) bietet s"amtliche Funktionen, die f"ur einen Texteditor ben"otigt werden. Dazu geh"ort u.a. die Ausgabe von Zeichen in das Editorfenster.

Die Ein- und Ausgabe von Text in der Tycoon Language wird auf die C-Funktionen {\sf ``read''} und {\sf ``write'' } abgebildet, die ``Tycoon Virtual Machine'' hingegen benutzt die Funktionen {\sf ``fileRead''} und {\sf ``fileWrite''} aus dem Modul {\sf ``rtfile''}. Unter Unix operieren diese Aufrufe direkt auf den Streams {\sf STDIN} und {\sf STDOUT}. Die Anpassungen f"ur den Macintosh m"ussen an dieser Stelle ansetzen: es wurden dazu die  Funktionen {\sf ``rtmac\_read''} und {\sf ``rtmac\_write''} eingef"uhrt. Diese Funktionen pr"ufen, ob der "ubergebene Stream-Parameter dem Konsole- oder Fehler-Stream entspricht. Ist dies der Fall, so werden f"ur {\sf ``read''/``fileRead''} neue Tastaturereignisse verarbeitet, f"ur {\sf ``write''}/{\sf ``fileWrite''} werden die Daten mittels TE-Manager-Funktionen auf dem Bildschirm angezeigt. Handelt es sich um einen Datei-Stream, so werden die normalen  C-Funktionen {\sf ``read''} und {\sf ``write''} aufgerufen.

Die genannten Funktionen k"onnen aus zwei Richtungen aufgerufen werden: aus der Hochsprache Tycoon (TL) oder aus der virtuellen Maschine selbst. F"ur die erste Aufrufart wird wie in Kapitel drei beschrieben eine Hash-Tabelle genutzt, "uber die der ben"otigte Funktionszeiger ermittelt wird. In diese Tabelle werden f"ur ``read'' und ``write'' jedoch die Zeiger auf die Funktionen {\sf ``rtmac\_read''} und {\sf ``rtmac\_write''} eingetragen, um so die ausschlie"sliche Verwendung der neuen Funktionen sicherzustellen. F"ur die zweite Aufrufart wird in den Funktionen {\sf ``fileRead''} und {\sf ``fileWrite''} statt der jeweiligen C-Funktion die angepa"ste Variante aufgerufen. Dies wird durch Pr"aprozessoranweisungen realisiert (siehe Abbildung \ref{sourcefileRead}).

\begin{figure}
\begin{verbatim}
static Word fileRead(rtstream_T stream, void *pBuffer, Word nBytes)
{
  rtdebug_ASSERT(stream);
  rtdebug_ASSERT(stream->hIn);
  rtdebug_ASSERT(pBuffer);
# ifdef rtstd\_LIB\_MPW
    return rtmac_read(stream, pBuffer, nBytes);
# endif
  return fread(pBuffer, /* nItemBytes */ 1, /* nItems */ nBytes,
               (FILE *) stream->hIn);
}
\end{verbatim}
\caption{Die Funktion fileRead}
\label{sourcefileRead}
\end{figure}

F"ur die Eingabe von Text wurde ein Ringpuffer eingef"uhrt, um die noch nicht von Tycoon verarbeiteten Eingaben zwischenzuspeichern und um eine Funktion realisieren zu k"onnen, die anstehenden Text signalisiert. Dazu wurden globale Variablen f"ur den Puffer selbst ({\sf ``rtmac\_sBuffer''}), die aktuelle Lese-({\sf ``rtmac\_iRead''}) und Schreibposition ({\sf ``rtmac\_iWrite''}) in diesem Puffer und ein Z"ahler ({\sf ``rtmac\_iReady''}) eingef"uhrt, der die Anzahl von Zeilenendezeichen speichert. Die Abbildung \ref{picRingbuffer} zeigt die Funktionsweise des Ringpuffers. Der Puffer ist mit 100 KByte gro"sz"ugig bemessen, um auch umfangreiche Quelltexte aufnehmen zu k"onnen. 

\begin{figure}
\psbild{0.6#1}{.}{ringbuffer.epsf}
\caption{Ringpuffer f"ur Textein-/Ausgabe}
\label{picRingbuffer}
\end{figure}

Der Puffer wird in zwei F"allen gef"ullt. Ein Tastendruck wird durch das Ereignis {\sf ``keyDown''} signalisiert. Die entsprechende Behandlungsroutine nutzt die TextEdit-Funktion {\sf ``TEKey''}, um das Zeichen im Fenster auszugeben. Wurde z.B. die R"uckschrittaste (Backspace) gedr"uckt, so wird das letzte Zeichen korrekt gel"oscht. Zus"atzlich wird das Zeichen durch die Funktion ``putChar'' an der aktuellen Schreibposition des Puffers eingef"ugt und die Schreibmarke erh"oht. Das L"oschen von Zeichen erfolgt "uber das R"ucksetzen der Schreibmarke. Wird ein Zeilenendezeichen gelesen, so mu"s es von ``Carriage Return'' in ``Line Feed'' gewandelt werden, da MacOS und Unix unterschiedliche ASCII-Codes verwenden und Tycoon Unix-Format erwartet. Bei Zeilenende wird der Z"ahler {\sf ``rtmac\_iReady''} erh"oht, um zu signalisieren, da"s neue Daten anstehen.

Das Kopieren von Text aus der Zwischenablage in die Tycoon-Konsole ist die zweite M"oglichkeit der Texteingabe. Der Text wird durch die TextEdit-Funktion {\sf ``TEStylePaste''} in das Fenster eingef"ugt und durch {\sf ``bufferText''} in den Tycoon-Ringbuffer "ubernommen. Innerhalb des Puffers mu"s wiederum das ASCII-Zeichen f"ur Zeilenende umgewandelt und der Z"ahler {\sf ``rtmac\_iReady''} entsprechend erh"oht werden.

Die Funktion {\sf ``fileReady''} im Modul {\sf ``rtfile''} liefert unter Unix durch Aufruf von {\sf ``select''} die Information, ob auf einem Stream neue Daten f"ur die Verarbeitung anstehen. Durch eine Pr"aprozessoranweisung wird in der Macintosh-Umgebung statt der 'select'-Anweisung die Funktion {\sf ``rtmac\_fileReady''} ausgef"uhrt, um diese Aufgabe zu erf"ullen. {\sf ``rtmac\_fileReady''} wandelt die Z"ahlervariable {\sf ``rtmac\_iReady''} in einen Bool'schen Wert und liefert diesen als Ergebnis.

\section{Speicherverwaltung}
\label{Abs. Speicherverwaltung}

Die Speicherverwaltung unter dem Macintosh Betriebssystem weist einige Besonderheiten auf, die auf das Alter des Systems zur"uckzuf"uhren sind und die den Programmierer in einigen Punkten einschr"anken. F"ur jede Macintosh-Applikation wird statisch die Gr"o"se des Speicherbereiches in Bytes angegeben, der ihr bei der Programmausf"uhrung zur Verf"ugung steht. Ist zur Laufzeit des Programms dieser Speicherbereich ersch"opft, so bietet das Betriebssystem keine M"oglichkeit, ihn dynamisch zu erweitern. Der Applikationsspeicher ist in mehrere Segmente unterteilt: bei der niedrigsten Speicheradresse beginnt der Heap (Halde), auf dem zur Laufzeit dynamisch Speicherbl"ocke durch die Applikation alloziert werden k"onnen. Dar"uber liegt der Stack (Keller/Stapel) der Applikation. Er w"achst von seiner Obergrenze, der h"oherwertigen Adresse, dem Heap entgegen. Der Bereich zwischen dem Stack und der Obergrenze des Applikationsspeichers nimmt eine Reihe von globalen Variablen und Sprungtabellen auf. Diese Speicheraufteilung ist in Abbildung \ref{picSpeicher} dargestellt. Die Adresse der Grenze zwischen Heap und Stack ist in der globalen Betriebssystemvariablen {\sf ``ApplLimit''} gespeichert. Das Betriebssystem pr"uft in regelm"a"sigen Abst"anden, ob der Stack in den Heap hineingewachsen ist. Dieser Mechanismus wird als {\sf ``Stack-Sniffer''} bezeichnet. Im Falle eines Stack-"Uberlaufs w"urde die Applikation durch das Betriebssystem mit einem Fehler abgebrochen.

\begin{figure}
\psbild{0.6#1}{.}{speicher.epsf}
\caption{Das Speichermodell einer Macintosh-Appliaktion}
\label{picSpeicher}
\end{figure}

Das MacOS umfa"st einige Funktionen f"ur das Allozieren von Speicherbl"ocken. Dabei werden mehrere Arten von Bl"ocken unterschieden: {\sf ``relocatable''}, {\sf ``non relocatable''}, {\sf ``purgeable''} und {\sf ``unpurgeable''}. Bl"ocke vom Typ {\sf ``relocatable''} werden mit der Funktion {\sf ``NewHandle''} angefordert. Sie k"onnen durch das Betriebssystem innerhalb des Heap verschoben werden, um zusammenh"angende Speicherbereiche zu schaffen. Die Funktion {\sf ``NewHandle''} liefert keine direkte physikalische Adresse, sondern einen indirekten Zeiger (ein {\sf ``Handle''}). F"ur jedes ``Handle'' wird ein {\sf ``Master Pointer''} angelegt, ein Eintrag in einer Tabelle ({\sf ``Master Pointer Block''}), die ein Handle auf eine logische Adresse abbildet. Wird ein solcher relokatibler Block durch das Betriebssystem verschoben, so wird in die Tabelle lediglich die neue Startadresse eingetragen, die Adressierung innerhalb des Programms bleibt davon unber"uhrt. In einigen F"allen ist es w"unschenswert, nicht verschiebbare ({\sf ``non relocatable''}) Speicherbl"ocke zu reservieren. Dies ist mit der Funktion {\sf ``NewPtr''} m"oglich, die einen Zeiger liefert, der direkt einen Speicherbereich addressiert. Die Betriebssystem verfolgt mehrere Strategien, um bei Speicheranforderungen zus"atzliche Bereiche freizugeben. Verschiebbare Speicherbl"ocke k"onnen zus"atzlich das Attribut {\sf ``purgeable''} besitzen. Derartige Speicherbl"ocke k"onnen durch das Betriebssystem dealloziert werden. Der Zeiger ({\sf ``Handle''} und {\sf ``Master Pointer''}) bleiben dabei erhalten. Das Freigeben von Speicher auf diesem Wege kann auch manuell durch Aufruf der Funktion {\sf ``PurgeMem''} ausgel"ost werden.

In einigen F"allen kann der Speicherbedarf einer Applikation den vorhandenen physikalischen Speicher des Rechners "uberschreiten. Aus diesem Grund bietet das MacOS virtuellen Speicher, der durch den {\sf ``Virtual Memory Manager''} verwaltet wird. Dazu wird auf einem Speichermedium, wie z.B. einer Festplatte, eine Auslagerungsdatei angelegt, in die Speicherbereiche verschoben werden, die nicht unmittelbar in Benutzung sind. Werden Daten in einem ausgelagerten Bereich referenziert, wird dies durch den ``Virtual Memory Manager'' erkannt. Er l"adt den entsprechenden Bereich in den Hauptspeicher des Rechners zur"uck und lagert stattdessen andere Daten aus. Damit diese Vorg"ange transparent bleiben,  müssen Datenbl"ocke mit den Funktionen {\sf ``NewHandle''} oder {\sf ``NewPtr''} alloziert werden.

Die Objektspeicher des Tycoon-Systems k"onnen beachtliche Gr"o"sen erreichen, die insbesondere auf gering ausgestatteten Computermodellen wie Laptops den Einsatz von virtuellem Speicher n"otig machen. In diesem Zusammenhang traten Programmabst"urze auf, wenn der Speicherbereich f"ur den Objekspeicher "uber die in Unix "ubliche Funktion {\sf ``malloc''} alloziert wurde. Es zeigte sich, das unter MPW die C-Funktionen {\sf ``malloc''} und {\sf ``realloc''} nur unvollst"andig auf den Betriebssystemfunktionen aufsetzen. Offensichtlich realisieren sie einen einfacheren Mechanismus zur Speicherverwaltung und greifen nur in einigen F"allen auf die Funktion {\sf ``NewPtr''} zur"uck. Dieses Verhalten ist wenig in den Handb"uchern zum Apple Betriebssystem oden dem MPW C-Referenzhandbuch beschrieben. Die Vermutung liegt nahe, da"s der {\sf ``Virtual Memory Manager''} keine Zugriffe auf Speicherbereiche "uberwacht, die mit {\sf ``malloc''} reserviert wurden. Durch Pr"aprozessoranweisungen wurden diese Aufrufe daher durch sie Funktion {\sf ``NewPtr''} ersetzt.

\section{Coroutinen-Implementation}
\label{Abs. Coroutinen-Implementation}

Die Tycoon Coroutinen-Implementation stie"s unter dem MacOS in erster Linie an Grenzen der Speicherverwaltung. Unter Unix kann eine beliebige Zahl von Coroutinen erzeugt werden, indem Speicher f"ur die Datenstrukturen und insbesondere den Stack einer Coroutine alloziert wird. Auf dem Macintosh verhindert die "Uberwachung durch den {\sf ``Stack-Sniffer''}, da"s der Stack-Pointer in den Heap der Applikation zeigt. In einem solchen Fall w"urde die Applikation mit einer Fehlermeldung beendet. Der Stackbereich der Coroutinen mu"s also oberhalb der Heap-Grenze {\sf ``ApplLimit''} liegen (siehe Abbildung \ref{picSpeicher}). Dazu wurden zur Portierung zwei verschiedene Ans"atze erfolgreich erprobt. Die eine L"osung weitet den Stackbereich der Applikation beim Programmstart stark aus, um den Stack mehrerer Coroutinen aufnehmen zu k"onnen. Die Variable {\sf ``ApplLimit''} wird entsprechend umgesetzt. Im zweiten Ansatz wird f"ur den Stack jeder Coroutine eine globale Variable ausreichender Gr"o"se definiert. Da globale Variablen im Bereich oberhalb des Stacks angelegt werden, entstehen keine Konflikte mit dem {\sf ``Stack-Sniffer''.} In beiden F"allen mu"s gegen"uber der Unix-L"osung der Nachteil in Kauf genommen werden, da"s die Anzahl der Coroutinen begrenzt ist, da die Speicherbl"ocke f"ur die Coroutinen-Stacks statisch festgelegt werden. Die Coroutinen existieren damit w"ahrend der gesamten Laufzeit der Applikation. Neben dem Ring mit aktiven Coroutinen wurde ein zweiter Ring eingef"uhrt, der inaktive Coroutinen aufnimmt (siehe dazu Abbildung \ref{picRing}).

\begin{figure}
\psbild{0.6#1}{.}{ring.epsf}
\caption{Ringe f"ur aktive und inaktive Coroutinen}
\label{picRing}
\end{figure}

Die Funktion {\sf ``rtcorout\_begin''} wird f"ur den ersten L"osungsansatz derart modifiziert, da"s sie die Datenstrukturen ({\sf ``rtcourout\_T''}) der Coroutinen im Stackbereich anlegt. Dabei wird mit der niederwertigsten Adresse des Stack begonnen, also seinem oberen Ende. Zwischen den Datenstrukturen wird ein Bereich von der Gr"o"se des Coroutinen-Stacks belassen (siehe Abbildung \ref{picStack}). Der Aufruf von {\sf ``rtcorout\_new''} nimmt unter MacOS keine Speicherallozierung vor und f"ugt keine neue Coroutine in den aktiven Ring ein, sondern migriert eine existierende aus dem inaktiven in den aktiven Ring. Dabei wird der Stack-Zeiger ({\sf ``stack pointer''}, {\sf SP}) auf die h"ochste Adresse des Bereiches gesetzt, der durch {\sf ``rtcorout\_begin''} "uber der jeweiligen Coroutine ausgespart wurde. Dar"uber hinaus wird der Programmz"ahler ({\sf ``program counter''}, {\sf PC}) mit einem Zeiger auf die Funktion {\sf ``executeAndFree''} initialisiert. Sie enth"alt den Aufruf des Byte-Code-Interpreters.

\begin{figure}
\psbild{0.6#1}{.}{stack.epsf}
\caption{Stackaufteilung f"ur eine feste Anzahl von Coroutinen}
\label{picStack}
\end{figure}

\subsection{Coroutinen: 68k-Macintosh}
\label{Abs. Coroutinen: Mac 68k}

Die Funktion {\sf ``rtcorout\_transfer''} sichert die Prozessorregister, den sogenannten Kontext, der aktiven Coroutine in der Variable {\sf ``context''} der  zugeh"origen Datenstruktur. Danach "ubergibt sie die Kontrolle an die n"achste Coroutine im Ring. Die Anzahl und die Reihenfolge der Prozessorregister h"angt von der zugrundeliegenden Prozessorarchitektur ab. Damit die Funktion {\sf ``rtcorout\_new''} die Initialisierung des Stack-Zeigers und des Programmz"ahlers vornehmen kann, mu"s sie deren Position im Kontext kennen, der durch das {\sf ``setjmp''}-Kommando gesichert wird. Diese Information kann durch den Einsatz eines Debuggers gewonnen werden, indem die einzelnen Schritte der {\sf ``setjmp''}-Funktion nachvollzogen und zu einem geeigneten Zeitpunkt die Registerinhalte des Prozessors mit denen der Kontext-Datenstruktur verglichen werden. F"ur die Motorola 68k Prozessorarchitektur in Verbindung mit der MPW Entwicklungsumgebung wurde ein Versatz zum Kontextanfang von 6 Worten f"ur den Programmz"ahler und 11 Worten f"ur den Stack-Zeiger ermittelt. Dieser Versatz wird in Form von Makros f"ur jede Plattform angegeben, der entsprechende Abschnitt ist in Abbildung \ref{sourceoffset} dargestellt.


\begin{figure}
\begin{verbatim}
#ifdef rtstd_LIB_MPW
# ifdef powerc
#  define iSP               2
#  define iPC               0
#  define iTOC              3
# else
#  define iSP               11
#  define iPC               6
# endif
# define nALIGNMENT        4
# define nBYTES_STACK      (64 * 1024)
# define nBYTES_SPACE      4
# define nMAX_COROUTS      8
# endif
\end{verbatim}
\caption {Versatz von Programmz"ahler und Kellerzeiger}
\label{sourceoffset}
\end{figure}

\subsection{Coroutinen: PowerPC-Macintosh}
\label{Abs. Coroutinen: Power Mac}

Der PowerPC Prozessor verf"ugt "uber zahlreiche Register. Der durch {\sf ``setjmp''} gesicherte Kontext ist wesentlich umfangreicher als der einer 68k-Architektur. Unter der MPW Entwicklungsumgebung betr"agt der Versatz von Programmz"ahler 0, der des Stack-Zeigers 2 Worte. Mit dem PowerPC wurde von Apple ein weiteres zentrales Prozessorregister eingef"uhrt, das als {\sf ``table of contents''}-Register ({\sf ``TOC''}) bezeichnet wird. Es ist auf eine neue Runtime-Architektur zur"uckzuf"uhren, die mit den neuen Prozessoren eingef"uhrt wurde. Es "ubernimmt die Aufgaben des 68k-Registers {\sf A5} und wird f"ur den Zugriff auf globale Daten genutzt. Das Register wird vom Betriebssystem aktualisiert. Die Implementation der {\sf ``setjmp''} und {\sf ``longjmp''}-Kommandos unter MPW sichert den Inhalt dieses Registers zus"atzlich 5 Worte oberhalb des Stack. Beide Informationen werden f"ur einen Kontextwechsel "uber {\sf ``longjmp''} ben"otigt. Die Funktion {\sf ``rtcorout\_new''} mu"s also das Register {\sf ``TOC''} sowohl im Kontext initialisieren (Versatz 3 Worte) als auch oberhalb des Stack eintragen, um eine funktionsf"ahige Coroutine zu instanziieren (siehe Abbildung \ref{sourcePowerTOC}). Es wurde daf"ur eine weitere Pr"aprozessoranweisung speziell f"ur PowerPC notwendig.

\begin{figure}
\begin{verbatim}
# ifdef powerc
  if (!setjmp(rtcorout_VARIABLE(c, context)))
  {
  pw = (Word *) &rtcorout_VARIABLE(c, context);
  help2 = (Word *) pw[iSP] + 20;
  pw[iSP] = (Word) (c + 1) + nBYTES_STACK;
  pw[iSP] &= ~(nALIGNMENT - 1);
  help = (Word *) pw[iSP] + 20;
  *help = *help2;
  pw[iTOC] = *help2;
  }
  else
  executeAndFree();
  rtexcept_init(c);
  return c;
# else
\end{verbatim}
\caption{Sichern des ``Table-of-Contents''-Registers unter Power Macintosh}
\label{sourcePowerTOC}
\end{figure}


\section{Umgebungsvariablen}
\label{Umgebungsvariablen}

Die graphische Benutzeroberfl"ache des Apple Macintosh bietet keine M"oglichkeit, Umgebungsvariablen zu definieren, wie dies unter Unix und einigen anderen Betriebssystemen "ublich ist\footnote{F"ur MPW-Werkzeuge k"onnen innerhalb der MPW-Shell Umgebungsvariablen definiert werden. Tycoon als MPW-Werkzeug anzubieten w"urde jedoch eine starke Einschr"ankung bedeuten, da ein Anwender auch "uber die MPW-Shell verf"ugen m"u"ste.}. Die entsprechende C-Funktion zur Bestimmung des Wertes einer Umgebungsvariablen ({\sf ``getenv''}) ist nicht in den MPW-Bibliotheken enthalten. Tycoon macht zumindest von der Variablen {\sf ``TYCOON\_ROOT''} Gebrauch, um den Verzeichnispfad zu bestimmen, unter dem das Tycoon-System installiert ist. Der Zugriff auf die meisten Dateien erfolgt "uber relative Pfadangaben, die Applikation mu"s unter Unix dazu im Unterverzeichnis {\sf ``bootlib''} abgelegt sein und dort gestartet werden. 

Ein Teil des Macintosh Betriebssystems ist das sogenannte {\sf ``Standard File Package''}, das u.a. Auswahlfenster f"ur das "Offnen von Dateien bereitstellt. Das Betriebssystem unterscheidet ein ``default directory'', auf das zugegriffen wird, wenn bei Dateizugriffen nicht explizit ein Verzeichnis angegeben wurde, und ein ``current directory'', das durch das {\sf ``Standard File Package''} verwaltet wird. Das ``current directory'' entspricht dem letzten Verzeichnis, auf das "uber Dateiauswahlfenster zugegriffen wurde. Wird ein Macintosh-Programm direkt durch Doppelklick gestartet, so entspricht zu Programmbeginn das ``current directory'' dem Verzeichnis, in dem sich die Applikation befindet. Aus diesem Grund wurde bei der Portierung die Bedingung "ubernommen, da"s sich die Tycoon-Applikation im ``{\sf bootlib}''-Verzeichnis des Tycoon-Dateibaumes befinden und dort gestartet werden mu"s. "Uber den Aufruf {\sf ``LMGetCurDirStore''} kann die Applikation in der Startphase das aktuelle Verzeichnis ermitteln, so die Variable {\sf ``TYCOON\_ROOT''} herleiten und einer globalen Programmvariablen zuweisen.

Die Funktion {\sf ``rtmac\_getenv''} implementiert die fehlende C-Funktion {\sf ``getenv''}: sie erh"alt als Eingabeparameter den Namen der Umgebungsvariablen, deren Wert ben"otigt wird. Sie liefert f"ur {\sf ``TYCOON\_ROOT''} den Inhalt der globalen Variablen, die beim Programmstart gef"ullt wurde. Andere Umgebungsvariablen werden derzeit nicht unterst"utzt, es wird in solchen F"allen der Wert {\sf ``mac''} zur"uckgegeben. 

\section{Socket-Implementation}
\label{Socket-Implementation}

F"ur die Kommunikation mit anderen, insbesondere entfernten Prozessen k"onnen auf TL-Ebene Sockets eingesetzt werden. Eine entsprechende TL-Bibliothek nutzt den C-Call-Mechanismus, um die unter C verf"ugbaren Funktionen auch in TL bereitszustellen. 

Das Konzept von Sockets ist nicht Bestandteil des Apple Macintosh Betriebssystems. Die entsprechende Funktionalit"at wird aber durch die ``Public-Domain''-Bibliothek {\sf ``Grand Unified Socket Interface'' (GUSI)} implementiert. Sie mu"s zus"atzlich zu einer Applikation gebunden werden und bietet mit wenigen Ausnahmen die unter Unix bekannten Funktionen f"ur die Verwaltung von Sockets.

Die unter Unix eingesetzten Tycoon-Bibliotheken f"ur Kommunikation "uber Sockets sind durch den Einsatz der GUSI-L"osung auch auf dem Macintosh Betriebssystem lauff"ahig. In einigen F"allen zeigten sich die GUSI-Bibliotheksfunktionen instabil. Insbesondere kann nach einem unerwarteten Verbindungsabbruch keine neue Verbindung "uber den zuvor genutzten Socket aufgebaut werden.

\section{Zugriffe auf das Dateisystem}
\label{Zugriffe auf das Dateisystem}

Das Macintosh-Betriebssystem verwendet ein streng hierarchisch aufgebautes Dateisystem ({\sf ``Hierarchical File System, HFS''}). Eine Datei wird dabei durch ihren Namen und eine numerische Verzeichnis-ID identifiziert. Ein Verzeichnis wird wiederum über seinen Namen und die Verzeichnis-ID des darüberliegenden Verzeichnisses angesprochen. Dieses Vorgehen deckt sich nicht mit dem unter Unix, bei dem eine Datei über eine explizite Pfadangabe aufgefunden wird. Das Unix-Verhalten wird durch die Standard-C-Funktionen auf Macintosh-Rechnern nachgebildet, so da"s Funktionen wie {\sf ``open''} in gewohnter Weise verwendet werden k"onnen. Es ist weiterhin möglich, über die Verkettung von Betriebssystemaufrufen eine Pfadangabe zu einer Datei zu gewinnen.

Im Gegensatz zu Unix stehen f"ur Verzeichnisoperationen keine Funktionen wie {\sf ``chdir''} zur Verf"ugung. Diese Funktionen werden in Tycoon durch das Modul {\sf ``directory''} in der Bibliothek {\sf ``STDENV''} genutzt. Die im Abschnitt \ref {Socket-Implementation} beschriebene Bibliothek {\sf ``GUSI''} bildet die Funktion {\sf ``chdir''} nach. Wird die Funktionalit"at des Moduls {\sf ``directory''} ben"otigt, so mu"s die ausf"uhrbare Tycoon-Applikation mit der GUSI-Bibliothek gebunden werden. Im Zuge der Portierung hatte diese Bibliothek jedoch negative Auswirkungungen auf die Performanz vor allem von Dateioperationen.

\section{Datei-Namen}
\label{Abs. Dateinamen}

Der Aufbau von Dateinamen ist unter Unix und MacOS sehr "ahnlich, weist jedoch folgende Unterschiede auf: als Trennzeichen zwischen Verzeichnis und Dateinamen wird auf dem Macintosh statt eines ``/'' ein ``:'' verwendet. Dar"uber hinaus erfolgt eine direkte Pfadangabe ohne vorangestellte Zeichen wie ``/'' oder ``:'', eine relative hingegen mu"s mit einem ``:'' eingeleitet werden. Die ``Tycoon Language'' "ubergibt Dateinamen im Unix-Format an die virtuelle Maschine. Bei der Portierung wurde die Funktion {\sf ``rtmac\_adaptFileName''} eingef"uhrt, um die Dateinamen an die Macintosh-Konventionen anzupassen. 
Die Umwandlungsroutine pr"uft, ob eine absolute Pfadangabe vorliegt. Dieser Fall sollte nicht auftreten, da trotz einer "Ubersetzung der Trennzeichen die Datei vermutlich nicht gefunden werden k"onnte. F"ur relative Pfadangaben wird zun"achst "uberpfr"uft, ob sie bereits den Verzeichnispfad enth"alt, der unter der globalen Variablen {\sf ``TYCOON\_ROOT''} eingetragen ist. Diese Angabe wird sonst der eigentlichen Pfadangabe vorangestellt. Danach wird in Abh"angigkeit weiterer f"uhrender Zeichen bestimmt, ob der Pfad zus"atzlich um das Verzeichnis {\sf ``bootlib''} erg"anzt werden mu"s. Dabei müssen drei unterschiedliche Kombinationen aus dem Verzeichnis {\sf ``bootlib''} und Trennzeichen ber"ucksichtigt werden. Schließlich wird der so gebildete Pfadname mit dem "ubergebenen Dateinamen erg"anzt, verbleibende Unix-Trennzeichen umgewandelt und die Zeichenkette als Ergebnis zur"uckgeliefert.

\section{Dynamisches Binden auf Apple Macintosh}
\label{Dynamisches Binden auf Apple Macintosh}

Dynamisches Binden von Funktionen war in frühen Versionen des MacOS nicht möglich. Für die 68k-Familie wurde daher der {\sf ``Shared Library Manager''} entwickelt, um die fehlende Funktionalität zur Verfügung zu stellen. Mit der PowerPC-Architektur wurde der sogenannte  {\sf ``Code Fragment Manager'' (CFM)} eingeführt. Er nimmt in der Laufzeitarchitektur der neuen Macintosh-Generation eine zentrale Stellung ein (siehe auch TOC-Register im Abschnitt \ref {Abs. Coroutinen: Power Mac}) und ersetzt au"serdem den {\sf ``Shared Library Manager''}. Zum Zeitpunkt dieser Arbeit lag keine Version des CFM für 68k-Modelle vor.

Das Verhalten beider Lösungen weicht stark vom Ansatz der Shared Libraries unter Unix ab: für die Applikation bleibt der Aufruf von Funktionen stets transparent, gleichgültig ob sie statisch oder dynamisch gebunden sind. Zur Übersetzungszeit der Applikation werden dazu Stubs anstatt der eigentlichen Funktionen gebunden, die Informationen wie die Identifikation und die Version der Shared Library enthalten. Der Programmquelltext enthält gew"ohnliche Funktionsaufrufe, der Code Fragment Manager löst diese Referenzen zur Laufzeit auf.

In Tycoon erscheinen Funktionsaufrufe auf dem Macintosh immer wie statische Aufrufe. Die gew"unschte Flexibilität geht dadurch verloren und alle Funktionen müssen explizit registriert werden (siehe Abschnitt \ref {C-Calls}). Aus diesem Grund und aufgrund der Existens zweier unterschiedlicher L"osungen für 68k- und PowerPC-Modelle wurde bei der Portierung zun"achst auf dynamisches Binden verzichtet.
