summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Fiekas <niklas.fiekas@backscattering.de>2020-11-27 19:53:17 +0000
committerGitHub <noreply@github.com>2020-11-27 19:53:17 +0000
commit49129434198a96444bc0e9582a14062d3a46e93a (patch)
tree904fb6b1fb539bffe69168c7202ccc3db15321dc
parent5e406a7a47699d93fa2a77fb72553600cb7abd0f (diff)
signal: expose CtrlC stream on windows (#3186)
* Make tokio::signal::windows::ctrl_c() public. * Stop referring to private tokio::signal::windows::Event in module documentation. Closes #3178
-rw-r--r--tokio/src/signal/windows.rs127
1 files changed, 116 insertions, 11 deletions
diff --git a/tokio/src/signal/windows.rs b/tokio/src/signal/windows.rs
index 1e783622..7f2e4862 100644
--- a/tokio/src/signal/windows.rs
+++ b/tokio/src/signal/windows.rs
@@ -1,9 +1,9 @@
//! Windows-specific types for signal handling.
//!
-//! This module is only defined on Windows and contains the primary `Event` type
-//! for receiving notifications of events. These events are listened for via the
+//! This module is only defined on Windows and allows receiving "ctrl-c"
+//! and "ctrl-break" notifications. These events are listened for via the
//! `SetConsoleCtrlHandler` function which receives events of the type
-//! `CTRL_C_EVENT` and `CTRL_BREAK_EVENT`
+//! `CTRL_C_EVENT` and `CTRL_BREAK_EVENT`.
#![cfg(windows)]
@@ -79,10 +79,6 @@ pub(crate) struct Event {
rx: Receiver<()>,
}
-pub(crate) fn ctrl_c() -> io::Result<Event> {
- Event::new(CTRL_C_EVENT)
-}
-
impl Event {
fn new(signum: DWORD) -> io::Result<Self> {
global_init()?;
@@ -135,6 +131,116 @@ unsafe extern "system" fn handler(ty: DWORD) -> BOOL {
}
}
+/// Creates a new stream which receives "ctrl-c" notifications sent to the
+/// process.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use tokio::signal::windows::ctrl_c;
+///
+/// #[tokio::main]
+/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// // An infinite stream of CTRL-C events.
+/// let mut stream = ctrl_c()?;
+///
+/// // Print whenever a CTRL-C event is received.
+/// for countdown in (0..3).rev() {
+/// stream.recv().await;
+/// println!("got CTRL-C. {} more to exit", countdown);
+/// }
+///
+/// Ok(())
+/// }
+/// ```
+pub fn ctrl_c() -> io::Result<CtrlC> {
+ Event::new(CTRL_C_EVENT).map(|inner| CtrlC { inner })
+}
+
+/// Represents a stream which receives "ctrl-c" notifications sent to the process
+/// via `SetConsoleCtrlHandler`.
+///
+/// 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.
+#[must_use = "streams do nothing unless polled"]
+#[derive(Debug)]
+pub struct CtrlC {
+ inner: Event,
+}
+
+impl CtrlC {
+ /// Receives 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_c;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// // An infinite stream of CTRL-C events.
+ /// let mut stream = ctrl_c()?;
+ ///
+ /// // Print whenever a CTRL-C event is received.
+ /// for countdown in (0..3).rev() {
+ /// stream.recv().await;
+ /// println!("got CTRL-C. {} more to exit", countdown);
+ /// }
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub async fn recv(&mut self) -> Option<()> {
+ self.inner.recv().await
+ }
+
+ /// Polls 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::CtrlC;
+ ///
+ /// struct MyFuture {
+ /// ctrl_c: CtrlC,
+ /// }
+ ///
+ /// 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_c.poll_recv(cx)
+ /// }
+ /// }
+ /// ```
+ pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
+ self.inner.rx.poll_recv(cx)
+ }
+}
+
+cfg_stream! {
+ impl crate::stream::Stream for CtrlC {
+ type Item = ();
+
+ fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<()>> {
+ self.poll_recv(cx)
+ }
+ }
+}
+
/// Represents a stream which receives "ctrl-break" notifications sent to the process
/// via `SetConsoleCtrlHandler`.
///
@@ -163,7 +269,7 @@ impl CtrlBreak {
/// // An infinite stream of CTRL-BREAK events.
/// let mut stream = ctrl_break()?;
///
- /// // Print whenever a CTRL-BREAK event is received
+ /// // Print whenever a CTRL-BREAK event is received.
/// loop {
/// stream.recv().await;
/// println!("got signal CTRL-BREAK");
@@ -171,8 +277,7 @@ impl CtrlBreak {
/// }
/// ```
pub async fn recv(&mut self) -> Option<()> {
- use crate::future::poll_fn;
- poll_fn(|cx| self.poll_recv(cx)).await
+ self.inner.recv().await
}
/// Polls to receive the next signal notification event, outside of an
@@ -231,7 +336,7 @@ cfg_stream! {
/// // An infinite stream of CTRL-BREAK events.
/// let mut stream = ctrl_break()?;
///
-/// // Print whenever a CTRL-BREAK event is received
+/// // Print whenever a CTRL-BREAK event is received.
/// loop {
/// stream.recv().await;
/// println!("got signal CTRL-BREAK");