]> git.lizzy.rs Git - rust.git/commitdiff
make Child::try_wait return io::Result<Option<ExitStatus>>
authorJack O'Connor <oconnor663@gmail.com>
Fri, 3 Feb 2017 22:39:41 +0000 (17:39 -0500)
committerJack O'Connor <oconnor663@gmail.com>
Tue, 7 Feb 2017 04:04:47 +0000 (23:04 -0500)
This is much nicer for callers who want to short-circuit real I/O errors
with `?`, because they can write this

    if let Some(status) = foo.try_wait()? {
        ...
    } else {
        ...
    }

instead of this

    match foo.try_wait() {
        Ok(status) => {
            ...
        }
        Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
            ...
        }
        Err(err) => return Err(err),
    }

The original design of `try_wait` was patterned after the `Read` and
`Write` traits, which support both blocking and non-blocking
implementations in a single API. But since `try_wait` is never blocking,
it makes sense to optimize for the non-blocking case.

Tracking issue: https://github.com/rust-lang/rust/issues/38903

src/libstd/process.rs
src/libstd/sys/redox/process.rs
src/libstd/sys/unix/process/process_fuchsia.rs
src/libstd/sys/unix/process/process_unix.rs
src/libstd/sys/windows/process.rs
src/test/run-pass/try-wait.rs

index c16b97ebda5e3c2bd4a1d4a4ca055c6101077c50..4ff35738b50fbd085657154c517563fbab6e991c 100644 (file)
@@ -844,9 +844,9 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// 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.
+    /// If the child has exited, then `Ok(Some(status))` is returned. If the
+    /// exit status is not available at this time then `Ok(None)` is returned.
+    /// If an error occurs, then that error is returned.
     ///
     /// Note that unlike `wait`, this function will not attempt to drop stdin.
     ///
@@ -857,14 +857,13 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// ```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 => {
+    ///     Ok(Some(status)) => println!("exited with: {}", status),
+    ///     Ok(None) => {
     ///         println!("status not ready yet, let's really wait");
     ///         let res = child.wait();
     ///         println!("result: {:?}", res);
@@ -873,8 +872,8 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// }
     /// ```
     #[unstable(feature = "process_try_wait", issue = "38903")]
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
-        self.handle.try_wait().map(ExitStatus)
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        Ok(self.handle.try_wait()?.map(ExitStatus))
     }
 
     /// Simultaneously waits for the child to exit and collect all remaining
index 50dcd44b42e92d3836267ff050e00278042c5912..60dc03fcf47e2aa7b5f0fed92d54aa493cc2d4e5 100644 (file)
@@ -502,17 +502,17 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         Ok(ExitStatus(status as i32))
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         if let Some(status) = self.status {
-            return Ok(status)
+            return Ok(Some(status))
         }
         let mut status = 0;
         let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
         if pid == 0 {
-            Err(io::Error::from_raw_os_error(syscall::EWOULDBLOCK))
+            Ok(None)
         } else {
             self.status = Some(ExitStatus(status as i32));
-            Ok(ExitStatus(status as i32))
+            Ok(Some(ExitStatus(status as i32)))
         }
     }
 }
index 87acb0ed9b977e4fe1dc9c7da72e27e0e8d1b2d7..0bb2e0c1a83d4469a534469b83ef8c363a08d901 100644 (file)
@@ -165,7 +165,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         Ok(ExitStatus::new(proc_info.rec.return_code))
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         use default::Default;
         use sys::process::magenta::*;
 
@@ -179,7 +179,7 @@ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
             match status {
                 0 => { }, // Success
                 x if x == ERR_TIMED_OUT => {
-                    return Err(io::Error::from(io::ErrorKind::WouldBlock));
+                    return Ok(None);
                 },
                 _ => { panic!("Failed to wait on process handle: {}", status); },
             }
@@ -192,7 +192,7 @@ pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
             return Err(io::Error::new(io::ErrorKind::InvalidData,
                                       "Failed to get exit status of process"));
         }
-        Ok(ExitStatus::new(proc_info.rec.return_code))
+        Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
     }
 }
 
index 0dc1739c1a15aef50a5e7d956ddff298a7c56b85..bbc987209e300edf7c9ebde5a1cbf2f02f13b211 100644 (file)
@@ -249,19 +249,19 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         Ok(ExitStatus::new(status))
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         if let Some(status) = self.status {
-            return Ok(status)
+            return Ok(Some(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))
+            Ok(None)
         } else {
             self.status = Some(ExitStatus::new(status));
-            Ok(ExitStatus::new(status))
+            Ok(Some(ExitStatus::new(status)))
         }
     }
 }
index d2ad81023e7feefcd7cb34da5684bc1c2c19e965..1afb3728c9d72e7d00d20a153631a312b72302e6 100644 (file)
@@ -340,18 +340,18 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         }
     }
 
-    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+    pub fn try_wait(&mut self) -> io::Result<Option<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 Ok(None);
                 }
                 _ => return Err(io::Error::last_os_error()),
             }
             let mut status = 0;
             cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
-            Ok(ExitStatus(status))
+            Ok(Some(ExitStatus(status)))
         }
     }
 
index d9826373cceb00803a2525ca120793b4da747e6e..be87b7b3c87e42fbd50cd4905bc39d9bd9af7a3a 100644 (file)
@@ -13,7 +13,6 @@
 #![feature(process_try_wait)]
 
 use std::env;
-use std::io;
 use std::process::Command;
 use std::thread;
 use std::time::Duration;
@@ -32,17 +31,17 @@ fn main() {
                          .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);
+    let maybe_status = me.try_wait().unwrap();
+    assert!(maybe_status.is_none());
+    let maybe_status = me.try_wait().unwrap();
+    assert!(maybe_status.is_none());
 
     me.kill().unwrap();
     me.wait().unwrap();
 
-    let status = me.try_wait().unwrap();
+    let status = me.try_wait().unwrap().unwrap();
     assert!(!status.success());
-    let status = me.try_wait().unwrap();
+    let status = me.try_wait().unwrap().unwrap();
     assert!(!status.success());
 
     let mut me = Command::new(env::current_exe().unwrap())
@@ -51,17 +50,17 @@ fn main() {
                          .unwrap();
     loop {
         match me.try_wait() {
-            Ok(res) => {
+            Ok(Some(res)) => {
                 assert!(res.success());
                 break
             }
-            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+            Ok(None) => {
                 thread::sleep(Duration::from_millis(1));
             }
             Err(e) => panic!("error in try_wait: {}", e),
         }
     }
 
-    let status = me.try_wait().unwrap();
+    let status = me.try_wait().unwrap().unwrap();
     assert!(status.success());
 }