aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2010-02-18 09:55:29 +1100
committerRob Pike <r@golang.org>2010-02-18 09:55:29 +1100
commit7b76175a1c4c6427fb54249adaced6081edd435e (patch)
tree0c31bc59a968cbf5972bf05caace72020dc43363
parent3dc04f4a22743623ef35ef69062e4d99ac12275d (diff)
downloadgo-7b76175a1c4c6427fb54249adaced6081edd435e.tar.gz
go-7b76175a1c4c6427fb54249adaced6081edd435e.zip
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
-rw-r--r--src/pkg/time/tick.go21
-rw-r--r--src/pkg/time/tick_test.go9
2 files changed, 24 insertions, 6 deletions
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
index bbbc469618..885a290bcf 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 e15793aea3..d089a9b98c 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()
+ }
+}