C Language
Traitement du signal
Recherche…
Syntaxe
- void (* signal (int sig, void (* func) (int))) (int);
Paramètres
Paramètre | Détails |
---|---|
SIG | Le signal pour mettre le gestionnaire de signal à l'un des SIGABRT , SIGFPE , SIGILL , SIGTERM , SIGINT , SIGSEGV ou à une valeur d'implémentation définie |
func | Le gestionnaire de signal, qui est l'un des suivants: SIG_DFL , pour le gestionnaire par défaut, SIG_IGN pour ignorer le signal ou un pointeur de fonction avec la signature void foo(int sig); . |
Remarques
L'utilisation de gestionnaires de signaux avec uniquement les garanties du standard C impose diverses limitations à ce qui peut ou ne peut pas être fait dans le gestionnaire de signaux défini par l'utilisateur.
Si la fonction définie par l'utilisateur est
SIGFPE
lors de la gestion deSIGSEGV
,SIGFPE
,SIGILL
ou de toute autre interruption matérielle définie par l'implémentation, le comportement n'est pas défini par le standard C. C’est parce que l’interface de C ne donne pas les moyens de changer l’état défectueux (par exemple après une division par0
) et donc, lors du retour du programme, il se trouve exactement dans le même état qu'avant l’interruption matérielle.Si la fonction définie par l'utilisateur a été appelée à la suite d'un appel d'
abort
ou deraise
, le gestionnaire de signaux n'est pas autorisé à appeler à nouveau uneraise
.Les signaux peuvent arriver au milieu de toute opération et, par conséquent, l'indivisibilité des opérations ne peut généralement pas être garantie et la gestion du signal ne fonctionne pas bien avec l'optimisation. Par conséquent, toutes les modifications apportées aux données dans un gestionnaire de signaux doivent être des variables.
- de type
sig_atomic_t
(toutes versions) ou un type atomique sans verrou (depuis C11, optionnel) - qui sont qualifiés de
volatile
.
- de type
Les autres fonctions de la bibliothèque standard C ne respecteront généralement pas ces restrictions, car elles peuvent changer les variables dans l'état global du programme. La norme C ne fait que des garanties pour
abort
,_Exit
(depuis C99),quick_exit
(depuis C11), lesignal
(pour le même nombre de signaux), et certaines opérations atomiques (depuis C11).
Le comportement n'est pas défini par la norme C si l'une des règles ci-dessus est violée. Les plates-formes peuvent avoir des extensions spécifiques, mais celles-ci ne sont généralement pas portables au-delà de cette plate-forme.
Généralement, les systèmes ont leur propre liste de fonctions qui sont des signaux asynchrones sûrs , c'est-à-dire des fonctions de la bibliothèque C pouvant être utilisées par un gestionnaire de signaux. Par exemple, souvent,
printf
fait partie de ces fonctions.En particulier, le standard C ne définit pas beaucoup l'interaction avec son interface de threads (depuis C11) ou toute autre bibliothèque de thread spécifique à la plate-forme telle que les threads POSIX. De telles plates-formes doivent spécifier l'interaction de telles bibliothèques de threads avec des signaux eux-mêmes.
Traitement du signal avec “signal ()”
Les numéros de signal peuvent être synchrones (comme SIGSEGV
- erreur de segmentation) lorsqu'ils sont déclenchés par un dysfonctionnement du programme lui-même ou asynchrone (comme l'attention interactive SIGINT
) lorsqu'ils sont initiés à l'extérieur du programme, par exemple par une pression sur Cntrl-C
.
La fonction signal()
fait partie de la norme ISO C et peut être utilisée pour affecter une fonction à un signal spécifique
#include <stdio.h> /* printf() */
#include <stdlib.h> /* abort() */
#include <signal.h> /* signal() */
void handler_nonportable(int sig)
{
/* undefined behavior, maybe fine on specific platform */
printf("Catched: %d\n", sig);
/* abort is safe to call */
abort();
}
sig_atomic_t volatile finished = 0;
void handler(int sig)
{
switch (sig) {
/* hardware interrupts should not return */
case SIGSEGV:
case SIGFPE:
case SIGILL:
/* quick_exit is safe to call */
quick_exit(EXIT_FAILURE);
/* use _Exit in pre-C11 */
_Exit(EXIT_FAILURE);
default:
/* Reset the signal to the default handler,
so we will not be called again if things go
wrong on return. */
signal(sig, SIG_DFL);
/* let everybody know that we are finished */
finished = sig;
return;
}
}
int main(void)
{
/* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
if (signal(SIGSEGV, &handler) == SIG_ERR) {
perror("could not establish handler for SIGSEGV");
return EXIT_FAILURE;
}
/* Catch the SIGTERM signal, termination request */
if (signal(SIGTERM, &handler) == SIG_ERR) {
perror("could not establish handler for SIGTERM");
return EXIT_FAILURE;
}
/* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
signal(SIGINT, SIG_IGN);
/* Do something that takes some time here, and leaves
the time to terminate the program from the keyboard. */
/* Then: */
if (finished) {
fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
return EXIT_FAILURE;
}
/* Try to force a segmentation fault, and raise a SIGSEGV */
{
char* ptr = 0;
*ptr = 0;
}
/* This should never be executed */
return EXIT_SUCCESS;
}
L'utilisation de signal()
impose des limitations importantes à ce que vous êtes autorisé à faire dans les gestionnaires de signaux, voir les remarques pour plus d'informations.
POSIX recommande l'utilisation de sigaction()
au lieu de signal()
, en raison de son comportement sous-spécifié et des variations importantes de sa mise en œuvre. POSIX définit également beaucoup plus de signaux que la norme ISO C, y compris SIGUSR1
et SIGUSR2
, qui peuvent être utilisés librement par le programmeur à toutes fins.