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