Programmieren unter MiNT/MultiTOS, Teil 4

Im ersten Teil dieses Artikels wollen wir noch ein wenig die Verwandtschaft von MiNT und UNIX hochleben lassen, anschließend stürzen wir uns auf die Neuheiten der grafischen Benutzeroberfläche von MultiTOS.

Eric R. Smith, der Macher von MiNT und offensichtlich ein großer UNIX-Fan, hat seinem Betriebssystem auch die UNIX-Pipes mit auf den Weg gegeben. Dieses interessante Feature der IO-Umleitung war zwar schon im gewöhnlichen TOS rudimentär vorhanden, ob seiner ungezählten Fehler wurde es allerdings praktisch nie sinnvoll genutzt.

Pipes

Die erste, wörtliche Übersetzung vom englischen »Pipe« bringt uns zur deutschen »Pfeife« und damit nicht weiter, da »Pipe« in diesem Fall »Röhre« bedeuten soll. Alternativ könnte es auch als Abkürzung von »Pipeline« gedeutet werden. Beides kommt dem wahren Sachverhalt recht nahe, denn eine »Pipe« verbindet zwei Prozesse miteinander. In der Regel verknüpft sie die Standard-Ausgabe des einen Prozesses mit der Standard-Eingabe des anderen. Einfacher ausgedrückt: Was der eine auf den Bildschirm schreibt, kommt beim anderen zur Tastatur wieder herein. Zugegeben, dieses Beispiel lahmt ein wenig, aber für den Endanwender sieht es so aus, da im Normalfall der Bildschirm als Standard-Ausgabe und die Tastatur als Standard-Eingabe fungiert. Natürlich funktioniert diese »Leitung« nur bei TOS-Programmen und bei diesen auch nur dann, wenn sich der Programmierer sauber an die GEMDOS-Funktionen zur Ein-/Ausgabe gehalten hat.

Ein kleines Beispiel aus der Praxis: Sie arbeiten mit der C-Shell (»tcsh.ttp«) und lassen sich mit »ls« ein sehr großes Verzeichnis anzeigen. Die Dateinamen rauschen nur so über den Bildschirm, und selbst ein schneller Leser wird nur die Hälfte mitbekommen. UNIX-Experten werden spätestens jetzt müde lächeln und die Befehlszeile »ls | more« eingeben. Mit dem Zeichen »l« wird der Shell mitgeteilt, daß sie die Ausgabe von »ls« zur Eingabe von »more« leiten soll, und fertig ist die »Pipe«. »MORE« ist ein nützliches Programm, das (unter anderem) Eingaben seitenweise anzeigt, damit auch gemütlichere Leser nicht in Hektik ausbrechen müssen. Dank MiNT steht dieses, wie auch viele andere nützliche UNIX-Tools, nun auf dem Atari zur Verfügung. »Pipes« stehen unter MiNT grundsätzlich im Speicher und sind dadurch recht flott. Sie sind auf eine Größe von 2048 Bytes beschränkt, versucht ein Prozeß mehr hineinzuschreiben, wird er von MiNT schlafen geschickt (suspended), bis der Empfänger die Pipe wieder geleert hat. Ist überhaupt kein Empfänger vorhanden oder hat dieser sich in der Zwischenzeit »verkrümelt«, wird der sendende Prozeß beendet. Interessierte Programmierer sollten sich die Beschreibung der Funktion Fpipe() näher betrachten.

Named-Pipes

Die einfachen »Pipes« sind systembedingt nicht für kompliziertere Interprozeßkommunikation geeignet. Um diesen Mangel aus der Welt zu schaffen, wurde in der UNIX-Welt ein naher Verwandter, die »Named-Pipe«, erdacht. Im Prinzip handelt es sich hierbei um Datei-ähnliche Gebilde, in die auf der einen Seite hineingeschrieben und auf der anderen wieder ausgelesen werden kann. Komplizierte Naturen nennen das Ganze auch gerne FIFO-Queue. FIFO steht für »First In First Out«, auf neugermanisch könnte man also »Zuerst-Rein-Zuerst-Raus- Warteschlange« sagen. Bildlich kann man sich eine FIFO-Queue sehr gut als Röhre zwischen zwei Prozessen vorstellen, der Sender schiebt an einer Seite die Buchstaben rein und in der gleichen Reihenfolge kommen sie beim Empfänger wieder raus. Diese Möglichkeit der Prozeßkommunikation wird sehr häufig in einer Client-/Server-Architektur eingesetzt. Ein Prozeß (der Server) sitzt resident im System, legt eine »Named-Pipe« an und wartet auf Befehle, die ein Client in diese schreibt. Unter MiNT existiert ein gutes Beispiel für diesen Vorgang: Das Programm »TOSRUN« überwacht die Named-Pipe »U:\PIPE\TOSRUN«. Schreibt nun ein Client den Namen und den Pfad einer TOS-Applikation in die »Named-Pipe«, startet»TOSRUN« diese Applikation in einem eigenen Fenster.

Damit dürfte auch erklärt sein, woher der Zusatz »Named« kommt: Im Gegensatz zu den ordinären »Pipes« haben die »Named-Pipes« eben einen Namen, unter dem sie wie jede andere Datei angesprochen werden können. Unter UNIX können diese »Named-Pipes« überall im Dateisystem liegen, unter MiNT hingegen dürfen sie nur im Verzeichnis »U:\PIPE« angelegt werden.Jede Datei, die in diesem Verzeichnis mit Fcreate(name,mode) angelegt wird, ist automatisch eine FIFO-Queue. Beim Parameter »mode« ist die Bedeutung der gesetzten Bits gegenüber einer gewöhnlichen Datei geändert:

Bit 1 Die FIFO ist unidirektional, der Server kann schreiben, der Client nur lesen.
Bit 2 EOF wird beim Lesen zurückgegeben, wenn kein anderer Prozeß schreibt, bzw. das SIGPIPF Signal wird beim Schreiben ausgelöst, kein anderer Prozeß liest.
Bit 4 Die FIFO verhält sich wie ein Pseudo-Terminal. Wenn z.B. wenn der Server CTRL-C schreibt, wird SIGINT an den Client geschickt.

Fcreate() liefert im Fall einer »Named-Pipe« ein ganz gewöhnliches Dateihandle zurück, mit dem Sie wie gewohnt arbeiten. Fwrite() schreibt in die »Named-Pipe«, Fread() liest daraus usw. Eines sollte man aber im Umgang mit ihnen bedenken: »Named-Pipes« sind immer temporär. Wenn die darin enthaltenen Daten wichtig sind, sollten sie nicht endgültig geschlossen werden. Schließt der letzte Prozeß die »Named-Pipe«, wird sie automatisch vom System gelöscht. Natürlich spricht auch nichts dagegen, daß ein Prozeß sowohl Server wie auch Client gleichzeitig ist. Er muß die Pipe nur mit Fcreate() erzeugen und sie dann zusätzlich mit Fopen() öffnen und schon handelt er in Tateinheit.

Auf der TOS-Diskette finden Sie ein kleines Programm mit dem sinnigen Namen »RUNTOS.PRG«, inklusive C-Quellcode. Dieses Teil demonstriert die Verwendung einer FIFO-Queue anhand von »U:\PIPE\TOSRUN«. Es startet TOS-Programme via Kommandozeile in einem Fenster von »TOSRUN«. Sehr nützlich ist dies bei der Verwendung einer GEM-gestützten Packershell unter MiNT. Anstatt den Packer direkt aufzurufen (z.B. »C:PPACKER\LHARC -X TEST.LZH«) und damit die Arbeit unter GEM zu blockieren, starten Sie »C:\RUNTOS.PRG C:\PACKER\LHARC.TTP -X TEST.LZH«; schon läuft der Packer im Hintergrund bei echtem Multitasking, und Sie können Ihrer Arbeit weiter ohne Kaffee-Pause nachgehen. Wie wir später noch sehen werden, zeigt auch der Desktop von MultiTOS eine ähnliche Vorgehensweise.

Nun wird es noch ein klein wenig technisch, denn FIFO-Pipes können unter MiNT für andere Prozesse gesperrt werden, damit z.B. niemand während eines Schreibvorganges dazwischen »pfuscht«. Die Sperrung erfolgt durch einen Fcntl() - Aufruf, bei dem folgende Struktur zur Anwendung kommt:

struct flock
{
	int  l_type;	/* Art der Sperre. */
	int  l_whence;	/* Sperre für was ? */
		/* 0 Dateianfang */
		/* 1 Aktuelle Position */
		/* 2 Dateiende */
	long l_start;	/* Beginn der Sperre. */
	long l_len;	/* Länge des Bereichs */
		/* 0 = bis Datei-Ende */
	int  l_pid;	/* PID des Sperres */
};

/* Arten für l_type */
#define F_RDLCK 0	/* Lesesperre */
#define F_WRLCK 1	/* Schreibsperre */
#define F_UNLCK 3	/* Sperre aufheben */

Leider versteht die aktuelle Version von MiNT nur Sperren, die sich auf die gesamte FIFO-Queue beziehen, daher sollten lock.l_start und lock.l_len im Moment immer auf 0 gesetzt werden. Noch ein Wermutstropfen: MiNT unterscheidet noch nicht zwischen Lese- und Schreib-Sperre, jede Sperre verhindert sowohl Lesen wie Schreiben. Greift ein Prozeß auf eine gesperrte FIFO-Queue zu, wird die Fehlermeldung -36 (Zugriff verweigert) zurückgeliefert. Und weil es so schön war, noch einer: Die Sperren sind in der aktuellen Implementierung eigentlich nur freundliche Hinweise, sie können von Prozessen ignoriert werden. Selbstverständlich würde aber ein sauberes Programm so etwas nie und nimmer machen! Mit an Sicherheit grenzender Wahrscheinlichkeit wird es sonst früher oder später zu Komplikationen kommen, da das Filelocking im Zeichen der Netzwerke sicher bald auch für normale Dateien eingeführt wird. Hat jemand an der Art und dem Verursacher einer Sperre Interesse, kann er mit Fcntl(fd, Lock, F_GETLK) die aktuellen Daten abfragen. lock wird hierbei auf die entsprechenden Werte gesetzt.

AES 4.0

So, damit wäre das Kapitel MiNT fürs erste abgeschlossen. Mausfreunde dürfen wieder aufatmen, es geht nun um die Neuheiten der grafischen Benutzeroberfläche AES 4.0 unter MultiTOS. Für den Anwender am auffälligsten sind - abgesehen vom Multitasking - sicher die neuen Möglichkeiten der Menü-Verwaltung. Endlich sind auch auf dem Atari ohne Tricks (scrollende) Untermenüs (Submenüs) in der Menüleiste möglich. Recht hübsch sehen auch die vom Betriebssystem nun direkt unterstützten Pop-Up-Menüs aus und natürlich dürfen auch die Pop-Ups wieder Untermenüs haben.

Auf der TOS-Diskette finden Sie das Programm »AES_DEMO.APP« inklusive des C-Quellcodes. Es zeigt den Umgang mit diesen Neuheiten und erlaubt das Einstellen der Menü-Parameter (Größe eines Submenüs, Zeit bis zur Anzeige usw). Aber damit nicht genug, denn wer unter MultiTOS in Pure-C programmieren will steht zunächst vor dem Problem, daß die neuen AES Befehle in der »PCGEMLIB.LIB« nicht enthalten sind Wer nicht auf ein Pure-C-Update warten möchte, kann »NEVVAES.LIB« verwenden. Diese Library ist ebenfalls auf der TOS-Diskette enthalten und muß vor »PCGEMLIB.LIB« in Ihre Projektdatei eingetragen werden. In »NEWAES.H« finden Sie Prototypen der neuen AES-Funktionen sowie verschiedene Definitionen.

Neue AES-Nachrichten

Natürlich gibt es nicht nur komplett Neues, es wurde auch Bewährtes gepflegt. Einige der alten AES-Befehle haben zum Teil mächtig zugelegt, wodurch einige AES-Nachrichten hinzugekommen sind. »WM_UNTOPED« kommt vom AES, wenn das obere Fenster durch ein anderes Fenster (sprich, durch Fremdeinwirkung) in den Hintergrund gelegt wird. Die Nummer des betreffenden Fensters steht im dritten Wort der MSG-Queue. Von der Funktion her gleich gilt »WM_ONTOP« für den umgekehrten Sachverhalt. Es signalisiert, daß ein Fenster zum TOP-Window befördert wurde.

Bei »AP_TERM« wird es nun ein wenig kompliziert Diese Nachricht ist in einem Multitasking-System von großer Bedeutung. Sie fordert den Empfänger auf, sich umgehend zu verabschieden! In der MSG-Queue ist der Grund dieser Aufforderung im Wort 5 enthalten, noch einmal AP_TERM, wenn das System gestoppt werden soll, oder »AP_RESCHG« für einen bevorstehenden Auflösungswechsel. Der Empfänger sollte diese Nachricht unbedingt auswerten, da sonst ein Auflösungswechsel vom Desktop aus unmöglich gemacht wird. Wenn der Aufforderung nicht Folge geleistet werden kann, sollte das AES durch shell_write() (mode 10) mit der »AP_TFAIL«-Nachricht informiert werden. Dieser Message kann man im Wort 1 der MSG-Queue einen beliebigen Fehlercode mitgeben.

Natürlich kann auch eine Applikation die AP_TERM-Nachricht abschicken. Bevor der Verursacher aber weiterarbeiten darf, muß er in einer evnt_multi()/evnt_mesag()-Schleife auf die Antwort vom AES warten. Sie kommt in Form der Nachricht »SHUT_COMPLFTED«, wobei im Wort 3 der MSG-Queue 1 für einen erfolgreichen oder 0 für einen gescheiterten Shutdownversuch steht. Wer wegen eines Auflösungswechsels AP_TERM abgesandt hat, muß zusätzlich noch auf die »RESCH_COMPLETED«-Nachricht warten. Nach Erhalt derselben muß sich allerdings auch der Empfänger verabschieden, um den Auflösungswechsel endgültig zu ermöglichen.

Ein Prozeß, der von einem anderen mit shel_write() gestartet wurde, ist kein »eigenes Kind«, - es ist vielmehr das Child des AES. Somit hat der Starter keine direkte Verbindung zu diesem Nachkommen und würde auch nichts von dessen Ende erfahren. In vielen Fällen muß aber auf eben dieses Ereignis reagiert werden. Aus diesem Grund hat Atari die AES-Nachricht »CH_EXIT« eingeführt. Sie signalisiert den »Tod« eines via shel_write() gestarteten Abkömmlings.

Die neuen AES-Funktionen

Es hat sich was getan im AES! Vor allem durch das echte Multitasking sind einige Aufgaben entstanden, für deren Bewältigung neue bzw. erweiterte AES-Aufrufe notwendig wurden. Arbeiten wir uns durch diesen Wust in alphabetischer Reihenfolge durch:

int appl_find (char *ap_fpname);

Da die MiNT-Identifikationsnummer eines Prozesses nicht identisch mit der ID des AES sein muß, wurde appl_find() um einen Mechanismus erweitert. Ist ap_fname ein 4 Byte langer String, sind die oberen zwei Bytes gleich 0xFFFF und steht in den unteren zwei Bytes die MiNT-ID, dann liefert appl_find() die AES-ID zurück. Genau umgekehrt funktioniert es, wenn in den oberen zwei Bytes 0xFFFE enthalten ist.

int appl_init ();

Hier wurden die Rückgabeparameter ausgebaut: Global[1] enthält bei einem Multitasking-AES -1, in Global[13] steht eine Kennung für die aktuelle Bildschirmauflösung. Diese entspricht dem Rückgabewert der XBIOS-Funktion getrez(), erhöht um die Zahl 2. Auch Global[14] wurde nicht verschont, es enthält die Anzahl der vom AES unterstützten Farben.

int appl_read (int ap_rid, int ap_rlength, void *ap_rpbuff);

Wird in ap_rid -1 übergeben, dann wartet appl_read() nicht mehr, bis tatsächlich eine Nachricht vorliegt, sondern kehrt bei einer leeren MSG-Queue sofort wieder zum Aufrufer zurück.

int appl_search (int ap_smode, char *ap_sname, int *ap_stype, int *ap_sid);

Diese Funktion liefert die AES-IDs aller AES-Prozesse im System zurück. Das Ganze funktioniert ähnlich wie bei Fsfirst()/Fsnext(). Mit ap_smode=APS_FIRST wird der Suchvorgang gestartet, ap_smode=APS_NEXT macht weiter, bis kein Prozeß mehr gefunden wird. Soll die ID der Shell (es gibt nur eine!) gefunden werden, muß ap_smode=APS_SHEL sein. Direkt zurückgeliefert wird eine 0 für nicht gefunden und die 1 im positiven Fall. Die restlichen Parameter:

ap_sname Ein Puffer mit Platz für mindestens neun Zeichen. In ihm wird der Name der gefundenen Applikation zurückgegeben.

ap_stype	Typ der Applikation:
	APK_SYS	1	Systemprozeß
	APK_APP	2	Applikation
	APK_ACC	4	Accessory
ap_sid	Die AES-ID

Wegen der unerwartet hohen Anteile an Neuerungen im AES 4.0, müssen wir Ihnen die weiteren Funktionen bis zur nächsten Ausgabe vorenthalten. Dort besprechen wir unter anderem Pop-Ups und die hierarchischen Menüs von GEM. (ah)


Richard Kurz
Aus: TOS 02 / 1993, Seite 84

Links

Copyright-Bestimmungen: siehe Über diese Seite