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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::cell::Cell;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic::{compiler_fence, Ordering};
use arr_macro::arr;
pub use libc::siginfo_t as SigInfo;
use libc::{c_int, c_void};
use nix::sys::signal;
pub use nix::sys::signal::{SaFlags, SigSet, Signal, SigAction, SigHandler};
pub use nix::Error;
thread_local!(static SIGNAL_HANDLERS: [Cell<Option<&'static dyn Fn(u8, &SigInfo)>>; 64] = arr![Cell::from(None); 64]);
extern "C" fn c_handler(signo: c_int, info: *mut SigInfo, _: *mut c_void) {
SIGNAL_HANDLERS.with(|handlers| {
if let Some(h) = handlers[signo as usize].get() {
if let Some(info) = unsafe { info.as_ref() } {
h(signo as u8, info)
}
}
});
}
struct HandlerGuard<'f, F: Fn(u8, &SigInfo) + 'f> {
signal: Signal,
handler: PhantomData<&'f F>,
old: Option<&'static dyn Fn(u8, &SigInfo)>,
}
impl<'f, F: Fn(u8, &SigInfo) + 'f> HandlerGuard<'f, F> {
fn install(signal: Signal, handler: &'f F) -> Self {
let old = SIGNAL_HANDLERS.with(|handlers| {
let fn_object = handler as &dyn Fn(u8, &SigInfo);
let static_fn = unsafe {
mem::transmute::<&'f dyn Fn(u8, &SigInfo), &'static dyn Fn(u8, &SigInfo)>(fn_object)
};
handlers[signal as usize].replace(Some(static_fn))
});
Self {
signal,
handler: Default::default(),
old,
}
}
}
impl<'f, F: Fn(u8, &SigInfo) + 'f> Drop for HandlerGuard<'f, F> {
fn drop(&mut self) {
let _mine = SIGNAL_HANDLERS
.with(|handlers| handlers[self.signal as usize].replace(self.old.take()));
}
}
pub struct SignalScope<F> {
handler: F,
signal: Signal,
flags: SaFlags,
set: SigSet,
after: Option<SigAction>
}
impl<Handler: Fn(u8, &SigInfo)> SignalScope<Handler> {
pub unsafe fn new(signal: Signal, flags: SaFlags, set: SigSet, handler: Handler) -> Self {
Self {
handler,
signal,
flags,
set,
after: None
}
}
pub fn run<T, F: FnOnce() -> T>(self, f: F) -> Result<T, Error> {
let action = SigHandler::SigAction(c_handler);
let sa = SigAction::new(action, self.flags, self.set);
let guard = HandlerGuard::install(self.signal, &self.handler);
let _old_handler = unsafe { signal::sigaction(self.signal, &sa)? };
compiler_fence(Ordering::SeqCst);
let ret = Ok(f());
compiler_fence(Ordering::SeqCst);
drop(guard);
ret
}
}