Skip to content

Commit de761af

Browse files
committed
kill: allow using real-time signals
Right now it is not possible to send real-time signals using kill because the underlying nix::sys::signal code does not support real-time signals. Workaround this by using libc directly. With this, the "EXIT" workaround can be dropped, because we no longer need to convert to nix::sys::signal::Signal.
1 parent a920af1 commit de761af

2 files changed

Lines changed: 42 additions & 17 deletions

File tree

src/uu/kill/src/kill.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
// spell-checker:ignore (ToDO) signalname pids killpg
77

88
use clap::{Arg, ArgAction, Command};
9-
use nix::sys::signal::{self, Signal};
10-
use nix::unistd::Pid;
9+
use nix::errno::Errno;
10+
use nix::libc;
1111
use std::io::Error;
1212
use uucore::display::Quotable;
1313
use uucore::error::{FromIo, UResult, USimpleError};
1414
use uucore::translate;
1515

1616
use uucore::signals::{
1717
signal_by_name_or_value, signal_list_name_by_value, signal_list_value_by_name_or_number,
18-
signal_name_by_value, signal_number_upper_bound,
18+
signal_number_upper_bound,
1919
};
2020
use uucore::{format_usage, show};
2121

@@ -68,18 +68,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
6868
15_usize //SIGTERM
6969
};
7070

71-
let sig_name = signal_name_by_value(sig);
72-
// Signal does not support converting from EXIT
73-
// Instead, nix::signal::kill expects Option::None to properly handle EXIT
74-
let sig: Option<Signal> = if sig_name.is_some_and(|name| name == "EXIT") {
75-
None
76-
} else {
77-
let sig = (sig as i32)
78-
.try_into()
79-
.map_err(|e| Error::from_raw_os_error(e as i32))?;
80-
Some(sig)
81-
};
82-
8371
let pids = parse_pids(&pids_or_signals)?;
8472
if pids.is_empty() {
8573
Err(USimpleError::new(1, translate!("kill-error-no-process-id")))
@@ -250,9 +238,14 @@ fn parse_pids(pids: &[String]) -> UResult<Vec<i32>> {
250238
.collect()
251239
}
252240

253-
fn kill(sig: Option<Signal>, pids: &[i32]) {
241+
fn kill(sig: usize, pids: &[i32]) {
254242
for &pid in pids {
255-
if let Err(e) = signal::kill(Pid::from_raw(pid), sig) {
243+
let result = unsafe {
244+
let res = libc::kill(pid, sig as libc::c_int);
245+
Errno::result(res)
246+
};
247+
248+
if let Err(e) = result {
256249
show!(
257250
Error::from_raw_os_error(e as i32)
258251
.map_err_context(|| { translate!("kill-error-sending-signal", "pid" => pid) })

tests/by-util/test_kill.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use regex::Regex;
77
use std::os::unix::process::ExitStatusExt;
88
use std::process::{Child, Command};
9+
#[cfg(any(target_os = "linux", target_os = "android"))]
10+
use uucore::signals::realtime_signal_bounds;
911
use uutests::new_ucmd;
1012

1113
// A child process the tests will try to kill.
@@ -493,3 +495,33 @@ fn test_kill_signal_only_no_pid() {
493495
.fails()
494496
.stderr_contains("no process ID specified");
495497
}
498+
499+
#[cfg(any(target_os = "linux", target_os = "android"))]
500+
#[test]
501+
fn test_kill_with_rtmin_offset() {
502+
let (rtmin, _) = realtime_signal_bounds().unwrap();
503+
let sig: i32 = (rtmin as i32) + 7;
504+
505+
let mut target = Target::new();
506+
new_ucmd!()
507+
.arg("-s")
508+
.arg("SIGRTMIN+7")
509+
.arg(format!("{}", target.pid()))
510+
.succeeds();
511+
assert_eq!(target.wait_for_signal(), Some(sig));
512+
}
513+
514+
#[cfg(any(target_os = "linux", target_os = "android"))]
515+
#[test]
516+
fn test_kill_with_rtmax_offset() {
517+
let (_, rtmax) = realtime_signal_bounds().unwrap();
518+
let sig: i32 = (rtmax as i32) - 7;
519+
520+
let mut target = Target::new();
521+
new_ucmd!()
522+
.arg("-s")
523+
.arg("SIGRTMAX-7")
524+
.arg(format!("{}", target.pid()))
525+
.succeeds();
526+
assert_eq!(target.wait_for_signal(), Some(sig));
527+
}

0 commit comments

Comments
 (0)