2010-08-24 17 views
5

Sto lavorando a una libreria in cui sto eseguendo varie attività su alcune librerie di terze parti che eseguono lavori relativamente specifici o pericolosi della piattaforma. (Nello specifico, sto scrivendo un parser di funzioni matematiche che chiama i compilatori JIT, come LLVM o libjit, per creare codice macchina.) In pratica, queste librerie di terze parti hanno la tendenza ad essere bloccate (parte di questo è colpa mia , certo, ma voglio ancora un po 'di assicurazione).Come isolare un lavoro/thread dagli arresti anomali

Mi piacerebbe, quindi, essere in grado di gestire con grazia un lavoro che sta morendo orribilmente - SIGSEGV, SIGILL, ecc. - senza far cadere il resto del mio codice (o il codice degli utenti che chiamano il mio funzioni della libreria). Per essere chiari, non mi interessa se quel particolare lavoro può continuare (non ho intenzione di provare a riparare una condizione di crash), né mi preoccupo veramente dello stato degli oggetti dopo un tale crash (scarterei li immediatamente se c'è un incidente). Voglio solo essere in grado di rilevare che si è verificato un arresto anomalo, interrompere il crash dall'eliminazione dell'intero processo, interrompere la chiamata a qualsiasi arresto anomalo e riprendere l'esecuzione.

(Per un po 'più di contesto, il codice in questo momento è un ciclo for, testare ciascuna delle JIT-compilatori disponibili. Alcuni di questi compilatori potrebbe bloccarsi. Se lo fanno, voglio solo per eseguire continue; e andare avanti con test di un altro compilatore.)

Attualmente, ho un'implementazione basata su signal() che fallisce in modo orribile; naturalmente, è un comportamento indefinito a longjmp() di un gestore di segnale e i gestori di segnale sono praticamente destinati a terminare con exit() o terminate(). Il solo lancio del codice in un'altra discussione non aiuta da solo, almeno per come l'ho provato finora. Non riesco anche a creare un modo per farlo funzionare usando le eccezioni C++.

Quindi, qual è il modo migliore per isolare un particolare set di istruzioni/thread/processo da arresti anomali?

risposta

10

Creare una nuova procedura.

+1

Questo è l'unico modo per farlo. Un thread può danneggiare la memoria ovunque nel processo, quindi dopo un SEGV, non è possibile garantire che la memoria non sia influenzata. – KeithB

+0

Grazie per l'heads-up. Quasi certamente la risposta giusta qui. Vado a leggere su fork() e compagnia. –

5

Che output raccogli quando un lavoro ha successo?

Chiedo perché se l'uscita è a larghezza di banda ridotta sarei tentato di eseguire ogni processo nel proprio processo.

Ognuno di questi lavori inattesi che si attivano ha un'alta probabilità di danneggiare la memoria utilizzata altrove nel processo.

I processi offrono la migliore protezione.

1

I processi offrono la migliore protezione, ma è possibile che non sia possibile farlo.

Se i punti di ingresso dei thread sono funzioni scritte (ad esempio, ThreadProc nel mondo Windows), è possibile raggrupparle nei blocchi try{...}catch(...). Se si desidera comunicare che si è verificata un'eccezione, è possibile comunicare codici di errore specifici al thread principale o utilizzare un altro meccanismo. Se si desidera registrare non solo l'esistenza di un'eccezione, ma l'eccezione, è necessario rilevare i tipi di eccezione specifici ed estrarre informazioni diagnostiche da essi per comunicare nuovamente al thread principale. 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; 
    } 
} 

essere consapevoli che se si va in questo modo si corre il rischio di getti del processo host quando si verificano le eccezioni. Dici che non stai cercando di correggere il problema, ma come fai a sapere che il thread maligno non ha mangiato il tuo stack, ad esempio? Catch-and-ignore è un ottimo modo per creare errori orribilmente confondenti.

0

Su Windows, è possibile utilizzare VirtualProtect(YourMemory, PAGE_READONLY) quando si chiama il codice non affidabile. Qualsiasi tentativo di modificare questa memoria causerebbe un'eccezione strutturata. Puoi tranquillamente prenderlo e continuare l'esecuzione. Tuttavia, la memoria allocata da quella libreria andrà ovviamente a fuga, così come altre risorse. L'equivalente Linux è mprotect(YorMemory, PROT_READ), che causa un SEGV.

Problemi correlati