//! RISC-V timer-related functionality use crate::config::CLOCK_FREQ; use crate::sbi::set_timer; use crate::sync::UPSafeCell; use crate::task::{add_task, TaskControlBlock}; use alloc::collections::BinaryHeap; use alloc::sync::Arc; use core::cmp::Ordering; use lazy_static::*; use riscv::register::time; const TICKS_PER_SEC: usize = 100; const MILLI_PER_SEC: usize = 1_000; const MICRO_PER_SEC: usize = 1_000_000; /// read the `mtime` register pub fn get_time() -> usize { time::read() } /// get current time in microseconds pub fn get_time_us() -> usize { time::read() / (CLOCK_FREQ / MICRO_PER_SEC) } /// get current time in milliseconds pub fn get_time_ms() -> usize { time::read() / (CLOCK_FREQ / MILLI_PER_SEC) } /// set the next timer interrupt pub fn set_next_trigger() { set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC); } pub struct TimerCondVar { pub expire_ms: usize, pub task: Arc, } impl PartialEq for TimerCondVar { fn eq(&self, other: &Self) -> bool { self.expire_ms == other.expire_ms } } impl Eq for TimerCondVar {} impl PartialOrd for TimerCondVar { fn partial_cmp(&self, other: &Self) -> Option { let a = -(self.expire_ms as isize); let b = -(other.expire_ms as isize); Some(a.cmp(&b)) } } impl Ord for TimerCondVar { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } } lazy_static! { static ref TIMERS: UPSafeCell> = unsafe { UPSafeCell::new(BinaryHeap::::new()) }; } pub fn add_timer(expire_ms: usize, task: Arc) { let mut timers = TIMERS.exclusive_access(); timers.push(TimerCondVar { expire_ms, task }); } pub fn check_timer() { let current_ms = get_time_ms(); let mut timers = TIMERS.exclusive_access(); while let Some(timer) = timers.peek() { if timer.expire_ms <= current_ms { add_task(Arc::clone(&timer.task)); timers.pop(); } else { break; } } }