2010-11-21 16 views
5

¿Qué sucede si un programa llama a una función que es un punto de cancelación de un manejador de señal? Hay una serie de funciones que POSIX especifica como puntos de cancelación y señal de señal asíncrona. Si un manejador de señal llama a dicha función y se actúa sobre la cancelación, el resultado es bastante similar a lo que sucedería si el hilo hubiera habilitado la cancelación asíncrona, en realidad mucho peor, porque todos los controladores de limpieza de cancelación, que probablemente no son de señal asíncrona seguro, se llamaría desde un contexto de controlador de señal.¿Puntos de cancelación en controladores de señal?

¿Qué especifica POSIX realmente en este caso, y qué hacen realmente las implementaciones? No puedo encontrar ningún lenguaje en POSIX que prohíba que se actúe sobre los puntos de cancelación en los manejadores de señal, ni ninguna protección en la fuente glibc/nptl.

Respuesta

2

No soy consciente de que POSIX incluso se atreve a mencionar este tema, pero no he hecho una búsqueda exhaustiva.

Algunos experimentos breves con un sistema gcc/nptl revelan que, como sospechaba y creo que tú también, no existe tal protección en NPTL: los controladores de cancelación son llamados desde el contexto del controlador de señal.

El programa siguiente (disculpas por la hackiness etc) muestra el resultado siguiente:

Signal handler called 
Sent cancellation 
Cleanup called 
In sighandler 

... que indican que:

  • el manejador de la señal fue llamado
  • el otro hilo a continuación, llamado pthread_cancel()
  • se llamó al controlador de cancelación, sin que el manejador de señal haya completado

Aquí está el programa:

#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 de cualquier respuesta mejor venir en breve, probablemente va a aceptar la suya. Por lo que puedo decir, esto básicamente significa que no puede usar la cancelación en un programa a menos que sus controladores de señal deshabiliten la cancelación ellos mismos o eviten llamar a cualquier función que pueda ser un punto de cancelación. Esto, a su vez, desafortunadamente significa que el código de la biblioteca que utiliza hilos sin la concientización/cooperación del programa llamante no puede usar la cancelación en absoluto (porque el programa llamante podría tener manejadores de señal de configuración); cualquier uso puede dar como resultado condiciones de carrera en las que el manejador de señales se cancela. –

+2

Sí, eso es correcto, aunque estrictamente hablando, el manejador de señal no puede deshabilitar la cancelación (las funciones pthread no son seguras para señales asíncronas). La biblioteca * podría * bloquear * todas las señales * en cualquier conversación que cree, pero eso no es lo ideal (especialmente porque el bloqueo de SIGRTMIN en Linux desactiva la cancelación ...). Siempre pensé que la cancelación era peligrosa: no se puede llamar a ninguna función de la biblioteca desde un hilo cancelable a menos que esté seguro de que la biblioteca se diseñó teniendo en cuenta la cancelación (o podría asignar recursos, llamar a una función de cancelación de puntos, nunca liberar esos recursos ...) – psmears

+0

Por lo que vale, acabo de probar el mismo programa en una máquina que ejecuta Solaris 10, con los mismos resultados ... Supongo que eso significa que, incluso si llega a haber algo en el estándar lo hace seguro, es inútil ya que las implementaciones más comunes no lo admiten: -/ – psmears

Cuestiones relacionadas