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
119
120
121
122
123
124
125
use crate::{
application::{self, Application},
thread, FrameworkError,
FrameworkErrorKind::{SignalError, ThreadError},
};
use libc::c_int;
use signal_hook::iterator::Signals;
use std::{convert::TryFrom, fmt};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Signal {
Hup = 1,
Int = 2,
Pipe = 13,
Alrm = 14,
Term = 15,
Chld = 20,
Usr1 = 30,
Usr2 = 31,
}
impl Signal {
pub fn number(self) -> u32 {
self as u32
}
pub fn name(self) -> &'static str {
match self {
Signal::Hup => "SIGHUP",
Signal::Int => "SIGINT",
Signal::Pipe => "SIGPIPE",
Signal::Alrm => "SIGALRM",
Signal::Term => "SIGTERM",
Signal::Chld => "SIGCHLD",
Signal::Usr1 => "SIGUSR1",
Signal::Usr2 => "SIGUSR2",
}
}
}
impl fmt::Display for Signal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl TryFrom<u32> for Signal {
type Error = FrameworkError;
fn try_from(num: u32) -> Result<Signal, FrameworkError> {
Ok(match num {
1 => Signal::Hup,
2 => Signal::Int,
13 => Signal::Pipe,
14 => Signal::Alrm,
15 => Signal::Term,
20 => Signal::Chld,
30 => Signal::Usr1,
31 => Signal::Usr2,
other => fail!(SignalError, "unregistered signal number: {}", other),
})
}
}
pub fn register_handler<A, I>(
app_lock: &'static application::Lock<A>,
signals: I,
) -> Result<(), FrameworkError>
where
A: Application + Send + Sync,
I: IntoIterator<Item = Signal>,
{
let mut app = app_lock.write();
let thread_name = thread::Name::new("abscissa::signal");
let signals = Signals::new(signals.into_iter().map(|s| s.number() as c_int))
.map_err(|e| format_err!(ThreadError, "{}", e))?;
app.state_mut()
.threads
.spawn(&thread_name, move || handler_thread(app_lock, signals))
}
fn handler_thread<A>(app_lock: &'static application::Lock<A>, signals: Signals)
where
A: Application,
{
while !thread::should_terminate() {
for sig_num in &signals {
let sig = Signal::try_from(sig_num as u32).unwrap();
debug!("received signal: {}", sig);
let mut app = app_lock.write();
app.handle_signal(sig).unwrap_or_else(|e| {
status_err!("error handling signal: {}", e)
});
}
}
}