1use core::cmp::Ordering;
2
3use crate::device_tree::clock_freq;
4use crate::sbi::set_timer;
5use crate::sync::UPIntrFreeCell;
6use crate::task::{TaskControlBlock, wakeup_task};
7use alloc::collections::BinaryHeap;
8use alloc::sync::Arc;
9use lazy_static::*;
10use riscv::register::time;
11
12const TICKS_PER_SEC: usize = 100;
13const MSEC_PER_SEC: usize = 1000;
14
15pub fn get_time() -> usize {
16 time::read()
17}
18
19pub fn get_time_ms() -> usize {
20 time::read() / (clock_freq() / MSEC_PER_SEC)
21}
22
23pub fn set_next_trigger() {
24 set_timer(get_time() + clock_freq() / TICKS_PER_SEC);
25}
26
27pub struct TimerCondVar {
28 pub expire_ms: usize,
29 pub task: Arc<TaskControlBlock>,
30}
31
32impl PartialEq for TimerCondVar {
33 fn eq(&self, other: &Self) -> bool {
34 self.expire_ms == other.expire_ms
35 }
36}
37impl Eq for TimerCondVar {}
38impl PartialOrd for TimerCondVar {
39 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
40 let a = -(self.expire_ms as isize);
41 let b = -(other.expire_ms as isize);
42 Some(a.cmp(&b))
43 }
44}
45
46impl Ord for TimerCondVar {
47 fn cmp(&self, other: &Self) -> Ordering {
48 self.partial_cmp(other).unwrap()
49 }
50}
51
52lazy_static! {
53 static ref TIMERS: UPIntrFreeCell<BinaryHeap<TimerCondVar>> =
54 unsafe { UPIntrFreeCell::new(BinaryHeap::<TimerCondVar>::new()) };
55}
56
57pub fn add_timer(expire_ms: usize, task: Arc<TaskControlBlock>) {
58 let mut timers = TIMERS.exclusive_access();
59 timers.push(TimerCondVar { expire_ms, task });
60}
61
62pub fn check_timer() {
63 let current_ms = get_time_ms();
64 TIMERS.exclusive_session(|timers| {
65 while let Some(timer) = timers.peek() {
66 if timer.expire_ms <= current_ms {
67 wakeup_task(Arc::clone(&timer.task));
68 timers.pop();
69 } else {
70 break;
71 }
72 }
73 });
74}