Files
UA-.NETStandard/Stack
Marc Schier d0ef235286 RetryBudget: swap Reset() write order to avoid stale-tick race
Previous Reset():
  Volatile.Write(ref m_started, 0);
  Interlocked.Exchange(ref m_startTicks, kNotStarted);

A concurrent EnsureStarted() observer could see m_started == 0 (taking
the "reset, so go start" branch), then read the stale m_startTicks
value BEFORE the Interlocked.Exchange landed, and treat the budget as
already-started against the pre-reset timestamp. IsExhausted /
TryConsume then computed elapsed time from the old origin.

Fix: reset m_startTicks first, then m_started. EnsureStarted writes
m_started = 1 only after the CAS on m_startTicks succeeds, so
resetting m_startTicks first preserves that invariant — no observer
can see "started == 1" with a stale tick value.
2026-06-11 09:56:06 +02:00
..