Skip to content

Commit

Permalink
feat: pidfd_send_signal
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanWoollett-Light committed Nov 16, 2023
1 parent bc6cf01 commit c2ac564
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 2 deletions.
3 changes: 2 additions & 1 deletion changelog/1868.added.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
- Added `pidfd_getfd` on Linux.
- Added `pid_open` on Linux.
- Added `pid_open` on Linux.
- Added `pidfd_send_signal` on Linux.
2 changes: 1 addition & 1 deletion src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,5 +224,5 @@ feature! {
pub mod timer;
}

#[cfg(all(target_os = "linux", feature = "process"))]
#[cfg(all(target_os = "linux", feature = "signal", feature = "process"))]
pub mod pidfd;
43 changes: 43 additions & 0 deletions src/sys/pidfd.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! pidfd related functionality
use crate::errno::Errno;
use crate::sys::signal::Signal;
use crate::unistd::Pid;
use crate::Result;
use std::convert::TryFrom;
Expand Down Expand Up @@ -70,3 +71,45 @@ pub fn pid_open(pid: Pid, nonblock: bool) -> Result<OwnedFd> {
_ => unreachable!(),
}
}

/// Sends the signal `sig` to the target process referred to by `pid`, a PID file descriptor that
/// refers to a process.
///
/// If the info argument is some [`libc::siginfo_t`] buffer, that buffer should be populated as
/// described in [rt_sigqueueinfo(2)](https://man7.org/linux/man-pages/man2/rt_sigqueueinfo.2.html).
///
/// If the info argument is `None`, this is equivalent to specifying a pointer to a `siginfo_t`
/// buffer whose fields match the values that are implicitly supplied when a signal is sent using
/// [`crate::sys::signal::kill`]:
///
/// - `si_signo` is set to the signal number;
/// - `si_errno` is set to 0;
/// - `si_code` is set to SI_USER;
/// - `si_pid` is set to the caller's PID; and
/// - `si_uid` is set to the caller's real user ID.
///
/// The calling process must either be in the same PID namespace as the process referred to by
/// pidfd, or be in an ancestor of that namespace.
pub fn pidfd_send_signal<Fd: AsFd>(
pid: Fd,
sig: Signal,
info: Option<libc::siginfo_t>,
) -> Result<()> {
let info = match info {
Some(i) => &i,
None => std::ptr::null(),
};
match unsafe {
libc::syscall(
libc::SYS_pidfd_send_signal,
pid.as_fd().as_raw_fd(),
sig as i32,
info,
0u32,
)
} {
-1 => Err(Errno::last()),
0 => Ok(()),
_ => unreachable!(),
}
}
3 changes: 3 additions & 0 deletions test/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ mod test_pthread;
mod test_ptrace;
#[cfg(any(target_os = "android", target_os = "linux"))]
mod test_timerfd;

#[cfg(all(target_os = "linux", feature = "signal", feature = "process"))]
pub mod test_pidfd;
28 changes: 28 additions & 0 deletions test/sys/test_pidfd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use nix::{
sys::{
pidfd::{pid_open, pidfd_send_signal},
signal::Signal,
signalfd::SigSet,
wait::waitpid,
},
unistd::{fork, ForkResult},
};

#[test]
fn test_pidfd_send_signal() {
match unsafe { fork().unwrap() } {
ForkResult::Parent { child } => {
// Send SIGUSR1
let pid_fd = pid_open(child, false).unwrap();
pidfd_send_signal(pid_fd, Signal::SIGUSR1, None).unwrap();
// Wait for child to exit.
waitpid(child, None).unwrap();
}
ForkResult::Child => {
// Wait for SIGUSR1
let mut mask = SigSet::empty();
mask.add(Signal::SIGUSR1);
assert_eq!(mask.wait().unwrap(), Signal::SIGUSR1);
}
}
}

0 comments on commit c2ac564

Please sign in to comment.