diff --git a/crates/containerd-shim-wasm/src/sys/unix/pid_fd.rs b/crates/containerd-shim-wasm/src/sys/unix/pid_fd.rs index 44fef47a8..ffa8a1ce7 100644 --- a/crates/containerd-shim-wasm/src/sys/unix/pid_fd.rs +++ b/crates/containerd-shim-wasm/src/sys/unix/pid_fd.rs @@ -1,22 +1,29 @@ use std::os::fd::{AsFd, FromRawFd as _, OwnedFd, RawFd}; +use containerd_shim::monitor::{monitor_subscribe, ExitEvent, Subject, Subscription, Topic}; use libc::pid_t; +use nix::errno::Errno; use nix::sys::wait::{waitid, Id, WaitPidFlag, WaitStatus}; +use nix::unistd::Pid; use tokio::io::unix::AsyncFd; pub(super) struct PidFd { fd: OwnedFd, + pid: pid_t, + subs: Subscription, } impl PidFd { pub(super) fn new(pid: impl Into) -> anyhow::Result { use libc::{syscall, SYS_pidfd_open, PIDFD_NONBLOCK}; - let pidfd = unsafe { syscall(SYS_pidfd_open, pid.into(), PIDFD_NONBLOCK) }; + let pid = pid.into(); + let pidfd = unsafe { syscall(SYS_pidfd_open, pid, PIDFD_NONBLOCK) }; if pidfd == -1 { return Err(std::io::Error::last_os_error().into()); } let fd = unsafe { OwnedFd::from_raw_fd(pidfd as RawFd) }; - Ok(Self { fd }) + let subs = monitor_subscribe(Topic::Pid)?; + Ok(Self { fd, pid, subs }) } pub(super) async fn wait(self) -> std::io::Result { @@ -31,13 +38,28 @@ impl PidFd { match waitid( Id::PIDFd(fd.as_fd()), WaitPidFlag::WEXITED | WaitPidFlag::WNOHANG, - )? { - WaitStatus::StillAlive => { + ) { + Ok(WaitStatus::StillAlive) => { let _ = fd.readable().await?; } - status => { + Ok(status) => { return Ok(status); } + Err(Errno::ECHILD) => { + // The process has already been reaped, probably by + // containerd-shim reaper. + // Get the status from there + return self.subs + .rx + .try_iter() + .find_map(|ExitEvent { subject, exit_code }| match subject { + Subject::Pid(p) if p == self.pid => Some(exit_code), + _ => None, + }) + .map(|status| WaitStatus::Exited(Pid::from_raw(self.pid), status)) + .ok_or(Errno::ECHILD.into()); + } + Err(err) => return Err(err.into()), } } }