Las señales no se vuelven a habilitar correctamente en execv ()
Pregunta
Estoy escribiendo un programa crítico para una distribución de Linux que estoy desarrollando. Necesita reiniciarse al recibir ciertas señales, para tratar de evitar fallas. El problema es que, después del reinicio, no puedo volver a habilitar esa señal. Es decir, la señal no se puede recibir dos veces. Después de ejecutarse (), cuando el nuevo proceso llama a la señal () para configurar la señal, se devuelve SIG_DFL. Cada vez. Incluso si lo llamo dos veces seguidas, lo que indica que nunca se configuró en primer lugar. ¿Se está transfiriendo alguna bandera extraña del proceso original?
Solución
Te estás equivocando por el hecho de que esencialmente estás tratando de manejar recursivamente una señal.
Cuando se usa signal()
para registrar un controlador de señal, ese número de señal se bloquea hasta que el controlador de señal regrese; en efecto, el núcleo / libc bloquea ese número de señal cuando se invoca el controlador de señal, y lo desbloquea después de que el controlador de señal regrese . Como nunca regresa del controlador de señal (en su lugar, execl
un nuevo binario), SIGUSR1
permanece bloqueado y, por lo tanto, no se detecta la segunda vez.
Esto se puede ver examinando /proc/</pid>/status
antes y después de enviar el primer SigCgt
.
Antes:
$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000000
SigCgt: 0000000000000200
Después:
$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000200
SigCgt: 0000000000000200
Tenga en cuenta que man signal(7)
indica que la señal 10 está registrada (el número es un campo de bits; el décimo bit está configurado, lo que equivale a SIGUSR1; consulte SigBlk
para ver los números). SIGUSR
está vacío antes de que se envíe sighandler
a su proceso, pero después de enviar la señal contiene sigaction
.
Tienes dos formas de resolver esto:
a). Desbloquee manualmente SA_NODEFER
antes de llamar a signal
en <=>:
sigset_t sigs;
sigprocmask(0, 0, &sigs);
sigdelset(&sigs, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigs);
b). Use <=> con la bandera <=> en lugar de <=> para registrar el controlador de señal. Esto evitará que <=> se bloquee dentro del controlador de señal:
struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
Otros consejos
Los manejadores de señales no se heredan en exec
porque SIG_IGN
sobrescribe su espacio de direcciones completo, y cualquier manejador de señales que no se restablezca estaría apuntando al lugar equivocado. El único momento en que no se restablece es si está configurado en, por ejemplo, <=>, que no depende del espacio de direcciones del proceso pre - <=>.