test/scheduling/kernel/dispatchcheck.rad 2.7 KiB raw
1
//! Observe user-space bootstrap and scheduling at the trap boundary.
2
use kernel::abi;
3
use std::lang::il;
4
use kernel::trap;
5
use kernel::dispatch;
6
use kernel::domains;
7
use kernel::budgets;
8
use kernel::events;
9
use kernel::sync;
10
11
/// Root has requested normal termination.
12
static ROOT_EXITED: bool = false;
13
/// Workers that returned after root released its authority.
14
static WORKERS: u32 = 0;
15
/// Write one byte to the test UART.
16
fn put(value: u8);
17
/// Most recent user operation for fault diagnosis.
18
static LAST_CALL: u64 = 0;
19
20
/// Print a complete hexadecimal diagnostic word.
21
fn number(value: u64) {
22
    let digits = "0123456789abcdef";
23
    for i in 0..16 { put(digits[((value >> ((15 - i) as u64 * 4)) & 15) as u32]); }
24
    put(10);
25
}
26
27
/// Check terminal calls without changing user-domain resources or execution.
28
export unsafe fn observe(frame: &trap::Frame) {
29
    if not trap::fromUser(frame) { return; }
30
    let cause = trap::classify(frame.cause);
31
    if cause == trap::Cause::Timer or cause == trap::Cause::Software or cause == trap::Cause::External { return; }
32
    if cause <> trap::Cause::UserCall {
33
        number(frame.cause); number(frame.pc); number(LAST_CALL); number(WORKERS as u64);
34
        assert false;
35
    }
36
    set LAST_CALL = frame.registers[17];
37
    assert frame.registers[17] <> abi::Operation::Abort as u64;
38
    let shutdown = frame.registers[17] == il::DEVICE_ACCESS as u64 and frame.registers[12] == 0x104;
39
    if frame.registers[17] <> abi::Operation::Exit as u64 and not shutdown { return; }
40
    let current = dispatch::current();
41
    let context = abi::reference(current.context);
42
    let guard = sync::enter();
43
    let owner = domains::STORE.contexts[context.index].owner;
44
    if owner.index == 0 {
45
        assert frame.registers[10] == 0;
46
        set ROOT_EXITED = true;
47
    } else if owner.index == 1 {
48
        assert ROOT_EXITED and WORKERS == 4 and shutdown and frame.registers[13] == 0x5555;
49
        let scheduler = try! domains::get(&domains::STORE, owner);
50
        assert scheduler.parent == nil;
51
        let ring = &scheduler.memory.ring;
52
        assert ring.tail - ring.head == 5;
53
        assert ring.data[ring.head & ring.mask].kind == events::CHILD_EXIT;
54
        assert ring.data[ring.head & ring.mask].code == 0;
55
        for i in 1..5 {
56
            let event = ring.data[(ring.head + i) & ring.mask];
57
            assert event.kind == events::CHILD_EXIT and event.code == 7;
58
        }
59
        let future = try! budgets::query(&budgets::STORE, &scheduler.memory.table, abi::Handle(current.budget));
60
        assert future.end > dispatch::clock();
61
        sync::leave(guard);
62
        return;
63
    } else {
64
        assert ROOT_EXITED and frame.registers[10] == 7;
65
        set WORKERS += 1;
66
    }
67
    sync::leave(guard);
68
}