PowerPC Kurs von Steffen HaeuserMultitasking-Programmierung mit WarpOS |
INTERN |
|
Bei Rückfragen stehe ich unter MagicSN@Birdland.es.bawue.de oder 07021/51787 oder Steffen Häuser, Limburgstr. 127, 73265 Dettingen/Teck, gerne zur Verfügung. Auch an Software, die ich Portieren kann, bin ich interessiert. Viele Aufgaben bei einer Software können bekanntlich auf mehrere Tasks aufgeteilt werden. Natürlich ist dies auch bei PPC-Software erwünscht. Dieser Artikel beschreibt, wie man Multitasking-Programmierung auf dem PPC durchführt, unter Verwendung des StormC oder des vbcc-WarpOS Compilers. Ich gehe dabei nicht im Einzelnen auf die Syntax ein, sondern erläutere im Wesentlichen die Verfahren. Syntax kann man in der Dokumentation von WarpOS nachlesen. 1. Die zentrale Funktion
Die zentrale Funktion für das PPC-Multitasking ist die Funktion CreateTaskPPC()
der powerpc.library. Sie entspricht gewissermaßen der Funktion CreateTask() der
exec.library, nur daß sie PPC-Tasks, und keine 68k-Tasks erzeugt. Dennoch gibt
es einige Unterschiede:
extern ULONG *LinkerDB; Falls nun ein Task auf globale Variablen zugreifen soll (__saveds allein genügt nicht !!!), so muß man etwa so programmieren:
ppctags[0].ti_Data=(ULONG)AudioHandlerTask; Nun kann der Task auch auf globale Variablen zugreifen. (Ein DeleteTaskPPC gibt es natürlich auch). 2. Ein Wort zum Multiprocessing Immer wieder kommt im Usenet - meist von Leuten, die keine PowerPC-Karte besitzen und gerne "theoretisieren" - das Stichwort "Multiprocessoring" hervor. Um dies klarzustellen: PowerUP ist *kein* Multiprozessorsystem, auch wenn es oft als solches bezeichnet wird. Der 68k und der PPC teilen sich einen gemeinsamen Bus, und wenn man versucht, beide gleichzeitig massivst auf diesem Arbeiten zu lassen - z.B. indem man einen Frame auf dem PPC berechnet, und den letzten Frame gleichzeitig mit dem 68k darstellt - so bricht die Busgeschwindigkeit MASSIVST zusammen. Man kann davon ausgehen, daß der Bus auf etwa die halbe Geschwindigkeit gebremst wird. Das Programm läuft also nur noch halb so schnell. DIES IST KEINE THEORIE, DIES SIND WERTE AUS DER PRAXIS, DIE VON MEHREREN PROGRAMMIERERN UNABHÄNGIG VONEINANDER GEMESSEN WURDEN. Es ist übrigens keine Frage des Kernels. Theoretisch kann man Pseudo-Multiprocessoring sowohl mit WarpOS (man würde das AllocXMsg-System einsetzen) als auch mit ppc.library (das Message-System der ppc.library) programmieren. Man erhält jedoch in beiden Fällen die gleichen miesen Resultate. ZU EINEM ECHTEN MULTIPROZESSOR GEHÖREN ENTWEDER ZWEI BUSSYSTEME ODER LOKALER SPEICHER. Ich denke, nun können wir das Multiprozessor-Märchen abhaken und uns der Programmierung des Multitaskings weiter widmen. 3. Hilfsfunktionen Aus der 68k exec.library sind zahllose Hilfsfunktionen für Tasks bekannt, z.B.:
InitSemaphore Alle diese Funktionen werden innerhalb von WarpOS PPC-Native (ohne Kontextswitches) angeboten. Dies sind keine exec.library Funktionen mehr, dies sind Funktionen des WarpOS-Kernels:
InitSemaphorePPC Ausser dem PPC am Ende des Namens ist der einzige Unterschied zu den exec-Funktionen, daß:
Die Includes für all diese neuen Datenstrukturen sind im Includepfad powerpc/ zu finden (z.B. powerpc/tasksPPC.h für die TaskPPC-Struktur). Gemein haben all diese Strukturen, daß sie jeweils ihr 68k-Äquivalent enthalten, so daß man, wenn man bei bestimmten Programmkonstrukten unbedingt die 68k-Struktur oder ein Teil von ihr benötigt, auch auf diese zugreifen kann, z.B.:
task=taskppc->tp_Task; Man kann z.B. ohne Probleme einem PPC-Task über die 68k-Funktion GetTaskPri eine neue Priorität zuweisen (allerdings ist es sinnvoller, GetTaskPriPPC zu verwenden). Es sei an dieser Stelle darauf hingewiesen, daß bei WarpOS Semaphoren eine bedeutsame Stellung einnehmen. Man kann bei WarpOS nicht einfach mit einem Forbid() das Multitasking abschalten. Es bleibt festzustellen, daß WarpOS dem AmigaOS eigentlich sehr ähnlich ist. Die Funktionen sind fast die Selben, zumindest im Bereich des Multitaskings. Achtung, nicht Alle der angegebenen Funktionen sind auch unter WarpUP V7 zugänglich. Im Zweifelsfall WarpOS-Dokumentation konsultieren. Zusätzlich existieren noch:
An dieser Stelle möchte ich noch einmal den Begriff Semaphore wiederholen, da er Neuland für viele Amiga-Programmierer ohne informatische Vorbildung sein dürfte. Def. Semaphor Ein Semaphor ist eine Datenstruktur, die von allen Tasks "angetestet" werden kann, ob sie gerade belegt oder frei ist. Ein bestimmter Code kann nur ausgeführt werden, wenn der zuständige Semaphor noch frei ist. Ist er belegt, so wartet der Semaphor, bis er wieder frei ist, und macht dann gleich weiter. Beim gleichzeitigen Zugriff mehrerer Tasks auf einen Semaphor gibt es auf KEINEN FALL Probleme. Beispiel: 1. Task:
extern int a; 2. Task:
extern int a; Der Wert von a ist zu jedem Zeitpunkt exakt definiert. Die beiden Tasks greifen niemals gleichzeitig darauf zu. Aufpassen sollte man, wenn man mehrere Semaphoren verschachtelt. Eine Situation, in der jeder Task auf das Freiwerden der Resource wartet, die gerade der andere Task belegt, nennt man einen DEADLOCK. Aber das soll hier genügen. Weitere Informationen über Semaphoren können jedem guten Buch über Betriebssysteme entnommen werden. Semaphoren sollten verwendet werden, wann immer eine Resource nicht gleichzeitig von zwei Tasks verwendet werden kann. Dabei werden Semaphoren erst initialisiert, dann "obtained", dann "released". Man sollte jeden "obtainten" Semaphore auch wieder "releasen", damit die Resource wieder frei wird. Semaphore sind ein sehr geschicktes Mittel, um Multitasking in einer Weise zu programmieren, daß Deadlock-Situationen oder auch Situationen, in denen zu oft gewartet wird, vermieden werden. 5. Das AllocXMsg-System Was nun noch fehlt, ist ein System, Nachrichten zwischen 68k und PPC hin und her zu schicken. Man beachte jedoch die Warnung von oben, dass ein solches Programm, wenn man nicht GENAU weiß, was man tut, zu großer Ineffizienz führen kann. a) Anlegen der Message-Ports Für den 68k wird ein MsgPort angelegt, für den PPC ein MsgPortPPC b) Anlegen der Tasks wie üblich c) Anlegen der Messages Der 68k verwendet die Funktion AllocXMsg. Hierbei muß eine Message-Größe angegeben werden, sowie der Reply-Port des 68k-Tasks. Für den PPC existiert eine analoge Funktion AllocXMsgPPC. FreeXMsg/FreeXMsgPPC existieren natürlich ebenfalls. d) Übertragen der Messages Hierzu werden die Funktionen PutXMsg (vom 68k zum PPC) und PutXMsgPPC (vom PPC zum 68k) eingesetzt. Als Parameter werden ein MsgPort(PPC) und die in c) gewonnene Message benötigt (in die zuvor die Nachricht eingetragen wird). e) Empfangen und Beantworten der Messages Auf 68k-Seite werden GetMsg, WaitPort und ReplyMsg eingesetzt, auf PPC-Seite GetMsgPPC, WaitPortPPC und ReplyMsgPPC. Reply-Messages erhalten hierbei den Nodetype NT_REPLYMSG. Nachdem die Message verschickt wurde, verliert der entsprechende Prozessor SOFORT den Besitz über die Message. Erst wenn sie Replied wurde, darf wieder auf die Message zugegriffen werden. Falls es keinen Replyport gibt, darf die Message - nachdem sie von der anderen Seite gelesen wurde - freigegeben werden. Nachdem die Message beantwortet wurde, kann sie weiterverwendet werden. Achtung: ReplyMsg sollte nur aufgerufen werden, wenn auch ein ReplyPort existiert. Achtung: Der empfangende Task darf nur Daten zugreifen, die direkt im Message-Körper enthalten sind. Eine Ausnahme ist nur möglich, falls sich die beiden Tasks selber um die Cache-Kohärenz kümmern. Nur am Messagekörper selbst führt das System Flushing/Invalidation durch. Achtung: Der empfangende Task hat auch Schreibzugriff auf den Message-Körper. Beim Anwenden des AllocXMsg-Systems sind also im wesentlichen zwei Dinge zu beachten:
6. Andere Elemente der powerpc.library Des weiteren enthält die powerpc.library noch:
Ein weiterer Abschnitt sei den "Hooks" gewidmet. Ein Hook ist eine nützliche Konstruktion, in der eine Funktion eine andere Funktion als Parameter erhält. Systeme wie AHI nützen diese recht extensiv. Leider geht das schief, falls z.B. die Funktion als Parameter PPC ist, die Funktion der Library/des Devices aber 68k. Es klappt einfach nicht, keine Chance. Ein Beispiel wäre AHI_AllocAudioA(), selbst wenn man den Hook-Parameter nicht angibt, geht das schief. Ein weiterer beliebter Befehl, der dieses Problem hat, ist RawDoFmt(). In Form von SPrintF/SPrintF68k bietet WarpOS Ersatzcode an. Lösung: 68k und PPC Code zusammenlinken, das komplette AHI-Handling im 68k-Part erledigen. Es wird stark empfohlen, ein MixedBinary zu verwenden, da StormC innerhalb eines MixedBinary die Handhabung für solche Dinge stark erleichtert. vbcc-WarpOS kann das leider noch nicht automatisch, hier muß der Kontextswitch zwischen den beiden Teilen noch manuell programmiert werden. Prinzipiell gilt jedoch das Selbe. 8. Empfehlungen Es sei im Allgemeinen empfohlen:
|
|
|