Domanda

Sto scrivendo un programma critico per il sistema per una distribuzione Linux che sto sviluppando.Ha bisogno di riavviarsi quando riceve determinati segnali, per cercare di evitare di schiantarsi.Il problema è che, dopo il riavvio, non riesco a riattivare quel segnale.Cioè, il segnale non può essere ricevuto due volte.Dopo l'esecuzione stessa di execv(), quando il nuovo processo chiama signal() per impostare il segnale, viene restituito SIG_DFL.Ogni volta.Anche se lo chiamo due volte di seguito, indicando che non è mai stato impostato.Qualche strano flag viene ripreso dal processo originale?

È stato utile?

Soluzione

Stai cadendo in fallo nel fatto che stai essenzialmente cercando di gestire ricorsivamente un segnale.

Quando si usa signal() per registrare un gestore di segnale, quel numero di segnale viene bloccato fino al ritorno del gestore di segnale - in effetti il ​​kernel/libc blocca quel numero di segnale quando viene invocato il gestore di segnale e lo sblocca dopo il ritorno del gestore di segnale.Dato che non torni mai dal gestore del segnale (invece tu execl un nuovo binario), SIGUSR1 rimane bloccato e quindi non viene catturato la 2a volta.

Questo può essere visto esaminando /proc/</pid>/status prima e dopo aver inviato il primo SIGUSR1.

Prima:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000000
SigCgt: 0000000000000200

Dopo:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000200
SigCgt: 0000000000000200

Notare che SigCgt indica che il segnale 10 è registrato (il numero è un campo bit;Viene impostato il 10° bit, che corrisponde a SIGUSR1, vedere man signal(7) per i numeri). SigBlk è vuoto prima SIGUSR viene inviato al processo, ma dopo aver inviato il segnale che contiene SIGUSR1.

Hai due modi per risolvere questo problema:

UN).Sblocca manualmente SIGUSR prima di chiamare execl In sighandler:

sigset_t sigs;
sigprocmask(0, 0, &sigs);
sigdelset(&sigs, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigs);

B).Utilizzo sigaction con il SA_NODEFER bandiera invece di signal per registrare il gestore del segnale.Ciò impedirà SIGUSR1 dall'essere bloccato all'interno del gestore del segnale:

struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);

Altri suggerimenti

I gestori di segnali non vengono ereditati in exec perché SIG_IGN sovrascrive l'intero spazio degli indirizzi e tutti i gestori di segnali che non vengono reimpostati indicherebbero quindi un punto errato. L'unica volta che non viene ripristinato è se è impostato, per esempio, su <=>, che non dipende dallo spazio degli indirizzi del processo pre - <=>.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top