use super::timer::TimerHandle;
use super::{ClockPtr, Interval, SyncUnsafeRcRefCell, SyncUnsafeWeakRefCell, Tick, Timer, TPL};
use anyhow::{Ok, Result as AnyResult};
use std::ops::Sub;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
use std::time::{Duration, Instant};
use crate::NonBlockTickBridge;
use log::info;
use rblist::{BList, Node, Scale};
const MAX_COUNT_PER_SCHEDULE: u32 = 100;
const MAX_TIMERS_PER_TICK: u32 = 10000;
static mut CLOCK_ID: AtomicUsize = AtomicUsize::new(1);
pub(super) type Scheduler = BList<Option<SyncUnsafeRcRefCell<TPL>>>;
pub type MockClockPtr = Pin<&'static Mutex<MockClock>>;
#[derive(Debug)]
pub struct MockClock {
me: Option<MockClockPtr>,
id: usize,
start: Tick,
last_check: Tick,
last: Tick,
now: Tick,
ts_start: Instant,
ts_last: Instant,
ts_now: Instant,
precision: u32,
}
impl MockClock {
pub fn init_distributed_clocks() {}
pub fn new(_: Option<Box<NonBlockTickBridge>>) -> Option<Pin<&'static Mutex<Self>>> {
let boxed = Box::new(Mutex::new(Self {
me: None,
id: unsafe { CLOCK_ID.fetch_add(1, Ordering::Relaxed) },
start: 0.into(),
last_check: 0.into(),
last: 0.into(),
now: 0.into(),
ts_start: Instant::now(),
ts_last: Instant::now(),
ts_now: Instant::now(),
precision: 500,
}));
let ptr: &'static Mutex<Self> = Box::leak(boxed);
let me = Some(Pin::new(ptr));
ptr.lock().unwrap().me = me;
info!("The mocked clock is created.");
me
}
pub fn new_timer<F>(
clk: Pin<&'static Mutex<Self>>,
duration: Duration,
f: F,
_name: String,
) -> AnyResult<Timer>
where
F: FnOnce() + Send + Sync + 'static,
{
info!(
"Create a new timer with duration {:?} in mocked clock",
duration
);
let interval: Interval = duration.into();
let mut guard = clk.lock().unwrap(); let clock = &mut *guard;
let clock_ptr: *mut MockClock = clock;
let tpl = TPL::new(clock_ptr, 100.into(), interval);
let mut tpl = tpl.unsafe_try_borrow_mut().unwrap();
tpl.new_timer(interval, Box::new(f), 10.into(), "test".into())
}
pub fn cancel_timer(_: Pin<&'static Mutex<Self>>, _t: &mut Timer) -> AnyResult<()> {
info!("Cancel the timer in mocked clock");
Ok(())
}
pub(super) fn remove_tpl(&mut self, interval: Interval) -> AnyResult<SyncUnsafeRcRefCell<TPL>> {
info!("Remove the timer production line in mocked clock");
Ok(TPL::new(self as *mut Self, 100.into(), interval))
}
pub(super) fn this(&self) -> ClockPtr {
let x = self.me.unwrap();
assert!(self.me.is_some()); x
}
pub(super) fn peg_timer_canceled(&mut self) {}
pub(super) fn id(&self) -> usize {
self.id
}
pub fn on_tick(clk: Pin<&'static Mutex<Self>>, tick: Tick) -> AnyResult<()> {
let mut guard = clk.lock().unwrap(); let clock = &mut *guard;
if clock.start.0 == 0 {
clock.start = tick;
clock.ts_start = Instant::now();
clock.last = tick;
clock.ts_last = Instant::now();
clock.now = tick;
clock.ts_now = Instant::now();
clock.last_check = tick;
} else {
clock.now = tick;
assert!(clock.now.since(clock.last) == 1.into());
clock.last = clock.now;
if clock.now.since(clock.last_check) == 1000.into() {
clock.ts_now = Instant::now();
let delta = clock.ts_now.sub(clock.ts_last);
info!(
"Clock[{}]:Time per 1000 ticks: {:?}, now:{:?}, start at:{:?}",
clock.id, delta, clock.now, clock.start
);
clock.ts_last = clock.ts_now;
clock.last_check = clock.now;
clock.precision = ((clock.precision + delta.as_millis() as u32) / 2) as u32;
}
}
Ok(())
}
pub fn precision(clk: Pin<&'static Mutex<Self>>) -> u32 {
let mut guard = clk.lock().unwrap(); let clock = &mut *guard;
clock.precision
}
pub fn clock_len(_clk: Pin<&'static Mutex<Self>>) -> isize {
0
}
pub fn now(clk: Pin<&'static Mutex<Self>>) -> Tick {
let guard = clk.lock().unwrap(); let clock = &*guard;
clock.now
}
}
impl MockClock {
pub fn schedule_tpl(
&mut self,
_: Tick,
_: SyncUnsafeRcRefCell<TPL>,
) -> AnyResult<(SyncUnsafeWeakRefCell<Scheduler>, Node)> {
info!("Schedule the timer production line in mocked clock");
Ok((
SyncUnsafeRcRefCell::unsafe_downgrade(&SyncUnsafeRcRefCell::new(BList::new(Scale::Medium))),
Node::default(),
))
}
pub fn deschedule_tpl(
&mut self,
_: Tick,
_: SyncUnsafeWeakRefCell<Scheduler>,
_: Node,
) -> AnyResult<()> {
info!("Deschedule the timer production line in mocked clock");
Ok(())
}
fn schedule(&mut self) -> (u32, BList<TimerHandle>, bool) {
info!("Schedule the timer in mocked clock");
(0, BList::new(Scale::Tiny), 0 > 0)
}
}