summaryrefslogtreecommitdiffstats
path: root/vendor/tokio/src/signal/windows.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/tokio/src/signal/windows.rs
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tokio/src/signal/windows.rs')
-rw-r--r--vendor/tokio/src/signal/windows.rs525
1 files changed, 337 insertions, 188 deletions
diff --git a/vendor/tokio/src/signal/windows.rs b/vendor/tokio/src/signal/windows.rs
index c231d6268..2f70f98b1 100644
--- a/vendor/tokio/src/signal/windows.rs
+++ b/vendor/tokio/src/signal/windows.rs
@@ -1,133 +1,28 @@
//! Windows-specific types for signal handling.
//!
-//! 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`.
+//! This module is only defined on Windows and allows receiving "ctrl-c",
+//! "ctrl-break", "ctrl-logoff", "ctrl-shutdown", and "ctrl-close"
+//! notifications. These events are listened for via the `SetConsoleCtrlHandler`
+//! function which receives the corresponding windows_sys event type.
-#![cfg(windows)]
+#![cfg(any(windows, docsrs))]
+#![cfg_attr(docsrs, doc(cfg(all(windows, feature = "signal"))))]
-use crate::signal::registry::{globals, EventId, EventInfo, Init, Storage};
use crate::signal::RxFuture;
-
-use std::convert::TryFrom;
use std::io;
-use std::sync::Once;
use std::task::{Context, Poll};
-use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
-use winapi::um::consoleapi::SetConsoleCtrlHandler;
-use winapi::um::wincon::{CTRL_BREAK_EVENT, CTRL_C_EVENT};
-
-#[derive(Debug)]
-pub(crate) struct OsStorage {
- ctrl_c: EventInfo,
- ctrl_break: EventInfo,
-}
-impl Init for OsStorage {
- fn init() -> Self {
- Self {
- ctrl_c: EventInfo::default(),
- ctrl_break: EventInfo::default(),
- }
- }
-}
-
-impl Storage for OsStorage {
- fn event_info(&self, id: EventId) -> Option<&EventInfo> {
- match DWORD::try_from(id) {
- Ok(CTRL_C_EVENT) => Some(&self.ctrl_c),
- Ok(CTRL_BREAK_EVENT) => Some(&self.ctrl_break),
- _ => None,
- }
- }
+#[cfg(not(docsrs))]
+#[path = "windows/sys.rs"]
+mod imp;
+#[cfg(not(docsrs))]
+pub(crate) use self::imp::{OsExtraData, OsStorage};
- fn for_each<'a, F>(&'a self, mut f: F)
- where
- F: FnMut(&'a EventInfo),
- {
- f(&self.ctrl_c);
- f(&self.ctrl_break);
- }
-}
-
-#[derive(Debug)]
-pub(crate) struct OsExtraData {}
-
-impl Init for OsExtraData {
- fn init() -> Self {
- Self {}
- }
-}
+#[cfg(docsrs)]
+#[path = "windows/stub.rs"]
+mod imp;
-/// Stream of events discovered via `SetConsoleCtrlHandler`.
-///
-/// This structure can be used to listen for events of the type `CTRL_C_EVENT`
-/// and `CTRL_BREAK_EVENT`. The `Stream` trait is implemented for this struct
-/// and will resolve for each notification received by the process. Note that
-/// there are few limitations with this as well:
-///
-/// * A notification to this process notifies *all* `Event` streams for that
-/// event type.
-/// * Notifications to an `Event` stream **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(crate) struct Event {
- inner: RxFuture,
-}
-
-impl Event {
- fn new(signum: DWORD) -> io::Result<Self> {
- global_init()?;
-
- let rx = globals().register_listener(signum as EventId);
-
- Ok(Self {
- inner: RxFuture::new(rx),
- })
- }
-}
-
-fn global_init() -> io::Result<()> {
- static INIT: Once = Once::new();
-
- let mut init = None;
-
- INIT.call_once(|| unsafe {
- let rc = SetConsoleCtrlHandler(Some(handler), TRUE);
- let ret = if rc == 0 {
- Err(io::Error::last_os_error())
- } else {
- Ok(())
- };
-
- init = Some(ret);
- });
-
- init.unwrap_or_else(|| Ok(()))
-}
-
-unsafe extern "system" fn handler(ty: DWORD) -> BOOL {
- let globals = globals();
- globals.record_event(ty as EventId);
-
- // According to https://docs.microsoft.com/en-us/windows/console/handlerroutine
- // the handler routine is always invoked in a new thread, thus we don't
- // have the same restrictions as in Unix signal handlers, meaning we can
- // go ahead and perform the broadcast here.
- if globals.broadcast() {
- TRUE
- } else {
- // No one is listening for this notification any more
- // let the OS fire the next (possibly the default) handler.
- FALSE
- }
-}
-
-/// Creates a new stream which receives "ctrl-c" notifications sent to the
+/// Creates a new listener which receives "ctrl-c" notifications sent to the
/// process.
///
/// # Examples
@@ -137,12 +32,12 @@ unsafe extern "system" fn handler(ty: DWORD) -> BOOL {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
-/// // An infinite stream of CTRL-C events.
-/// let mut stream = ctrl_c()?;
+/// // A listener of CTRL-C events.
+/// let mut signal = ctrl_c()?;
///
/// // Print whenever a CTRL-C event is received.
/// for countdown in (0..3).rev() {
-/// stream.recv().await;
+/// signal.recv().await;
/// println!("got CTRL-C. {} more to exit", countdown);
/// }
///
@@ -150,26 +45,32 @@ unsafe extern "system" fn handler(ty: DWORD) -> BOOL {
/// }
/// ```
pub fn ctrl_c() -> io::Result<CtrlC> {
- Event::new(CTRL_C_EVENT).map(|inner| CtrlC { inner })
+ Ok(CtrlC {
+ inner: self::imp::ctrl_c()?,
+ })
}
-/// Represents a stream which receives "ctrl-c" notifications sent to the process
+/// Represents a listener which receives "ctrl-c" notifications sent to the process
/// via `SetConsoleCtrlHandler`.
///
-/// A notification to this process notifies *all* streams listening for
+/// This event can be turned into a `Stream` using [`CtrlCStream`].
+///
+/// [`CtrlCStream`]: https://docs.rs/tokio-stream/latest/tokio_stream/wrappers/struct.CtrlCStream.html
+///
+/// A notification to this process notifies *all* receivers 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"]
+/// then the listener may only receive one item about the two notifications.
+#[must_use = "listeners do nothing unless polled"]
#[derive(Debug)]
pub struct CtrlC {
- inner: Event,
+ inner: RxFuture,
}
impl CtrlC {
/// Receives the next signal notification event.
///
- /// `None` is returned if no more events can be received by this stream.
+ /// `None` is returned if no more events can be received by the listener.
///
/// # Examples
///
@@ -178,12 +79,11 @@ impl CtrlC {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
- /// // An infinite stream of CTRL-C events.
- /// let mut stream = ctrl_c()?;
+ /// let mut signal = ctrl_c()?;
///
/// // Print whenever a CTRL-C event is received.
/// for countdown in (0..3).rev() {
- /// stream.recv().await;
+ /// signal.recv().await;
/// println!("got CTRL-C. {} more to exit", countdown);
/// }
///
@@ -191,13 +91,13 @@ impl CtrlC {
/// }
/// ```
pub async fn recv(&mut self) -> Option<()> {
- self.inner.inner.recv().await
+ 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.
+ /// `None` is returned if no more events can be received.
///
/// # Examples
///
@@ -223,27 +123,31 @@ impl CtrlC {
/// }
/// ```
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
- self.inner.inner.poll_recv(cx)
+ self.inner.poll_recv(cx)
}
}
-/// Represents a stream which receives "ctrl-break" notifications sent to the process
+/// Represents a listener which receives "ctrl-break" notifications sent to the process
/// via `SetConsoleCtrlHandler`.
///
-/// A notification to this process notifies *all* streams listening for
+/// This listener can be turned into a `Stream` using [`CtrlBreakStream`].
+///
+/// [`CtrlBreakStream`]: https://docs.rs/tokio-stream/latest/tokio_stream/wrappers/struct.CtrlBreakStream.html
+///
+/// A notification to this process notifies *all* receivers 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"]
+/// then the listener may only receive one item about the two notifications.
+#[must_use = "listeners do nothing unless polled"]
#[derive(Debug)]
pub struct CtrlBreak {
- inner: Event,
+ inner: RxFuture,
}
impl CtrlBreak {
/// Receives the next signal notification event.
///
- /// `None` is returned if no more events can be received by this stream.
+ /// `None` is returned if no more events can be received by this listener.
///
/// # Examples
///
@@ -252,24 +156,24 @@ impl CtrlBreak {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
- /// // An infinite stream of CTRL-BREAK events.
- /// let mut stream = ctrl_break()?;
+ /// // A listener of CTRL-BREAK events.
+ /// let mut signal = ctrl_break()?;
///
/// // Print whenever a CTRL-BREAK event is received.
/// loop {
- /// stream.recv().await;
+ /// signal.recv().await;
/// println!("got signal CTRL-BREAK");
/// }
/// }
/// ```
pub async fn recv(&mut self) -> Option<()> {
- self.inner.inner.recv().await
+ 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.
+ /// `None` is returned if no more events can be received by this listener.
///
/// # Examples
///
@@ -295,11 +199,11 @@ impl CtrlBreak {
/// }
/// ```
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
- self.inner.inner.poll_recv(cx)
+ self.inner.poll_recv(cx)
}
}
-/// Creates a new stream which receives "ctrl-break" notifications sent to the
+/// Creates a new listener which receives "ctrl-break" notifications sent to the
/// process.
///
/// # Examples
@@ -309,67 +213,312 @@ impl CtrlBreak {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
-/// // An infinite stream of CTRL-BREAK events.
-/// let mut stream = ctrl_break()?;
+/// // A listener of CTRL-BREAK events.
+/// let mut signal = ctrl_break()?;
///
/// // Print whenever a CTRL-BREAK event is received.
/// loop {
-/// stream.recv().await;
+/// signal.recv().await;
/// println!("got signal CTRL-BREAK");
/// }
/// }
/// ```
pub fn ctrl_break() -> io::Result<CtrlBreak> {
- Event::new(CTRL_BREAK_EVENT).map(|inner| CtrlBreak { inner })
+ Ok(CtrlBreak {
+ inner: self::imp::ctrl_break()?,
+ })
}
-#[cfg(all(test, not(loom)))]
-mod tests {
- use super::*;
- use crate::runtime::Runtime;
+/// Creates a new listener which receives "ctrl-close" notifications sent to the
+/// process.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use tokio::signal::windows::ctrl_close;
+///
+/// #[tokio::main]
+/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// // A listener of CTRL-CLOSE events.
+/// let mut signal = ctrl_close()?;
+///
+/// // Print whenever a CTRL-CLOSE event is received.
+/// for countdown in (0..3).rev() {
+/// signal.recv().await;
+/// println!("got CTRL-CLOSE. {} more to exit", countdown);
+/// }
+///
+/// Ok(())
+/// }
+/// ```
+pub fn ctrl_close() -> io::Result<CtrlClose> {
+ Ok(CtrlClose {
+ inner: self::imp::ctrl_close()?,
+ })
+}
- use tokio_test::{assert_ok, assert_pending, assert_ready_ok, task};
+/// Represents a listener which receives "ctrl-close" notitifications sent to the process
+/// via 'SetConsoleCtrlHandler'.
+///
+/// A notification to this process notifies *all* listeners 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 listener may only receive one item about the two notifications.
+#[must_use = "listeners do nothing unless polled"]
+#[derive(Debug)]
+pub struct CtrlClose {
+ inner: RxFuture,
+}
- #[test]
- fn ctrl_c() {
- let rt = rt();
- let _enter = rt.enter();
+impl CtrlClose {
+ /// Receives the next signal notification event.
+ ///
+ /// `None` is returned if no more events can be received by this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use tokio::signal::windows::ctrl_close;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// // A listener of CTRL-CLOSE events.
+ /// let mut signal = ctrl_close()?;
+ ///
+ /// // Print whenever a CTRL-CLOSE event is received.
+ /// signal.recv().await;
+ /// println!("got CTRL-CLOSE. Cleaning up before exiting");
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub async fn recv(&mut self) -> Option<()> {
+ self.inner.recv().await
+ }
- let mut ctrl_c = task::spawn(crate::signal::ctrl_c());
+ /// 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 listener.
+ ///
+ /// # 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::CtrlClose;
+ ///
+ /// struct MyFuture {
+ /// ctrl_close: CtrlClose,
+ /// }
+ ///
+ /// 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_close.poll_recv(cx)
+ /// }
+ /// }
+ /// ```
+ pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
+ self.inner.poll_recv(cx)
+ }
+}
- assert_pending!(ctrl_c.poll());
+/// Creates a new listener which receives "ctrl-shutdown" notifications sent to the
+/// process.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use tokio::signal::windows::ctrl_shutdown;
+///
+/// #[tokio::main]
+/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// // A listener of CTRL-SHUTDOWN events.
+/// let mut signal = ctrl_shutdown()?;
+///
+/// signal.recv().await;
+/// println!("got CTRL-SHUTDOWN. Cleaning up before exiting");
+///
+/// Ok(())
+/// }
+/// ```
+pub fn ctrl_shutdown() -> io::Result<CtrlShutdown> {
+ Ok(CtrlShutdown {
+ inner: self::imp::ctrl_shutdown()?,
+ })
+}
- // Windows doesn't have a good programmatic way of sending events
- // like sending signals on Unix, so we'll stub out the actual OS
- // integration and test that our handling works.
- unsafe {
- super::handler(CTRL_C_EVENT);
- }
+/// Represents a listener which receives "ctrl-shutdown" notitifications sent to the process
+/// via 'SetConsoleCtrlHandler'.
+///
+/// A notification to this process notifies *all* listeners 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 listener may only receive one item about the two notifications.
+#[must_use = "listeners do nothing unless polled"]
+#[derive(Debug)]
+pub struct CtrlShutdown {
+ inner: RxFuture,
+}
- assert_ready_ok!(ctrl_c.poll());
+impl CtrlShutdown {
+ /// Receives the next signal notification event.
+ ///
+ /// `None` is returned if no more events can be received by this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use tokio::signal::windows::ctrl_shutdown;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// // A listener of CTRL-SHUTDOWN events.
+ /// let mut signal = ctrl_shutdown()?;
+ ///
+ /// // Print whenever a CTRL-SHUTDOWN event is received.
+ /// signal.recv().await;
+ /// println!("got CTRL-SHUTDOWN. Cleaning up before exiting");
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub async fn recv(&mut self) -> Option<()> {
+ self.inner.recv().await
}
- #[test]
- fn ctrl_break() {
- let rt = rt();
+ /// 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 listener.
+ ///
+ /// # 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::CtrlShutdown;
+ ///
+ /// struct MyFuture {
+ /// ctrl_shutdown: CtrlShutdown,
+ /// }
+ ///
+ /// 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_shutdown.poll_recv(cx)
+ /// }
+ /// }
+ /// ```
+ pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
+ self.inner.poll_recv(cx)
+ }
+}
- rt.block_on(async {
- let mut ctrl_break = assert_ok!(super::ctrl_break());
+/// Creates a new listener which receives "ctrl-logoff" notifications sent to the
+/// process.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use tokio::signal::windows::ctrl_logoff;
+///
+/// #[tokio::main]
+/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// // A listener of CTRL-LOGOFF events.
+/// let mut signal = ctrl_logoff()?;
+///
+/// signal.recv().await;
+/// println!("got CTRL-LOGOFF. Cleaning up before exiting");
+///
+/// Ok(())
+/// }
+/// ```
+pub fn ctrl_logoff() -> io::Result<CtrlLogoff> {
+ Ok(CtrlLogoff {
+ inner: self::imp::ctrl_logoff()?,
+ })
+}
- // Windows doesn't have a good programmatic way of sending events
- // like sending signals on Unix, so we'll stub out the actual OS
- // integration and test that our handling works.
- unsafe {
- super::handler(CTRL_BREAK_EVENT);
- }
+/// Represents a listener which receives "ctrl-logoff" notitifications sent to the process
+/// via 'SetConsoleCtrlHandler'.
+///
+/// A notification to this process notifies *all* listeners 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 listener may only receive one item about the two notifications.
+#[must_use = "listeners do nothing unless polled"]
+#[derive(Debug)]
+pub struct CtrlLogoff {
+ inner: RxFuture,
+}
- ctrl_break.recv().await.unwrap();
- });
+impl CtrlLogoff {
+ /// Receives the next signal notification event.
+ ///
+ /// `None` is returned if no more events can be received by this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// use tokio::signal::windows::ctrl_logoff;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// // An listener of CTRL-LOGOFF events.
+ /// let mut signal = ctrl_logoff()?;
+ ///
+ /// // Print whenever a CTRL-LOGOFF event is received.
+ /// signal.recv().await;
+ /// println!("got CTRL-LOGOFF. Cleaning up before exiting");
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub async fn recv(&mut self) -> Option<()> {
+ self.inner.recv().await
}
- fn rt() -> Runtime {
- crate::runtime::Builder::new_current_thread()
- .build()
- .unwrap()
+ /// 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 listener.
+ ///
+ /// # 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::CtrlLogoff;
+ ///
+ /// struct MyFuture {
+ /// ctrl_logoff: CtrlLogoff,
+ /// }
+ ///
+ /// 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_logoff.poll_recv(cx)
+ /// }
+ /// }
+ /// ```
+ pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
+ self.inner.poll_recv(cx)
}
}