diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2015-05-12 11:03:49 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2015-05-16 11:18:36 -0700 |
| commit | 3dd3450484c1a914d07da2ab522e3bd27ce2a4bb (patch) | |
| tree | 036734c4a002be0f56eb75901802ac32f9a5000d /src/libstd/sys | |
| parent | 5e535eae5c4b70879aefc050a5fe0b8137c07eac (diff) | |
| download | rust-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.rs | 49 | ||||
| -rw-r--r-- | src/libstd/sys/unix/pipe.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process.rs | 13 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/process.rs | 69 | ||||
| -rw-r--r-- | src/libstd/sys/windows/handle.rs | 49 | ||||
| -rw-r--r-- | src/libstd/sys/windows/process.rs | 17 |
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) } |
