-
Notifications
You must be signed in to change notification settings - Fork 532
/
Copy pathsignals.rs
122 lines (101 loc) · 2.68 KB
/
signals.rs
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
use {
super::*,
nix::{
errno::Errno,
sys::signal::{SaFlags, SigAction, SigHandler, SigSet},
},
std::{
fs::File,
os::fd::{BorrowedFd, IntoRawFd},
sync::atomic::{self, AtomicI32},
},
};
const INVALID_FILENO: i32 = -1;
static WRITE: AtomicI32 = AtomicI32::new(INVALID_FILENO);
fn die(message: &str) -> ! {
// SAFETY:
//
// Standard error is open for the duration of the program.
const STDERR: BorrowedFd = unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) };
let mut i = 0;
let mut buffer = [0; 512];
let mut append = |s: &str| {
let remaining = buffer.len() - i;
let n = s.len().min(remaining);
let end = i + n;
buffer[i..end].copy_from_slice(&s.as_bytes()[0..n]);
i = end;
};
append("error: ");
append(message);
append("\n");
nix::unistd::write(STDERR, &buffer[0..i]).ok();
process::abort();
}
extern "C" fn handler(signal: libc::c_int) {
let errno = Errno::last();
let Ok(signal) = u8::try_from(signal) else {
die("unexpected signal");
};
// SAFETY:
//
// `WRITE` is initialized before the signal handler can run and remains open
// for the duration of the program.
let fd = unsafe { BorrowedFd::borrow_raw(WRITE.load(atomic::Ordering::Relaxed)) };
if let Err(err) = nix::unistd::write(fd, &[signal]) {
die(err.desc());
}
errno.set();
}
pub(crate) struct Signals(File);
impl Signals {
pub(crate) fn new() -> RunResult<'static, Self> {
let (read, write) = nix::unistd::pipe().map_err(|errno| Error::SignalHandlerPipeOpen {
io_error: errno.into(),
})?;
if WRITE
.compare_exchange(
INVALID_FILENO,
write.into_raw_fd(),
atomic::Ordering::Relaxed,
atomic::Ordering::Relaxed,
)
.is_err()
{
panic!("signal iterator cannot be initialized twice");
}
let sa = SigAction::new(
SigHandler::Handler(handler),
SaFlags::SA_RESTART,
SigSet::empty(),
);
for &signal in Signal::ALL {
// SAFETY:
//
// This is the only place we modify signal handlers, and
// `nix::sys::signal::sigaction` is unsafe only if an invalid signal
// handler has already been installed.
unsafe {
nix::sys::signal::sigaction(signal.into(), &sa).map_err(|errno| {
Error::SignalHandlerSigaction {
signal,
io_error: errno.into(),
}
})?;
}
}
Ok(Self(File::from(read)))
}
}
impl Iterator for Signals {
type Item = io::Result<Signal>;
fn next(&mut self) -> Option<Self::Item> {
let mut signal = [0];
Some(
self
.0
.read_exact(&mut signal)
.and_then(|()| Signal::try_from(signal[0])),
)
}
}