diff --git a/tokio/src/signal/unix.rs b/tokio/src/signal/unix.rs index 59c0b5d9248..740a01fa284 100644 --- a/tokio/src/signal/unix.rs +++ b/tokio/src/signal/unix.rs @@ -23,13 +23,25 @@ pub(crate) type OsStorage = Box<[SignalInfo]>; impl Init for OsStorage { fn init() -> Self { // There are reliable signals ranging from 1 to 33 available on every Unix platform. - #[cfg(not(target_os = "linux"))] + #[cfg(not(any(target_os = "linux", target_os = "illumos")))] let possible = 0..=33; // On Linux, there are additional real-time signals available. #[cfg(target_os = "linux")] let possible = 0..=libc::SIGRTMAX(); + // On illumos, signal numbers go up to 41 (SIGINFO). The list of signals + // hasn't changed since 2013. See + // https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/sys/iso/signal_iso.h. + // + // illumos also has real-time signals, but this capability isn't exposed + // by libc as of 0.2.167, so we don't support them at the moment. Once + // https://github.com/rust-lang/libc/pull/4171 is merged and released in + // upstream libc, we should switch the illumos impl to do what Linux + // does. + #[cfg(target_os = "illumos")] + let possible = 0..=41; + possible.map(|_| SignalInfo::default()).collect() } } @@ -130,7 +142,8 @@ impl SignalKind { target_os = "freebsd", target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", + target_os = "illumos" ))] pub const fn info() -> Self { Self(libc::SIGINFO) diff --git a/tokio/tests/signal_info.rs b/tokio/tests/signal_info.rs new file mode 100644 index 00000000000..b297263f350 --- /dev/null +++ b/tokio/tests/signal_info.rs @@ -0,0 +1,43 @@ +#![warn(rust_2018_idioms)] +#![cfg(feature = "full")] +#![cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos" +))] +#![cfg(not(miri))] // No `sigaction` on Miri + +mod support { + pub mod signal; +} +use support::signal::send_signal; + +use tokio::signal; +use tokio::signal::unix::SignalKind; +use tokio::sync::oneshot; +use tokio::time::{timeout, Duration}; + +#[tokio::test] +async fn siginfo() { + let mut sig = signal::unix::signal(SignalKind::info()).expect("installed signal handler"); + + let (fire, wait) = oneshot::channel(); + + // NB: simulate a signal coming in by exercising our signal handler + // to avoid complications with sending SIGINFO to the test process + tokio::spawn(async { + wait.await.expect("wait failed"); + send_signal(libc::SIGINFO); + }); + + let _ = fire.send(()); + + // Add a timeout to ensure the test doesn't hang. + timeout(Duration::from_secs(5), sig.recv()) + .await + .expect("received SIGINFO signal in time") + .expect("received SIGINFO signal"); +}