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