From 7b76175a1c4c6427fb54249adaced6081edd435e Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 18 Feb 2010 09:55:29 +1100 Subject: [PATCH] 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 --- src/pkg/time/tick.go | 21 +++++++++++++++------ 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 bbbc469618f..885a290bcfa 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 e15793aea33..d089a9b98ca 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() + } +}