diff options
Diffstat (limited to 'src/libstd/sys/unix/pipe.rs')
| -rw-r--r-- | src/libstd/sys/unix/pipe.rs | 55 | 
1 files changed, 55 insertions, 0 deletions
| diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index d88193e6227..e5cb3761001 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; + +use cmp; use io; use libc::{self, c_int}; +use mem; use sys::cvt_r; use sys::fd::FileDesc; @@ -68,3 +72,54 @@ impl AnonPipe { pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } } + +pub fn read2(p1: AnonPipe, + v1: &mut Vec<u8>, + p2: AnonPipe, + v2: &mut Vec<u8>) -> io::Result<()> { + // Set both pipes into nonblocking mode as we're gonna be reading from both + // in the `select` loop below, and we wouldn't want one to block the other! + let p1 = p1.into_fd(); + let p2 = p2.into_fd(); + p1.set_nonblocking(true); + p2.set_nonblocking(true); + + let max = cmp::max(p1.raw(), p2.raw()); + loop { + // wait for either pipe to become readable using `select` + try!(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, 0 as *mut _, 0 as *mut _, + 0 as *mut _) + })); + + // Read as much as we can from each pipe, ignoring EWOULDBLOCK or + // EAGAIN. If we hit EOF, then this will happen because the underlying + // reader will return Ok(0), in which case we'll see `Ok` ourselves. In + // this case we flip the other fd back into blocking mode and read + // whatever's leftover on that file descriptor. + let read = |fd: &FileDesc, dst: &mut Vec<u8>| { + match fd.read_to_end(dst) { + Ok(_) => Ok(true), + Err(e) => { + if e.raw_os_error() == Some(libc::EWOULDBLOCK) || + e.raw_os_error() == Some(libc::EAGAIN) { + Ok(false) + } else { + Err(e) + } + } + } + }; + if try!(read(&p1, v1)) { + p2.set_nonblocking(false); + return p2.read_to_end(v2).map(|_| ()); + } + if try!(read(&p2, v2)) { + p1.set_nonblocking(false); + return p1.read_to_end(v1).map(|_| ()); + } + } +} | 
