summaryrefslogtreecommitdiffstats
path: root/tokio/src/signal
diff options
context:
space:
mode:
authorIvan Petkov <ivanppetkov@gmail.com>2019-11-28 15:03:04 -0800
committerCarl Lerche <me@carllerche.com>2019-11-28 15:03:04 -0800
commitaef434c089754051e4a10c0e618f46003f31d2dc (patch)
treeb9b11b7d04e51d1b0b244222b207a73cce2ec76f /tokio/src/signal
parentcd73951130286bc7c8ff113084e00a71eced4b60 (diff)
signal: update documentation with caveats (#1854)
Diffstat (limited to 'tokio/src/signal')
-rw-r--r--tokio/src/signal/ctrl_c.rs18
-rw-r--r--tokio/src/signal/mod.rs9
-rw-r--r--tokio/src/signal/unix.rs107
-rw-r--r--tokio/src/signal/windows.rs87
4 files changed, 190 insertions, 31 deletions
diff --git a/tokio/src/signal/ctrl_c.rs b/tokio/src/signal/ctrl_c.rs
index 35ef2393..2240052c 100644
--- a/tokio/src/signal/ctrl_c.rs
+++ b/tokio/src/signal/ctrl_c.rs
@@ -15,6 +15,24 @@ use std::io;
/// future will complete on the first received `ctrl-c` **after** the initial
/// call to either `Future::poll` or `.await`.
///
+/// # Caveats
+///
+/// On Unix platforms, the first time that a `Signal` instance is registered for a
+/// particular signal kind, an OS signal-handler is installed which replaces the
+/// default platform behavior when that signal is received, **for the duration of
+/// the entire process**.
+///
+/// For example, Unix systems will terminate a process by default when it
+/// receives a signal generated by "CTRL+C" on the terminal. But, when a
+/// `ctrl_c` stream is created to listen for this signal, the time it arrives,
+/// it will be translated to a stream event, and the process will continue to
+/// execute. **Even if this `Signal` instance is dropped, subsequent SIGINT
+/// deliveries will end up captured by Tokio, and the default platform behavior
+/// will NOT be reset**.
+///
+/// Thus, applications should take care to ensure the expected signal behavior
+/// occurs as expected after listening for specific signals.
+///
/// # Examples
///
/// ```rust,no_run
diff --git a/tokio/src/signal/mod.rs b/tokio/src/signal/mod.rs
index 6b36bc4e..6e5e350d 100644
--- a/tokio/src/signal/mod.rs
+++ b/tokio/src/signal/mod.rs
@@ -1,16 +1,12 @@
//! Asynchronous signal handling for Tokio
//!
-//! The primary type exported from this crate, `unix::Signal`, allows
-//! listening for arbitrary signals on Unix platforms, receiving them
-//! in an asynchronous fashion.
-//!
//! Note that signal handling is in general a very tricky topic and should be
//! used with great care. This crate attempts to implement 'best practice' for
//! signal handling, but it should be evaluated for your own applications' needs
//! to see if it's suitable.
//!
-//! The are some fundamental limitations of this crate documented on the
-//! `Signal` structure as well.
+//! The are some fundamental limitations of this crate documented on the OS
+//! specific structures, as well.
//!
//! # Examples
//!
@@ -31,7 +27,6 @@
//!
//! ```rust,no_run
//! # #[cfg(unix)] {
-//!
//! use tokio::signal::unix::{signal, SignalKind};
//!
//! #[tokio::main]
diff --git a/tokio/src/signal/unix.rs b/tokio/src/signal/unix.rs
index b6ff9926..cd326424 100644
--- a/tokio/src/signal/unix.rs
+++ b/tokio/src/signal/unix.rs
@@ -309,12 +309,7 @@ impl Driver {
}
}
-/// An implementation of `Stream` for receiving a particular type of signal.
-///
-/// This structure implements the `Stream` trait and represents notifications
-/// of the current process receiving a particular signal. The signal being
-/// listened for is passed to `Signal::new`, and the same signal number is then
-/// yielded as each element for the stream.
+/// A stream of events for receiving a particular type of OS signal.
///
/// In general signal handling on Unix is a pretty tricky topic, and this
/// structure is no exception! There are some important limitations to keep in
@@ -336,13 +331,46 @@ impl Driver {
/// improvements are possible in this crate, it's recommended to not plan on
/// having millions of signal channels open.
///
-/// * Currently the "driver task" to process incoming signals never exits. This
-/// driver task runs in the background of the event loop provided, and
-/// in general you shouldn't need to worry about it.
-///
/// If you've got any questions about this feel free to open an issue on the
-/// repo, though, as I'd love to chat about this! In other words, I'd love to
-/// alleviate some of these limitations if possible!
+/// repo! New approaches to alleviate some of these limitations are always
+/// appreciated!
+///
+/// # Caveats
+///
+/// The first time that a `Signal` instance is registered for a particular
+/// signal kind, an OS signal-handler is installed which replaces the default
+/// platform behavior when that signal is received, **for the duration of the
+/// entire process**.
+///
+/// For example, Unix systems will terminate a process by default when it
+/// receives SIGINT. But, when a `Signal` instance is created to listen for
+/// this signal, the next SIGINT that arrives will be translated to a stream
+/// event, and the process will continue to execute. **Even if this `Signal`
+/// instance is dropped, subsequent SIGINT deliveries will end up captured by
+/// Tokio, and the default platform behavior will NOT be reset**.
+///
+/// Thus, applications should take care to ensure the expected signal behavior
+/// occurs as expected after listening for specific signals.
+///
+/// # Examples
+///
+/// Wait for SIGHUP
+///
+/// ```rust,no_run
+/// use tokio::signal::unix::{signal, SignalKind};
+///
+/// #[tokio::main]
+/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// // An infinite stream of hangup signals.
+/// let mut stream = signal(SignalKind::hangup())?;
+///
+/// // Print whenever a HUP signal is received
+/// loop {
+/// stream.recv().await;
+/// println!("got signal HUP");
+/// }
+/// }
+/// ```
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub struct Signal {
@@ -351,7 +379,7 @@ pub struct Signal {
}
/// Creates a new stream which will receive notifications when the current
-/// process receives the signal `signal`.
+/// process receives the specified signal `kind`.
///
/// This function will create a new stream which binds to the default reactor.
/// The `Signal` stream is an infinite stream which will receive
@@ -391,13 +419,62 @@ pub fn signal(kind: SignalKind) -> io::Result<Signal> {
}
impl Signal {
- #[doc(hidden)] // TODO: Dox
+ /// Receive the next signal notification event.
+ ///
+ /// `None` is returned if no more events can be received by this stream.
+ ///
+ /// # Examples
+ ///
+ /// Wait for SIGHUP
+ ///
+ /// ```rust,no_run
+ /// use tokio::signal::unix::{signal, SignalKind};
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// // An infinite stream of hangup signals.
+ /// let mut stream = signal(SignalKind::hangup())?;
+ ///
+ /// // Print whenever a HUP signal is received
+ /// loop {
+ /// stream.recv().await;
+ /// println!("got signal HUP");
+ /// }
+ /// }
+ /// ```
pub async fn recv(&mut self) -> Option<()> {
use crate::future::poll_fn;
poll_fn(|cx| self.poll_recv(cx)).await
}
- #[doc(hidden)] // TODO: document
+ /// Poll to receive the next signal notification event, outside of an
+ /// `async` context.
+ ///
+ /// `None` is returned if no more events can be received by this stream.
+ ///
+ /// # Examples
+ ///
+ /// Polling from a manually implemented future
+ ///
+ /// ```rust,no_run
+ /// use std::pin::Pin;
+ /// use std::future::Future;
+ /// use std::task::{Context, Poll};
+ /// use tokio::signal::unix::Signal;
+ ///
+ /// struct MyFuture {
+ /// signal: Signal,
+ /// }
+ ///
+ /// impl Future for MyFuture {
+ /// type Output = Option<()>;
+ ///
+ /// fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ /// println!("polling MyFuture");
+ /// self.signal.poll_recv(cx)
+ /// }
+ /// }
+ /// ```
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
let _ = self.driver.poll(cx);
self.rx.poll_recv(cx)
diff --git a/tokio/src/signal/windows.rs b/tokio/src/signal/windows.rs
index 725518d3..de35643e 100644
--- a/tokio/src/signal/windows.rs
+++ b/tokio/src/signal/windows.rs
@@ -73,7 +73,6 @@ impl Init for OsExtraData {
/// processed quickly enough. This means that if two notifications are
/// received back-to-back, then the stream may only receive one item about the
/// two notifications.
-// FIXME: refactor and combine with unix::Signal
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub(crate) struct Event {
@@ -139,7 +138,7 @@ unsafe extern "system" fn handler(ty: DWORD) -> BOOL {
/// Represents a stream which receives "ctrl-break" notifications sent to the process
/// via `SetConsoleCtrlHandler`.
///
-/// A notification to this process notifies *all* streams listening to
+/// A notification to this process notifies *all* streams listening for
/// this event. Moreover, the notifications **are coalesced** if they aren't processed
/// quickly enough. This means that if two notifications are received back-to-back,
/// then the stream may only receive one item about the two notifications.
@@ -150,25 +149,95 @@ pub struct CtrlBreak {
}
impl CtrlBreak {
- #[doc(hidden)] // TODO: document
+ /// Receive the next signal notification event.
+ ///
+ /// `None` is returned if no more events can be received by this stream.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use tokio::signal::windows::ctrl_break;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// // An infinite stream of CTRL-BREAK events.
+ /// let mut stream = ctrl_break()?;
+ ///
+ /// // Print whenever a CTRL-BREAK event is received
+ /// loop {
+ /// stream.recv().await;
+ /// println!("got signal CTRL-BREAK");
+ /// }
+ /// }
+ /// ```
+ pub async fn recv(&mut self) -> Option<()> {
+ use crate::future::poll_fn;
+ poll_fn(|cx| self.poll_recv(cx)).await
+ }
+
+ /// Poll to receive the next signal notification event, outside of an
+ /// `async` context.
+ ///
+ /// `None` is returned if no more events can be received by this stream.
+ ///
+ /// # Examples
+ ///
+ /// Polling from a manually implemented future
+ ///
+ /// ```rust,no_run
+ /// use std::pin::Pin;
+ /// use std::future::Future;
+ /// use std::task::{Context, Poll};
+ /// use tokio::signal::windows::CtrlBreak;
+ ///
+ /// struct MyFuture {
+ /// ctrl_break: CtrlBreak,
+ /// }
+ ///
+ /// impl Future for MyFuture {
+ /// type Output = Option<()>;
+ ///
+ /// fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ /// println!("polling MyFuture");
+ /// self.ctrl_break.poll_recv(cx)
+ /// }
+ /// }
+ /// ```
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
self.inner.rx.poll_recv(cx)
}
}
-#[cfg(feature = "stream")]
-impl futures_core::Stream for CtrlBreak {
- type Item = ();
+cfg_stream! {
+ impl futures_core::Stream for CtrlBreak {
+ type Item = ();
- fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
- self.poll_recv(cx)
+ fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
+ self.poll_recv(cx)
+ }
}
}
/// Creates a new stream which receives "ctrl-break" notifications sent to the
/// process.
///
-/// This function binds to the default reactor.
+/// # Examples
+///
+/// ```rust,no_run
+/// use tokio::signal::windows::ctrl_break;
+///
+/// #[tokio::main]
+/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// // An infinite stream of CTRL-BREAK events.
+/// let mut stream = ctrl_break()?;
+///
+/// // Print whenever a CTRL-BREAK event is received
+/// loop {
+/// stream.recv().await;
+/// println!("got signal CTRL-BREAK");
+/// }
+/// }
+/// ```
pub fn ctrl_break() -> io::Result<CtrlBreak> {
Event::new(CTRL_BREAK_EVENT).map(|inner| CtrlBreak { inner })
}