From 7d0c2291b1780eda74b4e3d18bdd50eb4d517d13 Mon Sep 17 00:00:00 2001 From: zzstoatzz Date: Mon, 3 Aug 2026 08:49:57 -0500 Subject: [PATCH] broadcaster: saturate the queue-full spin counter full_spins is a u32 diagnostic incremented in the push spin loop. When the broadcaster stops draining, a frame worker spins on it indefinitely and it overflows, panicking under ReleaseSafe -- so 'consumers are slow' becomes a crashed relay. Hit this on the zio backend, where a stalled drain kept the queue full: thread 9702 panic: integer overflow broadcaster.zig:371 in push frame_worker.zig:314 in processFrame Saturating add. The stall itself is a separate bug; a diagnostic counter should never be the thing that takes the process down. 107 pass, 1 skip. Co-Authored-By: Claude Opus 5 (1M context) --- src/internal/broadcaster.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/internal/broadcaster.zig b/src/internal/broadcaster.zig index 69fc47d..d3d029a 100644 --- a/src/internal/broadcaster.zig +++ b/src/internal/broadcaster.zig @@ -350,7 +350,11 @@ pub const BroadcastQueue = struct { if (next_tail == self.head.load(.acquire)) { // full — release lock, yield, retry self.push_lock.store(0, .release); - full_spins += 1; + // saturate: this is a diagnostic counter, and the queue staying + // full is exactly when it must not take the process down. a + // stalled drain spun this past 2^32 and panicked the worker + // under ReleaseSafe, turning "consumers are slow" into a crash. + full_spins +|= 1; std.atomic.spinLoopHint(); continue; } -- 2.51.2