Les signaux en C permettent d'informer un processus qu'un événement particulier s'est produit. Chaque processus peut gérer un traitement particulier pour un signal donné. Le traitement lié à un signal associe à un signal donné une fonction de traitement. Lors du déclenchement de cet événement le programme exécute la fonction associée puis reprend l'exécution du programme là où il l'avait laissée.
Comme il y a des différences importantes entre BSD et SYSTEM V, on consultera
le fichier <signal.h>
pour connaître les signaux disponibles. On pose
un traitement pour un signal de la manière suivante :
#include <signal.h> signal(NUMERO_DU_SIGNAL, procedure)La procédure est paramétrée par un entier (correspondant au numéro du signal). Il est nécessaire de réarmer le traitement d'un signal suite au traitement de celui-ci.
SIGINT
indique une interruption (kill -2
ou ^C
) du processus. Poser un récupérateur pour le signal SIGINT
qui affiche le message "Pas d'interruption possible"
en cas d'arrivée
de ce signal.
Voici le programme principal :
main () { int i; int c=0; signal(SIGINT,hand_int); printf("un programme qui boucle, essayer ^C pour l'arreter\n"); while (1) {i++; if ((i % 100000) == 0) {c++;printf("."); fflush(stdout);} } }Ecrire la procédure
hand_int
.
SIGSEGV
indique une "violation mémoire", un adressage interdit. Soit le programme suivant tiré de "la Communication sous Unix" page 163 :
small
char *p; void hand() { } main() { signal(SIGSEGV,hand); p=(char *)sbrk(512); printf("valeur initiale du point de rupture : %u\n",p); printf("valeur du point de rupture apres sbrk : %u\n",sbrk(0)); while(1) *p++='a'; }
Ecrire la fonction void hand()
qui affiche la valeur de p
et
le point de rupture.
SIGINT
en affichant
le nombre d'éléments déjà comptés.
Pour certaines applications l'exécution du programme doit être reprise
en un point particulier. Pour cela il est nécessaire d'utiliser des étiquettes dynamiques. On mémorise l'état de la pile d'exécution du processus dans une variable de type jmp_buf
défini dans <setjmp.h>
avec
la fonction setjmp
. Cette variable constitue l'étiquette. La fonction
longjmp
permet ensuite de reprendre l'exécution au point prévu en restaurant l'état de la pile. La valeur de retour de setjmp
est 0 après son appel ou une valeur non nulle quand ce retour s'effectue par un longjmp
(y compris dans le cas où la valeur retournée par longjmp
est 0).
int setjmp(jmp_buf env); void longjmp (jmp_buf env, int val);
Le mécanisme d'étiquettes dynamiques permet de construire un
mécanisme d'exceptions (comme en ML ou ADA). On définit la syntaxe suivante
pour intégrer des exceptions en C.
include "exception.h"
exception e;
Test()
{
TRY
Body();
EXCEPT(e)
Handler();
ENDTRY
}
avec le déclenchement d'une exception par :
RAISE(e,v)où
e
est une exception et v
un entier.
TRY, EXCEPT, ENDTRY, RAISE seront des macros C, Body et Handler le programme utilisateur.
Lors du déclenchement d'une exception, l'exécution du programme va au dernier récupérateur d'exceptions rencontré (TRY ... ENDTRY). Si l'exception déclenchée correspond à un des EXCEPT(e) le code de son
Handler est alors exécuté, et
le programme continue après le ENDTRY. Si l'exception n'est pas récupérée
elle est de nouveau déclenchée pour atteindre le récupérateur précédent.
_RaiseException
.
On trouvera sur la machine maya.cicrp.jussieu.fr
les
programmes suivants :
SIGINT
.
SIGINT
.
setjmp/longjmp
.
_RaiseException
.
dans le catalogue users/p6ipens/chaillou/enseignements/97-98/programmation/TD3.
N'hésitez pas à les compiler (mettre l'option -traditional
avec
gcc
pour faire passer le préprocesseur correctement), les tester, les lire et les modifier!!!