nx_supervisor.nx
buildroot/runtime/nx_supervisor.nx
about
nx_supervisor.nx -- Erlang-OTP-style restart-policy state machine.
Closes the SSS-class "subsystem restart gap" named in
NISHI_HONEST_TRADE_OFFS.md row 2 + NISHI_PREEMPTIVE_BUG_ABSORPTION.md.
Per cardinal user-owns-every-bit: this is a STATE MACHINE primitive.
The substrate doesn't fork or exec anything -- caller does the
actual process management. Supervisor returns "what action to
take now"; caller obeys.
Substrate's structural prevention of three known supervisor anti-
patterns:
1. Restart storms: max_restarts counter -> ESCALATE once exceeded
(don't burn CPU on infinite crash-restart loop)
2. Split-brain restarts: caller is single-supervisor-per-child;
sealed enum state means "is this child being restarted right
now or not" is unambiguous
3. State-loss across restart: snapshot-before-mark via
nx_module_cas integration (queued v2; v1 is stateless)
Exponential backoff (RFC 7234-class):
1st crash: base_backoff_ms wait
2nd: 2 * base wait
3rd: 4 * base wait
Nth: min(2^(N-1) * base, max_backoff_ms)
Healthy-window reset:
if (now - last_restart_ms) > healthy_threshold_ms, counter
resets to 0. Per Erlang OTP: a child that's been up long
enough has "recovered" and the next crash isn't part of the
crash storm.
Sealed enum: NxSupState (4 states):
HEALTHY child running normally (or never-started)
BACKING_OFF child crashed; waiting for backoff_ms before restart
ESCALATING exceeded max_restarts; parent supervisor should take over
TERMINATED explicit stop; no further restart
Sealed enum: NxSupAction (4 decisions):
ACTION_NONE child healthy, no action needed
dependencies 1 imports · 2 importers
imports: nx_syscalls_x86_64.nx
imported by: nx_proc_spawn.nxnx_supervisor_test.nx
structs
| 105 | struct NxSupervisor |
consts
| 61 | const NX_SUP_HEALTHY: i64 = 0 |
| 62 | const NX_SUP_BACKING_OFF: i64 = 1 |
| 63 | const NX_SUP_ESCALATING: i64 = 2 |
| 64 | const NX_SUP_TERMINATED: i64 = 3 |
| 65 | const NX_SUP_STATE_N: i64 = 4 |
| 83 | const NX_SUP_ACTION_NONE: i64 = 0 |
| 84 | const NX_SUP_ACTION_RESTART: i64 = 1 |
| 85 | const NX_SUP_ACTION_WAIT: i64 = 2 |
| 86 | const NX_SUP_ACTION_ESCALATE: i64 = 3 |
| 87 | const NX_SUP_ACTION_N: i64 = 4 |
| 121 | const NX_SUPERVISOR_BYTES: i64 = 80 // 10 i64 fields |
functions
| 67 | func nx_supervisor_state_is_valid(s: i64) -> i64 called by 1: main |
| 73 | func nx_supervisor_state_name(s: i64) -> *u8 called by 1: main |
| 89 | func nx_supervisor_action_is_valid(a: i64) -> i64 called by 1: main |
| 95 | func nx_supervisor_action_name(a: i64) -> *u8 called by 1: main |
| 127 | func nx_supervisor_init(sup: *NxSupervisor, called by 1: main |
| 155 | func nx_supervisor_backoff_ms(sup: *NxSupervisor) -> i64 |
| 175 | func nx_supervisor_record_crash(sup: *NxSupervisor, now_ms: i64) -> i64 |
| 203 | func nx_supervisor_record_start(sup: *NxSupervisor, now_ms: i64) -> i64 called by 1: main |
| 215 | func nx_supervisor_terminate(sup: *NxSupervisor) -> i64 called by 1: main |
| 227 | func nx_supervisor_decide(sup: *NxSupervisor, |
| 262 | func nx_supervisor_state(sup: *NxSupervisor) -> i64 called by 1: main |
| 267 | func nx_supervisor_n_restarts(sup: *NxSupervisor) -> i64 called by 1: main |
| 272 | func nx_supervisor_n_escalations(sup: *NxSupervisor) -> i64 called by 1: main |