From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libgo/go/time/tick.go | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 libgo/go/time/tick.go (limited to 'libgo/go/time/tick.go') diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go new file mode 100644 index 000000000..ddd727270 --- /dev/null +++ b/libgo/go/time/tick.go @@ -0,0 +1,171 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import ( + "os" + "sync" +) + +// A Ticker holds a synchronous channel that delivers `ticks' of a clock +// at intervals. +type Ticker struct { + C <-chan int64 // The channel on which the ticks are delivered. + c chan<- int64 // The same channel, but the end we use. + ns int64 + shutdown chan bool // Buffered channel used to signal shutdown. + nextTick int64 + next *Ticker +} + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +func (t *Ticker) Stop() { + // Make it non-blocking so multiple Stops don't block. + _ = t.shutdown <- true +} + +// Tick is a convenience wrapper for NewTicker providing access to the ticking +// channel only. Useful for clients that have no need to shut down the ticker. +func Tick(ns int64) <-chan int64 { + if ns <= 0 { + return nil + } + return NewTicker(ns).C +} + +type alarmer struct { + wakeUp chan bool // wakeup signals sent/received here + wakeMeAt chan int64 + wakeTime int64 +} + +// Set alarm to go off at time ns, if not already set earlier. +func (a *alarmer) set(ns int64) { + switch { + case a.wakeTime > ns: + // Next tick we expect is too late; shut down the late runner + // and (after fallthrough) start a new wakeLoop. + close(a.wakeMeAt) + fallthrough + case a.wakeMeAt == nil: + // There's no wakeLoop, start one. + a.wakeMeAt = make(chan int64) + a.wakeUp = make(chan bool, 1) + 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. + } +} + +// Channel to notify tickerLoop of new Tickers being created. +var newTicker chan *Ticker + +func startTickerLoop() { + newTicker = make(chan *Ticker) + go tickerLoop() +} + +// 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 and signal that this one is done by closing the wakeMeAt channel. +func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) { + for wakeAt := range wakeMeAt { + Sleep(wakeAt - Nanoseconds()) + wakeUp <- true + } +} + +// A single tickerLoop serves all ticks to Tickers. It waits for two events: +// either the creation of a new Ticker or a tick from the alarm, +// signalling a time to wake up one or more Tickers. +func tickerLoop() { + // Represents the next alarm to be delivered. + var alarm alarmer + var now, wakeTime int64 + var tickers *Ticker + for { + select { + case t := <-newTicker: + // Add Ticker to list + t.next = tickers + tickers = t + // Arrange for a new alarm if this one precedes the existing one. + alarm.set(t.nextTick) + case <-alarm.wakeUp: + now = Nanoseconds() + wakeTime = now + 1e15 // very long in the future + var prev *Ticker = nil + // Scan list of tickers, delivering updates to those + // that need it and determining the next wake time. + // TODO(r): list should be sorted in time order. + for t := tickers; t != nil; t = t.next { + if _, ok := <-t.shutdown; ok { + // Ticker is done; remove it from list. + if prev == nil { + tickers = t.next + } else { + prev.next = t.next + } + continue + } + if t.nextTick <= now { + if len(t.c) == 0 { + // Only send if there's room. We must not block. + // The channel is allocated with a one-element + // buffer, which is sufficient: if he hasn't picked + // up the last tick, no point in sending more. + t.c <- now + } + t.nextTick += t.ns + if t.nextTick <= now { + // Still behind; advance in one big step. + t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns + } + } + if t.nextTick < wakeTime { + wakeTime = t.nextTick + } + prev = t + } + 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 + } + } + } +} + +var onceStartTickerLoop sync.Once + +// NewTicker returns a new Ticker containing a channel that will +// send the time, in nanoseconds, every ns nanoseconds. It adjusts the +// intervals to make up for pauses in delivery of the ticks. The value of +// ns must be greater than zero; if not, NewTicker will panic. +func NewTicker(ns int64) *Ticker { + if ns <= 0 { + panic(os.ErrorString("non-positive interval for NewTicker")) + } + c := make(chan int64, 1) // See comment on send in tickerLoop + t := &Ticker{ + C: c, + c: c, + ns: ns, + shutdown: make(chan bool, 1), + nextTick: Nanoseconds() + ns, + } + onceStartTickerLoop.Do(startTickerLoop) + // must be run in background so global Tickers can be created + go func() { newTicker <- t }() + return t +} -- cgit v1.2.3