Programmieren unter MiNT/MultiTOS, Teil 3

Im letzten Teil hatten wir die Verwandtschaft von MiNT und UNIX im Bereich der Dateisysteme im Visier. Wen wundert es da, daß sich auch die Verwaltung der Prozesse und deren Kommunikation unter MiNT sehr stark an UNIX anlehnt.

Natürlich profitieren vor allem die Programmierer von dieser Vorgehensweise, da es für UNIX und seine diversen Abkömmlinge Massen an freier Software inklusive der Quellcodes gibt. Auch was die Literatur angeht, können sehr viele UNIX-Werke direkt für die Programmierung unter MiNT herangezogen werden. Die meisten der neuen MiNT-Betriebssystemaufrufe finden sich hier wieder. Diese neuen Funktionen hatten wir bisher in der Datei »MINTBIND.H« als Makros definiert. Mit dieser Methode kommt man zwar schnell ans Ziel, allerdings werden damit einige ANSI-C-Vorteile - Typenprüfung oder die Übergabe von Funktionszeigern - teilweise ausgeschaltet. Mit einer Library, in der die neuen Aufrufe direkt in Assembler realisiert sind, geht man diesen Nachteilen aus dem Weg. Für die 54 neuen Funktionen von MiNT V0.95 finden Sie auf der TOS-Diskette im Archiv »LINK« die Datei »MINTLIB.S«. Diese können Sie direkt in die Projektdatei aufnehmen. Eine zweite Variante ist das Kopieren von »MINTLIB.O« in den »LIB«-Ordner Ihrer Pure-C-Installation. Ihre MiNT-Projektdateien ergänzen Sie dann noch um die Zeile »MINTLIB.O«. Die Prototypen für die Aufrufe finden sich, anstelle der alten Makros, in der Datei »MINTBIND.H«.

Mit »LINK.APP« setzen und löschen Sie bequem symbolische Links oder lassen sich vorhandene Links zeigen. Natürlich läßt sich das Programm auch als Accessory installieren. Nach dem Start erscheint ein kleiner Dialog im Fenster (siehe Bild 1). Möchten Sie einen »Symb.-Link anlegen«, wählen Sie zuerst die Original-Datei bzw. den Original-Ordner in einer Dateiauswahlbox. Anschließend wird der Ziel-Link angegeben. Im Moment kann MiNT symbolische Links allerdings nur im ROOT-Verzeichnis des Laufwerks »U:« anlegen, deshalb ist dieses auch gleich vorgegeben. Analog funktioniert »Link löschen«, mit dem Sie symbolische Links wieder entfernen. Die Originale bleiben natürlich unversehrt! Wen die Neugierde plagt und wer gerne wissen möchte, welches Original sich hinter einem symbolischen Link verbirgt, der sollte »Link anzeigen« wählen.

Eines der Hauptanliegen der UNIX-Macher war es, mehrere Programme quasi gleichzeitig auf einem Computer laufen zu lassen. Da zu dieser Zeit die Mehrprozessorsysteme noch nicht aktuell waren, mußte ein Weg gefunden werden, um mehrere Computer in einem zu simulieren. Diese Emulation der Pseudoprozessoren durch schnelles Umschalten zwischen den einzelnen Prozessen erledigt der Kern von UNIX/MiNT. Ein Prozeß ist damit ein selbständig ablaufendes Programm, das von sich aus gesehen den Prozessor voll in Anspruch nimmt. Um dabei eine allgemeine Verwirrung zu vermeiden und eine eindeutige Unterscheidung der Prozesse zu ermöglichen, erhält jeder Prozeß eine einzigartige Nummer zugewiesen, die sogenannte PID (Process Identification), mit deren Hilfe er zukünftig angesprochen werden kann.

Bei Programmstart wird ein neuer Prozeß erzeugt, in dem das Programm nun ungestört von anderen laufen kann. Aus der Sicht des einzelnen Programmes gehört ihm der ganze Computer. Es existiert im System eine Liste mit allen Prozessen, die je nach Wichtigkeit (Priorität) Rechenzeit zugeteilt bekommen. Ein Verteiler (»Scheduler«) sorgt dafür, daß jeder Prozeß die ihm zustehende Rechenzeit bekommt. Beim Scheduling schaut das System in der Liste nach, welcher rechenbereite Prozeß die höchste Priorität hat. Dieser bekommt für eine bestimmte Zeit die CPU und darf rechnen.

Damit die anderen Prozesse mit gleicher oder gar niedrigerer Priorität auch zum Zuge kommen, berechnet das System die Prioritäten immer wieder neu. In diese Berechnung fließen die bereits verbrauchte Rechenzeit, die Wartezeit, die Größe des Prozesses und die Grundpriorität ein. Genaugenommen existieren also für jeden Prozeß zwei Prioritäten, die aktuelle, die er im Moment besitzt, und die Grundpriorität, die er beim Start bekommen hat.

Die aktuelle Priorität ändert sich auch abhängig von dem, was der Prozeß gerade so treibt. Tätigt er einen Systemaufruf, erhöht sie sich und der Prozeß befindet sich im Systemmodus. Im Benutzermodus vermindert sich die Priorität entsprechend. Unter MiNT geht diese Zweiteilung aus Kompatibilitätsgründen im Moment sogar so weit, daß ein Prozeß im Systemmodus die volle Rechenzeit zugeteilt bekommt. Während eines Betriebssystemaufrufs schaltet MiNT also nicht weiter (dies kann sich allerdings bald ändern).

Außer der automatischen Berechnung der aktuellen Priorität, die vom System selbst durchgeführt wird, kann natürlich auch der Benutzer die Priorität verändern. Beim Start eines Prozesses erbt dieser zunächst die Priorität des Prozesses, der ihn gestartet hat. Per Definition heißt der startende Prozeß »Parent« und der gestartete »Child«. Wer die Eltern eines Kindes näher kennenlernen möchte, wendet sich diskret an die PPID (»Parent Process Identification«) des Kindes. Damit weniger wichtige Prozesse (Berechnung der Steuererklärung) nun nicht die wichtigen Prozesse (Verwaltung der Long-Drink-Rezepte) in ihrer Arbeit behindern, lassen sich Prioritäten vergeben. Je höher die Priorität eines Prozesses ist, desto mehr Rechenzeit bekommt er und um so schneller ist er logischerweise dann auch. Unter MiNT reicht die Spanne der erlaubten Werte für die Priorität von -20 bis +20.

An einem UNIX-Rechner können mehrere Personen gleichzeitig an verschiedenen Terminals arbeiten. Welcher Person ein Prozeß gehört, besagt eine Kennung, die jeder Anwender und dessen Prozesse erhalten (UID). Um noch verschiedene Abteilungen zu unterscheiden, erhält jeder Benutzer zusätzlich eine Gruppennummer zugeordnet (GID), die seine Prozesse wiederum erben. Unter UNIX dienen diese Nummern hauptsächlich der Verwaltung von Zugriffsrechten, da in einem größeren System nicht jeder alles darf. MiNT in seiner aktuellen Version verfügt zwar auch über UID und GID, die restlichen Multiuser-Funktionen sind aber nur rudimentär enthalten.

Die Prozeßsignale

Damit die Prozesse nicht an Vereinsamung zugrunde gehen, enthält UNIX und natürlich auch MiNT ein Signal-System, mit dessen Hilfe Prozesse untereinander oder mit dem System in Verbindung treten. Im Prinzip ist ein Signal mit einem Interrupt vergleichbar.

Für ein bestimmtes Signal kann dem System ein Unterprogramm benannt werden, das beim Eintreffen des Signals aufgerufen wird. Ein sehr wichtiges Signal unter MiNT ist »SIGTERM«. Dieses Signal versendet MiNT an Programme, deren Abbild in »U:\PROC« in den Mülleimer wandert.

SIGTERM wirkt nicht ganz so radikal wie SIGKILL und kann vom Programm abgefangen werden. Ist dies nicht der Fall, beendet das System den betreffenden Prozeß. Da SIGTERM vom Benutzer sehr leicht ausgelöst werden kann und es bei Programmen mit einer GEM-Oberfläche leicht zu Problemen kommt, wenn diese sich unkontrolliert verabschieden, empfiehlt es sich, zumindest dieses Signal zu bearbeiten.

Zunächst muß eine Empfänger-Funktion definiert werden. In »LINK.APP« ist dies die Funktion »get_sigterm()«. Sie setzt im Falle eines Falles die Variable Done auf 99 und zeigt damit dem Programm an, daß es sich beenden soll.

void get_sigterm (void)	/* Diese Funktion wird von MiNT aufgerufen, wenn das */
	/* Signal SIGTERM an Link gesendet wurde!
Done = 99;

Damit in get_sigterm() auch etwas ankommt, müssen wir den Signalempfang mit der Funktion »Psignal()« scharf schalten. Der erste Parameter enthält das gewünschte Signal, der zweite Parameter ist ein Zeiger auf die Empfangsfunktion. Damit ist bereits ein einfacher Signal-Handler installiert.

Psignal (SIGTERM, (long)get_sigterm);

Wenn nun ein netter Mensch »LINK.PID« aus dem Ordner »U:\PROC«in den Mülleimer wirft, geschieht folgendes: MiNT sendet das Signal SIGTERM an LINK und merkt, daß LINK dieses Signal abfangen möchte. Es folgt diesem Wunsch und verzweigt nach get_sigterm(). Die Funktion setzt das Flag »Done« auf 99 und das Signal gilt zunächst als bearbeitet. Mit dem nächsten Event erkennt LINK, daß jemand sein Ende erwartet und handelt dementsprechend. Natürlich muß bei dieser Taktik dafür gesorgt werden, daß das Programm in regelmäßigen (nicht zu langen) Abständen zum Zuge kommt und das gesetzte Done-Flag erkennen kann. Innerhalb einer GEM-Anwendung ist dies aber dank »evnt_timer« kein Problem.

Im nächsten Kursteil werden wir die »named pipes« und die neuen AES-Funktionen genauer unter die Lupe nehmen. (ah)

Signale unter MiNT/MultiTOS

Name Beschreibung
SIGHUP »Das Ein-/Ausgabe-Terminal ist nicht mehr gültig.«
Dieses Signal kann vom Window Manager (TOS-WIN/MW) kommen, wenn der Benutzer das Terminalfenster geschlossen hat.
SIGINT »Unterbrechung«.
Dieses Signal wird gesendet, wenn der Benutzer Ctrl-C drückt. Der Benutzer möchte die aktuelle Aktion abbrechen oder das gesamte Programm beenden.
SIGQUIT »Abbruch«.
Dieses Signal wird gesendet, wenn der Benutzer Ctrl-\ drückt. Der Benutzer möchte das Programm dringend beenden!
SIGILL »Illegaler Befehl«.
Es wurde versucht, einen nicht vorhandenen Assembler-Befehl auszuführen.
SIGTRAP »Einzelschrittausführung«.
Der Trace-Trap wurde ausgelöst (für Debugger interessant).
SIGABRT »Grausamer Fehler«.
Üblicherweise kommt dieses Signal von der »Abort«-Bibliotheksfunktion und weist darauf hin, daß ein sehr schwerer Fehler vorliegt.
SIGPRIV »Privilegverletzung«.
Es wurde versucht, eine Supervisor-Instruktion im Usermodus auszuführen.
SIGFPE »MATH-Fehler«.
Im Prozeß ist eine Division durch Null oder ein Überlauf aufgetreten.
SIGKILL »Prozeßabbruch«.
Kann weder blockiert noch abgefangen werden! Der Empfänger-Prozeß stirbt unwiderruflich.
SIGBUS »Bus-Fehler«.
In einem Programm ist ein Bus-Fehler aufgetreten.
SIGSEGV »Adreß-Fehler«.
Es wurde auf eine illegale Speicheradresse zugegriffen.
SIGSYS »Fehlerhaftes Argument«.
Dieses Signal kommt vom System, wenn einem Systemaufruf falsche Werte übergeben werden.
SIGPIPE »Pipe-Fehler«.
Es wurde der Versuch gemacht, in eine nicht existierende Pipe zu schreiben, bzw. die Pipe ist zerbrochen.
SIGALRM »Alarm«.
Der mit »Talarm()« gesetzte Alarm ist abgelaufen.
SIGTERM »Bitte beenden«.
Dieses Signal wird gesendet, wenn ein Prozeß aus »U:\PROC« auf den Papierkorb gezogen wurde. Es ist die nette Form von SIGKILL.
SIGSTOP »Halt«.
Wird an einen Prozeß gesendet, wenn dieser zeitweilig anhalten soll. Kann nicht abgefangen werden.
SIGTSTP »Bitte anhalten«.
Wird an einen Prozeß gesendet, wenn dieser zeitweilig anhalten soll, z.B. wenn der Benutzer Ctrl-Z oder Ctrl-Y im Cooked-Mode drückt. Nette Form von SIGSTOP.
SIGCONT »Weitermachen«
Hebt SIGSTP oder SIGSTOP auf.
SIGCHILD »child beendet«.
Wird vom Kernel an den parent eines Kindes gesendet wenn das child »endet«.
SIGTTIN »Eingabe vom falschen Terminal«.
Wird an einen Prozeß gesendet, der versucht, von einem Terminal zu lesen, das ihm nicht gehört.
SIGTTOU »Ausgabe auf falsches Terminal«.
Wird an einen Prozeß gesendet, der versucht, auf ein Terminal zu schreiben, das ihm nicht gehört.
SIGXCPU »Zeitlimit voll«.
Die erlaubte Zahl an CPU-Zeit in Millisekunden ist verbraucht.
SIGWINCH Dieses Signal kann von einem Window Manager (TOSWIN/MW) gesendet werden, wenn der Benutzer die Größe des Fensters verändert hat.
SIGUSR1,SIGUSR2 »User-Signal 1« »User-Signal 2«

Diese beiden Signale können beliebig von Applikationen zur Kommunikation verwendet werden. ACHTUNG: werden diese Signale nicht abgefangen, wird der Empfänger beendet. Kontrollierte Fehlerbehandlung mit Signalen


Richard Kurz
Aus: TOS 01 / 1993, Seite 82

Links

Copyright-Bestimmungen: siehe Über diese Seite