Skip to content

Commit 011bb53

Browse files
committed
signal: remember the result of SetConsoleCtrlHandler
The unix implementation remembers whether it failed or not, so the windows implementation should do so as well. This PR also replaces the `(Once, AtomicState)` pair with `OnceLock` and tries to remember the original errno value.
1 parent 7a2135f commit 011bb53

2 files changed

Lines changed: 31 additions & 48 deletions

File tree

tokio/src/signal/unix.rs

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use crate::sync::watch;
1414

1515
use mio::net::UnixStream;
1616
use std::io::{self, Error, ErrorKind, Write};
17-
use std::sync::atomic::{AtomicBool, Ordering};
18-
use std::sync::Once;
17+
use std::sync::OnceLock;
1918
use std::task::{Context, Poll};
2019

2120
#[cfg(not(any(target_os = "linux", target_os = "illumos")))]
@@ -239,20 +238,10 @@ impl From<SignalKind> for std::os::raw::c_int {
239238
}
240239
}
241240

241+
#[derive(Default)]
242242
pub(crate) struct SignalInfo {
243243
event_info: EventInfo,
244-
init: Once,
245-
initialized: AtomicBool,
246-
}
247-
248-
impl Default for SignalInfo {
249-
fn default() -> SignalInfo {
250-
SignalInfo {
251-
event_info: EventInfo::default(),
252-
init: Once::new(),
253-
initialized: AtomicBool::new(false),
254-
}
255-
}
244+
init: OnceLock<Result<(), Option<i32>>>,
256245
}
257246

258247
/// Our global signal handler for all signals registered by this module.
@@ -294,26 +283,20 @@ fn signal_enable(signal: SignalKind, handle: &Handle) -> io::Result<()> {
294283
Some(slot) => slot,
295284
None => return Err(io::Error::new(io::ErrorKind::Other, "signal too large")),
296285
};
297-
let mut registered = Ok(());
298-
siginfo.init.call_once(|| {
299-
registered = unsafe {
300-
signal_hook_registry::register(signal, move || action(globals, signal)).map(|_| ())
301-
};
302-
if registered.is_ok() {
303-
siginfo.initialized.store(true, Ordering::Relaxed);
304-
}
305-
});
306-
registered?;
307-
// If the call_once failed, it won't be retried on the next attempt to register the signal. In
308-
// such case it is not run, registered is still `Ok(())`, initialized is still `false`.
309-
if siginfo.initialized.load(Ordering::Relaxed) {
310-
Ok(())
311-
} else {
312-
Err(Error::new(
313-
ErrorKind::Other,
314-
"Failed to register signal handler",
315-
))
316-
}
286+
287+
siginfo
288+
.init
289+
.get_or_init(|| {
290+
unsafe { signal_hook_registry::register(signal, move || action(globals, signal)) }
291+
.map(|_| ())
292+
.map_err(Error::raw_os_error)
293+
})
294+
.map_err(|e| {
295+
e.map_or_else(
296+
|| Error::new(ErrorKind::Other, "registering signal handler failed"),
297+
Error::from_raw_os_error,
298+
)
299+
})
317300
}
318301

319302
/// An listener for receiving a particular type of OS signal.

tokio/src/signal/windows/sys.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::io;
2-
use std::sync::Once;
2+
use std::sync::OnceLock;
33

44
use crate::signal::registry::{globals, EventId, EventInfo, Storage};
55
use crate::signal::RxFuture;
@@ -85,22 +85,22 @@ impl Storage for OsStorage {
8585
pub(crate) struct OsExtraData {}
8686

8787
fn global_init() -> io::Result<()> {
88-
static INIT: Once = Once::new();
88+
static INIT: OnceLock<Result<(), Option<i32>>> = OnceLock::new();
8989

90-
let mut init = None;
91-
92-
INIT.call_once(|| unsafe {
93-
let rc = console::SetConsoleCtrlHandler(Some(handler), 1);
94-
let ret = if rc == 0 {
95-
Err(io::Error::last_os_error())
90+
INIT.get_or_init(|| {
91+
let rc = unsafe { console::SetConsoleCtrlHandler(Some(handler), 1) };
92+
if rc == 0 {
93+
Err(io::Error::last_os_error().raw_os_error())
9694
} else {
9795
Ok(())
98-
};
99-
100-
init = Some(ret);
101-
});
102-
103-
init.unwrap_or_else(|| Ok(()))
96+
}
97+
})
98+
.map_err(|e| {
99+
e.map_or_else(
100+
|| io::Error::new(io::ErrorKind::Other, "registering signal handler failed"),
101+
io::Error::from_raw_os_error,
102+
)
103+
})
104104
}
105105

106106
unsafe extern "system" fn handler(ty: u32) -> BOOL {

0 commit comments

Comments
 (0)