starry-kernel 0.10.2

A Linux-compatible OS kernel built on ArceOS unikernel
Documentation
use ax_runtime::hal::time::TimeValue;
use starry_signal::Signo;

use super::{
    ITimerSetting, ITimerType, ProcessCpuTimeSnapshot, ProcessTimerManager, accounting, alarm,
    time_value_from_nanos,
};


fn interval_timer_active_gate_rules_hold_for_test() -> bool {
    let mut timers = ProcessTimerManager::new();
    let snapshot = ProcessCpuTimeSnapshot {
        user_ns: 0,
        system_ns: 0,
        sampled_at_ns: 0,
    };
    if timers.active_mask() != 0 {
        return false;
    }

    let _armed = timers.set_itimer(
        ITimerType::Virtual,
        ITimerSetting::new(time_value_from_nanos(1_000), time_value_from_nanos(2_000)),
        snapshot,
    );
    if timers.active_mask() != 1 << ITimerType::Virtual as usize {
        return false;
    }

    let _disarmed = timers.set_itimer(
        ITimerType::Virtual,
        ITimerSetting::new(TimeValue::ZERO, TimeValue::ZERO),
        snapshot,
    );
    timers.active_mask() == 0
}

fn interval_timer_arm_uses_current_snapshot_for_test() -> bool {
    const SECOND: u64 = 1_000_000_000;

    let mut timers = ProcessTimerManager::new();
    let armed_at = ProcessCpuTimeSnapshot {
        user_ns: 3 * SECOND,
        system_ns: 2 * SECOND,
        sampled_at_ns: 5 * SECOND,
    };
    let _armed = timers.set_itimer(
        ITimerType::Real,
        ITimerSetting::new(TimeValue::ZERO, time_value_from_nanos(2 * SECOND)),
        armed_at,
    );
    let pending = timers.poll(armed_at);

    pending.signals().next().is_none()
        && timers.get_itimer(ITimerType::Real, armed_at).1.as_nanos() == u128::from(2 * SECOND)
}

fn cpu_interval_timers_avoid_wall_alarms_for_test() -> bool {
    for (timer, signal) in [
        (ITimerType::Virtual, Signo::SIGVTALRM),
        (ITimerType::Prof, Signo::SIGPROF),
    ] {
        let mut timers = ProcessTimerManager::new();
        let armed_at = ProcessCpuTimeSnapshot {
            user_ns: 100,
            system_ns: 50,
            sampled_at_ns: 1_000,
        };
        let armed = timers.set_itimer(
            timer,
            ITimerSetting::new(TimeValue::ZERO, time_value_from_nanos(10)),
            armed_at,
        );
        if armed.publishes_wall_alarm() {
            return false;
        }

        let wall_only_advanced = ProcessCpuTimeSnapshot {
            sampled_at_ns: 1_000_000,
            ..armed_at
        };
        let pending = timers.poll_cpu(wall_only_advanced);
        if pending.signals().next().is_some()
            || pending.publishes_wall_alarm()
            || timers.get_itimer(timer, wall_only_advanced).1.as_nanos() != 10
        {
            return false;
        }

        let cpu_advanced = match timer {
            ITimerType::Virtual => ProcessCpuTimeSnapshot {
                user_ns: 110,
                ..wall_only_advanced
            },
            ITimerType::Prof => ProcessCpuTimeSnapshot {
                system_ns: 60,
                ..wall_only_advanced
            },
            ITimerType::Real => unreachable!(),
        };
        let expired = timers.poll_cpu(cpu_advanced);
        if expired.signals().collect::<alloc::vec::Vec<_>>() != [signal]
            || expired.publishes_wall_alarm()
        {
            return false;
        }
    }
    true
}

fn process_cpu_high_water_preserves_runtime_total_for_test() -> bool {
    accounting::process_cpu_high_water_preserves_runtime_total_for_test()
}

fn zero_process_cpu_time_delta_avoids_publication_for_test() -> bool {
    accounting::zero_process_cpu_time_delta_avoids_publication_for_test()
}

fn alarm_generation_rules_hold_for_test() -> bool {
    alarm::stale_alarm_cancellation_preserves_new_generation_for_test()
}


#[axtest::axtest]
fn interval_timer_active_gate_rules_hold() {
    assert!(interval_timer_active_gate_rules_hold_for_test());
}

#[axtest::axtest]
fn interval_timer_arm_uses_current_snapshot() {
    assert!(interval_timer_arm_uses_current_snapshot_for_test());
}

#[axtest::axtest]
fn cpu_interval_timers_avoid_wall_alarms() {
    assert!(cpu_interval_timers_avoid_wall_alarms_for_test());
}

#[axtest::axtest]
fn process_cpu_high_water_preserves_runtime_total() {
    assert!(process_cpu_high_water_preserves_runtime_total_for_test());
}

#[axtest::axtest]
fn zero_process_cpu_time_delta_avoids_publication() {
    assert!(zero_process_cpu_time_delta_avoids_publication_for_test());
}

#[axtest::axtest]
fn alarm_generation_rules_hold() {
    assert!(alarm_generation_rules_hold_for_test());
}