1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
//! based on https://www.man7.org/linux/man-pages/man2/pidfd_open.2.html
#![cfg(target_os = "linux")]
use std::{
io,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
os::fd::{BorrowedFd, RawFd},
process::{Child, ExitStatus},
ptr,
};
use libc::{SYS_pidfd_open, syscall};
use nix::poll::{PollFd, PollFlags};
pub struct ChildWaiter {
fd: RawFd,
child: Child,
}
#[derive(Debug)]
struct PidFdOpenError;
impl std::fmt::Display for PidFdOpenError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "pid_fd_open")
}
}
impl std::error::Error for PidFdOpenError {}
impl ChildWaiter {
pub fn new(child: Child) -> io::Result<Self> {
let fd = unsafe { syscall(SYS_pidfd_open, child.id(), 0) };
if fd < 0 {
Err(io::Error::other(PidFdOpenError))
} else {
let fd = fd as RawFd;
Ok(Self { child, fd })
}
}
pub fn wait(&mut self, timeout_ms: u16) -> io::Result<Option<ExitStatus>> {
let mut poll_fds = [PollFd::new(
unsafe { BorrowedFd::borrow_raw(self.fd) },
PollFlags::POLLIN,
)];
let _ = nix::poll::poll(&mut poll_fds, timeout_ms);
self.child.try_wait()
}
pub fn into_inner(self) -> Child {
unsafe {
libc::close(self.fd);
}
let this = ManuallyDrop::new(self);
unsafe { ptr::read(&this.child) }
}
}
impl Deref for ChildWaiter {
type Target = Child;
fn deref(&self) -> &Self::Target {
&self.child
}
}
impl DerefMut for ChildWaiter {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.child
}
}
impl Drop for ChildWaiter {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
|