Skip to content
This repository has been archived by the owner on May 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #35 from djmitche/issue33
Browse files Browse the repository at this point in the history
Address re-entrancy of Tick
  • Loading branch information
djmitche authored Oct 25, 2021
2 parents 5ad814c + 0b9476f commit f495692
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 2 deletions.
8 changes: 6 additions & 2 deletions clock.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,20 @@ type internalTimer Timer

func (t *internalTimer) Next() time.Time { return t.next }
func (t *internalTimer) Tick(now time.Time) {
// a gosched() after ticking, to allow any consequences of the
// tick to complete
defer gosched()

t.mock.mu.Lock()
if t.fn != nil {
t.fn()
// defer function execution until the lock is released, and
defer t.fn()
} else {
t.c <- now
}
t.mock.removeClockTimer((*internalTimer)(t))
t.stopped = true
t.mock.mu.Unlock()
gosched()
}

// Ticker holds a channel that receives "ticks" at regular intervals.
Expand Down
15 changes: 15 additions & 0 deletions clock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,5 +613,20 @@ func ExampleMock_Timer() {
// Count is 1 after 10 seconds
}

func TestMock_ReentrantDeadlock(t *testing.T) {
mockedClock := NewMock()
timer20 := mockedClock.Timer(20 * time.Second)
go func() {
v := <-timer20.C
panic(fmt.Sprintf("timer should not have ticked: %v", v))
}()
mockedClock.AfterFunc(10*time.Second, func() {
timer20.Stop()
})

mockedClock.Add(15 * time.Second)
mockedClock.Add(15 * time.Second)
}

func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) }
func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) }

0 comments on commit f495692

Please sign in to comment.