    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73

    use core::cmp::Ordering;

    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 lazy_static::*;
    use riscv::register::time;

    const TICKS_PER_SEC: usize = 100;
    const MSEC_PER_SEC: usize = 1000;

    pub fn get_time() -> usize {
        time::read()
    }

    pub fn get_time_ms() -> usize {
        time::read() / (CLOCK_FREQ / MSEC_PER_SEC)
    }

    pub fn set_next_trigger() {
        set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC);
    }

    pub struct TimerCondVar {
        pub expire_ms: usize,
        pub task: Arc<TaskControlBlock>,
    }

    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<Ordering> {
            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<BinaryHeap<TimerCondVar>> =
            unsafe { UPSafeCell::new(BinaryHeap::<TimerCondVar>::new()) };
    }

    pub fn add_timer(expire_ms: usize, task: Arc<TaskControlBlock>) {
        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;
            }
        }
    }