]> git.proxmox.com Git - rustc.git/blobdiff - src/libstd/process.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / libstd / process.rs
index 8f8699f4b9fea9f29f48a3530286ca1a8059a50f..91c3819307ffef652e1477421fb8ae60c385a0da 100644 (file)
@@ -20,14 +20,10 @@ use ffi::OsStr;
 use fmt;
 use io::{self, Error, ErrorKind};
 use path;
-use sync::mpsc::{channel, Receiver};
-use sys::pipe2::{self, AnonPipe};
-use sys::process2::Command as CommandImp;
-use sys::process2::Process as ProcessImp;
-use sys::process2::ExitStatus as ExitStatusImp;
-use sys::process2::Stdio as StdioImp2;
-use sys_common::{AsInner, AsInnerMut};
-use thread;
+use sys::pipe::{self, AnonPipe};
+use sys::process as imp;
+use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+use thread::{self, JoinHandle};
 
 /// Representation of a running or exited child process.
 ///
@@ -52,10 +48,10 @@ use thread;
 /// ```
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Child {
-    handle: ProcessImp,
+    handle: imp::Process,
 
     /// None until wait() or wait_with_output() is called.
-    status: Option<ExitStatusImp>,
+    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")]
@@ -70,7 +66,15 @@ pub struct Child {
     pub stderr: Option<ChildStderr>,
 }
 
-/// A handle to a child procesess's stdin
+impl AsInner<imp::Process> for Child {
+    fn as_inner(&self) -> &imp::Process { &self.handle }
+}
+
+impl IntoInner<imp::Process> for Child {
+    fn into_inner(self) -> imp::Process { self.handle }
+}
+
+/// A handle to a child process's stdin
 #[stable(feature = "process", since = "1.0.0")]
 pub struct ChildStdin {
     inner: AnonPipe
@@ -87,7 +91,15 @@ impl Write for ChildStdin {
     }
 }
 
-/// A handle to a child procesess's stdout
+impl AsInner<AnonPipe> for ChildStdin {
+    fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStdin {
+    fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+/// A handle to a child process's stdout
 #[stable(feature = "process", since = "1.0.0")]
 pub struct ChildStdout {
     inner: AnonPipe
@@ -100,7 +112,15 @@ impl Read for ChildStdout {
     }
 }
 
-/// A handle to a child procesess's stderr
+impl AsInner<AnonPipe> for ChildStdout {
+    fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStdout {
+    fn into_inner(self) -> AnonPipe { self.inner }
+}
+
+/// A handle to a child process's stderr
 #[stable(feature = "process", since = "1.0.0")]
 pub struct ChildStderr {
     inner: AnonPipe
@@ -113,6 +133,14 @@ impl Read for ChildStderr {
     }
 }
 
+impl AsInner<AnonPipe> for ChildStderr {
+    fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
+impl IntoInner<AnonPipe> for ChildStderr {
+    fn into_inner(self) -> AnonPipe { self.inner }
+}
+
 /// The `Command` type acts as a process builder, providing fine-grained control
 /// over how a new process should be spawned. A default configuration can be
 /// generated using `Command::new(program)`, where `program` gives a path to the
@@ -131,12 +159,12 @@ impl Read for ChildStderr {
 /// ```
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Command {
-    inner: CommandImp,
+    inner: imp::Command,
 
     // Details explained in the builder methods
-    stdin: Option<StdioImp>,
-    stdout: Option<StdioImp>,
-    stderr: Option<StdioImp>,
+    stdin: Option<Stdio>,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
 }
 
 impl Command {
@@ -153,7 +181,7 @@ impl Command {
     #[stable(feature = "process", since = "1.0.0")]
     pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
         Command {
-            inner: CommandImp::new(program.as_ref()),
+            inner: imp::Command::new(program.as_ref()),
             stdin: None,
             stdout: None,
             stderr: None,
@@ -210,36 +238,40 @@ impl Command {
     /// Configuration for the child process's stdin handle (file descriptor 0).
     #[stable(feature = "process", since = "1.0.0")]
     pub fn stdin(&mut self, cfg: Stdio) -> &mut Command {
-        self.stdin = Some(cfg.0);
+        self.stdin = Some(cfg);
         self
     }
 
     /// Configuration for the child process's stdout handle (file descriptor 1).
     #[stable(feature = "process", since = "1.0.0")]
     pub fn stdout(&mut self, cfg: Stdio) -> &mut Command {
-        self.stdout = Some(cfg.0);
+        self.stdout = Some(cfg);
         self
     }
 
     /// Configuration for the child process's stderr handle (file descriptor 2).
     #[stable(feature = "process", since = "1.0.0")]
     pub fn stderr(&mut self, cfg: Stdio) -> &mut Command {
-        self.stderr = Some(cfg.0);
+        self.stderr = Some(cfg);
         self
     }
 
     fn spawn_inner(&self, default_io: StdioImp) -> io::Result<Child> {
-        let (their_stdin, our_stdin) = try!(
+        let default_io = Stdio(default_io);
+
+        // See comment on `setup_io` for what `_drop_later` is.
+        let (their_stdin, our_stdin, _drop_later) = try!(
             setup_io(self.stdin.as_ref().unwrap_or(&default_io), true)
         );
-        let (their_stdout, our_stdout) = try!(
+        let (their_stdout, our_stdout, _drop_later) = try!(
             setup_io(self.stdout.as_ref().unwrap_or(&default_io), false)
         );
-        let (their_stderr, our_stderr) = try!(
+        let (their_stderr, our_stderr, _drop_later) = try!(
             setup_io(self.stderr.as_ref().unwrap_or(&default_io), false)
         );
 
-        match ProcessImp::spawn(&self.inner, their_stdin, their_stdout, their_stderr) {
+        match imp::Process::spawn(&self.inner, their_stdin, their_stdout,
+                                  their_stderr) {
             Err(e) => Err(e),
             Ok(handle) => Ok(Child {
                 handle: handle,
@@ -253,7 +285,7 @@ impl Command {
 
     /// Executes the command as a child process, returning a handle to it.
     ///
-    /// By default, stdin, stdout and stderr are inherited by the parent.
+    /// By default, stdin, stdout and stderr are inherited from the parent.
     #[stable(feature = "process", since = "1.0.0")]
     pub fn spawn(&mut self) -> io::Result<Child> {
         self.spawn_inner(StdioImp::Inherit)
@@ -279,13 +311,13 @@ impl Command {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn output(&mut self) -> io::Result<Output> {
-        self.spawn_inner(StdioImp::Piped).and_then(|p| p.wait_with_output())
+        self.spawn_inner(StdioImp::MakePipe).and_then(|p| p.wait_with_output())
     }
 
     /// Executes a command as a child process, waiting for it to finish and
     /// collecting its exit status.
     ///
-    /// By default, stdin, stdout and stderr are inherited by the parent.
+    /// By default, stdin, stdout and stderr are inherited from the parent.
     ///
     /// # Examples
     ///
@@ -318,29 +350,38 @@ impl fmt::Debug for Command {
     }
 }
 
-impl AsInner<CommandImp> for Command {
-    fn as_inner(&self) -> &CommandImp { &self.inner }
+impl AsInner<imp::Command> for Command {
+    fn as_inner(&self) -> &imp::Command { &self.inner }
 }
 
-impl AsInnerMut<CommandImp> for Command {
-    fn as_inner_mut(&mut self) -> &mut CommandImp { &mut self.inner }
+impl AsInnerMut<imp::Command> for Command {
+    fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
 }
 
-fn setup_io(io: &StdioImp, readable: bool)
-            -> io::Result<(StdioImp2, Option<AnonPipe>)>
+// Takes a `Stdio` configuration (this module) and whether the to-be-owned
+// handle will be readable.
+//
+// Returns a triple of (stdio to spawn with, stdio to store, stdio to drop). The
+// stdio to spawn with is passed down to the `sys` module and indicates how the
+// stdio stream should be set up. The "stdio to store" is an object which
+// should be returned in the `Child` that makes its way out. The "stdio to drop"
+// represents the raw value of "stdio to spawn with", but is the owned variant
+// for it. This needs to be dropped after the child spawns
+fn setup_io(io: &Stdio, readable: bool)
+            -> io::Result<(imp::Stdio, Option<AnonPipe>, Option<AnonPipe>)>
 {
-    use self::StdioImp::*;
-    Ok(match *io {
-        Null => (StdioImp2::None, None),
-        Inherit => (StdioImp2::Inherit, None),
-        Piped => {
-            let (reader, writer) = try!(pipe2::anon_pipe());
+    Ok(match io.0 {
+        StdioImp::MakePipe => {
+            let (reader, writer) = try!(pipe::anon_pipe());
             if readable {
-                (StdioImp2::Piped(reader), Some(writer))
+                (imp::Stdio::Raw(reader.raw()), Some(writer), Some(reader))
             } else {
-                (StdioImp2::Piped(writer), Some(reader))
+                (imp::Stdio::Raw(writer.raw()), Some(reader), Some(writer))
             }
         }
+        StdioImp::Raw(ref owned) => (imp::Stdio::Raw(owned.raw()), None, None),
+        StdioImp::Inherit => (imp::Stdio::Inherit, None, None),
+        StdioImp::None => (imp::Stdio::None, None, None),
     })
 }
 
@@ -364,17 +405,17 @@ pub struct Output {
 pub struct Stdio(StdioImp);
 
 // The internal enum for stdio setup; see below for descriptions.
-#[derive(Clone)]
 enum StdioImp {
-    Piped,
+    MakePipe,
+    Raw(imp::RawStdio),
     Inherit,
-    Null,
+    None,
 }
 
 impl Stdio {
     /// A new pipe should be arranged to connect the parent and child processes.
     #[stable(feature = "process", since = "1.0.0")]
-    pub fn piped() -> Stdio { Stdio(StdioImp::Piped) }
+    pub fn piped() -> Stdio { Stdio(StdioImp::MakePipe) }
 
     /// The child inherits from the corresponding parent descriptor.
     #[stable(feature = "process", since = "1.0.0")]
@@ -383,13 +424,19 @@ impl Stdio {
     /// This stream will be ignored. This is the equivalent of attaching the
     /// stream to `/dev/null`
     #[stable(feature = "process", since = "1.0.0")]
-    pub fn null() -> Stdio { Stdio(StdioImp::Null) }
+    pub fn null() -> Stdio { Stdio(StdioImp::None) }
+}
+
+impl FromInner<imp::RawStdio> for Stdio {
+    fn from_inner(inner: imp::RawStdio) -> Stdio {
+        Stdio(StdioImp::Raw(inner))
+    }
 }
 
 /// Describes the result of a process after it has terminated.
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "process", since = "1.0.0")]
-pub struct ExitStatus(ExitStatusImp);
+pub struct ExitStatus(imp::ExitStatus);
 
 impl ExitStatus {
     /// Was termination successful? Signal termination not considered a success,
@@ -410,8 +457,8 @@ impl ExitStatus {
     }
 }
 
-impl AsInner<ExitStatusImp> for ExitStatus {
-    fn as_inner(&self) -> &ExitStatusImp { &self.0 }
+impl AsInner<imp::ExitStatus> for ExitStatus {
+    fn as_inner(&self) -> &imp::ExitStatus { &self.0 }
 }
 
 #[stable(feature = "process", since = "1.0.0")]
@@ -456,6 +503,12 @@ impl Child {
         unsafe { self.handle.kill() }
     }
 
+    /// Returns the OS-assigned process identifier associated with this child.
+    #[stable(feature = "process_id", since = "1.3.0")]
+    pub fn id(&self) -> u32 {
+        self.handle.id()
+    }
+
     /// Waits for the child to exit completely, returning the status that it
     /// exited with. This function will continue to have the same return value
     /// after it has been called at least once.
@@ -478,7 +531,7 @@ impl Child {
     }
 
     /// Simultaneously waits for the child to exit and collect all remaining
-    /// output on the stdout/stderr handles, returning a `Output`
+    /// output on the stdout/stderr handles, returning an `Output`
     /// instance.
     ///
     /// The stdin handle to the child process, if any, will be closed
@@ -488,29 +541,24 @@ impl Child {
     #[stable(feature = "process", since = "1.0.0")]
     pub fn wait_with_output(mut self) -> io::Result<Output> {
         drop(self.stdin.take());
-        fn read<T: Read + Send + 'static>(stream: Option<T>) -> Receiver<io::Result<Vec<u8>>> {
-            let (tx, rx) = channel();
-            match stream {
-                Some(stream) => {
-                    thread::spawn(move || {
-                        let mut stream = stream;
-                        let mut ret = Vec::new();
-                        let res = stream.read_to_end(&mut ret);
-                        tx.send(res.map(|_| ret)).unwrap();
-                    });
-                }
-                None => tx.send(Ok(Vec::new())).unwrap()
-            }
-            rx
+        fn read<R>(mut input: R) -> JoinHandle<io::Result<Vec<u8>>>
+            where R: Read + Send + 'static
+        {
+            thread::spawn(move || {
+                let mut ret = Vec::new();
+                input.read_to_end(&mut ret).map(|_| ret)
+            })
         }
-        let stdout = read(self.stdout.take());
-        let stderr = read(self.stderr.take());
+        let stdout = self.stdout.take().map(read);
+        let stderr = self.stderr.take().map(read);
         let status = try!(self.wait());
+        let stdout = stdout.and_then(|t| t.join().unwrap().ok());
+        let stderr = stderr.and_then(|t| t.join().unwrap().ok());
 
         Ok(Output {
             status: status,
-            stdout: stdout.recv().unwrap().unwrap_or(Vec::new()),
-            stderr:  stderr.recv().unwrap().unwrap_or(Vec::new()),
+            stdout: stdout.unwrap_or(Vec::new()),
+            stderr: stderr.unwrap_or(Vec::new()),
         })
     }
 }
@@ -528,6 +576,7 @@ impl Child {
 /// to run.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn exit(code: i32) -> ! {
+    ::sys_common::cleanup();
     ::sys::os::exit(code)
 }
 
@@ -537,7 +586,6 @@ mod tests {
     use io::prelude::*;
 
     use io::ErrorKind;
-    use rt::running_on_valgrind;
     use str;
     use super::{Command, Output, Stdio};
 
@@ -576,12 +624,15 @@ mod tests {
     fn signal_reported_right() {
         use os::unix::process::ExitStatusExt;
 
-        let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
-        assert!(p.is_ok());
-        let mut p = p.unwrap();
+        let mut p = Command::new("/bin/sh")
+                            .arg("-c").arg("read a")
+                            .stdin(Stdio::piped())
+                            .spawn().unwrap();
+        p.kill().unwrap();
         match p.wait().unwrap().signal() {
             Some(9) => {},
-            result => panic!("not terminated by signal 9 (instead, {:?})", result),
+            result => panic!("not terminated by signal 9 (instead, {:?})",
+                             result),
         }
     }
 
@@ -683,10 +734,7 @@ mod tests {
 
         assert!(status.success());
         assert_eq!(output_str.trim().to_string(), "hello");
-        // FIXME #7224
-        if !running_on_valgrind() {
-            assert_eq!(stderr, Vec::new());
-        }
+        assert_eq!(stderr, Vec::new());
     }
 
     #[cfg(not(target_os="android"))]
@@ -725,28 +773,7 @@ mod tests {
 
         assert!(status.success());
         assert_eq!(output_str.trim().to_string(), "hello");
-        // FIXME #7224
-        if !running_on_valgrind() {
-            assert_eq!(stderr, Vec::new());
-        }
-    }
-
-    #[cfg(all(unix, not(target_os="android")))]
-    pub fn pwd_cmd() -> Command {
-        Command::new("pwd")
-    }
-    #[cfg(target_os="android")]
-    pub fn pwd_cmd() -> Command {
-        let mut cmd = Command::new("/system/bin/sh");
-        cmd.arg("-c").arg("pwd");
-        cmd
-    }
-
-    #[cfg(windows)]
-    pub fn pwd_cmd() -> Command {
-        let mut cmd = Command::new("cmd");
-        cmd.arg("/c").arg("cd");
-        cmd
+        assert_eq!(stderr, Vec::new());
     }
 
     #[cfg(all(unix, not(target_os="android")))]
@@ -770,15 +797,17 @@ mod tests {
     #[cfg(not(target_os="android"))]
     #[test]
     fn test_inherit_env() {
-        use std::env;
-        if running_on_valgrind() { return; }
+        use env;
 
         let result = env_cmd().output().unwrap();
         let output = String::from_utf8(result.stdout).unwrap();
 
         for (ref k, ref v) in env::vars() {
-            // don't check windows magical empty-named variables
-            assert!(k.is_empty() ||
+            // Windows has hidden environment variables whose names start with
+            // equals signs (`=`). Those do not show up in the output of the
+            // `set` command.
+            assert!((cfg!(windows) && k.starts_with("=")) ||
+                    k.starts_with("DYLD") ||
                     output.contains(&format!("{}={}", *k, *v)),
                     "output doesn't contain `{}={}`\n{}",
                     k, v, output);
@@ -787,8 +816,7 @@ mod tests {
     #[cfg(target_os="android")]
     #[test]
     fn test_inherit_env() {
-        use std::env;
-        if running_on_valgrind() { return; }
+        use env;
 
         let mut result = env_cmd().output().unwrap();
         let output = String::from_utf8(result.stdout).unwrap();