punti di annullamento in gestori di segnale?
-
26-09-2019 - |
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.
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);
}