base/sys/linux/
signalfd.rs1use std::fs::File;
6use std::mem;
7use std::os::raw::c_int;
8use std::os::unix::io::AsRawFd;
9use std::os::unix::io::FromRawFd;
10use std::os::unix::io::RawFd;
11use std::result;
12
13use libc::c_void;
14use libc::read;
15use libc::signalfd;
16use libc::signalfd_siginfo;
17use libc::EAGAIN;
18use libc::SFD_CLOEXEC;
19use libc::SFD_NONBLOCK;
20use log::error;
21use remain::sorted;
22use thiserror::Error;
23
24use super::signal;
25use super::Error as ErrnoError;
26use super::RawDescriptor;
27use crate::descriptor::AsRawDescriptor;
28
29#[sorted]
30#[derive(Error, Debug)]
31pub enum Error {
32 #[error("failed to block the signal when creating signalfd: {0}")]
34 CreateBlockSignal(signal::Error),
35 #[error("failed to create a new signalfd: {0}")]
37 CreateSignalFd(ErrnoError),
38 #[error("failed to construct sigset when creating signalfd: {0}")]
40 CreateSigset(ErrnoError),
41 #[error("signalfd failed to return a full siginfo struct, read only {0} bytes")]
44 SignalFdPartialRead(usize),
45 #[error("unable to read from signalfd: {0}")]
47 SignalFdRead(ErrnoError),
48}
49
50pub type Result<T> = result::Result<T, Error>;
51
52pub struct SignalFd {
57 signalfd: File,
58 signal: c_int,
59}
60
61impl SignalFd {
62 pub fn new(signal: c_int) -> Result<SignalFd> {
68 let sigset = signal::create_sigset(&[signal]).map_err(Error::CreateSigset)?;
69
70 let fd = unsafe { signalfd(-1, &sigset, SFD_CLOEXEC | SFD_NONBLOCK) };
73 if fd < 0 {
74 return Err(Error::CreateSignalFd(ErrnoError::last()));
75 }
76
77 signal::block_signal(signal).map_err(Error::CreateBlockSignal)?;
79
80 unsafe {
84 Ok(SignalFd {
85 signalfd: File::from_raw_fd(fd),
86 signal,
87 })
88 }
89 }
90
91 pub fn read(&self) -> Result<Option<signalfd_siginfo>> {
93 let mut siginfo: signalfd_siginfo = unsafe { mem::zeroed() };
96 let siginfo_size = mem::size_of::<signalfd_siginfo>();
97
98 let ret = unsafe {
105 read(
106 self.signalfd.as_raw_fd(),
107 &mut siginfo as *mut signalfd_siginfo as *mut c_void,
108 siginfo_size,
109 )
110 };
111
112 if ret < 0 {
113 let err = ErrnoError::last();
114 if err.errno() == EAGAIN {
115 Ok(None)
116 } else {
117 Err(Error::SignalFdRead(err))
118 }
119 } else if ret == (siginfo_size as isize) {
120 Ok(Some(siginfo))
121 } else {
122 Err(Error::SignalFdPartialRead(ret as usize))
123 }
124 }
125}
126
127impl AsRawFd for SignalFd {
128 fn as_raw_fd(&self) -> RawFd {
129 self.signalfd.as_raw_fd()
130 }
131}
132
133impl AsRawDescriptor for SignalFd {
134 fn as_raw_descriptor(&self) -> RawDescriptor {
135 self.signalfd.as_raw_descriptor()
136 }
137}
138
139impl Drop for SignalFd {
140 fn drop(&mut self) {
141 let res = signal::unblock_signal(self.signal);
144 if let Err(e) = res {
145 error!("signalfd failed to unblock signal {}: {}", self.signal, e);
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use std::mem;
153 use std::ptr::null;
154
155 use libc::pthread_sigmask;
156 use libc::raise;
157 use libc::sigismember;
158 use libc::sigset_t;
159
160 use super::super::signal::SIGRTMIN;
161 use super::*;
162
163 #[test]
164 fn new() {
165 SignalFd::new(SIGRTMIN()).unwrap();
166 }
167
168 #[test]
169 fn read() {
170 let sigid = SIGRTMIN() + 1;
171 let sigrt_fd = SignalFd::new(sigid).unwrap();
172
173 let ret = unsafe { raise(sigid) };
175 assert_eq!(ret, 0);
176
177 let siginfo = sigrt_fd.read().unwrap().unwrap();
178 assert_eq!(siginfo.ssi_signo, sigid as u32);
179 }
180
181 #[test]
182 fn drop() {
183 let sigid = SIGRTMIN() + 2;
184
185 let sigrt_fd = SignalFd::new(sigid).unwrap();
186 unsafe {
188 let mut sigset: sigset_t = mem::zeroed();
189 pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
190 assert_eq!(sigismember(&sigset, sigid), 1);
191 }
192
193 mem::drop(sigrt_fd);
194
195 unsafe {
198 let mut sigset: sigset_t = mem::zeroed();
199 pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
200 assert_eq!(sigismember(&sigset, sigid), 0);
201 }
202 }
203}