From d6a2e595c8ca58b9552befbdc18773189a0453ae Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 29 Jul 2026 08:56:17 +0200 Subject: [PATCH] fix(diag): probe-owned inbound depth counter - SingleReader channels have no Count The first armed ACDREAM_PROBE_NET launch died at exit 4 one second into the world: the [net-tick] line read _inboundQueue.Reader.Count, but the queue is built with SingleReader=true and that channel implementation throws NotSupportedException from Count. The net thread now increments and the frame thread decrements a probe-owned Interlocked counter instead; behavior with the probe off is untouched. Co-Authored-By: Claude Fable 5 --- src/AcDream.Core.Net/WorldSession.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/AcDream.Core.Net/WorldSession.cs b/src/AcDream.Core.Net/WorldSession.cs index f3109efd..3048b887 100644 --- a/src/AcDream.Core.Net/WorldSession.cs +++ b/src/AcDream.Core.Net/WorldSession.cs @@ -995,6 +995,8 @@ public sealed class WorldSession : IDisposable while (_inboundQueue.Reader.TryRead( out PooledInboundDatagram datagram)) { + if (NetDiagnostics.ProbeNet) + Interlocked.Decrement(ref _probeInboundDepth); try { ProcessDatagram(datagram.Memory); @@ -1034,6 +1036,10 @@ public sealed class WorldSession : IDisposable private int _probeBudgetBreaks; private int _probeSendWindow; private int _probeAckWindow; + // Probe-owned queue depth: the SingleReader channel's Reader.Count + // throws NotSupportedException, so the net thread increments on + // enqueue and the frame thread decrements on dequeue instead. + private int _probeInboundDepth; /// /// #260 probe: accumulate per-Tick cadence facts and emit one @@ -1067,7 +1073,7 @@ public sealed class WorldSession : IDisposable int acks = Interlocked.Exchange(ref _probeAckWindow, 0); Console.WriteLine( $"[net-tick] in/s={_probeProcessedWindow / windowSeconds:F0}" - + $" q={_inboundQueue.Reader.Count}" + + $" q={Volatile.Read(ref _probeInboundDepth)}" + $" budget-breaks={_probeBudgetBreaks}" + $" maxgap={maxGapMs:F0}ms" + $" out/s={sends / windowSeconds:F0}" @@ -1145,6 +1151,8 @@ public sealed class WorldSession : IDisposable new PooledInboundDatagram( queuedBuffer, result.Length)); + if (ownershipTransferred && NetDiagnostics.ProbeNet) + Interlocked.Increment(ref _probeInboundDepth); } catch (System.Net.Sockets.SocketException ex) {