self.handle.wait().map(ExitStatus)
}
+ /// Attempts to collect the exit status of the child if it has already
+ /// exited.
+ ///
+ /// This function will not block the calling thread and will only advisorily
+ /// check to see if the child process has exited or not. If the child has
+ /// exited then on Unix the process id is reaped. This function is
+ /// guaranteed to repeatedly return a successful exit status so long as the
+ /// child has already exited.
+ ///
+ /// If the child has exited, then `Ok(status)` is returned. If the exit
+ /// status is not available at this time then an error is returned with the
+ /// error kind `WouldBlock`. If an error occurs, then that error is returned.
+ ///
+ /// Note that unlike `wait`, this function will not attempt to drop stdin.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```no_run
+ /// #![feature(process_try_wait)]
+ ///
+ /// use std::io;
+ /// use std::process::Command;
+ ///
+ /// let mut child = Command::new("ls").spawn().unwrap();
+ ///
+ /// match child.try_wait() {
+ /// Ok(status) => println!("exited with: {}", status),
+ /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ /// println!("status not ready yet, let's really wait");
+ /// let res = child.wait();
+ /// println!("result: {:?}", res);
+ /// }
+ /// Err(e) => println!("error attempting to wait: {}", e),
+ /// }
+ /// ```
+ #[unstable(feature = "process_try_wait", issue = "38903")]
+ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+ self.handle.try_wait().map(ExitStatus)
+ }
+
/// Simultaneously waits for the child to exit and collect all remaining
/// output on the stdout/stderr handles, returning an `Output`
/// instance.
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
}
}
+
pub fn wait(&mut self) -> io::Result<ExitStatus> {
use sys::cvt_r;
if let Some(status) = self.status {
self.status = Some(ExitStatus::new(status));
Ok(ExitStatus::new(status))
}
+
+ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+ if let Some(status) = self.status {
+ return Ok(status)
+ }
+ let mut status = 0 as c_int;
+ let pid = cvt(unsafe {
+ libc::waitpid(self.pid, &mut status, libc::WNOHANG)
+ })?;
+ if pid == 0 {
+ Err(io::Error::from_raw_os_error(libc::EWOULDBLOCK))
+ } else {
+ self.status = Some(ExitStatus::new(status));
+ Ok(ExitStatus::new(status))
+ }
+ }
}
pub const FILE_END: DWORD = 2;
pub const WAIT_OBJECT_0: DWORD = 0x00000000;
+pub const WAIT_TIMEOUT: DWORD = 258;
#[cfg(target_env = "msvc")]
pub const MAX_SYM_NAME: usize = 2000;
}
}
+ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+ unsafe {
+ match c::WaitForSingleObject(self.handle.raw(), 0) {
+ c::WAIT_OBJECT_0 => {}
+ c::WAIT_TIMEOUT => {
+ return Err(io::Error::from_raw_os_error(c::WSAEWOULDBLOCK))
+ }
+ _ => return Err(io::Error::last_os_error()),
+ }
+ let mut status = 0;
+ cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
+ Ok(ExitStatus(status))
+ }
+ }
+
pub fn handle(&self) -> &Handle { &self.handle }
pub fn into_handle(self) -> Handle { self.handle }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(process_try_wait)]
+
+use std::env;
+use std::io;
+use std::process::Command;
+use std::thread;
+use std::time::Duration;
+
+fn main() {
+ let args = env::args().collect::<Vec<_>>();
+ if args.len() != 1 {
+ match &args[1][..] {
+ "sleep" => thread::sleep(Duration::new(1_000, 0)),
+ _ => {}
+ }
+ return
+ }
+
+ let mut me = Command::new(env::current_exe().unwrap())
+ .arg("sleep")
+ .spawn()
+ .unwrap();
+ let err = me.try_wait().unwrap_err();
+ assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
+ let err = me.try_wait().unwrap_err();
+ assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
+
+ me.kill().unwrap();
+ me.wait().unwrap();
+
+ let status = me.try_wait().unwrap();
+ assert!(!status.success());
+ let status = me.try_wait().unwrap();
+ assert!(!status.success());
+
+ let mut me = Command::new(env::current_exe().unwrap())
+ .arg("return-quickly")
+ .spawn()
+ .unwrap();
+ loop {
+ match me.try_wait() {
+ Ok(res) => {
+ assert!(res.success());
+ break
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ thread::sleep(Duration::from_millis(1));
+ }
+ Err(e) => panic!("error in try_wait: {}", e),
+ }
+ }
+
+ let status = me.try_wait().unwrap();
+ assert!(status.success());
+}