mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-21 00:00:10 +02:00
signal: update documentation with caveats (#1854)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
+92
-15
@@ -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)
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user