2010-11-21 3 views
5

Was passiert, wenn ein Programm eine Funktion aufruft, bei der es sich um einen Abbruchpunkt von einem Signalhandler handelt? Es gibt eine Reihe von Funktionen, die POSIX sowohl als async-signalsichere als auch als Cancel-Punkte spezifiziert. Wenn ein Signal-Handler eine solche Funktion aufruft und die Annullierung durchgeführt wird, ist das Ergebnis ziemlich ähnlich dem, was passieren würde, wenn der Thread asynchrone Auslöschung aktiviert hätte - tatsächlich viel schlechter, weil alle Stornierungs-Bereinigungshandler, die wahrscheinlich kein asynchrones Signal sind, sicher, würde von einem Signal-Handler-Kontext aufgerufen werden.Abbruchpunkte in Signalhandlern?

Was bedeutet POSIX in diesem Fall eigentlich und was machen Implementierungen eigentlich? Ich kann keine Sprache in POSIX finden, die das Unterdrücken von Abbruchpunkten in Signalhandlern oder einen solchen Schutz in der glibc/nptl-Quelle verbieten würde.

Antwort

2

Mir ist nicht bewusst, dass POSIX es sogar wagt, dieses Thema zu erwähnen, aber ich habe keine erschöpfende Suche durchgeführt.

Einige kurze Experimente mit einem gcc/nptl-System zeigen, dass, wie ich vermutete und ich denke, dass Sie es auch getan haben, gibt es keinen solchen Schutz in NPTL - die Cancellation-Handler werden tatsächlich aufgerufen, aus dem Signal-Handler-Kontext.

Das folgende Programm (Leider für die hackiness etc) zeigt die folgende Ausgabe:

Signal handler called 
Sent cancellation 
Cleanup called 
In sighandler 

... anzeigt, dass:

  • die Signalbehandlungsroutine dann
  • der andere Thread aufgerufen wurde pthread_cancel()
  • wurde der Abbruchbehandler aufgerufen, ohne dass der Signalhandler
  • abgeschlossen hat

Hier ist das Programm:

#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

Kurzirgend bessere Antwort in Kürze, ich wahrscheinlich bei Ihnen akzeptieren werde. Soweit ich das beurteilen kann, bedeutet das im Grunde genommen nur, dass Sie die Löschung in einem Programm nicht verwenden können, es sei denn, Ihre Signalhandler deaktivieren die Löschung selbst oder vermeiden es, eine Funktion aufzurufen, die ein Abbruchpunkt sein könnte. Dies wiederum bedeutet unglücklicherweise, dass Bibliothekscode, der Threads verwendet, ohne dass das aufrufende Programm die Aufmerksamkeit/Kooperation hat, überhaupt keine Löschung verwenden kann (weil das aufrufende Programm möglicherweise Signalverarbeitungsroutinen eingerichtet hat); Jede Verwendung könnte zu Rennbedingungen führen, bei denen der Signal-Handler abgebrochen wird. –

+2

Ja, das stimmt - streng genommen kann der Signal-Handler die Löschung jedoch nicht deaktivieren (die pthread-Funktionen sind nicht async-signal-sicher). Die Bibliothek * könnte * alle * Signale in beliebigen Threads blockieren, die sie erzeugt, aber das ist nicht ideal (zumal das Blockieren von SIGRTMIN unter Linux die Löschung deaktiviert ...). Ich habe immer gedacht, dass die Löschung gefährlich ist - Sie können keine Bibliotheksfunktionen aus einem abbrechbaren Thread aufrufen, es sei denn, Sie sind sicher, dass die Bibliothek unter Berücksichtigung von Stornierungen konzipiert wurde (andernfalls könnte sie Ressourcen zuweisen, eine Abbruchfunktion aufrufen und dann nie befreie diese Ressourcen ...) – psmears

+0

Für was es wert ist Ich habe gerade das gleiche Programm auf einer Maschine mit Solaris 10 versucht, mit den gleichen Ergebnissen ... Ich denke, das bedeutet, dass, selbst wenn sich herausstellt, etwas in sein Der Standard, der das sicher macht, ist nutzlos, da die gängigsten Implementierungen es nicht unterstützen: -/ – psmears