mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-02 00:00:11 +02:00
rt: move time driver into runtime module (#4983)
This patch moves the time driver into the runtime module. The time driver is a runtime concern and is only used by the runtime. Moving the drivers is the first step to cleaning up some Tokio internals. There will be follow-up patches that integrate the drivers and other runtime concerns more closely. This is an internal refactor and should not impact any public APIs.
This commit is contained in:
+2
-3
@@ -497,9 +497,8 @@ cfg_rt! {
|
|||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
}
|
}
|
||||||
cfg_not_rt! {
|
cfg_not_rt! {
|
||||||
cfg_io_driver_impl! {
|
// The `runtime` module is used when the IO or time driver is needed.
|
||||||
pub(crate) mod runtime;
|
pub(crate) mod runtime;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod coop;
|
pub(crate) mod coop;
|
||||||
|
|||||||
@@ -98,10 +98,10 @@ cfg_not_process_driver! {
|
|||||||
// ===== time driver =====
|
// ===== time driver =====
|
||||||
|
|
||||||
cfg_time! {
|
cfg_time! {
|
||||||
type TimeDriver = crate::park::either::Either<crate::time::driver::Driver<IoStack>, IoStack>;
|
type TimeDriver = crate::park::either::Either<crate::runtime::time::Driver<IoStack>, IoStack>;
|
||||||
|
|
||||||
pub(crate) type Clock = crate::time::Clock;
|
pub(crate) type Clock = crate::time::Clock;
|
||||||
pub(crate) type TimeHandle = Option<crate::time::driver::Handle>;
|
pub(crate) type TimeHandle = Option<crate::runtime::time::Handle>;
|
||||||
|
|
||||||
fn create_clock(enable_pausing: bool, start_paused: bool) -> Clock {
|
fn create_clock(enable_pausing: bool, start_paused: bool) -> Clock {
|
||||||
crate::time::Clock::new(enable_pausing, start_paused)
|
crate::time::Clock::new(enable_pausing, start_paused)
|
||||||
@@ -115,7 +115,7 @@ cfg_time! {
|
|||||||
use crate::park::either::Either;
|
use crate::park::either::Either;
|
||||||
|
|
||||||
if enable {
|
if enable {
|
||||||
let driver = crate::time::driver::Driver::new(io_stack, clock);
|
let driver = crate::runtime::time::Driver::new(io_stack, clock);
|
||||||
let handle = driver.handle();
|
let handle = driver.handle();
|
||||||
|
|
||||||
(Either::A(driver), Some(handle))
|
(Either::A(driver), Some(handle))
|
||||||
|
|||||||
@@ -181,6 +181,10 @@ cfg_io_driver_impl! {
|
|||||||
pub(crate) mod io;
|
pub(crate) mod io;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg_time! {
|
||||||
|
pub(crate) mod time;
|
||||||
|
}
|
||||||
|
|
||||||
cfg_rt! {
|
cfg_rt! {
|
||||||
pub(crate) mod enter;
|
pub(crate) mod enter;
|
||||||
|
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ impl StateCell {
|
|||||||
/// timer. As this participates in intrusive data structures, it must be pinned
|
/// timer. As this participates in intrusive data structures, it must be pinned
|
||||||
/// before polling.
|
/// before polling.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct TimerEntry {
|
pub(crate) struct TimerEntry {
|
||||||
/// Arc reference to the driver. We can only free the driver after
|
/// Arc reference to the driver. We can only free the driver after
|
||||||
/// deregistering everything from their respective timer wheels.
|
/// deregistering everything from their respective timer wheels.
|
||||||
driver: Handle,
|
driver: Handle,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::loom::sync::Arc;
|
use crate::loom::sync::Arc;
|
||||||
use crate::time::driver::ClockTime;
|
use crate::runtime::time::ClockTime;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// Handle to time driver instance.
|
/// Handle to time driver instance.
|
||||||
@@ -17,7 +17,7 @@ impl Handle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the time source associated with this handle.
|
/// Returns the time source associated with this handle.
|
||||||
pub(super) fn time_source(&self) -> &ClockTime {
|
pub(crate) fn time_source(&self) -> &ClockTime {
|
||||||
&self.time_source
|
&self.time_source
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,15 +7,14 @@
|
|||||||
//! Time driver.
|
//! Time driver.
|
||||||
|
|
||||||
mod entry;
|
mod entry;
|
||||||
pub(self) use self::entry::{EntryList, TimerEntry, TimerHandle, TimerShared};
|
pub(crate) use entry::TimerEntry;
|
||||||
|
use entry::{EntryList, TimerHandle, TimerShared};
|
||||||
|
|
||||||
mod handle;
|
mod handle;
|
||||||
pub(crate) use self::handle::Handle;
|
pub(crate) use self::handle::Handle;
|
||||||
|
|
||||||
mod wheel;
|
mod wheel;
|
||||||
|
|
||||||
pub(super) mod sleep;
|
|
||||||
|
|
||||||
use crate::loom::sync::atomic::{AtomicBool, Ordering};
|
use crate::loom::sync::atomic::{AtomicBool, Ordering};
|
||||||
use crate::loom::sync::{Arc, Mutex};
|
use crate::loom::sync::{Arc, Mutex};
|
||||||
use crate::park::{Park, Unpark};
|
use crate::park::{Park, Unpark};
|
||||||
@@ -104,8 +103,8 @@ pub(crate) struct Driver<P: Park + 'static> {
|
|||||||
|
|
||||||
/// A structure which handles conversion from Instants to u64 timestamps.
|
/// A structure which handles conversion from Instants to u64 timestamps.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(self) struct ClockTime {
|
pub(crate) struct ClockTime {
|
||||||
clock: super::clock::Clock,
|
clock: crate::time::Clock,
|
||||||
start_time: Instant,
|
start_time: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +116,7 @@ impl ClockTime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn deadline_to_tick(&self, t: Instant) -> u64 {
|
pub(crate) fn deadline_to_tick(&self, t: Instant) -> u64 {
|
||||||
// Round up to the end of a ms
|
// Round up to the end of a ms
|
||||||
self.instant_to_tick(t + Duration::from_nanos(999_999))
|
self.instant_to_tick(t + Duration::from_nanos(999_999))
|
||||||
}
|
}
|
||||||
@@ -136,7 +135,7 @@ impl ClockTime {
|
|||||||
Duration::from_millis(t)
|
Duration::from_millis(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn now(&self) -> u64 {
|
pub(crate) fn now(&self) -> u64 {
|
||||||
self.instant_to_tick(self.clock.now())
|
self.instant_to_tick(self.clock.now())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,7 +402,7 @@ impl Handle {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err((entry, super::error::InsertError::Elapsed)) => unsafe {
|
Err((entry, crate::time::error::InsertError::Elapsed)) => unsafe {
|
||||||
entry.fire(Ok(()))
|
entry.fire(Ok(()))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ fn model(f: impl Fn() + Send + Sync + 'static) {
|
|||||||
#[test]
|
#[test]
|
||||||
fn single_timer() {
|
fn single_timer() {
|
||||||
model(|| {
|
model(|| {
|
||||||
let clock = crate::time::clock::Clock::new(true, false);
|
let clock = crate::time::Clock::new(true, false);
|
||||||
let time_source = super::ClockTime::new(clock.clone());
|
let time_source = super::ClockTime::new(clock.clone());
|
||||||
|
|
||||||
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
||||||
@@ -79,7 +79,7 @@ fn single_timer() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn drop_timer() {
|
fn drop_timer() {
|
||||||
model(|| {
|
model(|| {
|
||||||
let clock = crate::time::clock::Clock::new(true, false);
|
let clock = crate::time::Clock::new(true, false);
|
||||||
let time_source = super::ClockTime::new(clock.clone());
|
let time_source = super::ClockTime::new(clock.clone());
|
||||||
|
|
||||||
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
||||||
@@ -110,7 +110,7 @@ fn drop_timer() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn change_waker() {
|
fn change_waker() {
|
||||||
model(|| {
|
model(|| {
|
||||||
let clock = crate::time::clock::Clock::new(true, false);
|
let clock = crate::time::Clock::new(true, false);
|
||||||
let time_source = super::ClockTime::new(clock.clone());
|
let time_source = super::ClockTime::new(clock.clone());
|
||||||
|
|
||||||
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
||||||
@@ -145,7 +145,7 @@ fn reset_future() {
|
|||||||
model(|| {
|
model(|| {
|
||||||
let finished_early = Arc::new(AtomicBool::new(false));
|
let finished_early = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
let clock = crate::time::clock::Clock::new(true, false);
|
let clock = crate::time::Clock::new(true, false);
|
||||||
let time_source = super::ClockTime::new(clock.clone());
|
let time_source = super::ClockTime::new(clock.clone());
|
||||||
|
|
||||||
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
let inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
|
||||||
@@ -201,7 +201,7 @@ fn normal_or_miri<T>(normal: T, miri: T) -> T {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(loom))]
|
#[cfg(not(loom))]
|
||||||
fn poll_process_levels() {
|
fn poll_process_levels() {
|
||||||
let clock = crate::time::clock::Clock::new(true, false);
|
let clock = crate::time::Clock::new(true, false);
|
||||||
clock.pause();
|
clock.pause();
|
||||||
|
|
||||||
let time_source = super::ClockTime::new(clock.clone());
|
let time_source = super::ClockTime::new(clock.clone());
|
||||||
@@ -242,7 +242,7 @@ fn poll_process_levels() {
|
|||||||
fn poll_process_levels_targeted() {
|
fn poll_process_levels_targeted() {
|
||||||
let mut context = Context::from_waker(noop_waker_ref());
|
let mut context = Context::from_waker(noop_waker_ref());
|
||||||
|
|
||||||
let clock = crate::time::clock::Clock::new(true, false);
|
let clock = crate::time::Clock::new(true, false);
|
||||||
clock.pause();
|
clock.pause();
|
||||||
|
|
||||||
let time_source = super::ClockTime::new(clock.clone());
|
let time_source = super::ClockTime::new(clock.clone());
|
||||||
@@ -258,46 +258,3 @@ fn poll_process_levels_targeted() {
|
|||||||
handle.process_at_time(192);
|
handle.process_at_time(192);
|
||||||
handle.process_at_time(192);
|
handle.process_at_time(192);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[test]
|
|
||||||
fn balanced_incr_and_decr() {
|
|
||||||
const OPS: usize = 5;
|
|
||||||
|
|
||||||
fn incr(inner: Arc<Inner>) {
|
|
||||||
for _ in 0..OPS {
|
|
||||||
inner.increment().expect("increment should not have failed");
|
|
||||||
thread::yield_now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decr(inner: Arc<Inner>) {
|
|
||||||
let mut ops_performed = 0;
|
|
||||||
while ops_performed < OPS {
|
|
||||||
if inner.num(Ordering::Relaxed) > 0 {
|
|
||||||
ops_performed += 1;
|
|
||||||
inner.decrement();
|
|
||||||
}
|
|
||||||
thread::yield_now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loom::model(|| {
|
|
||||||
let unpark = Box::new(MockUnpark);
|
|
||||||
let instant = Instant::now();
|
|
||||||
|
|
||||||
let inner = Arc::new(Inner::new(instant, unpark));
|
|
||||||
|
|
||||||
let incr_inner = inner.clone();
|
|
||||||
let decr_inner = inner.clone();
|
|
||||||
|
|
||||||
let incr_handle = thread::spawn(move || incr(incr_inner));
|
|
||||||
let decr_handle = thread::spawn(move || decr(decr_inner));
|
|
||||||
|
|
||||||
incr_handle.join().expect("should never fail");
|
|
||||||
decr_handle.join().expect("should never fail");
|
|
||||||
|
|
||||||
assert_eq!(inner.num(Ordering::SeqCst), 0);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
use crate::time::driver::TimerHandle;
|
use crate::runtime::time::{EntryList, TimerHandle, TimerShared};
|
||||||
|
|
||||||
use crate::time::driver::{EntryList, TimerShared};
|
|
||||||
|
|
||||||
use std::{fmt, ptr::NonNull};
|
use std::{fmt, ptr::NonNull};
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::time::driver::{TimerHandle, TimerShared};
|
use crate::runtime::time::{TimerHandle, TimerShared};
|
||||||
use crate::time::error::InsertError;
|
use crate::time::error::InsertError;
|
||||||
|
|
||||||
mod level;
|
mod level;
|
||||||
@@ -82,17 +82,13 @@
|
|||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! [`interval`]: crate::time::interval()
|
//! [`interval`]: crate::time::interval()
|
||||||
|
//! [`sleep`]: sleep()
|
||||||
|
|
||||||
mod clock;
|
mod clock;
|
||||||
pub(crate) use self::clock::Clock;
|
pub(crate) use self::clock::Clock;
|
||||||
#[cfg(feature = "test-util")]
|
#[cfg(feature = "test-util")]
|
||||||
pub use clock::{advance, pause, resume};
|
pub use clock::{advance, pause, resume};
|
||||||
|
|
||||||
pub(crate) mod driver;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use driver::sleep::{sleep, sleep_until, Sleep};
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
mod instant;
|
mod instant;
|
||||||
@@ -101,14 +97,13 @@ pub use self::instant::Instant;
|
|||||||
mod interval;
|
mod interval;
|
||||||
pub use interval::{interval, interval_at, Interval, MissedTickBehavior};
|
pub use interval::{interval, interval_at, Interval, MissedTickBehavior};
|
||||||
|
|
||||||
|
mod sleep;
|
||||||
|
pub use sleep::{sleep, sleep_until, Sleep};
|
||||||
|
|
||||||
mod timeout;
|
mod timeout;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use timeout::{timeout, timeout_at, Timeout};
|
pub use timeout::{timeout, timeout_at, Timeout};
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[cfg(not(loom))]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
// Re-export for convenience
|
// Re-export for convenience
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use std::time::Duration;
|
pub use std::time::Duration;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#[cfg(all(tokio_unstable, feature = "tracing"))]
|
#[cfg(all(tokio_unstable, feature = "tracing"))]
|
||||||
use crate::time::driver::ClockTime;
|
use crate::runtime::time::ClockTime;
|
||||||
use crate::time::driver::{Handle, TimerEntry};
|
use crate::runtime::time::{Handle, TimerEntry};
|
||||||
use crate::time::{error::Error, Duration, Instant};
|
use crate::time::{error::Error, Duration, Instant};
|
||||||
use crate::util::trace;
|
use crate::util::trace;
|
||||||
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
mod test_sleep;
|
|
||||||
|
|
||||||
use crate::time::{self, Instant};
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
fn assert_send<T: Send>() {}
|
|
||||||
fn assert_sync<T: Sync>() {}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn registration_is_send_and_sync() {
|
|
||||||
use crate::time::Sleep;
|
|
||||||
|
|
||||||
assert_send::<Sleep>();
|
|
||||||
assert_sync::<Sleep>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn sleep_is_eager() {
|
|
||||||
let when = Instant::now() + Duration::from_millis(100);
|
|
||||||
let _ = time::sleep_until(when);
|
|
||||||
}
|
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
//use crate::time::driver::{Driver, Entry, Handle};
|
|
||||||
|
|
||||||
/*
|
|
||||||
macro_rules! poll {
|
|
||||||
($e:expr) => {
|
|
||||||
$e.enter(|cx, e| e.poll_elapsed(cx))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn frozen_utility_returns_correct_advanced_duration() {
|
|
||||||
let clock = Clock::new();
|
|
||||||
clock.pause();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
clock.advance(ms(10));
|
|
||||||
assert_eq!(clock.now() - start, ms(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn immediate_sleep() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
let when = clock.now();
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, when));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
|
|
||||||
assert_ok!(driver.park_timeout(Duration::from_millis(1000)));
|
|
||||||
|
|
||||||
// The time has not advanced. The `turn` completed immediately.
|
|
||||||
assert_eq!(clock.now() - start, ms(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn delayed_sleep_level_0() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
for &i in &[1, 10, 60] {
|
|
||||||
// Create a `Sleep` that elapses in the future
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, start + ms(i)));
|
|
||||||
|
|
||||||
// The sleep instance has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(i));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sub_ms_delayed_sleep() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
|
|
||||||
for _ in 0..5 {
|
|
||||||
let deadline = clock.now() + ms(1) + Duration::new(0, 1);
|
|
||||||
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, deadline));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
|
|
||||||
assert!(clock.now() >= deadline);
|
|
||||||
|
|
||||||
clock.advance(Duration::new(0, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn delayed_sleep_wrapping_level_0() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
assert_ok!(driver.park_timeout(ms(5)));
|
|
||||||
assert_eq!(clock.now() - start, ms(5));
|
|
||||||
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(60)));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(64));
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(65));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn timer_wrapping_with_higher_levels() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Set sleep to hit level 1
|
|
||||||
let mut e1 = task::spawn(sleep_until(&handle, clock.now() + ms(64)));
|
|
||||||
assert_pending!(poll!(e1));
|
|
||||||
|
|
||||||
// Turn a bit
|
|
||||||
assert_ok!(driver.park_timeout(ms(5)));
|
|
||||||
|
|
||||||
// Set timeout such that it will hit level 0, but wrap
|
|
||||||
let mut e2 = task::spawn(sleep_until(&handle, clock.now() + ms(60)));
|
|
||||||
assert_pending!(poll!(e2));
|
|
||||||
|
|
||||||
// This should result in s1 firing
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(64));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e1));
|
|
||||||
assert_pending!(poll!(e2));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(65));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sleep_with_deadline_in_past() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Create `Sleep` that elapsed immediately.
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() - ms(100)));
|
|
||||||
|
|
||||||
// Even though the `Sleep` expires in the past, it is not ready yet
|
|
||||||
// because the timer must observe it.
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer, it runs for the elapsed time
|
|
||||||
assert_ok!(driver.park_timeout(ms(1000)));
|
|
||||||
|
|
||||||
// The time has not advanced. The `turn` completed immediately.
|
|
||||||
assert_eq!(clock.now() - start, ms(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn delayed_sleep_level_1() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Create a `Sleep` that elapses in the future
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(234)));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer, this will wake up to cascade the timer down.
|
|
||||||
assert_ok!(driver.park_timeout(ms(1000)));
|
|
||||||
assert_eq!(clock.now() - start, ms(192));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer again
|
|
||||||
assert_ok!(driver.park_timeout(ms(1000)));
|
|
||||||
assert_eq!(clock.now() - start, ms(234));
|
|
||||||
|
|
||||||
// The sleep has elapsed.
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Create a `Sleep` that elapses in the future
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(234)));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer with a smaller timeout than the cascade.
|
|
||||||
assert_ok!(driver.park_timeout(ms(100)));
|
|
||||||
assert_eq!(clock.now() - start, ms(100));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer, this will wake up to cascade the timer down.
|
|
||||||
assert_ok!(driver.park_timeout(ms(1000)));
|
|
||||||
assert_eq!(clock.now() - start, ms(192));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer again
|
|
||||||
assert_ok!(driver.park_timeout(ms(1000)));
|
|
||||||
assert_eq!(clock.now() - start, ms(234));
|
|
||||||
|
|
||||||
// The sleep has elapsed.
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn concurrently_set_two_timers_second_one_shorter() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
let mut e1 = task::spawn(sleep_until(&handle, clock.now() + ms(500)));
|
|
||||||
let mut e2 = task::spawn(sleep_until(&handle, clock.now() + ms(200)));
|
|
||||||
|
|
||||||
// The sleep has not elapsed
|
|
||||||
assert_pending!(poll!(e1));
|
|
||||||
assert_pending!(poll!(e2));
|
|
||||||
|
|
||||||
// Sleep until a cascade
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(192));
|
|
||||||
|
|
||||||
// Sleep until the second timer.
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(200));
|
|
||||||
|
|
||||||
// The shorter sleep fires
|
|
||||||
assert_ready_ok!(poll!(e2));
|
|
||||||
assert_pending!(poll!(e1));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(448));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e1));
|
|
||||||
|
|
||||||
// Turn again, this time the time will advance to the second sleep
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(500));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn short_sleep() {
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Create a `Sleep` that elapses in the future
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(1)));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
// Turn the timer, but not enough time will go by.
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
|
|
||||||
// The sleep has elapsed.
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
|
|
||||||
// The time has advanced to the point of the sleep elapsing.
|
|
||||||
assert_eq!(clock.now() - start, ms(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sorta_long_sleep_until() {
|
|
||||||
const MIN_5: u64 = 5 * 60 * 1000;
|
|
||||||
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Create a `Sleep` that elapses in the future
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(MIN_5)));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
let cascades = &[262_144, 262_144 + 9 * 4096, 262_144 + 9 * 4096 + 15 * 64];
|
|
||||||
|
|
||||||
for &elapsed in cascades {
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(elapsed));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(MIN_5));
|
|
||||||
|
|
||||||
// The sleep has elapsed.
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn very_long_sleep() {
|
|
||||||
const MO_5: u64 = 5 * 30 * 24 * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
// Create a `Sleep` that elapses in the future
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(MO_5)));
|
|
||||||
|
|
||||||
// The sleep has not elapsed.
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
let cascades = &[
|
|
||||||
12_884_901_888,
|
|
||||||
12_952_010_752,
|
|
||||||
12_959_875_072,
|
|
||||||
12_959_997_952,
|
|
||||||
];
|
|
||||||
|
|
||||||
for &elapsed in cascades {
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
assert_eq!(clock.now() - start, ms(elapsed));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn the timer, but not enough time will go by.
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
|
|
||||||
// The time has advanced to the point of the sleep elapsing.
|
|
||||||
assert_eq!(clock.now() - start, ms(MO_5));
|
|
||||||
|
|
||||||
// The sleep has elapsed.
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unpark_is_delayed() {
|
|
||||||
// A special park that will take much longer than the requested duration
|
|
||||||
struct MockPark(Clock);
|
|
||||||
|
|
||||||
struct MockUnpark;
|
|
||||||
|
|
||||||
impl Park for MockPark {
|
|
||||||
type Unpark = MockUnpark;
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn unpark(&self) -> Self::Unpark {
|
|
||||||
MockUnpark
|
|
||||||
}
|
|
||||||
|
|
||||||
fn park(&mut self) -> Result<(), Self::Error> {
|
|
||||||
panic!("parking forever");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
|
|
||||||
assert_eq!(duration, ms(0));
|
|
||||||
self.0.advance(ms(436));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Unpark for MockUnpark {
|
|
||||||
fn unpark(&self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let clock = Clock::new();
|
|
||||||
clock.pause();
|
|
||||||
let start = clock.now();
|
|
||||||
let mut driver = Driver::new(MockPark(clock.clone()), clock.clone());
|
|
||||||
let handle = driver.handle();
|
|
||||||
|
|
||||||
let mut e1 = task::spawn(sleep_until(&handle, clock.now() + ms(100)));
|
|
||||||
let mut e2 = task::spawn(sleep_until(&handle, clock.now() + ms(101)));
|
|
||||||
let mut e3 = task::spawn(sleep_until(&handle, clock.now() + ms(200)));
|
|
||||||
|
|
||||||
assert_pending!(poll!(e1));
|
|
||||||
assert_pending!(poll!(e2));
|
|
||||||
assert_pending!(poll!(e3));
|
|
||||||
|
|
||||||
assert_ok!(driver.park());
|
|
||||||
|
|
||||||
assert_eq!(clock.now() - start, ms(500));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e1));
|
|
||||||
assert_ready_ok!(poll!(e2));
|
|
||||||
assert_ready_ok!(poll!(e3));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn set_timeout_at_deadline_greater_than_max_timer() {
|
|
||||||
const YR_1: u64 = 365 * 24 * 60 * 60 * 1000;
|
|
||||||
const YR_5: u64 = 5 * YR_1;
|
|
||||||
|
|
||||||
let (mut driver, clock, handle) = setup();
|
|
||||||
let start = clock.now();
|
|
||||||
|
|
||||||
for _ in 0..5 {
|
|
||||||
assert_ok!(driver.park_timeout(ms(YR_1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut e = task::spawn(sleep_until(&handle, clock.now() + ms(1)));
|
|
||||||
assert_pending!(poll!(e));
|
|
||||||
|
|
||||||
assert_ok!(driver.park_timeout(ms(1000)));
|
|
||||||
assert_eq!(clock.now() - start, ms(YR_5) + ms(1));
|
|
||||||
|
|
||||||
assert_ready_ok!(poll!(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup() -> (Driver<MockPark>, Clock, Handle) {
|
|
||||||
let clock = Clock::new();
|
|
||||||
clock.pause();
|
|
||||||
let driver = Driver::new(MockPark(clock.clone()), clock.clone());
|
|
||||||
let handle = driver.handle();
|
|
||||||
|
|
||||||
(driver, clock, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sleep_until(handle: &Handle, when: Instant) -> Arc<Entry> {
|
|
||||||
Entry::new(&handle, when, ms(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MockPark(Clock);
|
|
||||||
|
|
||||||
struct MockUnpark;
|
|
||||||
|
|
||||||
impl Park for MockPark {
|
|
||||||
type Unpark = MockUnpark;
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn unpark(&self) -> Self::Unpark {
|
|
||||||
MockUnpark
|
|
||||||
}
|
|
||||||
|
|
||||||
fn park(&mut self) -> Result<(), Self::Error> {
|
|
||||||
panic!("parking forever");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
|
|
||||||
self.0.advance(duration);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Unpark for MockUnpark {
|
|
||||||
fn unpark(&self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ms(n: u64) -> Duration {
|
|
||||||
Duration::from_millis(n)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Reference in New Issue
Block a user