]>
Commit | Line | Data |
---|---|---|
416331ca | 1 | use crate::io::{self, IoSlice, IoSliceMut}; |
416331ca | 2 | use crate::mem; |
60c5eb7d | 3 | use crate::sync::atomic::AtomicBool; |
416331ca XL |
4 | use crate::sys::fd::FileDesc; |
5 | use crate::sys::{cvt, cvt_r}; | |
60c5eb7d | 6 | use libc::{self /*, c_int apparently not used? */}; |
416331ca XL |
7 | |
8 | pub struct AnonPipe(FileDesc); | |
9 | ||
10 | pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { | |
11 | static INVALID: AtomicBool = AtomicBool::new(false); | |
12 | ||
13 | let mut fds = [0; 2]; | |
14 | cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; | |
15 | ||
16 | let fd0 = FileDesc::new(fds[0]); | |
17 | let fd1 = FileDesc::new(fds[1]); | |
18 | fd0.set_cloexec()?; | |
19 | fd1.set_cloexec()?; | |
20 | Ok((AnonPipe(fd0), AnonPipe(fd1))) | |
21 | } | |
22 | ||
23 | impl AnonPipe { | |
24 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { | |
25 | self.0.read(buf) | |
26 | } | |
f9f354fc | 27 | |
416331ca | 28 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
60c5eb7d XL |
29 | self.0.read_vectored(bufs) |
30 | } | |
416331ca | 31 | |
f9f354fc XL |
32 | #[inline] |
33 | pub fn is_read_vectored(&self) -> bool { | |
34 | self.0.is_read_vectored() | |
35 | } | |
36 | ||
416331ca XL |
37 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
38 | self.0.write(buf) | |
39 | } | |
40 | ||
60c5eb7d XL |
41 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
42 | self.0.write_vectored(bufs) | |
43 | } | |
416331ca | 44 | |
f9f354fc XL |
45 | #[inline] |
46 | pub fn is_write_vectored(&self) -> bool { | |
47 | self.0.is_write_vectored() | |
48 | } | |
49 | ||
60c5eb7d XL |
50 | pub fn fd(&self) -> &FileDesc { |
51 | &self.0 | |
52 | } | |
53 | pub fn into_fd(self) -> FileDesc { | |
54 | self.0 | |
55 | } | |
416331ca XL |
56 | pub fn diverge(&self) -> ! { |
57 | panic!() | |
60c5eb7d | 58 | } |
416331ca XL |
59 | } |
60 | ||
60c5eb7d | 61 | pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> { |
416331ca XL |
62 | // Set both pipes into nonblocking mode as we're gonna be reading from both |
63 | // in the `select` loop below, and we wouldn't want one to block the other! | |
64 | let p1 = p1.into_fd(); | |
65 | let p2 = p2.into_fd(); | |
66 | p1.set_nonblocking_pipe(true)?; | |
67 | p2.set_nonblocking_pipe(true)?; | |
68 | ||
69 | let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; | |
70 | fds[0].fd = p1.raw(); | |
71 | fds[0].events = libc::POLLIN; | |
72 | fds[1].fd = p2.raw(); | |
73 | fds[1].events = libc::POLLIN; | |
74 | loop { | |
75 | // wait for either pipe to become readable using `poll` | |
76 | cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; | |
77 | ||
78 | if fds[0].revents != 0 && read(&p1, v1)? { | |
79 | p2.set_nonblocking_pipe(false)?; | |
dfeec247 | 80 | return p2.read_to_end(v2).map(drop); |
416331ca XL |
81 | } |
82 | if fds[1].revents != 0 && read(&p2, v2)? { | |
83 | p1.set_nonblocking_pipe(false)?; | |
dfeec247 | 84 | return p1.read_to_end(v1).map(drop); |
416331ca XL |
85 | } |
86 | } | |
87 | ||
88 | // Read as much as we can from each pipe, ignoring EWOULDBLOCK or | |
89 | // EAGAIN. If we hit EOF, then this will happen because the underlying | |
90 | // reader will return Ok(0), in which case we'll see `Ok` ourselves. In | |
91 | // this case we flip the other fd back into blocking mode and read | |
92 | // whatever's leftover on that file descriptor. | |
93 | fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> { | |
94 | match fd.read_to_end(dst) { | |
95 | Ok(_) => Ok(true), | |
96 | Err(e) => { | |
60c5eb7d XL |
97 | if e.raw_os_error() == Some(libc::EWOULDBLOCK) |
98 | || e.raw_os_error() == Some(libc::EAGAIN) | |
99 | { | |
416331ca XL |
100 | Ok(false) |
101 | } else { | |
102 | Err(e) | |
103 | } | |
104 | } | |
105 | } | |
106 | } | |
107 | } |