1
0
mirror of https://github.com/golang/go synced 2024-11-22 01:04:40 -07:00

time.Ticker: fix bug arising when all tickers are dead.

thanks to yglgogo for analysis.

Fixes #593.

R=rsc
CC=golang-dev
https://golang.org/cl/210044
This commit is contained in:
Rob Pike 2010-02-18 09:55:29 +11:00
parent 3dc04f4a22
commit 7b76175a1c
2 changed files with 24 additions and 6 deletions

View File

@ -39,16 +39,23 @@ type alarmer struct {
// Set alarm to go off at time ns, if not already set earlier. // Set alarm to go off at time ns, if not already set earlier.
func (a *alarmer) set(ns int64) { func (a *alarmer) set(ns int64) {
// If there's no wakeLoop or the next tick we expect is too late, start a new wakeLoop switch {
if a.wakeMeAt == nil || a.wakeTime > ns { case a.wakeTime > ns:
// Stop previous wakeLoop. // Next tick we expect is too late; shut down the late runner
if a.wakeMeAt != nil { // and (after fallthrough) start a new wakeLoop.
a.wakeMeAt <- -1 a.wakeMeAt <- -1
} fallthrough
case a.wakeMeAt == nil:
// There's no wakeLoop, start one.
a.wakeMeAt = make(chan int64, 10) a.wakeMeAt = make(chan int64, 10)
go wakeLoop(a.wakeMeAt, a.wakeUp) go wakeLoop(a.wakeMeAt, a.wakeUp)
fallthrough
case a.wakeTime == 0:
// Nobody else is waiting; it's just us.
a.wakeTime = ns a.wakeTime = ns
a.wakeMeAt <- ns a.wakeMeAt <- ns
default:
// There's already someone scheduled.
} }
} }
@ -141,6 +148,8 @@ func tickerLoop() {
// Please send wakeup at earliest required time. // Please send wakeup at earliest required time.
// If there are no tickers, don't bother. // If there are no tickers, don't bother.
alarm.wakeMeAt <- wakeTime alarm.wakeMeAt <- wakeTime
} else {
alarm.wakeTime = 0
} }
} }
prevTime = now prevTime = now

View File

@ -34,3 +34,12 @@ func TestTicker(t *testing.T) {
t.Fatalf("Ticker did not shut down") t.Fatalf("Ticker did not shut down")
} }
} }
// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
func TestTeardown(t *testing.T) {
for i := 0; i < 3; i++ {
ticker := NewTicker(1e8)
<-ticker.C
ticker.Stop()
}
}