From b675fcb0bb3e3b2ccd209a1d2dfbd9a00079ec37 Mon Sep 17 00:00:00 2001 From: Matthew Edwards Date: Fri, 12 May 2023 21:03:14 -0700 Subject: [PATCH] Fix race condition on 'now' when creating a timer --- clock.go | 6 ++++-- clock_test.go | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/clock.go b/clock.go index dd93c21..14ddc07 100644 --- a/clock.go +++ b/clock.go @@ -172,10 +172,11 @@ func (m *Mock) runNextTimer(max time.Time) bool { // Move "now" forward and unlock clock. m.now = t.Next() + now := m.now m.mu.Unlock() // Execute timer. - t.Tick(m.now) + t.Tick(now) return true } @@ -258,8 +259,9 @@ func (m *Mock) Timer(d time.Duration) *Timer { stopped: false, } m.timers = append(m.timers, (*internalTimer)(t)) + now := m.now m.mu.Unlock() - m.runNextTimer(m.now) + m.runNextTimer(now) return t } diff --git a/clock_test.go b/clock_test.go index 5c10efc..9e1db5e 100644 --- a/clock_test.go +++ b/clock_test.go @@ -766,5 +766,24 @@ func TestMock_AddAfterFuncRace(t *testing.T) { wg.Wait() // and wait for them } +func TestMock_AfterRace(t *testing.T) { + mock := NewMock() + + const num = 10 + var finished atomic.Int32 + + for i := 0; i < num; i++ { + go func() { + <-mock.After(1 * time.Millisecond) + finished.Add(1) + }() + } + + for finished.Load() < num { + mock.Add(time.Second) + gosched() + } +} + func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) } func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) }