Skip to content

Commit c2ac564

Browse files
feat: pidfd_send_signal
1 parent bc6cf01 commit c2ac564

File tree

5 files changed

+77
-2
lines changed

5 files changed

+77
-2
lines changed

changelog/1868.added.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
- Added `pidfd_getfd` on Linux.
2-
- Added `pid_open` on Linux.
2+
- Added `pid_open` on Linux.
3+
- Added `pidfd_send_signal` on Linux.

src/sys/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,5 +224,5 @@ feature! {
224224
pub mod timer;
225225
}
226226

227-
#[cfg(all(target_os = "linux", feature = "process"))]
227+
#[cfg(all(target_os = "linux", feature = "signal", feature = "process"))]
228228
pub mod pidfd;

src/sys/pidfd.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! pidfd related functionality
22
33
use crate::errno::Errno;
4+
use crate::sys::signal::Signal;
45
use crate::unistd::Pid;
56
use crate::Result;
67
use std::convert::TryFrom;
@@ -70,3 +71,45 @@ pub fn pid_open(pid: Pid, nonblock: bool) -> Result<OwnedFd> {
7071
_ => unreachable!(),
7172
}
7273
}
74+
75+
/// Sends the signal `sig` to the target process referred to by `pid`, a PID file descriptor that
76+
/// refers to a process.
77+
///
78+
/// If the info argument is some [`libc::siginfo_t`] buffer, that buffer should be populated as
79+
/// described in [rt_sigqueueinfo(2)](https://man7.org/linux/man-pages/man2/rt_sigqueueinfo.2.html).
80+
///
81+
/// If the info argument is `None`, this is equivalent to specifying a pointer to a `siginfo_t`
82+
/// buffer whose fields match the values that are implicitly supplied when a signal is sent using
83+
/// [`crate::sys::signal::kill`]:
84+
///
85+
/// - `si_signo` is set to the signal number;
86+
/// - `si_errno` is set to 0;
87+
/// - `si_code` is set to SI_USER;
88+
/// - `si_pid` is set to the caller's PID; and
89+
/// - `si_uid` is set to the caller's real user ID.
90+
///
91+
/// The calling process must either be in the same PID namespace as the process referred to by
92+
/// pidfd, or be in an ancestor of that namespace.
93+
pub fn pidfd_send_signal<Fd: AsFd>(
94+
pid: Fd,
95+
sig: Signal,
96+
info: Option<libc::siginfo_t>,
97+
) -> Result<()> {
98+
let info = match info {
99+
Some(i) => &i,
100+
None => std::ptr::null(),
101+
};
102+
match unsafe {
103+
libc::syscall(
104+
libc::SYS_pidfd_send_signal,
105+
pid.as_fd().as_raw_fd(),
106+
sig as i32,
107+
info,
108+
0u32,
109+
)
110+
} {
111+
-1 => Err(Errno::last()),
112+
0 => Ok(()),
113+
_ => unreachable!(),
114+
}
115+
}

test/sys/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,6 @@ mod test_pthread;
5757
mod test_ptrace;
5858
#[cfg(any(target_os = "android", target_os = "linux"))]
5959
mod test_timerfd;
60+
61+
#[cfg(all(target_os = "linux", feature = "signal", feature = "process"))]
62+
pub mod test_pidfd;

test/sys/test_pidfd.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use nix::{
2+
sys::{
3+
pidfd::{pid_open, pidfd_send_signal},
4+
signal::Signal,
5+
signalfd::SigSet,
6+
wait::waitpid,
7+
},
8+
unistd::{fork, ForkResult},
9+
};
10+
11+
#[test]
12+
fn test_pidfd_send_signal() {
13+
match unsafe { fork().unwrap() } {
14+
ForkResult::Parent { child } => {
15+
// Send SIGUSR1
16+
let pid_fd = pid_open(child, false).unwrap();
17+
pidfd_send_signal(pid_fd, Signal::SIGUSR1, None).unwrap();
18+
// Wait for child to exit.
19+
waitpid(child, None).unwrap();
20+
}
21+
ForkResult::Child => {
22+
// Wait for SIGUSR1
23+
let mut mask = SigSet::empty();
24+
mask.add(Signal::SIGUSR1);
25+
assert_eq!(mask.wait().unwrap(), Signal::SIGUSR1);
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)