| #include <pronix.de> |
|
|
4.1. signal - Einrichten von Signalhandlern
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Name | Beschreibung | UNIX | DOS | Default-Aktion |
| SIGABRT | abnormale Beendigung (abort()) | X | X | Beendigung |
| SIGALRM | Ablauf einer Zeitschaltuhr | X | Beendigung | |
| SIGBUS | Hardware-Fehler | X | Beendigung | |
| SIGCHLD | Statusänderung in Kindprozess | X | Ignorieren | |
| SIGCONT | Fortsetzen eines angehaltenen Programms | X | Fortsetzen/Ignorieren | |
| SIGEMT | Hardware-Fehler | X | Beendigung | |
| SIGFPE | Arithmetischer Fehler | X | X | Beendigung |
| SIGILL | Unerlaubter Hardware-Befehl | X | X | Beendigung |
| SIGINT | Unterbrechungstaste am Terminal | X | X | Beendigung |
| SIGIO | Asynchrone I/O | X | Ignorieren | |
| SIGKILL | Beendigung | X | Beendigung | |
| SIGPIPE | Schreiben in Pipes ohne Leser | X | Beendigung | |
| SIGPWR | Stromausfall | X | Ignorieren | |
| SIGQUIT | Unterbrechungstaste am Terminal | X | Beendigung | |
| SIGSEGV | Unerlaubte Speicheradressierung | X | X | Beendigung |
| SIGSTOP | Prozess anhalten | X | Prozess anhalten | |
| SIGTTIN | Lesewunsch von Hintergrundprozess | X | Prozess anhalten | |
| SIGTTOU | Schreibwunsch von Hintergrundprozess | X | Prozess anhalten | |
| SIGUSR1 | Benutzerdefiniert | X | Beendigung | |
| SIGUSR2 | Benutzerdefiniert | X | Beendigung | |
| SIGXCPU | Überschreitung des CPU-Limits | X | Beendigung | |
| SIGXFSZ | Überschreitung der maximalen Dateigröße (4GB) | X | Beendigung | |
| SIGURG | dringendes Ereignis | X | Ignorieren | |
| SIGWINCH | Änderung der Windows-Größe | X | Ignorieren |
Folgende Befehle sind laut ANSI-C vorgeschrieben ...
| Name | Bedeutung |
| SIGABRT | Dieses Signal signalisiert das das Programm abnormal beendet wurde (abort()). |
| SIGFPE | Diese Signal wird angezeigt z.B. bei einer Division durch 0 oder einem Überlauf einer Zahl. |
| SIGILL | Dies wird angezeigt wenn ein illegaler Hardware-Befehl ausgeführt wird. |
| SIGINT | Dies Signal wird an alle Prozesse geschickt wenn die Tasten-Kombination STRG-C gedrückt wurde. |
| SIGSEGV | Wird dies Angezeigt wurde versucht auf eine unerlaubte Speicherstelle zu schreiben oder zu lesen. |
| SIGTERM | Voreingestelltes Signal, das das kill-Kommando an einen Prozess schickt, das beendet werden |
Kommen wir wieder zurück zu unserer Erklärung des Prototypen ...
signalfunktion *signal(int signr,signalfunktion *sighandler);
Jetzt benötigen Sie noch die Variable sighandler. Hierbei sind auch zwei Angaben in der Headerdatei <signal.h> definiert. SIG_DFL und SIG_IGN. Mit SIG_DFL wird die Default-Aktion ausgeführt die meist das Beenden des Prozesses bedeutet. z.B. ...
signal(SIGINT,SIG_DFL);
Falls bei dem Programm die Tastenkombination STRG+C gedrückt wurde, wird die Default-Einstellung des Signals SIGINT ausgeführt und dies bedeutet, dass das Programm beendet würde. Als zweite Möglichkeit können Sie eingeben ...
signal(SIGINT,SIG_IGN);
Wenn Sie nun die Tastenkombination STRG+C drücken, würde nichts passieren, da das Signal SIGINT ignoriert wird. Als dritte Möglichkeit können Sie das Signal SIGINT abfangen und übergeben die Adresse einer eigenen Funktion, die das Programm ausführen soll, wenn die Tastekombination STRG+C gedrückt wurde z.B. ...
signal(SIGINT,funktionsaufruf);
Jetzt wird es Zeit um zu sehen wie Sie die Funktion signal() in der Praxis einsetzen können ...
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigfunc(int sig)
{
char c;
if(sig != SIGINT)
return;
else
{
printf("\nWollen sie das Programm beenden (j/n) : ");
while((c=getchar()) != 'n')
return;
exit (0);
}
}
int main()
{
int i;
signal(SIGINT,sigfunc);
while(1)
{
printf("Die Endlosschleife koennen sie mit STRG-C beenden");
for(i=0;i<=48;i++)
printf("\b");
}
return 0;
}
Mit ...
signal(SIGINT,sigfunc);
... richten Sie einen Signalhandler für das Signal SIGINT ein, der die Funktion sigfunc aufrufen soll.
Nun wollen wir ein Programm schreiben, dass Zahlen dividiert. Das Programm soll eine Funktion aufrufen die, falls versucht wurde durch 0 zu teilen, ausgibt das dies nicht möglich ist. Zusätzlich wollen wir zur Demonstration die Tastenkombination STRG+C ignorieren ...
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigfunc(int sig)
{
if(sig != SIGFPE)
return;
else
printf("Sie koennen keinen Wert durch 0 teilen!!\n");
}
int main()
{
int wert,wert2;
signal(SIGFPE,sigfunc); /*Floating Point Error*/
signal(SIGINT,SIG_IGN); /*STRG - C ignorieren*/
printf("Programm zum Dividieren von Zahlen!\n");
printf("Zahl eingeben : ");
scanf("%d",&wert);
while(1)
{
printf("geteilt durch > ");
scanf("%d",&wert2);
printf("Gesamt = %d\n",wert/=wert2);
}
}
Ein weiteres Beispiel mit SIGABRT ...
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigfunc(int sig)
{
if(sig==SIGABRT)
printf("Demonstration von SIGABRT ausgeloest mit abort()\n");
}
int main()
{
signal(SIGABRT,sigfunc);
abort();
return 0;
}
Ich glaube Ihnen dürfte jetzt klar sein, wie man die Signale richtig einsetzt. Um zu testen, ob der Aufruf von signal überhaupt erfolgreich war, gibt es in der Headerdatei <signal.h> den Fehlercode SIG_ERR der mit dem Wert -1 definiert ist. Wollen Sie also signal() (eigentlich sollte es nicht wollen sonder sollen heißen) auf Fehler überprüfen könnte dies so aussehen ...
if( signal(SIGINT,sigfunc) == SIG_ERR)
{ ..........Fehler beim beim Aufruf von signal.......
Für Linux/Unix gilt außerdem noch, dass die beiden Signal SIGKILL und SIGSTOP nicht mit SIG_IGN ignoriert werden können, damit der Superuser immer die Möglichkeit hat das Programm zu killen oder stoppen.
Signale mit fork und exec
Der neue Prozess, den Sie mit fork erzeugen, erbt natürlich auch alle Signalhandler des aufrufenden Prozesses.
Durch Überlagerung eines Prozesses mit den exec-Funktion, verlieren auch die eingerichteten Signalhandler Ihre Gültigkeit. Alle Signale werden wieder auf Ihren Ursprünglichen Zustand (default-Zustand) gesetzt und reagieren auch so.
Ein Hinweis zur Verwendung von Signalen: Verwenden Sie für Signale stets den symbolischen Namen, da die numerischen Werte von System zu System variieren können. Also besser ...
signal(SIGINT, function);
... anstatt wie auch möglich ...
signal(2,function);