fix: ClearAllTimers stops every timer in a slot, not just the first (#2723)
## Summary `Timer.ClearAllTimers` walked each wheel slot with a `do/while` that read `node._nextTimer` but never advanced `node`. `Stop()` unlinks the head from its slot, so the second pass read a null successor from the same, now-detached node and exited. Only the first timer in every slot was stopped; the rest kept running. The loop now reads the successor, stops the node, and advances. Nothing in the repo calls `ClearAllTimers` today, so no running server is affected. It is public API for shards and tests. ## Tests - `TimerTests.ClearAllTimers_StopsEveryTimerInASlot` puts three timers in the same slot, clears them, asserts none is `Running`, and slices past their due time. It fails without the fix. - Server.Tests: all pass.
This commit is contained in:
parent
9a25054809
commit
47f972ec9d
2 changed files with 30 additions and 5 deletions
|
|
@ -85,6 +85,30 @@ public class TimerTests
|
|||
Assert.Equal(2, timerTicks.ExecutedCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClearAllTimers_StopsEveryTimerInASlot()
|
||||
{
|
||||
Timer.Init(0);
|
||||
|
||||
var timers = new Timer[3];
|
||||
for (var i = 0; i < timers.Length; i++)
|
||||
{
|
||||
timers[i] = Timer.DelayCall(TimeSpan.FromMilliseconds(80), () => Assert.Fail("cleared timer fired"));
|
||||
}
|
||||
|
||||
Timer.ClearAllTimers(0);
|
||||
|
||||
for (var i = 0; i < timers.Length; i++)
|
||||
{
|
||||
Assert.False(timers[i].Running);
|
||||
}
|
||||
|
||||
for (var tick = 8; tick <= 160; tick += 8)
|
||||
{
|
||||
Timer.Slice(tick);
|
||||
}
|
||||
}
|
||||
|
||||
private class TimerTicks
|
||||
{
|
||||
public long ExpectedTicks;
|
||||
|
|
|
|||
|
|
@ -321,13 +321,14 @@ public partial class Timer
|
|||
for (var i = 0; i < _ringSize; i++)
|
||||
{
|
||||
var node = t[i];
|
||||
Timer next;
|
||||
|
||||
do
|
||||
while (node != null)
|
||||
{
|
||||
next = node?._nextTimer;
|
||||
node?.Stop();
|
||||
} while (next != null);
|
||||
// Stop() unlinks the node, so read its successor first.
|
||||
var next = node._nextTimer;
|
||||
node.Stop();
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue