Auto merge of #115228 - saethlin:is-interrupted, r=thomcc

Add a new helper to avoid calling io::Error::kind

On `cfg(unix)`, `Error::kind` emits an enormous jump table that LLVM seems unable to optimize out. I don't really understand why, but see for yourself: https://godbolt.org/z/17hY496KG

This change lets us check for `ErrorKind::Interrupted` without going through a big match. I've checked the codegen locally, and it has the desired effect on the codegen for `BufReader::read_exact`.
This commit is contained in:
bors 2023-08-26 02:19:08 +00:00
commit 9334ec9354
12 changed files with 66 additions and 7 deletions

View File

@ -745,14 +745,17 @@ fn buffer_capacity_required(mut file: &File) -> Option<usize> {
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for &File {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.read_vectored(bufs)
}
#[inline]
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.inner.read_buf(cursor)
}

View File

@ -916,6 +916,16 @@ impl Error {
ErrorData::SimpleMessage(m) => m.kind,
}
}
#[inline]
pub(crate) fn is_interrupted(&self) -> bool {
match self.repr.data() {
ErrorData::Os(code) => sys::is_interrupted(code),
ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted,
ErrorData::Simple(kind) => kind == ErrorKind::Interrupted,
ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
}
}
}
impl fmt::Debug for Repr {

View File

@ -390,7 +390,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
let mut cursor = read_buf.unfilled();
match r.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
@ -421,7 +421,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
buf.extend_from_slice(&probe[..n]);
break;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(ref e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
}
@ -470,7 +470,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
let tmp = buf;
buf = &mut tmp[n..];
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@ -860,7 +860,7 @@ pub trait Read {
let prev_written = cursor.written();
match self.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
@ -1579,7 +1579,7 @@ pub trait Write {
));
}
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@ -1943,7 +1943,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
let (done, used) = {
let available = match r.fill_buf() {
Ok(n) => n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(ref e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
};
match memchr::memchr(delim, available) {
@ -2734,7 +2734,7 @@ impl<R: Read> Iterator for Bytes<R> {
return match self.inner.read(slice::from_mut(&mut byte)) {
Ok(0) => None,
Ok(..) => Some(Ok(byte)),
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(ref e) if e.is_interrupted() => continue,
Err(e) => Some(Err(e)),
};
}

View File

@ -79,6 +79,11 @@ pub fn error_name(er: abi::ER) -> Option<&'static str> {
}
}
#[inline]
pub fn is_interrupted(er: abi::ER) -> bool {
er == abi::E_RLWAI
}
pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
match er {
// Success

View File

@ -86,6 +86,12 @@ pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
}
}
#[inline]
pub fn is_interrupted(code: i32) -> bool {
use fortanix_sgx_abi::Error;
code == Error::Interrupted as _
}
pub fn decode_error_kind(code: i32) -> ErrorKind {
use fortanix_sgx_abi::Error;

View File

@ -31,6 +31,11 @@ pub fn error_name(er: abi::ER) -> Option<&'static str> {
}
}
#[inline]
fn is_interrupted(er: abi::ER) -> bool {
false
}
pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
match er {
// Success

View File

@ -72,6 +72,11 @@ pub fn unsupported_err() -> crate::io::Error {
)
}
#[inline]
pub fn is_interrupted(code: i32) -> bool {
error::is_interrupted(code)
}
pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
error::decode_error_kind(code)
}

View File

@ -181,6 +181,12 @@ pub(super) fn error_name(er: abi::ER) -> Option<&'static str> {
unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok()
}
#[inline]
pub fn is_interrupted(er: abi::ER) -> bool {
let errno = netc::SOLID_NET_ERR_BASE - er;
errno as libc::c_int == libc::EINTR
}
pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
let errno = netc::SOLID_NET_ERR_BASE - er;
match errno as libc::c_int {

View File

@ -240,6 +240,11 @@ pub use crate::sys::android::signal;
#[cfg(not(target_os = "android"))]
pub use libc::signal;
#[inline]
pub(crate) fn is_interrupted(errno: i32) -> bool {
errno == libc::EINTR
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
use ErrorKind::*;
match errno as libc::c_int {

View File

@ -23,6 +23,10 @@ pub fn unsupported_err() -> std_io::Error {
)
}
pub fn is_interrupted(_code: i32) -> bool {
false
}
pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
crate::io::ErrorKind::Uncategorized
}

View File

@ -76,6 +76,11 @@ cfg_if::cfg_if! {
mod common;
pub use common::*;
#[inline]
pub fn is_interrupted(errno: i32) -> bool {
errno == wasi::ERRNO_INTR.raw().into()
}
pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
use std_io::ErrorKind::*;
if errno > u16::MAX as i32 || errno < 0 {

View File

@ -60,6 +60,11 @@ pub unsafe fn cleanup() {
net::cleanup();
}
#[inline]
pub fn is_interrupted(_errno: i32) -> bool {
false
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
use ErrorKind::*;