From 320a5fdca7637e4045d4e3c8a7e592e3a833b1da Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Sat, 20 Jul 2019 10:50:27 -0700 Subject: [PATCH] signal: replace `windows::Event` with `windows::CtrlBreak` (#1331) * Add a new `windows::CtrlBreak` struct which wil represent a stream of CTRL_BREAK_EVENT signals on Windows systems * The `windows::Event` type is no longer publicly accessible and is replaced by using `CtrlC` or `windows::CtrlBreak`. [breaking-change] --- tokio-signal/CHANGELOG.md | 6 ++++ tokio-signal/src/ctrl_c.rs | 7 ++++- tokio-signal/src/lib.rs | 3 -- tokio-signal/src/windows.rs | 58 ++++++++++++++++++++++++++++++------- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/tokio-signal/CHANGELOG.md b/tokio-signal/CHANGELOG.md index 5014fb4d9..90a8cb2e5 100644 --- a/tokio-signal/CHANGELOG.md +++ b/tokio-signal/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.3.0 + +### Changed +- **Breaking:** `windows::Event` has been removed in favor of `CtrlC` and +a separate `windows::CtrlBreak` struct. + # 0.2.9 ### Fixed diff --git a/tokio-signal/src/ctrl_c.rs b/tokio-signal/src/ctrl_c.rs index 6bde65c37..377ee39db 100644 --- a/tokio-signal/src/ctrl_c.rs +++ b/tokio-signal/src/ctrl_c.rs @@ -20,6 +20,11 @@ use tokio_reactor::Handle; /// Note that there are a number of caveats listening for signals, and you may /// wish to read up on the documentation in the `unix` or `windows` module to /// take a peek. +/// +/// Notably, a notification to this process notifies *all* streams listening to +/// 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 { @@ -39,7 +44,7 @@ impl CtrlC { /// process. /// /// This function binds to reactor specified by `handle`. - pub fn with_handle(handle: &Handle) -> IoFuture { + pub fn with_handle(handle: &Handle) -> IoFuture { Inner::ctrl_c(handle).map_ok(|inner| Self { inner }).boxed() } } diff --git a/tokio-signal/src/lib.rs b/tokio-signal/src/lib.rs index ef8e48236..50d907a56 100644 --- a/tokio-signal/src/lib.rs +++ b/tokio-signal/src/lib.rs @@ -85,7 +85,6 @@ extern crate lazy_static; use futures_core::future::Future; -use futures_core::stream::Stream; use std::io; use std::pin::Pin; @@ -104,7 +103,5 @@ pub mod windows; /// A future whose output is `io::Result` pub type IoFuture = Pin> + Send>>; -/// A stream whose item is `io::Result` -pub type IoStream = Pin> + Send>>; pub use ctrl_c::CtrlC; diff --git a/tokio-signal/src/windows.rs b/tokio-signal/src/windows.rs index f0ffc8b49..9c699fb68 100644 --- a/tokio-signal/src/windows.rs +++ b/tokio-signal/src/windows.rs @@ -16,6 +16,7 @@ use std::task::{Context, Poll}; use futures_core::stream::Stream; use futures_util::future::{self, FutureExt}; +use futures_util::try_future::TryFutureExt; use tokio_reactor::Handle; use tokio_sync::mpsc::{channel, Receiver, Sender}; use winapi::shared::minwindef::*; @@ -91,7 +92,7 @@ static INIT: Once = Once::new(); // FIXME: refactor and combine with unix::Signal #[must_use = "streams do nothing unless polled"] #[derive(Debug)] -pub struct Event { +pub(crate) struct Event { rx: Receiver<()>, } @@ -113,15 +114,7 @@ impl Event { /// /// This function will register a handler via `SetConsoleCtrlHandler` and /// deliver notifications to the returned stream. - pub fn ctrl_break() -> IoFuture { - Event::ctrl_break_handle(&Handle::default()) - } - - /// Creates a new stream listening for the `CTRL_BREAK_EVENT` events. - /// - /// This function will register a handler via `SetConsoleCtrlHandler` and - /// deliver notifications to the returned stream. - pub fn ctrl_break_handle(handle: &Handle) -> IoFuture { + fn ctrl_break_handle(handle: &Handle) -> IoFuture { Event::new(CTRL_BREAK_EVENT, handle) } @@ -199,6 +192,49 @@ unsafe extern "system" fn handler(ty: DWORD) -> BOOL { TRUE } +/// Represents a stream which receives "ctrl-break" notifications sent to the process +/// via `SetConsoleCtrlHandler`. +/// +/// A notification to this process notifies *all* streams listening to +/// 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 CtrlBreak { + inner: Event, +} + +impl CtrlBreak { + /// Creates a new stream which receives "ctrl-break" notifications sent to the + /// process. + /// + /// This function binds to the default reactor. + pub fn new() -> IoFuture { + Self::with_handle(&Handle::default()) + } + + /// Creates a new stream which receives "ctrl-break" notifications sent to the + /// process. + /// + /// This function binds to reactor specified by `handle`. + pub fn with_handle(handle: &Handle) -> IoFuture { + Event::ctrl_break_handle(handle) + .map_ok(|inner| Self { inner }) + .boxed() + } +} + +impl Stream for CtrlBreak { + type Item = (); + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.inner) + .poll_next(cx) + .map(|item| item.map(|_| ())) + } +} + #[cfg(test)] mod tests { use super::*; @@ -231,7 +267,7 @@ mod tests { let _ = rt.block_on(with_timeout(event_ctrl_c.into_future())); let event_ctrl_break = rt - .block_on(with_timeout(Event::ctrl_break())) + .block_on(with_timeout(CtrlBreak::new())) .expect("failed to run future"); unsafe {