zurück : weiter : inhalt =


 

3               System

 

3.1                   Speicher

Die Einführung macht klar, daß irgendeine Form von Kontrolle über die benutzten Speicherbereiche erforderlich ist. Ohne diese könnten alle möglichen Jobs zur selben Zeit in denselben Bereichen arbeiten und einander die Daten verderben. So ist eine der wichtigsten Aufgaben des Qdos, dafür zu sorgen, daß keinesfalls irgendwelche zwei Jobs zufällig in dieselbe Speicherstelle schreiben. Was natürlich nicht heißt, daß wir einfach irgendein Programm zusammenstellen können und darauf vertrauen, daß Qdos nun die Schutzfunktion gegenüber anderen Programmen übernimmt. Schreiben von Daten irgendwohin in den Speicher wird mit einiger Sicherheit zum Zusammenbruch des Systems führen. Damit der Schutz wirksam werden kann, sind Regeln zu befolgen, wie sie hier beschrieben werden.

Der Ort, an den Qdos die Codeteile, also auch Programme, lädt, ist vorher nicht bekannt. Darum müssen sie folgenden Bedingungen genügen:
 

Auch sollte der Speicher in koordinierter Weise benutzt werden. Zwar übernimmt Qdos den Schutz alter und die Zuteilung neuer Bereiche, doch die Reihenfolge hängt vom Verlauf der Programme ab. Bei häufig veränderter Speicheraufteilung werden Teilbereiche freigegeben und in neuer Größe besetzt. So können bei unkontrolliertem Vorgehen Sperren durch noch vergebene Stücke entstehen, die den gesamten Speicher zerteilen. Geschlossene größere Bereiche lassen sich danach nur schwer wiedergewinnen. Ohne überlegte Anwendung richten die Hilfsmittel zur Speicherverwaltung auch nichts mehr aus. Ein "garbage collection" könnte durch Neuorganisation den Speicher aufräumen. Da so ein Zustand jedoch leicht vermeidbar ist, bietet das System dergleichen nicht an.
 
 

3.1.1   *       Speicheraufteilung

Als ersten Hinweis verfügen wir im Handbuch {20} über die "memory map", eine Tabelle der Speichereinteilung, die nun einzeln zu betrachten ist. Gelegentliche Hinweise auf noch nicht behandelte Systemdaten lasse man getrost erst einmal unbeachtet. Sie werden später nützliche Referenzen sein. Die hier angegebenen Adressen sind der Abstand in positiver Richtung (offset - Versatz) zur Basis der Systemvariablen, immer abgekürzt als (sb).
 
SV_RAMTOP : Ram Top
SV_RESPR : Resident Procedure Area, rpa
 SV_TRNSP : Transient Program Area, tpa
 SV_BASIC : SuperBASIC Area, sba
 SV_FREE : Bereich (bedingt) frei nutzbaren Speichers
 SV_CHEAP : Common Heap, System Heap, User Heap
SV_BASE : Die Basisadresse der Systemvariablen.

3.1.2   *       Speicherverwaltung

Neben den später behandelten Hilfsmitteln ist der Speicher das wesentliche Arbeitsgebiet eines jeden Computers. Alle Programme werden dort für den Zugriff durch den Processor bereitgehalten. Alle seine Operationen finden darin statt oder werden mit Hilfe dort abgelegter Daten gesteuert. So hat ein Betriebssystem auch die Verwaltung des Speichers zu ermöglichen.

Der Speicher kann vom Qdos jederzeit und in ständig wechselnder Aufteilung vergeben worden sein. Das System selbst oder Jobs und andere Programme veranlassen dies mittels einiger der Manager-Traps und Vectoren. Auch Routinen beim Einrichten oder Schließen von Kanälen haben neben der eigentlichen Aufgabe solche Funktionen zu erfüllen.

Daneben wickelt die Speicherverwaltung nicht nur Zuweisung und Freigabe von Speicherbereichen ab, sie erfüllt auch eine Schutzfunktion. Diese steckt tief im System und betrifft auch nur dessen Wirkungen. So kann es schnell geschehen, daß durch direkten Eingriff in einen reservierten Arbeitsbereich das ganze System zusammenbricht.

Die Datentypen erfordern jeweils besonderes Vorgehen:
 
 

3.1.2.1 - Residente Proceduren

                (von SV.RESPR(sb) bis SV.RAMT(sb)-1)

Der Bereich ist gegenüber Veränderungen durch das System geschützt. Darum können hier eingetragene Codeteile ohne Gefahr auch das Betriebssystem selbst verändern.

Es gibt je eine Manager-Trap, MT.ALRES (1/22) und MT.RERES (1/23), mit der dort Platz reserviert oder wieder freigegeben werden kann. Dies aber nur solange in der tpa noch kein Programm steht. Da jener Bereich nicht verschiebbar ist, wird dann eine Veränderung hier nicht mehr erlaubt.

MT.RERES wurde erst mit MINERVA funktionsfähig.
 
 

3.1.2.2 - Transiente Programme

(von SV.TRNSP(sb) bis SV.RESPR(sb)-1)
Dieser Bereich ist jederzeit veränderbar - nicht in seiner Lage, jedoch in seiner Größe und Aufteilung. Werden die Veränderungen an seinem offenen Ende vollzogen, so kann sich sein gesamter Bereich in den restlichen Speicher hinein ausdehnen oder Teile an ihn zurückgeben. "Offen" ist die Seite nach niedrigen Adressen zum Basic-Bereich hin, der sich als einziger auch in der Lage jederzeit verändern läßt. Sonst entstehen bei der Freigabe Lücken, die bei neuer Zuweisung im allgemeinen nur teilweise ausgefüllt werden, oder offen bleiben, wenn sie dafür zu klein sind. Qdos verwaltet diese Teilbereiche derart, daß sie später vollständig freigegeben werden können, sobald zum Ende hin keine besetzten Stellen mehr verzeichnet sind.

Die hier untergebrachten Programme sind das, was allgemein Job heißt. Die Traps MT.CJOB (1/1) oder MT.RJOB (1/4) und MT.FRJOB (1/5) richten dort Jobs ein und organisieren die zugehörigen Speicheranteile. Mit MT.FREE (1/6) wird der größte freie Bereich ermittelt. Weitere Möglichkeiten der Speicherzuweisung gibt es hier nicht.

Jedoch kann etwa ein Puffer in Gestalt eines niemals zu aktivierenden Jobs eingerichtet werden, oder es steht zur Sicherheit gleich an dessen Anfang eine endlose Schleife in Form eines Sprunges auf dieselbe Adresse.  Ein Beispiel liefert QUILL, und es zeigt zugleich, welch ein Unsinn das ist. Reine Bunker-Jobs kosten unnötig Zeit durch die Systemverwaltung und wegen der zusätzlichen Daten auch Speicher. Sie bieten kaum Vorteile gegenüber der ordentlichen Zuweisung und Freigabe mit MT.ALCHP rsp MT.RECHP (1/24, 25).
 
 

3.1.2.3 - Basic

                (von SV.BASIC(sb) bis SV.TRNSP(sb)-1)

Der (erste) Basic-Befehlsinterpreter wird durch das System automatisch als Job mit der Nummer (Job-ID) Null eingerichtet, sofern nicht eine ROM-Erweiterung das Betriebssystem sofort übernommen hat. Er reklamiert für die eigenen Daten und für das Programm, in diesem Falle nicht als Processorcode, sondern in Form eines tokenisierten Basic-Programms, seinen Teil des Speichers. Damit der nun für weitere Programme - Jobs - nicht versperrt wird, ist er, neben weiteren Basic-Interpretern bei MINERVA, der einzige Job, der sich in den Speicher hinein ausdehen oder auch Teile seiner selbst wieder aufgeben kann. Hierzu dienen MT.ALBAS (1/22) und MT.REBAS (1/23) - deren Funktion für SQ jedoch nicht mehr erklärt wird und zweifelhaft ist {15}.

 

3.1.2.4 - Heap in Varianten

                (SV.HEAP(sb) bis SV.BASIC(sb)-1)
  IOSS und File-Systeme kontrollieren ihre Speicherbereiche selbst, wie das in den betreffenden Handlern (s. dort) vorgegeben ist.
 

Heap Verwaltung durch das System

Für die freie Verwendung des Heap einmal ein Beispiel {1}:

Anfangs sei er unbenutzt und leer.

Dann reklamiert Job 'A' einen Teil davon beim Qdos, indem er den Bedarf mit MT.ALCHP (1/24) anmeldet. War genügend Platz frei, erhält er die Anfangsadresse in A0 mitgeteilt und der Heap sieht etwa so aus:
 
 
- frei -
 Bereich A
 
Dann kommt irgendein Job 'B', und will auch seinen Teil haben, ein weiterer Job 'C' setzt seinen Speicher darüber:
 
- frei -
Bereich C
Bereich B
 Bereich A
 
Nun wird irgendwann der Job 'B' entfernt. Weil Qdos über die Speichervergabe Buch führt, und erfährt, daß der Job auch ein Stück Speicher besaß, gibt es dieses frei:
 
- frei -
Bereich C
- frei -
 Bereich A
 
Ein weiterer Job reklamiert Speicher, und nachdem Qdos den erstbesten ausreichend großen Bereich gefunden hat, erhält dieser Job 'D' das entsprechende Stück in der eben freige-wordenen Lücke zugeteilt:
 
- frei -
Bereich C
- frei -
 D 
 Bereich A
 
Der nächste Job 'E' benötigt einen weit größeren Bereich, der nicht mehr zwischen 'D' und 'C' paßt, und so erhält ihn im noch unbenutzten Teil oberhalb von 'C'.

 
Bereich E
Bereich C
- frei -
D
 Bereich A
 
Schließlich kommt 'A' mit einer neuen Anforderung. Qdos weist ihm dann nach der Suche im Speicher die Stelle nach dem Bereich von 'D' unterhalb von 'C' zu, wo gerade noch genug Platz ist:
 
Bereich E
Bereich C
mehr A
D
 Bereich A
 
Werden nun etwa die Jobs A und C aufgegeben, ist vielleicht noch eine sonstwie genutzte Reservierung hinzugekommen, so kann ein neuer Job F von derselben Größe wie E nicht mehr ausgeführt werden, da der zusammenhängede Bereich trotz ansich genügend freien Speichers zu klein ist.
 
Bereich E
- frei -
S
D
- frei -
 
 

Vermeiden der "heap fragmentation"

Jetzt läßt sich auch erkennen, wie nach zahlreichen Zuweisungen und Freigaben der Speicher total zerstückelt sein wird:

Vor jedem reservierten Teilbereich stehen vier Langwort-Posten, mit deren Hilfe Qdos die Zuteilung verwaltet. Es ist darin zuerst die eigene Länge verzeichnet, und dann die Kennung des Besutzer-Jobs dieses Bereichs, weiter die Adresse des bei und zur Freigabe aufzurufenden Programmteils und schließlich ein für Markierungen durch das System freigehaltener Langwort-Platz.
SQ wandelt einmal mehr auf eigenen und geheimen Pfaden: Was herausgefunden werden konnte ist, daß statt der Adresse der Freigaberoutine u.U. eine Null eingetragen wird. Wie man damit ggf. umgehen kann, zeigt ein Beispiel im Anhang.

Nach der Freigabe steht am Anfang die Länge des von da an freien Bereichs und die Adresse des ggf. nächsten freien Blocks, rsp. eine Null am Ende der Kette.

Nur, wenn in Reihenfolge und mit absteigenden Adressen unmittelbar aneinander anschließende Bereiche reserviert wurden, kann Qdos die Teile später wieder zusammenfügen. Die Freigabe beginnt bei einem beliebigen Teilbereich und man fährt in unregelmäßiger Folge so fort. Benachbarte freie Felder werden dann zu einem entsprechend größeren Einzelblock zusammengefaßt. Irgendwann wird das Ende der Kette erreicht sein. Danach steht der gesamte Bereich ab dem zuerst freigegebenen Teil geschlossen zur Verfügung.

Der Anwender wird die Vergabe im allgemeinen nicht direkt kontrollieren können, denn diese geschieht vorrangig durch das System. Indirekt ist die Steuerung jedoch durch Wahl der Reihenfolge möglich, in der die betreffenden Jobs eingerichtet werden. So wird dann die geschlossene Freigabe aufgrund der zu erwartenden Reihenfolge beim Löschen wahrscheinlich.
Umso wichtiger sind geeignete Maßnahmen bei der Programmgestaltung. Dort ist es ein leichtes, und sinnvoll, statt der Zuweisungen eines einzigen Monster-Blocks oder gar mit den Datenbereich  des Jobs selber die Reservierung bedarfsweise in mehreren sinnfällig gestückelten Einzelposten vorzunehmen. Diese fügen sich dann sehr viel leichter in bestehende Lücken des Gesamtspeichers ein. Ein aufschlußreiches Beispiel gibt etwa die "zip"-Dateienkomprimierung mit über 300K "dataspace".

Verschachtelung von verketteten Speicherblöcken entsteht sehr leicht, wenn verschiedene länger im Speicher verweilende Jobs in unregelmäßiger Reihenfolge Reservierungen vornehmen.

Wurde der Block mit MT.ALCHP reserviert, und ist er auch weiterhin besetzt, steht an dritter Stelle die Adresse des nächsten besetzten Speicherteils, die anderen Werte beziehen sich dann ebenfalls auf besetzte Bereiche {MGG}. Die vierte Eintragung ist "unbenutzt", nicht aber zur freien Verwendung geeignet, denn spätere Betriebssysteme mögen durchaus Gebrauch davon machen (z.B. MINERVA).

Die Heap-Verwaltung bietet zugleich einen Ausweg aus der Misere. Qdos erlaubt nämlich auch das Einrichten eines User-Heap. Das ist ein Speicherblock, der von einem Job selbst in gleicher Weise verwaltet wird, wie der Common Heap durch Qdos. Mit Hilfe besonderer Aufrufe der Traps MT.ALLOC (1/12) und MT.LNKFR (1/13) richtet sich der betreffende Job den größtmöglichen oder -nötigen Block ein und teilt ihn dann nach Bedarf selber auf.

Der Vorgang beginnt mit dem Aufruf von MT.ALCHP, oder es dient dazu der eigene Datenbereich des Jobs. Der User-Heap wird dadurch errichtet, daß das Programm ein Pointerfeld der beschriebenen Art an den Anfang des Speicherblocks setzt.

Sein Pointer für den nächsten freien Bereich steht auf Null und das Längenfeld gibt die Größe des gesamten verfügbaren Bereiches an. Letzteres signalisiert später dem System das Ende der Liste. Die Pointer auf die jeweilige Folgeadresse sind relativ zu ihrer eigenen Position. Die A6-relative Adresse des Pointerfeldes dient dann als Basis für die Trap-Aufrufe. Das Programm muß neben der Adresse des aktuellen Pointerfeldes die Gesamtlänge speichern und verfügbar halten.

Ein so eingerichteter User-Heap kann durch Ankoppeln an das Ende der Liste freier Bereiche des Common Heap dorthin ausgedehnt werden. Aufgrund der vollständig relativen Adressierung ist er auch verlagerbar.

Auch die Vectoren MM.ALCHP ($C0) und MM.RECHP ($C2), dann MM.ALLOC ($D8) und MM.LNKFR ($DA), sind hierfür einsetzbar. Im Unterschied zu den Trap-Aufrufen wird dort absolut adressiert, sodaß diese Vectoren weniger flexibel anzuwenden sind.

Die ersten beiden sind vornehmlich zum Gebrauch innerhalb von Device-Handlern gedacht. Sie dürfen keinesfalls aus einem Interrupt-Service heraus und nur im Supervisor-Betrieb aufgerufen werden. A6 muß die Basisadresse der Systemvariablen enthalten.

Im Vorgriff auf später zu Erklärendes schon einmal der Hinweis, daß die erstmalige Zuweisung von Kanälen auf die einzelnen Geräte vor allen anderen Reservierungen erfolgen sollte. Ganz besonders, wenn Directory Devices betroffen sind, z.B. Microdrive oder Floppy. Diese richten sich für jedes Laufwerk besondere Tabellen in unteren Speicherbereich ein, die auch nach Schließen aller Kanäle ihre Speicherblöcke nicht mehr zurückgeben.

Eine einfache Maßnahme besteht darin, gleich zu Anfang auf allen Laufwerken einen Kanal aufzumachen und ihn sofort wieder zu schließen. Dann stehen die Tabellen am Anfang des System Heap und können von nun an keinem Job mehr hinderlich werden.

 

3.1.2.5         *       Queue

Wie bei einer einfachen Speicherreservierung wird auch hier ein Header aus 16 Bytes aufgebaut, den aber diesmal das IOSS betreut. Es folgt der Pufferspeicher.

Eingerichtet wird solch eine Queue mit dem Vector IO.QSET ($DC), dem neben der Puffergröße in D1 die Basisadresse eines um mindestens 16 Bytes größeren freien Speicherbereichs mitzugeben ist.
 
 
eoff | nextq
end
nextin
nextout
 queue
0 = basis 4:ende 8:schreiben 12:lesen 16+: Daten...
 

 
Pufferspeicher dieser Art sind auch ohne ausdrückliche Bereichszuweisung einzurichten. Wie das Betriebssystem die Organisation übernimmt, wie es solche Bereiche freigibt, und wie Programme sich dieser Einrichtung bedienen können, erklären die Darstellungen zu den verschiedenen Devices. - Mit, was will man anderes erwarten, gewissen "Ausnahmen" für die SQ-Systeme.
 
 

3.1.2.6 *       Allgemeine Strukturen

Die Queue ist Vorstufe eines Device, der PIPE, wo selbst eine Basisadresse nicht mehr bekannt sein muß. Damit ist eine Form virtuellen Speichers vollständig installiert. rsp, um mit der Mode zu gehen, ein "Objekt", auf das mit den "Methoden" in Gestalt der Qdos-Traps zugegriffen wird.

In weiter gefaßtem Sinne sind auch alle anderen Geräte des QL, soweit sie mit der Speicherung von Daten zu tun haben, virtuelle Speicher und "Objekte". Zugriffsmittel (oder "Methoden" des Zugriffs) sind dabei die Traps und Vectoren des Qdos. So wird die Position in einem File etwa der Ram-Disc auf dieselbe Weise eingestellt, wie das bei der Floppy Disc geschieht. Anschaulicher noch wird das mit dem MEM-Device aus {4}, dessen Arbeitsbereich der gesamte als RAM oder ROM "wirkliche" Speicher ist. Es kann sogar über Netzwerk gleichermaßen im Speicher eines anderen QL wirksam werden, für die Anwendung erscheint es prinzipiell ohne Unterschied.

Geräteabhängiges braucht uns nicht zu kümmern, es wird bestens und zuverlässig vom jeweiligen Handler betreut.

Wie die noch folgenden Ausführungen zeigen werden, ist diese konsequent durchgeführte Einrichtung der virtuellen Speicher eine große Stärke des Betriebssystems.
 
 


 
  oben : zurück : weiter : inhalt 

(count)