Skip to main content

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!`.