2013-06-06 8 views
6

Ho la seguente funzione di sigaction gestoreCome rendere sicura la funzione async-signal?

void signal_term_handler(int sig) 
{ 
    printf("EXIT :TERM signal Received!\n"); 
    int rc = flock(pid_file, LOCK_UN | LOCK_NB); 
    if(rc) { 
     char *piderr = "PID file unlock failed!"; 
     fprintf(stderr, "%s\n", piderr); 
     printf(piderr); 
    } 
    abort(); 
} 

Qualcuno mi ha detto che flock e printf non sono async-signal-safe. E non riuscivo a trovare una funzione asincrona-segnale sicura alternativa per flock in questo list.

e secondo link qui:

quando un segnale interrompe una funzione pericoloso e la segnalazione di cattura chiama una funzione non sicuro, il comportamento è indefinito

Esistono modo rendere flock async-signal-safe? O c'è un'altra soluzione per eseguire flock quando ricevo TERM segnale?

+0

Possibile duplicato di [Come evitare l'uso di printf in un gestore di segnale?] (Https://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-a-signal-handler) per 'printf', https://stackoverflow.com/questions/16979059/use-flock-in-the-sigaction-handler per' flock'. –

risposta

4

È possibile utilizzare fcntl() come alternativa ad affluire().

+0

Attenzione che la semantica dei blocchi 'fcntl()'e diversa e meno utile di' flock() '. – jilles

+0

Infatti, posso usare fcntl per sviluppare una nuova funzione property flock() come indicato in questo [argomento] (http://stackoverflow.com/questions/16988256/how-to-lock-and-unlock-pid-file- con-fcntl). Grazie per la risposta – MOHAMED

0

È possibile utilizzare exit() invece di abort() nel vostro gestore di segnale, e poi mettere le funzioni non sicure in un gestore di uscita utilizzando atexit().

aggiornamento: In generale, non è possibile inserire alcuna chiamata di sistema potenzialmente bloccante nel gestore di segnale. Un modo per evitarlo è semplicemente impostare un flag nel gestore del segnale, quindi eseguire le funzioni desiderate nel contesto del loop principale.

volatile int shutdown = 0; 

void signal_term_handler(int sig) 
{ 
    shutdown = 1; 
} 

void cleanup() { 
    printf("EXIT :TERM signal Received!\n"); 
    int rc = flock(pid_file, LOCK_UN | LOCK_NB); 
    if(rc) { 
     char *piderr = "PID file unlock failed!"; 
     fprintf(stderr, "%s\n", piderr); 
     printf(piderr); 
    } 
} 

void *workerFunction(void *arg) { 
    while (!shutdown) { 
     ... do stuff ... 
    } 
    return NULL; 
} 

int main(int argc, char *argv[]) { 
    //... 
    pthread_create(...,workerFunction,...); 
    pthread_join(...); 
    cleanup(); 
    return 0; 
} 
+0

I gestori di uscita possono essere chiamati in modo sincrono. Facendo così da un gestore di segnali invocato in modo asincrono farli correre come? – alk

+0

Giusto, non ho letto abbastanza attentamente la domanda. Credo che stavo rispondendo ad una domanda più basilare su come evitare le funzioni non sicure in un gestore di segnale. In questo caso, si vorrebbe sostituire exit() con qualcosa come l'impostazione di un flag di spegnimento. –

+0

questo è sbagliato; dovrebbe essere volatile sig_atomic_t –

4

flock() è generalmente async-signal-safe perché è una chiamata di sistema. La sua semantica rende difficile implementarla in modo diverso. Non è nella lista POSIX delle funzioni sicure del segnale asincrono perché non è affatto in POSIX.

Probabilmente non è necessario lo sblocco esplicito perché i blocchi flock() vengono rilasciati automaticamente quando tutti i descrittori di file che fanno riferimento alla descrizione del file aperto vengono chiusi.

Le chiamate printf() e fprintf() devono essere sostituite con le chiamate write() appropriate. Le funzioni stdio non sono nella lista delle funzioni sicure del segnale asincrono e sono spesso fortemente asincrone-segnale-non sicuro.

La chiamata abort() è probabilmente più sostituito impostando il segnale per l'azione di default e inviare nuovamente a sé; in questo modo, le shell sanno che il tuo programma è uscito a causa del segnale e possono abortire sequenze di comandi quando appropriato.

+0

Posso usare 'flock()' senza problemi nel gestore di sigaction? – MOHAMED

+0

Sì, ma come ho detto potrebbe non essere necessario. – jilles