signal (C RTL)

Aus Appmethod Topics
Wechseln zu: Navigation, Suche

Nach oben zu signal.h - Index


Header-Datei

signal.h

Kategorie

Prozesssteuerungsroutinen

Prototyp

void (_USERENTRY *signal(int sig, void (_USERENTRY *func)(int sig[, int subcode])))(int);

Beschreibung

Gibt Aktionen für die Signalbehandlung an.

signal legt fest, wie nach Empfang des Signals mit der Nummer sig dieses Signal behandelt wird. Sie können eine benutzerdefinierte Behandlungsroutine (angegeben über das Argument func) installieren oder eine der beiden in signal.h definierten Behandlungsroutinen SIG_DFL und SIG_IGN verwenden. Die Funktion func muss mit der Aufrufkonvention _USERENTRY deklariert werden.

Eine Routine, die ein Signal abfängt (etwa eine Gleitkomma-Exception), löscht auch das Signal. Um weiterhin Signale empfangen zu können, muss über einen erneuten Aufruf von signal die Signalbehandlungsroutine neu installiert werden.

SIG_DFL

Beendet das Programm

SIG_ERR

Gibt an, dass signal wegen eines Fehlers zurückkehrte

SIG_IGN

Dieser Signaltyp wird ignoriert



Die folgende Tabelle enthält die Signaltypen und ihre Standardwerte:

SIGBREAK

Die Tastatur muss sich im Direktmodus befinden.

SIGABRT

Programmabbruch. Die Standardaktion entspricht dem Aufruf von _exit(3).

SIGFPE

Berechnungsfehler aufgrund einer Division durch 0, einer ungültigen Operation und ähnlichem. Die Standardaktion entspricht dem Aufruf von _exit(1).

SIGILL

Ungültige Operation. Standardaktion entspricht dem Aufruf von _exit(1).

SIGINT

Ctrl-C-Interrupt. Die Standardaktion entspricht dem Aufruf von _exit(3).

SIGSEGV

Ungültiger Speicherzugriff. Die Standardaktion entspricht dem Aufruf von _exit(1).

SIGTERM

Aufforderung zur Programmbeendigung. Die Standardaktion entspricht dem Aufruf von _exit(1).

Benutzerdefinierte Signale können nur durch einen Aufruf von raise generiert werden. Die Standardaktion ist, das Signal zu ignorieren.



In signal.h ist der Typ sig_atomic_t definiert, der größte ganzzahlige Typ, den der Prozessor bei Vorliegen von asynchronen Interrupts als Ganzes laden kann (dies ist ein 32-Bit-Integerwert -- ein Borland C++ Integer).

Wird ein Signal über die Funktion raise oder durch ein externes Ereignis generiert, passieren die beiden folgenden Dinge:

  • Ist für das Signal eine benutzerdefinierte Behandlungsroutine definiert, wird als Aktion für diesen Signaltyp SIG_DFL eingesetzt.
  • Die benutzerdefinierte Funktion wird mit dem Signaltyp als Parameter aufgerufen.

Die benutzerdefinierte Behandlungsroutine kann über return zurückkehren oder über einen Aufruf von abort, _exit, exit oder longjmp. Soll Ihre Behandlungsroutine weiterhin Signale empfangen und behandeln, dann muss sie die Funktion signal erneut aufrufen.

Borland C++ implementiert eine Erweiterung von ANSI C für Signale des Typs SIGFPE, SIGSEGV oder SIGILL. Die benutzerdefinierte Funktion wird mit einem oder zwei zusätzlichen Parametern aufgerufen. Wurden SIGFPE, SIGSEGV oder SIGILL als Ergebnis eines expliziten Aufrufs der Funktion raise ausgelöst, wird die benutzerdefinierte Behandlungsroutine mit einem zusätzlichen Parameter aufgerufen, einem Integerwert, der angibt, dass die Behandlungsroutine explizit aufgerufen wurde. Es gibt für SIGFPE, SIGSEGV und SIGILL folgende explizite Aktivierungswerte.

Anmerkung:  Die Deklarationen dieser Typen sind in float.h definiert.

SIGFPE

FPE_EXPLICITGEN

SIGSEGV

SEGV_EXPLICITGEN

SIGILL

ILL_EXPLICITGEN



Wird SIGFPE wegen einer Gleitkomma-Exception ausgelöst, wird die benutzerdefinierte Behandlungsroutine mit einem zusätzlichen Parameter aufgerufen, der den FPE_xxx-Typ des Signals angibt. Werden SIGSEGV, SIGILL oder die Integer-bezogenen Varianten der SIGFPE-Signale (FPE_INTOVFLOW oder FPE_INTDIV0) als Ergebnis einer Prozessor-Exception ausgelöst, wird die benutzerdefinierte Behandlungsroutine mit zwei zusätzlichen Parametern aufgerufen:

1.Der Exception-Typ SIGFPE, SIGSEGV oder SIGILL (alle diese Typen sind in float.h definiert). Der erste Parameter ist der übliche ANSI-Signaltyp.

2. Einen Integer-Zeiger in den Stack des Interrupt-Handlers, der die benutzerdefinierte Behandlungsroutine aufgerufen hat. Dieser Zeiger verweist auf eine Liste von Prozessorregistern, die gesichert wurden, als die Exception auftrat. Diese Register liegen in derselben Reihenfolge vor, wie die Parameter einer Interrupt-Funktion, also EBP, EDI, ESI, EDS, ES, EDX, ECX, EBX, EAX, EIP, CS, EFL. Um einen Registerwert zu ändern, nachdem die Behandlungsroutine zurückgekehrt ist, ändern Sie eine der Positionen in dieser Liste.

Möchten Sie beispielsweise den Wert von SI ändern, können Sie Folgendes tun:

*((int*)list_pointer + 2) = new_SI_value;

Auf diese Weise kann die Behandlungsroutine jedes Register, das Sie möchten, überprüfen und richtigstellen.

Die folgenden Signale des Typs SIGFPE können auftreten (oder generiert werden). Sie entsprechen dem Exceptions, die die 80x87-Prozessorfamilie ermitteln kann, und den Exceptions "INTEGER DIVIDE BY ZERO" (Integer-Division durch Null) und "INTERRUPT ON OVERFLOW" (Interrupt bei Überlauf) der Haupt-CPU. (Deren Deklarationen sind in float.h definiert.)

FPE_INTOVFLOW

INTO bei gesetzten OF-Flag ausgeführt

FPE_INTDIV0

Integer-Division durch Null

FPE_INVALID

Ungültige Operation

FPE_ZERODIVIDE

Division durch Null

FPE_OVERFLOW

Numerischer Überlauf

FPE_UNDERFLOW

Numerischer Unterlauf

FPE_INEXACT

Genauigkeit

FPE_EXPLICITGEN

Benutzerprogramm führte raise(SIGFPE) aus

FPE_STACKFAULT

Gleitkomma-Stack-Über- oder -Unterlauf

FPE_STACKFAULT

Stack-Überlauf



Die Signale FPE_INTOVFLOW und FPE_INTDIV0 werden von Integer-Operationen, die anderen von Gleitkommaoperation generiert. Ob Gleitkomma-Exceptions generiert werden, hängt vom Steuerwort des numerischen Coprozessors ab, das mit _control87 geändert werden kann. Nicht normale Exceptions werden von Borland C++ behandelt und nicht der Signalbehandlungsroutine übergeben.

Die folgenden Signale des Typs SIGSEGV können auftreten:

SEGV_BOUND

Grenzbeschränkungs-Exception

SEGV_EXPLICITGEN

raise(SIGSEGV) wurde ausgeführt



Die folgenden Signale des Typs SIGILL können auftreten:

ILL_EXECUTION

Versuch einer unzulässigen Operation

ILL_EXPLICITGEN

raise(SIGILL) wurde ausgeführt



Ist der Signaltyp SIGFPE, SIGSEGV oder SIGILL, ist ein Aufruf von return durch die Signalbehandlungsroutine im Allgemeinen dann nicht ratsam, wenn der Status des Gleitkommaprozessors ungültig ist, das Ergebnis einer Integer-Division falsch ist, eine Operation unerwarteterweise zu einem Überlauf geführt hat, eine Grenzanweisung fehlgeschlagen ist, oder versucht wurde, eine ungültige Operation auszuführen. Ein return ist nur dann ratsam, wenn die Behandlungsroutine die Register so ändert, dass ein vernünftiger Rückkehrkontext gegeben ist, oder der Signaltyp anzeigt, dass das Signal explizit generiert wurde (beispielsweise FPE_EXPLICITGEN, SEGV_EXPLICITGEN oder ILL_EXPLICITGEN). In der Regel sollten Sie in diesem Fall eine Fehlermeldung anzeigen lassen und das Programm mit _exit, exit oder abort beenden. Wird return unter allen anderen Bedingungen ausgeführt, ist das Verhalten des Programms wahrscheinlich nicht vorhersehbar.

Anmerkung:  Seien Sie insbesondere vorsichtig, wenn Sie die Funktion signal in einem Multithread-Programm verwenden. Die Siganale SIGINT, SIGTERM und SIGBREAK können in einer nicht unter Win32 laufenden Anwendung nur vom Haupt-Thread (Thread eins) verwendet werden. Wird eines dieser Signals ausgelöst, dann wird der aktuell ausgeführte Thread ausgesetzt und die Steuerung geht, sofern vorhanden, an die Signalbehandlungsroutine über, die von Thread eins eingerichtet wurde. Andere Signale können von jedem Thread behandelt werden.

Anmerkung:  Eine Signalbehandlungsroutine sollte keine Funktionen der C++ Laufzeitbibliothek verwenden, da dabei ein Semaphor-Deadlock auftreten könnte. Stattdessen sollte die Behandlungsroutine ein Flag setzen oder einen Semaphor senden und unmittelbar darauf zurückkehren.

Rückgabewert

Wenn erfolgreich, gibt signal einen Zeiger auf die vorige für diesen Signaltyp angegebene Behandlungsroutine zurück.

Bei einem Fehler gibt signal SIG_ERR zurück und setzt die externe Variable errno auf EINVAL.

Beispiel



 /* signal-Beispiel */
 /*
     Dieses Beispiel installiert eine Signalbehandlungsroutine für SIGFPE,
     fängt einen Integerüberlauf ab, berichtigt das Register AX
     und kehrt zurück.  Dieses Beispiel KÖNNTE dazu führen, dass Ihr Computer
     abstürzt, und erzeugt, abhängig vom verwendeten Speichermodell,
     Laufzeitfehler.
 */
 #pragma inline
 #include <stdio.h>
 #include <signal.h>
 #ifdef __cplusplus
    typedef void (*fptr)(int);
 #else
    typedef void (*fptr)();
 #endif
 void Catcher(int *reglist)
 {
    signal(SIGFPE, (fptr)Catcher);  //  ******Signalbehandlungsroutine erneut installieren
    printf("Caught it!\n"); *(reglist + 8) = 3; /* bei Rückkehr AX = 3 setzen */
 }
 int main(void)
 {
    signal(SIGFPE, (fptr)Catcher);  /* Catcher in passenden Typ umwandeln */
    asm     mov     ax,07FFFH       /* AX = 32767 */
    asm     inc     ax              /* bewirkt Überlauf */
    asm     into                    /* Behandlungsroutine aktivieren */
    /* Die Behandlungsroutine setzt bei ihrer Rückkehr AX auf 3. Würde das nicht geschehen,
       würde eine weitere Exception ausgelöst, wenn das nächste 'into'
       nach der Anweisung 'dec' ausgeführt wird. */
    asm     inc     ax              /* jetzt kein Überlauf */
    asm     into                    /* aktiviert nicht */
    return 0;
 }



Portabilität



POSIX Win32 ANSI C ANSI C++

+

+

+

+