From 97dcaba0cac63dd0aa58000f9a419bb7c8181d45 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 21 Jul 2024 07:26:49 +0000 Subject: [PATCH 1/2] mio option update proposal, for having haiku support mostly. --- Cargo.lock | 14 ++++++++++++++ signal-hook-mio/Cargo.toml | 2 ++ 2 files changed, 16 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 9c79706..8c99c42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,6 +660,19 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4929e1f84c5e54c3ec6141cd5d8b5a5c055f031f80cf78f2072920173cb4d880" +dependencies = [ + "hermit-abi", + "libc", + "log", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "mio-uds" version = "0.6.8" @@ -1027,6 +1040,7 @@ dependencies = [ "mio 0.6.23", "mio 0.7.14", "mio 0.8.11", + "mio 1.0.0", "mio-uds", "serial_test 0.5.1", "signal-hook", diff --git a/signal-hook-mio/Cargo.toml b/signal-hook-mio/Cargo.toml index 19d08f7..5df24fd 100644 --- a/signal-hook-mio/Cargo.toml +++ b/signal-hook-mio/Cargo.toml @@ -23,10 +23,12 @@ maintenance = { status = "actively-developed" } support-v0_6 = ["mio-0_6", "mio-uds"] support-v0_7 = ["mio-0_7"] support-v0_8 = ["mio-0_8"] +support-v1_0 = ["mio-1_0"] [dependencies] libc = "~0.2" signal-hook = { version = "~0.3", path = ".." } +mio-1_0 = { package = "mio", version = "~1.0", features = ["net", "os-ext"], optional = true } mio-0_8 = { package = "mio", version = "~0.8", features = ["net", "os-ext"], optional = true } mio-0_7 = { package = "mio", version = "~0.7", features = ["os-util", "uds"], optional = true } mio-0_6 = { package = "mio", version = "~0.6", optional = true } From 5a0b19a551a77cbfbc2460c92f393ac9fa50c209 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 24 Jul 2024 08:33:56 +0100 Subject: [PATCH 2/2] adding missing pieces --- signal-hook-mio/src/lib.rs | 96 ++++++++++++++++++++++++- signal-hook-mio/tests/mio_1_0.rs | 118 +++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 signal-hook-mio/tests/mio_1_0.rs diff --git a/signal-hook-mio/src/lib.rs b/signal-hook-mio/src/lib.rs index 215fdf7..2833f67 100644 --- a/signal-hook-mio/src/lib.rs +++ b/signal-hook-mio/src/lib.rs @@ -11,13 +11,15 @@ //! * `support-v0_6` for sub module [`v0_6`] //! * `support-v0_7` for sub module [`v0_7`] //! * `support-v0_8` for sub module [`v0_8`] +//! * `support-v0_8` for sub module [`v1_0`] //! //! See the specific sub modules for usage examples. #[cfg(any( feature = "support-v0_6", feature = "support-v0_7", - feature = "support-v0_8" + feature = "support-v0_8", + feature = "support-v1_0" ))] macro_rules! implement_signals_with_pipe { ($pipe:path) => { @@ -94,6 +96,98 @@ macro_rules! implement_signals_with_pipe { }; } +/// A module for integrating signal handling with the MIO 1.0 runtime. +/// +/// This provides the [`Signals`][v1_0::Signals] struct as an abstraction +/// which can be used with [`mio::Poll`][mio_1_0::Poll]. +/// +/// # Examples +/// +/// ```rust +/// # use mio_1_0 as mio; +/// use std::io::{Error, ErrorKind}; +/// +/// use signal_hook::consts::signal::*; +/// use signal_hook_mio::v1_0::Signals; +/// +/// use mio::{Events, Poll, Interest, Token}; +/// +/// fn main() -> Result<(), Error> { +/// let mut poll = Poll::new()?; +/// +/// let mut signals = Signals::new(&[ +/// SIGTERM, +/// # SIGUSR1, +/// ])?; +/// +/// let signal_token = Token(0); +/// +/// poll.registry().register(&mut signals, signal_token, Interest::READABLE)?; +/// # signal_hook::low_level::raise(SIGUSR1).unwrap(); // Just for terminating the example +/// +/// let mut events = Events::with_capacity(10); +/// 'outer: loop { +/// poll.poll(&mut events, None) +/// .or_else(|e| if e.kind() == ErrorKind::Interrupted { +/// // We get interrupt when a signal happens inside poll. That's non-fatal, just +/// // retry. +/// events.clear(); +/// Ok(()) +/// } else { +/// Err(e) +/// })?; +/// for event in events.iter() { +/// match event.token() { +/// Token(0) => { +/// for signal in signals.pending() { +/// match signal { +/// SIGTERM => break 'outer, +/// # SIGUSR1 => return Ok(()), +/// _ => unreachable!(), +/// } +/// } +/// }, +/// _ => unreachable!("Register other sources and match for their tokens here"), +/// } +/// } +/// } +/// +/// Ok(()) +/// } +/// ``` +#[cfg(feature = "support-v1_0")] +pub mod v1_0 { + use mio::event::Source; + use mio::{Interest, Registry, Token}; + use mio_1_0 as mio; + + implement_signals_with_pipe!(mio::net::UnixStream); + + impl Source for Signals { + fn register( + &mut self, + registry: &Registry, + token: Token, + interest: Interest, + ) -> Result<(), Error> { + self.0.get_read_mut().register(registry, token, interest) + } + + fn reregister( + &mut self, + registry: &Registry, + token: Token, + interest: Interest, + ) -> Result<(), Error> { + self.0.get_read_mut().reregister(registry, token, interest) + } + + fn deregister(&mut self, registry: &Registry) -> Result<(), Error> { + self.0.get_read_mut().deregister(registry) + } + } +} + /// A module for integrating signal handling with the MIO 0.8 runtime. /// /// This provides the [`Signals`][v0_8::Signals] struct as an abstraction diff --git a/signal-hook-mio/tests/mio_1_0.rs b/signal-hook-mio/tests/mio_1_0.rs new file mode 100644 index 0000000..ebc01a3 --- /dev/null +++ b/signal-hook-mio/tests/mio_1_0.rs @@ -0,0 +1,118 @@ +#![cfg(feature = "support-v1_0")] + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +use mio_1_0::{Events, Interest, Poll, Token}; + +use signal_hook::consts::{SIGUSR1, SIGUSR2}; +use signal_hook::low_level::raise; +use signal_hook_mio::v1_0::Signals; + +use serial_test::serial; + +use libc::c_int; + +#[test] +#[serial] +fn mio_wakeup() { + let mut signals = Signals::new(&[SIGUSR1]).unwrap(); + let mut poll = Poll::new().unwrap(); + let token = Token(0); + poll.registry() + .register(&mut signals, token, Interest::READABLE) + .unwrap(); + + let mut events = Events::with_capacity(10); + + // The self pipe shouldn't be readable yet + poll.poll(&mut events, Some(Duration::from_secs(0))) + .unwrap(); + assert!(events.is_empty()); + + raise(SIGUSR1).unwrap(); + poll.poll(&mut events, Some(Duration::from_secs(10))) + .unwrap(); + let event = events.iter().next().unwrap(); + + assert!(event.is_readable()); + assert_eq!(token, event.token()); + let sig = signals.pending().next().unwrap(); + assert_eq!(SIGUSR1, sig); + + // The self pipe shouldn't be readable after consuming signals + poll.poll(&mut events, Some(Duration::from_secs(0))) + .unwrap(); + assert!(events.is_empty()); +} + +#[test] +#[serial] +fn mio_multiple_signals() { + let mut signals = Signals::new(&[SIGUSR1, SIGUSR2]).unwrap(); + let mut poll = Poll::new().unwrap(); + let token = Token(0); + poll.registry() + .register(&mut signals, token, Interest::READABLE) + .unwrap(); + + let mut events = Events::with_capacity(10); + + raise(SIGUSR1).unwrap(); + raise(SIGUSR2).unwrap(); + + poll.poll(&mut events, Some(Duration::from_secs(10))) + .unwrap(); + + let event = events.iter().next().unwrap(); + assert!(event.is_readable()); + + let sigs: Vec = signals.pending().collect(); + assert_eq!(2, sigs.len()); + assert!(sigs.contains(&SIGUSR1)); + assert!(sigs.contains(&SIGUSR2)); + + // The self pipe shouldn't be completely empty after calling pending() + poll.poll(&mut events, Some(Duration::from_secs(0))) + .unwrap(); + assert!(events.is_empty()); +} + +#[test] +#[serial] +fn mio_parallel_multiple() { + let mut signals = Signals::new(&[SIGUSR1]).unwrap(); + let mut poll = Poll::new().unwrap(); + let token = Token(0); + poll.registry() + .register(&mut signals, token, Interest::READABLE) + .unwrap(); + + let mut events = Events::with_capacity(10); + + let thread_done = Arc::new(AtomicBool::new(false)); + + let done = Arc::clone(&thread_done); + thread::spawn(move || { + for _ in 0..10 { + // Wait some time to allow main thread to poll + thread::sleep(Duration::from_millis(25)); + raise(SIGUSR1).unwrap(); + } + done.store(true, Ordering::SeqCst); + + // Raise a final signal so the main thread wakes up + // if it already called poll. + raise(SIGUSR1).unwrap(); + }); + + while !thread_done.load(Ordering::SeqCst) { + poll.poll(&mut events, Some(Duration::from_secs(10))) + .unwrap(); + let event = events.iter().next().unwrap(); + assert!(event.is_readable()); + assert_eq!(SIGUSR1, signals.pending().next().unwrap()); + } +}