40 lines
1.9 KiB
Zig
40 lines
1.9 KiB
Zig
//! crash-test — a test fixture, not a driver: claims the device it is assigned,
|
|
//! hellos the device manager, announces itself, then faults on purpose. The
|
|
//! driver-restart scenario drives the manager's whole restart machinery with
|
|
//! it: fault → exit reason → backoff → respawn → the **same claim succeeding
|
|
//! again** (claim release on death, M17.1, through the manager's path) → the
|
|
//! crash-loop cap. Spawned bare (the initial-ramdisk sweep starts every bundled
|
|
//! binary), it exits silently so it cannot derange other tests.
|
|
|
|
const std = @import("std");
|
|
const runtime = @import("runtime");
|
|
const protocol = runtime.device_manager_protocol;
|
|
|
|
pub fn main(init: runtime.process.Init) void {
|
|
const argument = init.arguments.get(1) orelse return; // bare: stay silent
|
|
const assigned = std.fmt.parseInt(u64, argument, 10) catch return;
|
|
|
|
// The respawn only reaches this line because the kernel released the
|
|
// previous instance's claim at death. A failed claim exits cleanly — the
|
|
// manager reads "meant to stop" and the scenario fails loudly by silence.
|
|
if (!runtime.device.claim(assigned)) {
|
|
_ = runtime.system.write("crash-test: claim failed\n");
|
|
return;
|
|
}
|
|
|
|
var manager: ?runtime.ipc.Handle = null;
|
|
var tries: u32 = 0;
|
|
while (manager == null and tries < 100) : (tries += 1) {
|
|
manager = runtime.ipc.lookup(.device_manager);
|
|
if (manager == null) runtime.system.sleep(20);
|
|
}
|
|
const h = manager orelse return;
|
|
const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.device), .device_id = assigned };
|
|
var reply: [protocol.message_maximum]u8 = undefined;
|
|
_ = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch return;
|
|
|
|
_ = runtime.system.write("crash-test: faulting now\n");
|
|
const poison: *volatile u32 = @ptrFromInt(0xdead0000);
|
|
poison.* = 1; // the restart machinery's fuel: a real segmentation fault
|
|
}
|