os/
timer.rs

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}