From adef66274905fbc576ec3fb762f64166a69a5ecf Mon Sep 17 00:00:00 2001 From: barry3406 Date: Fri, 10 Apr 2026 07:34:22 -0700 Subject: [PATCH 1/3] net: document pipe try_read*/try_write* readiness behavior Add a Notes section to all five try_* methods on pipe::Sender and pipe::Receiver explaining that the runtime's I/O driver only delivers readiness events after control is yielded back to it, so calling try_read/try_write before any .await returns WouldBlock even when the operation could otherwise succeed. This is the same readiness model used by every other Tokio I/O type; the pipe docs simply did not previously call it out. Refs #7625. --- tokio/src/net/unix/pipe.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tokio/src/net/unix/pipe.rs b/tokio/src/net/unix/pipe.rs index 65bd51ad8a1..b1509f3ed72 100644 --- a/tokio/src/net/unix/pipe.rs +++ b/tokio/src/net/unix/pipe.rs @@ -617,6 +617,13 @@ impl Sender { /// number of bytes written. If the pipe is not ready to write data, /// `Err(io::ErrorKind::WouldBlock)` is returned. /// + /// # Notes + /// + /// The runtime's I/O driver only delivers readiness events to a `Sender` + /// after control is yielded back to it. Calling this method before any + /// `.await` (such as [`writable`]) will return `WouldBlock` even when + /// the pipe has space available. + /// /// # Examples /// /// ```no_run @@ -681,6 +688,13 @@ impl Sender { /// number of bytes written. If the pipe is not ready to write data, /// `Err(io::ErrorKind::WouldBlock)` is returned. /// + /// # Notes + /// + /// The runtime's I/O driver only delivers readiness events to a `Sender` + /// after control is yielded back to it. Calling this method before any + /// `.await` (such as [`writable`]) will return `WouldBlock` even when + /// the pipe has space available. + /// /// # Examples /// /// ```no_run @@ -1120,6 +1134,13 @@ impl Receiver { /// If the pipe is not ready to read data, /// `Err(io::ErrorKind::WouldBlock)` is returned. /// + /// # Notes + /// + /// The runtime's I/O driver only delivers readiness events to a `Receiver` + /// after control is yielded back to it. Calling this method before any + /// `.await` (such as [`readable()`]) will return `WouldBlock` even when + /// data is already available in the pipe. + /// /// # Examples /// /// ```no_run @@ -1188,6 +1209,13 @@ impl Receiver { /// closed and will no longer write data. If the pipe is not ready to read /// data `Err(io::ErrorKind::WouldBlock)` is returned. /// + /// # Notes + /// + /// The runtime's I/O driver only delivers readiness events to a `Receiver` + /// after control is yielded back to it. Calling this method before any + /// `.await` (such as [`readable()`]) will return `WouldBlock` even when + /// data is already available in the pipe. + /// /// # Examples /// /// ```no_run @@ -1258,6 +1286,13 @@ impl Receiver { /// closed and will no longer write data. If the pipe is not ready to read /// data `Err(io::ErrorKind::WouldBlock)` is returned. /// + /// # Notes + /// + /// The runtime's I/O driver only delivers readiness events to a `Receiver` + /// after control is yielded back to it. Calling this method before any + /// `.await` (such as [`readable()`]) will return `WouldBlock` even when + /// data is already available in the pipe. + /// /// # Examples /// /// ```no_run From ac68806851438c411e8947e69472ddc1180148d2 Mon Sep 17 00:00:00 2001 From: barry3406 Date: Sun, 12 Apr 2026 01:34:21 -0700 Subject: [PATCH 2/3] address review: soften Notes wording per Darksonn's suggestion --- tokio/src/net/unix/pipe.rs | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/tokio/src/net/unix/pipe.rs b/tokio/src/net/unix/pipe.rs index b1509f3ed72..a351e0d0724 100644 --- a/tokio/src/net/unix/pipe.rs +++ b/tokio/src/net/unix/pipe.rs @@ -619,10 +619,11 @@ impl Sender { /// /// # Notes /// - /// The runtime's I/O driver only delivers readiness events to a `Sender` - /// after control is yielded back to it. Calling this method before any - /// `.await` (such as [`writable`]) will return `WouldBlock` even when - /// the pipe has space available. + /// To avoid unnecessary syscalls, this will only attempt the write + /// operation if the OS has informed Tokio that this pipe has become + /// writable. Because of this, `try_write()` may fail with a + /// [`WouldBlock`] error if Tokio has not yet heard from the OS that + /// this pipe has become writable. /// /// # Examples /// @@ -690,10 +691,11 @@ impl Sender { /// /// # Notes /// - /// The runtime's I/O driver only delivers readiness events to a `Sender` - /// after control is yielded back to it. Calling this method before any - /// `.await` (such as [`writable`]) will return `WouldBlock` even when - /// the pipe has space available. + /// To avoid unnecessary syscalls, this will only attempt the write + /// operation if the OS has informed Tokio that this pipe has become + /// writable. Because of this, `try_write_vectored()` may fail with a + /// [`WouldBlock`] error if Tokio has not yet heard from the OS that + /// this pipe has become writable. /// /// # Examples /// @@ -1136,10 +1138,11 @@ impl Receiver { /// /// # Notes /// - /// The runtime's I/O driver only delivers readiness events to a `Receiver` - /// after control is yielded back to it. Calling this method before any - /// `.await` (such as [`readable()`]) will return `WouldBlock` even when - /// data is already available in the pipe. + /// To avoid unnecessary syscalls, this will only attempt the read + /// operation if the OS has informed Tokio that this pipe has become + /// readable. Because of this, `try_read()` may fail with a + /// [`WouldBlock`] error if Tokio has not yet heard from the OS that + /// this pipe has become readable. /// /// # Examples /// @@ -1211,10 +1214,11 @@ impl Receiver { /// /// # Notes /// - /// The runtime's I/O driver only delivers readiness events to a `Receiver` - /// after control is yielded back to it. Calling this method before any - /// `.await` (such as [`readable()`]) will return `WouldBlock` even when - /// data is already available in the pipe. + /// To avoid unnecessary syscalls, this will only attempt the read + /// operation if the OS has informed Tokio that this pipe has become + /// readable. Because of this, `try_read_vectored()` may fail with a + /// [`WouldBlock`] error if Tokio has not yet heard from the OS that + /// this pipe has become readable. /// /// # Examples /// @@ -1288,10 +1292,11 @@ impl Receiver { /// /// # Notes /// - /// The runtime's I/O driver only delivers readiness events to a `Receiver` - /// after control is yielded back to it. Calling this method before any - /// `.await` (such as [`readable()`]) will return `WouldBlock` even when - /// data is already available in the pipe. + /// To avoid unnecessary syscalls, this will only attempt the read + /// operation if the OS has informed Tokio that this pipe has become + /// readable. Because of this, `try_read_buf()` may fail with a + /// [`WouldBlock`] error if Tokio has not yet heard from the OS that + /// this pipe has become readable. /// /// # Examples /// From 3c06d4b798325a4d81ba5d8189c54fcf9ffba458 Mon Sep 17 00:00:00 2001 From: barry3406 Date: Thu, 16 Apr 2026 11:28:21 -0700 Subject: [PATCH 3/3] fix WouldBlock intra-doc link --- tokio/src/net/unix/pipe.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tokio/src/net/unix/pipe.rs b/tokio/src/net/unix/pipe.rs index a351e0d0724..ae2edc86ec2 100644 --- a/tokio/src/net/unix/pipe.rs +++ b/tokio/src/net/unix/pipe.rs @@ -658,6 +658,8 @@ impl Sender { /// Ok(()) /// } /// ``` + /// + /// [`WouldBlock`]: std::io::ErrorKind::WouldBlock pub fn try_write(&self, buf: &[u8]) -> io::Result { self.io .registration() @@ -732,6 +734,8 @@ impl Sender { /// Ok(()) /// } /// ``` + /// + /// [`WouldBlock`]: std::io::ErrorKind::WouldBlock pub fn try_write_vectored(&self, buf: &[io::IoSlice<'_>]) -> io::Result { self.io .registration() @@ -1181,6 +1185,8 @@ impl Receiver { /// Ok(()) /// } /// ``` + /// + /// [`WouldBlock`]: std::io::ErrorKind::WouldBlock pub fn try_read(&self, buf: &mut [u8]) -> io::Result { self.io .registration() @@ -1263,6 +1269,8 @@ impl Receiver { /// Ok(()) /// } /// ``` + /// + /// [`WouldBlock`]: std::io::ErrorKind::WouldBlock pub fn try_read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { self.io .registration() @@ -1334,6 +1342,8 @@ impl Receiver { /// Ok(()) /// } /// ``` + /// + /// [`WouldBlock`]: std::io::ErrorKind::WouldBlock pub fn try_read_buf(&self, buf: &mut B) -> io::Result { self.io.registration().try_io(Interest::READABLE, || { use std::io::Read;