Les signaux ne sont pas réactivés correctement avec execv ()
Question
J'écris un programme essentiel au système pour une distribution Linux que je développe. Il doit redémarrer à la réception de certains signaux pour éviter un crash. Le problème est que, après le redémarrage, je ne peux pas réactiver ce signal. Autrement dit, le signal ne peut pas être reçu deux fois. Après execv (), lorsque le nouveau processus appelle signal () pour configurer le signal, SIG_DFL est renvoyé. À chaque fois. Même si je l’appelle deux fois de suite, cela signifie qu’il n’a jamais été réglé. Un drapeau étrange est-il reporté du processus d'origine?
La solution
Vous craignez le fait que vous essayez essentiellement de gérer un signal de manière récursive.
Lorsque vous utilisez signal()
pour enregistrer un gestionnaire de signaux, ce numéro de signal est bloqué jusqu'au retour du gestionnaire de signaux. En fait, le noyau / libc bloque ce numéro de signal lorsque le gestionnaire de signaux est appelé et le débloque après son retour. . Comme vous ne revenez jamais du gestionnaire de signal (à la place vous execl
un nouveau binaire), SIGUSR1
reste bloqué et n'est donc pas intercepté une seconde fois.
Ceci peut être constaté en examinant /proc/</pid>/status
avant et après l'envoi du premier SigCgt
.
Avant:
$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000000
SigCgt: 0000000000000200
Après:
$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000200
SigCgt: 0000000000000200
Notez que man signal(7)
indique que le signal 10 est enregistré (le numéro est un champ de bits; le 10ème bit est défini, ce qui équivaut à SIGUSR1, voir SigBlk
pour les numéros). SIGUSR
est vide avant que sighandler
soit envoyé à votre processus, mais après l'envoi du signal, il contient sigaction
.
Vous avez deux moyens de résoudre ce problème:
a). Débloquer manuellement SA_NODEFER
avant d'appeler signal
dans <=>:
sigset_t sigs;
sigprocmask(0, 0, &sigs);
sigdelset(&sigs, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigs);
b). Utilisez <=> avec l'indicateur <=> au lieu de <=> pour enregistrer le gestionnaire de signaux. Ceci évitera le blocage de <=> l'intérieur du gestionnaire de signaux:
struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
Autres conseils
Les gestionnaires de signaux ne sont pas hérités sur exec
parce que SIG_IGN
écrase tout votre espace adresse et que tous les gestionnaires de signaux non réinitialisés pointeraient alors au mauvais endroit. La seule fois où il n'est pas réinitialisé, c'est s'il est défini sur, par exemple, <=>, ce qui ne dépend pas de l'espace d'adressage du processus précédent - <=>.