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