std/sys/pal/unix/
pipe.rs
1use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
2use crate::mem;
3use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
4use crate::sys::fd::FileDesc;
5use crate::sys::{cvt, cvt_r};
6use crate::sys_common::{FromInner, IntoInner};
7
8#[derive(Debug)]
13pub struct AnonPipe(FileDesc);
14
15pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
16 let mut fds = [0; 2];
17
18 cfg_if::cfg_if! {
22 if #[cfg(any(
23 target_os = "dragonfly",
24 target_os = "freebsd",
25 target_os = "hurd",
26 target_os = "illumos",
27 target_os = "linux",
28 target_os = "netbsd",
29 target_os = "openbsd",
30 target_os = "redox"
31 ))] {
32 unsafe {
33 cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
34 Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1]))))
35 }
36 } else {
37 unsafe {
38 cvt(libc::pipe(fds.as_mut_ptr()))?;
39
40 let fd0 = FileDesc::from_raw_fd(fds[0]);
41 let fd1 = FileDesc::from_raw_fd(fds[1]);
42 fd0.set_cloexec()?;
43 fd1.set_cloexec()?;
44 Ok((AnonPipe(fd0), AnonPipe(fd1)))
45 }
46 }
47 }
48}
49
50impl AnonPipe {
51 #[allow(dead_code)]
52 pub fn try_clone(&self) -> io::Result<Self> {
54 self.0.duplicate().map(Self)
55 }
56
57 pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
58 self.0.read(buf)
59 }
60
61 pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
62 self.0.read_buf(buf)
63 }
64
65 pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
66 self.0.read_vectored(bufs)
67 }
68
69 #[inline]
70 pub fn is_read_vectored(&self) -> bool {
71 self.0.is_read_vectored()
72 }
73
74 pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
75 self.0.read_to_end(buf)
76 }
77
78 pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
79 self.0.write(buf)
80 }
81
82 pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
83 self.0.write_vectored(bufs)
84 }
85
86 #[inline]
87 pub fn is_write_vectored(&self) -> bool {
88 self.0.is_write_vectored()
89 }
90
91 #[allow(dead_code)]
92 pub fn as_file_desc(&self) -> &FileDesc {
94 &self.0
95 }
96}
97
98impl IntoInner<FileDesc> for AnonPipe {
99 fn into_inner(self) -> FileDesc {
100 self.0
101 }
102}
103
104pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> {
105 let p1 = p1.into_inner();
108 let p2 = p2.into_inner();
109 p1.set_nonblocking(true)?;
110 p2.set_nonblocking(true)?;
111
112 let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
113 fds[0].fd = p1.as_raw_fd();
114 fds[0].events = libc::POLLIN;
115 fds[1].fd = p2.as_raw_fd();
116 fds[1].events = libc::POLLIN;
117 loop {
118 cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
120
121 if fds[0].revents != 0 && read(&p1, v1)? {
122 p2.set_nonblocking(false)?;
123 return p2.read_to_end(v2).map(drop);
124 }
125 if fds[1].revents != 0 && read(&p2, v2)? {
126 p1.set_nonblocking(false)?;
127 return p1.read_to_end(v1).map(drop);
128 }
129 }
130
131 fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> {
137 match fd.read_to_end(dst) {
138 Ok(_) => Ok(true),
139 Err(e) => {
140 if e.raw_os_error() == Some(libc::EWOULDBLOCK)
141 || e.raw_os_error() == Some(libc::EAGAIN)
142 {
143 Ok(false)
144 } else {
145 Err(e)
146 }
147 }
148 }
149 }
150}
151
152impl AsRawFd for AnonPipe {
153 #[inline]
154 fn as_raw_fd(&self) -> RawFd {
155 self.0.as_raw_fd()
156 }
157}
158
159impl AsFd for AnonPipe {
160 fn as_fd(&self) -> BorrowedFd<'_> {
161 self.0.as_fd()
162 }
163}
164
165impl IntoRawFd for AnonPipe {
166 fn into_raw_fd(self) -> RawFd {
167 self.0.into_raw_fd()
168 }
169}
170
171impl FromRawFd for AnonPipe {
172 unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
173 Self(FromRawFd::from_raw_fd(raw_fd))
174 }
175}
176
177impl FromInner<FileDesc> for AnonPipe {
178 fn from_inner(fd: FileDesc) -> Self {
179 Self(fd)
180 }
181}