Record and expose how every process ends (M17.2)

The kernel records an ExitReason at all three death sites — clean exit,
fault (classified by vector), and process_kill — into a bounded ring
before the exit notification posts, so a supervisor's query never races
the notice. process_exit_reason is gated by the same supervisor check as
kill; runtime.process.exitReason is the stable interface. This is the
input restart policy reads (docs/process-lifecycle.md iron rule 2).
This commit is contained in:
Daniel Samson
2026-07-12 23:34:09 +01:00
parent 888eaa74e1
commit 2ebfb0c3b0
10 changed files with 162 additions and 19 deletions
+18
View File
@@ -53,9 +53,27 @@ pub const SystemCall = enum(u64) {
process_enumerate = 24, // process_enumerate(buffer, maximum) -> total: snapshot the task table
process_kill = 25, // process_kill(id) -> 0/-errno: end a process this process spawned
ipc_send = 26, // ipc_send(handle, message_ptr, message_len) -> 0/-errno: post a payload to an endpoint's async queue without blocking
process_exit_reason = 27, // process_exit_reason(id) -> ExitReason/-errno: how a dead child ended (its supervisor only)
_,
};
/// How a process ended — recorded by the kernel at death, queried by the
/// supervisor with `process_exit_reason`, and the input to its restart decision
/// (docs/process-lifecycle.md): a clean exit meant to stop, a fault wants a
/// restart with backoff, killed means the supervisor did it itself. The faults
/// mirror the CPU exceptions a ring-3 process can die of; they are exit reasons,
/// never delivered to the faulting process (recovery is restart, not a handler).
pub const ExitReason = enum(u8) {
exited = 0, // returned from main / called exit
aborted = 1, // deliberate self-termination (reserved: no abort path yet)
segmentation_fault = 2, // page fault
illegal_instruction = 3, // invalid opcode
arithmetic_fault = 4, // divide error, x87 or SIMD fault
protection_fault = 5, // general protection fault
fault = 6, // any other CPU exception
killed = 7, // process_kill
};
/// The x86 MSI message address base (`0xFEE0_0000`): a device raises an MSI by writing
/// `data` to this address, which the Local APIC turns into an interrupt at the vector
/// in `data`. The kernel returns the concrete (address, data) from `msi_bind`; this is