1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use std::cell::RefCell;
use std::panic::{self, AssertUnwindSafe, PanicInfo};
use std::sync::Once;
static INIT: Once = Once::new();
static mut DEFAULT_HOOK: Option<*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)> = None;
thread_local! {
static MUTED: RefCell<bool> = RefCell::new(false)
}
fn initialize() {
unsafe {
DEFAULT_HOOK = Some(Box::into_raw(panic::take_hook()));
panic::set_hook(Box::new(track_hook));
}
}
pub fn mute() {
INIT.call_once(initialize);
MUTED.with(|m| *m.borrow_mut() = true);
}
pub fn unmute() {
MUTED.with(|m| *m.borrow_mut() = false);
}
fn track_hook(p: &PanicInfo<'_>) {
MUTED.with(|m| {
if *m.borrow() {
return;
}
unsafe {
if let Some(hook) = DEFAULT_HOOK {
(*hook)(p);
}
}
});
}
pub fn recover_safe<F, R>(f: F) -> std::thread::Result<R>
where
F: FnOnce() -> R,
{
mute();
let res = panic::catch_unwind(AssertUnwindSafe(f));
unmute();
res
}