Expand description
What keeps a facility thread alive, and what is said when one dies.
Three single-purpose worker threads carry every deferred and timed
operation this runtime offers: the delayed-callback timer
(super::delayed_timer) behind sleep, interval, scan periods and
callbackRequestDelayed; the scanOnce worker (super::scan_once) behind
FLNK and scanOnce; and the callback bands
(super::callback_executor). Each owns a Mutex + Condvar queue and
runs callbacks its callers supplied. Two defects follow from that shape,
and they were the same defect in all three files:
.lock().unwrap()propagates a poisoned mutex. Poison means “a thread panicked while holding this”, not “the data is broken” — these queues are plain collections whose invariants survive a panic — so propagating turns one caller’s panic into the loss of the whole facility.- A caller-supplied callback runs on the facility thread. An unwinding callback therefore unwinds the loop and the thread ends. Nothing announces it: submitters keep enqueueing, the IOC keeps answering CA and PVA, and every timed operation has simply stopped. An operator sees a healthy IOC whose records no longer process.
C reaches neither state: there is no unwinding, and callbackTask
(callback.c:210-235) cannot be ended by the callback it invoked.
On a target built with panic = "abort" the two catch_unwinds here never
catch and the process aborts instead. That is a different outcome but not a
silent one, which is the property being defended.
Functions§
- recover
- Take a lock whose data outlives a panic — the only lock accessor these facilities use.
- run_
isolated - Run one caller-supplied callback on a facility thread so that a panic inside it costs that callback and nothing else.