test/cycles/spin.rad 3.7 KiB raw
1
//! Concurrent load, spawn, yield, fault, and teardown cycles.
2
use support;
3
export mod abi;
4
export mod sys;
5
export mod mmio;
6
7
/// Ordered shared-memory access boundary for the single event consumer.
8
@intrinsic fn memoryFence();
9
10
/// Controller resources and retained completion metadata.
11
record Arguments: Copy {
12
    /// Readable binary worker package.
13
    source: abi::Handle,
14
    /// Exact package byte length.
15
    length: u64,
16
    /// Read-only clock capability.
17
    clock: abi::Handle,
18
    /// Page that owns this argument record.
19
    page: abi::Handle,
20
    /// Reserved worker interval in clock ticks.
21
    quantum: u64,
22
    /// Shared worker code base reported to the checker.
23
    codeBase: u64,
24
    /// Number of fully checked worker lifetimes.
25
    completed: u64,
26
}
27
28
/// Published event wire record.
29
record Event: Copy {
30
    /// Notification kind.
31
    kind: u16,
32
    /// Reserved zero bits.
33
    reserved: u16,
34
    /// Terminal status or fault code.
35
    code: u32,
36
    /// Generation-bearing child identity.
37
    value: u64,
38
}
39
40
/// Shared single-consumer event ring.
41
record Ring: Copy {
42
    /// Published event slots.
43
    data: [Event; 256],
44
    /// Consumer progress.
45
    head: u32,
46
    /// Producer progress.
47
    tail: u32,
48
    /// Ring index mask.
49
    mask: u32,
50
}
51
52
/// Kernel startup pointers for one controller.
53
record Env: Copy {
54
    /// Writable arguments retained by the parent.
55
    argsPointer: *unsafe mut Arguments,
56
    /// Argument record byte size.
57
    argsSize: u64,
58
    /// Installed event capability.
59
    eventsHandle: u64,
60
    /// Shared event-ring pointer.
61
    eventsPointer: *unsafe mut Ring,
62
}
63
64
/// Repeat publication lookup and private worker lifetimes on this hart.
65
@default unsafe fn main(env: *Env) {
66
    assert env.argsSize == @sizeOf(Arguments) as u64;
67
    let mut args = env.argsPointer;
68
    let initial = sys::currentContext();
69
    for turn in 0..4 {
70
        assert support::advance() == turn as u64 + 1;
71
        let mut image = abi::Handle(0);
72
        while image == abi::Handle(0) {
73
            set image = try sys::imageLoad(abi::Handle(0), args.source, 0, args.length) catch error {
74
                assert error == abi::Error::Busy;
75
                continue;
76
            };
77
        }
78
        let loaded = try! sys::queryImage(image);
79
        if turn == 0 { set args.codeBase = loaded.codeBase; }
80
        assert loaded.codeBase == args.codeBase;
81
        let child = try! sys::domainCreate(abi::Handle(0), image);
82
        let identity = sys::queryDomain(child).id;
83
        let stack = try! sys::pageAllocate(abi::Handle(0), 4);
84
        let extent = sys::queryPage(stack);
85
        let moved = try! sys::capabilityTransfer(stack, child, abi::RIGHTS_MASK as u64);
86
        let shared = try! sys::capabilityGrant(args.page, child, abi::READ as u64);
87
        try! sys::domainActivate(child, extent.base + extent.count * 4096, args as *unsafe opaque, (turn % 2) as u64);
88
        let current = sys::currentContext();
89
        assert current.context == initial.context and current.hart == initial.hart;
90
        let later = try! sys::budgetSplit(abi::Handle(current.budget), mmio::read64(args.clock, 0) + args.quantum);
91
        try! sys::yield(child);
92
        assert sys::currentContext().budget == *later;
93
        let mut ring = env.eventsPointer;
94
        let head = ring.head;
95
        let tail = ring.tail;
96
        memoryFence();
97
        assert head <> tail and ring.mask == 255;
98
        let event = ring.data[head & ring.mask];
99
        assert event.value == identity and event.reserved == 0;
100
        if turn % 2 == 0 { assert event.kind == 4 and event.code == 9; }
101
        else { assert event.kind == 3 and event.code == 3; }
102
        memoryFence();
103
        set ring.head = head + 1;
104
        try! sys::capabilityDrop(image);
105
        set args.completed = turn as u64 + 1;
106
    }
107
    sys::exit(68);
108
}