2014-12-09 8 views
7

Sto lavorando su un Rust wrapper for the Duktape JavaScript interpreter. In un normale caso d'uso, lo stack di chiamate sarà simile al seguente:Cattura il panico! quando Rust ha chiamato da C FFI, senza generare i thread

  1. Ruggine: codice applicazione arbitrario.
  2. Rust: il mio wrapper della libreria.
  3. C: l'interprete Duktape.
  4. Rust: My Rust code.
  5. Rust: callback arbitrari nel codice dell'applicazione.

Cosa succede se (5) chiama panic!? Secondo vari sviluppatori di Rust su IRC, tentare di eseguire il panic! da callframes non-ruggine come (3) può comportare un comportamento indefinito.

Tuttavia, secondo la documentazione di Rust, l'unico modo per catturare uno panic! è l'utilizzo di std::task::try, che genera un thread aggiuntivo. C'è anche rustrt::unwind::try, che non può essere annidato due volte in un singolo thread, tra le altre restrizioni.

Una soluzione, proposta da Benjamin Herr, è interrompere il processo se il codice in (5) va in panico. Ho confezionato la sua soluzione come abort_on_panic, e sembra funzionare, per i valori di "lavoro" che includono "crash l'intero programma, ma le cose almeno non corrompere sottilmente":

abort_on_panic!("cannot panic inside this block", { 
    panic!("something went wrong!"); 
}); 

ma è un modo per emulare std::task::try senza l'overhead della creazione di thread/attività?

risposta

3

Non è possibile "prendere" uno panic!. Termina l'esecuzione del thread corrente. Pertanto, senza girare uno nuovo per isolare, sta andando a terminare la discussione si è in

+0

Grazie! È effettivamente necessario per 'std :: task :: try' per generare un nuovo thread del SO? Sembra che potrebbe essere implementato per salvare alcuni stati di runtime, richiamare il "task" nello stesso thread del sistema operativo e ripristinare lo stato di runtime al termine. Ciò manterrebbe la stessa API pubblica della versione corrente, ma potrebbe risparmiare il costo di chiamare 'pthread_new' tutto ciò che JavaScript chiama a Rust. – emk

+0

Questo è un po 'più alto di quello di Rust. –

5

È ora possibile utilizzare panic::recover per recuperare l'errore:.

let result = panic::recover(|| { 
    panic!("oh no!"); 
}); 
assert!(result.is_err()); 

Passing al successivo strato di ruggine è altrettanto facile:

panic::propagate(err); 

std::panic è molto probabilmente sarà stabile a Rust 1.9.0.

+0

Link a panic :: recover is broken. –

Problemi correlati