//! Working with processes.
#![stable(feature = "process", since = "1.0.0")]
-#![allow(non_upper_case_globals)]
use prelude::v1::*;
use io::prelude::*;
use ffi::OsStr;
use fmt;
-use io::{self, Error, ErrorKind};
-use path;
+use io;
+use path::Path;
use str;
use sys::pipe::{self, AnonPipe};
use sys::process as imp;
pub struct Child {
handle: imp::Process,
- /// None until wait() or wait_with_output() is called.
- status: Option<imp::ExitStatus>,
-
/// The handle for writing to the child's stdin, if it has been captured
#[stable(feature = "process", since = "1.0.0")]
pub stdin: Option<ChildStdin>,
/// Sets the working directory for the child process.
#[stable(feature = "process", since = "1.0.0")]
- pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command {
+ pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
self.inner.cwd(dir.as_ref().as_ref());
self
}
Err(e) => Err(e),
Ok(handle) => Ok(Child {
handle: handle,
- status: None,
stdin: our_stdin.map(|fd| ChildStdin { inner: fd }),
stdout: our_stdout.map(|fd| ChildStdout { inner: fd }),
stderr: our_stderr.map(|fd| ChildStderr { inner: fd }),
/// SIGKILL on unix platforms.
#[stable(feature = "process", since = "1.0.0")]
pub fn kill(&mut self) -> io::Result<()> {
- #[cfg(unix)] fn collect_status(p: &mut Child) {
- // On Linux (and possibly other unices), a process that has exited will
- // continue to accept signals because it is "defunct". The delivery of
- // signals will only fail once the child has been reaped. For this
- // reason, if the process hasn't exited yet, then we attempt to collect
- // their status with WNOHANG.
- if p.status.is_none() {
- match p.handle.try_wait() {
- Some(status) => { p.status = Some(status); }
- None => {}
- }
- }
- }
- #[cfg(windows)] fn collect_status(_p: &mut Child) {}
-
- collect_status(self);
-
- // if the process has finished, and therefore had waitpid called,
- // and we kill it, then on unix we might ending up killing a
- // newer process that happens to have the same (re-used) id
- if self.status.is_some() {
- return Err(Error::new(
- ErrorKind::InvalidInput,
- "invalid argument: can't kill an exited process",
- ))
- }
-
- unsafe { self.handle.kill() }
+ self.handle.kill()
}
/// Returns the OS-assigned process identifier associated with this child.
#[stable(feature = "process", since = "1.0.0")]
pub fn wait(&mut self) -> io::Result<ExitStatus> {
drop(self.stdin.take());
- match self.status {
- Some(code) => Ok(ExitStatus(code)),
- None => {
- let status = try!(self.handle.wait());
- self.status = Some(status);
- Ok(ExitStatus(status))
- }
- }
+ self.handle.wait().map(ExitStatus)
}
/// Simultaneously waits for the child to exit and collect all remaining
// 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::*;
/// 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 {
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,
}
};
- let p = Process{ pid: pid };
+ let mut p = Process { pid: pid, status: None };
drop(output);
let mut bytes = [0; 8];
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))
}
}