Skip to content

Commit 2a345bb

Browse files
committed
make Child::try_wait return io::Result<Option<ExitStatus>>
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: #38903
1 parent c49d102 commit 2a345bb

File tree

6 files changed

+30
-32
lines changed

6 files changed

+30
-32
lines changed

src/libstd/process.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -844,9 +844,9 @@ impl Child {
844844
/// guaranteed to repeatedly return a successful exit status so long as the
845845
/// child has already exited.
846846
///
847-
/// If the child has exited, then `Ok(status)` is returned. If the exit
848-
/// status is not available at this time then an error is returned with the
849-
/// error kind `WouldBlock`. If an error occurs, then that error is returned.
847+
/// If the child has exited, then `Ok(Some(status))` is returned. If the
848+
/// exit status is not available at this time then `Ok(None)` is returned.
849+
/// If an error occurs, then that error is returned.
850850
///
851851
/// Note that unlike `wait`, this function will not attempt to drop stdin.
852852
///
@@ -857,14 +857,13 @@ impl Child {
857857
/// ```no_run
858858
/// #![feature(process_try_wait)]
859859
///
860-
/// use std::io;
861860
/// use std::process::Command;
862861
///
863862
/// let mut child = Command::new("ls").spawn().unwrap();
864863
///
865864
/// match child.try_wait() {
866-
/// Ok(status) => println!("exited with: {}", status),
867-
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
865+
/// Ok(Some(status)) => println!("exited with: {}", status),
866+
/// Ok(None) => {
868867
/// println!("status not ready yet, let's really wait");
869868
/// let res = child.wait();
870869
/// println!("result: {:?}", res);
@@ -873,8 +872,8 @@ impl Child {
873872
/// }
874873
/// ```
875874
#[unstable(feature = "process_try_wait", issue = "38903")]
876-
pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
877-
self.handle.try_wait().map(ExitStatus)
875+
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
876+
Ok(self.handle.try_wait()?.map(ExitStatus))
878877
}
879878

880879
/// Simultaneously waits for the child to exit and collect all remaining

src/libstd/sys/redox/process.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -502,17 +502,17 @@ impl Process {
502502
Ok(ExitStatus(status as i32))
503503
}
504504

505-
pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
505+
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
506506
if let Some(status) = self.status {
507-
return Ok(status)
507+
return Ok(Some(status))
508508
}
509509
let mut status = 0;
510510
let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
511511
if pid == 0 {
512-
Err(io::Error::from_raw_os_error(syscall::EWOULDBLOCK))
512+
Ok(None)
513513
} else {
514514
self.status = Some(ExitStatus(status as i32));
515-
Ok(ExitStatus(status as i32))
515+
Ok(Some(ExitStatus(status as i32)))
516516
}
517517
}
518518
}

src/libstd/sys/unix/process/process_fuchsia.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl Process {
165165
Ok(ExitStatus::new(proc_info.rec.return_code))
166166
}
167167

168-
pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
168+
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
169169
use default::Default;
170170
use sys::process::magenta::*;
171171

@@ -179,7 +179,7 @@ impl Process {
179179
match status {
180180
0 => { }, // Success
181181
x if x == ERR_TIMED_OUT => {
182-
return Err(io::Error::from(io::ErrorKind::WouldBlock));
182+
return Ok(None);
183183
},
184184
_ => { panic!("Failed to wait on process handle: {}", status); },
185185
}
@@ -192,7 +192,7 @@ impl Process {
192192
return Err(io::Error::new(io::ErrorKind::InvalidData,
193193
"Failed to get exit status of process"));
194194
}
195-
Ok(ExitStatus::new(proc_info.rec.return_code))
195+
Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
196196
}
197197
}
198198

src/libstd/sys/unix/process/process_unix.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -249,19 +249,19 @@ impl Process {
249249
Ok(ExitStatus::new(status))
250250
}
251251

252-
pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
252+
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
253253
if let Some(status) = self.status {
254-
return Ok(status)
254+
return Ok(Some(status))
255255
}
256256
let mut status = 0 as c_int;
257257
let pid = cvt(unsafe {
258258
libc::waitpid(self.pid, &mut status, libc::WNOHANG)
259259
})?;
260260
if pid == 0 {
261-
Err(io::Error::from_raw_os_error(libc::EWOULDBLOCK))
261+
Ok(None)
262262
} else {
263263
self.status = Some(ExitStatus::new(status));
264-
Ok(ExitStatus::new(status))
264+
Ok(Some(ExitStatus::new(status)))
265265
}
266266
}
267267
}

src/libstd/sys/windows/process.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -340,18 +340,18 @@ impl Process {
340340
}
341341
}
342342

343-
pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
343+
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
344344
unsafe {
345345
match c::WaitForSingleObject(self.handle.raw(), 0) {
346346
c::WAIT_OBJECT_0 => {}
347347
c::WAIT_TIMEOUT => {
348-
return Err(io::Error::from_raw_os_error(c::WSAEWOULDBLOCK))
348+
return Ok(None);
349349
}
350350
_ => return Err(io::Error::last_os_error()),
351351
}
352352
let mut status = 0;
353353
cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
354-
Ok(ExitStatus(status))
354+
Ok(Some(ExitStatus(status)))
355355
}
356356
}
357357

src/test/run-pass/try-wait.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#![feature(process_try_wait)]
1414

1515
use std::env;
16-
use std::io;
1716
use std::process::Command;
1817
use std::thread;
1918
use std::time::Duration;
@@ -32,17 +31,17 @@ fn main() {
3231
.arg("sleep")
3332
.spawn()
3433
.unwrap();
35-
let err = me.try_wait().unwrap_err();
36-
assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
37-
let err = me.try_wait().unwrap_err();
38-
assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
34+
let maybe_status = me.try_wait().unwrap();
35+
assert!(maybe_status.is_none());
36+
let maybe_status = me.try_wait().unwrap();
37+
assert!(maybe_status.is_none());
3938

4039
me.kill().unwrap();
4140
me.wait().unwrap();
4241

43-
let status = me.try_wait().unwrap();
42+
let status = me.try_wait().unwrap().unwrap();
4443
assert!(!status.success());
45-
let status = me.try_wait().unwrap();
44+
let status = me.try_wait().unwrap().unwrap();
4645
assert!(!status.success());
4746

4847
let mut me = Command::new(env::current_exe().unwrap())
@@ -51,17 +50,17 @@ fn main() {
5150
.unwrap();
5251
loop {
5352
match me.try_wait() {
54-
Ok(res) => {
53+
Ok(Some(res)) => {
5554
assert!(res.success());
5655
break
5756
}
58-
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
57+
Ok(None) => {
5958
thread::sleep(Duration::from_millis(1));
6059
}
6160
Err(e) => panic!("error in try_wait: {}", e),
6261
}
6362
}
6463

65-
let status = me.try_wait().unwrap();
64+
let status = me.try_wait().unwrap().unwrap();
6665
assert!(status.success());
6766
}

0 commit comments

Comments
 (0)