Home GEMDOSGEMDOS Programmstart und TPAProgrammstart und TPA gemdos-Trapgemdos-Trap

5.7 Signale

Das aus der U*NIX-Welt stammende Signal-Konzept steht auch unter den Betriebssystemen MultiTOS und MagiC (ab Version 4.50) zur Verfügung. Signale können als natürliche Zahlen aufgefaßt werden, die einen bestimmten Ausnahmezustand (Exception) repräsentieren. Sie sind mit einem Interrupt oder einer CPU-Exception vergleichbar, mit dem Unterschied jedoch, daß es sich um eine reine Software-Implementation handelt.

Jeder Prozess besitzt:

Bei einem Pexec werden die Signalmaske und der pending-Wert (s.o.) des Child-Prozesses auf Null gesetzt. Die Komponente sa_handler der sigaction Struktur wird vererbt, wobei ein Wert ungleich 0 oder 1 immer auf 0 gesetzt wird. Die Komponenten sa_mask und sa_flags der Struktur werden auf den Wert Null gesetzt.

Die meisten Signale können von einem Programm abgefangen, (um etwa beim Eintreffen eine bestimmte Routine aufzurufen) ignoriert, oder auch blockiert werden. Blockierte Signale werden solange nicht berücksichtigt, bis die Blockade wieder aufgehoben wird. Zur Terminologie: Man sagt, daß ein Signal zu einem Prozess geschickt wird, wenn die das Signal repräsentierende Exception auftritt, oder wenn das Signal per Pkill von einem anderen Prozess gesendet wird. Ein Signal wurde hingegen an einen Prozess überbracht, wenn der entsprechende Prozess aufwacht, und die für das Signal passenden Aktionen einleitet. Zu beachten ist, daß das SignalHandling nicht zeitlos geschieht: Zwischen dem Abschicken eines Signals, und der Aufnahme der dazu passenden Aktionen kann evtl. ein beträchtlicher Zeitraum verstreichen.

Insgesamt stehen 31 mögliche Signale (0 bis 30) zur Verfügung, denen aber noch nicht allen eine feste Bedeutung zugewiesen ist. Die folgende Liste beschreibt (soweit bekannt) alle möglichen Signale in der Form: Signalnummer, Name des Signals, Bedeutung des Signals für den empfangenden Prozess. Sofern nicht ausdrücklich anders beschrieben, besteht die Default Aktion beim Eintreffen eines Signals in der Terminierung des empfangenden Prozesses.

Nummer Name Bedeutung
   
   0   SIGNULL Null: Dieses Signal besitzt keine Defaultaktion, da es streng genommen gar kein Signal ist. Zusammen mit Pkill kann es jedoch benutzt werden, um die Existenz eines Prozesses zu testen. Das Signal kann nicht maskiert oder abgefangen werden.
   1   SIGHUP Hang Up: Wird normalerweise verschickt, wenn ein Terminal, mit dem ein Prozess verbunden ist, nicht mehr gültig ist. Nach Erhalt dieses Signals sollte der Prozess keine Ausgaben mehr auf das Terminal machen. In MagiC wird der VT52 das Signal verschicken, wenn ein Terminalfenster geschlossen wurde.
   2   SIGINT Interrupt: Wird i.a. verschickt, wenn der Benutzer die Tastenkombination ^C betätigt. Dieses Signal wird von zukünftigen Versionen MagiC statt der bisherigen ^C-Behandlung benutzt.
   3   SIGQUIT Quit: Wird i.a. verschickt, wenn der Benutzer die Tastenkombination ^\ betätigt. Das Signal soll 'härter' als SIGINT sein, und wird z.Zt. noch nicht von MagiC bzw. VT52 verschickt.
   4   SIGILL Illegal instruction: Entspricht dem gleichnamigen Exceptionvektor des 68K-Prozessors. Das Signal sollte nicht abgefangen werden. In MiNT kann das Signal abgefangen werden, d.h. der Vektor wird praktisch für jeden Prozess umgebogen. In MagiC funktioniert das jedoch z.Zt. noch nicht, so daß hier immer 8 Bomben erscheinen.
   5   SIGTRAP Trap: Entspricht dem Exceptionvektor 'Trace' des 68K-Prozessors und wird nach jeder Anweisung gesendet, wenn das System im Einzelschritt 'trace' Modus läuft. Dieses Signal sollte nur von Debuggern abgefangen werden. In MiNT kann das Signal abgefangen werden, d.h. der Vektor wird praktisch für jeden Prozess umgebogen. In MagiC funktioniert das z.Zt. jedoch noch nicht, d.h. es erscheinen immer 9 Bomben.
   6   SIGABRT Abort: Wird normalerweise von der Bibliotheksfunktion abort() in ANSI C verwendet, und sollte nicht abgefangen werden. Dieses Signal wird nicht vom Betriebssystem selbst verschickt.
   7   SIGPRIV Privilege Violation: Entspricht dem gleichnamigen Exceptionvektor im 68K-Prozessor, wenn ein Prozess versucht, eine Anweisung im User-Mode auszuführen, die nur im Supervisor Mode ausgeführt werden darf. Dieses Signal sollte nicht abgefangen werden; in MiNT ist dies jedoch möglich, so daß der Exceptionvektor praktisch für jeden Prozess umgebogen wird. In MagiC funktioniert das z.Zt. jedoch noch nicht, d.h. es erscheinen immer 8 Bomben.
   8   SIGFPE Floating Point Exception: Die Default-Aktion besteht darin, das Signal zu ignorieren. Es entspricht dem 68k-Execptionvektor 'Division durch Null' oder eine Floating Point Exception. Das Signal kann ignoriert oder abgefangen werden. In MiNT kann das Signal abgefangen werden, so daß der Vektor praktisch für jeden Prozess umgebogen wird. In MagiC ist dies z.Zt. noch nicht möglich.
   9   SIGKILL Kill: Terminiert den empfangenden Prozess. Das Signal kann nicht maskiert bzw. abgefangen werden; deshalb sollte dieses Signal erst dann verschickt werden, wenn SIGTERM erfolglos war. Das Signal wird von MagiC selbst z.Zt. noch nicht verschickt.
  10   SIGBUS Bus Error: Entspricht dem gleichnamigen Exceptionvektor des 68K-Prozessors. Das Signal sollte nicht ignoriert oder abgefangen werden. In MiNT kann das Signal abgefangen werden, d.h. der Exceptionvektor wird praktisch für jeden Prozess umgebogen; in MagiC geht das z.Zt. jedoch noch nicht, so daß immer 2 Bomben erscheinen. In MiNT werden SIGBUS, SIGSEGV und SIGPRIV beim ersten Eintreffen des Signals auf die Defaultroutine des Systems zurückgesetzt, so daß ein doppelter Bus-/Adreß-/Privilegfehler den Prozess immer beendet.
  11   SIGSEGV Segmentation violation: Entspricht dem Exceptionvektor 'Adressfehler' des 68K-Prozessors. Das Signal sollte nicht abgefangen oder ignoriert werden. In MiNT kann das Signal abgefangen werden, d.h. der Exceptionvektor wird praktisch für jeden Prozess umgebogen. In MagiC geht das jedoch z.Zt. noch nicht, d.h. es erscheinen immer 3 Bomben.
  12   SIGSYS Bad System Call: Wird verschickt, wenn ein Parameter für ein Systemaufruf ungültig ist bzw. den erlaubten Wertebereich überschreitet und der Aufruf selbst keinen Fehler meldet. Wird von MagiC z.Zt. noch nicht verschickt.
  13   SIGPIPE Pipe Error: Wird beim Versuch verschickt, in eine nicht mehr existierende Pipe zu schreiben, und kann z.B. beim Drag&Drop-Protokoll maskiert werden. Dieses Signal wird z.Zt. von MagiC noch nicht verschickt.
  14   SIGALRM Alarm: Wird von MiNT für Talarm verwendet, und dient z.B. zum Behandeln von Time-Outs. In MagiC wird dieses Signal z.Zt. noch nicht verschickt.
  15   SIGTERM Terminate: Standardsignal zum Beenden eines Prozesses; es wird von MiNT z.B. beim Löschen einer Programmdatei im Verzeichnis U:\PROC verschickt, von MagiC z.Zt. jedoch noch ignoriert.
  16   SIGURG Dieses Signal ist z.Zt. noch nicht definiert.
  17   SIGSTOP Stop: Die Default-Aktion besteht darin, den empfangenden Prozess anzuhalten. Das Signal kann nicht blockiert bzw. abgefangen werden. In MagiC werden dabei sämtliche Threads eines Prozesses angehalten. Im gestoppten Zustand gehen in MagiC keinerlei Maus- bzw. Tastaturklicks verloren; beim Fortfahren des Prozesses per SIGCONT werden die entsprechenden Nachrichten ausgewertet.
  18   SIGTSTP Terminal Stop: Die Default-Aktion besteht darin, den empfangenden Prozess anzuhalten. Das Signal entspricht SIGSTOP, und wird i.a. vom Benutzer durch Drücken der Tastenkombination ^Z ausgelöst. Es kann nicht maskiert bzw. abgefangen werden. Das Signal wird z.Zt. noch nicht von MagiC und VT52 verschickt.
  19   SIGCONT Continue: Die Default-Aktion besteht darin, den empfangenen (und vorher durch SIGSTOP oder Pause gestoppten) Prozess wieder aufzuwecken. Obwohl das Signal nicht maskiert bzw. ignoriert werden kann, kann eine Behandlungsroutine für das Signal installiert werden. In MagiC werden sämtliche Threads aufgeweckt, die durch einen Aufruf von Pause bzw. SIGSTOP angehalten worden sind.
  20   SIGCHLD Child Terminated: Die Default-Aktion besteht darin, das Signal zu ignorieren. Es wird sowohl beim Terminieren als auch beim Anhalten eines Prozesses an den Parent-Prozess verschickt. In MiNT kann festgelegt werden, daß dieses Signal nur beim Terminieren verschickt wird, und darüber hinaus auch festgestellt werden, welcher Child-Prozess betroffen war. Da MagiC bisher nur das wartende Pexec kennt (d.h. der Parent wartet so lange, bis der Child terminiert), gibt es das Signal hier noch nicht. Die durch shel_write erzeugten Prozesse sind keine richtigen Childs, sondern völlig unabhängige Prozesse; in diesen Fällen muss daher auf das Eintreffen der Nachricht CH_EXIT gewartet werden.
  21   SIGTTIN Terminal Input-Error: Die Default-Aktion besteht darin, den empfangenden Prozess anzuhalten. In der Regel versucht ein Prozess von einem Terminal zu lesen, das ihm nicht gehört. Von MagiC bzw. VT52 wird das Signal z.Zt. noch nicht verschickt.
  22   SIGTTOU Terminal Output-Error: Die Default-Aktion besteht darin, den empfangenden Prozess anzuhalten. In der Regel versucht ein Prozess Ausgaben auf ein Terminal vorzunehmen, das ihm nicht gehört. Von MagiC bzw. VT52 wird das Signal z.Zt. noch nicht verschickt.
  23   SIGIO I/O possible: Eine Ein-/Ausgabe für eine Dateikennung ist möglich.
  24   SIGXCPU Exhaustion of CPU-Limit: Das per Psetlimit bzw. durch die erweiterten shel_write-Modi festgelegte Rechenzeit-Kontingent ist abgelaufen. Da die Begrenzung der Rechenzeit in MagiC bisher nicht implementiert ist, wird das Signal z.Zt. noch nicht verschickt.
  25   SIGXFSZ File size limit exceeded: Wird verschickt wenn eine Datei auf eine Weise verändert wird, die die maximale Größe einer Datei, die dem Prozess erlaubt ist, überschritten wird.
  26   SIGVTALRM Time limit expired: Wird an einen Prozess geschickt, der seine maximale CPU Zeit überschritten hat.
  27   SIGPROF Profiling time expired: Wird an einen Prozess geschickt, um ihm mitzuteilen, daß seine maximale Profiling Zeit überschritten ist.
  28   SIGWINCH Window-Changed: Die Default-Aktion besteht darin, das Signal zu ignorieren. Es wird normalerweise verschickt, wenn sich die Terminalgröße (d.h. die Anzahl der Zeilen bzw. Spalten) verändert hat. Ein Programm daß im Terminalfenster abläuft, kann sich nun entsprechend neu konfigurieren. Zur Ermittlung der aktuellen Fenstergröße gibt es in MiNT Fcntl-Opcodes, die in MagiC bisher jedoch noch nicht implementiert sind. Das Signal wird daher z.Zt. noch nicht von MagiC bzw. VT52 verschickt.
  29   SIGUSR1 User-Defined:
  30   SIGUSR2 User-Defined: Diese zwei Signale dürfen durch Benutzerprogramme verschickt werden. Da ein Prozess beim Empfangen dieses Signals per Default terminiert wird, sollte es nur verschickt werden, wenn der Empfänger bekannt ist.
  31   SIGPWR Das System wird wegen eines Fehlers in der Stromversorgung neu gestartet.

Querverweis:
Signalhandler in MagiC   Prozessfunktionen   Beispielcode   Psigaction   Psignal   Pkill   Test auf Pipes

5.7.1 Signalhandler in MagiC

Da sich Signalhandler in MagiC etwas von denen in MiNT bzw. MultiTOS unterscheiden, wird an dieser Stelle auf die wichtigsten Unterschiede bzw. Eigenschaften eingegangen. Zunächst einmal muss festgestellt werden, daß in MagiC AES- und VDI-Aufrufe aus einem Signalhandler heraus erlaubt sind (ganz im Gegensatz zu MiNT).

Ein Signalhandler läuft im Usermodus und verwendet den Userstack des Haupt-Threads, der solange schläft. In MiNT wird der Supervisor-Stack des Prozesses verwendet. Daher schießt laut MiNT-Dokumentation die Verschachtelung von Signalen ab 4 Stück einen Prozeß wegen Stapelüberlaufs ab. In MagiC ist jeder Signalhandler ein eigener Thread mit eigenem Supervisor-Stack, es kann also lediglich der extrem unwahrscheinliche Fall des Userstack-Überlaufs eintreten. Wenn jedoch zur Behandlung eines Signals zuwenig Speicher für einen neuen Thread zur Verfügung steht, wird eine Alertbox "System hat keinen freien Speicher mehr" ausgegeben, und es sollte schleunigst ein Programm beendet werden. Für jede Signalbehandlung benötigt MagiC ca. 7k Speicherplatz.

Für Signale gilt in MagiC das gleiche wie für Threads (ein Signalhandler ist ein Thread), d.h. die entsprechenden Systembibliotheken müssen reentrant sein. Es kommt jedoch noch erschwerend hinzu, daß der Haupt-Thread während der Abarbeitung des Signals angehalten wird. Wenn also der Haupt-Thread eine Semaphore (Stichwort: wind_update) gesetzt hat, ensteht ein Deadlock, wenn der Signalhandler diese Semaphore ebenfalls setzen will. Weiterhin kann ein Prozeß in MagiC an beinahe beliebiger Stelle unterbrochen werden (MagiC ist reentrant, sogar DOS ist unterbrechbar), so daß der Haupt-Thread u.U. wichtige Bereiche des Systems sperrt (Dateien, Verzeichnisse, Semaphoren). Daher kann es z.B. vorkommen, daß bestimmte Dateien nicht gelöscht oder geöffnet werden können.

Beim normalen Beenden eines Signalhandlers werden alle von dem Handler gesperrten Semaphoren automatisch freigegeben. Weiterhin werden ggf. Fenster, Bildschirmhintergrund und Menüleiste des Signalhandlers freigegeben. Man beachte, daß ein Signalhandler eine eigene AES Message-Queue besitzt, d.h. evnt_message und appl_write sind mit Vorsicht zu verwenden.

Bei Psigreturn werden die Semaphoren aller Signalhandler als auch die des Haupt-Thread freigegeben. Nicht freigegeben werden jedoch Fenster, Bildschirmhintergrund und Menüleiste der Signalhandler. Das wäre zwar kein großes Problem gewesen, dürfte aber in der Praxis nicht notwendig sein. Psigreturn restauriert den Supervisor-Stack des Haupt-Thread, d.h. ein setjmp/longjmp-Mechanismus braucht nur den USP zu setzen. Dies ist in der MiNT-Dokumentation nicht ausreichend dokumentiert und funktioniert auch nur dann, wenn der Haupt-Thread per GEMDOS-Aufruf wartet. Kommt AES ins Spiel, stürzt MultiTOS ab. Psigreturn sollte daher nach Möglichkeit vermieden werden. Psigreturn ist in MagiC nicht vom Typ VOID wie in MiNT, sondern vom Typ LONG. Wenn die Funktion von einem Nicht-Signalhandler aufgerufen wird, liefert Psigreturn den Wert EACCDN zurück, sonst E_OK. Hat Psigreturn E_OK geliefert, sollte (wie in MiNT) auf keinen Fall die Behandlungs-Prozedur normal per rts beendet werden, weil die Rücksprungadresse auf dem Userstack nach der Ausführung von Psigreturn ungültig ist.

Ein Problem existiert in MagiC mit den bisherigen Versionen von VT52. Ein Signalhandler kann noch keine Tastaturabfragen im VT52 durchführen; die Tasten werden noch nicht empfangen. Dies wird sich in einer späteren Version jedoch noch ändern.

Querverweis: Prozessfunktionen   Signale   Threads

5.7.2 Beispielcode zu Signalen

Das erste Programm installiert einen Signalhandler für die beiden Signale SIGUSR1 und SIGUSR2. Damit kann man die Verschachtelung der beiden Signale testen, wenn beide hintereinander verschickt werden. Das Programm sollte im VT52 bzw. im MINIWIN laufen. Wenn man während der "for()" Warteschleife Ctrl-Alt-Esc betätigt, erkennt man, daß MagiC für jeden Signalhandler einen eigenen Thread erstellt. Das hat den Vorteil, daß unter MagiC keine Ereignisse (Maus, Timer, ...) verlorengehen können, während ein Signal bearbeitet wird.

------------------------------ schnipp --------------------------
#include <tos.h>
#include <stdio.h>

void cdecl handler(long signr)
{
    long i;

    printf("handler: Signal %ld empfangen.\n", signr);
    Cconws("warte...");
    for (i = 0; i < 7000000L; i++)
        ;
    Cconws("...OK\r\n");
}

int main( void )
{
    long ret;

    printf("Meine ProcID ist %d.\n", Pgetpid());
    ret = (long) Psignal(SIGUSR1, handler);
    printf("Psignal => %ld\n", ret);
    ret = (long) Psignal(SIGUSR2, handler);
    printf("Psignal => %ld\n", ret);
    Cconin();
    return(0);
}
------------------------------ schnipp --------------------------

Das zweite Programm zeigt die Behandlung des Psigreturn()-Aufrufs. Unter MiNT funktioniert dieses Programm nur, wenn man keine AES-Aufrufe (evnt_keybd() oder evnt_multi()) verwendet, sondern z.B. Cconin() verwendet. D.h. das folgende Programm funktioniert unter MagiC und stürzt unter MultiTOS (MiNT 1.08+AES 4.1) ab. Das Problem liegt wahrscheinlich an der Restauration des Supervisor-Stacks (Systemstapelzeiger), dabei versagt MultiTOS wegen des inhomogenen Konzepts AES<->MiNT.

------------------------------ schnipp --------------------------
#include <tos.h>
#include <aes.h>
#include <setjmp.h>
#include <tosdefs.h>
#include <stdio.h>

jmp_buf env;

void cdecl handler(long signr)
{
    printf("handler: Signal %ld empfangen.\n", signr);
    Cconws("Mache Psigreturn()\r\n");
    Psigreturn();
    longjmp(env, 1);
}

int main( void )
{
    long ssp;

    appl_init();
    printf("Meine ProcID ist %d.\n", Pgetpid());
    Psignal(SIGUSR1, handler);

    if  (setjmp(env))
        Cconws("komme von longjmp.\r\n");
    else    Cconws("komme von setjmp.\r\n");
    ssp = Super(0L);
    Super((void *) ssp);
    printf("ssp = 0%08lx\n", ssp);
    evnt_keybd();
    return(0);
}

Querverweis: Signale   Prozessfunktionen   GEMDOS


Home GEMDOSGEMDOS Programmstart und TPAProgrammstart und TPA gemdos-Trapgemdos-Trap