#![cfg(all(unix, feature = "native"))]
#[cfg(target_os = "linux")]
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use nix::sys::signal::Signal;
use nix::unistd::Pid;
#[cfg(target_os = "linux")]
struct Pidfd(OwnedFd);
#[cfg(target_os = "linux")]
impl Pidfd {
fn open(pid: u32) -> std::io::Result<Self> {
#[allow(unsafe_code)]
let res = unsafe {
nix::libc::syscall(
nix::libc::SYS_pidfd_open,
pid as nix::libc::c_long,
0 as nix::libc::c_long,
)
};
if res < 0 {
return Err(std::io::Error::last_os_error());
}
#[allow(unsafe_code)]
let fd = unsafe { OwnedFd::from_raw_fd(res as i32) };
Ok(Self(fd))
}
fn send_signal(&self, sig: Signal) -> std::io::Result<()> {
#[allow(unsafe_code)]
let res = unsafe {
nix::libc::syscall(
nix::libc::SYS_pidfd_send_signal,
self.0.as_raw_fd() as nix::libc::c_long,
sig as nix::libc::c_int as nix::libc::c_long,
std::ptr::null::<nix::libc::siginfo_t>(),
0 as nix::libc::c_long,
)
};
if res < 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(())
}
}
}
pub struct KillTarget {
pid: Pid,
#[cfg(target_os = "linux")]
pidfd: Option<Pidfd>,
}
impl KillTarget {
pub fn from_child(child: &tokio::process::Child) -> Option<Self> {
let pid_raw = child.id()?;
Some(Self {
pid: Pid::from_raw(pid_raw as i32),
#[cfg(target_os = "linux")]
pidfd: Pidfd::open(pid_raw).ok(),
})
}
pub fn from_pid(pid: Pid) -> Self {
Self {
pid,
#[cfg(target_os = "linux")]
pidfd: {
let raw = pid.as_raw();
if raw > 0 {
Pidfd::open(raw as u32).ok()
} else {
None
}
},
}
}
pub fn signal(&self, sig: Signal) {
#[cfg(target_os = "linux")]
if let Some(pfd) = &self.pidfd {
let _ = pfd.send_signal(sig);
return;
}
let _ = nix::sys::signal::kill(self.pid, sig);
}
pub fn signal_pg(&self, sig: Signal) {
let _ = nix::sys::signal::killpg(self.pid, sig);
}
pub fn pid(&self) -> Pid {
self.pid
}
}