1 //! Unix-specific types for signal handling.
2 //!
3 //! This module is only defined on Unix platforms and contains the primary
4 //! `Signal` type for receiving notifications of signals.
5 
6 #![cfg(unix)]
7 #![cfg_attr(docsrs, doc(cfg(all(unix, feature = "signal"))))]
8 
9 use crate::signal::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
10 use crate::signal::RxFuture;
11 use crate::sync::watch;
12 
13 use mio::net::UnixStream;
14 use std::io::{self, Error, ErrorKind, Write};
15 use std::pin::Pin;
16 use std::sync::atomic::{AtomicBool, Ordering};
17 use std::sync::Once;
18 use std::task::{Context, Poll};
19 
20 pub(crate) mod driver;
21 use self::driver::Handle;
22 
23 pub(crate) type OsStorage = Vec<SignalInfo>;
24 
25 // Number of different unix signals
26 // (FreeBSD has 33)
27 const SIGNUM: usize = 33;
28 
29 impl Init for OsStorage {
init() -> Self30     fn init() -> Self {
31         (0..SIGNUM).map(|_| SignalInfo::default()).collect()
32     }
33 }
34 
35 impl Storage for OsStorage {
event_info(&self, id: EventId) -> Option<&EventInfo>36     fn event_info(&self, id: EventId) -> Option<&EventInfo> {
37         self.get(id).map(|si| &si.event_info)
38     }
39 
for_each<'a, F>(&'a self, f: F) where F: FnMut(&'a EventInfo),40     fn for_each<'a, F>(&'a self, f: F)
41     where
42         F: FnMut(&'a EventInfo),
43     {
44         self.iter().map(|si| &si.event_info).for_each(f)
45     }
46 }
47 
48 #[derive(Debug)]
49 pub(crate) struct OsExtraData {
50     sender: UnixStream,
51     receiver: UnixStream,
52 }
53 
54 impl Init for OsExtraData {
init() -> Self55     fn init() -> Self {
56         let (receiver, sender) = UnixStream::pair().expect("failed to create UnixStream");
57 
58         Self { sender, receiver }
59     }
60 }
61 
62 /// Represents the specific kind of signal to listen for.
63 #[derive(Debug, Clone, Copy)]
64 pub struct SignalKind(libc::c_int);
65 
66 impl SignalKind {
67     /// Allows for listening to any valid OS signal.
68     ///
69     /// For example, this can be used for listening for platform-specific
70     /// signals.
71     /// ```rust,no_run
72     /// # use tokio::signal::unix::SignalKind;
73     /// # let signum = -1;
74     /// // let signum = libc::OS_SPECIFIC_SIGNAL;
75     /// let kind = SignalKind::from_raw(signum);
76     /// ```
77     // Use `std::os::raw::c_int` on public API to prevent leaking a non-stable
78     // type alias from libc.
79     // `libc::c_int` and `std::os::raw::c_int` are currently the same type, and are
80     // unlikely to change to other types, but technically libc can change this
81     // in the future minor version.
82     // See https://github.com/tokio-rs/tokio/issues/3767 for more.
from_raw(signum: std::os::raw::c_int) -> Self83     pub fn from_raw(signum: std::os::raw::c_int) -> Self {
84         Self(signum as libc::c_int)
85     }
86 
87     /// Represents the SIGALRM signal.
88     ///
89     /// On Unix systems this signal is sent when a real-time timer has expired.
90     /// By default, the process is terminated by this signal.
alarm() -> Self91     pub fn alarm() -> Self {
92         Self(libc::SIGALRM)
93     }
94 
95     /// Represents the SIGCHLD signal.
96     ///
97     /// On Unix systems this signal is sent when the status of a child process
98     /// has changed. By default, this signal is ignored.
child() -> Self99     pub fn child() -> Self {
100         Self(libc::SIGCHLD)
101     }
102 
103     /// Represents the SIGHUP signal.
104     ///
105     /// On Unix systems this signal is sent when the terminal is disconnected.
106     /// By default, the process is terminated by this signal.
hangup() -> Self107     pub fn hangup() -> Self {
108         Self(libc::SIGHUP)
109     }
110 
111     /// Represents the SIGINFO signal.
112     ///
113     /// On Unix systems this signal is sent to request a status update from the
114     /// process. By default, this signal is ignored.
115     #[cfg(any(
116         target_os = "dragonfly",
117         target_os = "freebsd",
118         target_os = "macos",
119         target_os = "netbsd",
120         target_os = "openbsd"
121     ))]
info() -> Self122     pub fn info() -> Self {
123         Self(libc::SIGINFO)
124     }
125 
126     /// Represents the SIGINT signal.
127     ///
128     /// On Unix systems this signal is sent to interrupt a program.
129     /// By default, the process is terminated by this signal.
interrupt() -> Self130     pub fn interrupt() -> Self {
131         Self(libc::SIGINT)
132     }
133 
134     /// Represents the SIGIO signal.
135     ///
136     /// On Unix systems this signal is sent when I/O operations are possible
137     /// on some file descriptor. By default, this signal is ignored.
io() -> Self138     pub fn io() -> Self {
139         Self(libc::SIGIO)
140     }
141 
142     /// Represents the SIGPIPE signal.
143     ///
144     /// On Unix systems this signal is sent when the process attempts to write
145     /// to a pipe which has no reader. By default, the process is terminated by
146     /// this signal.
pipe() -> Self147     pub fn pipe() -> Self {
148         Self(libc::SIGPIPE)
149     }
150 
151     /// Represents the SIGQUIT signal.
152     ///
153     /// On Unix systems this signal is sent to issue a shutdown of the
154     /// process, after which the OS will dump the process core.
155     /// By default, the process is terminated by this signal.
quit() -> Self156     pub fn quit() -> Self {
157         Self(libc::SIGQUIT)
158     }
159 
160     /// Represents the SIGTERM signal.
161     ///
162     /// On Unix systems this signal is sent to issue a shutdown of the
163     /// process. By default, the process is terminated by this signal.
terminate() -> Self164     pub fn terminate() -> Self {
165         Self(libc::SIGTERM)
166     }
167 
168     /// Represents the SIGUSR1 signal.
169     ///
170     /// On Unix systems this is a user defined signal.
171     /// By default, the process is terminated by this signal.
user_defined1() -> Self172     pub fn user_defined1() -> Self {
173         Self(libc::SIGUSR1)
174     }
175 
176     /// Represents the SIGUSR2 signal.
177     ///
178     /// On Unix systems this is a user defined signal.
179     /// By default, the process is terminated by this signal.
user_defined2() -> Self180     pub fn user_defined2() -> Self {
181         Self(libc::SIGUSR2)
182     }
183 
184     /// Represents the SIGWINCH signal.
185     ///
186     /// On Unix systems this signal is sent when the terminal window is resized.
187     /// By default, this signal is ignored.
window_change() -> Self188     pub fn window_change() -> Self {
189         Self(libc::SIGWINCH)
190     }
191 }
192 
193 pub(crate) struct SignalInfo {
194     event_info: EventInfo,
195     init: Once,
196     initialized: AtomicBool,
197 }
198 
199 impl Default for SignalInfo {
default() -> SignalInfo200     fn default() -> SignalInfo {
201         SignalInfo {
202             event_info: Default::default(),
203             init: Once::new(),
204             initialized: AtomicBool::new(false),
205         }
206     }
207 }
208 
209 /// Our global signal handler for all signals registered by this module.
210 ///
211 /// The purpose of this signal handler is to primarily:
212 ///
213 /// 1. Flag that our specific signal was received (e.g. store an atomic flag)
214 /// 2. Wake up the driver by writing a byte to a pipe
215 ///
216 /// Those two operations should both be async-signal safe.
action(globals: Pin<&'static Globals>, signal: libc::c_int)217 fn action(globals: Pin<&'static Globals>, signal: libc::c_int) {
218     globals.record_event(signal as EventId);
219 
220     // Send a wakeup, ignore any errors (anything reasonably possible is
221     // full pipe and then it will wake up anyway).
222     let mut sender = &globals.sender;
223     drop(sender.write(&[1]));
224 }
225 
226 /// Enables this module to receive signal notifications for the `signal`
227 /// provided.
228 ///
229 /// This will register the signal handler if it hasn't already been registered,
230 /// returning any error along the way if that fails.
signal_enable(signal: SignalKind, handle: &Handle) -> io::Result<()>231 fn signal_enable(signal: SignalKind, handle: &Handle) -> io::Result<()> {
232     let signal = signal.0;
233     if signal < 0 || signal_hook_registry::FORBIDDEN.contains(&signal) {
234         return Err(Error::new(
235             ErrorKind::Other,
236             format!("Refusing to register signal {}", signal),
237         ));
238     }
239 
240     // Check that we have a signal driver running
241     handle.check_inner()?;
242 
243     let globals = globals();
244     let siginfo = match globals.storage().get(signal as EventId) {
245         Some(slot) => slot,
246         None => return Err(io::Error::new(io::ErrorKind::Other, "signal too large")),
247     };
248     let mut registered = Ok(());
249     siginfo.init.call_once(|| {
250         registered = unsafe {
251             signal_hook_registry::register(signal, move || action(globals, signal)).map(|_| ())
252         };
253         if registered.is_ok() {
254             siginfo.initialized.store(true, Ordering::Relaxed);
255         }
256     });
257     registered?;
258     // If the call_once failed, it won't be retried on the next attempt to register the signal. In
259     // such case it is not run, registered is still `Ok(())`, initialized is still `false`.
260     if siginfo.initialized.load(Ordering::Relaxed) {
261         Ok(())
262     } else {
263         Err(Error::new(
264             ErrorKind::Other,
265             "Failed to register signal handler",
266         ))
267     }
268 }
269 
270 /// A stream of events for receiving a particular type of OS signal.
271 ///
272 /// In general signal handling on Unix is a pretty tricky topic, and this
273 /// structure is no exception! There are some important limitations to keep in
274 /// mind when using `Signal` streams:
275 ///
276 /// * Signals handling in Unix already necessitates coalescing signals
277 ///   together sometimes. This `Signal` stream is also no exception here in
278 ///   that it will also coalesce signals. That is, even if the signal handler
279 ///   for this process runs multiple times, the `Signal` stream may only return
280 ///   one signal notification. Specifically, before `poll` is called, all
281 ///   signal notifications are coalesced into one item returned from `poll`.
282 ///   Once `poll` has been called, however, a further signal is guaranteed to
283 ///   be yielded as an item.
284 ///
285 ///   Put another way, any element pulled off the returned stream corresponds to
286 ///   *at least one* signal, but possibly more.
287 ///
288 /// * Signal handling in general is relatively inefficient. Although some
289 ///   improvements are possible in this crate, it's recommended to not plan on
290 ///   having millions of signal channels open.
291 ///
292 /// If you've got any questions about this feel free to open an issue on the
293 /// repo! New approaches to alleviate some of these limitations are always
294 /// appreciated!
295 ///
296 /// # Caveats
297 ///
298 /// The first time that a `Signal` instance is registered for a particular
299 /// signal kind, an OS signal-handler is installed which replaces the default
300 /// platform behavior when that signal is received, **for the duration of the
301 /// entire process**.
302 ///
303 /// For example, Unix systems will terminate a process by default when it
304 /// receives SIGINT. But, when a `Signal` instance is created to listen for
305 /// this signal, the next SIGINT that arrives will be translated to a stream
306 /// event, and the process will continue to execute. **Even if this `Signal`
307 /// instance is dropped, subsequent SIGINT deliveries will end up captured by
308 /// Tokio, and the default platform behavior will NOT be reset**.
309 ///
310 /// Thus, applications should take care to ensure the expected signal behavior
311 /// occurs as expected after listening for specific signals.
312 ///
313 /// # Examples
314 ///
315 /// Wait for SIGHUP
316 ///
317 /// ```rust,no_run
318 /// use tokio::signal::unix::{signal, SignalKind};
319 ///
320 /// #[tokio::main]
321 /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
322 ///     // An infinite stream of hangup signals.
323 ///     let mut stream = signal(SignalKind::hangup())?;
324 ///
325 ///     // Print whenever a HUP signal is received
326 ///     loop {
327 ///         stream.recv().await;
328 ///         println!("got signal HUP");
329 ///     }
330 /// }
331 /// ```
332 #[must_use = "streams do nothing unless polled"]
333 #[derive(Debug)]
334 pub struct Signal {
335     inner: RxFuture,
336 }
337 
338 /// Creates a new stream which will receive notifications when the current
339 /// process receives the specified signal `kind`.
340 ///
341 /// This function will create a new stream which binds to the default reactor.
342 /// The `Signal` stream is an infinite stream which will receive
343 /// notifications whenever a signal is received. More documentation can be
344 /// found on `Signal` itself, but to reiterate:
345 ///
346 /// * Signals may be coalesced beyond what the kernel already does.
347 /// * Once a signal handler is registered with the process the underlying
348 ///   libc signal handler is never unregistered.
349 ///
350 /// A `Signal` stream can be created for a particular signal number
351 /// multiple times. When a signal is received then all the associated
352 /// channels will receive the signal notification.
353 ///
354 /// # Errors
355 ///
356 /// * If the lower-level C functions fail for some reason.
357 /// * If the previous initialization of this specific signal failed.
358 /// * If the signal is one of
359 ///   [`signal_hook::FORBIDDEN`](fn@signal_hook_registry::register#panics)
signal(kind: SignalKind) -> io::Result<Signal>360 pub fn signal(kind: SignalKind) -> io::Result<Signal> {
361     let rx = signal_with_handle(kind, &Handle::current())?;
362 
363     Ok(Signal {
364         inner: RxFuture::new(rx),
365     })
366 }
367 
signal_with_handle( kind: SignalKind, handle: &Handle, ) -> io::Result<watch::Receiver<()>>368 pub(crate) fn signal_with_handle(
369     kind: SignalKind,
370     handle: &Handle,
371 ) -> io::Result<watch::Receiver<()>> {
372     // Turn the signal delivery on once we are ready for it
373     signal_enable(kind, handle)?;
374 
375     Ok(globals().register_listener(kind.0 as EventId))
376 }
377 
378 impl Signal {
379     /// Receives the next signal notification event.
380     ///
381     /// `None` is returned if no more events can be received by this stream.
382     ///
383     /// # Examples
384     ///
385     /// Wait for SIGHUP
386     ///
387     /// ```rust,no_run
388     /// use tokio::signal::unix::{signal, SignalKind};
389     ///
390     /// #[tokio::main]
391     /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
392     ///     // An infinite stream of hangup signals.
393     ///     let mut stream = signal(SignalKind::hangup())?;
394     ///
395     ///     // Print whenever a HUP signal is received
396     ///     loop {
397     ///         stream.recv().await;
398     ///         println!("got signal HUP");
399     ///     }
400     /// }
401     /// ```
recv(&mut self) -> Option<()>402     pub async fn recv(&mut self) -> Option<()> {
403         self.inner.recv().await
404     }
405 
406     /// Polls to receive the next signal notification event, outside of an
407     /// `async` context.
408     ///
409     /// This method returns:
410     ///
411     ///  * `Poll::Pending` if no signals are available but the channel is not
412     ///    closed.
413     ///  * `Poll::Ready(Some(()))` if a signal is available.
414     ///  * `Poll::Ready(None)` if the channel has been closed and all signals
415     ///    sent before it was closed have been received.
416     ///
417     /// # Examples
418     ///
419     /// Polling from a manually implemented future
420     ///
421     /// ```rust,no_run
422     /// use std::pin::Pin;
423     /// use std::future::Future;
424     /// use std::task::{Context, Poll};
425     /// use tokio::signal::unix::Signal;
426     ///
427     /// struct MyFuture {
428     ///     signal: Signal,
429     /// }
430     ///
431     /// impl Future for MyFuture {
432     ///     type Output = Option<()>;
433     ///
434     ///     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
435     ///         println!("polling MyFuture");
436     ///         self.signal.poll_recv(cx)
437     ///     }
438     /// }
439     /// ```
poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>>440     pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
441         self.inner.poll_recv(cx)
442     }
443 }
444 
445 // Work around for abstracting streams internally
446 pub(crate) trait InternalStream {
poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>>447     fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>>;
448 }
449 
450 impl InternalStream for Signal {
poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>>451     fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
452         self.poll_recv(cx)
453     }
454 }
455 
ctrl_c() -> io::Result<Signal>456 pub(crate) fn ctrl_c() -> io::Result<Signal> {
457     signal(SignalKind::interrupt())
458 }
459 
460 #[cfg(all(test, not(loom)))]
461 mod tests {
462     use super::*;
463 
464     #[test]
signal_enable_error_on_invalid_input()465     fn signal_enable_error_on_invalid_input() {
466         signal_enable(SignalKind::from_raw(-1), &Handle::default()).unwrap_err();
467     }
468 
469     #[test]
signal_enable_error_on_forbidden_input()470     fn signal_enable_error_on_forbidden_input() {
471         signal_enable(
472             SignalKind::from_raw(signal_hook_registry::FORBIDDEN[0]),
473             &Handle::default(),
474         )
475         .unwrap_err();
476     }
477 }
478