Domanda

Che cosa accade 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 punti async-signal-safe e cancellazione. Se un gestore di segnale chiama tale funzione una e l'annullamento sia accolta, il risultato è molto simile a quello che sarebbe successo se il filo aveva permesso cancellazione asincrona - in realtà molto peggio, perché tutte le funzioni di pulizia di annullamento, che sono probabilmente non async-segnale- cassetta di sicurezza, sarebbe stato chiamato da un contesto segnale gestore.

Che cosa significa in realtà POSIX specifica in questo caso, e che cosa implementazioni effettivamente fare? Non riesco a trovare alcuna lingua in POSIX che vietare i punti di cancellazione a gestori di segnale di essere agito su, né tale protezione nella glibc / NPTL fonte.

È stato utile?

Soluzione

Io non sono consapevoli del fatto che POSIX osa persino parlare di questo argomento, ma non ho fatto una ricerca esaustiva.

Alcuni breve la sperimentazione di un sistema di gcc / nptl rivela che, come sospettavo e penso che hai fatto troppo, non v'è alcuna protezione NPTL -. I gestori di annullamento effettivamente vengono chiamati, all'interno del contesto gestore di segnale

Il seguente programma (scuse per l'hackiness etc) il seguente output:

Signal handler called
Sent cancellation
Cleanup called
In sighandler

... che indica che:

  • il gestore di segnale stato chiamato
  • l'altro thread poi chiamato pthread_cancel()
  • il gestore cancellazione poi si è chiamato, senza che il conduttore di segnale completato

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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top