diff --git a/tokio/src/signal/mod.rs b/tokio/src/signal/mod.rs index 0d505210159..e79f4802a61 100644 --- a/tokio/src/signal/mod.rs +++ b/tokio/src/signal/mod.rs @@ -50,16 +50,9 @@ mod ctrl_c; #[cfg(feature = "signal")] pub use ctrl_c::ctrl_c; +#[cfg(unix)] pub(crate) mod registry; -mod os { - #[cfg(unix)] - pub(crate) use super::unix::{OsExtraData, OsStorage}; - - #[cfg(windows)] - pub(crate) use super::windows::{OsExtraData, OsStorage}; -} - pub mod unix; pub mod windows; diff --git a/tokio/src/signal/registry.rs b/tokio/src/signal/registry.rs index 2a3eea3982d..b2fd4c73059 100644 --- a/tokio/src/signal/registry.rs +++ b/tokio/src/signal/registry.rs @@ -1,4 +1,4 @@ -use crate::signal::os::{OsExtraData, OsStorage}; +use crate::signal::unix::{OsExtraData, OsStorage}; use crate::sync::watch; use std::ops; diff --git a/tokio/src/signal/windows.rs b/tokio/src/signal/windows.rs index 4c7e85901b5..085657117c1 100644 --- a/tokio/src/signal/windows.rs +++ b/tokio/src/signal/windows.rs @@ -16,9 +16,6 @@ use std::task::{Context, Poll}; #[path = "windows/sys.rs"] mod imp; -#[cfg(windows)] -pub(crate) use self::imp::{OsExtraData, OsStorage}; - // For building documentation on Unix machines when the `docsrs` flag is set. #[cfg(not(windows))] #[path = "windows/stub.rs"] diff --git a/tokio/src/signal/windows/sys.rs b/tokio/src/signal/windows/sys.rs index 9fe1261ff32..dda379978ca 100644 --- a/tokio/src/signal/windows/sys.rs +++ b/tokio/src/signal/windows/sys.rs @@ -1,35 +1,37 @@ use std::io; use std::sync::OnceLock; -use crate::signal::registry::{globals, EventId, EventInfo, Storage}; use crate::signal::RxFuture; +use crate::sync::watch; use windows_sys::core::BOOL; use windows_sys::Win32::System::Console as console; +type EventInfo = watch::Sender<()>; + pub(super) fn ctrl_break() -> io::Result { - new(console::CTRL_BREAK_EVENT) + new(®istry().ctrl_break) } pub(super) fn ctrl_close() -> io::Result { - new(console::CTRL_CLOSE_EVENT) + new(®istry().ctrl_close) } pub(super) fn ctrl_c() -> io::Result { - new(console::CTRL_C_EVENT) + new(®istry().ctrl_c) } pub(super) fn ctrl_logoff() -> io::Result { - new(console::CTRL_LOGOFF_EVENT) + new(®istry().ctrl_logoff) } pub(super) fn ctrl_shutdown() -> io::Result { - new(console::CTRL_SHUTDOWN_EVENT) + new(®istry().ctrl_shutdown) } -fn new(signum: u32) -> io::Result { +fn new(event_info: &EventInfo) -> io::Result { global_init()?; - let rx = globals().register_listener(signum as EventId); + let rx = event_info.subscribe(); Ok(RxFuture::new(rx)) } @@ -40,16 +42,14 @@ fn event_requires_infinite_sleep_in_handler(signum: u32) -> bool { // // For more information, see: // https://learn.microsoft.com/en-us/windows/console/handlerroutine#remarks - match signum { - console::CTRL_CLOSE_EVENT => true, - console::CTRL_LOGOFF_EVENT => true, - console::CTRL_SHUTDOWN_EVENT => true, - _ => false, - } + matches!( + signum, + console::CTRL_CLOSE_EVENT | console::CTRL_LOGOFF_EVENT | console::CTRL_SHUTDOWN_EVENT + ) } #[derive(Debug, Default)] -pub(crate) struct OsStorage { +struct Registry { ctrl_break: EventInfo, ctrl_close: EventInfo, ctrl_c: EventInfo, @@ -57,32 +57,24 @@ pub(crate) struct OsStorage { ctrl_shutdown: EventInfo, } -impl Storage for OsStorage { - fn event_info(&self, id: EventId) -> Option<&EventInfo> { - match u32::try_from(id) { - Ok(console::CTRL_BREAK_EVENT) => Some(&self.ctrl_break), - Ok(console::CTRL_CLOSE_EVENT) => Some(&self.ctrl_close), - Ok(console::CTRL_C_EVENT) => Some(&self.ctrl_c), - Ok(console::CTRL_LOGOFF_EVENT) => Some(&self.ctrl_logoff), - Ok(console::CTRL_SHUTDOWN_EVENT) => Some(&self.ctrl_shutdown), +impl Registry { + fn event_info(&self, signum: u32) -> Option<&EventInfo> { + match signum { + console::CTRL_BREAK_EVENT => Some(&self.ctrl_break), + console::CTRL_CLOSE_EVENT => Some(&self.ctrl_close), + console::CTRL_C_EVENT => Some(&self.ctrl_c), + console::CTRL_LOGOFF_EVENT => Some(&self.ctrl_logoff), + console::CTRL_SHUTDOWN_EVENT => Some(&self.ctrl_shutdown), _ => None, } } - - fn for_each<'a, F>(&'a self, mut f: F) - where - F: FnMut(&'a EventInfo), - { - f(&self.ctrl_break); - f(&self.ctrl_close); - f(&self.ctrl_c); - f(&self.ctrl_logoff); - f(&self.ctrl_shutdown); - } } -#[derive(Debug, Default)] -pub(crate) struct OsExtraData {} +fn registry() -> &'static Registry { + static REGISTRY: OnceLock = OnceLock::new(); + + REGISTRY.get_or_init(Default::default) +} fn global_init() -> io::Result<()> { static INIT: OnceLock>> = OnceLock::new(); @@ -104,27 +96,23 @@ fn global_init() -> io::Result<()> { } unsafe extern "system" fn handler(ty: u32) -> BOOL { - let globals = globals(); - globals.record_event(ty as EventId); + // Ignore unknown control signal types. + let Some(event_info) = registry().event_info(ty) else { + return 0; + }; - // According to https://docs.microsoft.com/en-us/windows/console/handlerroutine + // According to https://learn.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. - let event_was_handled = globals.broadcast(); - - if event_was_handled && event_requires_infinite_sleep_in_handler(ty) { - loop { + match event_info.send(()) { + Ok(_) if event_requires_infinite_sleep_in_handler(ty) => loop { std::thread::park(); - } - } - - if event_was_handled { - 1 - } else { + }, + Ok(_) => 1, // No one is listening for this notification any more // let the OS fire the next (possibly the default) handler. - 0 + Err(_) => 0, } }