mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-09 00:00:08 +02:00
signal: specialize windows Registry (#7885)
This commit is contained in:
@@ -50,16 +50,9 @@ mod ctrl_c;
|
|||||||
#[cfg(feature = "signal")]
|
#[cfg(feature = "signal")]
|
||||||
pub use ctrl_c::ctrl_c;
|
pub use ctrl_c::ctrl_c;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
pub(crate) mod registry;
|
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 unix;
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::signal::os::{OsExtraData, OsStorage};
|
use crate::signal::unix::{OsExtraData, OsStorage};
|
||||||
use crate::sync::watch;
|
use crate::sync::watch;
|
||||||
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ use std::task::{Context, Poll};
|
|||||||
#[path = "windows/sys.rs"]
|
#[path = "windows/sys.rs"]
|
||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub(crate) use self::imp::{OsExtraData, OsStorage};
|
|
||||||
|
|
||||||
// For building documentation on Unix machines when the `docsrs` flag is set.
|
// For building documentation on Unix machines when the `docsrs` flag is set.
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
#[path = "windows/stub.rs"]
|
#[path = "windows/stub.rs"]
|
||||||
|
|||||||
@@ -1,35 +1,37 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use crate::signal::registry::{globals, EventId, EventInfo, Storage};
|
|
||||||
use crate::signal::RxFuture;
|
use crate::signal::RxFuture;
|
||||||
|
use crate::sync::watch;
|
||||||
|
|
||||||
use windows_sys::core::BOOL;
|
use windows_sys::core::BOOL;
|
||||||
use windows_sys::Win32::System::Console as console;
|
use windows_sys::Win32::System::Console as console;
|
||||||
|
|
||||||
|
type EventInfo = watch::Sender<()>;
|
||||||
|
|
||||||
pub(super) fn ctrl_break() -> io::Result<RxFuture> {
|
pub(super) fn ctrl_break() -> io::Result<RxFuture> {
|
||||||
new(console::CTRL_BREAK_EVENT)
|
new(®istry().ctrl_break)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ctrl_close() -> io::Result<RxFuture> {
|
pub(super) fn ctrl_close() -> io::Result<RxFuture> {
|
||||||
new(console::CTRL_CLOSE_EVENT)
|
new(®istry().ctrl_close)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ctrl_c() -> io::Result<RxFuture> {
|
pub(super) fn ctrl_c() -> io::Result<RxFuture> {
|
||||||
new(console::CTRL_C_EVENT)
|
new(®istry().ctrl_c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ctrl_logoff() -> io::Result<RxFuture> {
|
pub(super) fn ctrl_logoff() -> io::Result<RxFuture> {
|
||||||
new(console::CTRL_LOGOFF_EVENT)
|
new(®istry().ctrl_logoff)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ctrl_shutdown() -> io::Result<RxFuture> {
|
pub(super) fn ctrl_shutdown() -> io::Result<RxFuture> {
|
||||||
new(console::CTRL_SHUTDOWN_EVENT)
|
new(®istry().ctrl_shutdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(signum: u32) -> io::Result<RxFuture> {
|
fn new(event_info: &EventInfo) -> io::Result<RxFuture> {
|
||||||
global_init()?;
|
global_init()?;
|
||||||
let rx = globals().register_listener(signum as EventId);
|
let rx = event_info.subscribe();
|
||||||
Ok(RxFuture::new(rx))
|
Ok(RxFuture::new(rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,16 +42,14 @@ fn event_requires_infinite_sleep_in_handler(signum: u32) -> bool {
|
|||||||
//
|
//
|
||||||
// For more information, see:
|
// For more information, see:
|
||||||
// https://learn.microsoft.com/en-us/windows/console/handlerroutine#remarks
|
// https://learn.microsoft.com/en-us/windows/console/handlerroutine#remarks
|
||||||
match signum {
|
matches!(
|
||||||
console::CTRL_CLOSE_EVENT => true,
|
signum,
|
||||||
console::CTRL_LOGOFF_EVENT => true,
|
console::CTRL_CLOSE_EVENT | console::CTRL_LOGOFF_EVENT | console::CTRL_SHUTDOWN_EVENT
|
||||||
console::CTRL_SHUTDOWN_EVENT => true,
|
)
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct OsStorage {
|
struct Registry {
|
||||||
ctrl_break: EventInfo,
|
ctrl_break: EventInfo,
|
||||||
ctrl_close: EventInfo,
|
ctrl_close: EventInfo,
|
||||||
ctrl_c: EventInfo,
|
ctrl_c: EventInfo,
|
||||||
@@ -57,32 +57,24 @@ pub(crate) struct OsStorage {
|
|||||||
ctrl_shutdown: EventInfo,
|
ctrl_shutdown: EventInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Storage for OsStorage {
|
impl Registry {
|
||||||
fn event_info(&self, id: EventId) -> Option<&EventInfo> {
|
fn event_info(&self, signum: u32) -> Option<&EventInfo> {
|
||||||
match u32::try_from(id) {
|
match signum {
|
||||||
Ok(console::CTRL_BREAK_EVENT) => Some(&self.ctrl_break),
|
console::CTRL_BREAK_EVENT => Some(&self.ctrl_break),
|
||||||
Ok(console::CTRL_CLOSE_EVENT) => Some(&self.ctrl_close),
|
console::CTRL_CLOSE_EVENT => Some(&self.ctrl_close),
|
||||||
Ok(console::CTRL_C_EVENT) => Some(&self.ctrl_c),
|
console::CTRL_C_EVENT => Some(&self.ctrl_c),
|
||||||
Ok(console::CTRL_LOGOFF_EVENT) => Some(&self.ctrl_logoff),
|
console::CTRL_LOGOFF_EVENT => Some(&self.ctrl_logoff),
|
||||||
Ok(console::CTRL_SHUTDOWN_EVENT) => Some(&self.ctrl_shutdown),
|
console::CTRL_SHUTDOWN_EVENT => Some(&self.ctrl_shutdown),
|
||||||
_ => None,
|
_ => 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)]
|
fn registry() -> &'static Registry {
|
||||||
pub(crate) struct OsExtraData {}
|
static REGISTRY: OnceLock<Registry> = OnceLock::new();
|
||||||
|
|
||||||
|
REGISTRY.get_or_init(Default::default)
|
||||||
|
}
|
||||||
|
|
||||||
fn global_init() -> io::Result<()> {
|
fn global_init() -> io::Result<()> {
|
||||||
static INIT: OnceLock<Result<(), Option<i32>>> = OnceLock::new();
|
static INIT: OnceLock<Result<(), Option<i32>>> = OnceLock::new();
|
||||||
@@ -104,27 +96,23 @@ fn global_init() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn handler(ty: u32) -> BOOL {
|
unsafe extern "system" fn handler(ty: u32) -> BOOL {
|
||||||
let globals = globals();
|
// Ignore unknown control signal types.
|
||||||
globals.record_event(ty as EventId);
|
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
|
// 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
|
// have the same restrictions as in Unix signal handlers, meaning we can
|
||||||
// go ahead and perform the broadcast here.
|
// go ahead and perform the broadcast here.
|
||||||
let event_was_handled = globals.broadcast();
|
match event_info.send(()) {
|
||||||
|
Ok(_) if event_requires_infinite_sleep_in_handler(ty) => loop {
|
||||||
if event_was_handled && event_requires_infinite_sleep_in_handler(ty) {
|
|
||||||
loop {
|
|
||||||
std::thread::park();
|
std::thread::park();
|
||||||
}
|
},
|
||||||
}
|
Ok(_) => 1,
|
||||||
|
|
||||||
if event_was_handled {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
// No one is listening for this notification any more
|
// No one is listening for this notification any more
|
||||||
// let the OS fire the next (possibly the default) handler.
|
// let the OS fire the next (possibly the default) handler.
|
||||||
0
|
Err(_) => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user