J'ai un petit doute sur la gestion des signaux POSIX installés grâce
à sigaction(). J'ai accès à un certain nombre d'Unix dont Linux,
Tru64, Solaris, NetBSD, OpenBSD et FreeBSD. Et NetBSD me pose un
petit problème. Je n'arrive pas à savoir s'il s'agit d'un problème
dans mon code ou d'u truc qui m'aurait échappé.
Considérons le code suivant :
do
{
code_retour = nanosleep(&temporisation, &temporisation);
erreur = errno;
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et
je vois le gestionnaire se lancer (j'ai collé un printf() dans le
gestionnaire en question). Sous NetBSD, le gestionnaire de signal
est lancé dans un thread spécifique (et non le thread de
l'appelant). Ça ne semble pas être en contradiction avec les specs
POSIX. Mais nanosleep() sort avec un code d'erreur EINTR _avant_ que
le signal soit effectivement traité. Or dans la suite des
instructions de la boucle se trouve un test sur une variable volatile
et atomique positionnée par ce gestionnaire de signal. La plupart du
temps, ce test échoue car le gestionnaire de signal s'exécutant dans
un autre thread n'a pas encore positionné la variable à la bonne
valeur.
D'où une série de questions ;-)
1/ Est-ce un comportement attendu ou un bug de la gestion des
signaux de NetBSD ? Je n'observe ce comportement que sous ce
système.
2/ Comment s'assurer de façon propre que le gestionnaire de signal
a terminé ses traitement sans y coller un sem_post() (j'aimerais
éviter) ?
Merci de votre attention,
JKB
PS: Nicolas George, pas la peine de répondre, je t'ai plonké depuis
longtemps.
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et je vois le gestionnaire se lancer (j'ai collé un printf() dans le gestionnaire en question). Sous NetBSD, le gestionnaire de signal est lancé dans un thread spécifique (et non le thread de l'appelant).
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Quel est l'effet de kill(0,SIGINT), il lance un thread ? Si tu places ce kill() après nanosleep, et que nanosleep est interrompu par ^C, tu te retrouves avec deux threads en plus de main() ?
-- LL
Le 8 octobre 2012, JKB a écrit :
Considérons le code suivant :
do
{
code_retour = nanosleep(&temporisation, &temporisation);
erreur = errno;
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et
je vois le gestionnaire se lancer (j'ai collé un printf() dans le
gestionnaire en question). Sous NetBSD, le gestionnaire de signal
est lancé dans un thread spécifique (et non le thread de
l'appelant).
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Quel est l'effet de kill(0,SIGINT), il lance un thread ? Si tu places
ce kill() après nanosleep, et que nanosleep est interrompu par ^C, tu te
retrouves avec deux threads en plus de main() ?
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et je vois le gestionnaire se lancer (j'ai collé un printf() dans le gestionnaire en question). Sous NetBSD, le gestionnaire de signal est lancé dans un thread spécifique (et non le thread de l'appelant).
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Quel est l'effet de kill(0,SIGINT), il lance un thread ? Si tu places ce kill() après nanosleep, et que nanosleep est interrompu par ^C, tu te retrouves avec deux threads en plus de main() ?
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et je vois le gestionnaire se lancer (j'ai collé un printf() dans le gestionnaire en question). Sous NetBSD, le gestionnaire de signal est lancé dans un thread spécifique (et non le thread de l'appelant).
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Si, mais qu'est-ce que cela changerait ?
Quel est l'effet de kill(0,SIGINT), il lance un thread ? Si tu places ce kill() après nanosleep, et que nanosleep est interrompu par ^C, tu te retrouves avec deux threads en plus de main() ?
Je ne sais pas, je n'ai pas essayé.
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Le Wed, 10 Oct 2012 13:39:18 +0200,
Lucas Levrel <lucas.levrel@u-pec.fr> écrivait :
Le 8 octobre 2012, JKB a écrit :
Considérons le code suivant :
do
{
code_retour = nanosleep(&temporisation, &temporisation);
erreur = errno;
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et
je vois le gestionnaire se lancer (j'ai collé un printf() dans le
gestionnaire en question). Sous NetBSD, le gestionnaire de signal
est lancé dans un thread spécifique (et non le thread de
l'appelant).
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Si, mais qu'est-ce que cela changerait ?
Quel est l'effet de kill(0,SIGINT), il lance un thread ? Si tu places
ce kill() après nanosleep, et que nanosleep est interrompu par ^C, tu te
retrouves avec deux threads en plus de main() ?
Je ne sais pas, je n'ai pas essayé.
JKB
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Je simplifie. J'interromps nanosleep() grâce à un SIGINT (ctrl+C) et je vois le gestionnaire se lancer (j'ai collé un printf() dans le gestionnaire en question). Sous NetBSD, le gestionnaire de signal est lancé dans un thread spécifique (et non le thread de l'appelant).
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Si, mais qu'est-ce que cela changerait ?
Quel est l'effet de kill(0,SIGINT), il lance un thread ? Si tu places ce kill() après nanosleep, et que nanosleep est interrompu par ^C, tu te retrouves avec deux threads en plus de main() ?
Je ne sais pas, je n'ai pas essayé.
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Paul Gaborit
À (at) Wed, 10 Oct 2012 13:59:34 +0200, Alain Ketterlin écrivait (wrote):
Paul Gaborit writes:
Ce que j'aimerai savoir c'est, lorsqu'on écrit un programme, quel est le critère pour déterminer s'il va tomber dans l'un ou l'autre des deux cas (le cas "normal" ou il n'y a pas concurrence et celui où le signal est traité par un thread).
(tout système et le programme est multi-threadé) ou (NetBSD).
Heu ?!? Comment faut-il interpréter cette formule ?
-- Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
À (at) Wed, 10 Oct 2012 13:59:34 +0200,
Alain Ketterlin <alain@dpt-info.u-strasbg.fr> écrivait (wrote):
Paul Gaborit <Paul.Gaborit@invalid.invalid> writes:
Ce que j'aimerai savoir c'est, lorsqu'on écrit un programme, quel est le
critère pour déterminer s'il va tomber dans l'un ou l'autre des deux cas
(le cas "normal" ou il n'y a pas concurrence et celui où le signal est
traité par un thread).
(tout système et le programme est multi-threadé) ou (NetBSD).
Heu ?!? Comment faut-il interpréter cette formule ?
--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
À (at) Wed, 10 Oct 2012 13:59:34 +0200, Alain Ketterlin écrivait (wrote):
Paul Gaborit writes:
Ce que j'aimerai savoir c'est, lorsqu'on écrit un programme, quel est le critère pour déterminer s'il va tomber dans l'un ou l'autre des deux cas (le cas "normal" ou il n'y a pas concurrence et celui où le signal est traité par un thread).
(tout système et le programme est multi-threadé) ou (NetBSD).
Heu ?!? Comment faut-il interpréter cette formule ?
-- Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Le Thu, 11 Oct 2012 09:14:00 +0200, Alain Ketterlin écrivait :
Paul Gaborit writes:
À (at) Wed, 10 Oct 2012 13:59:34 +0200, Alain Ketterlin écrivait (wrote):
Paul Gaborit writes:
Ce que j'aimerai savoir c'est, lorsqu'on écrit un programme, quel est le critère pour déterminer s'il va tomber dans l'un ou l'autre des deux cas (le cas "normal" ou il n'y a pas concurrence et celui où le signal est traité par un thread).
(tout système et le programme est multi-threadé) ou (NetBSD).
Heu ?!? Comment faut-il interpréter cette formule ?
si le programme est multi-threadé alors c'est pénible sinon si le système est NetBSD alors c'est aussi pénible sinon tout va bien, en sortie d'un appel interrompu le handler est exécuté
Ici "c'est pénible" signifie qu'il faut recourir à sem_wait/sem_post.
Même pas... Parce que j'ai passé la journée d'hier à mettre sur papier une machine à état qui fonctionnait partout. Le couple sem_wait()/sem_post() arrive à des conditions bloquantes dans certains cas. Je crois avoir trouvé un début de solution en lançant le traitement du gestionnaire de signal dans un thread dédié (mais pas le gestionnaire, sinon je ne peux pas interrompre les appels systèmes lents) et en effectuant un raise() pour réveiller l'appel système lent en fin de traitement du gestionnaire.
L'intérêt est de garder le même traitement quel que soit l'OS cible. Plus de nouvelles lorsque j'aurai implanté la chose, donc pas avant la semaine prochaine.
Cordialement,
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Le Thu, 11 Oct 2012 09:14:00 +0200,
Alain Ketterlin <alain@dpt-info.u-strasbg.fr> écrivait :
Paul Gaborit <Paul.Gaborit@invalid.invalid> writes:
À (at) Wed, 10 Oct 2012 13:59:34 +0200,
Alain Ketterlin <alain@dpt-info.u-strasbg.fr> écrivait (wrote):
Paul Gaborit <Paul.Gaborit@invalid.invalid> writes:
Ce que j'aimerai savoir c'est, lorsqu'on écrit un programme, quel est le
critère pour déterminer s'il va tomber dans l'un ou l'autre des deux cas
(le cas "normal" ou il n'y a pas concurrence et celui où le signal est
traité par un thread).
(tout système et le programme est multi-threadé) ou (NetBSD).
Heu ?!? Comment faut-il interpréter cette formule ?
si le programme est multi-threadé alors
c'est pénible
sinon si le système est NetBSD alors
c'est aussi pénible
sinon
tout va bien, en sortie d'un appel interrompu le handler est exécuté
Ici "c'est pénible" signifie qu'il faut recourir à sem_wait/sem_post.
Même pas... Parce que j'ai passé la journée d'hier à mettre sur
papier une machine à état qui fonctionnait partout. Le couple
sem_wait()/sem_post() arrive à des conditions bloquantes dans
certains cas. Je crois avoir trouvé un début de solution en lançant
le traitement du gestionnaire de signal dans un thread dédié (mais
pas le gestionnaire, sinon je ne peux pas interrompre les appels
systèmes lents) et en effectuant un raise() pour réveiller
l'appel système lent en fin de traitement du gestionnaire.
L'intérêt est de garder le même traitement quel que soit l'OS cible.
Plus de nouvelles lorsque j'aurai implanté la chose, donc pas avant
la semaine prochaine.
Cordialement,
JKB
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Le Thu, 11 Oct 2012 09:14:00 +0200, Alain Ketterlin écrivait :
Paul Gaborit writes:
À (at) Wed, 10 Oct 2012 13:59:34 +0200, Alain Ketterlin écrivait (wrote):
Paul Gaborit writes:
Ce que j'aimerai savoir c'est, lorsqu'on écrit un programme, quel est le critère pour déterminer s'il va tomber dans l'un ou l'autre des deux cas (le cas "normal" ou il n'y a pas concurrence et celui où le signal est traité par un thread).
(tout système et le programme est multi-threadé) ou (NetBSD).
Heu ?!? Comment faut-il interpréter cette formule ?
si le programme est multi-threadé alors c'est pénible sinon si le système est NetBSD alors c'est aussi pénible sinon tout va bien, en sortie d'un appel interrompu le handler est exécuté
Ici "c'est pénible" signifie qu'il faut recourir à sem_wait/sem_post.
Même pas... Parce que j'ai passé la journée d'hier à mettre sur papier une machine à état qui fonctionnait partout. Le couple sem_wait()/sem_post() arrive à des conditions bloquantes dans certains cas. Je crois avoir trouvé un début de solution en lançant le traitement du gestionnaire de signal dans un thread dédié (mais pas le gestionnaire, sinon je ne peux pas interrompre les appels systèmes lents) et en effectuant un raise() pour réveiller l'appel système lent en fin de traitement du gestionnaire.
L'intérêt est de garder le même traitement quel que soit l'OS cible. Plus de nouvelles lorsque j'aurai implanté la chose, donc pas avant la semaine prochaine.
Cordialement,
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Lucas Levrel
Le 10 octobre 2012, JKB a écrit :
Le Wed, 10 Oct 2012 13:39:18 +0200, Lucas Levrel écrivait :
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Évidemment, si le traitement ne doit être fait que dans le gestionnaire de SIGINT, il faudra créer un gestionnaire pour tous les signaux qui fasse aussi fait=1; .
-- LL
Le 10 octobre 2012, JKB a écrit :
Le Wed, 10 Oct 2012 13:39:18 +0200,
Lucas Levrel <lucas.levrel@u-pec.fr> écrivait :
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Évidemment, si le traitement ne doit être fait que dans le gestionnaire de
SIGINT, il faudra créer un gestionnaire pour tous les signaux qui fasse
aussi fait=1; .
Évidemment, si le traitement ne doit être fait que dans le gestionnaire de SIGINT, il faudra créer un gestionnaire pour tous les signaux qui fasse aussi fait=1; .
-- LL
JKB
Le Thu, 11 Oct 2012 10:44:54 +0200, Lucas Levrel écrivait :
Le 10 octobre 2012, JKB a écrit :
Le Wed, 10 Oct 2012 13:39:18 +0200, Lucas Levrel écrivait :
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Évidemment, si le traitement ne doit être fait que dans le gestionnaire de SIGINT, il faudra créer un gestionnaire pour tous les signaux qui fasse aussi fait=1; .
Parce que ce serait trop simple ;-)
Je cherche un bug dans un programme qui est multithreadé (et qui doit traiter le signal SIGUSR1 par thread en plus d'un SIGINT qui peut être traité plus globalement). Je suis tombé sur quelque chose d'incompréhensible qui m'a fait faire un exemple minimal monothreadé qui présentait le même souci avec le seul SIGINT.
Je sais bien qu'un esprit fort comme Michel Talon va me dire que ce n'est pas bien, mais en l'occurrence, c'est comme ça que c'est conçu et ça ne dépend pas de moi (un processus externe récupère des données depuis plusieurs périphériques et envoie un signal au processus de lecture, lequel réveille avec un mécanisme un peu sioux le bon thread de traitement).
Utiliser une variable ne serait possible qu'en utilisant les variables globales par thread, mais ces fonctions ne peuvent pas être appelées depuis un gestionnaire de signal...
Cordialement,
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Le Thu, 11 Oct 2012 10:44:54 +0200,
Lucas Levrel <lucas.levrel@u-pec.fr> écrivait :
Le 10 octobre 2012, JKB a écrit :
Le Wed, 10 Oct 2012 13:39:18 +0200,
Lucas Levrel <lucas.levrel@u-pec.fr> écrivait :
Ne peux-tu pas utiliser sigtimedwait à la place de nanosleep ?
Évidemment, si le traitement ne doit être fait que dans le gestionnaire de
SIGINT, il faudra créer un gestionnaire pour tous les signaux qui fasse
aussi fait=1; .
Parce que ce serait trop simple ;-)
Je cherche un bug dans un programme qui est multithreadé (et qui
doit traiter le signal SIGUSR1 par thread en plus d'un SIGINT qui
peut être traité plus globalement). Je suis tombé sur
quelque chose d'incompréhensible qui m'a fait faire un exemple
minimal monothreadé qui présentait le même souci avec le seul
SIGINT.
Je sais bien qu'un esprit fort comme Michel Talon va me dire que ce
n'est pas bien, mais en l'occurrence, c'est comme ça que c'est conçu
et ça ne dépend pas de moi (un processus externe récupère des données
depuis plusieurs périphériques et envoie un signal au processus de
lecture, lequel réveille avec un mécanisme un peu sioux le bon thread de
traitement).
Utiliser une variable ne serait possible qu'en utilisant les
variables globales par thread, mais ces fonctions ne peuvent pas
être appelées depuis un gestionnaire de signal...
Cordialement,
JKB
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Évidemment, si le traitement ne doit être fait que dans le gestionnaire de SIGINT, il faudra créer un gestionnaire pour tous les signaux qui fasse aussi fait=1; .
Parce que ce serait trop simple ;-)
Je cherche un bug dans un programme qui est multithreadé (et qui doit traiter le signal SIGUSR1 par thread en plus d'un SIGINT qui peut être traité plus globalement). Je suis tombé sur quelque chose d'incompréhensible qui m'a fait faire un exemple minimal monothreadé qui présentait le même souci avec le seul SIGINT.
Je sais bien qu'un esprit fort comme Michel Talon va me dire que ce n'est pas bien, mais en l'occurrence, c'est comme ça que c'est conçu et ça ne dépend pas de moi (un processus externe récupère des données depuis plusieurs périphériques et envoie un signal au processus de lecture, lequel réveille avec un mécanisme un peu sioux le bon thread de traitement).
Utiliser une variable ne serait possible qu'en utilisant les variables globales par thread, mais ces fonctions ne peuvent pas être appelées depuis un gestionnaire de signal...
Cordialement,
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Lucas Levrel
Le 11 octobre 2012, JKB a écrit :
Utiliser une variable ne serait possible qu'en utilisant les variables globales par thread, mais ces fonctions ne peuvent pas être appelées depuis un gestionnaire de signal...
Et un « bête » tableau global (à chaque thread sa case) ? Je suppose que le nombre de threads est variable... Une liste chaînée ?
-- LL
Le 11 octobre 2012, JKB a écrit :
Utiliser une variable ne serait possible qu'en utilisant les
variables globales par thread, mais ces fonctions ne peuvent pas
être appelées depuis un gestionnaire de signal...
Et un « bête » tableau global (à chaque thread sa case) ? Je suppose que
le nombre de threads est variable... Une liste chaînée ?
Utiliser une variable ne serait possible qu'en utilisant les variables globales par thread, mais ces fonctions ne peuvent pas être appelées depuis un gestionnaire de signal...
Et un « bête » tableau global (à chaque thread sa case) ? Je suppose que le nombre de threads est variable... Une liste chaînée ?