xref: /aosp_15_r20/external/crosvm/base/src/sys/linux/signalfd.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_int;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::AsRawFd;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::FromRawFd;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::RawFd;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::result;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker use libc::c_void;
14*bb4ee6a4SAndroid Build Coastguard Worker use libc::read;
15*bb4ee6a4SAndroid Build Coastguard Worker use libc::signalfd;
16*bb4ee6a4SAndroid Build Coastguard Worker use libc::signalfd_siginfo;
17*bb4ee6a4SAndroid Build Coastguard Worker use libc::EAGAIN;
18*bb4ee6a4SAndroid Build Coastguard Worker use libc::SFD_CLOEXEC;
19*bb4ee6a4SAndroid Build Coastguard Worker use libc::SFD_NONBLOCK;
20*bb4ee6a4SAndroid Build Coastguard Worker use log::error;
21*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
22*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
23*bb4ee6a4SAndroid Build Coastguard Worker 
24*bb4ee6a4SAndroid Build Coastguard Worker use super::signal;
25*bb4ee6a4SAndroid Build Coastguard Worker use super::Error as ErrnoError;
26*bb4ee6a4SAndroid Build Coastguard Worker use super::RawDescriptor;
27*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::AsRawDescriptor;
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
30*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
31*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
32*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to block the signal when creating signalfd.
33*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to block the signal when creating signalfd: {0}")]
34*bb4ee6a4SAndroid Build Coastguard Worker     CreateBlockSignal(signal::Error),
35*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to create a new signalfd.
36*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to create a new signalfd: {0}")]
37*bb4ee6a4SAndroid Build Coastguard Worker     CreateSignalFd(ErrnoError),
38*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to construct sigset when creating signalfd.
39*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to construct sigset when creating signalfd: {0}")]
40*bb4ee6a4SAndroid Build Coastguard Worker     CreateSigset(ErrnoError),
41*bb4ee6a4SAndroid Build Coastguard Worker     /// Signalfd could be read, but didn't return a full siginfo struct.
42*bb4ee6a4SAndroid Build Coastguard Worker     /// This wraps the number of bytes that were actually read.
43*bb4ee6a4SAndroid Build Coastguard Worker     #[error("signalfd failed to return a full siginfo struct, read only {0} bytes")]
44*bb4ee6a4SAndroid Build Coastguard Worker     SignalFdPartialRead(usize),
45*bb4ee6a4SAndroid Build Coastguard Worker     /// Unable to read from signalfd.
46*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to read from signalfd: {0}")]
47*bb4ee6a4SAndroid Build Coastguard Worker     SignalFdRead(ErrnoError),
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker 
50*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = result::Result<T, Error>;
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker /// A safe wrapper around a Linux signalfd (man 2 signalfd).
53*bb4ee6a4SAndroid Build Coastguard Worker ///
54*bb4ee6a4SAndroid Build Coastguard Worker /// A signalfd can be used for non-synchronous signals (such as SIGCHLD) so that
55*bb4ee6a4SAndroid Build Coastguard Worker /// signals can be processed without the use of a signal handler.
56*bb4ee6a4SAndroid Build Coastguard Worker pub struct SignalFd {
57*bb4ee6a4SAndroid Build Coastguard Worker     signalfd: File,
58*bb4ee6a4SAndroid Build Coastguard Worker     signal: c_int,
59*bb4ee6a4SAndroid Build Coastguard Worker }
60*bb4ee6a4SAndroid Build Coastguard Worker 
61*bb4ee6a4SAndroid Build Coastguard Worker impl SignalFd {
62*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new SignalFd for the given signal, blocking the normal handler
63*bb4ee6a4SAndroid Build Coastguard Worker     /// for the signal as well. Since we mask out the normal handler, this is
64*bb4ee6a4SAndroid Build Coastguard Worker     /// a risky operation - signal masking will persist across fork and even
65*bb4ee6a4SAndroid Build Coastguard Worker     /// **exec** so the user of SignalFd should think long and hard about
66*bb4ee6a4SAndroid Build Coastguard Worker     /// when to mask signals.
new(signal: c_int) -> Result<SignalFd>67*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(signal: c_int) -> Result<SignalFd> {
68*bb4ee6a4SAndroid Build Coastguard Worker         let sigset = signal::create_sigset(&[signal]).map_err(Error::CreateSigset)?;
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
71*bb4ee6a4SAndroid Build Coastguard Worker         // This is safe as we check the return value and know that fd is valid.
72*bb4ee6a4SAndroid Build Coastguard Worker         let fd = unsafe { signalfd(-1, &sigset, SFD_CLOEXEC | SFD_NONBLOCK) };
73*bb4ee6a4SAndroid Build Coastguard Worker         if fd < 0 {
74*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::CreateSignalFd(ErrnoError::last()));
75*bb4ee6a4SAndroid Build Coastguard Worker         }
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker         // Mask out the normal handler for the signal.
78*bb4ee6a4SAndroid Build Coastguard Worker         signal::block_signal(signal).map_err(Error::CreateBlockSignal)?;
79*bb4ee6a4SAndroid Build Coastguard Worker 
80*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
81*bb4ee6a4SAndroid Build Coastguard Worker         // This is safe because we checked fd for success and know the
82*bb4ee6a4SAndroid Build Coastguard Worker         // kernel gave us an fd that we own.
83*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
84*bb4ee6a4SAndroid Build Coastguard Worker             Ok(SignalFd {
85*bb4ee6a4SAndroid Build Coastguard Worker                 signalfd: File::from_raw_fd(fd),
86*bb4ee6a4SAndroid Build Coastguard Worker                 signal,
87*bb4ee6a4SAndroid Build Coastguard Worker             })
88*bb4ee6a4SAndroid Build Coastguard Worker         }
89*bb4ee6a4SAndroid Build Coastguard Worker     }
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker     /// Read a siginfo struct from the signalfd, if available.
read(&self) -> Result<Option<signalfd_siginfo>>92*bb4ee6a4SAndroid Build Coastguard Worker     pub fn read(&self) -> Result<Option<signalfd_siginfo>> {
93*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
94*bb4ee6a4SAndroid Build Coastguard Worker         // signalfd_siginfo doesn't have a default, so just zero it.
95*bb4ee6a4SAndroid Build Coastguard Worker         let mut siginfo: signalfd_siginfo = unsafe { mem::zeroed() };
96*bb4ee6a4SAndroid Build Coastguard Worker         let siginfo_size = mem::size_of::<signalfd_siginfo>();
97*bb4ee6a4SAndroid Build Coastguard Worker 
98*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
99*bb4ee6a4SAndroid Build Coastguard Worker         // This read is safe since we've got the space allocated for a
100*bb4ee6a4SAndroid Build Coastguard Worker         // single signalfd_siginfo, and that's exactly how much we're
101*bb4ee6a4SAndroid Build Coastguard Worker         // reading. Handling of EINTR is not required since SFD_NONBLOCK
102*bb4ee6a4SAndroid Build Coastguard Worker         // was specified. signalfds will always read in increments of
103*bb4ee6a4SAndroid Build Coastguard Worker         // sizeof(signalfd_siginfo); see man 2 signalfd.
104*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe {
105*bb4ee6a4SAndroid Build Coastguard Worker             read(
106*bb4ee6a4SAndroid Build Coastguard Worker                 self.signalfd.as_raw_fd(),
107*bb4ee6a4SAndroid Build Coastguard Worker                 &mut siginfo as *mut signalfd_siginfo as *mut c_void,
108*bb4ee6a4SAndroid Build Coastguard Worker                 siginfo_size,
109*bb4ee6a4SAndroid Build Coastguard Worker             )
110*bb4ee6a4SAndroid Build Coastguard Worker         };
111*bb4ee6a4SAndroid Build Coastguard Worker 
112*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
113*bb4ee6a4SAndroid Build Coastguard Worker             let err = ErrnoError::last();
114*bb4ee6a4SAndroid Build Coastguard Worker             if err.errno() == EAGAIN {
115*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(None)
116*bb4ee6a4SAndroid Build Coastguard Worker             } else {
117*bb4ee6a4SAndroid Build Coastguard Worker                 Err(Error::SignalFdRead(err))
118*bb4ee6a4SAndroid Build Coastguard Worker             }
119*bb4ee6a4SAndroid Build Coastguard Worker         } else if ret == (siginfo_size as isize) {
120*bb4ee6a4SAndroid Build Coastguard Worker             Ok(Some(siginfo))
121*bb4ee6a4SAndroid Build Coastguard Worker         } else {
122*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::SignalFdPartialRead(ret as usize))
123*bb4ee6a4SAndroid Build Coastguard Worker         }
124*bb4ee6a4SAndroid Build Coastguard Worker     }
125*bb4ee6a4SAndroid Build Coastguard Worker }
126*bb4ee6a4SAndroid Build Coastguard Worker 
127*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawFd for SignalFd {
as_raw_fd(&self) -> RawFd128*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_fd(&self) -> RawFd {
129*bb4ee6a4SAndroid Build Coastguard Worker         self.signalfd.as_raw_fd()
130*bb4ee6a4SAndroid Build Coastguard Worker     }
131*bb4ee6a4SAndroid Build Coastguard Worker }
132*bb4ee6a4SAndroid Build Coastguard Worker 
133*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for SignalFd {
as_raw_descriptor(&self) -> RawDescriptor134*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
135*bb4ee6a4SAndroid Build Coastguard Worker         self.signalfd.as_raw_descriptor()
136*bb4ee6a4SAndroid Build Coastguard Worker     }
137*bb4ee6a4SAndroid Build Coastguard Worker }
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for SignalFd {
drop(&mut self)140*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
141*bb4ee6a4SAndroid Build Coastguard Worker         // This is thread-safe and safe in the sense that we're doing what
142*bb4ee6a4SAndroid Build Coastguard Worker         // was promised - unmasking the signal when we go out of scope.
143*bb4ee6a4SAndroid Build Coastguard Worker         let res = signal::unblock_signal(self.signal);
144*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = res {
145*bb4ee6a4SAndroid Build Coastguard Worker             error!("signalfd failed to unblock signal {}: {}", self.signal, e);
146*bb4ee6a4SAndroid Build Coastguard Worker         }
147*bb4ee6a4SAndroid Build Coastguard Worker     }
148*bb4ee6a4SAndroid Build Coastguard Worker }
149*bb4ee6a4SAndroid Build Coastguard Worker 
150*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
151*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
152*bb4ee6a4SAndroid Build Coastguard Worker     use std::mem;
153*bb4ee6a4SAndroid Build Coastguard Worker     use std::ptr::null;
154*bb4ee6a4SAndroid Build Coastguard Worker 
155*bb4ee6a4SAndroid Build Coastguard Worker     use libc::pthread_sigmask;
156*bb4ee6a4SAndroid Build Coastguard Worker     use libc::raise;
157*bb4ee6a4SAndroid Build Coastguard Worker     use libc::sigismember;
158*bb4ee6a4SAndroid Build Coastguard Worker     use libc::sigset_t;
159*bb4ee6a4SAndroid Build Coastguard Worker 
160*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::signal::SIGRTMIN;
161*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
162*bb4ee6a4SAndroid Build Coastguard Worker 
163*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
new()164*bb4ee6a4SAndroid Build Coastguard Worker     fn new() {
165*bb4ee6a4SAndroid Build Coastguard Worker         SignalFd::new(SIGRTMIN()).unwrap();
166*bb4ee6a4SAndroid Build Coastguard Worker     }
167*bb4ee6a4SAndroid Build Coastguard Worker 
168*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
read()169*bb4ee6a4SAndroid Build Coastguard Worker     fn read() {
170*bb4ee6a4SAndroid Build Coastguard Worker         let sigid = SIGRTMIN() + 1;
171*bb4ee6a4SAndroid Build Coastguard Worker         let sigrt_fd = SignalFd::new(sigid).unwrap();
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: Safe because sigid is valid and return value is checked.
174*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { raise(sigid) };
175*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(ret, 0);
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker         let siginfo = sigrt_fd.read().unwrap().unwrap();
178*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(siginfo.ssi_signo, sigid as u32);
179*bb4ee6a4SAndroid Build Coastguard Worker     }
180*bb4ee6a4SAndroid Build Coastguard Worker 
181*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
drop()182*bb4ee6a4SAndroid Build Coastguard Worker     fn drop() {
183*bb4ee6a4SAndroid Build Coastguard Worker         let sigid = SIGRTMIN() + 2;
184*bb4ee6a4SAndroid Build Coastguard Worker 
185*bb4ee6a4SAndroid Build Coastguard Worker         let sigrt_fd = SignalFd::new(sigid).unwrap();
186*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: Safe because sigset and sigid are valid and return value is checked.
187*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
188*bb4ee6a4SAndroid Build Coastguard Worker             let mut sigset: sigset_t = mem::zeroed();
189*bb4ee6a4SAndroid Build Coastguard Worker             pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
190*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(sigismember(&sigset, sigid), 1);
191*bb4ee6a4SAndroid Build Coastguard Worker         }
192*bb4ee6a4SAndroid Build Coastguard Worker 
193*bb4ee6a4SAndroid Build Coastguard Worker         mem::drop(sigrt_fd);
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker         // The signal should no longer be masked.
196*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: Safe because sigset and sigid are valid and return value is checked.
197*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
198*bb4ee6a4SAndroid Build Coastguard Worker             let mut sigset: sigset_t = mem::zeroed();
199*bb4ee6a4SAndroid Build Coastguard Worker             pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
200*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(sigismember(&sigset, sigid), 0);
201*bb4ee6a4SAndroid Build Coastguard Worker         }
202*bb4ee6a4SAndroid Build Coastguard Worker     }
203*bb4ee6a4SAndroid Build Coastguard Worker }
204