mio/sys/unix/pipe.rs
1//! Unix pipe.
2//!
3//! See the [`new`] function for documentation.
4
5use std::io;
6use std::os::fd::RawFd;
7
8#[cfg_attr(not(feature = "os-ext"), allow(dead_code))] // Used by pipe waker, but not for all OS.
9pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> {
10 let mut fds: [RawFd; 2] = [-1, -1];
11
12 #[cfg(any(
13 target_os = "android",
14 target_os = "dragonfly",
15 target_os = "freebsd",
16 target_os = "fuchsia",
17 target_os = "hurd",
18 target_os = "linux",
19 target_os = "netbsd",
20 target_os = "openbsd",
21 target_os = "illumos",
22 target_os = "redox",
23 target_os = "solaris",
24 target_os = "vita",
25 target_os = "cygwin",
26 target_os = "nuttx",
27 ))]
28 unsafe {
29 if libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) != 0 {
30 return Err(io::Error::last_os_error());
31 }
32 }
33
34 #[cfg(any(
35 target_os = "aix",
36 target_os = "haiku",
37 target_os = "ios",
38 target_os = "macos",
39 target_os = "tvos",
40 target_os = "visionos",
41 target_os = "watchos",
42 target_os = "espidf",
43 target_os = "nto",
44 ))]
45 unsafe {
46 // For platforms that don't have `pipe2(2)` we need to manually set the
47 // correct flags on the file descriptor.
48 if libc::pipe(fds.as_mut_ptr()) != 0 {
49 return Err(io::Error::last_os_error());
50 }
51
52 for fd in &fds {
53 if libc::fcntl(*fd, libc::F_SETFL, libc::O_NONBLOCK) != 0
54 || libc::fcntl(*fd, libc::F_SETFD, libc::FD_CLOEXEC) != 0
55 {
56 let err = io::Error::last_os_error();
57 // Don't leak file descriptors. Can't handle closing error though.
58 let _ = libc::close(fds[0]);
59 let _ = libc::close(fds[1]);
60 return Err(err);
61 }
62 }
63 }
64
65 Ok(fds)
66}
67
68cfg_os_ext! {
69use std::fs::File;
70use std::io::{IoSlice, IoSliceMut, Read, Write};
71use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd};
72use std::process::{ChildStderr, ChildStdin, ChildStdout};
73
74use crate::io_source::IoSource;
75use crate::{event, Interest, Registry, Token};
76
77/// Create a new non-blocking Unix pipe.
78///
79/// This is a wrapper around Unix's [`pipe(2)`] system call and can be used as
80/// inter-process or thread communication channel.
81///
82/// This channel may be created before forking the process and then one end used
83/// in each process, e.g. the parent process has the sending end to send command
84/// to the child process.
85///
86/// [`pipe(2)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html
87///
88/// # Events
89///
90/// The [`Sender`] can be registered with [`WRITABLE`] interest to receive
91/// [writable events], the [`Receiver`] with [`READABLE`] interest. Once data is
92/// written to the `Sender` the `Receiver` will receive an [readable event].
93///
94/// In addition to those events, events will also be generated if the other side
95/// is dropped. To check if the `Sender` is dropped you'll need to check
96/// [`is_read_closed`] on events for the `Receiver`, if it returns true the
97/// `Sender` is dropped. On the `Sender` end check [`is_write_closed`], if it
98/// returns true the `Receiver` was dropped. Also see the second example below.
99///
100/// [`WRITABLE`]: Interest::WRITABLE
101/// [writable events]: event::Event::is_writable
102/// [`READABLE`]: Interest::READABLE
103/// [readable event]: event::Event::is_readable
104/// [`is_read_closed`]: event::Event::is_read_closed
105/// [`is_write_closed`]: event::Event::is_write_closed
106///
107/// # Deregistering
108///
109/// Both `Sender` and `Receiver` will deregister themselves when dropped,
110/// **iff** the file descriptors are not duplicated (via [`dup(2)`]).
111///
112/// [`dup(2)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html
113///
114/// # Examples
115///
116/// Simple example that writes data into the sending end and read it from the
117/// receiving end.
118///
119/// ```
120/// use std::io::{self, Read, Write};
121///
122/// use mio::{Poll, Events, Interest, Token};
123/// use mio::unix::pipe;
124///
125/// // Unique tokens for the two ends of the channel.
126/// const PIPE_RECV: Token = Token(0);
127/// const PIPE_SEND: Token = Token(1);
128///
129/// # fn main() -> io::Result<()> {
130/// // Create our `Poll` instance and the `Events` container.
131/// let mut poll = Poll::new()?;
132/// let mut events = Events::with_capacity(8);
133///
134/// // Create a new pipe.
135/// let (mut sender, mut receiver) = pipe::new()?;
136///
137/// // Register both ends of the channel.
138/// poll.registry().register(&mut receiver, PIPE_RECV, Interest::READABLE)?;
139/// poll.registry().register(&mut sender, PIPE_SEND, Interest::WRITABLE)?;
140///
141/// const MSG: &[u8; 11] = b"Hello world";
142///
143/// loop {
144/// poll.poll(&mut events, None)?;
145///
146/// for event in events.iter() {
147/// match event.token() {
148/// PIPE_SEND => sender.write(MSG)
149/// .and_then(|n| if n != MSG.len() {
150/// // We'll consider a short write an error in this
151/// // example. NOTE: we can't use `write_all` with
152/// // non-blocking I/O.
153/// Err(io::ErrorKind::WriteZero.into())
154/// } else {
155/// Ok(())
156/// })?,
157/// PIPE_RECV => {
158/// let mut buf = [0; 11];
159/// let n = receiver.read(&mut buf)?;
160/// println!("received: {:?}", &buf[0..n]);
161/// assert_eq!(n, MSG.len());
162/// assert_eq!(&buf, &*MSG);
163/// return Ok(());
164/// },
165/// _ => unreachable!(),
166/// }
167/// }
168/// }
169/// # }
170/// ```
171///
172/// Example that receives an event once the `Sender` is dropped.
173///
174/// ```
175/// # use std::io;
176/// #
177/// # use mio::{Poll, Events, Interest, Token};
178/// # use mio::unix::pipe;
179/// #
180/// # const PIPE_RECV: Token = Token(0);
181/// # const PIPE_SEND: Token = Token(1);
182/// #
183/// # fn main() -> io::Result<()> {
184/// // Same setup as in the example above.
185/// let mut poll = Poll::new()?;
186/// let mut events = Events::with_capacity(8);
187///
188/// let (mut sender, mut receiver) = pipe::new()?;
189///
190/// poll.registry().register(&mut receiver, PIPE_RECV, Interest::READABLE)?;
191/// poll.registry().register(&mut sender, PIPE_SEND, Interest::WRITABLE)?;
192///
193/// // Drop the sender.
194/// drop(sender);
195///
196/// poll.poll(&mut events, None)?;
197///
198/// for event in events.iter() {
199/// match event.token() {
200/// PIPE_RECV if event.is_read_closed() => {
201/// // Detected that the sender was dropped.
202/// println!("Sender dropped!");
203/// return Ok(());
204/// },
205/// _ => unreachable!(),
206/// }
207/// }
208/// # unreachable!();
209/// # }
210/// ```
211pub fn new() -> io::Result<(Sender, Receiver)> {
212 let fds = new_raw()?;
213 // SAFETY: `new_raw` initialised the `fds` above.
214 let r = unsafe { Receiver::from_raw_fd(fds[0]) };
215 let w = unsafe { Sender::from_raw_fd(fds[1]) };
216 Ok((w, r))
217}
218
219/// Sending end of an Unix pipe.
220///
221/// See [`new`] for documentation, including examples.
222#[derive(Debug)]
223pub struct Sender {
224 inner: IoSource<File>,
225}
226
227impl Sender {
228 /// Set the `Sender` into or out of non-blocking mode.
229 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
230 set_nonblocking(self.inner.as_raw_fd(), nonblocking)
231 }
232
233 /// Execute an I/O operation ensuring that the socket receives more events
234 /// if it hits a [`WouldBlock`] error.
235 ///
236 /// # Notes
237 ///
238 /// This method is required to be called for **all** I/O operations to
239 /// ensure the user will receive events once the socket is ready again after
240 /// returning a [`WouldBlock`] error.
241 ///
242 /// [`WouldBlock`]: io::ErrorKind::WouldBlock
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// # use std::error::Error;
248 /// #
249 /// # fn main() -> Result<(), Box<dyn Error>> {
250 /// use std::io;
251 /// use std::os::fd::AsRawFd;
252 /// use mio::unix::pipe;
253 ///
254 /// let (sender, receiver) = pipe::new()?;
255 ///
256 /// // Wait until the sender is writable...
257 ///
258 /// // Write to the sender using a direct libc call, of course the
259 /// // `io::Write` implementation would be easier to use.
260 /// let buf = b"hello";
261 /// let n = sender.try_io(|| {
262 /// let buf_ptr = &buf as *const _ as *const _;
263 /// let res = unsafe { libc::write(sender.as_raw_fd(), buf_ptr, buf.len()) };
264 /// if res != -1 {
265 /// Ok(res as usize)
266 /// } else {
267 /// // If EAGAIN or EWOULDBLOCK is set by libc::write, the closure
268 /// // should return `WouldBlock` error.
269 /// Err(io::Error::last_os_error())
270 /// }
271 /// })?;
272 /// eprintln!("write {} bytes", n);
273 ///
274 /// // Wait until the receiver is readable...
275 ///
276 /// // Read from the receiver using a direct libc call, of course the
277 /// // `io::Read` implementation would be easier to use.
278 /// let mut buf = [0; 512];
279 /// let n = receiver.try_io(|| {
280 /// let buf_ptr = &mut buf as *mut _ as *mut _;
281 /// let res = unsafe { libc::read(receiver.as_raw_fd(), buf_ptr, buf.len()) };
282 /// if res != -1 {
283 /// Ok(res as usize)
284 /// } else {
285 /// // If EAGAIN or EWOULDBLOCK is set by libc::read, the closure
286 /// // should return `WouldBlock` error.
287 /// Err(io::Error::last_os_error())
288 /// }
289 /// })?;
290 /// eprintln!("read {} bytes", n);
291 /// # Ok(())
292 /// # }
293 /// ```
294 pub fn try_io<F, T>(&self, f: F) -> io::Result<T>
295 where
296 F: FnOnce() -> io::Result<T>,
297 {
298 self.inner.do_io(|_| f())
299 }
300}
301
302impl event::Source for Sender {
303 fn register(
304 &mut self,
305 registry: &Registry,
306 token: Token,
307 interests: Interest,
308 ) -> io::Result<()> {
309 self.inner.register(registry, token, interests)
310 }
311
312 fn reregister(
313 &mut self,
314 registry: &Registry,
315 token: Token,
316 interests: Interest,
317 ) -> io::Result<()> {
318 self.inner.reregister(registry, token, interests)
319 }
320
321 fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
322 self.inner.deregister(registry)
323 }
324}
325
326impl Write for Sender {
327 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
328 self.inner.do_io(|mut sender| sender.write(buf))
329 }
330
331 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
332 self.inner.do_io(|mut sender| sender.write_vectored(bufs))
333 }
334
335 fn flush(&mut self) -> io::Result<()> {
336 self.inner.do_io(|mut sender| sender.flush())
337 }
338}
339
340impl Write for &Sender {
341 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
342 self.inner.do_io(|mut sender| sender.write(buf))
343 }
344
345 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
346 self.inner.do_io(|mut sender| sender.write_vectored(bufs))
347 }
348
349 fn flush(&mut self) -> io::Result<()> {
350 self.inner.do_io(|mut sender| sender.flush())
351 }
352}
353
354/// # Notes
355///
356/// The underlying pipe is **not** set to non-blocking.
357impl From<ChildStdin> for Sender {
358 fn from(stdin: ChildStdin) -> Sender {
359 // Safety: `ChildStdin` is guaranteed to be a valid file descriptor.
360 unsafe { Sender::from_raw_fd(stdin.into_raw_fd()) }
361 }
362}
363
364impl FromRawFd for Sender {
365 unsafe fn from_raw_fd(fd: RawFd) -> Sender {
366 Sender {
367 inner: IoSource::new(File::from_raw_fd(fd)),
368 }
369 }
370}
371
372impl AsRawFd for Sender {
373 fn as_raw_fd(&self) -> RawFd {
374 self.inner.as_raw_fd()
375 }
376}
377
378impl IntoRawFd for Sender {
379 fn into_raw_fd(self) -> RawFd {
380 self.inner.into_inner().into_raw_fd()
381 }
382}
383
384impl From<Sender> for OwnedFd {
385 fn from(sender: Sender) -> Self {
386 sender.inner.into_inner().into()
387 }
388}
389
390impl AsFd for Sender {
391 fn as_fd(&self) -> BorrowedFd<'_> {
392 self.inner.as_fd()
393 }
394}
395
396impl From<OwnedFd> for Sender {
397 fn from(fd: OwnedFd) -> Self {
398 Sender {
399 inner: IoSource::new(File::from(fd)),
400 }
401 }
402}
403
404/// Receiving end of an Unix pipe.
405///
406/// See [`new`] for documentation, including examples.
407#[derive(Debug)]
408pub struct Receiver {
409 inner: IoSource<File>,
410}
411
412impl Receiver {
413 /// Set the `Receiver` into or out of non-blocking mode.
414 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
415 set_nonblocking(self.inner.as_raw_fd(), nonblocking)
416 }
417
418 /// Execute an I/O operation ensuring that the socket receives more events
419 /// if it hits a [`WouldBlock`] error.
420 ///
421 /// # Notes
422 ///
423 /// This method is required to be called for **all** I/O operations to
424 /// ensure the user will receive events once the socket is ready again after
425 /// returning a [`WouldBlock`] error.
426 ///
427 /// [`WouldBlock`]: io::ErrorKind::WouldBlock
428 ///
429 /// # Examples
430 ///
431 /// ```
432 /// # use std::error::Error;
433 /// #
434 /// # fn main() -> Result<(), Box<dyn Error>> {
435 /// use std::io;
436 /// use std::os::fd::AsRawFd;
437 /// use mio::unix::pipe;
438 ///
439 /// let (sender, receiver) = pipe::new()?;
440 ///
441 /// // Wait until the sender is writable...
442 ///
443 /// // Write to the sender using a direct libc call, of course the
444 /// // `io::Write` implementation would be easier to use.
445 /// let buf = b"hello";
446 /// let n = sender.try_io(|| {
447 /// let buf_ptr = &buf as *const _ as *const _;
448 /// let res = unsafe { libc::write(sender.as_raw_fd(), buf_ptr, buf.len()) };
449 /// if res != -1 {
450 /// Ok(res as usize)
451 /// } else {
452 /// // If EAGAIN or EWOULDBLOCK is set by libc::write, the closure
453 /// // should return `WouldBlock` error.
454 /// Err(io::Error::last_os_error())
455 /// }
456 /// })?;
457 /// eprintln!("write {} bytes", n);
458 ///
459 /// // Wait until the receiver is readable...
460 ///
461 /// // Read from the receiver using a direct libc call, of course the
462 /// // `io::Read` implementation would be easier to use.
463 /// let mut buf = [0; 512];
464 /// let n = receiver.try_io(|| {
465 /// let buf_ptr = &mut buf as *mut _ as *mut _;
466 /// let res = unsafe { libc::read(receiver.as_raw_fd(), buf_ptr, buf.len()) };
467 /// if res != -1 {
468 /// Ok(res as usize)
469 /// } else {
470 /// // If EAGAIN or EWOULDBLOCK is set by libc::read, the closure
471 /// // should return `WouldBlock` error.
472 /// Err(io::Error::last_os_error())
473 /// }
474 /// })?;
475 /// eprintln!("read {} bytes", n);
476 /// # Ok(())
477 /// # }
478 /// ```
479 pub fn try_io<F, T>(&self, f: F) -> io::Result<T>
480 where
481 F: FnOnce() -> io::Result<T>,
482 {
483 self.inner.do_io(|_| f())
484 }
485}
486
487impl event::Source for Receiver {
488 fn register(
489 &mut self,
490 registry: &Registry,
491 token: Token,
492 interests: Interest,
493 ) -> io::Result<()> {
494 self.inner.register(registry, token, interests)
495 }
496
497 fn reregister(
498 &mut self,
499 registry: &Registry,
500 token: Token,
501 interests: Interest,
502 ) -> io::Result<()> {
503 self.inner.reregister(registry, token, interests)
504 }
505
506 fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
507 self.inner.deregister(registry)
508 }
509}
510
511impl Read for Receiver {
512 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
513 self.inner.do_io(|mut sender| sender.read(buf))
514 }
515
516 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
517 self.inner.do_io(|mut sender| sender.read_vectored(bufs))
518 }
519}
520
521impl Read for &Receiver {
522 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
523 self.inner.do_io(|mut sender| sender.read(buf))
524 }
525
526 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
527 self.inner.do_io(|mut sender| sender.read_vectored(bufs))
528 }
529}
530
531/// # Notes
532///
533/// The underlying pipe is **not** set to non-blocking.
534impl From<ChildStdout> for Receiver {
535 fn from(stdout: ChildStdout) -> Receiver {
536 // Safety: `ChildStdout` is guaranteed to be a valid file descriptor.
537 unsafe { Receiver::from_raw_fd(stdout.into_raw_fd()) }
538 }
539}
540
541/// # Notes
542///
543/// The underlying pipe is **not** set to non-blocking.
544impl From<ChildStderr> for Receiver {
545 fn from(stderr: ChildStderr) -> Receiver {
546 // Safety: `ChildStderr` is guaranteed to be a valid file descriptor.
547 unsafe { Receiver::from_raw_fd(stderr.into_raw_fd()) }
548 }
549}
550
551impl IntoRawFd for Receiver {
552 fn into_raw_fd(self) -> RawFd {
553 self.inner.into_inner().into_raw_fd()
554 }
555}
556
557impl AsRawFd for Receiver {
558 fn as_raw_fd(&self) -> RawFd {
559 self.inner.as_raw_fd()
560 }
561}
562
563impl FromRawFd for Receiver {
564 unsafe fn from_raw_fd(fd: RawFd) -> Receiver {
565 Receiver {
566 inner: IoSource::new(File::from_raw_fd(fd)),
567 }
568 }
569}
570
571impl From<Receiver> for OwnedFd {
572 fn from(receiver: Receiver) -> Self {
573 receiver.inner.into_inner().into()
574 }
575}
576
577impl AsFd for Receiver {
578 fn as_fd(&self) -> BorrowedFd<'_> {
579 self.inner.as_fd()
580 }
581}
582
583impl From<OwnedFd> for Receiver {
584 fn from(fd: OwnedFd) -> Self {
585 Receiver {
586 inner: IoSource::new(File::from(fd)),
587 }
588 }
589}
590
591#[cfg(not(any(target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "vita")))]
592fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> {
593 let value = nonblocking as libc::c_int;
594 if unsafe { libc::ioctl(fd, libc::FIONBIO, &value) } == -1 {
595 Err(io::Error::last_os_error())
596 } else {
597 Ok(())
598 }
599}
600
601#[cfg(any(target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "vita"))]
602fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> {
603 let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) };
604 if flags < 0 {
605 return Err(io::Error::last_os_error());
606 }
607
608 let nflags = if nonblocking {
609 flags | libc::O_NONBLOCK
610 } else {
611 flags & !libc::O_NONBLOCK
612 };
613
614 if flags != nflags {
615 if unsafe { libc::fcntl(fd, libc::F_SETFL, nflags) } < 0 {
616 return Err(io::Error::last_os_error());
617 }
618 }
619
620 Ok(())
621}
622} // `cfg_os_ext!`.