Skip to content

Commit fc2a014

Browse files
authored
Support SIGRTMIN+n signals. (#1292)
* Support `SIGRTMIN+n` signals. Change `Signal` from an `enum` to a `struct` wrapper around an `i32` so that it can accomodate values it doesn't know about statically, and add APIs for constructing and working with `SIGRTMIN+n` signal values. This requires making `Signal::from_raw` depend on a new "use-libc-sigrt" feature, as it depends on being able to call into libc. This also adds `Signal::from_raw_unchecked` which does not call into libc and is unsafe. Fixes #1249. * Add a `runtime::sigrt` function for constructing no-libc "realtime" signals. * Misc documentation cleanups.
1 parent 06cf043 commit fc2a014

13 files changed

Lines changed: 385 additions & 114 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ name = "mod"
8585
harness = false
8686

8787
[package.metadata.docs.rs]
88-
features = ["all-apis"]
88+
features = ["all-apis", "use-libc-sigrt"]
8989
targets = [
9090
"x86_64-unknown-linux-gnu",
9191
"i686-unknown-linux-gnu",
@@ -195,6 +195,9 @@ all-apis = [
195195
"time",
196196
]
197197

198+
# Enable `Signal::rt` and related features, which depend on libc.
199+
use-libc-sigrt = []
200+
198201
# When using the linux_raw backend, should we use libc for reading the aux
199202
# vectors, instead of reading them ourselves from /proc/self/auxv?
200203
use-libc-auxv = []

examples/kq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn main() -> std::io::Result<()> {
2222
#[cfg(feature = "process")]
2323
Event::new(
2424
EventFilter::Signal {
25-
signal: rustix::process::Signal::Info,
25+
signal: rustix::process::Signal::INFO,
2626
times: 0,
2727
},
2828
EventFlags::ADD,

src/backend/libc/process/syscalls.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ pub(crate) fn setsid() -> io::Result<Pid> {
523523
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
524524
#[inline]
525525
pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
526-
unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig as i32)) }
526+
unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig.as_raw())) }
527527
}
528528

529529
#[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<()> {
532532
unsafe {
533533
ret(c::kill(
534534
pid.as_raw_nonzero().get().wrapping_neg(),
535-
sig as i32,
535+
sig.as_raw(),
536536
))
537537
}
538538
}
539539

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

546546
#[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
600600
unsafe {
601601
ret(pidfd_send_signal(
602602
borrowed_fd(pidfd),
603-
sig as c::c_int,
603+
sig.as_raw(),
604604
core::ptr::null(),
605605
0,
606606
))

src/backend/linux_raw/conv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ pub(super) fn negative_pid<'a, Num: ArgNumber>(pid: Pid) -> ArgReg<'a, Num> {
709709
impl<'a, Num: ArgNumber> From<Signal> for ArgReg<'a, Num> {
710710
#[inline]
711711
fn from(sig: Signal) -> Self {
712-
pass_usize(sig as usize)
712+
pass_usize(sig.as_raw() as usize)
713713
}
714714
}
715715

src/backend/linux_raw/runtime/syscalls.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,13 @@ pub(crate) fn sigsuspend(set: &Sigset) -> io::Result<()> {
215215
#[inline]
216216
pub(crate) fn sigwait(set: &Sigset) -> io::Result<Signal> {
217217
unsafe {
218-
match Signal::from_raw(ret_c_int(syscall_readonly!(
218+
Ok(Signal::from_raw_unchecked(ret_c_int(syscall_readonly!(
219219
__NR_rt_sigtimedwait,
220220
by_ref(set),
221221
zero(),
222222
zero(),
223223
size_of::<kernel_sigset_t, _>()
224-
))?) {
225-
Some(signum) => Ok(signum),
226-
None => Err(io::Errno::NOTSUP),
227-
}
224+
))?))
228225
}
229226
}
230227

src/event/kqueue.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ impl Event {
3434
EventFilter::Proc { pid, flags } => {
3535
(Pid::as_raw(Some(pid)) as _, 0, c::EVFILT_PROC, flags.bits())
3636
}
37-
EventFilter::Signal { signal, times: _ } => (signal as _, 0, c::EVFILT_SIGNAL, 0),
37+
EventFilter::Signal { signal, times: _ } => {
38+
(signal.as_raw() as _, 0, c::EVFILT_SIGNAL, 0)
39+
}
3840
EventFilter::Timer { ident, timer } => {
3941
#[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))]
4042
let (data, fflags) = match timer {
@@ -118,7 +120,8 @@ impl Event {
118120
flags: ProcessEvents::from_bits_retain(self.inner.fflags),
119121
},
120122
c::EVFILT_SIGNAL => EventFilter::Signal {
121-
signal: Signal::from_raw(self.inner.ident as _).unwrap(),
123+
// SAFETY: `EventFilter::new` requires a valid `Signal`.
124+
signal: unsafe { Signal::from_raw_unchecked(self.inner.ident as _) },
122125
times: self.inner.data as _,
123126
},
124127
c::EVFILT_TIMER => EventFilter::Timer {

src/process/exit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ pub const EXIT_SUCCESS: i32 = backend::c::EXIT_SUCCESS;
2424
/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html
2525
pub const EXIT_FAILURE: i32 = backend::c::EXIT_FAILURE;
2626

27-
/// The exit status used by a process terminated with a [`Signal::Abort`]
27+
/// The exit status used by a process terminated with a [`Signal::ABORT`]
2828
/// signal.
2929
///
3030
/// # References
3131
/// - [Linux]
3232
///
3333
/// [Linux]: https://tldp.org/LDP/abs/html/exitcodes.html
34-
/// [`Signal::Abort`]: crate::process::Signal::Abort
34+
/// [`Signal::ABORT`]: crate::process::Signal::ABORT
3535
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
3636
pub const EXIT_SIGNALED_SIGABRT: i32 = backend::c::EXIT_SIGNALED_SIGABRT;

src/process/prctl.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![allow(unsafe_code)]
77

88
use core::mem::size_of;
9+
use core::num::NonZeroI32;
910
use core::ptr::{null, null_mut, NonNull};
1011

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

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

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

src/process/procctl.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#[cfg(feature = "alloc")]
99
use alloc::{vec, vec::Vec};
1010
use core::mem::MaybeUninit;
11+
use core::num::NonZeroI32;
1112
use core::ptr;
1213

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

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

@@ -419,7 +431,7 @@ pub fn reaper_kill(
419431
flags.set(KillFlags::CHILDREN, direct_children);
420432
flags.set(KillFlags::SUBTREE, subtree.is_some());
421433
let mut req = procctl_reaper_kill {
422-
rk_sig: signal as c_int,
434+
rk_sig: signal.as_raw(),
423435
rk_flags: flags.bits(),
424436
rk_subtree: subtree.map(|p| p.as_raw_nonzero().into()).unwrap_or(0),
425437
rk_killed: 0,

src/pty.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
156156
///
157157
/// On Linux, calling this function has no effect, as the kernel is expected to
158158
/// grant the appropriate access. On all other platforms, this function has
159-
/// unspecified behavior if the calling process has a [`Signal::Child`] signal
159+
/// unspecified behavior if the calling process has a [`Signal::CHILD`] signal
160160
/// handler installed.
161161
///
162162
/// # References
@@ -167,7 +167,7 @@ pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
167167
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/grantpt.html
168168
/// [Linux]: https://man7.org/linux/man-pages/man3/grantpt.3.html
169169
/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Allocation.html#index-grantpt
170-
/// [`Signal::Child`]: crate::process::Signal::Child
170+
/// [`Signal::CHILD`]: crate::process::Signal::CHILD
171171
#[inline]
172172
pub fn grantpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
173173
#[cfg(not(linux_kernel))]

0 commit comments

Comments
 (0)