Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions src/uucore/src/lib/features/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,50 @@ pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
}
let signal_name = signal_name_upcase.trim_start_matches("SIG");

ALL_SIGNALS.iter().position(|&s| s == signal_name)
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
return try_parse_sigrt(signal_name_or_value)
.or_else(|| ALL_SIGNALS.iter().position(|&s| s == signal_name));
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
return ALL_SIGNALS.iter().position(|&s| s == signal_name);
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
/// Parses signals of the form RTMIN(+[0-9]\+)?|RTMAX(-[0-9]\+)?
fn try_parse_sigrt(signal_name: &str) -> Option<usize> {
realtime_signal_bounds()?;
if let Some(rest) = signal_name.strip_prefix("RTMIN") {
if rest.is_empty() {
Some(libc::SIGRTMIN() as usize)
} else if let Some(rest) = rest.strip_prefix("+")
&& let Ok(offset) = rest.parse::<usize>()
{
let value = libc::SIGRTMIN() as usize + offset;
if value <= libc::SIGRTMAX() as usize {
Some(value)
} else {
None
}
} else {
None
}
} else if let Some(rest) = signal_name.strip_prefix("RTMAX") {
if rest.is_empty() {
Some(libc::SIGRTMAX() as usize)
} else if let Some(rest) = rest.strip_prefix("-")
&& let Ok(offset) = rest.parse::<usize>()
{
let value = libc::SIGRTMAX() as usize - offset;
if value >= libc::SIGRTMIN() as usize {
Some(value)
} else {
None
}
} else {
None
}
} else {
None
}
}

/// Returns true if the given number is a valid signal number.
Expand All @@ -414,15 +457,15 @@ pub fn signal_name_by_value(signal_value: usize) -> Option<&'static str> {
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn realtime_signal_bounds() -> Option<(usize, usize)> {
pub fn realtime_signal_bounds() -> Option<(usize, usize)> {
let rtmin = libc::SIGRTMIN();
let rtmax = libc::SIGRTMAX();

(0 < rtmin && rtmin <= rtmax).then_some((rtmin as usize, rtmax as usize))
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn realtime_signal_bounds() -> Option<(usize, usize)> {
pub fn realtime_signal_bounds() -> Option<(usize, usize)> {
None
}

Expand Down
17 changes: 16 additions & 1 deletion tests/by-util/test_kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore IAMNOTASIGNAL RTMAX RTMIN SIGRTMAX
// spell-checker:ignore IAMNOTASIGNAL RTMAX RTMIN SIGRTMAX SIGRT SIGRTMIN SIGRTMAX
use regex::Regex;
use std::os::unix::process::ExitStatusExt;
use std::process::{Child, Command};
Expand Down Expand Up @@ -493,3 +493,18 @@ fn test_kill_signal_only_no_pid() {
.fails()
.stderr_contains("no process ID specified");
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_kill_with_signal_sigrt() {
if !uucore::os::is_wsl() && uucore::signals::realtime_signal_bounds().is_some() {
for signal in &["SIGRTMIN", "SIGRTMIN+1", "SIGRTMAX", "SIGRTMAX-1"] {
let target = Target::new();
new_ucmd!()
.arg("-s")
.arg(signal)
.arg(format!("{}", target.pid()))
.succeeds();
}
}
}
21 changes: 20 additions & 1 deletion tests/by-util/test_timeout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore dont
// spell-checker:ignore dont sigrt sigrtmin sigrtmax

use rstest::rstest;
use std::time::Duration;
Expand Down Expand Up @@ -286,3 +286,22 @@ fn test_foreground_signal0_kill_after() {
.args(&["--foreground", "-s0", "-k.1", ".1", "sleep", "10"])
.fails_with_code(137);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_timeout_sigrt() {
if !uucore::os::is_wsl() && uucore::signals::realtime_signal_bounds().is_some() {
new_ucmd!()
.args(&["-s", "SIGRTMIN", "0.1", "sleep", "2"])
.succeeds();
new_ucmd!()
.args(&["-s", "SIGRTMIN+1", "0.1", "sleep", "2"])
.succeeds();
new_ucmd!()
.args(&["-s", "SIGRTMAX", "0.1", "sleep", "2"])
.succeeds();
new_ucmd!()
.args(&["-s", "SIGRTMAX-1", "0.1", "sleep", "2"])
.succeeds();
}
}
Loading