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:
Carl Lerche
2022-09-06 14:12:09 -07:00
committed by GitHub
parent 116fa7c614
commit bbfd34f6a3
13 changed files with 33 additions and 546 deletions
+2 -3
View File
@@ -497,9 +497,8 @@ cfg_rt! {
pub mod runtime;
}
cfg_not_rt! {
cfg_io_driver_impl! {
pub(crate) mod runtime;
}
// The `runtime` module is used when the IO or time driver is needed.
pub(crate) mod runtime;
}
pub(crate) mod coop;
+3 -3
View File
@@ -98,10 +98,10 @@ cfg_not_process_driver! {
// ===== time driver =====
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 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 {
crate::time::Clock::new(enable_pausing, start_paused)
@@ -115,7 +115,7 @@ cfg_time! {
use crate::park::either::Either;
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();
(Either::A(driver), Some(handle))
+4
View File
@@ -181,6 +181,10 @@ cfg_io_driver_impl! {
pub(crate) mod io;
}
cfg_time! {
pub(crate) mod time;
}
cfg_rt! {
pub(crate) mod enter;
@@ -283,7 +283,7 @@ impl StateCell {
/// timer. As this participates in intrusive data structures, it must be pinned
/// before polling.
#[derive(Debug)]
pub(super) struct TimerEntry {
pub(crate) struct TimerEntry {
/// Arc reference to the driver. We can only free the driver after
/// deregistering everything from their respective timer wheels.
driver: Handle,
@@ -1,5 +1,5 @@
use crate::loom::sync::Arc;
use crate::time::driver::ClockTime;
use crate::runtime::time::ClockTime;
use std::fmt;
/// Handle to time driver instance.
@@ -17,7 +17,7 @@ impl 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
}
@@ -7,15 +7,14 @@
//! Time driver.
mod entry;
pub(self) use self::entry::{EntryList, TimerEntry, TimerHandle, TimerShared};
pub(crate) use entry::TimerEntry;
use entry::{EntryList, TimerHandle, TimerShared};
mod handle;
pub(crate) use self::handle::Handle;
mod wheel;
pub(super) mod sleep;
use crate::loom::sync::atomic::{AtomicBool, Ordering};
use crate::loom::sync::{Arc, Mutex};
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.
#[derive(Debug, Clone)]
pub(self) struct ClockTime {
clock: super::clock::Clock,
pub(crate) struct ClockTime {
clock: crate::time::Clock,
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
self.instant_to_tick(t + Duration::from_nanos(999_999))
}
@@ -136,7 +135,7 @@ impl ClockTime {
Duration::from_millis(t)
}
pub(self) fn now(&self) -> u64 {
pub(crate) fn now(&self) -> u64 {
self.instant_to_tick(self.clock.now())
}
}
@@ -403,7 +402,7 @@ impl Handle {
None
}
Err((entry, super::error::InsertError::Elapsed)) => unsafe {
Err((entry, crate::time::error::InsertError::Elapsed)) => unsafe {
entry.fire(Ok(()))
},
}
@@ -48,7 +48,7 @@ fn model(f: impl Fn() + Send + Sync + 'static) {
#[test]
fn single_timer() {
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 inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
@@ -79,7 +79,7 @@ fn single_timer() {
#[test]
fn drop_timer() {
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 inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
@@ -110,7 +110,7 @@ fn drop_timer() {
#[test]
fn change_waker() {
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 inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
@@ -145,7 +145,7 @@ fn reset_future() {
model(|| {
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 inner = super::Inner::new(time_source.clone(), MockUnpark::mock());
@@ -201,7 +201,7 @@ fn normal_or_miri<T>(normal: T, miri: T) -> T {
#[test]
#[cfg(not(loom))]
fn poll_process_levels() {
let clock = crate::time::clock::Clock::new(true, false);
let clock = crate::time::Clock::new(true, false);
clock.pause();
let time_source = super::ClockTime::new(clock.clone());
@@ -242,7 +242,7 @@ fn poll_process_levels() {
fn poll_process_levels_targeted() {
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();
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);
}
/*
#[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::time::driver::{EntryList, TimerShared};
use crate::runtime::time::{EntryList, TimerHandle, TimerShared};
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;
mod level;
+4 -9
View File
@@ -82,17 +82,13 @@
//! ```
//!
//! [`interval`]: crate::time::interval()
//! [`sleep`]: sleep()
mod clock;
pub(crate) use self::clock::Clock;
#[cfg(feature = "test-util")]
pub use clock::{advance, pause, resume};
pub(crate) mod driver;
#[doc(inline)]
pub use driver::sleep::{sleep, sleep_until, Sleep};
pub mod error;
mod instant;
@@ -101,14 +97,13 @@ pub use self::instant::Instant;
mod interval;
pub use interval::{interval, interval_at, Interval, MissedTickBehavior};
mod sleep;
pub use sleep::{sleep, sleep_until, Sleep};
mod timeout;
#[doc(inline)]
pub use timeout::{timeout, timeout_at, Timeout};
#[cfg(test)]
#[cfg(not(loom))]
mod tests;
// Re-export for convenience
#[doc(no_inline)]
pub use std::time::Duration;
@@ -1,6 +1,6 @@
#[cfg(all(tokio_unstable, feature = "tracing"))]
use crate::time::driver::ClockTime;
use crate::time::driver::{Handle, TimerEntry};
use crate::runtime::time::ClockTime;
use crate::runtime::time::{Handle, TimerEntry};
use crate::time::{error::Error, Duration, Instant};
use crate::util::trace;
-22
View File
@@ -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);
}
-443
View File
@@ -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)
}
*/