code wiki / (root) / nx_progress_watchdog.nx

nx_progress_watchdog.nx source

↩ module page · 65 lines · 2332 B

1// nx_progress_watchdog.nx -- detects stalled phases in long ingest runs. 2// 3// A heartbeat-based liveness monitor: caller heartbeats at progress 4// points; check() reports STALLED if too much wall-clock has elapsed 5// since the last heartbeat. Lightweight: zero syscalls per heartbeat 6// (just stores the timestamp); one clock read per check. 7// 8// genealogy_id: ibm_360_watchdog_timer + os_softdog_1990s 9// lineage_id: liveness_monitor 10 11// nx_safety_envelope: 12// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 13// sil_target: SIL1 14// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 15// verdict: NOT_YET_EVALUATED 16 17import "nx_syscalls.nx" 18import "nx_tier.nx" 19import "nx_clock.nx" 20 21const NX_WATCHDOG_OK: nx_int = 0 22const NX_WATCHDOG_STALLED: nx_int = 1 23 24struct NxWatchdog { 25 stall_timeout_ns: nx_int, 26 last_beat_ns: nx_int, 27 n_heartbeats: nx_int, 28 n_stalls_detected: nx_int, 29} 30 31func nx_progress_watchdog_new(stall_timeout_ms: nx_int) -> *NxWatchdog { 32 let raw: *nx_byte = sys_mmap(NX_BUF_TINY) 33 let w: *NxWatchdog = raw as *NxWatchdog 34 w.stall_timeout_ns = stall_timeout_ms * NX_NS_PER_MS 35 w.last_beat_ns = nx_clock_monotonic_ns() 36 w.n_heartbeats = 0 37 w.n_stalls_detected = 0 38 return w 39} 40 41func nx_progress_watchdog_heartbeat(w: *NxWatchdog) -> nx_int { 42 w.last_beat_ns = nx_clock_monotonic_ns() 43 w.n_heartbeats = w.n_heartbeats + 1 44 return 0 45} 46 47func nx_progress_watchdog_check(w: *NxWatchdog) -> nx_int { 48 let now_ns: nx_int = nx_clock_monotonic_ns() 49 let elapsed_ns: nx_int = now_ns - w.last_beat_ns 50 if elapsed_ns > w.stall_timeout_ns { 51 w.n_stalls_detected = w.n_stalls_detected + 1 52 return NX_WATCHDOG_STALLED 53 } 54 return NX_WATCHDOG_OK 55} 56 57func nx_progress_watchdog_elapsed_ms(w: *NxWatchdog) -> nx_int { 58 let now_ns: nx_int = nx_clock_monotonic_ns() 59 let dt_ns: nx_int = now_ns - w.last_beat_ns 60 return dt_ns / NX_NS_PER_MS 61} 62 63func nx_progress_watchdog_n_heartbeats(w: *NxWatchdog) -> nx_int { return w.n_heartbeats } 64func nx_progress_watchdog_n_stalls(w: *NxWatchdog) -> nx_int { return w.n_stalls_detected } 65func nx_progress_watchdog_stall_timeout_ms(w: *NxWatchdog) -> nx_int { return w.stall_timeout_ns / NX_NS_PER_MS }