about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorDavid LeGare <excaliburhissheath@gmail.com>2017-05-05 20:35:41 -0500
committerDavid LeGare <excaliburhissheath@gmail.com>2017-05-05 20:35:41 -0500
commitd7df6dcd7399e0c49b6008ab3b82c979dba835a6 (patch)
treee2054076d05c9f68a99f235717bd95efb72faaf9 /src/libstd/sys
parente406cd1ec9abb77236318db30e362e4654411a1a (diff)
parentf4209651ec4d4455dab4fc3f3a3456a897d9da7f (diff)
downloadrust-d7df6dcd7399e0c49b6008ab3b82c979dba835a6.tar.gz
rust-d7df6dcd7399e0c49b6008ab3b82c979dba835a6.zip
Merge remote-tracking branch 'rust-lang/master' into iss29367-windows-docs
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/redox/process.rs21
-rw-r--r--src/libstd/sys/redox/syscall/call.rs5
-rw-r--r--src/libstd/sys/redox/syscall/number.rs1
-rw-r--r--src/libstd/sys/unix/ext/net.rs4
-rw-r--r--src/libstd/sys/unix/mod.rs2
-rw-r--r--src/libstd/sys/unix/pipe.rs22
-rw-r--r--src/libstd/sys/unix/process/magenta.rs77
-rw-r--r--src/libstd/sys/unix/process/process_common.rs16
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs11
-rw-r--r--src/libstd/sys/unix/time.rs2
-rw-r--r--src/libstd/sys/windows/ext/fs.rs2
-rw-r--r--src/libstd/sys/windows/ext/process.rs1
-rw-r--r--src/libstd/sys/windows/process.rs9
-rw-r--r--src/libstd/sys/windows/stdio.rs92
14 files changed, 147 insertions, 118 deletions
diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs
index 707b4cbc6ac..95e9438cd71 100644
--- a/src/libstd/sys/redox/process.rs
+++ b/src/libstd/sys/redox/process.rs
@@ -270,19 +270,22 @@ impl Command {
         }
 
         if let Some(fd) = stdio.stderr.fd() {
-            let _ = syscall::close(2);
-            t!(cvt(syscall::dup(fd, &[])));
-            let _ = syscall::close(fd);
+            t!(cvt(syscall::dup2(fd, 2, &[])));
+            let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFL, 0)));
+            flags &= ! syscall::O_CLOEXEC;
+            t!(cvt(syscall::fcntl(2, syscall::F_SETFL, flags)));
         }
         if let Some(fd) = stdio.stdout.fd() {
-            let _ = syscall::close(1);
-            t!(cvt(syscall::dup(fd, &[])));
-            let _ = syscall::close(fd);
+            t!(cvt(syscall::dup2(fd, 1, &[])));
+            let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFL, 0)));
+            flags &= ! syscall::O_CLOEXEC;
+            t!(cvt(syscall::fcntl(1, syscall::F_SETFL, flags)));
         }
         if let Some(fd) = stdio.stdin.fd() {
-            let _ = syscall::close(0);
-            t!(cvt(syscall::dup(fd, &[])));
-            let _ = syscall::close(fd);
+            t!(cvt(syscall::dup2(fd, 0, &[])));
+            let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFL, 0)));
+            flags &= ! syscall::O_CLOEXEC;
+            t!(cvt(syscall::fcntl(0, syscall::F_SETFL, flags)));
         }
 
         if let Some(g) = self.gid {
diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs
index f58c240f31e..fadf7325d75 100644
--- a/src/libstd/sys/redox/syscall/call.rs
+++ b/src/libstd/sys/redox/syscall/call.rs
@@ -71,6 +71,11 @@ pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
     unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
 }
 
+/// Copy and transform a file descriptor
+pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
+    unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
+}
+
 /// Replace the current process with a new executable
 pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> {
     unsafe { syscall4(SYS_EXECVE, path.as_ptr() as usize, path.len(),
diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs
index 358746cd20a..98f8b73e4e1 100644
--- a/src/libstd/sys/redox/syscall/number.rs
+++ b/src/libstd/sys/redox/syscall/number.rs
@@ -28,6 +28,7 @@ pub const SYS_UNLINK: usize =   SYS_CLASS_PATH | 10;
 
 pub const SYS_CLOSE: usize =    SYS_CLASS_FILE | 6;
 pub const SYS_DUP: usize =      SYS_CLASS_FILE | SYS_RET_FILE | 41;
+pub const SYS_DUP2: usize =     SYS_CLASS_FILE | SYS_RET_FILE | 63;
 pub const SYS_READ: usize =     SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
 pub const SYS_WRITE: usize =    SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
 pub const SYS_LSEEK: usize =    SYS_CLASS_FILE | 19;
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index 55118829eee..d688f2fa504 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -641,7 +641,7 @@ impl UnixListener {
                 let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
                 let (addr, len) = sockaddr_un(path)?;
 
-                cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len))?;
+                cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
                 cvt(libc::listen(*inner.as_inner(), 128))?;
 
                 Ok(UnixListener(inner))
@@ -920,7 +920,7 @@ impl UnixDatagram {
                 let socket = UnixDatagram::unbound()?;
                 let (addr, len) = sockaddr_un(path)?;
 
-                cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len))?;
+                cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
 
                 Ok(socket)
             }
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index c57751a01d7..854d380d128 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -92,7 +92,7 @@ pub fn init() {
 
     #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
     unsafe fn reset_sigpipe() {
-        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
+        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
     #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))]
     unsafe fn reset_sigpipe() {}
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 51e00fc1ab9..706256ff10e 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -8,11 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use cmp;
 use io;
 use libc::{self, c_int};
 use mem;
-use ptr;
 use sys::{cvt, cvt_r};
 use sys::fd::FileDesc;
 
@@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe,
     p1.set_nonblocking(true)?;
     p2.set_nonblocking(true)?;
 
-    let max = cmp::max(p1.raw(), p2.raw());
+    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
+    fds[0].fd = p1.raw();
+    fds[0].events = libc::POLLIN;
+    fds[1].fd = p2.raw();
+    fds[1].events = libc::POLLIN;
     loop {
-        // wait for either pipe to become readable using `select`
-        cvt_r(|| unsafe {
-            let mut read: libc::fd_set = mem::zeroed();
-            libc::FD_SET(p1.raw(), &mut read);
-            libc::FD_SET(p2.raw(), &mut read);
-            libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
-                         ptr::null_mut())
-        })?;
+        // wait for either pipe to become readable using `poll`
+        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
 
         // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
         // EAGAIN. If we hit EOF, then this will happen because the underlying
@@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe,
                 }
             }
         };
-        if read(&p1, v1)? {
+        if fds[0].revents != 0 && read(&p1, v1)? {
             p2.set_nonblocking(false)?;
             return p2.read_to_end(v2).map(|_| ());
         }
-        if read(&p2, v2)? {
+        if fds[1].revents != 0 && read(&p2, v2)? {
             p1.set_nonblocking(false)?;
             return p1.read_to_end(v1).map(|_| ());
         }
diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs
index 07f29784df6..5b5e29c0374 100644
--- a/src/libstd/sys/unix/process/magenta.rs
+++ b/src/libstd/sys/unix/process/magenta.rs
@@ -202,7 +202,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002;
 
 // ERR_NO_RESOURCES: The system was not able to allocate some resource
 // needed for the operation.
-#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -5;
+#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -3;
 
 // ERR_NO_MEMORY: The system was not able to allocate memory needed
 // for the operation.
@@ -210,30 +210,34 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002;
 
 // ERR_CALL_FAILED: The second phase of mx_channel_call(; did not complete
 // successfully.
-#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -53;
+#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -5;
+
+// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be
+// retried.  This should not be seen outside of the VDSO.
+#[allow(unused)] pub const ERR_INTERRUPTED_RETRY: mx_status_t = -6;
 
 // ======= Parameter errors =======
 // ERR_INVALID_ARGS: an argument is invalid, ex. null pointer
 #[allow(unused)] pub const ERR_INVALID_ARGS: mx_status_t = -10;
 
+// ERR_BAD_HANDLE: A specified handle value does not refer to a handle.
+#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -11;
+
 // ERR_WRONG_TYPE: The subject of the operation is the wrong type to
 // perform the operation.
 // Example: Attempting a message_read on a thread handle.
-#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -54;
+#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -12;
 
 // ERR_BAD_SYSCALL: The specified syscall number is invalid.
-#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -11;
-
-// ERR_BAD_HANDLE: A specified handle value does not refer to a handle.
-#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -12;
+#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -13;
 
 // ERR_OUT_OF_RANGE: An argument is outside the valid range for this
 // operation.
-#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -13;
+#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -14;
 
 // ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for
 // this operation.
-#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -14;
+#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -15;
 
 // ======= Precondition or state errors =======
 // ERR_BAD_STATE: operation failed because the current state of the
@@ -241,47 +245,48 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002;
 // not satisfied
 #[allow(unused)] pub const ERR_BAD_STATE: mx_status_t = -20;
 
+// ERR_TIMED_OUT: The time limit for the operation elapsed before
+// the operation completed.
+#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -21;
+
+// ERR_SHOULD_WAIT: The operation cannot be performed currently but
+// potentially could succeed if the caller waits for a prerequisite
+// to be satisfied, for example waiting for a handle to be readable
+// or writable.
+// Example: Attempting to read from a message pipe that has no
+// messages waiting but has an open remote will return ERR_SHOULD_WAIT.
+// Attempting to read from a message pipe that has no messages waiting
+// and has a closed remote end will return ERR_REMOTE_CLOSED.
+#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -22;
+
+// ERR_CANCELED: The in-progress operation (e.g. a wait) has been
+// // canceled.
+#[allow(unused)] pub const ERR_CANCELED: mx_status_t = -23;
+
+// ERR_PEER_CLOSED: The operation failed because the remote end
+// of the subject of the operation was closed.
+#[allow(unused)] pub const ERR_PEER_CLOSED: mx_status_t = -24;
+
 // ERR_NOT_FOUND: The requested entity is not found.
-#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -3;
+#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -25;
 
 // ERR_ALREADY_EXISTS: An object with the specified identifier
 // already exists.
 // Example: Attempting to create a file when a file already exists
 // with that name.
-#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -15;
+#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -26;
 
 // ERR_ALREADY_BOUND: The operation failed because the named entity
 // is already owned or controlled by another entity. The operation
 // could succeed later if the current owner releases the entity.
-#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -16;
-
-// ERR_TIMED_OUT: The time limit for the operation elapsed before
-// the operation completed.
-#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -23;
-
-// ERR_HANDLE_CLOSED: a handle being waited on was closed
-#[allow(unused)] pub const ERR_HANDLE_CLOSED: mx_status_t = -24;
-
-// ERR_REMOTE_CLOSED: The operation failed because the remote end
-// of the subject of the operation was closed.
-#[allow(unused)] pub const ERR_REMOTE_CLOSED: mx_status_t = -25;
+#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -27;
 
 // ERR_UNAVAILABLE: The subject of the operation is currently unable
 // to perform the operation.
 // Note: This is used when there's no direct way for the caller to
 // observe when the subject will be able to perform the operation
 // and should thus retry.
-#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -26;
-
-// ERR_SHOULD_WAIT: The operation cannot be performed currently but
-// potentially could succeed if the caller waits for a prerequisite
-// to be satisfied, for example waiting for a handle to be readable
-// or writable.
-// Example: Attempting to read from a message pipe that has no
-// messages waiting but has an open remote will return ERR_SHOULD_WAIT.
-// Attempting to read from a message pipe that has no messages waiting
-// and has a closed remote end will return ERR_REMOTE_CLOSED.
-#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -27;
+#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -28;
 
 // ======= Permission check errors =======
 // ERR_ACCESS_DENIED: The caller did not have permission to perform
@@ -312,3 +317,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002;
 #[allow(unused)] pub const ERR_BAD_PATH: mx_status_t = -50;
 #[allow(unused)] pub const ERR_NOT_DIR: mx_status_t = -51;
 #[allow(unused)] pub const ERR_NOT_FILE: mx_status_t = -52;
+// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit.
+#[allow(unused)] pub const ERR_FILE_BIG: mx_status_t = -53;
+// ERR_NO_SPACE: Filesystem or device space is exhausted.
+#[allow(unused)] pub const ERR_NO_SPACE: mx_status_t = -54;
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index 5f1a6c2f746..e9f41009064 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -417,13 +417,27 @@ mod tests {
         }
     }
 
+    // Android with api less than 21 define sig* functions inline, so it is not
+    // available for dynamic link. Implementing sigemptyset and sigaddset allow us
+    // to support older Android version (independent of libc version).
+    // The following implementations are based on https://git.io/vSkNf
+
     #[cfg(not(target_os = "android"))]
     extern {
+        #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
+        fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
+
         #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
         fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
     }
 
     #[cfg(target_os = "android")]
+    unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
+        libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
+        return 0;
+    }
+
+    #[cfg(target_os = "android")]
     unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
         use slice;
 
@@ -450,7 +464,7 @@ mod tests {
 
             let mut set: libc::sigset_t = mem::uninitialized();
             let mut old_set: libc::sigset_t = mem::uninitialized();
-            t!(cvt(libc::sigemptyset(&mut set)));
+            t!(cvt(sigemptyset(&mut set)));
             t!(cvt(sigaddset(&mut set, libc::SIGINT)));
             t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
 
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index a213273aac8..edd322ca6fa 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -193,7 +193,16 @@ impl Command {
             // need to clean things up now to avoid confusing the program
             // we're about to run.
             let mut set: libc::sigset_t = mem::uninitialized();
-            t!(cvt(libc::sigemptyset(&mut set)));
+            if cfg!(target_os = "android") {
+                // Implementing sigemptyset allow us to support older Android
+                // versions. See the comment about Android and sig* functions in
+                // process_common.rs
+                libc::memset(&mut set as *mut _ as *mut _,
+                             0,
+                             mem::size_of::<libc::sigset_t>());
+            } else {
+                t!(cvt(libc::sigemptyset(&mut set)));
+            }
             t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set,
                                          ptr::null_mut())));
             let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index a08cec38f73..a1ad94872de 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -157,7 +157,7 @@ mod inner {
         pub fn sub_duration(&self, other: &Duration) -> Instant {
             Instant {
                 t: self.t.checked_sub(dur2intervals(other))
-                       .expect("overflow when adding duration to instant"),
+                       .expect("overflow when subtracting duration from instant"),
             }
         }
     }
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index ea322b9822a..e2e405db276 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -188,7 +188,7 @@ pub trait OpenOptionsExt {
     /// [`CreateFile`]).
     ///
     /// If a _new_ file is created because it does not yet exist and
-    ///`.create(true)` or `.create_new(true)` are specified, the new file is
+    /// `.create(true)` or `.create_new(true)` are specified, the new file is
     /// given the attributes declared with `.attributes()`.
     ///
     /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
index 1419a4af427..759f055c4b1 100644
--- a/src/libstd/sys/windows/ext/process.rs
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -104,6 +104,7 @@ pub trait CommandExt {
     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
     ///
     /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+    ///
     /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
     #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index 1afb3728c9d..dfbc1b581ee 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -257,8 +257,13 @@ impl Stdio {
             // INVALID_HANDLE_VALUE.
             Stdio::Inherit => {
                 match stdio::get(stdio_id) {
-                    Ok(io) => io.handle().duplicate(0, true,
-                                                    c::DUPLICATE_SAME_ACCESS),
+                    Ok(io) => {
+                        let io = Handle::new(io.handle());
+                        let ret = io.duplicate(0, true,
+                                               c::DUPLICATE_SAME_ACCESS);
+                        io.into_raw();
+                        return ret
+                    }
                     Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
                 }
             }
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index b1a57c349fb..d72e4b4438b 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -22,42 +22,43 @@ use sys::cvt;
 use sys::handle::Handle;
 use sys_common::io::read_to_end_uninitialized;
 
-pub struct NoClose(Option<Handle>);
-
 pub enum Output {
-    Console(NoClose),
-    Pipe(NoClose),
+    Console(c::HANDLE),
+    Pipe(c::HANDLE),
 }
 
 pub struct Stdin {
-    handle: Output,
     utf8: Mutex<io::Cursor<Vec<u8>>>,
 }
-pub struct Stdout(Output);
-pub struct Stderr(Output);
+pub struct Stdout;
+pub struct Stderr;
 
 pub fn get(handle: c::DWORD) -> io::Result<Output> {
     let handle = unsafe { c::GetStdHandle(handle) };
     if handle == c::INVALID_HANDLE_VALUE {
         Err(io::Error::last_os_error())
     } else if handle.is_null() {
-        Err(io::Error::new(io::ErrorKind::Other,
-                           "no stdio handle available for this process"))
+        Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
     } else {
-        let ret = NoClose::new(handle);
         let mut out = 0;
         match unsafe { c::GetConsoleMode(handle, &mut out) } {
-            0 => Ok(Output::Pipe(ret)),
-            _ => Ok(Output::Console(ret)),
+            0 => Ok(Output::Pipe(handle)),
+            _ => Ok(Output::Console(handle)),
         }
     }
 }
 
-fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
-    let handle = match *out {
-        Output::Console(ref c) => c.get().raw(),
-        Output::Pipe(ref p) => return p.get().write(data),
+fn write(handle: c::DWORD, data: &[u8]) -> io::Result<usize> {
+    let handle = match try!(get(handle)) {
+        Output::Console(c) => c,
+        Output::Pipe(p) => {
+            let handle = Handle::new(p);
+            let ret = handle.write(data);
+            handle.into_raw();
+            return ret
+        }
     };
+
     // As with stdin on windows, stdout often can't handle writes of large
     // sizes. For an example, see #14940. For this reason, don't try to
     // write the entire output buffer on windows.
@@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
 
 impl Stdin {
     pub fn new() -> io::Result<Stdin> {
-        get(c::STD_INPUT_HANDLE).map(|handle| {
-            Stdin {
-                handle: handle,
-                utf8: Mutex::new(Cursor::new(Vec::new())),
-            }
+        Ok(Stdin {
+            utf8: Mutex::new(Cursor::new(Vec::new())),
         })
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        let handle = match self.handle {
-            Output::Console(ref c) => c.get().raw(),
-            Output::Pipe(ref p) => return p.get().read(buf),
+        let handle = match try!(get(c::STD_INPUT_HANDLE)) {
+            Output::Console(c) => c,
+            Output::Pipe(p) => {
+                let handle = Handle::new(p);
+                let ret = handle.read(buf);
+                handle.into_raw();
+                return ret
+            }
         };
         let mut utf8 = self.utf8.lock().unwrap();
         // Read more if the buffer is empty
@@ -125,11 +128,9 @@ impl Stdin {
                 Ok(utf8) => utf8.into_bytes(),
                 Err(..) => return Err(invalid_encoding()),
             };
-            if let Output::Console(_) = self.handle {
-                if let Some(&last_byte) = data.last() {
-                    if last_byte == CTRL_Z {
-                        data.pop();
-                    }
+            if let Some(&last_byte) = data.last() {
+                if last_byte == CTRL_Z {
+                    data.pop();
                 }
             }
             *utf8 = Cursor::new(data);
@@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin {
 
 impl Stdout {
     pub fn new() -> io::Result<Stdout> {
-        get(c::STD_OUTPUT_HANDLE).map(Stdout)
+        Ok(Stdout)
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        write(&self.0, data)
+        write(c::STD_OUTPUT_HANDLE, data)
     }
 
     pub fn flush(&self) -> io::Result<()> {
@@ -172,11 +173,11 @@ impl Stdout {
 
 impl Stderr {
     pub fn new() -> io::Result<Stderr> {
-        get(c::STD_ERROR_HANDLE).map(Stderr)
+        Ok(Stderr)
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        write(&self.0, data)
+        write(c::STD_ERROR_HANDLE, data)
     }
 
     pub fn flush(&self) -> io::Result<()> {
@@ -197,27 +198,12 @@ impl io::Write for Stderr {
     }
 }
 
-impl NoClose {
-    fn new(handle: c::HANDLE) -> NoClose {
-        NoClose(Some(Handle::new(handle)))
-    }
-
-    fn get(&self) -> &Handle { self.0.as_ref().unwrap() }
-}
-
-impl Drop for NoClose {
-    fn drop(&mut self) {
-        self.0.take().unwrap().into_raw();
-    }
-}
-
 impl Output {
-    pub fn handle(&self) -> &Handle {
-        let nc = match *self {
-            Output::Console(ref c) => c,
-            Output::Pipe(ref c) => c,
-        };
-        nc.0.as_ref().unwrap()
+    pub fn handle(&self) -> c::HANDLE {
+        match *self {
+            Output::Console(c) => c,
+            Output::Pipe(c) => c,
+        }
     }
 }