ostd/timer/
mod.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! The timer support.
4
5mod jiffies;
6
7use alloc::{boxed::Box, vec::Vec};
8use core::{cell::RefCell, sync::atomic::Ordering};
9
10pub use jiffies::Jiffies;
11
12use crate::{
13    arch::trap::TrapFrame,
14    cpu::{CpuId, PinCurrentCpu},
15    cpu_local, irq,
16};
17
18/// The timer frequency in Hz.
19///
20/// Here we choose 1000Hz since 1000Hz is easier for unit conversion and convenient for timer.
21/// What's more, the frequency cannot be set too high or too low, 1000Hz is a modest choice.
22///
23/// For system performance reasons, this rate cannot be set too high, otherwise most of the time is
24/// spent in executing timer code.
25pub const TIMER_FREQ: u64 = 1000;
26
27type InterruptCallback = Box<dyn Fn() + Sync + Send>;
28
29cpu_local! {
30    static INTERRUPT_CALLBACKS: RefCell<Vec<InterruptCallback>> = RefCell::new(Vec::new());
31}
32
33/// Registers a function that will be executed during the timer interrupt on the current CPU.
34pub fn register_callback_on_cpu<F>(func: F)
35where
36    F: Fn() + Sync + Send + 'static,
37{
38    let irq_guard = irq::disable_local();
39    INTERRUPT_CALLBACKS
40        .get_with(&irq_guard)
41        .borrow_mut()
42        .push(Box::new(func));
43}
44
45pub(crate) fn call_timer_callback_functions(_: &TrapFrame) {
46    let irq_guard = irq::disable_local();
47
48    if irq_guard.current_cpu() == CpuId::bsp() {
49        jiffies::ELAPSED.fetch_add(1, Ordering::Relaxed);
50    }
51
52    let callbacks_guard = INTERRUPT_CALLBACKS.get_with(&irq_guard);
53    for callback in callbacks_guard.borrow().iter() {
54        (callback)();
55    }
56    drop(callbacks_guard);
57}