-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
1 parent
bfa8cad
commit aa7e0ce
Showing
4 changed files
with
120 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters