diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 3eee45d000cd1..2dedb2df08a2a 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1489,6 +1489,40 @@ impl Child { let status = self.wait()?; Ok(Output { status, stdout, stderr }) } + + /// Indicates that the process has exited and the exit status is known. + /// + /// You should only call this function after using `waitpid` on Unix or an + /// equivalent function on another platform. It will cause future calls to + /// [`wait`] and [`wait_with_output`] to use this exit status. + /// + /// # Examples + /// + /// ``` + /// # use std::process::{Child, ExitStatus}; + /// use std::process::{Command, Stdio}; + /// + /// let mut child = Command::new("echo") + /// .arg("Hello world") + /// .stdout(Stdio::piped()) + /// .spawn() + /// .expect("failed to execute child"); + /// + /// # fn external_wait(child: &mut Child) -> ExitStatus { + /// # child.wait().unwrap() + /// # } + /// let status = external_wait(&mut child); + /// child.set_status(status); + /// + /// assert_eq!(status, child.wait().expect("failed to wait on child")); + /// ``` + /// + /// [`wait`]: #method.wait + /// [`wait_with_output`]: #method.wait_with_output + #[stable(feature = "child_set_status", since = "1.44.0")] + pub fn set_status(&mut self, status: ExitStatus) { + self.handle.set_status(status.0); + } } /// Terminates the current process with the specified exit code. diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs index 4702e5c549228..48467b881cfd5 100644 --- a/src/libstd/sys/cloudabi/shims/process.rs +++ b/src/libstd/sys/cloudabi/shims/process.rs @@ -146,4 +146,6 @@ impl Process { pub fn try_wait(&mut self) -> io::Result> { match self.0 {} } + + pub fn set_status(&mut self, _: ExitStatus) {} } diff --git a/src/libstd/sys/hermit/process.rs b/src/libstd/sys/hermit/process.rs index 4702e5c549228..48467b881cfd5 100644 --- a/src/libstd/sys/hermit/process.rs +++ b/src/libstd/sys/hermit/process.rs @@ -146,4 +146,6 @@ impl Process { pub fn try_wait(&mut self) -> io::Result> { match self.0 {} } + + pub fn set_status(&mut self, _: ExitStatus) {} } diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs index 4702e5c549228..48467b881cfd5 100644 --- a/src/libstd/sys/sgx/process.rs +++ b/src/libstd/sys/sgx/process.rs @@ -146,4 +146,6 @@ impl Process { pub fn try_wait(&mut self) -> io::Result> { match self.0 {} } + + pub fn set_status(&mut self, _: ExitStatus) {} } diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index f0bd1cdfed52f..794e3e78fc43d 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -32,7 +32,7 @@ impl Command { let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? }; - Ok((Process { handle: Handle::new(process_handle) }, ours)) + Ok((Process { handle: Handle::new(process_handle), status: None }, ours)) } pub fn exec(&mut self, default: Stdio) -> io::Error { @@ -139,6 +139,7 @@ impl Command { pub struct Process { handle: Handle, + status: Option, } impl Process { @@ -160,6 +161,10 @@ impl Process { use crate::default::Default; use crate::sys::process::zircon::*; + if let Some(status) = self.status { + return Ok(status); + } + let mut proc_info: zx_info_process_t = Default::default(); let mut actual: size_t = 0; let mut avail: size_t = 0; @@ -186,13 +191,19 @@ impl Process { "Failed to get exit status of process", )); } - Ok(ExitStatus(proc_info.return_code)) + let status = ExitStatus(proc_info.return_code); + self.set_status(status); + Ok(status) } pub fn try_wait(&mut self) -> io::Result> { use crate::default::Default; use crate::sys::process::zircon::*; + if let Some(status) = self.status { + return Ok(status); + } + let mut proc_info: zx_info_process_t = Default::default(); let mut actual: size_t = 0; let mut avail: size_t = 0; @@ -224,7 +235,12 @@ impl Process { "Failed to get exit status of process", )); } - Ok(Some(ExitStatus(proc_info.return_code))) + self.set_status(ExitStatus(proc_info.return_code)); + Ok(self.status) + } + + pub fn set_status(&mut self, status: ExitStatus) { + self.status = Some(status); } } diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 07d0fbf61fe22..91ef14d91138f 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -436,8 +436,8 @@ impl Process { } let mut status = 0 as c_int; cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?; - self.status = Some(ExitStatus::new(status)); - Ok(ExitStatus::new(status)) + self.set_status(ExitStatus(status)); + Ok(ExitStatus(status)) } pub fn try_wait(&mut self) -> io::Result> { @@ -446,12 +446,14 @@ impl Process { } let mut status = 0 as c_int; let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?; - if pid == 0 { - Ok(None) - } else { - self.status = Some(ExitStatus::new(status)); - Ok(Some(ExitStatus::new(status))) + if pid != 0 { + self.set_status(ExitStatus(status)); } + Ok(self.status) + } + + pub fn set_status(&mut self, status: ExitStatus) { + self.status = Some(status); } } @@ -460,10 +462,6 @@ impl Process { pub struct ExitStatus(c_int); impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - fn exited(&self) -> bool { unsafe { libc::WIFEXITED(self.0) } } diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs index 6d5506bec5f7d..37b846309273a 100644 --- a/src/libstd/sys/vxworks/process/process_common.rs +++ b/src/libstd/sys/vxworks/process/process_common.rs @@ -344,10 +344,6 @@ impl fmt::Debug for Command { pub struct ExitStatus(c_int); impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - fn exited(&self) -> bool { /*unsafe*/ { libc::WIFEXITED(self.0) } diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs index f7e84ae3de9c7..55b76f0976461 100644 --- a/src/libstd/sys/vxworks/process/process_vxworks.rs +++ b/src/libstd/sys/vxworks/process/process_vxworks.rs @@ -149,8 +149,8 @@ impl Process { } let mut status = 0 as c_int; cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?; - self.status = Some(ExitStatus::new(status)); - Ok(ExitStatus::new(status)) + self.set_status(ExitStatus(status)); + Ok(ExitStatus(status)) } pub fn try_wait(&mut self) -> io::Result> { @@ -159,11 +159,13 @@ impl Process { } let mut status = 0 as c_int; let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?; - if pid == 0 { - Ok(None) - } else { - self.status = Some(ExitStatus::new(status)); - Ok(Some(ExitStatus::new(status))) + if pid != 0 { + self.set_status(ExitStatus(status)); } + Ok(self.status) + } + + pub fn set_status(&mut self, status: ExitStatus) { + self.status = Some(status); } } diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs index 7156c9ab92f2b..4cbfae0b624ed 100644 --- a/src/libstd/sys/wasi/process.rs +++ b/src/libstd/sys/wasi/process.rs @@ -146,4 +146,6 @@ impl Process { pub fn try_wait(&mut self) -> io::Result> { match self.0 {} } + + pub fn set_status(&mut self, _: ExitStatus) {} } diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs index 4702e5c549228..48467b881cfd5 100644 --- a/src/libstd/sys/wasm/process.rs +++ b/src/libstd/sys/wasm/process.rs @@ -146,4 +146,6 @@ impl Process { pub fn try_wait(&mut self) -> io::Result> { match self.0 {} } + + pub fn set_status(&mut self, _: ExitStatus) {} } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index a62a637393ea3..82aca0a8df79b 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -220,7 +220,7 @@ impl Command { // around to be able to close it later. drop(Handle::new(pi.hThread)); - Ok((Process { handle: Handle::new(pi.hProcess) }, pipes)) + Ok((Process { handle: Handle::new(pi.hProcess), status: None }, pipes)) } } @@ -319,6 +319,7 @@ impl From for Stdio { /// for the process to terminate. pub struct Process { handle: Handle, + status: Option, } impl Process { @@ -332,6 +333,9 @@ impl Process { } pub fn wait(&mut self) -> io::Result { + if let Some(status) = self.status { + return Ok(status); + } unsafe { let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE); if res != c::WAIT_OBJECT_0 { @@ -339,11 +343,15 @@ impl Process { } let mut status = 0; cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; + self.set_status(ExitStatus(status)); Ok(ExitStatus(status)) } } pub fn try_wait(&mut self) -> io::Result> { + if let Some(status) = self.status { + return Ok(Some(status)); + } unsafe { match c::WaitForSingleObject(self.handle.raw(), 0) { c::WAIT_OBJECT_0 => {} @@ -354,10 +362,15 @@ impl Process { } let mut status = 0; cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; - Ok(Some(ExitStatus(status))) + self.set_status(ExitStatus(status)); + Ok(self.status) } } + pub fn set_status(&mut self, status: ExitStatus) { + self.status = Some(status); + } + pub fn handle(&self) -> &Handle { &self.handle }