2010-08-24 9 views
5

Estoy trabajando en una biblioteca donde realizo diversas tareas en algunas bibliotecas de terceros que realizan trabajos poco detallados o peligrosos específicos de la plataforma. (Específicamente, estoy escribiendo un analizador sintáctico de funciones que llama a los compiladores JIT, como LLVM o libjit, para construir código de máquina.) En la práctica, estas bibliotecas de terceros tienden a ser un desastre (parte de esto es culpa mía , por supuesto, pero aún quiero un seguro).Cómo aislar un trabajo/subproceso de bloqueos

Me gustaría, entonces, poder tratar con gracia un trabajo que muere horriblemente - SIGSEGV, SIGILL, etc. - sin desglosar el resto de mi código (o el código de los usuarios que llaman a mi funciones de biblioteca). Para ser claro, no me importa si ese trabajo en particular puede continuar (no voy a tratar de reparar una condición de falla), ni me importa realmente el estado de los objetos después de un choque (lo descartaré). ellos inmediatamente si hay un choque). Solo quiero ser capaz de detectar que se ha producido un bloqueo, detener el bloqueo de todo el proceso, dejar de llamar a lo que sea que esté cayendo y reanudar la ejecución.

(Para un poco más de contexto, el código en este momento es un bucle for, probando cada uno de los compiladores JIT disponibles. Algunos de estos compiladores pueden fallar. Si lo hacen, solo quiero ejecutar continue; y continuar con la prueba de otro compilador.)

Actualmente, tengo una implementación basada en signal() que falla bastante horriblemente; por supuesto, es un comportamiento indefinido a longjmp() de un manejador de señal, y se espera que los controladores de señal terminen con exit() o terminate(). Solo arrojar el código en otro hilo no ayuda por sí solo, al menos como lo he probado hasta ahora. Tampoco puedo hackear una forma de hacer que esto funcione usando excepciones de C++.

Entonces, ¿cuál es la mejor manera de aislar un conjunto particular de instrucciones/hilo/trabajo de fallas?

Respuesta

10

Genera un nuevo proceso.

+1

Esta es la única forma de hacerlo. Un hilo puede dañar la memoria en cualquier parte del proceso, por lo que después de un SEGV, no puede garantizar que su memoria no se vea afectada. – KeithB

+0

Gracias por el aviso. Casi con certeza la respuesta correcta aquí. Me voy a leer en fork() y compañía. –

5

¿Qué salida recolectas cuando un trabajo tiene éxito?

Pregunto porque si el resultado es un ancho de banda bajo, estaría tentado de ejecutar cada trabajo en su propio proceso.

Cada uno de estos trabajos accidentados que se activan tiene una alta probabilidad de dañar la memoria utilizada en cualquier otro lugar de su proceso.

Los procesos ofrecen la mejor protección.

1

Los procesos ofrecen la mejor protección, pero es posible que no pueda hacer eso.

Si los puntos de entrada de sus hilos son funciones que escribió, (por ejemplo, ThreadProc en el mundo de Windows), puede envolverlos en bloques try{...}catch(...). Si desea comunicar que se ha producido una excepción, puede volver a comunicar los códigos de error específicos al hilo principal o utilizar algún otro mecanismo. Si desea registrar no solo que se ha producido una excepción, sino también la excepción, deberá detectar tipos de excepción específicos y extraer información de diagnóstico de ellos para comunicarse de nuevo con el hilo principal. A'la:

int my_tempermental_thread() 
{ 
    try 
    { 
    // ... magic happens ... 
    return 0; 
    } 
    catch(const std::exception& ex) 
    { 
    // ... or maybe it doesn't ... 
    string reason = ex.what(); 
    tell_main_thread_what_went_wong(reason); 
    return 1; 
    } 
    catch(...) 
    { 
    // ... definitely not magical happenings here ... 
    tell_main_thread_what_went_wrong("uh, something bad and undefined"); 
    return 2; 
    } 
} 

en cuenta que si usted va esta manera se corre el riesgo de regar el proceso de host cuando se producen las excepciones. Usted dice que no está tratando de corregir el problema, pero ¿cómo sabe que el hilo maligno no se comió su pila, por ejemplo? Catch-and-ignore es una gran manera de crear errores horriblemente confusos.

0

En Windows, es posible que pueda utilizar VirtualProtect(YourMemory, PAGE_READONLY) al llamar al código que no es de confianza. Cualquier intento de modificar esta memoria causaría una excepción estructurada. Puede atrapar esto de forma segura y continuar la ejecución. Sin embargo, la memoria asignada por esa biblioteca, por supuesto, tendrá fugas, al igual que otros recursos. El equivalente de Linux es mprotect(YorMemory, PROT_READ), lo que causa un SEGV.

Cuestiones relacionadas