mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-24 00:00:11 +02:00
signal: add support for realtime signals on illumos (#7029)
The API was added in libc 0.2.168. Also added a test for realtime signals.
This commit is contained in:
+2
-2
@@ -109,11 +109,11 @@ tracing = { version = "0.1.29", default-features = false, features = ["std"], op
|
||||
backtrace = { version = "0.3.58" }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = { version = "0.2.149", optional = true }
|
||||
libc = { version = "0.2.168", optional = true }
|
||||
signal-hook-registry = { version = "1.1.1", optional = true }
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
libc = { version = "0.2.149" }
|
||||
libc = { version = "0.2.168" }
|
||||
nix = { version = "0.29.0", default-features = false, features = ["aio", "fs", "socket"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows-sys]
|
||||
|
||||
@@ -26,22 +26,12 @@ impl Init for OsStorage {
|
||||
#[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")]
|
||||
// On Linux and illumos, there are additional real-time signals
|
||||
// available. (This is also likely true on Solaris, but this should be
|
||||
// verified before being enabled.)
|
||||
#[cfg(any(target_os = "linux", target_os = "illumos"))]
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg(feature = "full")]
|
||||
#![cfg(any(target_os = "linux", target_os = "illumos"))]
|
||||
#![cfg(not(miri))] // No `sigaction` in Miri.
|
||||
|
||||
mod support {
|
||||
pub mod signal;
|
||||
}
|
||||
|
||||
use libc::c_int;
|
||||
use support::signal::send_signal;
|
||||
|
||||
use futures::stream::{FuturesUnordered, StreamExt};
|
||||
use std::collections::HashMap;
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
use tokio::time::{sleep, Duration};
|
||||
use tokio_test::assert_ok;
|
||||
|
||||
#[tokio::test]
|
||||
async fn signal_realtime() {
|
||||
// Attempt to register a real-time signal for everything between SIGRTMIN
|
||||
// and SIGRTMAX.
|
||||
let signals = (libc::SIGRTMIN()..=sigrt_max())
|
||||
.map(|signum| {
|
||||
let sig = assert_ok!(
|
||||
signal(SignalKind::from_raw(signum)),
|
||||
"failed to create signal for {}",
|
||||
sigrtnum_to_string(signum),
|
||||
);
|
||||
(signum, sig)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
eprintln!(
|
||||
"registered {} signals in the range {}..={}",
|
||||
signals.len(),
|
||||
libc::SIGRTMIN(),
|
||||
libc::SIGRTMAX()
|
||||
);
|
||||
|
||||
// Now send signals to each of the registered signals.
|
||||
for signum in libc::SIGRTMIN()..=sigrt_max() {
|
||||
send_signal(signum);
|
||||
}
|
||||
|
||||
let futures = signals
|
||||
.into_iter()
|
||||
.map(|(signum, mut sig)| async move {
|
||||
let res = sig.recv().await;
|
||||
(signum, res)
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>();
|
||||
|
||||
// Ensure that all signals are received in time -- attempt to get whatever
|
||||
// we can.
|
||||
let sleep = std::pin::pin!(sleep(Duration::from_secs(5)));
|
||||
let done = futures.take_until(sleep).collect::<HashMap<_, _>>().await;
|
||||
|
||||
let mut none = Vec::new();
|
||||
let mut missing = Vec::new();
|
||||
for signum in libc::SIGRTMIN()..=sigrt_max() {
|
||||
match done.get(&signum) {
|
||||
Some(Some(())) => {}
|
||||
Some(None) => none.push(signum),
|
||||
None => missing.push(signum),
|
||||
}
|
||||
}
|
||||
|
||||
if none.is_empty() && missing.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut msg = String::new();
|
||||
if !none.is_empty() {
|
||||
msg.push_str("no signals received for:\n");
|
||||
for signum in none {
|
||||
msg.push_str(&format!("- {}\n", sigrtnum_to_string(signum)));
|
||||
}
|
||||
}
|
||||
|
||||
if !missing.is_empty() {
|
||||
msg.push_str("missing signals for:\n");
|
||||
for signum in missing {
|
||||
msg.push_str(&format!("- {}\n", sigrtnum_to_string(signum)));
|
||||
}
|
||||
}
|
||||
|
||||
panic!("{}", msg);
|
||||
}
|
||||
|
||||
fn sigrt_max() -> c_int {
|
||||
// Generally, you would expect this to be SIGRTMAX. But QEMU only supports
|
||||
// 28 real-time signals even though it might report SIGRTMAX to be higher.
|
||||
// See https://wiki.qemu.org/ChangeLog/9.2#signals.
|
||||
//
|
||||
// The goal of this test is to test that real-time signals are supported in
|
||||
// general, not necessarily that every single signal is supported (which, as
|
||||
// this example suggests, depends on the execution environment). So cap this
|
||||
// at SIGRTMIN+27 (i.e. SIGRTMIN..=SIGRTMIN+27, so 28 signals inclusive).
|
||||
libc::SIGRTMAX().min(libc::SIGRTMIN() + 27)
|
||||
}
|
||||
|
||||
fn sigrtnum_to_string(signum: i32) -> String {
|
||||
format!("SIGRTMIN+{} (signal {})", signum - libc::SIGRTMIN(), signum)
|
||||
}
|
||||
@@ -2,6 +2,14 @@ pub fn send_signal(signal: libc::c_int) {
|
||||
use libc::{getpid, kill};
|
||||
|
||||
unsafe {
|
||||
assert_eq!(kill(getpid(), signal), 0);
|
||||
let pid = getpid();
|
||||
assert_eq!(
|
||||
kill(pid, signal),
|
||||
0,
|
||||
"kill(pid = {}, {}) failed with error: {}",
|
||||
pid,
|
||||
signal,
|
||||
std::io::Error::last_os_error(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user