io: retry ErrorKind::Interrupted in read_exact (#8417)

Co-authored-by: philphauler <[email protected]>
This commit is contained in:
Phil Phauler
2026-09-06 20:17:28 +08:00
committed by GitHub
co-authored by philphauler
parent 787697f76f
commit 0069aef281
2 changed files with 43 additions and 2 deletions
+5 -1
View File
@@ -57,7 +57,11 @@ where
// if our buffer is empty, then we need to read some data to continue.
let rem = me.buf.remaining();
if rem != 0 {
ready!(Pin::new(&mut *me.reader).poll_read(cx, me.buf))?;
match ready!(Pin::new(&mut *me.reader).poll_read(cx, me.buf)) {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e).into(),
}
if me.buf.remaining() == rem {
return Err(eof()).into();
}
+38 -1
View File
@@ -9,7 +9,10 @@
)
))]
use tokio::io::AsyncReadExt;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf};
use tokio_test::assert_ok;
#[tokio::test]
@@ -21,3 +24,37 @@ async fn read_exact() {
assert_eq!(n, 8);
assert_eq!(buf[..], b"hello wo"[..]);
}
struct InterruptThenRead {
interrupted: bool,
data: &'static [u8],
}
impl AsyncRead for InterruptThenRead {
fn poll_read(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
if !self.interrupted {
self.interrupted = true;
return Poll::Ready(Err(io::Error::from(io::ErrorKind::Interrupted)));
}
let n = std::cmp::min(self.data.len(), buf.remaining());
buf.put_slice(&self.data[..n]);
self.data = &self.data[n..];
Poll::Ready(Ok(()))
}
}
#[tokio::test]
async fn read_exact_retries_interrupted() {
let mut reader = InterruptThenRead {
interrupted: false,
data: b"hello",
};
let mut buf = [0u8; 5];
let n = reader.read_exact(&mut buf).await.unwrap();
assert_eq!(n, 5);
assert_eq!(&buf, b"hello");
}