Skip to main content

os/
timer.rs

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}