From 0c02bd18011c4290b27c3dc70ec2e762c6dcaffc Mon Sep 17 00:00:00 2001 From: Eoghan Sherry Date: Sat, 8 Jan 2011 21:24:44 -0800 Subject: [PATCH] time: fix tick accuracy when using multiple Tickers * correctly ignore obsolete ticks * fix update of next alarm time * tighten alarm channel buffers Fixes #1379. R=r, adg, r2 CC=golang-dev, soul9 https://golang.org/cl/3789045 --- src/pkg/time/tick.go | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go index 8f7d4226fed..ddd72727027 100644 --- a/src/pkg/time/tick.go +++ b/src/pkg/time/tick.go @@ -47,11 +47,12 @@ func (a *alarmer) set(ns int64) { 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 + close(a.wakeMeAt) fallthrough case a.wakeMeAt == nil: // There's no wakeLoop, start one. - a.wakeMeAt = make(chan int64, 10) + a.wakeMeAt = make(chan int64) + a.wakeUp = make(chan bool, 1) go wakeLoop(a.wakeMeAt, a.wakeUp) fallthrough case a.wakeTime == 0: @@ -73,19 +74,10 @@ func startTickerLoop() { // wakeLoop delivers ticks at scheduled times, sleeping until the right moment. // If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new -// wakeLoop but they will share the wakeUp channel and signal that this one -// is done by giving it a negative time request. +// wakeLoop and signal that this one is done by closing the wakeMeAt channel. func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) { - for { - wakeAt := <-wakeMeAt - if wakeAt < 0 { // tickerLoop has started another wakeLoop - return - } - now := Nanoseconds() - if wakeAt > now { - Sleep(wakeAt - now) - now = Nanoseconds() - } + for wakeAt := range wakeMeAt { + Sleep(wakeAt - Nanoseconds()) wakeUp <- true } } @@ -96,9 +88,7 @@ func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) { func tickerLoop() { // Represents the next alarm to be delivered. var alarm alarmer - // All wakeLoops deliver wakeups to this channel. - alarm.wakeUp = make(chan bool, 10) - var now, prevTime, wakeTime int64 + var now, wakeTime int64 var tickers *Ticker for { select { @@ -110,10 +100,6 @@ func tickerLoop() { alarm.set(t.nextTick) case <-alarm.wakeUp: now = Nanoseconds() - // Ignore an old time due to a dying wakeLoop - if now < prevTime { - continue - } wakeTime = now + 1e15 // very long in the future var prev *Ticker = nil // Scan list of tickers, delivering updates to those @@ -151,12 +137,12 @@ func tickerLoop() { if tickers != nil { // Please send wakeup at earliest required time. // If there are no tickers, don't bother. + alarm.wakeTime = wakeTime alarm.wakeMeAt <- wakeTime } else { alarm.wakeTime = 0 } } - prevTime = now } }