| 1 | //! Asynchronous signal handling for Tokio. |
| 2 | //! |
| 3 | //! Note that signal handling is in general a very tricky topic and should be |
| 4 | //! used with great care. This crate attempts to implement 'best practice' for |
| 5 | //! signal handling, but it should be evaluated for your own applications' needs |
| 6 | //! to see if it's suitable. |
| 7 | //! |
| 8 | //! There are some fundamental limitations of this crate documented on the OS |
| 9 | //! specific structures, as well. |
| 10 | //! |
| 11 | //! # Examples |
| 12 | //! |
| 13 | //! Print on "ctrl-c" notification. |
| 14 | //! |
| 15 | //! ```rust,no_run |
| 16 | //! use tokio::signal; |
| 17 | //! |
| 18 | //! #[tokio::main] |
| 19 | //! async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 20 | //! signal::ctrl_c().await?; |
| 21 | //! println!("ctrl-c received!" ); |
| 22 | //! Ok(()) |
| 23 | //! } |
| 24 | //! ``` |
| 25 | //! |
| 26 | //! Wait for `SIGHUP` on Unix |
| 27 | //! |
| 28 | //! ```rust,no_run |
| 29 | //! # #[cfg (unix)] { |
| 30 | //! use tokio::signal::unix::{signal, SignalKind}; |
| 31 | //! |
| 32 | //! #[tokio::main] |
| 33 | //! async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 34 | //! // An infinite stream of hangup signals. |
| 35 | //! let mut stream = signal(SignalKind::hangup())?; |
| 36 | //! |
| 37 | //! // Print whenever a HUP signal is received |
| 38 | //! loop { |
| 39 | //! stream.recv().await; |
| 40 | //! println!("got signal HUP" ); |
| 41 | //! } |
| 42 | //! } |
| 43 | //! # } |
| 44 | //! ``` |
| 45 | use crate::sync::watch::Receiver; |
| 46 | use std::task::{Context, Poll}; |
| 47 | |
| 48 | #[cfg (feature = "signal" )] |
| 49 | mod ctrl_c; |
| 50 | #[cfg (feature = "signal" )] |
| 51 | pub use ctrl_c::ctrl_c; |
| 52 | |
| 53 | pub(crate) mod registry; |
| 54 | |
| 55 | mod os { |
| 56 | #[cfg (unix)] |
| 57 | pub(crate) use super::unix::{OsExtraData, OsStorage}; |
| 58 | |
| 59 | #[cfg (windows)] |
| 60 | pub(crate) use super::windows::{OsExtraData, OsStorage}; |
| 61 | } |
| 62 | |
| 63 | pub mod unix; |
| 64 | pub mod windows; |
| 65 | |
| 66 | mod reusable_box; |
| 67 | use self::reusable_box::ReusableBoxFuture; |
| 68 | |
| 69 | #[derive (Debug)] |
| 70 | struct RxFuture { |
| 71 | inner: ReusableBoxFuture<Receiver<()>>, |
| 72 | } |
| 73 | |
| 74 | async fn make_future(mut rx: Receiver<()>) -> Receiver<()> { |
| 75 | rx.changed().await.expect(msg:"signal sender went away" ); |
| 76 | rx |
| 77 | } |
| 78 | |
| 79 | impl RxFuture { |
| 80 | fn new(rx: Receiver<()>) -> Self { |
| 81 | Self { |
| 82 | inner: ReusableBoxFuture::new(make_future(rx)), |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | async fn recv(&mut self) -> Option<()> { |
| 87 | use std::future::poll_fn; |
| 88 | poll_fn(|cx: &mut Context<'_>| self.poll_recv(cx)).await |
| 89 | } |
| 90 | |
| 91 | fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> { |
| 92 | match self.inner.poll(cx) { |
| 93 | Poll::Pending => Poll::Pending, |
| 94 | Poll::Ready(rx: Receiver<()>) => { |
| 95 | self.inner.set(make_future(rx)); |
| 96 | Poll::Ready(Some(())) |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |