1use core::cmp::Ordering;
2
3use crate::config::CLOCK_FREQ;
4use crate::sbi::set_timer;
5use crate::sync::UPSafeCell;
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: UPSafeCell<BinaryHeap<TimerCondVar>> =
54 unsafe { UPSafeCell::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 remove_timer(task: Arc<TaskControlBlock>) {
63 let mut timers = TIMERS.exclusive_access();
64 let mut temp = BinaryHeap::<TimerCondVar>::new();
65 for condvar in timers.drain() {
66 if Arc::as_ptr(&task) != Arc::as_ptr(&condvar.task) {
67 temp.push(condvar);
68 }
69 }
70 timers.clear();
71 timers.append(&mut temp);
72}
73
74pub fn check_timer() {
75 let current_ms = get_time_ms();
76 let mut timers = TIMERS.exclusive_access();
77 while let Some(timer) = timers.peek() {
78 if timer.expire_ms <= current_ms {
79 wakeup_task(Arc::clone(&timer.task));
80 timers.pop();
81 } else {
82 break;
83 }
84 }
85}