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 {
58
            set migrations[hart as u32] = current.hart + 1;
59
        }
60
    }
61
}
62
63
/// Start an additional context with its physical hart index in validated memory.
64
export fn worker(args: *u64, size: u64) {
65
    assert size == 8;
66
    run(*args);
67
}
68
69
/// The initial context owns hart zero's window.
70
@default fn main(env: *opaque) {
71
    if idle <> 0 {
72
        set wakeState = 2;
73
        sys::wait();
74
        set wakeState = 3;
75
        while wakeState <> 4 {
76
        }
77
        set wakeState = 5;
78
        sys::wait();
79
        set wakeState = 6;
80
        while wakeState <> 7 {
81
        }
82
        set wakeState = 8;
83
        sys::wait();
84
        set wakeState = 9;
85
        while wakeState <> 10 {
86
        }
87
        set wakeState = 11;
88
        let allocation = try! sys::pageAllocate(abi::Handle(0), 4096);
89
        set wakeState = 12;
90
        while true {
91
        }
92
    }
93
    run(0);
94
}