summaryrefslogtreecommitdiff
path: root/src/pkg
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
commitc48c878bc173af95dc71109ee532f29b696f3f97 (patch)
treeecac9c7e96f49cc56b7fadd0fcfb570d0889fb1f /src/pkg
parentb7f303f117f16fa41ca82ab689b9dbc9b1f60162 (diff)
downloadgolang-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.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 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()
+ }
+}