use axhal::time::{current_time_nanos, NANOS_PER_MICROS, NANOS_PER_SEC};
#[cfg(feature = "signal")]
use axsignal::signal_no::SignalNo;
#[cfg(feature = "signal")]
use crate_interface::{call_interface, def_interface};
numeric_enum_macro::numeric_enum! {
#[repr(i32)]
#[allow(non_camel_case_types)]
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum TimerType {
NONE = -1,
REAL = 0,
VIRTUAL = 1,
PROF = 2,
}
}
impl From<usize> for TimerType {
fn from(num: usize) -> Self {
match Self::try_from(num as i32) {
Ok(val) => val,
Err(_) => Self::NONE,
}
}
}
pub struct TimeStat {
utime_ns: usize,
stime_ns: usize,
user_tick: usize,
kernel_tick: usize,
timer_type: TimerType,
timer_interval_ns: usize,
timer_remained_ns: usize,
}
#[cfg(feature = "signal")]
#[def_interface]
pub trait SignalCaller {
fn send_signal(tid: isize, signum: isize);
}
#[allow(unused)]
impl TimeStat {
pub fn new() -> Self {
Self {
utime_ns: 0,
stime_ns: 0,
user_tick: 0,
kernel_tick: current_time_nanos() as usize,
timer_type: TimerType::NONE,
timer_interval_ns: 0,
timer_remained_ns: 0,
}
}
pub fn clear(&mut self) {
self.utime_ns = 0;
self.stime_ns = 0;
self.user_tick = 0;
self.kernel_tick = current_time_nanos() as usize;
}
pub fn switch_into_kernel_mode(&mut self, tid: isize) {
let now_time_ns = current_time_nanos() as usize;
let delta = now_time_ns - self.user_tick;
self.utime_ns += delta;
self.kernel_tick = now_time_ns;
if self.timer_type != TimerType::NONE {
self.update_timer(delta, tid);
};
}
pub fn switch_into_user_mode(&mut self, tid: isize) {
let now_time_ns = current_time_nanos() as usize;
let delta = now_time_ns - self.kernel_tick;
self.stime_ns += delta;
self.user_tick = now_time_ns;
if self.timer_type == TimerType::REAL || self.timer_type == TimerType::PROF {
self.update_timer(delta, tid);
};
}
pub fn swtich_from_old_task(&mut self, tid: isize) {
let now_time_ns = current_time_nanos() as usize;
let delta = now_time_ns - self.kernel_tick;
self.stime_ns += delta;
self.kernel_tick = now_time_ns;
if self.timer_type == TimerType::REAL || self.timer_type == TimerType::PROF {
self.update_timer(delta, tid);
};
}
pub fn switch_to_new_task(&mut self, tid: isize) {
let now_time_ns = current_time_nanos() as usize;
let delta = now_time_ns - self.kernel_tick;
self.kernel_tick = now_time_ns;
if self.timer_type == TimerType::REAL {
self.update_timer(delta, tid)
}
}
pub fn output_as_us(&self) -> (usize, usize, usize, usize) {
let utime_s = self.utime_ns / (NANOS_PER_SEC as usize);
let stime_s = self.stime_ns / (NANOS_PER_SEC as usize);
let utime_us = self.utime_ns / (NANOS_PER_MICROS as usize);
let stime_us = self.stime_ns / (NANOS_PER_MICROS as usize);
(utime_s, utime_us, stime_s, stime_us)
}
pub fn output_timer_as_us(&self) -> (usize, usize) {
(self.timer_interval_ns / 1000, self.timer_remained_ns / 1000)
}
pub fn set_timer(
&mut self,
timer_interval_ns: usize,
timer_remained_ns: usize,
timer_type: usize,
) -> bool {
self.timer_type = timer_type.into();
self.timer_interval_ns = timer_interval_ns;
self.timer_remained_ns = timer_remained_ns;
self.timer_type != TimerType::NONE
}
pub fn update_timer(&mut self, delta: usize, _tid: isize) {
if self.timer_remained_ns == 0 {
return;
}
if self.timer_remained_ns > delta {
self.timer_remained_ns -= delta;
return;
}
self.timer_remained_ns = self.timer_interval_ns;
#[cfg(feature = "signal")]
{
let signal_num = match &self.timer_type {
TimerType::REAL => SignalNo::SIGALRM,
TimerType::VIRTUAL => SignalNo::SIGVTALRM,
TimerType::PROF => SignalNo::SIGPROF,
_ => SignalNo::ERR,
};
if signal_num != SignalNo::ERR {
call_interface!(SignalCaller::send_signal(_tid, signal_num as isize));
}
}
}
}