Skip to content

Commit d3cdf49

Browse files
committed
signal: add support for realtime signals on illumos
The API was added in libc 0.2.168. Also added a test for realtime signals.
1 parent bfa8cad commit d3cdf49

File tree

3 files changed

+104
-16
lines changed

3 files changed

+104
-16
lines changed

tokio/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ tracing = { version = "0.1.29", default-features = false, features = ["std"], op
109109
backtrace = { version = "0.3.58" }
110110

111111
[target.'cfg(unix)'.dependencies]
112-
libc = { version = "0.2.149", optional = true }
112+
libc = { version = "0.2.168", optional = true }
113113
signal-hook-registry = { version = "1.1.1", optional = true }
114114

115115
[target.'cfg(unix)'.dev-dependencies]
116-
libc = { version = "0.2.149" }
116+
libc = { version = "0.2.168" }
117117
nix = { version = "0.29.0", default-features = false, features = ["aio", "fs", "socket"] }
118118

119119
[target.'cfg(windows)'.dependencies.windows-sys]

tokio/src/signal/unix.rs

+4-14
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,12 @@ impl Init for OsStorage {
2626
#[cfg(not(any(target_os = "linux", target_os = "illumos")))]
2727
let possible = 0..=33;
2828

29-
// On Linux, there are additional real-time signals available.
30-
#[cfg(target_os = "linux")]
29+
// On Linux and illumos, there are additional real-time signals
30+
// available. (This is also likely true on Solaris, but this should be
31+
// verified before being enabled.)
32+
#[cfg(any(target_os = "linux", target_os = "illumos"))]
3133
let possible = 0..=libc::SIGRTMAX();
3234

33-
// On illumos, signal numbers go up to 41 (SIGINFO). The list of signals
34-
// hasn't changed since 2013. See
35-
// https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/sys/iso/signal_iso.h.
36-
//
37-
// illumos also has real-time signals, but this capability isn't exposed
38-
// by libc as of 0.2.167, so we don't support them at the moment. Once
39-
// https://github.com/rust-lang/libc/pull/4171 is merged and released in
40-
// upstream libc, we should switch the illumos impl to do what Linux
41-
// does.
42-
#[cfg(target_os = "illumos")]
43-
let possible = 0..=41;
44-
4535
possible.map(|_| SignalInfo::default()).collect()
4636
}
4737
}

tokio/tests/signal_realtime.rs

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#![warn(rust_2018_idioms)]
2+
#![cfg(feature = "full")]
3+
#![cfg(any(target_os = "linux", target_os = "illumos"))]
4+
#![cfg(not(miri))] // No `sigaction` in Miri.
5+
6+
mod support {
7+
pub mod signal;
8+
}
9+
10+
use support::signal::send_signal;
11+
12+
use futures::stream::{FuturesUnordered, StreamExt};
13+
use std::collections::HashMap;
14+
use tokio::signal::unix::{signal, SignalKind};
15+
use tokio::time::{sleep, Duration};
16+
use tokio_test::assert_ok;
17+
18+
#[tokio::test]
19+
async fn signal_realtime() {
20+
// Attempt to register a real-time signal for everything between SIGRTMIN
21+
// and SIGRTMAX.
22+
let signals = (libc::SIGRTMIN()..=libc::SIGRTMAX())
23+
.into_iter()
24+
.map(|signum| {
25+
let sig = assert_ok!(
26+
signal(SignalKind::from_raw(signum)),
27+
"failed to create signal for SIGRTMIN+{} (signal {})",
28+
signum - libc::SIGRTMIN(),
29+
signum
30+
);
31+
(signum, sig)
32+
})
33+
.collect::<Vec<_>>();
34+
35+
eprintln!(
36+
"registered {} signals in the range {}..={}",
37+
signals.len(),
38+
libc::SIGRTMIN(),
39+
libc::SIGRTMAX()
40+
);
41+
42+
// Now send signals to each of the registered signals.
43+
for signum in libc::SIGRTMIN()..=libc::SIGRTMAX() {
44+
send_signal(signum);
45+
}
46+
47+
let futures = signals
48+
.into_iter()
49+
.map(|(signum, mut sig)| async move {
50+
let res = sig.recv().await;
51+
(signum, res)
52+
})
53+
.collect::<FuturesUnordered<_>>();
54+
55+
// Ensure that all signals are received in time -- attempt to get whatever
56+
// we can.
57+
let sleep = std::pin::pin!(sleep(Duration::from_secs(5)));
58+
let done = futures.take_until(sleep).collect::<HashMap<_, _>>().await;
59+
60+
let mut none = Vec::new();
61+
let mut missing = Vec::new();
62+
for signum in libc::SIGRTMIN()..=libc::SIGRTMAX() {
63+
match done.get(&signum) {
64+
Some(Some(())) => {}
65+
Some(None) => none.push(signum),
66+
None => missing.push(signum),
67+
}
68+
}
69+
70+
if none.is_empty() && missing.is_empty() {
71+
return;
72+
}
73+
74+
let mut msg = String::new();
75+
if !none.is_empty() {
76+
msg.push_str("no signals received for:\n");
77+
for signum in none {
78+
msg.push_str(&format!(
79+
"- SIGRTMIN+{} (signal {})\n",
80+
signum - libc::SIGRTMIN(),
81+
signum
82+
));
83+
}
84+
}
85+
86+
if !missing.is_empty() {
87+
msg.push_str("missing signals for:\n");
88+
for signum in missing {
89+
msg.push_str(&format!(
90+
"- SIGRTMIN+{} (signal {})\n",
91+
signum - libc::SIGRTMIN(),
92+
signum
93+
));
94+
}
95+
}
96+
97+
panic!("{}", msg);
98+
}

0 commit comments

Comments
 (0)