use super::lowlevel::{pidfd_send_signal, pidfd_try_wait, pidfd_wait};
use std::cell::OnceCell;
use std::io;
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use std::process::ExitStatus;
pub struct PidFd {
fd: OwnedFd,
exit_status: OnceCell<io::Result<ExitStatus>>,
}
impl PidFd {
fn new(fd: OwnedFd) -> Self {
Self {
fd,
exit_status: OnceCell::new(),
}
}
pub fn kill(&self) -> io::Result<()> {
pidfd_send_signal(self, libc::SIGKILL)
}
pub fn wait(&self) -> io::Result<ExitStatus> {
let status = self.exit_status.get_or_init(|| pidfd_wait(self));
match status {
Ok(v) => Ok(*v),
Err(e) => Err(io::Error::from_raw_os_error(e.raw_os_error().unwrap())),
}
}
pub fn try_wait(&self) -> io::Result<Option<ExitStatus>> {
pidfd_try_wait(self)
}
}
impl AsRawFd for PidFd {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}
impl FromRawFd for PidFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
unsafe { Self::new(OwnedFd::from_raw_fd(fd)) }
}
}
impl IntoRawFd for PidFd {
fn into_raw_fd(self) -> RawFd {
self.fd.into_raw_fd()
}
}
impl AsFd for PidFd {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}
impl From<OwnedFd> for PidFd {
fn from(fd: OwnedFd) -> Self {
Self::new(fd)
}
}
impl From<PidFd> for OwnedFd {
fn from(pid_fd: PidFd) -> Self {
pid_fd.fd
}
}