第一节 获得系统时间
系统时间是支持内核运行最重要的基础之一,也是应用需要获取的重要服务之一。获取系统时间必须基于硬件平台提供的时间寄存器,它们本质上就是由晶振驱动的计数器。对 RiscV64 来说,在 M-Mode 有一个专门的计数寄存器 mtime 作为计算时间的基础,它在 S-Mode 被映射为名为 time 的寄存器,所以内核虽然运行在 S-Mode,也可以读出该寄存器的值。按照规范文档的说法,time 是 mtime 的 shadow。
既然获取系统时间是体系结构相关的功能,我们把它放到 axhal 中实现。
// axhal/src/riscv64/time.rs
use core::time::Duration;
use riscv::register::time;
const TIMER_FREQUENCY: u64 = 10_000_000; // 10MHz
const NANOS_PER_SEC: u64 = 1_000_000_000;
const NANOS_PER_TICK: u64 = NANOS_PER_SEC / TIMER_FREQUENCY;
pub type TimeValue = Duration;
#[inline]
pub fn current_ticks() -> u64 {
time::read() as u64
}
#[inline]
pub const fn ticks_to_nanos(ticks: u64) -> u64 {
ticks * NANOS_PER_TICK
}
pub fn current_time_nanos() -> u64 {
ticks_to_nanos(current_ticks())
}
pub fn current_time() -> TimeValue {
TimeValue::from_nanos(current_time_nanos())
}
// axhal/src/riscv64.rs
pub mod time;
第18行:核心函数 current_ticks(),返回 ticks 计数值;其他函数都以它为基础进行计算。
第22行:对外提供时间服务的主要函数。无论是内核模块还是应用接口库都是经由它获取系统时间。
本节我们先来扩展 axstd,参照 Rust 官方 STD 库的实现方式,提供 Instant 类型和相关方法,向应用提供时间功能:
// axstd/src/time.rs
use core::time::Duration;
use core::ops::Sub;
use core::fmt;
#[derive(Clone, Copy)]
pub struct Instant(axhal::time::TimeValue);
impl Instant {
pub fn now() -> Instant {
Instant(axhal::time::current_time())
}
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.0.checked_sub(earlier.0).unwrap_or_default()
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
fn sub(self, other: Instant) -> Self::Output {
self.duration_since(other)
}
}
impl fmt::Display for Instant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.{:06}", self.0.as_secs(), self.0.subsec_micros())
}
}
// axstd/src/lib.rs
pub mod time;
pub use time::*;
现在,我们可以在应用 axorigin 中,测试一下获取时间的功能:
// axorigin/src/main.rs
#![no_std]
#![no_main]
use axstd::{String, println, time};
#[no_mangle]
pub fn main(_hartid: usize, _dtb: usize) {
let now = time::Instant::now();
println!("\nNow: {}", now);
let s = String::from("from String");
println!("Hello, ArceOS![{}]", s);
let d = now.elapsed();
println!("Elapsed: {}.{:06}", d.as_secs(), d.subsec_micros());
}
执行 make run
测试,显示结果:
ArceOS is starting ...
Now: 0.103643 Hello, ArceOS![from String] Elapsed: 0.003917
获取时间功能验证成功!