starry-kernel 0.10.2

A Linux-compatible OS kernel built on ArceOS unikernel
Documentation
extern crate alloc;

use alloc::sync::Arc;
use core::{
    any::Any,
    sync::atomic::{AtomicBool, Ordering},
};

#[path = "../src/perf/output.rs"]
mod output;

use output::{PerfOutputRoute, PerfOutputScope, PerfRingOutput, validate_output_redirect};

struct DropProbe(Arc<AtomicBool>);

impl Drop for DropProbe {
    fn drop(&mut self) {
        self.0.store(true, Ordering::Release);
    }
}

#[test]
fn output_snapshot_pins_ring_until_the_writer_finishes() {
    let dropped = Arc::new(AtomicBool::new(false));
    let owner = Arc::new(DropProbe(Arc::clone(&dropped)));
    let anchor: Arc<dyn Any + Send + Sync> = owner.clone();
    let output = PerfRingOutput::new(0x1000, 0x2000, anchor);

    drop(owner);
    assert!(
        !dropped.load(Ordering::Acquire),
        "an output snapshot must retain the ring after fd/task teardown"
    );
    assert_eq!(output.ring_vaddr(), 0x1000);
    assert_eq!(output.ring_len(), 0x2000);

    let mapping_anchor = output.mapping_anchor();
    drop(output);
    assert!(
        !dropped.load(Ordering::Acquire),
        "the VMA anchor must retain the complete output snapshot"
    );
    drop(mapping_anchor);
    assert!(dropped.load(Ordering::Acquire));
}

#[test]
fn cloned_outputs_share_one_bounded_writer_gate() {
    let anchor: Arc<dyn Any + Send + Sync> = Arc::new(());
    let output = PerfRingOutput::new(0x3000, 0x4000, anchor);
    let clone = output.clone();

    let writer = output
        .try_begin_write()
        .expect("the first producer must acquire the output");
    assert!(
        clone.try_begin_write().is_none(),
        "an IRQ producer must drop instead of racing or waiting for another CPU"
    );
    clone.record_contention_drop();
    assert_eq!(clone.contention_drops(), 1);
    drop(writer);
    assert!(
        clone.try_begin_write().is_some(),
        "releasing one snapshot must publish the shared ring to every producer"
    );
}

#[test]
fn detach_restores_the_events_own_ring() {
    let own = PerfRingOutput::new(0x5000, 0x2000, Arc::new(()));
    let redirected = PerfRingOutput::new(0x9000, 0x2000, Arc::new(()));
    let mut route = PerfOutputRoute::new();
    route.publish_owned(&own);
    route.redirect(redirected.clone());

    let (selected, is_redirected) = route.effective().unwrap();
    assert!(is_redirected);
    assert_eq!(selected.ring_vaddr(), redirected.ring_vaddr());

    route.detach();
    let (selected, is_redirected) = route.effective().unwrap();
    assert!(!is_redirected);
    assert_eq!(selected.ring_vaddr(), own.ring_vaddr());

    route.clear();
    assert!(route.effective().is_none());
}

#[test]
fn output_redirect_requires_distinct_events_in_one_owner_context() {
    let task = PerfOutputScope::Task(0x1_0000_0007);
    let other_task = PerfOutputScope::Task(0x2_0000_0007);
    let cpu = PerfOutputScope::Cpu(1);

    assert!(validate_output_redirect(10, 11, task, task).is_ok());
    assert!(validate_output_redirect(10, 10, task, task).is_err());
    assert!(validate_output_redirect(10, 11, task, other_task).is_err());
    assert!(validate_output_redirect(10, 11, task, cpu).is_err());
}