Skip to content

Support SIGRTMIN+n signals. #1292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 28, 2025
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -85,7 +85,7 @@ name = "mod"
harness = false

[package.metadata.docs.rs]
features = ["all-apis"]
features = ["all-apis", "use-libc-sigrt"]
targets = [
"x86_64-unknown-linux-gnu",
"i686-unknown-linux-gnu",
@@ -195,6 +195,9 @@ all-apis = [
"time",
]

# Enable `Signal::rt` and related features, which depend on libc.
use-libc-sigrt = []

# When using the linux_raw backend, should we use libc for reading the aux
# vectors, instead of reading them ourselves from /proc/self/auxv?
use-libc-auxv = []
2 changes: 1 addition & 1 deletion examples/kq.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ fn main() -> std::io::Result<()> {
#[cfg(feature = "process")]
Event::new(
EventFilter::Signal {
signal: rustix::process::Signal::Info,
signal: rustix::process::Signal::INFO,
times: 0,
},
EventFlags::ADD,
8 changes: 4 additions & 4 deletions src/backend/libc/process/syscalls.rs
Original file line number Diff line number Diff line change
@@ -523,7 +523,7 @@ pub(crate) fn setsid() -> io::Result<Pid> {
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
#[inline]
pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig as i32)) }
unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig.as_raw())) }
}

#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
@@ -532,15 +532,15 @@ pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> {
unsafe {
ret(c::kill(
pid.as_raw_nonzero().get().wrapping_neg(),
sig as i32,
sig.as_raw(),
))
}
}

#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
#[inline]
pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> {
unsafe { ret(c::kill(0, sig as i32)) }
unsafe { ret(c::kill(0, sig.as_raw())) }
}

#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
@@ -600,7 +600,7 @@ pub(crate) fn pidfd_send_signal(pidfd: BorrowedFd<'_>, sig: Signal) -> io::Resul
unsafe {
ret(pidfd_send_signal(
borrowed_fd(pidfd),
sig as c::c_int,
sig.as_raw(),
core::ptr::null(),
0,
))
2 changes: 1 addition & 1 deletion src/backend/linux_raw/conv.rs
Original file line number Diff line number Diff line change
@@ -709,7 +709,7 @@ pub(super) fn negative_pid<'a, Num: ArgNumber>(pid: Pid) -> ArgReg<'a, Num> {
impl<'a, Num: ArgNumber> From<Signal> for ArgReg<'a, Num> {
#[inline]
fn from(sig: Signal) -> Self {
pass_usize(sig as usize)
pass_usize(sig.as_raw() as usize)
}
}

7 changes: 2 additions & 5 deletions src/backend/linux_raw/runtime/syscalls.rs
Original file line number Diff line number Diff line change
@@ -215,16 +215,13 @@ pub(crate) fn sigsuspend(set: &Sigset) -> io::Result<()> {
#[inline]
pub(crate) fn sigwait(set: &Sigset) -> io::Result<Signal> {
unsafe {
match Signal::from_raw(ret_c_int(syscall_readonly!(
Ok(Signal::from_raw_unchecked(ret_c_int(syscall_readonly!(
__NR_rt_sigtimedwait,
by_ref(set),
zero(),
zero(),
size_of::<kernel_sigset_t, _>()
))?) {
Some(signum) => Ok(signum),
None => Err(io::Errno::NOTSUP),
}
))?))
}
}

7 changes: 5 additions & 2 deletions src/event/kqueue.rs
Original file line number Diff line number Diff line change
@@ -34,7 +34,9 @@ impl Event {
EventFilter::Proc { pid, flags } => {
(Pid::as_raw(Some(pid)) as _, 0, c::EVFILT_PROC, flags.bits())
}
EventFilter::Signal { signal, times: _ } => (signal as _, 0, c::EVFILT_SIGNAL, 0),
EventFilter::Signal { signal, times: _ } => {
(signal.as_raw() as _, 0, c::EVFILT_SIGNAL, 0)
}
EventFilter::Timer { ident, timer } => {
#[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))]
let (data, fflags) = match timer {
@@ -118,7 +120,8 @@ impl Event {
flags: ProcessEvents::from_bits_retain(self.inner.fflags),
},
c::EVFILT_SIGNAL => EventFilter::Signal {
signal: Signal::from_raw(self.inner.ident as _).unwrap(),
// SAFETY: `EventFilter::new` requires a valid `Signal`.
signal: unsafe { Signal::from_raw_unchecked(self.inner.ident as _) },
times: self.inner.data as _,
},
c::EVFILT_TIMER => EventFilter::Timer {
4 changes: 2 additions & 2 deletions src/process/exit.rs
Original file line number Diff line number Diff line change
@@ -24,13 +24,13 @@ pub const EXIT_SUCCESS: i32 = backend::c::EXIT_SUCCESS;
/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html
pub const EXIT_FAILURE: i32 = backend::c::EXIT_FAILURE;

/// The exit status used by a process terminated with a [`Signal::Abort`]
/// The exit status used by a process terminated with a [`Signal::ABORT`]
/// signal.
///
/// # References
/// - [Linux]
///
/// [Linux]: https://tldp.org/LDP/abs/html/exitcodes.html
/// [`Signal::Abort`]: crate::process::Signal::Abort
/// [`Signal::ABORT`]: crate::process::Signal::ABORT
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
pub const EXIT_SIGNALED_SIGABRT: i32 = backend::c::EXIT_SIGNALED_SIGABRT;
18 changes: 15 additions & 3 deletions src/process/prctl.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
#![allow(unsafe_code)]

use core::mem::size_of;
use core::num::NonZeroI32;
use core::ptr::{null, null_mut, NonNull};

use bitflags::bitflags;
@@ -36,7 +37,18 @@ const PR_GET_PDEATHSIG: c_int = 2;
#[inline]
#[doc(alias = "PR_GET_PDEATHSIG")]
pub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG) }.map(Signal::from_raw)
let raw = unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG)? };
if let Some(non_zero) = NonZeroI32::new(raw) {
// SAFETY: The only way to get a libc-reserved signal number in
// here would be to do something equivalent to
// `set_parent_process_death_signal`, but that would have required
// using a `Signal` with a libc-reserved value.
Ok(Some(unsafe {
Signal::from_raw_nonzero_unchecked(non_zero)
}))
} else {
Ok(None)
}
}

const PR_SET_PDEATHSIG: c_int = 1;
@@ -52,7 +64,7 @@ const PR_SET_PDEATHSIG: c_int = 1;
#[inline]
#[doc(alias = "PR_SET_PDEATHSIG")]
pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
let signal = signal.map_or(0_usize, |signal| signal as usize);
let signal = signal.map_or(0_usize, |signal| signal.as_raw() as usize);
unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ())
}

@@ -436,7 +448,7 @@ const PR_TSC_SIGSEGV: u32 = 2;
pub enum TimeStampCounterReadability {
/// Allow the use of the timestamp counter.
Readable = PR_TSC_ENABLE,
/// Throw a [`Signal::Segv`] signal instead of reading the TSC.
/// Throw a [`Signal::SEGV`] signal instead of reading the TSC.
RaiseSIGSEGV = PR_TSC_SIGSEGV,
}

18 changes: 15 additions & 3 deletions src/process/procctl.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
#[cfg(feature = "alloc")]
use alloc::{vec, vec::Vec};
use core::mem::MaybeUninit;
use core::num::NonZeroI32;
use core::ptr;

use bitflags::bitflags;
@@ -92,7 +93,18 @@ const PROC_PDEATHSIG_STATUS: c_int = 12;
/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,…)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
#[inline]
pub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
unsafe { procctl_get_optional::<c_int>(PROC_PDEATHSIG_STATUS, None) }.map(Signal::from_raw)
let raw = unsafe { procctl_get_optional::<c_int>(PROC_PDEATHSIG_STATUS, None) }?;
if let Some(non_zero) = NonZeroI32::new(raw) {
// SAFETY: The only way to get a libc-reserved signal number in
// here would be to do something equivalent to
// `set_parent_process_death_signal`, but that would have required
// using a `Signal` with a libc-reserved value.
Ok(Some(unsafe {
Signal::from_raw_nonzero_unchecked(non_zero)
}))
} else {
Ok(None)
}
}

const PROC_PDEATHSIG_CTL: c_int = 11;
@@ -107,7 +119,7 @@ const PROC_PDEATHSIG_CTL: c_int = 11;
/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,…)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
#[inline]
pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
let signal = signal.map_or(0, |signal| signal as c_int);
let signal = signal.map_or(0, |signal| signal.as_raw());
unsafe { procctl_set::<c_int>(PROC_PDEATHSIG_CTL, None, &signal) }
}

@@ -419,7 +431,7 @@ pub fn reaper_kill(
flags.set(KillFlags::CHILDREN, direct_children);
flags.set(KillFlags::SUBTREE, subtree.is_some());
let mut req = procctl_reaper_kill {
rk_sig: signal as c_int,
rk_sig: signal.as_raw(),
rk_flags: flags.bits(),
rk_subtree: subtree.map(|p| p.as_raw_nonzero().into()).unwrap_or(0),
rk_killed: 0,
4 changes: 2 additions & 2 deletions src/pty.rs
Original file line number Diff line number Diff line change
@@ -156,7 +156,7 @@ pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
///
/// On Linux, calling this function has no effect, as the kernel is expected to
/// grant the appropriate access. On all other platforms, this function has
/// unspecified behavior if the calling process has a [`Signal::Child`] signal
/// unspecified behavior if the calling process has a [`Signal::CHILD`] signal
/// handler installed.
///
/// # References
@@ -167,7 +167,7 @@ pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/grantpt.html
/// [Linux]: https://man7.org/linux/man-pages/man3/grantpt.3.html
/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Allocation.html#index-grantpt
/// [`Signal::Child`]: crate::process::Signal::Child
/// [`Signal::CHILD`]: crate::process::Signal::CHILD
#[inline]
pub fn grantpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
#[cfg(not(linux_kernel))]
53 changes: 44 additions & 9 deletions src/runtime.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,10 @@
//!
//! - Some of the functions in this module cannot be used in a process which
//! also has a libc present. This can be true even for functions that have
//! the same name as a libc function that Rust code can use.
//! the same name as a libc function that Rust code can use. Such functions
//! are not marked `unsafe` (unless they are unsafe for other reasons), even
//! though they invoke Undefined Behavior if called in a process which has a
//! libc present.
//!
//! - Some of the functions in this module don't behave exactly the same way
//! as functions in libc with similar names. Sometimes information about the
@@ -62,7 +65,13 @@ pub type Sigaction = linux_raw_sys::general::kernel_sigaction;
#[cfg(linux_raw)]
pub type Stack = linux_raw_sys::general::stack_t;

/// `sigset_t`
/// `sigset_t`.
///
/// Undefined behavior could happen in some functions if `Sigset` ever
/// contains signal numbers in the range from
/// `linux_raw_sys::general::SIGRTMIN` to what the libc thinks `SIGRTMIN` is.
/// Unless you are implementing the libc. Which you may indeed be doing, if
/// you're reading this.
#[cfg(linux_raw)]
pub type Sigset = linux_raw_sys::general::kernel_sigset_t;

@@ -560,26 +569,31 @@ pub fn linux_secure() -> bool {
///
/// This is not identical to `brk` in libc. libc `brk` may have bookkeeping
/// that needs to be kept up to date that this doesn't keep up to date, so
/// don't use it unless you are implementing libc.
/// don't use it unless you know your code won't share a process with a libc
/// (perhaps because you yourself are implementing a libc).
#[cfg(linux_raw)]
#[inline]
pub unsafe fn brk(addr: *mut c_void) -> io::Result<*mut c_void> {
backend::runtime::syscalls::brk(addr)
}

/// `__SIGRTMIN`—The start of the realtime signal range.
/// `SIGRTMIN`—The start of the raw OS “real-time” signal range.
///
/// This is the raw `SIGRTMIN` value from the OS, which is not the same as the
/// `SIGRTMIN` macro provided by libc. Don't use this unless you are
/// implementing libc.
/// `SIGRTMIN` macro provided by libc. Don't use this unless you know your code
/// won't share a process with a libc (perhaps because you yourself are
/// implementing a libc).
///
/// See [`sigrt`] for a convenient way to construct `SIGRTMIN + n` values.
#[cfg(linux_raw)]
pub const SIGRTMIN: u32 = linux_raw_sys::general::SIGRTMIN;

/// `__SIGRTMAX`—The last of the realtime signal range.
/// `SIGRTMAX`—The last of the raw OS “real-time” signal range.
///
/// This is the raw `SIGRTMAX` value from the OS, which is not the same as the
/// `SIGRTMAX` macro provided by libc. Don't use this unless you are
/// implementing libc.
/// `SIGRTMAX` macro provided by libc. Don't use this unless you know your code
/// won't share a process with a libc (perhaps because you yourself are
/// implementing a libc).
#[cfg(linux_raw)]
pub const SIGRTMAX: u32 = {
// Use the actual `SIGRTMAX` value on platforms which define it.
@@ -604,3 +618,24 @@ pub const SIGRTMAX: u32 = {
linux_raw_sys::general::_NSIG - 1
}
};

/// Return a [`Signal`] corresponding to `SIGRTMIN + n`.
///
/// This is similar to [`Signal::rt`], but uses the raw OS `SIGRTMIN` value
/// instead of the libc `SIGRTMIN` value. Don't use this unless you know your
/// code won't share a process with a libc (perhaps because you yourself are
/// implementing a libc).
#[cfg(linux_raw)]
#[doc(alias = "SIGRTMIN")]
pub fn sigrt(n: u32) -> Option<Signal> {
let sig = SIGRTMIN.wrapping_add(n);
if (SIGRTMIN..=SIGRTMAX).contains(&sig) {
// SAFETY: We've checked that `sig` is in the expected range. It could
// still conflict with libc's reserved values, however users of the
// `runtime` module here must already know that there's no other libc
// to conflict with.
Some(unsafe { Signal::from_raw_unchecked(sig as i32) })
} else {
None
}
}
Loading