starry-kernel 0.10.1

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

    #[test]
    fn rearming_physically_replaces_the_previous_alarm_node() {
        let slot = AlarmSlot::new();
        let mut queue = AlarmQueue::new();
        let first = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(10))));
        let second = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(20))));

        let AlarmChange::Schedule {
            deadline: first_deadline,
            token: first_token,
        } = first
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        queue.schedule(first_deadline, first_token, ());
        let AlarmChange::Schedule {
            deadline: second_deadline,
            token: second_token,
        } = second
        else {
            unreachable!("rearmed slot must produce a schedule action")
        };
        queue.schedule(second_deadline, second_token, ());

        assert_eq!(queue.entries.len(), 1);
        assert!(
            matches!(queue.next_action(ClockSnapshot::new(Duration::ZERO, Duration::ZERO)), AlarmQueueAction::Wait(deadline) if deadline == Duration::from_nanos(20))
        );
    }

    #[test]
    fn stale_generation_cannot_replace_the_current_alarm() {
        let slot = AlarmSlot::new();
        let mut queue = AlarmQueue::new();
        let stale = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(10))));
        let current = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(20))));

        let AlarmChange::Schedule {
            deadline: current_deadline,
            token: current_token,
        } = current
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        queue.schedule(current_deadline, current_token, ());
        let AlarmChange::Schedule {
            deadline: stale_deadline,
            token: stale_token,
        } = stale
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        queue.schedule(stale_deadline, stale_token, ());

        assert_eq!(queue.entries.len(), 1);
        assert!(
            matches!(queue.next_action(ClockSnapshot::new(Duration::ZERO, Duration::ZERO)), AlarmQueueAction::Wait(deadline) if deadline == Duration::from_nanos(20))
        );
    }

    #[test]
    fn disarming_physically_removes_the_alarm_node() {
        let slot = AlarmSlot::new();
        let mut queue = AlarmQueue::new();
        let schedule = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(10))));
        let AlarmChange::Schedule {
            deadline: deadline,
            token,
        } = schedule
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        queue.schedule(deadline, token, ());

        let cancellation = slot.replace(None);
        let AlarmChange::Cancel(cancellation_token) = cancellation else {
            unreachable!("disarmed slot must produce a cancellation")
        };
        queue.cancel(&cancellation_token);

        assert!(queue.is_empty());
    }

    #[test]
    fn stale_cancellation_does_not_remove_a_newer_alarm_generation() {
        let slot = AlarmSlot::new();
        let mut queue = AlarmQueue::new();
        let stale_schedule = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(10))));
        let AlarmChange::Schedule {
            deadline: stale_deadline,
            token: stale_token,
        } = stale_schedule
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        queue.schedule(stale_deadline, stale_token, ());

        // Delay the cancellation until a concurrent rearm has already
        // published and installed a newer generation.
        let stale_cancellation = slot.replace(None);
        let current_schedule =
            slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(20))));
        let AlarmChange::Schedule {
            deadline: current_deadline,
            token: current_token,
        } = current_schedule
        else {
            unreachable!("rearmed slot must produce a schedule action")
        };
        queue.schedule(current_deadline, current_token, ());

        let AlarmChange::Cancel(cancellation_token) = stale_cancellation else {
            unreachable!("disarmed slot must produce a cancellation")
        };
        queue.cancel(&cancellation_token);

        assert_eq!(queue.entries.len(), 1);
        assert!(
            matches!(queue.next_action(ClockSnapshot::new(Duration::ZERO, Duration::ZERO)), AlarmQueueAction::Wait(deadline) if deadline == Duration::from_nanos(20))
        );
    }

    #[test]
    fn pruning_a_stale_due_node_reclassifies_the_new_future_head() {
        let stale_slot = AlarmSlot::new();
        let future_slot = AlarmSlot::new();
        let mut queue = AlarmQueue::new();
        let stale = stale_slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(10))));
        let future = future_slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(20))));
        let AlarmChange::Schedule {
            deadline: stale_deadline,
            token: stale_token,
        } = stale
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        let AlarmChange::Schedule {
            deadline: future_deadline,
            token: future_token,
        } = future
        else {
            unreachable!("armed slot must produce a schedule action")
        };
        queue.schedule(stale_deadline, stale_token, ());
        queue.schedule(future_deadline, future_token, ());

        // Publish cancellation without applying the queue removal yet. This
        // is the exact race where the worker observes a stale due head.
        let _pending_cancellation = stale_slot.replace(None);

        assert!(matches!(
            queue.next_action(ClockSnapshot::new(Duration::from_nanos(15), Duration::ZERO)),
            AlarmQueueAction::Wait(deadline) if deadline == Duration::from_nanos(20)
        ));
        assert_eq!(queue.entries.len(), 1);
    }

    #[test]
    fn alarm_worker_does_not_absorb_a_publish_during_its_queue_snapshot() {
        let epoch = AtomicU64::new(0);
        let snapshot = take_alarm_worker_snapshot(&epoch, || {
            epoch.fetch_add(1, Ordering::AcqRel);
            AlarmAction::AwaitNewTimer
        });

        assert_ne!(
            epoch.load(Ordering::Acquire),
            snapshot.epoch,
            "a queue update racing the snapshot must make the worker's wait predicate true",
        );
    }
}

#[cfg(axtest)]
pub(super) fn stale_alarm_cancellation_preserves_new_generation_for_test() -> bool {
    let slot = AlarmSlot::new();
    let mut queue = AlarmQueue::new();
    let stale_schedule = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(10))));
    let AlarmChange::Schedule {
        deadline: stale_deadline,
        token: stale_token,
    } = stale_schedule
    else {
        return false;
    };
    queue.schedule(stale_deadline, stale_token, ());

    let stale_cancellation = slot.replace(None);
    let current_schedule = slot.replace(Some(ClockDeadline::Monotonic(Duration::from_nanos(20))));
    let AlarmChange::Schedule {
        deadline: current_deadline,
        token: current_token,
    } = current_schedule
    else {
        return false;
    };
    queue.schedule(current_deadline, current_token, ());

    let AlarmChange::Cancel(cancellation_token) = stale_cancellation else {
        return false;
    };
    queue.cancel(&cancellation_token);

    queue.entries.len() == 1
        && matches!(queue.next_action(ClockSnapshot::new(Duration::ZERO, Duration::ZERO)), AlarmQueueAction::Wait(deadline) if deadline == Duration::from_nanos(20))
}