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