diff options
author | Rob Pike <r@golang.org> | 2010-02-18 09:55:29 +1100 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2010-02-18 09:55:29 +1100 |
commit | c48c878bc173af95dc71109ee532f29b696f3f97 (patch) | |
tree | ecac9c7e96f49cc56b7fadd0fcfb570d0889fb1f /src/pkg | |
parent | b7f303f117f16fa41ca82ab689b9dbc9b1f60162 (diff) | |
download | golang-c48c878bc173af95dc71109ee532f29b696f3f97.tar.gz |
time.Ticker: fix bug arising when all tickers are dead.
thanks to yglgogo for analysis.
Fixes issue 593.
R=rsc
CC=golang-dev
http://codereview.appspot.com/210044
Diffstat (limited to 'src/pkg')
-rw-r--r-- | src/pkg/time/tick.go | 21 | ||||
-rw-r--r-- | src/pkg/time/tick_test.go | 9 |
2 files changed, 24 insertions, 6 deletions
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go index bbbc46961..885a290bc 100644 --- a/src/pkg/time/tick.go +++ b/src/pkg/time/tick.go @@ -39,16 +39,23 @@ type alarmer struct { // Set alarm to go off at time ns, if not already set earlier. func (a *alarmer) set(ns int64) { - // If there's no wakeLoop or the next tick we expect is too late, start a new wakeLoop - if a.wakeMeAt == nil || a.wakeTime > ns { - // Stop previous wakeLoop. - if a.wakeMeAt != nil { - a.wakeMeAt <- -1 - } + switch { + case a.wakeTime > ns: + // Next tick we expect is too late; shut down the late runner + // and (after fallthrough) start a new wakeLoop. + a.wakeMeAt <- -1 + fallthrough + case a.wakeMeAt == nil: + // There's no wakeLoop, start one. a.wakeMeAt = make(chan int64, 10) go wakeLoop(a.wakeMeAt, a.wakeUp) + fallthrough + case a.wakeTime == 0: + // Nobody else is waiting; it's just us. a.wakeTime = ns a.wakeMeAt <- ns + default: + // There's already someone scheduled. } } @@ -141,6 +148,8 @@ func tickerLoop() { // Please send wakeup at earliest required time. // If there are no tickers, don't bother. alarm.wakeMeAt <- wakeTime + } else { + alarm.wakeTime = 0 } } prevTime = now diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go index e15793aea..d089a9b98 100644 --- a/src/pkg/time/tick_test.go +++ b/src/pkg/time/tick_test.go @@ -34,3 +34,12 @@ func TestTicker(t *testing.T) { 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() + } +} |