test/smp/spin.rad 3.2 KiB raw
1
//! Concurrent user contexts with shared private state and separate call buffers.
2
export mod abi;
3
export mod sys;
4
5
/// Completed allocation transactions, indexed by the executing hart.
6
export static count: [u64; 8] = [0; 8];
7
8
/// Future budget handles assigned to callers on the preceding online hart.
9
export static windows: [u64; 8] = [0; 8];
10
11
/// Capability used to notify the shared domain from each online hart.
12
export static notification: u64 = 0;
13
14
/// Shared-domain capability for the injected physical interrupt source.
15
export static interrupt: u64 = 0;
16
17
/// Observed destination hart plus one after each context changes budget.
18
export static migrations: [u64; 8] = [0; 8];
19
20
/// Progress shared with the machine fixture for waits and interrupted allocation.
21
export static wakeState: u64 = 0;
22
23
/// Nonzero selects the independently activated idle-wakeup context.
24
export static idle: u64 = 0;
25
26
/// Check hart identity and shared-table allocation through repeated direct calls.
27
fn run(hart: u64) {
28
    let source = sys::queryInterrupt(abi::Handle(interrupt));
29
    assert source.number == 7;
30
    let original = sys::currentContext();
31
    assert original.hart == hart;
32
    let budget = abi::Handle(windows[hart as u32]);
33
    let before = try! sys::queryBudget(budget);
34
    let right = try! sys::budgetSplit(budget, before.start + 1000);
35
    let leftInfo = try! sys::queryBudget(budget);
36
    let rightInfo = try! sys::queryBudget(right);
37
    assert leftInfo.start == before.start and leftInfo.end == rightInfo.start;
38
    assert rightInfo.end == before.end and rightInfo.hart == before.hart;
39
    let merged = try! sys::budgetMerge(budget, right);
40
    assert merged == budget;
41
    let after = try! sys::queryBudget(merged);
42
    assert after.start == before.start and after.end == before.end;
43
    try! sys::capabilityDrop(merged);
44
    try! sys::wakeup(abi::Handle(notification), hart as u32);
45
    for i in 0..16 {
46
        let page = try! sys::pageAllocate(abi::Handle(0), 1);
47
        let info = sys::queryPage(page);
48
        assert info.count == 1 and info.base <> 0;
49
        try! sys::capabilityDrop(page);
50
        let current = sys::currentContext();
51
        assert current.context == original.context and current.hart == hart;
52
        set count[hart as u32] += 1;
53
    }
54
    while true {
55
        let current = sys::currentContext();
56
        assert current.context == original.context;
57
        if current.budget <> original.budget { set migrations[hart as u32] = current.hart + 1; }
58
    }
59
}
60
61
/// Start an additional context with its physical hart index in validated memory.
62
export fn worker(args: *u64, size: u64) {
63
    assert size == 8;
64
    run(*args);
65
}
66
67
/// The initial context owns hart zero's window.
68
@default fn main(env: *opaque) {
69
    if idle <> 0 {
70
        set wakeState = 2;
71
        sys::wait();
72
        set wakeState = 3;
73
        while wakeState <> 4 {}
74
        set wakeState = 5;
75
        sys::wait();
76
        set wakeState = 6;
77
        while wakeState <> 7 {}
78
        set wakeState = 8;
79
        sys::wait();
80
        set wakeState = 9;
81
        while wakeState <> 10 {}
82
        set wakeState = 11;
83
        let allocation = try! sys::pageAllocate(abi::Handle(0), 4096);
84
        set wakeState = 12;
85
        while true {}
86
    }
87
    run(0);
88
}