interprocess/os/unix/
unnamed_pipe.rs

1//! Unix-specific named pipe functionality.
2
3use {
4    super::{c_wrappers, FdOps},
5    crate::{
6        os::unix::unixprelude::*,
7        unnamed_pipe::{Recver as PubRecver, Sender as PubSender},
8        Sealed,
9    },
10    std::{
11        fmt::{self, Debug, Formatter},
12        io,
13        os::fd::OwnedFd,
14    },
15};
16
17#[cfg(feature = "tokio")]
18pub(crate) mod tokio;
19
20/// Unix-specific extensions to synchronous named pipe senders and receivers.
21#[allow(private_bounds)]
22pub trait UnnamedPipeExt: AsFd + Sealed {
23    /// Sets whether the nonblocking mode for the pipe half is enabled. By default, it is
24    /// disabled.
25    ///
26    /// In nonblocking mode, attempts to receive from a [`Recver`](PubRecver) when there is no
27    /// data available, much like attempts to send data via a [`Sender`](PubSender) when the send
28    /// buffer has filled up because the receiving side hasn't received enough bytes in time,
29    /// never block like they normally do. Instead, a [`WouldBlock`](io::ErrorKind::WouldBlock)
30    /// error is immediately returned, allowing the thread to perform useful actions in the
31    /// meantime.
32    #[inline]
33    fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
34        c_wrappers::set_nonblocking(self.as_fd(), nonblocking)
35    }
36}
37#[cfg_attr(feature = "doc_cfg", doc(cfg(unix)))]
38impl UnnamedPipeExt for PubRecver {}
39#[cfg_attr(feature = "doc_cfg", doc(cfg(unix)))]
40impl UnnamedPipeExt for PubSender {}
41
42/// Like [platform-general `pipe()`](crate::unnamed_pipe::pipe), but allows pipe pairs to be
43/// immediately created in nonblocking mode on Linux, eliding a `fcntl()`.
44///
45/// ## System calls
46/// - `pipe2` (Linux)
47/// - `pipe` (not Linux)
48/// - `fcntl` (not Linux, only if `nonblocking` is `true`)
49pub fn pipe(nonblocking: bool) -> io::Result<(PubSender, PubRecver)> {
50    let (success, fds) = unsafe {
51        let mut fds: [c_int; 2] = [0; 2];
52        let result;
53        #[cfg(any(target_os = "linux", target_os = "android"))]
54        {
55            result =
56                libc::pipe2(fds.as_mut_ptr(), if nonblocking { libc::O_NONBLOCK } else { 0 });
57        }
58        #[cfg(not(any(target_os = "linux", target_os = "android")))]
59        {
60            result = libc::pipe(fds.as_mut_ptr());
61        }
62        (result == 0, fds)
63    };
64    if success {
65        let (w, r) = unsafe {
66            // SAFETY: we just created both of those file descriptors, which means that neither of
67            // them can be in use elsewhere.
68            let w = OwnedFd::from_raw_fd(fds[1]);
69            let r = OwnedFd::from_raw_fd(fds[0]);
70            (w, r)
71        };
72        let w = PubSender(Sender(FdOps(w)));
73        let r = PubRecver(Recver(FdOps(r)));
74        #[cfg(not(any(target_os = "linux", target_os = "android")))]
75        {
76            if nonblocking {
77                w.set_nonblocking(true)?;
78                r.set_nonblocking(true)?;
79            }
80        }
81        Ok((w, r))
82    } else {
83        Err(io::Error::last_os_error())
84    }
85}
86
87// This is imported by a macro, hence the confusing name.
88#[inline]
89pub(crate) fn pipe_impl() -> io::Result<(PubSender, PubRecver)> { pipe(false) }
90
91pub(crate) struct Recver(FdOps);
92impl Sealed for Recver {}
93impl Debug for Recver {
94    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
95        f.debug_struct("Recver").field("fd", &self.0 .0.as_raw_fd()).finish()
96    }
97}
98multimacro! {
99    Recver,
100    forward_rbv(FdOps, &),
101    forward_sync_ref_read,
102    forward_try_clone,
103    forward_handle,
104    derive_sync_mut_read,
105}
106
107pub(crate) struct Sender(FdOps);
108impl Sealed for Sender {}
109impl Debug for Sender {
110    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
111        f.debug_struct("Sender").field("fd", &self.0 .0.as_raw_fd()).finish()
112    }
113}
114
115multimacro! {
116    Sender,
117    forward_rbv(FdOps, &),
118    forward_sync_ref_write,
119    forward_try_clone,
120    forward_handle,
121    derive_sync_mut_write,
122}