diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-02-03 18:09:35 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-02-10 09:28:48 -0800 |
| commit | 627515a7ff4fe12084d7e95969bda307849b4d0e (patch) | |
| tree | afbfe3723becc8e32d58cf7668fb066a063b8daf /src/libstd/sys | |
| parent | b1898db0f10f9641c7616e93499348d4fe743ddd (diff) | |
| download | rust-627515a7ff4fe12084d7e95969bda307849b4d0e.tar.gz rust-627515a7ff4fe12084d7e95969bda307849b4d0e.zip | |
std: Push Child's exit status to sys::process
On Unix we have to be careful to not call `waitpid` twice, but we don't have to be careful on Windows due to the way process handles work there. As a result the cached `Option<ExitStatus>` is only necessary on Unix, and it's also just an implementation detail of the Unix module. At the same time. also update some code in `kill` on Unix to avoid a wonky waitpid with WNOHANG. This was added in 0e190b9a to solve #13124, but the `signal(0)` method is not supported any more so there's no need to for this workaround. I believe that this is no longer necessary as it's not really doing anything.
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/unix/process.rs | 42 | ||||
| -rw-r--r-- | src/libstd/sys/windows/process.rs | 8 |
2 files changed, 25 insertions, 25 deletions
diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 7387e9def9f..41b9b3ef126 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_snake_case)] - use prelude::v1::*; use os::unix::prelude::*; @@ -271,7 +269,8 @@ impl fmt::Display for ExitStatus { /// The unique id of the process (this should never be negative). pub struct Process { - pid: pid_t + pid: pid_t, + status: Option<ExitStatus>, } pub enum Stdio { @@ -285,11 +284,6 @@ pub type RawStdio = FileDesc; const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; impl Process { - pub unsafe fn kill(&self) -> io::Result<()> { - try!(cvt(libc::kill(self.pid, libc::SIGKILL))); - Ok(()) - } - pub fn spawn(cfg: &mut Command, in_fd: Stdio, out_fd: Stdio, @@ -324,7 +318,7 @@ impl Process { } }; - let p = Process{ pid: pid }; + let mut p = Process { pid: pid, status: None }; drop(output); let mut bytes = [0; 8]; @@ -516,22 +510,26 @@ impl Process { self.pid as u32 } - pub fn wait(&self) -> io::Result<ExitStatus> { - let mut status = 0 as c_int; - try!(cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })); - Ok(ExitStatus(status)) + pub fn kill(&mut self) -> io::Result<()> { + // If we've already waited on this process then the pid can be recycled + // and used for another process, and we probably shouldn't be killing + // random processes, so just return an error. + if self.status.is_some() { + Err(Error::new(ErrorKind::InvalidInput, + "invalid argument: can't kill an exited process")) + } else { + cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ()) + } } - pub fn try_wait(&self) -> Option<ExitStatus> { - let mut status = 0 as c_int; - match cvt_r(|| unsafe { - libc::waitpid(self.pid, &mut status, libc::WNOHANG) - }) { - Ok(0) => None, - Ok(n) if n == self.pid => Some(ExitStatus(status)), - Ok(n) => panic!("unknown pid: {}", n), - Err(e) => panic!("unknown waitpid error: {}", e), + pub fn wait(&mut self) -> io::Result<ExitStatus> { + if let Some(status) = self.status { + return Ok(status) } + let mut status = 0 as c_int; + try!(cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })); + self.status = Some(ExitStatus(status)); + Ok(ExitStatus(status)) } } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 6a04aa2f2c4..e5e4187d228 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -202,8 +202,10 @@ impl Process { Ok(Process { handle: Handle::new(pi.hProcess) }) } - pub unsafe fn kill(&self) -> io::Result<()> { - try!(cvt(c::TerminateProcess(self.handle.raw(), 1))); + pub fn kill(&mut self) -> io::Result<()> { + try!(cvt(unsafe { + c::TerminateProcess(self.handle.raw(), 1) + })); Ok(()) } @@ -213,7 +215,7 @@ impl Process { } } - pub fn wait(&self) -> io::Result<ExitStatus> { + pub fn wait(&mut self) -> io::Result<ExitStatus> { unsafe { let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE); if res != c::WAIT_OBJECT_0 { |
