std/sys/pal/unix/linux/
pidfd.rs1use crate::io;
2use crate::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
3use crate::sys::fd::FileDesc;
4use crate::sys::process::ExitStatus;
5use crate::sys::{AsInner, FromInner, IntoInner, cvt};
6
7#[cfg(test)]
8mod tests;
9
10#[derive(Debug)]
11pub(crate) struct PidFd(FileDesc);
12
13impl PidFd {
14 pub fn kill(&self) -> io::Result<()> {
15 self.send_signal(libc::SIGKILL)
16 }
17
18 #[cfg(any(test, target_env = "gnu", target_env = "musl"))]
19 pub(crate) fn current_process() -> io::Result<PidFd> {
20 let pid = crate::process::id();
21 let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, pid, 0) })?;
22 Ok(unsafe { PidFd::from_raw_fd(pidfd as RawFd) })
23 }
24
25 #[cfg(any(test, target_env = "gnu", target_env = "musl"))]
26 pub(crate) fn pid(&self) -> io::Result<u32> {
27 use crate::sys::weak::weak;
28
29 let mut pidfd_info: libc::pidfd_info = unsafe { crate::mem::zeroed() };
32 pidfd_info.mask = libc::PIDFD_INFO_PID as u64;
33 match cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) })
34 {
35 Ok(_) => {}
36 Err(e) if e.raw_os_error() == Some(libc::EINVAL) => {
37 weak!(
39 fn pidfd_getpid(pidfd: RawFd) -> libc::pid_t;
40 );
41 if let Some(pidfd_getpid) = pidfd_getpid.get() {
42 let pid: libc::c_int = cvt(unsafe { pidfd_getpid(self.0.as_raw_fd()) })?;
43 return Ok(pid as u32);
44 }
45 return Err(e);
46 }
47 Err(e) => return Err(e),
48 }
49
50 Ok(pidfd_info.pid)
51 }
52
53 fn exit_for_reaped_child(&self) -> io::Result<ExitStatus> {
54 let mut pidfd_info: libc::pidfd_info = unsafe { crate::mem::zeroed() };
57 pidfd_info.mask = libc::PIDFD_INFO_EXIT as u64;
58 cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) })?;
59 Ok(ExitStatus::new(pidfd_info.exit_code))
60 }
61
62 fn waitid(&self, options: libc::c_int) -> io::Result<Option<ExitStatus>> {
63 let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() };
64 let r = cvt(unsafe {
65 libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, options)
66 });
67 match r {
68 Err(waitid_err) if waitid_err.raw_os_error() == Some(libc::ECHILD) => {
69 match self.exit_for_reaped_child() {
71 Ok(exit_status) => return Ok(Some(exit_status)),
72 Err(_) => return Err(waitid_err),
73 }
74 }
75 Err(e) => return Err(e),
76 Ok(_) => {}
77 }
78 if unsafe { siginfo.si_pid() } == 0 {
79 Ok(None)
80 } else {
81 Ok(Some(ExitStatus::from_waitid_siginfo(siginfo)))
82 }
83 }
84
85 pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
86 cvt(unsafe {
87 libc::syscall(
88 libc::SYS_pidfd_send_signal,
89 self.0.as_raw_fd(),
90 signal,
91 crate::ptr::null::<()>(),
92 0,
93 )
94 })
95 .map(drop)
96 }
97
98 pub fn wait(&self) -> io::Result<ExitStatus> {
99 let r = self.waitid(libc::WEXITED)?;
100 match r {
101 Some(exit_status) => Ok(exit_status),
102 None => unreachable!("waitid with WEXITED should not return None"),
103 }
104 }
105
106 pub fn try_wait(&self) -> io::Result<Option<ExitStatus>> {
107 self.waitid(libc::WEXITED | libc::WNOHANG)
108 }
109}
110
111impl AsInner<FileDesc> for PidFd {
112 fn as_inner(&self) -> &FileDesc {
113 &self.0
114 }
115}
116
117impl IntoInner<FileDesc> for PidFd {
118 fn into_inner(self) -> FileDesc {
119 self.0
120 }
121}
122
123impl FromInner<FileDesc> for PidFd {
124 fn from_inner(inner: FileDesc) -> Self {
125 Self(inner)
126 }
127}
128
129impl FromRawFd for PidFd {
130 unsafe fn from_raw_fd(fd: RawFd) -> Self {
131 Self(FileDesc::from_raw_fd(fd))
132 }
133}
134
135impl IntoRawFd for PidFd {
136 fn into_raw_fd(self) -> RawFd {
137 self.0.into_raw_fd()
138 }
139}