starry-kernel 0.10.0

A Linux-compatible OS kernel built on ArceOS unikernel
Documentation
#[cfg(all(test, not(axtest)))]
mod tests {
    use super::*;

    #[test]
    fn timer_poll_returns_a_bounded_signal_batch_without_a_callback() {
        let mut manager = ProcessTimerManager::new();
        for timer in &mut manager.itimers {
            *timer = ITimer {
                interval_ns: 0,
                deadline_ns: Some(5),
            };
        }

        let pending = manager.poll_at(
            ProcessCpuTimeSnapshot {
                user_ns: 10,
                system_ns: 0,
                sampled_at_ns: 10,
            },
            false,
        );
        let signals: alloc::vec::Vec<_> = pending.signals().collect();

        assert_eq!(signals.len(), 3);
        assert!(signals.contains(&Signo::SIGALRM));
        assert!(signals.contains(&Signo::SIGVTALRM));
        assert!(signals.contains(&Signo::SIGPROF));
    }

    #[test]
    fn active_mask_tracks_only_armed_interval_timers() {
        let mut manager = ProcessTimerManager::new();
        let snapshot = snapshot_at(0, 0, 0);
        assert_eq!(manager.active_mask(), 0);

        let _real = manager.set_itimer(ITimerType::Real, setting(0, 10), snapshot);
        assert_eq!(manager.active_mask(), 1 << ITimerType::Real as usize);

        let _virtual = manager.set_itimer(ITimerType::Virtual, setting(5, 20), snapshot);
        assert_eq!(
            manager.active_mask(),
            (1 << ITimerType::Real as usize) | (1 << ITimerType::Virtual as usize)
        );

        let _disarm_real = manager.set_itimer(ITimerType::Real, setting(0, 0), snapshot);
        assert_eq!(
            manager.active_mask(),
            1 << ITimerType::Virtual as usize
        );

        let _cancellation = manager.cancel_alarm();
        assert_eq!(manager.active_mask(), 0);
    }

    #[test]
    fn newly_armed_timer_does_not_consume_prior_clock_time() {
        const SECOND: u64 = 1_000_000_000;

        let mut manager = ProcessTimerManager::new();
        let armed_at = snapshot_at(3 * SECOND, 2 * SECOND, 5 * SECOND);
        let _armed = manager.set_itimer(
            ITimerType::Real,
            setting(0, 2 * SECOND),
            armed_at,
        );

        let pending = manager.poll(armed_at);

        assert_eq!(pending.signals().next(), None);
        assert_eq!(
            manager.get_itimer(ITimerType::Real, armed_at).1,
            time_value_from_nanos(2 * SECOND)
        );
    }

    #[test]
    fn cpu_timers_do_not_publish_wall_clock_alarms() {
        for (timer, signal) in [
            (ITimerType::Virtual, Signo::SIGVTALRM),
            (ITimerType::Prof, Signo::SIGPROF),
        ] {
            let mut manager = ProcessTimerManager::new();
            let armed_at = snapshot_at(100, 50, 1_000);
            let armed = manager.set_itimer(timer, setting(0, 10), armed_at);

            assert!(
                !armed.publishes_wall_alarm(),
                "{timer:?} must be driven by CPU accounting, not wall time"
            );

            let wall_only_advanced = snapshot_at(100, 50, 1_000_000);
            let pending = manager.poll_cpu(wall_only_advanced);
            assert_eq!(pending.signals().next(), None);
            assert!(!pending.publishes_wall_alarm());
            assert_eq!(
                manager.get_itimer(timer, wall_only_advanced).1,
                time_value_from_nanos(10)
            );

            let cpu_advanced = match timer {
                ITimerType::Virtual => snapshot_at(110, 50, 1_000_001),
                ITimerType::Prof => snapshot_at(100, 60, 1_000_001),
                ITimerType::Real => unreachable!(),
            };
            let expired = manager.poll_cpu(cpu_advanced);
            assert_eq!(expired.signals().collect::<alloc::vec::Vec<_>>(), [signal]);
            assert!(!expired.publishes_wall_alarm());
        }
    }

    #[test]
    fn scheduler_tick_poll_does_not_consume_the_wall_timer() {
        let mut manager = ProcessTimerManager::new();
        let armed_at = snapshot_at(0, 0, 0);
        let _real = manager.set_itimer(ITimerType::Real, setting(0, 10), armed_at);
        let _virtual = manager.set_itimer(ITimerType::Virtual, setting(0, 10), armed_at);

        let pending = manager.poll_cpu(snapshot_at(10, 0, 10));

        assert_eq!(
            pending.signals().collect::<alloc::vec::Vec<_>>(),
            [Signo::SIGVTALRM]
        );
        assert_eq!(
            manager.active_mask(),
            1 << ITimerType::Real as usize,
            "the wall timer remains owned by its alarm generation"
        );
    }

    #[test]
    fn periodic_timer_coalesces_missed_periods_without_deadline_drift() {
        let mut manager = ProcessTimerManager::new();
        let armed_at = snapshot_at(0, 0, 100);
        let _armed = manager.set_itimer(ITimerType::Real, setting(10, 10), armed_at);

        let late_snapshot = snapshot_at(0, 0, 135);
        let first_poll = manager.poll(late_snapshot);
        let second_poll = manager.poll(late_snapshot);

        assert_eq!(first_poll.signals().collect::<alloc::vec::Vec<_>>(), [Signo::SIGALRM]);
        assert_eq!(second_poll.signals().next(), None);
        assert_eq!(
            manager.get_itimer(ITimerType::Real, late_snapshot).1,
            time_value_from_nanos(5)
        );
    }

    fn setting(interval_ns: u64, remaining_ns: u64) -> ITimerSetting {
        ITimerSetting::new(
            time_value_from_nanos(interval_ns),
            time_value_from_nanos(remaining_ns),
        )
    }

    const fn snapshot_at(
        user_ns: u64,
        system_ns: u64,
        sampled_at_ns: u64,
    ) -> ProcessCpuTimeSnapshot {
        ProcessCpuTimeSnapshot {
            user_ns,
            system_ns,
            sampled_at_ns,
        }
    }
}