diff --git a/src/runtime.rs b/src/runtime.rs index 5200001..41ae326 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -2056,6 +2056,22 @@ fn shutdown_forest_roots(inner: &Arc, root: Pid) { if pid == root { continue; } + // Lock-free reject first. The slab is `max_actors` entries (16_384 by + // default) and is almost entirely vacant at root exit, so locking every + // slot's `cold` to discover `actor == None` made this scan cost one + // uncontended mutex round-trip per slot — a fixed ~150 µs per run on a + // 5900X, and `general.rs` times `init` + `run` together, so it landed + // in every smarm bench number. A non-Live slot has no actor to shut + // down, and the lock is taken again below for the ones that do. + // + // This does not weaken the sweep. `is_live_for` is a snapshot, so a + // slot can go Live just after we pass it — but that was already true + // of a spawn landing after the scan finished, and there is no second + // sweep either way (an actor that outlives this scan is its spawner's + // business, per the rule below). + if !slot.is_live_for(pid) { + continue; + } // Read the parent under the cold lock (generation-verified); act // outside it — `request_shutdown_inner` sends and may unpark. let parent = {