sslxy

amigaos-exec

Nicht „AmigaDOS allein“, sondern die ganze Schichtung: Exec unten, AmigaDOS darüber, Shell und Dateisystem als konkrete Arbeitsoberfläche.

AmigaOS wird oft oberflächlich beschrieben: Workbench, bunte Fenster, Multitasking, Guru Meditation. Das ist die sichtbare Schicht. Technisch interessant ist der Unterbau: Exec als kleiner Kernelkern mit Scheduling, Signals, Ports, Messages, Interrupts und Speicherverwaltung; darüber Libraries und Devices; darüber wiederum AmigaDOS mit Shell, Dateinamenraum, Handlern, Dateisystemzugriff und Prozesslogik.

Genau dort wird die Sache sauber. Wer nur „AmigaDOS“ sagt, meint oft das ganze System und beschreibt dann in Wirklichkeit Exec. Wer nur „Exec“ sagt, vergisst schnell, dass die tägliche Arbeit auf dem Amiga eben nicht aus nacktem Scheduling bestand, sondern aus Shell, Scripts, Assigns, File Handles, Locks, Handlern und DOS-Packets. Diese Seite trennt das. Das ist der eigentliche Zweck.

System Diagnostic

> AMIGAOS / EXEC / DOS ANALYSIS
JAHR 1985 – frühes AmigaOS mit Exec + Intuition + AmigaDOS KERN Exec – Scheduling, Tasks, Signals, Ports, Messages, Interrupts, Memory EXECBASE zentrale klassische Kernelstruktur mit Systemlisten, Speicherlisten, aktuellem Task und Zustandsdaten STARTUP Resident-Tags, InitResident, Prioritäten und Initialisierungsreihenfolge verbinden ROM und nachgeladene Module TASK STATES laufend, bereit, wartend und Sonderzustände; Priorität entscheidet unter lauffähigen Tasks SIGNALS 32 Bits pro Task; ein Teil systemreserviert, freie Bits müssen zugeteilt und wieder freigegeben werden SYNC SignalSemaphore bevorzugt; Forbid/Permit und Disable/Enable nur für eng begrenzte kritische Abschnitte DEVICE I/O IORequest + ReplyPort + OpenDevice; synchron über DoIO oder asynchron über SendIO/WaitIO DOS-SCHICHT AmigaDOS – Shell, Dateisystem-Namensraum, Handler, Locks, File Handles, Scripts HERKUNFT AmigaDOS 1.x auf TRIPOS-/BCPL-Basis, später stärker in C umgebaut PROZESSMODELL DOS-Process = Exec-Task + Exec-Message-Port + DOS-spezifische Struktur IPC Exec Messages / MsgPorts / Signals sowie DOS-Packets für Handler-Kommunikation ALERTS Guru Alert = strukturierter Fehler-/Alarmmechanismus, nicht bloß Folklore
Das System ist nicht „magisch“. Es ist geschichtet. Genau das macht es lesbar.
[context/1985]

Kontext 1985: warum AmigaOS auffiel

Mitte der 1980er war grafische Oberfläche allein noch kein Alleinstellungsmerkmal mehr. Interessant wurde es dort, wo ein Heimcomputer mehrere Dinge gleichzeitig konnte, ohne dass das gesamte System dabei auseinanderfiel. Genau dort fiel der Amiga auf: Grafik, Audio, Mausoberfläche und gleichzeitig echtes präemptives Multitasking auf einer Maschine, die preislich nicht im Workstation-Bereich lag.

Das Entscheidende ist aber: Dieses Multitasking war nicht nur ein Werbebegriff. Es war systemisch im Kern verankert. Exec verwaltete Tasks, Prioritäten, Ports, Messages und Signals so, dass mehrere Komponenten des Systems gleichzeitig aktiv sein konnten, ohne auf kooperatives Wohlverhalten aller Programme angewiesen zu sein. Das war 1985 im Heimcomputerbereich kein Normalzustand.

Gleichzeitig war das System nicht monolithisch im Sinn eines alles verschlingenden Kernels. AmigaOS war früh klar geschichtet: Exec als Kern, darüber Libraries und Systemdienste, Intuition für die GUI, AmigaDOS für Shell, Dateisysteme und Dateinamenraum. Wer diese Schichten nicht trennt, beschreibt am Ende alles unsauber.

„Der eigentliche Fortschritt war nicht die Oberfläche. Er war die Architektur darunter.“

[architecture/layers]

Systemschichten und Zuständigkeiten

Beim klassischen Amiga ist „das Betriebssystem“ kein einzelner großer Block. Verschiedene Schichten greifen ineinander, bleiben aber technisch unterscheidbar. Eine Funktion wie das Öffnen einer Datei kann deshalb Exec-Mechanismen benutzen, ohne selbst zum Exec-Kern zu gehören.

Schicht Typische Verantwortung
Exec Tasks, Scheduler, Signals, Ports, Messages, Interrupts, Speicher, Libraries, Devices und Resources.
System-Libraries Grafik, Intuition, Utility-Funktionen und weitere klar abgegrenzte APIs.
AmigaDOS Processes, Shell, Dateinamenraum, Handler, Locks, File Handles, Assigns und DOS-Packets.
Workbench / Intuition Grafische Arbeitsoberfläche, Fenster, Menüs, Gadgets, Icons und Benutzerinteraktion.
Custom-Chips DMA, Grafik, Audio, Diskettenlogik und Hardwareereignisse; vom Betriebssystem koordiniert, aber keine Betriebssystemschicht.

Die Schichten sind nicht voneinander isoliert. AmigaDOS-Handler verwenden Exec-Message-Ports. Intuition sendet IDCMP-Messages über Exec-Ports. Devices arbeiten mit IORequests und ReplyPorts. Die Trennung liegt also in der Zuständigkeit und API, nicht in vollständig abgeschotteten Welten.

„Exec stellt die Mechanik bereit. Die darüberliegenden Schichten geben ihr Bedeutung.“

[kernel/exec]

Exec: was der Kernelkern wirklich macht

Exec ist der eigentliche Kern des Systems. Nicht „das ganze OS“, sondern der Teil, der die fundamentalen Mechanismen bereitstellt: Taskverwaltung, Scheduling, Signale, Message Ports, Interrupts, Speicherallokation und das Öffnen bzw. Schließen von Libraries und Devices. Man kann Exec als kleinen Kernelkern bezeichnen. Nicht deshalb, weil später das Wort „Mikrokernel“ modern wurde, sondern weil seine Aufgabe tatsächlich auf diese Grundmechanismen konzentriert ist.

Exec organisiert viele seiner internen Strukturen als verkettete Listen. Das ist kein Zufall und keine Eleganzübung. Es ist effizient, einfach nachvollziehbar und auf einer 68000-Maschine mit knappen Ressourcen sinnvoll. Ready-Listen, Waiting-Listen, Ports, Nodes – die gesamte Systemlogik ist stark listenorientiert.

[Exec Core]
> Scheduling von Tasks nach Priorität
> Wait/Signal-Mechanismus statt sinnlosem Polling
> MsgPorts und Messages als generische IPC-Basis
> AllocMem()/FreeMem() als grundlegende Speicherpfade
> Libraries und Devices werden dynamisch geöffnet, nicht statisch vorausgesetzt

Das Entscheidende an Exec ist nicht, dass es „viel“ macht. Es macht im Gegenteil relativ wenig – aber genau die richtigen Dinge. Alles, was darüber liegt, kann sich auf diese Grundmechanismen verlassen. Das ist der Grund, warum das System trotz begrenzter Hardware so lebendig wirkte.

Task-Level und Interrupt-Level

Gerade weil Exec Interrupts im Kern mitführt, muss man Task-Kontext und Interrupt-Kontext sauber trennen. Ein normaler Task läuft schedulierbar im üblichen Exec-Ablauf. Ein Interrupt dagegen unterbricht diesen Ablauf auf Hardware-Ereignisse hin und läuft nicht als gewöhnlicher DOS- oder Shell-Kontext. Auf Interrupt-Level gelten andere Regeln: kurz bleiben, keine unnötigen Seiteneffekte, keine DOS-Logik hineinziehen, keine bequemen Annahmen über blockierende Aufrufe machen.

Genau das ist beim Amiga mit seinen Level-1-bis-7-Interrupts und den Custom-Chips praktisch relevant. Die Architektur ist nicht deshalb interessant, weil sie „Interrupts auch kann“, sondern weil sie sauber zeigt, dass asynchrone Hardware-Ereignisse und schedulierbare Tasks zwei verschiedene Ebenen sind. Wer diese Ebenen vermischt, macht aus einem lesbaren System sehr schnell ein unlesbares.

[kernel/execbase]

ExecBase: zentrale Struktur des klassischen Systems

ExecBase ist die zentrale Datenstruktur von Exec. Sie ist nicht nur eine Funktionsbasis, sondern enthält beziehungsweise referenziert wesentliche globale Systemzustände: den aktuellen Task, Tasklisten, Speicherlisten, Library-, Device-, Resource-, Port- und Semaphorelisten sowie CPU- und Systeminformationen.

Auf klassischen 68k-Amigas liegt der Zeiger auf ExecBase traditionell an absoluter Adresse 4. Diese historische Konvention machte den Einstieg in Exec sehr direkt, darf aber nicht als allgemein gültiges Modell für moderne AmigaOS-Varianten oder andere Architekturen verallgemeinert werden.

ThisTask

Verweis auf den aktuell laufenden Task. Viele Exec-Funktionen beziehen ihren Kontext daraus.

TaskReady / TaskWait

Listen für lauffähige und wartende Tasks. Direkter Zugriff verlangt korrekte Synchronisation.

MemList

Verwaltete Speicherregionen mit ihren Eigenschaften und freien Bereichen.

Systemlisten

Libraries, Devices, Resources, Ports und Semaphoren werden in benannten Listen organisiert.

[Classic_68k_Context]
> SysBase pointer conventionally obtained from address 4
> ExecBase exposes system state, not private application storage
> lists require documented locking discipline
> direct visibility increases responsibility
[kernel/resident_startup]

Resident-Module und Systemstart

Exec verbindet die einzelnen Systembestandteile über Resident-Strukturen, historisch oft als ROMTags bezeichnet. Ein Resident-Tag beschreibt unter anderem Modulname, Version, Initialisierungsart, Priorität und Einsprung beziehungsweise Init-Daten.

Beim Start sucht das System nach gültigen Resident-Strukturen und initialisiert Module in einer definierten Reihenfolge. Libraries, Devices und andere Systemkomponenten können dadurch aus Kickstart-ROM, Erweiterungs-ROM oder diskbasierten Segmenten in dasselbe Initialisierungsmodell eingebunden werden.

  • Matchword und Selbstverweis: helfen beim zuverlässigen Erkennen der Resident-Struktur.
  • Flags: bestimmen unter anderem, in welcher Startphase ein Modul initialisiert wird.
  • Priorität: ordnet Module innerhalb einer Initialisierungsphase.
  • InitResident: wertet die Struktur aus und erzeugt beziehungsweise startet die beschriebene Komponente.
  • Expansion-Hardware: kann eigene Diagnoseroutinen und Resident-Tags mitbringen.

Damit wird verständlich, warum AmigaOS nicht aus einer einzigen statisch gelinkten Kerneldatei besteht. Das System setzt sich aus Modulen zusammen, die nach gemeinsamen Konventionen entdeckt und initialisiert werden.

[Resident_Startup]
> locate valid Resident structure
> classify startup phase and priority
> InitResident creates or launches module
> ROM and expansion components share one startup vocabulary
[kernel/tasks]

Tasks, Scheduling und Prioritäten

Exec arbeitet mit Tasks, nicht im modernen Sinn mit stark isolierten Prozessen. Speicherschutz im heutigen Sinn gibt es nicht. Das bedeutet: Der Scheduler kann elegant und schnell sein, aber ein fehlerhaftes Programm kann weiterhin das ganze System beschädigen. Das ist kein Widerspruch, sondern die reale Form dieses Systems.

Der Scheduler ist präemptiv. Ein laufender Task muss die CPU nicht freiwillig abgeben; Exec kann umschalten, sobald die Bedingungen dafür vorliegen. Dazu kommen Prioritäten. Ein Task mit höherer Priorität verdrängt niedrigere, sofern er lauffähig ist. Das ist praktisch, aber auch gefährlich: Ein schlecht geschriebener Task mit zu hoher Priorität kann ein System effektiv ausbremsen.

Task

Die grundlegende ausführbare Einheit innerhalb von Exec. Enthält Kontext, Priorität, Stackinformationen und ist in die Exec-Listen eingebunden.

Ein Task ist zunächst Exec-seitig gedacht. DOS-spezifische Eigenschaften kommen erst darüber.

Priorität

Steuert, wie aggressiv ein Task gegenüber anderen bevorzugt wird. Nützlich für Systemdienste, aber problematisch, wenn Anwendungssoftware unnötig hoch priorisiert.

Das System ist damit flexibel, verlangt aber Disziplin vom Programmierer.

Wait statt Busy Loop

Gut geschriebene Tasks warten auf Signale, Messages oder I/O-Ereignisse. Schleifen, die nur CPU verbraten, sind auf dem Amiga besonders auffällig und besonders schlecht.

Kein Speicherschutz

Der Scheduler kann präemptiv und sauber sein, trotzdem bleibt das System verwundbar. Ein Schreibzugriff an die falsche Adresse ist kein lokales Problem, sondern potentiell ein Systemproblem.

Genau hier liegt einer der charakteristischen Züge des Amiga: technisch elegant, aber nicht paternalistisch. Das System hilft, aber es schützt nicht gegen jeden Fehler. Das ist leistungsfähig, solange die Beteiligten wissen, was sie tun.

[kernel/scheduler_states]

Scheduler und Taskzustände

Präemptives Multitasking bedeutet nicht, dass jeder Task ständig einen gleich großen Zeitscheibenanteil erhält. Exec betrachtet zuerst, welche Tasks überhaupt lauffähig sind, und berücksichtigt anschließend ihre Prioritäten. Ein wartender Task verbraucht keine CPU-Zeit, bis ein Ereignis ihn wieder aktiviert.

Zustand Einordnung
Running Der Task besitzt aktuell die CPU und ist über ExecBase als laufender Task sichtbar.
Ready Der Task könnte laufen und wartet in der Ready-Liste auf seine Auswahl.
Waiting Der Task schläft, typischerweise in Wait(), bis eines seiner erwarteten Signale eintrifft.
Exception Für den Task ist eine Exception- beziehungsweise Signalbehandlung vorgemerkt.
Removed Der Task ist nicht mehr normal in Ready- oder Wait-Listen eingeordnet.

Tasks gleicher Priorität können sich die CPU zeitlich teilen. Ein höherpriorisierter lauffähiger Task kann einen niedrigeren verdrängen. Das Prioritätssystem eignet sich für zeitkritische Systemaufgaben, darf aber nicht als Ersatz für sauberes Warten und Ereignissteuerung missbraucht werden.

Wait ist aktive Systemdisziplin

Wait() prüft die gewünschten Signalbits und versetzt den Task bei Bedarf in den Wartezustand. Das ist kein Leerlauf im schlechten Sinn, sondern gibt die CPU bewusst an andere Arbeit ab. Busy-Wait-Schleifen umgehen genau diesen Vorteil.

[kernel/ipc]

Signals, Message Ports und Messages

Einer der stärksten Teile von Exec ist die Interprozess-Kommunikation. Nicht im Sinn schwerer, abstrakter Frameworks, sondern direkt und effizient: Ein Task kann auf Signale warten; Messages können über Message Ports zwischen Tasks verschickt werden. Das System bleibt dabei asynchron und klar.

Signals

Jeder Task hat eine Signalmaske. Signale sind Bitmarkierungen, auf die ein Task mit Wait() warten kann. Sie sind die leichtgewichtigste Form der Synchronisation: „Es ist etwas passiert, mach weiter.“ Mehr nicht. Gerade deshalb sind sie nützlich.

Message Ports

Ein Message Port ist ein Zielpunkt für Nachrichten. Ein Task besitzt typischerweise einen Port oder mehrere Ports; andere Tasks können Messages dorthin schicken. Intern hängen an einem Port Listen von Messages. Ein Port ist also kein bloßer Handle-Wert, sondern ein realer Knotenpunkt im Exec-Modell.

Messages

Messages sind Datenstrukturen mit Header und Nutzdaten, die an Ports geschickt werden. Das Grundprinzip ist pointerbasiert: Es werden nicht zwangsläufig große Datenblöcke kopiert, sondern Strukturen übergeben. Das ist schnell, setzt aber saubere Besitz- und Lebensdauerlogik voraus.

[Exec IPC Ablauf]
> Task A erzeugt/füllt Message-Struktur
> PutMsg(portB, msg)
> Exec hängt Message in Port-Liste ein
> zugehöriges Signal für Task B wird gesetzt
> Task B wacht auf, GetMsg(portB), verarbeitet und antwortet ggf.

Dieses Modell ist bemerkenswert, weil es zugleich einfach und systemweit brauchbar ist. Es ist keine Sonderlösung für irgendeine GUI-Schicht, sondern ein Grundbaustein. Genau deshalb taucht es auch später in der DOS-Schicht wieder auf – dort allerdings in spezialisierter Form über DOS-Packets und Handler.

[kernel/message_ownership]

Message-Eigentum, Queue und ReplyMsg

Exec kopiert beim normalen Message-Passing nicht automatisch den gesamten Nachrichteninhalt. PutMsg() hängt einen Zeiger auf die Message-Struktur in die Queue des Zielports. Dadurch ist die Übergabe schnell, verlangt aber eine klare Eigentumsregel.

  1. Sender bereitet die Message vor: Struktur, Nutzdaten und ReplyPort müssen gültig bleiben.
  2. PutMsg: der Sender übergibt die Message an den Empfänger und darf sie bis zur Rückgabe nicht verändern oder freigeben.
  3. Portsignal: der Besitzer des Zielports wird über das zugehörige Signal geweckt.
  4. GetMsg: der Empfänger entfernt die Message aus der Portqueue und verarbeitet sie.
  5. ReplyMsg: bei einem Request/Reply-Protokoll geht die Message über den ReplyPort zurück.
  6. Sender übernimmt wieder: erst jetzt darf er Speicher und abhängige Daten wiederverwenden oder freigeben.

Ein gesetztes Portsignal bedeutet nicht zwingend, dass beim späteren GetMsg() noch genau eine Message bereitliegt. Mehrere Ereignisse können zusammenfallen, andere Logik kann die Queue bereits leeren, und Signals sind Bits statt Ereigniszähler. Deshalb wird eine Portqueue nach dem Aufwachen normalerweise vollständig mit GetMsg() geleert.

[Request_Reply_Ownership]
> sender owns message
> PutMsg transfers ownership to receiver
> receiver processes and ReplyMsg returns ownership
> pointer transfer is fast only when lifetime rules are obeyed

„Eine Message wird nicht nur gesendet. Für eine Zeit wird ihr Speicher ausgeliehen.“

[kernel/synchronization]

SignalSemaphore, Forbid/Permit und Disable/Enable

Nicht jede gemeinsam genutzte Datenstruktur braucht dieselbe Art von Schutz. Exec stellt unterschiedliche Mechanismen bereit. Ihre Reichweite unterscheidet sich erheblich – von gezielter Ressourcenarbitration bis zur zeitweisen Unterbindung des gesamten Taskwechsels oder der Interruptverarbeitung.

Mechanismus Wirkung
SignalSemaphore Schützt gezielt eine gemeinsam genutzte Ressource. Andere Tasks können schlafen, statt das gesamte Multitasking anzuhalten.
Forbid / Permit Unterbindet Taskwechsel für einen sehr kurzen kritischen Abschnitt. Interrupts laufen weiter.
Disable / Enable Unterbindet Interruptverarbeitung und damit praktisch auch präemptives Scheduling; nur für extrem kurze hardware- oder interruptkritische Abschnitte.

Semaphoren sind für normale gemeinsam genutzte Daten die bevorzugte Lösung, weil nur konkurrierende Benutzer warten. Forbid() kann nötig sein, wenn eine klassische globale Exec-Liste atomar gesucht und unmittelbar benutzt werden muss. Disable() ist noch einschneidender und darf nicht als bequemes allgemeines Schloss verwendet werden.

Ein direkter oder indirekter Aufruf von Wait() bricht einen Forbid- oder Disable-Zustand auf. Deshalb sind I/O, Ausgabe und andere möglicherweise blockierende Funktionen innerhalb solcher Abschnitte gefährlich.

[kernel/interrupts]

Interrupts, Serverketten und Task-Exceptions

Hardwareereignisse erreichen den 68000 über Interruptstufen. Exec organisiert dafür Vektoren, Interrupt-Handler und bei gemeinsam genutzten Quellen priorisierte Interrupt-Serverketten. Ein Interrupt-Server wird nicht wie ein normaler Task geplant, sondern im Interruptkontext aufgerufen.

  • Interrupt-Handler: bedient eine exklusiver zugeordnete Interruptquelle.
  • Interrupt-Server: Teil einer priorisierten Kette für eine gemeinsam ausgewertete Interruptstufe.
  • AddIntServer / RemIntServer: verwalten Server in der jeweiligen Kette.
  • Cause: löst einen Softwareinterrupt über eine Interrupt-Struktur aus.
  • Task-Exception: nutzt Signals, um im Kontext des betroffenen Tasks eine besondere Behandlung auszuführen.

Interruptcode darf nicht beliebig Libraries, DOS-Funktionen oder blockierende Dienste aufrufen. Er soll den Hardwarezustand sichern, das Ereignis quittieren, minimale Daten bereitstellen und die aufwendigere Verarbeitung an einen Task delegieren – häufig über Signal, Message oder Softwareinterrupt.

[Interrupt_Design]
> acknowledge hardware quickly
> store minimal state
> Signal task or enqueue work
> leave complex processing to schedulable context
[kernel/memory]

Speicherverwaltung, Chip-RAM, Fast-RAM und Fragmentierung

Exec verwaltet mehrere physische Speicherregionen über Memory-Header. Ein Allokationsaufruf kann Eigenschaften verlangen, etwa Chip-erreichbaren Speicher oder beliebigen geeigneten Speicher. Die Rückgabe ist ein echter Zeiger auf zusammenhängenden Speicher – kein geschützter Handle.

Chip-RAM

Muss für Daten verwendet werden, auf die klassische Custom-Chips direkt per DMA zugreifen: Bitplanes, Sprites, Audio- und Diskettenpuffer.

Fast-RAM

Steht primär CPU und geeigneten Erweiterungen zur Verfügung und konkurriert nicht mit den Custom-Chips um dieselben klassischen Chip-RAM-Zyklen.

AllocMem / AllocVec

Klassische Allokationswege. Größe, Flags und passender Freigabeaufruf müssen zusammenpassen.

Pools

Spätere Exec-Versionen bieten Speicherpools, um viele kleine Allokationen effizienter zu bündeln und Fragmentierung zu reduzieren.

Die Anzeige „noch viele Kilobyte frei“ garantiert nicht, dass ein einzelner großer zusammenhängender Block verfügbar ist. Häufiges Anlegen und Freigeben unterschiedlich großer Blöcke kann den freien Speicher fragmentieren.

Ohne Speicherschutz kann jeder fehlerhafte Zeiger fremde Daten, Systemstrukturen oder Code beschädigen. Die Speicherverwaltung kennt freie und belegte Bereiche, isoliert Anwendungen aber nicht wie ein modernes virtuelles Speichersystem.

[system/libraries]

Libraries, Devices und Systemschichtung

AmigaOS ist nicht nur ein Kernel mit ein paar Syscalls. Es ist ein System aus Libraries und Devices, die bei Bedarf geöffnet werden. exec.library ist die Basis, darüber liegen weitere Libraries wie intuition.library, graphics.library oder dos.library. Dieser Aufbau ist ein Kernmerkmal des Systems.

Eine Library wird nicht einfach „angenommen“, sondern explizit geöffnet. Das hat praktische Konsequenzen: Versionen können geprüft werden, der Aufrufer weiß, worauf er sich stützt, und die Schichtung bleibt sichtbar. Das ist nüchterner als viele spätere Systeme, die zu viel implizit machen.

  • exec.library: Kernmechanismen – Tasks, Ports, Messages, Signals, Interrupts, Speicher.
  • intuition.library: Fenster, Menüs, Gadgets, GUI-Interaktion.
  • graphics.library: Bildschirme, Bitmaps, Drawing-Primitiven.
  • dos.library: Shell, Dateizugriff, Dateinamenraum, Handler-Kommunikation, Prozesse, Redirection, Script-Ausführung.

Wichtig ist die Trennung zwischen Exec Devices und AmigaDOS-Devices. Ein Exec-Device ist die gerätenahe Seite, etwa trackdisk.device oder serial.device. Ein AmigaDOS-Device ist die DOS-Namensraumseite wie DF0:, SER: oder CON:. Dazwischen sitzt typischerweise ein Handler oder Dateisystem-Handler. Wer diese Ebenen vermischt, beschreibt das System falsch.

Genauso wichtig ist die Praxisregel der Paarung: OpenLibrary() und CloseLibrary() gehören zusammen. Eine Library explizit zu öffnen ist nur die halbe Wahrheit; sie später sauber wieder zu schließen gehört zum selben disziplinierten Modell. Fehlende CloseLibrary()-Aufrufe waren keine theoretische Schönheitsfrage, sondern echte Quelle für schleichende Probleme, Inkonsistenzen und unaufgeräumte Zustände in langlebiger Software.

[kernel/device_io]

Exec Devices und asynchrones I/O

Ein Exec-Device ist eine gerätenahe, libraryähnliche Systemkomponente mit standardisiertem I/O-Modell. Der Aufrufer öffnet das Device mit einem vorbereiteten IORequest. Das Device trägt anschließend seine Device- und Unit-Zeiger in die Request-Struktur ein.

  1. ReplyPort erzeugen: Ziel für die abgeschlossene I/O-Anfrage.
  2. IORequest anlegen: Struktur passend zum Device-Typ und ReplyPort.
  3. OpenDevice: Device und gewünschte Unit öffnen.
  4. Felder setzen: Kommando, Puffer, Länge, Offset und Flags vorbereiten.
  5. DoIO: synchron ausführen und erst nach Abschluss zurückkehren.
  6. SendIO: asynchron starten; der Task kann zwischenzeitlich andere Arbeit leisten.
  7. CheckIO / WaitIO: Abschluss prüfen beziehungsweise darauf warten.
  8. AbortIO: laufende Anfrage abbrechen lassen und anschließend trotzdem korrekt auf Abschluss warten.
  9. CloseDevice: erst wenn kein Request mehr aktiv ist.
[Async_Device_IO]
> OpenDevice(name, unit, ioReq, flags)
> fill io_Command / io_Data / io_Length / io_Offset
> SendIO(ioReq)
> Wait(replyPort signal) or perform other work
> WaitIO(ioReq) and inspect io_Error / actual result
> CloseDevice only after request ownership is settled

Das Modell zeigt erneut die Exec-Grundidee: asynchrone Hardwarearbeit wird mit Message Ports, Signals und klarer Request-Lebensdauer verbunden. DoIO() ist dabei eine bequeme synchrone Hülle, nicht ein anderes Device-Protokoll.

[kernel/resources_and_lifetime]

Resources, benannte Listen und Lebensdauerregeln

Neben Libraries und Devices kennt Exec leichtere Resources. Sie werden über OpenResource() gefunden und besitzen nicht zwingend dieselbe Open-/Close- und Expunge-Logik wie Libraries. Beispiele sind systemnahe Hardware- oder Koordinationsressourcen.

Libraries, Devices, Resources, Ports und Semaphoren können in öffentlichen benannten Listen erscheinen. Eine Suchfunktion wie FindPort() liefert jedoch nur einen Zeiger. Zwischen Finden und Benutzen könnte ein anderer Task den Eintrag entfernen. Deshalb gehören Suche, Besitzübergabe und Lebensdauer in ein gemeinsames Protokoll.

Typ Lebensdauerregel
Library OpenLibrary und CloseLibrary paaren; Version prüfen; Funktionsbasis nur während gültiger Öffnung benutzen.
Device OpenDevice und CloseDevice paaren; aktive IORequests vor dem Schließen vollständig abschließen.
Resource Über OpenResource finden; API und eigene Schutzregeln der Ressource beachten.
MsgPort Keine wartenden oder unterwegs befindlichen Messages zurücklassen; Signalbit und Queue geordnet auflösen.
Semaphore Nur entfernen, wenn kein Task sie hält oder darauf wartet; jedes erfolgreiche Obtain braucht ein Release.

Die Offenheit der Systemlisten ist kein Freibrief für unkoordinierten Direktzugriff. Gerade weil Zeiger und Strukturen sichtbar sind, muss ein Programm sauber dokumentieren, wann ein Objekt ihm gehört und wann nur ein geliehener Verweis vorliegt.

[dos/origin]

TRIPOS, BCPL und die Herkunft von AmigaDOS

Der eigentliche DOS-Teil des frühen AmigaOS kam nicht aus Exec herausgewachsen, sondern aus einer anderen Herkunftslinie: TRIPOS und BCPL. Das ist wichtig, weil viele Eigenheiten des frühen AmigaDOS genau daraus stammen.

TRIPOS war ein portables Betriebssystem aus dem akademischen Umfeld, später von MetaComCo auf den 68000 gebracht. Commodore nutzte diesen Unterbau für das frühe AmigaDOS. Deshalb war AmigaDOS 1.x stark BCPL-geprägt. Das merkt man nicht nur historisch, sondern ganz konkret an Begriffen und Datentypen.

BPTR und BSTR

BCPL arbeitet mit anderen Pointer-Konventionen als C. Ein klassisches Beispiel ist der BPTR: kein normaler Bytepointer, sondern ein wortadressierter Pointer im BCPL-Stil. Praktisch heißt das: Werte sind gegenüber normalen Adressen verschoben/skaliert, und man kann sie nicht einfach wie normale C-Pointer behandeln. Dasselbe gilt für BSTR, also längencodierte Strings mit anderer Konvention als nullterminierte C-Strings.

Genau diese BCPL-Erbschaft war einer der Gründe, warum frühes AmigaDOS aus C- oder Assembler-Sicht oft sperriger wirkte als Exec. Nicht weil die DOS-Ideen schlecht gewesen wären, sondern weil die Datendarstellung aus einer anderen Welt stammte.

[Frühes AmigaDOS]
> Herkunft: TRIPOS/MetaComCo
> Sprache: BCPL in der 1.x-Linie
> typische Spuren: BPTR, BSTR, DOS-spezifische Strukturen
> später zunehmend in C umgebaut, aber die Denkform blieb lange sichtbar

Wer frühe AmigaDOS-APIs verstehen will, muss diese Herkunft mitdenken. Sonst wirkt manches unnötig exotisch, obwohl es historisch einfach konsequent ist.

[dos/doslibrary]

dos.library und der DOS-Namensraum

dos.library ist die Schicht, die aus roher Exec-Mechanik einen benutzbaren Dateisystem- und Shell-Betrieb macht. Hier liegen Dateinamenraum, Shell-Kommandoausführung, Handler-Ansprache, Locks, File Handles, Redirection, Script-Logik und Prozessdetails. Das ist der eigentliche AmigaDOS-Kern.

Der Namensraum von AmigaDOS ist kein Unix-Namensraum und auch kein MS-DOS-Laufwerksmodell. Namen wie DF0:, DH0:, RAM:, CON:, SER:, PIPE: oder NIL: sind logische DOS-Gerätenamen im selben Namensraum. Dazu kommen Assigns wie SYS:, C:, S:, L: oder LIBS:. Dieser Namensraum ist flexibler als ein starres Laufwerksbuchstabenmodell, aber er verlangt, dass man die Begriffe korrekt trennt.

  • Volume / Device Name: etwa DH0: oder DF0: – Ausgangspunkt eines Pfads.
  • Assign: logischer Alias auf ein Verzeichnis oder mehrere Verzeichnisse, z. B. LIBS:.
  • Handler-basierte DOS-Ziele: CON:, SER:, PIPE:, NIL: – keine „Dateien“, aber im DOS-Namensraum wie solche benutzbar.

Das wirkt zuerst ungewohnt, ist aber technisch sauber: Alles, was sich wie ein DOS-Endpunkt verhält, lebt im gleichen Namensraum und kann über die DOS-Schicht angesprochen werden. Genau das macht Redirection und flexible Geräteansprache so elegant.

Die DOS-Schicht selbst – mit Locks, File Handles, Assigns, Handlern, DOS-Packets, RUN und EXECUTE – steht auf der Schwesterseite amiga-dos.htm im Detail. Hier geht es bewusst um die größere Schichtung mit Exec darunter.

[dos/handlers]

Handler, Devices und DOS-Packets

Einer der wichtigsten Punkte überhaupt: AmigaDOS arbeitet gegenüber Dateisystemen und DOS-Geräten nicht direkt mit rohen Exec-Devices, sondern mit Handlern. Ein Handler ist ein Prozess, der eine standardisierte Menge an DOS-Anfragen verarbeitet.

Das bedeutet konkret: Wenn ein Programm Open("DF0:datei", ...) oder Read(fh, ...) aufruft, führt dos.library nicht selbst die gesamte Dateisystemarbeit aus. Stattdessen werden Anfragen an den zuständigen Handler geschickt – typischerweise per Message Port und in Form von DOS-Packets. Der Handler übersetzt diese DOS-Anfrage in die passenden low-level Operationen, oft unter Nutzung eines Exec-Devices wie trackdisk.device.

Exec Device

Gerätenahe Ebene, z. B. trackdisk.device oder serial.device.

Direkter, hardwareorientierter Zugang.

DOS Device / Handler

Namensraumseite wie DF0:, CON:, SER: oder PIPE:.

Wird durch einen Handler-Prozess verwaltet, der DOS-Anfragen entgegennimmt.

DOS-Packets

DOS-Packets sind spezialisierte Message-Strukturen für DOS- und Dateisystemoperationen. Man kann sie als Exec-Style-Messages mit zusätzlicher Parameterstruktur verstehen. Für normale Programme ist wichtig: Man arbeitet meist über dos.library und nicht direkt mit selbstgebauten DOS-Packets. Für Handler-Autoren ist dieses Modell jedoch zentral.

[DOS Zugriffspfad]
> Programm ruft dos.library-Funktion auf
> dos.library ermittelt zuständigen Handler / Port
> Anfrage wird als DOS-Packet gesendet
> Handler verarbeitet, spricht ggf. Exec-Device an
> Ergebnis geht zurück an dos.library und dann an den Aufrufer

Das ist eine saubere Entkopplung. dos.library muss nicht jedes Dateisystem oder jedes Sondergerät im Detail kennen. Es reicht, dass die Handler die Paketkonventionen verstehen.

[dos/shell-process]

Shell, CLI und das Process-Modell

Die Shell ist nicht bloß ein Fenster mit Prompt. Sie ist ein DOS-Prozess. Genau hier wird der Unterschied zwischen Exec und AmigaDOS besonders greifbar.

Ein DOS-Process ist mehr als ein Exec-Task. Offiziell kann man ihn als Kombination aus Exec task structure, Exec message port und AmigaDOS process value sehen. Der interne Prozessidentifikator im DOS-Kontext ist dabei der Pointer auf den Exec-Message-Port pr_MessagePort, von dem aus der zugehörige Exec-Task ermittelt werden kann.

[AmigaDOS Process]
> Exec Task
> Exec Message Port
> DOS-spezifische Prozessdaten (CLI/Shell-/Datei-/Pfadkontext)

Das ist entscheidend, weil Shell und Kommandoausführung genau auf dieser Ebene leben. Eine Shell liest Eingaben, wertet Redirection aus, sucht Kommandos im Suchpfad, startet externe Programme und Scripts und verwaltet den Kontext – aktuelles Verzeichnis, offene Streams, Prompt, Return Codes und ähnliche Dinge. Das ist DOS-Logik, nicht Exec-Logik.

CLI, Shell, NewShell, NewCLI

Es können mehrere Shell-Prozesse gleichzeitig laufen. Sie werden intern nummeriert. NEWSHELL bzw. NEWCLI starten einen neuen Shell-Prozess. Das ist nicht bloß ein neues Fenster, sondern tatsächlich ein weiterer DOS-Prozess mit eigenem Kontext.

Genau deshalb lässt sich AmigaDOS auch gut skripten und mehrfach parallel benutzen. Jede Shell ist ihr eigener DOS-Kontext, nicht nur eine andere Darstellung desselben globalen Zustands.

[dos/assigns-locks]

Assigns, Locks und File Handles

Assigns

Ein Assign ist ein logischer Name, der auf ein Verzeichnis – oder sogar auf mehrere Verzeichnisse – zeigt. LIBS:, C:, S: oder L: sind die klassischen Beispiele. Dadurch muss Software nicht wissen, auf welchem konkreten Volume sich eine Ressource befindet; sie fragt einfach LIBS: oder C: ab.

Besonders stark ist, dass Assigns nicht auf genau ein Ziel festgelegt sein müssen. Mit passenden Optionen kann ein Assign um weitere Verzeichnisse ergänzt werden. Das System durchsucht dann die Assign-Liste in Reihenfolge. Das ist eine überraschend flexible Lösung für ein solches System.

Locks

Ein Lock ist in AmigaDOS nicht nur „gesperrt“ im umgangssprachlichen Sinn, sondern eine konkrete Struktur für Zugriff und Referenzierung. Locks werden verwendet, um Objekte eindeutig zu referenzieren und konkurrierende Zugriffe zu kontrollieren. Wesentlich sind dabei Shared Locks und Exclusive Locks.

  • Shared Lock: für lesenden Zugriff; mehrere gleichzeitig möglich.
  • Exclusive Lock: für schreibenden Zugriff; Konflikte mit anderen Locks werden verhindert.

Das ist wichtig, weil viele DOS-Funktionen nicht nur mit Pfadstrings arbeiten, sondern intern mit Locks weitergehen. Ein Lock ist damit sowohl Schutzmechanismus als auch Navigationshilfe im Dateisystem.

File Handles

Ein File Handle ist der laufende Zugriffskanal auf eine geöffnete Datei oder einen streamartigen DOS-Endpunkt. Für das aufrufende Programm ist das die konkrete Arbeitsoberfläche: lesen, schreiben, seeken, schließen. Ein File Handle ist also der operative Gegenpart zum Lock. Der Lock referenziert und schützt, der File Handle arbeitet laufend mit dem geöffneten Objekt.

Wichtig ist, dass File Handles auf weit mehr als bloße Plattendateien zeigen können. CON:, SER:, PIPE:, NIL: – all das lässt sich im DOS-Sinn wie ein Datei-Endpunkt öffnen und behandeln. Genau daraus entstehen die flexible Redirection und die Shell-Stärke des Systems.

[dos/io-execution]

Pipes, Redirection, Execute und Run

Redirection

Redirection gehört zur Shell-Schicht. Mit < und > kann Eingabe oder Ausgabe auf Dateien oder DOS-Geräte umgelenkt werden. Die Shell analysiert die Kommandozeile und sorgt dafür, dass die gestarteten Programme andere Ein- oder Ausgabeströme sehen als das eigentliche Konsolenfenster.

[Redirection Beispiele]
> DIR >T:dirlist
> TYPE S:Startup-Sequence >CON:0/0/640/120/Startup
> COPY DF0:datei RAM:datei

PIPE:

PIPE: ist ein handlerbasierter Kommunikationskanal für gepufferte I/O-Kommunikation zwischen Programmen. Technisch interessant daran ist, dass er wie ein DOS-Endpunkt im Namensraum erscheint. Für Programme, die sequentielle Ein-/Ausgabe erwarten, kann PIPE:name wie eine Datei wirken, obwohl dahinter ein interprozessualer Puffermechanismus steckt.

Das zeigt exemplarisch, wie stark die DOS-Schicht des Amiga ist: Ein Kommunikationsmechanismus wird nicht als exotischer Sonderfall nebenher gebaut, sondern sauber in denselben Namensraum eingebunden wie Dateien und Geräte.

Execute

Execute() beziehungsweise das Shell-Kommando EXECUTE gehören zur DOS-/Shell-Schicht. Execute() führt eine Shell-Kommandozeile aus. Wichtig: Die Funktion kehrt grundsätzlich erst zurück, wenn die angeforderte Kommandoausführung abgeschlossen ist. Sie ist also nicht die primitive „starte im Hintergrund und vergiss es“-Variante.

Zusätzlich kann Execute() mit passenden File Handles so benutzt werden, dass ein neuer interaktiver Shell-Kontext entsteht. Genau deshalb gehört Execute() in eine Seite über AmigaDOS und nicht in eine Seite über nacktes Exec.

Run

RUN ist die Shell-seitige Antwort auf „starte im Hintergrund“. Das Kommando lädt und startet ein Programm beziehungsweise eine Shell-Aktivität so, dass der Prompt zurückkehrt und die aktuelle Shell weiter bedient werden kann. Das ist keine neue Scheduling-Theorie – sondern konkrete DOS-Prozesslogik.

Praktisch wichtig ist dabei: Die gestartete Aktivität bleibt mit ihrem Ursprungskontext verbunden, insbesondere was Ein-/Ausgabe betrifft, wenn man nicht bewusst auf NIL: oder andere Ziele umlenkt. Genau deshalb kann man eine Shell nicht beliebig schließen, solange von ihr gestartete Hintergrundprozesse noch an ihren Streams hängen.

[schichtung_hinweis]

RUN, EXECUTE, Redirection und PIPE: sind keine Exec-Kernmechanismen. Sie leben auf der DOS-/Shell-Schicht. Exec liefert nur die Basis, auf der das möglich wird.

[alerts/guru]

Guru Alert präzise erklärt

Die berühmte Guru Meditation ist weder bloß Kult noch bloß ein „Absturzbildschirm“. Präziser ist: Es handelt sich um einen Alert-/Fehlermechanismus des Systems. Die ausgegebene Zahl ist strukturiert und kodiert Informationen über Fehlerklasse und betroffene Komponente.

Entscheidend ist dabei der nüchterne Blick: Ein Guru Alert ist keine philosophische Botschaft und auch nicht automatisch ein Debugger im modernen Sinn. Er ist ein sichtbarer, formatierter Systemalarm. In manchen Fällen ist ein Fehler als recoverable gedacht, in anderen ist er fatal. Das hängt von der Alert-Klasse ab.

[Alert Format]
> 32-Bit Alert Number
> strukturierte Segmente für Klasse / Subsystem / Fehler
> nicht „mystisch“, sondern kodiert

Aufbau der 32-Bit-Alertnummer

Die erste 32-Bit-Zahl lässt sich schematisch als DIGGSSSS lesen: Das höchste Bit kennzeichnet DeadEnd oder Recovery, die folgenden Bits ordnen ein ROM- beziehungsweise Systemsubsystem zu, danach folgen allgemeine und spezifische Fehleranteile. Die genaue Bedeutung muss anhand der passenden Alert-Tabelle und Systemversion bestimmt werden.

Teil Bedeutung
D DeadEnd-Bit: gesetzt bedeutet nicht wiederherstellbarer Alarm; ungesetzt kennzeichnet die Recovery-Form.
I Subsystem- beziehungsweise Herkunftskennung.
GG Allgemeine Fehlergruppe.
SSSS Spezifischer Fehler innerhalb der Gruppe.

Beispiel 00000003

00000003 ist nach der dokumentierten Alerttabelle nicht nur irgendein Beispielwert, sondern die recoverable Form eines illegalen Adresszugriffs auf eine ungerade Adresse. Der zweite angezeigte Longword-Wert ist zusätzlicher Kontext, dessen konkrete Aussage vom Fehlerpfad abhängt.

[Example_Alert]
> 00000003 = recoverable odd-address access alert
> second longword = context value dependent on alert path
> decode with documented table, not memory or folklore

Dass der Guru Alert bis heute so stark erinnert wird, liegt nicht nur am Namen. Es liegt daran, dass das System an dieser Stelle sichtbar ehrlich wird: Es verdeckt den schweren Fehler nicht mit allgemeiner Freundlichkeit, sondern zeigt an, dass etwas grundsätzlich schiefgelaufen ist.

Im klassischen Amiga-Kontext darf man dabei eines nicht vergessen: Ohne Speicherschutz ist ein schwerer Programmfehler eben nicht sauber auf den fehlbaren Task beschränkt. Gerade deshalb sind Alerts auf dieser Ebene systemisch relevant.

„Ein Guru Alert ist keine Legende. Er ist die formalisierte Aussage, dass die Sache an einer fundamentalen Stelle entgleist ist.“

[documentation/exec_sources]

Technische Referenzen

Die Exec-Abschnitte orientieren sich an den Commodore-Amiga ROM Kernel Reference Manuals, den Exec-AutoDocs und der fortgeführten AmigaOS-Entwicklerdokumentation. Die AmigaDOS-Zusammenfassung wird zusätzlich durch das AmigaDOS-Handbuch eingeordnet.

Moderne AmigaOS-Dokumentation enthält teilweise Erweiterungen aus AmigaOS 4. Diese Seite verwendet sie nur dort, wo die beschriebene Grundidee auch für die klassische 68k-Linie gilt oder der Unterschied ausdrücklich genannt wird.

[meaning/architecture]

Was daran bis heute bemerkenswert ist

Bemerkenswert ist nicht nur, dass der Amiga früh präemptives Multitasking hatte. Bemerkenswert ist die Kombination aus technischer Eleganz und praktischer Lesbarkeit. Exec unten, DOS darüber, Handler als vermittelnde Prozesse, Libraries als explizite Systemschicht, Shell und Dateinamenraum als benutzbarer Überbau – das ist nicht zufällig gewachsenes Chaos, sondern als Struktur erkennbar.

Ebenso bemerkenswert ist, dass genau diese Eleganz nicht mit moderner Schutzarchitektur verwechselt werden darf. Das System ist offen, schnell, direkt – und dadurch verwundbar. Es verlangt Können. In diesem Sinn ist AmigaOS kein bequemes System, sondern ein ehrliches.

Für mich liegt genau darin der bleibende Wert: Man kann an AmigaOS / Exec / AmigaDOS noch heute sauber studieren, was eine gute Schichtung ist, wie Interprozess-Kommunikation sinnvoll klein gehalten werden kann und warum Shell-/Dateisystemlogik als eigene Ebene über dem Kernel existieren sollte.

[Langfristige Lehre]
> Kernelkern klein halten
> darüber saubere Dienste statt Monolith
> IPC als Grundbaustein, nicht als nachträgliche Dekoration
> DOS-/Shell-Schicht bewusst von Scheduling und Low-Level trennen

„AmigaOS war stark, wo es geschichtet war – nicht wo man alles in einen einzigen Begriff warf.“

Die DOS-Schicht im Detail steht auf amiga-dos.htm. Die konkreten Systeme, an denen diese Architektur im Alltag erfahrbar wurde, stehen auf hardware.htm und amiga4000t.htm.