compiler/
kernel/
lib/
scripts/
seed/
sublime/
test/
acceptance/
boot/
bootstrap/
cycles/
dispatch/
loader/
mmio/
modules/
native/
packages/
pages/
runtime/
scheduling/
kernel/
dispatchcheck.rad
2.7 KiB
machine.ras
274 B
run
1.3 KiB
shared/
slots/
smp/
sync/
termination/
tests/
trap/
run
2.7 KiB
runner.rad
10.3 KiB
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
10.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
551 B
test/scheduling/kernel/dispatchcheck.rad
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 | } |