about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-05-12 11:03:49 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-05-16 11:18:36 -0700
commit3dd3450484c1a914d07da2ab522e3bd27ce2a4bb (patch)
tree036734c4a002be0f56eb75901802ac32f9a5000d /src/libstd/sys
parent5e535eae5c4b70879aefc050a5fe0b8137c07eac (diff)
downloadrust-3dd3450484c1a914d07da2ab522e3bd27ce2a4bb.tar.gz
rust-3dd3450484c1a914d07da2ab522e3bd27ce2a4bb.zip
std: Implement lowering and raising for process IO
This commit implements a number of standard traits for the standard library's
process I/O handles. The `FromRaw{Fd,Handle}` traits are now implemented for the
`Stdio` type and the `AsRaw{Fd,Handle}` traits are now implemented for the
`Child{Stdout,Stdin,Stderr}` types. Additionally this implements the
`AsRawHandle` trait for `Child` on Windows.

The stability markers for these implementations mention that they are stable for
1.1 as I will nominate this commit for cherry-picking to beta.
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/unix/ext/process.rs49
-rw-r--r--src/libstd/sys/unix/pipe.rs5
-rw-r--r--src/libstd/sys/unix/process.rs13
-rw-r--r--src/libstd/sys/windows/ext/mod.rs1
-rw-r--r--src/libstd/sys/windows/ext/process.rs69
-rw-r--r--src/libstd/sys/windows/handle.rs49
-rw-r--r--src/libstd/sys/windows/process.rs17
7 files changed, 185 insertions, 18 deletions
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
index 45d0d62a015..2d30b016a2d 100644
--- a/src/libstd/sys/unix/ext/process.rs
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -13,10 +13,11 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use os::unix::raw::{uid_t, gid_t};
+use os::unix::io::{FromRawFd, RawFd, AsRawFd};
 use prelude::v1::*;
 use process;
 use sys;
-use sys_common::{AsInnerMut, AsInner};
+use sys_common::{AsInnerMut, AsInner, FromInner};
 
 /// Unix-specific extensions to the `std::process::Command` builder
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -63,3 +64,49 @@ impl ExitStatusExt for process::ExitStatus {
         }
     }
 }
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for process::Stdio {
+    /// Creates a new instance of `Stdio` from the raw underlying file
+    /// descriptor.
+    ///
+    /// When this `Stdio` is used as an I/O handle for a child process the given
+    /// file descriptor will be `dup`d into the destination file descriptor in
+    /// the child process.
+    ///
+    /// Note that this function **does not** take ownership of the file
+    /// descriptor provided and it will **not** be closed when `Stdio` goes out
+    /// of scope. As a result this method is unsafe because due to the lack of
+    /// knowledge about the lifetime of the provided file descriptor, this could
+    /// cause another I/O primitive's ownership property of its file descriptor
+    /// to be violated.
+    ///
+    /// Also note that this file descriptor may be used multiple times to spawn
+    /// processes. For example the `Command::spawn` function could be called
+    /// more than once to spawn more than one process sharing this file
+    /// descriptor.
+    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+        process::Stdio::from_inner(sys::process::Stdio::Fd(fd))
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawFd for process::ChildStdin {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawFd for process::ChildStdout {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawFd for process::ChildStderr {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index e9d8c69fefb..6283a29ae46 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -44,7 +44,6 @@ impl AnonPipe {
         self.0.write(buf)
     }
 
-    pub fn into_fd(self) -> FileDesc {
-        self.0
-    }
+    pub fn fd(&self) -> &FileDesc { &self.0 }
+    pub fn into_fd(self) -> FileDesc { self.0 }
 }
diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs
index 290310f4ad9..c67fbfd0a14 100644
--- a/src/libstd/sys/unix/process.rs
+++ b/src/libstd/sys/unix/process.rs
@@ -123,6 +123,7 @@ pub enum Stdio {
     Inherit,
     Piped(AnonPipe),
     None,
+    Fd(c_int),
 }
 
 const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
@@ -253,6 +254,7 @@ impl Process {
         let setup = |src: Stdio, dst: c_int| {
             let fd = match src {
                 Stdio::Inherit => return true,
+                Stdio::Fd(fd) => return cvt_r(|| libc::dup2(fd, dst)).is_ok(),
                 Stdio::Piped(pipe) => pipe.into_fd(),
 
                 // If a stdio file descriptor is set to be ignored, we open up
@@ -412,3 +414,14 @@ fn translate_status(status: c_int) -> ExitStatus {
         ExitStatus::Signal(imp::WTERMSIG(status))
     }
 }
+
+impl Stdio {
+    pub fn clone_if_copy(&self) -> Stdio {
+        match *self {
+            Stdio::Inherit => Stdio::Inherit,
+            Stdio::None => Stdio::None,
+            Stdio::Fd(fd) => Stdio::Fd(fd),
+            Stdio::Piped(_) => unreachable!(),
+        }
+    }
+}
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
index 08dfa4cc877..ead533e7759 100644
--- a/src/libstd/sys/windows/ext/mod.rs
+++ b/src/libstd/sys/windows/ext/mod.rs
@@ -20,6 +20,7 @@ pub mod ffi;
 pub mod fs;
 pub mod io;
 pub mod raw;
+pub mod process;
 
 /// A prelude for conveniently writing platform-specific code.
 ///
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
new file mode 100644
index 00000000000..0fd43a450f3
--- /dev/null
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -0,0 +1,69 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Extensions to `std::process` for Windows.
+
+#![stable(feature = "from_raw_os", since = "1.1.0")]
+
+use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle};
+use process;
+use sys;
+use sys_common::{AsInner, FromInner};
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawHandle for process::Stdio {
+    /// Creates a new instance of `Stdio` from the raw underlying handle.
+    ///
+    /// When this `Stdio` is used as an I/O handle for a child process the given
+    /// handle will be duplicated via `DuplicateHandle` to ensure that the
+    /// handle has the correct permissions to cross the process boundary.
+    ///
+    /// Note that this function **does not** take ownership of the handle
+    /// provided and it will **not** be closed when `Stdio` goes out of scope.
+    /// As a result this method is unsafe because due to the lack of knowledge
+    /// about the lifetime of the provided handle, this could cause another I/O
+    /// primitive's ownership property of its handle to be violated.
+    ///
+    /// Also note that this handle may be used multiple times to spawn
+    /// processes. For example the `Command::spawn` function could be called
+    /// more than once to spawn more than one process sharing this handle.
+    unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
+        let handle = sys::handle::RawHandle::new(handle as *mut _);
+        process::Stdio::from_inner(sys::process::Stdio::Handle(handle))
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawHandle for process::Child {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawHandle for process::ChildStdin {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawHandle for process::ChildStdout {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl AsRawHandle for process::ChildStderr {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index c835d503388..a566c5eff32 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -15,26 +15,55 @@ use io;
 use libc::funcs::extra::kernel32::{GetCurrentProcess, DuplicateHandle};
 use libc::{self, HANDLE};
 use mem;
+use ops::Deref;
 use ptr;
 use sys::cvt;
 
-pub struct Handle(HANDLE);
+/// An owned container for `HANDLE` object, closing them on Drop.
+///
+/// All methods are inherited through a `Deref` impl to `RawHandle`
+pub struct Handle(RawHandle);
 
-unsafe impl Send for Handle {}
-unsafe impl Sync for Handle {}
+/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference
+/// as well as Rust-y methods.
+///
+/// This does **not** drop the handle when it goes out of scope, use `Handle`
+/// instead for that.
+#[derive(Copy, Clone)]
+pub struct RawHandle(HANDLE);
+
+unsafe impl Send for RawHandle {}
+unsafe impl Sync for RawHandle {}
 
 impl Handle {
     pub fn new(handle: HANDLE) -> Handle {
-        Handle(handle)
+        Handle(RawHandle::new(handle))
     }
 
-    pub fn raw(&self) -> HANDLE { self.0 }
-
     pub fn into_raw(self) -> HANDLE {
-        let ret = self.0;
+        let ret = self.raw();
         mem::forget(self);
         return ret;
     }
+}
+
+impl Deref for Handle {
+    type Target = RawHandle;
+    fn deref(&self) -> &RawHandle { &self.0 }
+}
+
+impl Drop for Handle {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.raw()); }
+    }
+}
+
+impl RawHandle {
+    pub fn new(handle: HANDLE) -> RawHandle {
+        RawHandle(handle)
+    }
+
+    pub fn raw(&self) -> HANDLE { self.0 }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let mut read = 0;
@@ -79,9 +108,3 @@ impl Handle {
         Ok(Handle::new(ret))
     }
 }
-
-impl Drop for Handle {
-    fn drop(&mut self) {
-        unsafe { let _ = libc::CloseHandle(self.0); }
-    }
-}
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index 032a349b00e..9b0ab692a34 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -27,7 +27,7 @@ use ptr;
 use sync::{StaticMutex, MUTEX_INIT};
 use sys::c;
 use sys::fs::{OpenOptions, File};
-use sys::handle::Handle;
+use sys::handle::{Handle, RawHandle};
 use sys::pipe::AnonPipe;
 use sys::stdio;
 use sys::{self, cvt};
@@ -109,6 +109,7 @@ pub enum Stdio {
     Inherit,
     Piped(AnonPipe),
     None,
+    Handle(RawHandle),
 }
 
 impl Process {
@@ -211,6 +212,8 @@ impl Process {
             }
         }
     }
+
+    pub fn handle(&self) -> &Handle { &self.handle }
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -347,6 +350,15 @@ fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec<u16>) {
 }
 
 impl Stdio {
+    pub fn clone_if_copy(&self) -> Stdio {
+        match *self {
+            Stdio::Inherit => Stdio::Inherit,
+            Stdio::None => Stdio::None,
+            Stdio::Handle(handle) => Stdio::Handle(handle),
+            Stdio::Piped(_) => unreachable!(),
+        }
+    }
+
     fn to_handle(&self, stdio_id: libc::DWORD) -> io::Result<Handle> {
         use libc::DUPLICATE_SAME_ACCESS;
 
@@ -356,6 +368,9 @@ impl Stdio {
                     io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
                 })
             }
+            Stdio::Handle(ref handle) => {
+                handle.duplicate(0, true, DUPLICATE_SAME_ACCESS)
+            }
             Stdio::Piped(ref pipe) => {
                 pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
             }