mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 16:33:24 +00:00
Make *_or_timeout
APIs concise
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
10cc85d588
commit
32b8e05cc3
@ -9,7 +9,7 @@ use ostd::{
|
||||
};
|
||||
use spin::Once;
|
||||
|
||||
use crate::{prelude::*, process::Pid, time::wait::TimerBuilder};
|
||||
use crate::{prelude::*, process::Pid, time::wait::ManagedTimeout};
|
||||
|
||||
type FutexBitSet = u32;
|
||||
type FutexBucketRef = Arc<Mutex<FutexBucket>>;
|
||||
@ -22,14 +22,14 @@ const FUTEX_BITSET_MATCH_ANY: FutexBitSet = 0xFFFF_FFFF;
|
||||
pub fn futex_wait(
|
||||
futex_addr: u64,
|
||||
futex_val: i32,
|
||||
timer_builder: Option<TimerBuilder>,
|
||||
timeout: Option<ManagedTimeout>,
|
||||
ctx: &Context,
|
||||
pid: Option<Pid>,
|
||||
) -> Result<()> {
|
||||
futex_wait_bitset(
|
||||
futex_addr as _,
|
||||
futex_val,
|
||||
timer_builder,
|
||||
timeout,
|
||||
FUTEX_BITSET_MATCH_ANY,
|
||||
ctx,
|
||||
pid,
|
||||
@ -40,7 +40,7 @@ pub fn futex_wait(
|
||||
pub fn futex_wait_bitset(
|
||||
futex_addr: Vaddr,
|
||||
futex_val: i32,
|
||||
timer_builder: Option<TimerBuilder>,
|
||||
timeout: Option<ManagedTimeout>,
|
||||
bitset: FutexBitSet,
|
||||
ctx: &Context,
|
||||
pid: Option<Pid>,
|
||||
@ -73,7 +73,7 @@ pub fn futex_wait_bitset(
|
||||
// drop lock
|
||||
drop(futex_bucket);
|
||||
|
||||
waiter.pause_timer_timeout(timer_builder.as_ref())
|
||||
waiter.pause_timeout(timeout)
|
||||
}
|
||||
|
||||
/// Does futex wake
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::{sync::atomic::Ordering, time::Duration};
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use ostd::sync::{WaitQueue, Waiter};
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
prelude::*,
|
||||
process::posix_thread::PosixThreadExt,
|
||||
thread::Thread,
|
||||
time::wait::{TimerBuilder, WaitTimeout},
|
||||
time::wait::{ManagedTimeout, TimeoutExt},
|
||||
};
|
||||
|
||||
/// `Pause` is an extension trait to make [`Waiter`] and [`WaitQueue`] signal aware.
|
||||
@ -36,7 +36,7 @@ pub trait Pause: WaitTimeout {
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.pause_until_or_timer_timeout_opt(cond, None)
|
||||
self.pause_until_or_timeout_impl(cond, None)
|
||||
}
|
||||
|
||||
/// Pauses the execution of the current thread until the `cond` is met ( i.e., `cond()`
|
||||
@ -51,26 +51,18 @@ pub trait Pause: WaitTimeout {
|
||||
///
|
||||
/// [`ETIME`]: crate::error::Errno::ETIME
|
||||
/// [`EINTR`]: crate::error::Errno::EINTR
|
||||
fn pause_until_or_timeout<F, R>(&self, mut cond: F, timeout: &Duration) -> Result<R>
|
||||
fn pause_until_or_timeout<'a, F, T, R>(&self, mut cond: F, timeout: T) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
T: Into<TimeoutExt<'a>>,
|
||||
{
|
||||
if *timeout == Duration::ZERO {
|
||||
return cond()
|
||||
.ok_or_else(|| Error::with_message(Errno::ETIME, "the time limit is reached"));
|
||||
}
|
||||
let timer_builder = TimerBuilder::new(timeout);
|
||||
self.pause_until_or_timer_timeout_opt(cond, Some(&timer_builder))
|
||||
}
|
||||
let timeout = timeout.into();
|
||||
let timeout_inner = match timeout.check_expired() {
|
||||
Ok(inner) => inner,
|
||||
Err(err) => return cond().ok_or(err),
|
||||
};
|
||||
|
||||
/// Similar to [`Pause::pause_until_or_timeout`].
|
||||
///
|
||||
/// The only difference is that the timeout is against the user-specified clock.
|
||||
fn pause_until_or_timer_timeout<F, R>(&self, cond: F, timer_builder: &TimerBuilder) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.pause_until_or_timer_timeout_opt(cond, Some(timer_builder))
|
||||
self.pause_until_or_timeout_impl(cond, timeout_inner)
|
||||
}
|
||||
|
||||
/// Pauses the execution of the current thread until the `cond` is met ( i.e., `cond()`
|
||||
@ -85,10 +77,11 @@ pub trait Pause: WaitTimeout {
|
||||
///
|
||||
/// [`ETIME`]: crate::error::Errno::ETIME
|
||||
/// [`EINTR`]: crate::error::Errno::EINTR
|
||||
fn pause_until_or_timer_timeout_opt<F, R>(
|
||||
#[doc(hidden)]
|
||||
fn pause_until_or_timeout_impl<F, R>(
|
||||
&self,
|
||||
cond: F,
|
||||
timer_builder: Option<&TimerBuilder>,
|
||||
timeout: Option<&ManagedTimeout>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>;
|
||||
@ -101,21 +94,20 @@ pub trait Pause: WaitTimeout {
|
||||
///
|
||||
/// If `timeout` is expired before woken up or some signals are received,
|
||||
/// this method will return [`Errno::ETIME`].
|
||||
fn pause_timer_timeout(&self, timer_builder: Option<&TimerBuilder>) -> Result<()>;
|
||||
fn pause_timeout<'a>(&self, timeout: impl Into<TimeoutExt<'a>>) -> Result<()>;
|
||||
}
|
||||
|
||||
impl Pause for Waiter {
|
||||
fn pause_until_or_timer_timeout_opt<F, R>(
|
||||
fn pause_until_or_timeout_impl<F, R>(
|
||||
&self,
|
||||
mut cond: F,
|
||||
timer_builder: Option<&TimerBuilder>,
|
||||
cond: F,
|
||||
timeout: Option<&ManagedTimeout>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
if let Some(res) = cond() {
|
||||
return Ok(res);
|
||||
}
|
||||
// No fast paths for `Waiter`. If the caller wants a fast path, it should do so _before_
|
||||
// the waiter is created.
|
||||
|
||||
let current_thread = self.task().data().downcast_ref::<Arc<Thread>>();
|
||||
|
||||
@ -123,11 +115,7 @@ impl Pause for Waiter {
|
||||
.as_ref()
|
||||
.and_then(|thread| thread.as_posix_thread())
|
||||
else {
|
||||
if let Some(timer_builder) = timer_builder {
|
||||
return self.wait_until_or_timer_timeout(cond, timer_builder);
|
||||
} else {
|
||||
return self.wait_until_or_cancelled(cond, || Ok(()));
|
||||
}
|
||||
return self.wait_until_or_timeout_cancelled(cond, || Ok(()), timeout);
|
||||
};
|
||||
|
||||
let cancel_cond = || {
|
||||
@ -141,19 +129,16 @@ impl Pause for Waiter {
|
||||
};
|
||||
|
||||
posix_thread.set_signalled_waker(self.waker());
|
||||
let res = if let Some(timer_builder) = timer_builder {
|
||||
self.wait_until_or_timer_timeout_cancelled(cond, cancel_cond, timer_builder)
|
||||
} else {
|
||||
self.wait_until_or_cancelled(cond, cancel_cond)
|
||||
};
|
||||
let res = self.wait_until_or_timeout_cancelled(cond, cancel_cond, timeout);
|
||||
posix_thread.clear_signalled_waker();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn pause_timer_timeout(&self, timer_builder: Option<&TimerBuilder>) -> Result<()> {
|
||||
let timer = timer_builder.map(|timer_builder| {
|
||||
fn pause_timeout<'a>(&self, timeout: impl Into<TimeoutExt<'a>>) -> Result<()> {
|
||||
let timer = timeout.into().check_expired()?.map(|timeout| {
|
||||
let waker = self.waker();
|
||||
timer_builder.fire(move || {
|
||||
timeout.create_timer(move || {
|
||||
waker.wake_up();
|
||||
})
|
||||
});
|
||||
@ -184,14 +169,15 @@ impl Pause for Waiter {
|
||||
}
|
||||
|
||||
impl Pause for WaitQueue {
|
||||
fn pause_until_or_timer_timeout_opt<F, R>(
|
||||
fn pause_until_or_timeout_impl<F, R>(
|
||||
&self,
|
||||
mut cond: F,
|
||||
timer_builder: Option<&TimerBuilder>,
|
||||
timeout: Option<&ManagedTimeout>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
// Fast path:
|
||||
if let Some(res) = cond() {
|
||||
return Ok(res);
|
||||
}
|
||||
@ -201,11 +187,11 @@ impl Pause for WaitQueue {
|
||||
self.enqueue(waiter.waker());
|
||||
cond()
|
||||
};
|
||||
waiter.pause_until_or_timer_timeout_opt(cond, timer_builder)
|
||||
waiter.pause_until_or_timeout_impl(cond, timeout)
|
||||
}
|
||||
|
||||
fn pause_timer_timeout(&self, _timer_builder: Option<&TimerBuilder>) -> Result<()> {
|
||||
panic!("`pause_timer_timeout` can only be used on `Waiter`");
|
||||
fn pause_timeout<'a>(&self, _timeout: impl Into<TimeoutExt<'a>>) -> Result<()> {
|
||||
panic!("`pause_timeout` can only be used on `Waiter`");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,11 +209,7 @@ impl EventCounter {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(timeout) = timeout {
|
||||
waiter.pause_until_or_timeout(cond, timeout)
|
||||
} else {
|
||||
waiter.pause_until(cond)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
clocks::{MonotonicClock, RealTimeClock},
|
||||
timer::Timeout,
|
||||
timespec_t,
|
||||
wait::TimerBuilder,
|
||||
wait::ManagedTimeout,
|
||||
},
|
||||
};
|
||||
|
||||
@ -40,7 +40,7 @@ pub fn sys_futex(
|
||||
Ok(val as usize)
|
||||
};
|
||||
|
||||
let get_futex_timer_builder = |timeout_addr: Vaddr| -> Result<Option<TimerBuilder<'static>>> {
|
||||
let get_futex_timeout = |timeout_addr: Vaddr| -> Result<Option<ManagedTimeout<'static>>> {
|
||||
if timeout_addr == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
@ -78,7 +78,7 @@ pub fn sys_futex(
|
||||
MonotonicClock::timer_manager()
|
||||
};
|
||||
|
||||
Ok(Some(TimerBuilder::new_with_timer_manager(
|
||||
Ok(Some(ManagedTimeout::new_with_manager(
|
||||
timeout,
|
||||
timer_manager,
|
||||
)))
|
||||
@ -91,15 +91,15 @@ pub fn sys_futex(
|
||||
};
|
||||
let res = match futex_op {
|
||||
FutexOp::FUTEX_WAIT => {
|
||||
let timer_builder = get_futex_timer_builder(utime_addr)?;
|
||||
futex_wait(futex_addr as _, futex_val as _, timer_builder, ctx, pid).map(|_| 0)
|
||||
let timeout = get_futex_timeout(utime_addr)?;
|
||||
futex_wait(futex_addr as _, futex_val as _, timeout, ctx, pid).map(|_| 0)
|
||||
}
|
||||
FutexOp::FUTEX_WAIT_BITSET => {
|
||||
let timer_builder = get_futex_timer_builder(utime_addr)?;
|
||||
let timeout = get_futex_timeout(utime_addr)?;
|
||||
futex_wait_bitset(
|
||||
futex_addr as _,
|
||||
futex_val as _,
|
||||
timer_builder,
|
||||
timeout,
|
||||
bitset as _,
|
||||
ctx,
|
||||
pid,
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
clocks::{BootTimeClock, MonotonicClock, RealTimeClock},
|
||||
timer::Timeout,
|
||||
timespec_t,
|
||||
wait::TimerBuilder,
|
||||
wait::ManagedTimeout,
|
||||
TIMER_ABSTIME,
|
||||
},
|
||||
};
|
||||
@ -109,10 +109,11 @@ fn do_clock_nanosleep(
|
||||
}
|
||||
};
|
||||
|
||||
let timer_builder =
|
||||
TimerBuilder::new_with_timer_manager(Timeout::After(duration), timer_manager);
|
||||
let res = waiter.pause_until_or_timeout(
|
||||
|| None,
|
||||
ManagedTimeout::new_with_manager(Timeout::After(duration), timer_manager),
|
||||
);
|
||||
|
||||
let res = waiter.pause_until_or_timer_timeout(|| None, &timer_builder);
|
||||
match res {
|
||||
Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)),
|
||||
Err(e) if e.error() == Errno::EINTR => {
|
||||
|
@ -12,23 +12,18 @@ pub trait WaitTimeout {
|
||||
/// Waits until some condition returns `Some(_)`, or a given timeout is reached. If
|
||||
/// the condition does not becomes `Some(_)` before the timeout is reached,
|
||||
/// this function will return `ETIME` error.
|
||||
fn wait_until_or_timeout<F, R>(&self, cond: F, timeout: &Duration) -> Result<R>
|
||||
fn wait_until_or_timeout<'a, F, T, R>(&self, mut cond: F, timeout: T) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
T: Into<TimeoutExt<'a>>,
|
||||
{
|
||||
let timer_builder = TimerBuilder::new(timeout);
|
||||
self.wait_until_or_timer_timeout(cond, &timer_builder)
|
||||
}
|
||||
let timeout = timeout.into();
|
||||
let timeout_inner = match timeout.check_expired() {
|
||||
Ok(inner) => inner,
|
||||
Err(err) => return cond().ok_or(err),
|
||||
};
|
||||
|
||||
/// Similar to [`WaitTimeout::wait_until_or_timeout`].
|
||||
///
|
||||
/// The difference is that the timeout of this method is against the specified clock,
|
||||
/// which is defined in `timer_builder`.
|
||||
fn wait_until_or_timer_timeout<F, R>(&self, cond: F, timer_builder: &TimerBuilder) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.wait_until_or_timer_timeout_cancelled(cond, || Ok(()), timer_builder)
|
||||
self.wait_until_or_timeout_cancelled(cond, || Ok(()), timeout_inner)
|
||||
}
|
||||
|
||||
/// Waits until some condition returns `Some(_)`, or be cancelled due to
|
||||
@ -36,112 +31,150 @@ pub trait WaitTimeout {
|
||||
/// does not becomes `Some(_)` before the timeout is reached or `cancel_cond`
|
||||
/// returns `Err`, this function will return corresponding `Err`.
|
||||
#[doc(hidden)]
|
||||
fn wait_until_or_timer_timeout_cancelled<F, R, FCancel>(
|
||||
fn wait_until_or_timeout_cancelled<F, R, FCancel>(
|
||||
&self,
|
||||
cond: F,
|
||||
cancel_cond: FCancel,
|
||||
timer_builder: &TimerBuilder,
|
||||
timeout: Option<&ManagedTimeout>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
FCancel: Fn() -> Result<()>;
|
||||
}
|
||||
|
||||
/// A helper structure to build timers from a specified timeout and timer manager.
|
||||
pub struct TimerBuilder<'a> {
|
||||
timeout: Timeout,
|
||||
timer_manager: &'a Arc<TimerManager>,
|
||||
/// A timeout with extended semantics.
|
||||
pub enum TimeoutExt<'a> {
|
||||
/// The timeout will never fire.
|
||||
Never,
|
||||
/// The timeout will expire later according to [`ManagedTimeout`].
|
||||
At(ManagedTimeout<'a>),
|
||||
}
|
||||
|
||||
impl<'a> TimerBuilder<'a> {
|
||||
/// Creates a new `TimerBuilder` against the default JIFFIES clock.
|
||||
pub fn new(timeout: &Duration) -> Self {
|
||||
let timeout = Timeout::After(*timeout);
|
||||
let jiffies_timer_manager = JIFFIES_TIMER_MANAGER.get().unwrap();
|
||||
Self::new_with_timer_manager(timeout, jiffies_timer_manager)
|
||||
impl<'a> TimeoutExt<'a> {
|
||||
/// Checks whether the timeout is expired.
|
||||
///
|
||||
/// This method will return:
|
||||
/// - `Ok(Some(_))` if the timeout isn't expired but it may be expired later.
|
||||
/// - `Ok(None)` if the timeout will never be expired.
|
||||
/// - `Err(ETIME)` if the timeout is expired.
|
||||
pub fn check_expired(&self) -> Result<Option<&ManagedTimeout<'a>>> {
|
||||
match self {
|
||||
TimeoutExt::At(inner) if inner.is_expired() => {
|
||||
return_errno_with_message!(Errno::ETIME, "the time limit is reached")
|
||||
}
|
||||
TimeoutExt::At(inner) => Ok(Some(inner)),
|
||||
TimeoutExt::Never => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `TimerBuilder` with given timer manager.
|
||||
pub const fn new_with_timer_manager(
|
||||
impl From<&Duration> for TimeoutExt<'_> {
|
||||
fn from(value: &Duration) -> Self {
|
||||
Self::At(ManagedTimeout::new(*value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<&Duration>> for TimeoutExt<'_> {
|
||||
fn from(value: Option<&Duration>) -> Self {
|
||||
match value {
|
||||
Some(duration) => duration.into(),
|
||||
None => Self::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ManagedTimeout<'a>> for TimeoutExt<'a> {
|
||||
fn from(value: ManagedTimeout<'a>) -> Self {
|
||||
Self::At(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Option<ManagedTimeout<'a>>> for TimeoutExt<'a> {
|
||||
fn from(value: Option<ManagedTimeout<'a>>) -> Self {
|
||||
match value {
|
||||
Some(timeout) => timeout.into(),
|
||||
None => Self::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Timeout`] with the associated [`TimerManager`].
|
||||
pub struct ManagedTimeout<'a> {
|
||||
timeout: Timeout,
|
||||
timer_manager: &'a Arc<TimerManager>,
|
||||
) -> Self {
|
||||
Self {
|
||||
timeout,
|
||||
timer_manager,
|
||||
}
|
||||
manager: &'a Arc<TimerManager>,
|
||||
}
|
||||
|
||||
impl<'a> ManagedTimeout<'a> {
|
||||
/// Creates a new `ManagedTimeout` with the JIFFIES timer manager.
|
||||
pub fn new(timeout: Duration) -> Self {
|
||||
let timeout = Timeout::After(timeout);
|
||||
let manager = JIFFIES_TIMER_MANAGER.get().unwrap();
|
||||
Self::new_with_manager(timeout, manager)
|
||||
}
|
||||
|
||||
/// Returns the timeout
|
||||
pub const fn timeout(&self) -> &Timeout {
|
||||
&self.timeout
|
||||
/// Creates a new `ManagedTimeout` with the given timer manager.
|
||||
pub const fn new_with_manager(timeout: Timeout, manager: &'a Arc<TimerManager>) -> Self {
|
||||
Self { timeout, manager }
|
||||
}
|
||||
|
||||
fn is_expired(&self) -> bool {
|
||||
self.timer_manager.is_expired_timeout(&self.timeout)
|
||||
/// Returns weather the timeout is expired.
|
||||
pub fn is_expired(&self) -> bool {
|
||||
self.manager.is_expired_timeout(&self.timeout)
|
||||
}
|
||||
|
||||
/// Builds and sets a timer,
|
||||
/// which will trigger `callback` when `self.timeout()` is reached.
|
||||
pub fn fire<F>(&self, callback: F) -> Arc<Timer>
|
||||
/// Creates a timer for the timeout.
|
||||
pub fn create_timer<F>(&self, callback: F) -> Arc<Timer>
|
||||
where
|
||||
F: Fn() + Send + Sync + 'static,
|
||||
{
|
||||
let timer = self.timer_manager.create_timer(callback);
|
||||
let timer = self.manager.create_timer(callback);
|
||||
timer.set_timeout(self.timeout.clone());
|
||||
timer
|
||||
}
|
||||
}
|
||||
|
||||
impl WaitTimeout for Waiter {
|
||||
fn wait_until_or_timer_timeout_cancelled<F, R, FCancel>(
|
||||
fn wait_until_or_timeout_cancelled<F, R, FCancel>(
|
||||
&self,
|
||||
mut cond: F,
|
||||
cond: F,
|
||||
cancel_cond: FCancel,
|
||||
timer_builder: &TimerBuilder,
|
||||
timeout: Option<&ManagedTimeout>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
FCancel: Fn() -> Result<()>,
|
||||
{
|
||||
if timer_builder.is_expired() {
|
||||
return cond()
|
||||
.ok_or_else(|| Error::with_message(Errno::ETIME, "the time limit is reached"));
|
||||
}
|
||||
|
||||
if let Some(res) = cond() {
|
||||
return Ok(res);
|
||||
}
|
||||
// No fast paths for `Waiter`. If the caller wants a fast path, it should do so _before_
|
||||
// the waiter is created.
|
||||
|
||||
let timer = timeout.map(|timeout| {
|
||||
let waker = self.waker();
|
||||
let timer = timer_builder.fire(move || {
|
||||
timeout.create_timer(move || {
|
||||
waker.wake_up();
|
||||
})
|
||||
});
|
||||
|
||||
let timeout_cond = {
|
||||
let cancel_cond = {
|
||||
let timer = timer.clone();
|
||||
move || {
|
||||
if timer.remain() != Duration::ZERO {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::with_message(
|
||||
Errno::ETIME,
|
||||
"the time limit is reached",
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let cancel_cond = || {
|
||||
timeout_cond()?;
|
||||
move || {
|
||||
if timer
|
||||
.as_ref()
|
||||
.is_some_and(|timer| timer.remain() == Duration::ZERO)
|
||||
{
|
||||
return_errno_with_message!(Errno::ETIME, "the time limit is reached");
|
||||
}
|
||||
|
||||
cancel_cond()
|
||||
}
|
||||
};
|
||||
|
||||
let res = self.wait_until_or_cancelled(cond, cancel_cond);
|
||||
|
||||
// If `res` is not `ETIME` error, then the timeout may not have been expired.
|
||||
// We cancel it manually.
|
||||
if !res
|
||||
if let Some(timer) = timer
|
||||
&& !res
|
||||
.as_ref()
|
||||
.is_err_and(|e: &Error| e.error() == Errno::ETIME)
|
||||
{
|
||||
@ -153,21 +186,17 @@ impl WaitTimeout for Waiter {
|
||||
}
|
||||
|
||||
impl WaitTimeout for WaitQueue {
|
||||
fn wait_until_or_timer_timeout_cancelled<F, R, FCancel>(
|
||||
fn wait_until_or_timeout_cancelled<F, R, FCancel>(
|
||||
&self,
|
||||
mut cond: F,
|
||||
cancel_cond: FCancel,
|
||||
timer_builder: &TimerBuilder,
|
||||
timeout: Option<&ManagedTimeout>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
FCancel: Fn() -> Result<()>,
|
||||
{
|
||||
if timer_builder.is_expired() {
|
||||
return cond()
|
||||
.ok_or_else(|| Error::with_message(Errno::ETIME, "the time limit is reached"));
|
||||
}
|
||||
|
||||
// Fast path:
|
||||
if let Some(res) = cond() {
|
||||
return Ok(res);
|
||||
}
|
||||
@ -177,6 +206,6 @@ impl WaitTimeout for WaitQueue {
|
||||
self.enqueue(waiter.waker());
|
||||
cond()
|
||||
};
|
||||
waiter.wait_until_or_timer_timeout_cancelled(cond, cancel_cond, timer_builder)
|
||||
waiter.wait_until_or_timeout_cancelled(cond, cancel_cond, timeout)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user