//! 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
}
