Skip to content

Commit

Permalink
add Interest::ERROR
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev committed Jul 10, 2023
1 parent 82c2fa5 commit 952f386
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 20 deletions.
104 changes: 89 additions & 15 deletions tokio/src/io/interest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,59 @@ use std::ops;
/// I/O resource readiness states.
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Interest(mio::Interest);
pub struct Interest {
mio: Option<mio::Interest>,
has_error_interest: bool,
}

impl Interest {
const fn new(mio: mio::Interest) -> Self {
Self {
mio: Some(mio),
has_error_interest: false,
}
}

// The non-FreeBSD definitions in this block are active only when
// building documentation.
cfg_aio! {
/// Interest for POSIX AIO.
#[cfg(target_os = "freebsd")]
pub const AIO: Interest = Interest(mio::Interest::AIO);
pub const AIO: Interest = Interest::new(mio::Interest::AIO);

/// Interest for POSIX AIO.
#[cfg(not(target_os = "freebsd"))]
pub const AIO: Interest = Interest(mio::Interest::READABLE);
pub const AIO: Interest = Interest::new(mio::Interest::READABLE);

/// Interest for POSIX AIO lio_listio events.
#[cfg(target_os = "freebsd")]
pub const LIO: Interest = Interest(mio::Interest::LIO);
pub const LIO: Interest = Interest::new(mio::Interest::LIO);

/// Interest for POSIX AIO lio_listio events.
#[cfg(not(target_os = "freebsd"))]
pub const LIO: Interest = Interest(mio::Interest::READABLE);
pub const LIO: Interest = Interest::new(mio::Interest::READABLE);
}

/// Interest in all readable events.
///
/// Readable interest includes read-closed events.
pub const READABLE: Interest = Interest(mio::Interest::READABLE);
pub const READABLE: Interest = Interest::new(mio::Interest::READABLE);

/// Interest in all writable events.
///
/// Writable interest includes write-closed events.
pub const WRITABLE: Interest = Interest(mio::Interest::WRITABLE);
pub const WRITABLE: Interest = Interest::new(mio::Interest::WRITABLE);

/// Interest in error events.
pub const ERROR: Interest = Interest {
mio: None,
has_error_interest: true,
};

/// Returns a `Interest` set representing priority completion interests.
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
pub const PRIORITY: Interest = Interest(mio::Interest::PRIORITY);
pub const PRIORITY: Interest = Interest::new(mio::Interest::PRIORITY);

/// Returns true if the value includes readable interest.
///
Expand All @@ -63,7 +79,10 @@ impl Interest {
/// assert!(both.is_readable());
/// ```
pub const fn is_readable(self) -> bool {
self.0.is_readable()
match self.mio {
Some(mio) => mio.is_readable(),
None => false,
}
}

/// Returns true if the value includes writable interest.
Expand All @@ -80,7 +99,10 @@ impl Interest {
/// assert!(both.is_writable());
/// ```
pub const fn is_writable(self) -> bool {
self.0.is_writable()
match self.mio {
Some(mio) => mio.is_writable(),
None => false,
}
}

/// Returns true if the value includes priority interest.
Expand All @@ -99,7 +121,10 @@ impl Interest {
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
pub const fn is_priority(self) -> bool {
self.0.is_priority()
match self.mio {
Some(mio) => mio.is_priority(),
None => false,
}
}

/// Add together two `Interest` values.
Expand All @@ -116,12 +141,44 @@ impl Interest {
/// assert!(BOTH.is_readable());
/// assert!(BOTH.is_writable());
pub const fn add(self, other: Interest) -> Interest {
Interest(self.0.add(other.0))
Interest {
mio: match (self.mio, other.mio) {
(Some(a), Some(b)) => Some(a.add(b)),
(Some(c), None) | (None, Some(c)) => Some(c),
(None, None) => None,
},
has_error_interest: self.has_error_interest || other.has_error_interest,
}
}

/// Returns true if the value includes error interest.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// assert!(Interest::ERROR.is_error());
/// assert!(!Interest::WRITABLE.is_error());
///
/// let combined = Interest::READABLE | Interest::ERROR;
/// assert!(combined.is_error());
/// ```
pub const fn is_error(self) -> bool {
self.has_error_interest
}

// This function must be crate-private to avoid exposing a `mio` dependency.
pub(crate) const fn to_mio(self) -> mio::Interest {
self.0
match self.mio {
Some(mio) => mio,
None => {
// error interest is implicit, and mio does not have a specific Interest::ERROR
// so we provide an arbitrary interest here, and filter out the this readiness
// in `Interest::mask` and `Ready::from_interest`.
mio::Interest::READABLE
}
}
}

pub(crate) fn mask(self) -> Ready {
Expand All @@ -130,6 +187,7 @@ impl Interest {
Interest::WRITABLE => Ready::WRITABLE | Ready::WRITE_CLOSED,
#[cfg(any(target_os = "linux", target_os = "android"))]
Interest::PRIORITY => Ready::PRIORITY | Ready::READ_CLOSED,
Interest::ERROR => Ready::ERROR,
_ => Ready::EMPTY,
}
}
Expand All @@ -147,12 +205,28 @@ impl ops::BitOr for Interest {
impl ops::BitOrAssign for Interest {
#[inline]
fn bitor_assign(&mut self, other: Self) {
self.0 = (*self | other).0;
*self = *self | other
}
}

impl fmt::Debug for Interest {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(fmt)
match self.mio {
None => {
if self.has_error_interest {
write!(fmt, "ERROR")
} else {
Ok(())
}
}
Some(mio) => {
mio.fmt(fmt)?;
if self.has_error_interest {
write!(fmt, " | ERROR")
} else {
Ok(())
}
}
}
}
}
5 changes: 3 additions & 2 deletions tokio/src/io/ready.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,9 @@ impl Ready {
ready |= Ready::READ_CLOSED;
}

// an event with the error readiness matches any interest
ready |= Ready::ERROR;
if interest.is_error() {
ready |= Ready::ERROR;
}

ready
}
Expand Down
5 changes: 2 additions & 3 deletions tokio/tests/io_async_fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ async fn await_error_readiness_timestamping() {
fd.get_ref().send(buf).unwrap();

// the send timestamp should now be in the error queue
let guard = fd.ready(Interest::READABLE).await.unwrap();
let guard = fd.ready(Interest::ERROR).await.unwrap();
assert_eq!(guard.ready(), Ready::ERROR);
}

Expand Down Expand Up @@ -799,7 +799,6 @@ async fn await_error_readiness_invalid_address() {

let fd = AsyncFd::new(socket).unwrap();

let guard = fd.ready(Interest::READABLE).await.unwrap();

let guard = fd.ready(Interest::ERROR).await.unwrap();
assert_eq!(guard.ready(), Ready::ERROR);
}

0 comments on commit 952f386

Please sign in to comment.