Programmiererecke: Von Fenstern und Speicherplatz

Die Programmiererecke feiert 25. Jubiläum! Anlaß, an die zurückliegenden zwei Jahre zu erinnern, in denen wir immer wieder mit brauchbaren Anregungen versuchten, Programmentwicklern die Arbeit zu erleichtern.

Die »wind_update()«-Funktion scheint sich zu unserem Lieblingsthema zu entwickeln. Auch diesmal gibt es Neues von der wind_update()-Front. Bei der Arbeit mit dem alternativen Desktop »Gemini« geschah es mehrfach, daß Gemini in der Boot-Phase den Bildschirminhalt löschte, obwohl ein Accessory sich zuvor die Schreibrechte mittels wind_update(BEG_UPDATE);7 gesichert hatte. Das Ergebnis war Bildmüll in schönsten Regenbogenfarben; eigentlich ein untrügliches Zeichen für einen vergessenen wind_update()-Aufruf. Doch weit gefehlt: Gemini verschachtelt seine wind_update()-Aufrufe sorgfältig und fehlerfrei. Woher aber sollte dann der verstümmelte Bildschirm stammen? Wieso »vergaß« TOS den gesetzten wind_update()-Status?

Des Rätsels Lösung: ein »wind_new()«-Aufruf von Gemini. Diese Funktion ist erst seit TOS 1.04 implementiert und in vielen Dokumentationen ungenügend erläutert. Atari schreibt jedoch in der offiziellen TOS-1.04-Dokumentation: »wind_new() closes and deletes all windows, resets the wind_update() function, flushes and restores mouse ownership back to the system« - die Funktion schließt und löscht also sämtliche geöffneten Fenster und setzt - das ist an dieser Stelle entscheidend - den wind_update()-Status zurück, was den »MCTRL«-Parameter dieser Funktion einschließt, der die Mauskontrolle abgibt. Was bedeutet das in der Praxis?

Da wind_new() den Status aller vorangegangenen wind_update()-Aufrufe zurücksetzt, werden einem Accessory, das sich ordnungsgemäß die Schreibrechte gesichert hat, der Boden unter den Füßen weggezogen, respektive dem Accessory die Schreibrechte radikal entzogen. Nur ist im GEM leider keine Routine vorgesehen, mit der das Hauptprogramm dies dem Accessory mitteilen könnte. Um Pixelmüll zu vermeiden, muß demzufolge das Programm, das den wind_new()-Aufruf tätigt, selbst sicherstellen, daß sämtliche anderen Prozesse ihre Schreibzyklen abgeschlossen haben. Und dies erledigt das Programm am einfachsten, indem es vor jedem wind_new()-call einen wind_update()-Aufruf tätigt [3]. Verwenden Sie die Zeilen

wind_update (BEG_UPDATE); 
wind_new(); 

und ihr Hauptprogramm wird kein Accessory bei der Ausgabe behindern. Noch etwas ist zu beachten: Da wind_new() selbstverständlich auch den wind_update()-Status der Hauptapplikation löscht, darf kein wind_update (END_UPDATE); diesen Zeilen folgen, denn der Schreibstatus ist zu diesem Zeitpunkt ja bereits gelöscht.

Wie seit langem dokumentiert ist, lädt TOS beim Programmstart jedes Programm in den größten freien Speicherblock und stellt ihm diesen bei Programmstart vollständig zur Verfügung. Beim TT bestimmen darüber hinaus einige Programm-Headerflags den Speicher, in den das Programm reloziert wird. Tatsache ist, daß der größte freie Speicherblock dem Programm so lange zur Verfügung steht, bis es den Block mittels »Mshrink()« verkleinert. Dies ist bei Nicht-GEM-Programmen nicht zwingend, denn das Betriebssystem kann während des Programmablaufs ohnehin keine weiteren Prozesse bearbeiten, die eventuell Speicher benötigen würden. Ein sauberes GEM-Programm gibt jedoch sämtlichen nicht benötigten Speicher frei, um ihn anderen Prozessen (beispielsweise Accessories) zur Verfügung zu stellen. Darüber hinaus benötigt das AES seinerseits freien Speicher, Atari empfiehlt mindestens 8 KByte freizulassen.

Dennoch halten sich viele Programme nicht an diese Richtwerte, sondern geben entweder den unbenutzten »Heap« nicht wieder frei oder allozieren nach der Freigabe erneut große Teile des freien Restspeichers. Gerade im Multiprozeßsystem entstehen dadurch enorme Probleme: Accessories erhalten zu wenig freien Speicher, und auch im Hinblick auf ein lang erwartetes wirklich multitaskingfähiges Atari-GEM sollte von dieser Praxis abgesehen werden.

Sich zu ärgern nutzt nichts - Selbsthilfe ist gefragt: Unser »Mxalloc/2«-Assembler-Listing hängt sich in den GEM-DOS-Trap und fängt darin die Aufrufe »Malloc()« und »Mxalloc()« ab. Es prüft danach, ob dem Systemaufruf als Parameter der Wert -1 angegeben wurde, mit dem TOS selbst und jedes andere laufende Programm ermittelt, welche Größe der größte noch freie Speicherblock besitzt. Sofern dies der Fall ist, bemüht unser Programm erst einmal die normale OS-Routine. Nach dem Ausführen dieser Routine kehrt es jedoch nicht einfach ins aufrufende Programm zurück, sondern halbiert erst einmal den Rückgabewert. Damit wird dem System vorgegaukelt, der größte freie Speicherblock sei nur halb so groß, wie er faktisch ist. Das aufrufende Programm wird folglich weniger Speicher allozieren, als es dies eigentlich tun dürfte, was dazu führt, daß der Speicher sich in wesentlich kürzerer Zeit füllt als bisher. Der Nachteil dieser Methode sollte jedoch auch nicht verschwiegen werden: Der Speicher wird mehr und mehr in kleine Bruchstücke zerteilt, was jedoch bei den neueren TOS-Versionen (ab 1.04 aufwärts) kein wesentliches Manko mehr ist, da hier die Speicherverwaltung recht intelligent bewerkstelligt wird und der berüchtigte »Out Of Internal Memory«-Fehler kaum mehr auftritt.

Nach dem Programmstart initialisiert sich ein Teil unseres Assembler-Programms resident im Speicher. Es benutzt dazu das »XBRA«-Verfahren, anhand dessen sich das Programm auch wieder deaktivieren läßt, falls sich die Speichersegmentierung entgegen allen Erwartungen negativ auf das Gesamtsystem auswirkt. Beim erneuten Programmstart wird deshalb das Programm deaktiviert, beim dritten wieder eingeschaltet und so fort.

(uw)

Literaturverweise:

[1] H-D. Jankowski, J. F. Reschke, D. Rabich, »Atari ST Profibuch«, 2. überarbeitete Auflage, Sybex Verlag 1989

[2] »Rainbow TOS Release Notes«, Atari Corp. 1989

[3] L. Prüßner, »GEM-Verkehrsplanung: Aktion sauberer Bildschirm«, ST-Magazin 11/89, Seiten 68ff., Markt & Technik Verlag

Zwei Prozesse, die gleichzeitig auf dem Bildschirm aktiv sein dürfen. Schuld ist der wind_new()-Aufruf.

******************************************************************
* This file was created by SYS_MON, the ATARI ST System Monitor,
* copyright by Karsten Isakovic, Berlin
*
* it is forbidden to publish this file or extracts or It without
* the copyright header !

 MAIN	Supexec	CODE $06DFCE ->
 MAIN	evnt_timer	100,0
>ACC	evnt_timer	-> 0
 ACC	wind_update	BEG_UPDATE	; ACC beantragt UPDATE
>MAIN	evnt_timer	-> 0
 MAIN	evnt_timer	100,0
>ACC	wind_update	-> 1	; bewilligt!
 ACC	evnt_timer	255,0
>MAIN	evnt_timer	-> 0
 MAIN	evnt_timer	100,0-> 0
 MAIN	wind_new	-> 0	; Status wird gelöscht
 MAIN	wind_update	BEG_UPDATE -> 1	; für MAIN ebenfalls!
 MAIN	evnt_timer	100,0

*
* End of SYS_MON file
******************************************************************

Listing: Malloc/2


Laurenz Prüßner
Aus: ST-Magazin 03 / 1991, Seite 92

Links

Copyright-Bestimmungen: siehe Über diese Seite