Il faut faire attention a ne pas faire d'appel bloquant dans les gestionnaires d'interruption.
Mise à part l'intérêt d'une mise en oeuvre de l'appel longjump()/setjump(), qui n'est pas justifiée ici (d'ailleurs les seuls cas ou je l'ai rencontré ne l'étaient pas non plus) je trouve que tu utilises l'enclume pour écraser le clou.
le man page indique que ces appels sont utilisés pour la gestion d'erreurs critiques et pour gérer des interruptions. En plus de cela la fonction qui appelle setjmpp() ne doit pas se terminer lorsque tu appels setjmp(), sinon le contexte de pile sauvegardé n'est pas valide, cela fait quand même une belle restriction.
Faire un select() (POSIX 1) ou un poll() avec un timeout en attente d'entrée sur le stdin (ou autre) aurait été bien plus simple et tu maitriserais mieux le contexte d'exécution.
De plus, utiliser un gestionnaire de signaux avec alarm() te permet de poursuivre l'exécution de ton programme et d'exécuter une action plus tard (genre controler que tu a fais le boulot dans un laps de temps) or ici tu n'as rien a faire sinon attendre, raison de plus pour utiliser poll()/select().
Enfin il te faut te rappeler que l'on peut sortir des appels systèmes lents bloquants lorsque le processus reçoit un signal, a la condition que le gestionnaire installé ne demande pas leur redémarrage. Tu peux très bien donc ne rien faire dans ton handler et traiter la sortie de scanf().
Cependant signal() installe le gestionnaire avec le redémarrage des appels système lents, ce que l'on peut voir avec strace :
rt_sigaction(SIGALRM, {SIG_DFL}, {0x8048490, [ALRM], SA_RESTART}, 8) = 0
Il te faut donc utiliser sigaction(), voici un exemple de code ci-dessous utilisant un gestionnaire de signal() :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include <stdio.h>
#include <unistd.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
//! Dummy function to avoid exit on alarm
void hdle_alarm (int val)
{
// do nothing
}
int main (void)
{
int i = -1 ;
int j = 3 ;
sighandler_t hldle_bckp = NULL ;
struct sigaction act ;
struct sigaction oldact ;
sigset_t set ;
int ret = 0 ;
printf("Begin\n");
/*hldle_bckp = signal (SIGALRM, hdle_alarm) ;
if (hldle_bckp == SIG_ERR)
{
printf("error handler");
return -1 ;
}*/
// Installer notre gestionnaire
sigfillset (&set) ;
act.sa_handler = hdle_alarm ;
act.sa_mask = set ;
act.sa_flags = 0 ; // L'interet ici par rapport a signal est de justement est de ne pas redemarrer les appels systemes lents avec le flags SA_RESTART qui est fournit lors de signal()
if ( sigaction (SIGALRM, &act, &oldact) == -1 )
{
printf("error handler");
// can disp errno
return -1 ;
}
while ((j--) && (ret<=0) )
{
alarm(1) ;
ret = scanf("%d", &i) ;
if (ret<=0)
{
printf("alarm\n") ;
}
}
printf("End with i=%d\n", i);
//signal (SIGALRM, hldle_bckp);
sigaction (SIGALRM, &oldact, NULL);
return 0 ;
} |
Résultat :
1 2 3 4 5
| Begin
alarm
alarm
alarm
End with i=-1 |
Mais je te conseille toujours d'utiliser un poll()...
Partager