use super::*;
const MAX_ITIMER_NANOS: u64 = i64::MAX as u64;
#[repr(i32)]
#[allow(non_camel_case_types)]
#[derive(Eq, PartialEq, Debug, Clone, Copy, FromRepr)]
pub enum ITimerType {
Real = 0,
Virtual = 1,
Prof = 2,
}
impl ITimerType {
pub fn signo(&self) -> Signo {
match self {
ITimerType::Real => Signo::SIGALRM,
ITimerType::Virtual => Signo::SIGVTALRM,
ITimerType::Prof => Signo::SIGPROF,
}
}
fn clock_now_ns(self, snapshot: ProcessCpuTimeSnapshot) -> u64 {
match self {
Self::Real => snapshot.sampled_at_ns,
Self::Virtual => snapshot.user_ns,
Self::Prof => snapshot.user_ns.saturating_add(snapshot.system_ns),
}
}
}
fn real_itimer_alarm_delay(remaining_ns: u64) -> Duration {
Duration::from_nanos(remaining_ns.max(1))
}
#[derive(Clone, Copy)]
pub(crate) struct ITimerSetting {
interval_ns: u64,
remaining_ns: u64,
}
impl ITimerSetting {
pub(crate) fn new(interval: TimeValue, remaining: TimeValue) -> Self {
Self {
interval_ns: bounded_itimer_nanos(interval),
remaining_ns: bounded_itimer_nanos(remaining),
}
}
}
struct ITimer {
interval_ns: u64,
deadline_ns: Option<u64>,
}
impl ITimer {
pub fn new() -> Self {
Self {
interval_ns: 0,
deadline_ns: None,
}
}
fn remaining_ns(&self, now_ns: u64) -> u64 {
self.deadline_ns
.map_or(0, |deadline_ns| deadline_ns.saturating_sub(now_ns))
}
fn replace(&mut self, setting: ITimerSetting, now_ns: u64) {
self.interval_ns = setting.interval_ns;
self.deadline_ns = (setting.remaining_ns != 0).then(|| {
now_ns
.saturating_add(setting.remaining_ns)
.min(MAX_ITIMER_NANOS)
});
}
fn update(&mut self, now_ns: u64) -> bool {
let Some(deadline_ns) = self.deadline_ns else {
return false;
};
if now_ns < deadline_ns {
false
} else {
self.deadline_ns = (self.interval_ns != 0).then(|| {
next_periodic_deadline(deadline_ns, self.interval_ns, now_ns).min(MAX_ITIMER_NANOS)
});
true
}
}
}
impl Default for ITimer {
fn default() -> Self {
Self::new()
}
}
include!("itimer/manager.rs");
#[derive(Default)]
struct ITimerUpdate {
expired: bool,
alarm_change: Option<AlarmChange>,
}
fn next_periodic_deadline(deadline_ns: u64, interval_ns: u64, now_ns: u64) -> u64 {
let elapsed_periods = now_ns
.saturating_sub(deadline_ns)
.checked_div(interval_ns)
.unwrap_or(0);
deadline_ns.saturating_add(interval_ns.saturating_mul(elapsed_periods.saturating_add(1)))
}
fn bounded_itimer_nanos(value: TimeValue) -> u64 {
u64::try_from(value.as_nanos().min(u128::from(MAX_ITIMER_NANOS))).unwrap_or(MAX_ITIMER_NANOS)
}
include!("itimer/tests.rs");