2010-11-21 4 views
5

Cosa succede se un programma chiama una funzione che è un punto di cancellazione da un gestore di segnale? Ci sono un certo numero di funzioni che POSIX specifica sia come async-signal-safe che come punti di cancellazione. Se un gestore di segnale chiama tale funzione e la cancellazione viene applicata, il risultato è abbastanza simile a quello che succederebbe se il thread avesse abilitato la cancellazione asincrona - in realtà molto peggio, perché tutti i gestori di cancellazione cancellazione, che probabilmente non sono segnali asincroni- sicuro, sarebbe chiamato da un contesto di gestore del segnale.Punti di cancellazione nei gestori di segnale?

In questo caso, cosa specifica effettivamente POSIX e cosa fanno effettivamente le implementazioni? Non riesco a trovare alcun linguaggio in POSIX che impedisca l'esecuzione dei punti di cancellazione nei gestori di segnale, né alcuna protezione di questo tipo nella fonte glibc/nptl.

risposta

2

Non sono a conoscenza del fatto che POSIX abbia persino osato parlare di questo argomento, ma non ho fatto una ricerca esauriente.

Alcune brevi sperimentazioni con un sistema gcc/nptl rivelano che, come sospettavo e penso che lo faceste anche voi, non esiste una tale protezione in NPTL - i gestori di cancellazione vengono effettivamente chiamati, dal contesto del gestore di segnali.

Il seguente programma (scuse per la hackiness etc) visualizza il seguente output:

Signal handler called 
Sent cancellation 
Cleanup called 
In sighandler 

... indicano che:

  • il gestore di segnale stato chiamato
  • l'altro filo poi chiamato pthread_cancel()
  • il gestore di annullamento è stato chiamato, senza il gestore del segnale che completa

Ecco il programma:

#include <stdio.h> 
#include <pthread.h> 
#include <signal.h> 
#include <string.h> 
#include <unistd.h> 
#include <assert.h> 

pthread_t mainthread; 

int in_sighandler = 0; 

void 
cleanup (void *arg) 
{ 
    write(1, "Cleanup called\n", strlen("Cleanup called\n")); 
    if (in_sighandler) { 
     write(1, "In sighandler\n", strlen("In sighandler\n")); 
    } else { 
     write(1, "Not in sighandler\n", strlen("In sighandler\n")); 
    } 
} 


void 
sighandler (int sig, siginfo_t *siginfo, void *arg) 
{ 
    in_sighandler = 1; 
    write(1,"Signal handler called\n", strlen("Signal handler called\n")); // write() is a CP 
    usleep(3000000); // usleep() is a CP; not strictly async-signal-safe but happens to be so in Linux 
    write(1, "Signal handler exit\n", strlen("Signal handler exit\n")); 
    in_sighandler = 0; 
} 

void * 
thread (void *arg) 
{ 
    sleep(1); 
    pthread_kill(mainthread, SIGUSR1); 
    usleep(500000); 
    pthread_cancel(mainthread); 
    printf("Sent cancellation\n"); 
    return (NULL); 
} 

int 
main (int argc, char **argv) 
{ 
    int rc; 
    struct sigaction sa; 
    pthread_t threadid; 

    mainthread = pthread_self(); 

    // Set up a signal handler to test its cancellation properties 
    sa.sa_sigaction = &sighandler; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_SIGINFO; 
    rc = sigaction(SIGUSR1, &sa, NULL); 
    assert(rc == 0); 

    // Set up a thread to send us signals and cancel us 
    rc = pthread_create(&threadid, NULL, &thread, NULL); 
    assert(rc == 0); 

    // Set up cleanup handlers and loop forever 
    pthread_cleanup_push(&cleanup, NULL); 
    while (1) { 
     sleep(60); 
    } 
    pthread_cleanup_pop(0); 
    return (0); 
} 
+1

corto di qualsiasi risposta migliore in arrivo presto, io probabilmente accettare la vostra. Per quanto ne so, questo significa semplicemente che non puoi usare la cancellazione in un programma a meno che i tuoi gestori di segnale disabilitino la cancellazione o evitino di chiamare qualsiasi funzione che potrebbe essere un punto di cancellazione. Questo a sua volta, sfortunatamente, significa che il codice della libreria che utilizza i thread senza la consapevolezza/cooperazione del programma chiamante non può usare affatto la cancellazione (perché il programma chiamante potrebbe avere gestori di segnale di installazione); qualsiasi utilizzo potrebbe comportare condizioni di gara in cui il gestore del segnale viene cancellato. –

+2

Sì, è vero, anche se in senso stretto il gestore del segnale non può disabilitare la cancellazione (le funzioni pthread non sono sicure per il segnale asincrono). La libreria * potrebbe * bloccare * tutti * i segnali in qualsiasi thread che crea, ma non è l'ideale (specialmente dal momento che bloccare SIGRTMIN su Linux disabilita la cancellazione ...). Ho sempre pensato che la cancellazione fosse pericolosa - non è possibile chiamare alcuna funzione di libreria da una discussione cancellabile a meno che non si sia certi che la libreria è stata progettata pensando alla cancellazione (altrimenti potrebbe allocare risorse, chiamare una funzione di cancellazione, quindi mai liberare quelle risorse ...) – psmears

+0

Per quello che vale ho appena provato lo stesso programma su una macchina con Solaris 10, con gli stessi risultati ... Suppongo che questo significhi che, anche se ci sarà qualcosa in lo standard che rende questo sicuro, è inutile dal momento che le implementazioni più comuni non lo supportano: -/ – psmears