Question

Qu'est-ce qui se passe si un programme appelle une fonction qui est un point d'annulation d'un gestionnaire de signal? Il y a un certain nombre de fonctions qui spécifie que les deux POSIX points de signal-async de sécurité et d'annulation. Si un gestionnaire de signal appelle une telle fonction et l'annulation est sollicité, le résultat est tout à fait semblable à ce qui se passerait si le fil avait permis l'annulation asynchrone - bien pire, parce que tous les gestionnaires de nettoyage d'annulation, qui ne sont probablement pas async-SIGNAL sûr, serait appelé à partir d'un contexte signal gestionnaire.

Qu'est-ce que fait préciser Posix dans ce cas, et qu'est-ce que les mises en œuvre font réellement? Je ne peux trouver aucune langue POSIX qui interdit les points d'annulation dans les gestionnaires de signaux d'agir conformément à, ni une telle protection dans la glibc / nptl la source.

Était-ce utile?

La solution

Je ne suis pas au courant que ose même Posix mentionner ce sujet, mais je ne l'ai pas fait une recherche exhaustive.

Quelques brèves expériences avec un système de gcc / nptl révèle que, comme je doutais et je pense que vous aussi, il n'y a pas une telle protection dans NPTL -. Les gestionnaires d'annulation ne s'appellent en effet, à partir du contexte du gestionnaire de signaux

Le programme ci-dessous (excuses pour le hackiness etc) affiche la sortie suivante:

Signal handler called
Sent cancellation
Cleanup called
In sighandler

... ce qui indique que:

  • le gestionnaire de signaux été appelé
  • l'autre thread alors appelé pthread_cancel()
  • le gestionnaire d'annulation puis s'appelé, sans le gestionnaire de signal terminé

Voici le programme:

#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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top