Skip to content

Commit cfd127a

Browse files
feat: pidfd_send_signal
1 parent 35ab211 commit cfd127a

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1515
([#1868](https://github.com/nix-rust/nix/pull/1868))
1616
- Added `pid_open` on Linux.
1717
([#1868](https://github.com/nix-rust/nix/pull/1868))
18+
- Added `pidfd_send_signal` on Linux.
19+
([#1868](https://github.com/nix-rust/nix/pull/1868))
1820

1921
### Changed
2022

src/sys/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,6 @@ feature! {
227227
pub mod timer;
228228
}
229229

230-
#[cfg(all(target_os = "linux", feature = "process"))]
230+
#[cfg(all(target_os = "linux", feature = "signal", feature = "process"))]
231231
/// pidfd related functionality
232232
pub mod pidfd;

src/sys/pidfd.rs

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

test/sys/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,6 @@ mod test_pthread;
5858
mod test_ptrace;
5959
#[cfg(any(target_os = "android", target_os = "linux"))]
6060
mod test_timerfd;
61+
62+
#[cfg(all(target_os = "linux", feature = "signal", feature = "process"))]
63+
pub mod test_pidfd;

test/sys/test_pidfd.rs

+28
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)