| 1 | //! Module with the self-pipe pattern. |
| 2 | //! |
| 3 | //! One of the common patterns around signals is to have a pipe with both ends in the same program. |
| 4 | //! Whenever there's a signal, the signal handler writes one byte of garbage data to the write end, |
| 5 | //! unless the pipe's already full. The application then can handle the read end. |
| 6 | //! |
| 7 | //! This has two advantages. First, the real signal action moves outside of the signal handler |
| 8 | //! where there are a lot less restrictions. Second, it fits nicely in all kinds of asynchronous |
| 9 | //! loops and has less chance of race conditions. |
| 10 | //! |
| 11 | //! This module offers premade functions for the write end (and doesn't insist that it must be a |
| 12 | //! pipe ‒ anything that can be written to is fine ‒ sockets too, therefore `UnixStream::pair` is a |
| 13 | //! good candidate). |
| 14 | //! |
| 15 | //! If you want to integrate with some asynchronous library, plugging streams from `mio-uds` or |
| 16 | //! `tokio-uds` libraries should work. |
| 17 | //! |
| 18 | //! If it looks too low-level for your needs, the [`iterator`][crate::iterator] module contains some |
| 19 | //! higher-lever interface that also uses a self-pipe pattern under the hood. |
| 20 | //! |
| 21 | //! # Correct order of handling |
| 22 | //! |
| 23 | //! A care needs to be taken to avoid race conditions, especially when handling the same signal in |
| 24 | //! a loop. Specifically, another signal might come when the action for the previous signal is |
| 25 | //! being taken. The correct order is first to clear the content of the pipe (read some/all data |
| 26 | //! from it) and then take the action. This way a spurious wakeup can happen (the pipe could wake |
| 27 | //! up even when no signal came after the signal was taken, because ‒ it arrived between cleaning |
| 28 | //! the pipe and taking the action). Note that some OS primitives (eg. `select`) suffer from |
| 29 | //! spurious wakeups themselves (they can claim a FD is readable when it is not true) and blocking |
| 30 | //! `read` might return prematurely (with eg. `EINTR`). |
| 31 | //! |
| 32 | //! The reverse order of first taking the action and then clearing the pipe might lose signals, |
| 33 | //! which is usually worse. |
| 34 | //! |
| 35 | //! This is not a problem with blocking on reading from the pipe (because both the blocking and |
| 36 | //! cleaning is the same action), but in case of asynchronous handling it matters. |
| 37 | //! |
| 38 | //! If you want to combine setting some flags with a self-pipe pattern, the flag needs to be set |
| 39 | //! first, then the pipe written. On the read end, first the pipe needs to be cleaned, then the |
| 40 | //! flag and then the action taken. This is what the [`SignalsInfo`][crate::iterator::SignalsInfo] |
| 41 | //! structure does internally. |
| 42 | //! |
| 43 | //! # Write collating |
| 44 | //! |
| 45 | //! While unlikely if handled correctly, it is possible the write end is full when a signal comes. |
| 46 | //! In such case the signal handler simply does nothing. If the write end is full, the read end is |
| 47 | //! readable and therefore will wake up. On the other hand, blocking in the signal handler would |
| 48 | //! definitely be a bad idea. |
| 49 | //! |
| 50 | //! However, this also means the number of bytes read from the end might be lower than the number |
| 51 | //! of signals that arrived. This should not generally be a problem, since the OS already collates |
| 52 | //! signals of the same kind together. |
| 53 | //! |
| 54 | //! # Examples |
| 55 | //! |
| 56 | //! This example waits for at last one `SIGUSR1` signal to come before continuing (and |
| 57 | //! terminating). It sends the signal to itself, so it correctly terminates. |
| 58 | //! |
| 59 | //! ```rust |
| 60 | //! use std::io::{Error, Read}; |
| 61 | //! use std::os::unix::net::UnixStream; |
| 62 | //! |
| 63 | //! use signal_hook::consts::SIGUSR1; |
| 64 | //! use signal_hook::low_level::{pipe, raise}; |
| 65 | //! |
| 66 | //! fn main() -> Result<(), Error> { |
| 67 | //! let (mut read, write) = UnixStream::pair()?; |
| 68 | //! pipe::register(SIGUSR1, write)?; |
| 69 | //! // This will write into the pipe write end through the signal handler |
| 70 | //! raise(SIGUSR1).unwrap(); |
| 71 | //! let mut buff = [0]; |
| 72 | //! read.read_exact(&mut buff)?; |
| 73 | //! println!("Happily terminating" ); |
| 74 | //! Ok(()) |
| 75 | //! } |
| 76 | |
| 77 | use std::io::{Error, ErrorKind}; |
| 78 | use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; |
| 79 | |
| 80 | use libc::{self, c_int}; |
| 81 | |
| 82 | use crate::SigId; |
| 83 | |
| 84 | #[cfg (target_os = "aix" )] |
| 85 | const MSG_NOWAIT: i32 = libc::MSG_NONBLOCK; |
| 86 | #[cfg (not(target_os = "aix" ))] |
| 87 | const MSG_NOWAIT: i32 = libc::MSG_DONTWAIT; |
| 88 | |
| 89 | #[derive (Copy, Clone)] |
| 90 | pub(crate) enum WakeMethod { |
| 91 | Send, |
| 92 | Write, |
| 93 | } |
| 94 | |
| 95 | struct WakeFd { |
| 96 | fd: RawFd, |
| 97 | method: WakeMethod, |
| 98 | } |
| 99 | |
| 100 | impl WakeFd { |
| 101 | /// Sets close on exec and nonblock on the inner file descriptor. |
| 102 | fn set_flags(&self) -> Result<(), Error> { |
| 103 | unsafe { |
| 104 | let flags: i32 = libc::fcntl(self.as_raw_fd(), cmd:libc::F_GETFL, 0); |
| 105 | if flags == -1 { |
| 106 | return Err(Error::last_os_error()); |
| 107 | } |
| 108 | let flags: i32 = flags | libc::O_NONBLOCK | libc::O_CLOEXEC; |
| 109 | if libc::fcntl(self.as_raw_fd(), cmd:libc::F_SETFL, flags) == -1 { |
| 110 | return Err(Error::last_os_error()); |
| 111 | } |
| 112 | } |
| 113 | Ok(()) |
| 114 | } |
| 115 | fn wake(&self) { |
| 116 | wake(self.fd, self.method); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | impl AsRawFd for WakeFd { |
| 121 | fn as_raw_fd(&self) -> RawFd { |
| 122 | self.fd |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | impl Drop for WakeFd { |
| 127 | fn drop(&mut self) { |
| 128 | unsafe { |
| 129 | libc::close(self.fd); |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | pub(crate) fn wake(pipe: RawFd, method: WakeMethod) { |
| 135 | unsafe { |
| 136 | // This writes some data into the pipe. |
| 137 | // |
| 138 | // There are two tricks: |
| 139 | // * First, the crazy cast. The first part turns reference into pointer. The second part |
| 140 | // turns pointer to u8 into a pointer to void, which is what write requires. |
| 141 | // * Second, we ignore errors, on purpose. We don't have any means to handling them. The |
| 142 | // two conceivable errors are EBADFD, if someone passes a non-existent file descriptor or |
| 143 | // if it is closed. The second is EAGAIN, in which case the pipe is full ‒ there were |
| 144 | // many signals, but the reader didn't have time to read the data yet. It'll still get |
| 145 | // woken up, so not fitting another letter in it is fine. |
| 146 | let data: *const c_void = b"X" as *const _ as *const _; |
| 147 | match method { |
| 148 | WakeMethod::Write => libc::write(fd:pipe, buf:data, count:1), |
| 149 | WakeMethod::Send => libc::send(socket:pipe, buf:data, len:1, MSG_NOWAIT), |
| 150 | }; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | /// Registers a write to a self-pipe whenever there's the signal. |
| 155 | /// |
| 156 | /// In this case, the pipe is taken as the `RawFd`. It'll be closed on deregistration. Effectively, |
| 157 | /// the function takes ownership of the file descriptor. This includes feeling free to set arbitrary |
| 158 | /// flags on it, including file status flags (that are shared across file descriptors created by |
| 159 | /// `dup`). |
| 160 | /// |
| 161 | /// Note that passing the wrong file descriptor won't cause UB, but can still lead to severe bugs ‒ |
| 162 | /// like data corruptions in files. Prefer using [`register`] if possible. |
| 163 | /// |
| 164 | /// Also, it is perfectly legal for multiple writes to be collated together (if not consumed) and |
| 165 | /// to generate spurious wakeups (but will not generate spurious *bytes* in the pipe). |
| 166 | /// |
| 167 | /// # Internal details |
| 168 | /// |
| 169 | /// Internally, it *currently* does following. Note that this is *not* part of the stability |
| 170 | /// guarantees and may change if necessary. |
| 171 | /// |
| 172 | /// * If the file descriptor can be used with [`send`][libc::send], it'll be used together with |
| 173 | /// [`MSG_DONTWAIT`][libc::MSG_DONTWAIT]. This is tested by sending `0` bytes of data (depending |
| 174 | /// on the socket type, this might wake the read end with an empty message). |
| 175 | /// * If it is not possible, the [`O_NONBLOCK`][libc::O_NONBLOCK] will be set on the file |
| 176 | /// descriptor and [`write`][libc::write] will be used instead. |
| 177 | pub fn register_raw(signal: c_int, pipe: RawFd) -> Result<SigId, Error> { |
| 178 | let res: isize = unsafe { libc::send(socket:pipe, &[] as *const _, len:0, MSG_NOWAIT) }; |
| 179 | let fd: WakeFd = match (res, Error::last_os_error().kind()) { |
| 180 | (0, _) | (-1, ErrorKind::WouldBlock) => WakeFd { |
| 181 | fd: pipe, |
| 182 | method: WakeMethod::Send, |
| 183 | }, |
| 184 | _ => { |
| 185 | let fd: WakeFd = WakeFd { |
| 186 | fd: pipe, |
| 187 | method: WakeMethod::Write, |
| 188 | }; |
| 189 | fd.set_flags()?; |
| 190 | fd |
| 191 | } |
| 192 | }; |
| 193 | let action: impl Fn() = move || fd.wake(); |
| 194 | unsafe { super::register(signal, action) } |
| 195 | } |
| 196 | |
| 197 | /// Registers a write to a self-pipe whenever there's the signal. |
| 198 | /// |
| 199 | /// The ownership of pipe is taken and will be closed whenever the created action is unregistered. |
| 200 | /// |
| 201 | /// Note that if you want to register the same pipe for multiple signals, there's `try_clone` |
| 202 | /// method on many unix socket primitives. |
| 203 | /// |
| 204 | /// See [`register_raw`] for further details. |
| 205 | pub fn register<P>(signal: c_int, pipe: P) -> Result<SigId, Error> |
| 206 | where |
| 207 | P: IntoRawFd + 'static, |
| 208 | { |
| 209 | register_raw(signal, pipe.into_raw_fd()) |
| 210 | } |
| 211 | |
| 212 | #[cfg (test)] |
| 213 | mod tests { |
| 214 | use std::io::Read; |
| 215 | use std::os::unix::net::{UnixDatagram, UnixStream}; |
| 216 | |
| 217 | use super::*; |
| 218 | |
| 219 | // Note: multiple tests share the SIGUSR1 signal. This is fine, we only need to know the signal |
| 220 | // arrives. It's OK to arrive multiple times, from multiple tests. |
| 221 | fn wakeup() { |
| 222 | crate::low_level::raise(libc::SIGUSR1).unwrap(); |
| 223 | } |
| 224 | |
| 225 | #[test ] |
| 226 | fn register_with_socket() -> Result<(), Error> { |
| 227 | let (mut read, write) = UnixStream::pair()?; |
| 228 | register(libc::SIGUSR1, write)?; |
| 229 | wakeup(); |
| 230 | let mut buff = [0; 1]; |
| 231 | read.read_exact(&mut buff)?; |
| 232 | assert_eq!(b"X" , &buff); |
| 233 | Ok(()) |
| 234 | } |
| 235 | |
| 236 | #[test ] |
| 237 | #[cfg (not(target_os = "haiku" ))] |
| 238 | fn register_dgram_socket() -> Result<(), Error> { |
| 239 | let (read, write) = UnixDatagram::pair()?; |
| 240 | register(libc::SIGUSR1, write)?; |
| 241 | wakeup(); |
| 242 | let mut buff = [0; 1]; |
| 243 | // The attempt to detect if it is socket can generate an empty message. Therefore, do a few |
| 244 | // retries. |
| 245 | for _ in 0..3 { |
| 246 | let len = read.recv(&mut buff)?; |
| 247 | if len == 1 && &buff == b"X" { |
| 248 | return Ok(()); |
| 249 | } |
| 250 | } |
| 251 | panic!("Haven't received the right data" ); |
| 252 | } |
| 253 | |
| 254 | #[test ] |
| 255 | fn register_with_pipe() -> Result<(), Error> { |
| 256 | let mut fds = [0; 2]; |
| 257 | unsafe { assert_eq!(0, libc::pipe(fds.as_mut_ptr())) }; |
| 258 | register_raw(libc::SIGUSR1, fds[1])?; |
| 259 | wakeup(); |
| 260 | let mut buff = [0; 1]; |
| 261 | unsafe { assert_eq!(1, libc::read(fds[0], buff.as_mut_ptr() as *mut _, 1)) } |
| 262 | assert_eq!(b"X" , &buff); |
| 263 | Ok(()) |
| 264 | } |
| 265 | } |
| 266 | |