Commit fbb70297 authored by Rob Pike's avatar Rob Pike

expand ticker interface to allow a client to shut down a ticker.

existing interface still works.

R=rsc
DELTA=50  (32 added, 2 deleted, 16 changed)
OCL=34930
CL=34932
parent ea4ada89
......@@ -7,7 +7,7 @@ package time
// TODO(rsc): This implementation of Tick is a
// simple placeholder. Eventually, there will need to be
// a single central time server no matter how many tickers
// are active. There also needs to be a way to cancel a ticker.
// are active.
//
// Also, if timeouts become part of the select statement,
// perhaps the Ticker is just:
......@@ -19,40 +19,63 @@ package time
// c <- nsec;
// }
func ticker(ns int64, c chan int64) {
// 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.
ns int64;
shutdown bool;
}
// Stop turns off a ticker. After Stop, no more ticks will be delivered.
func (t *Ticker) Stop() {
t.shutdown = true
}
func (t *Ticker) ticker(c chan<- int64) {
now := Nanoseconds();
when := now;
for {
when += ns; // next alarm
for !t.shutdown {
when += t.ns; // next alarm
// if c <- now took too long, skip ahead
if when < now {
// one big step
when += (now-when)/ns * ns;
when += (now-when)/t.ns * t.ns;
}
for when <= now {
// little steps until when > now
when += ns
when += t.ns
}
Sleep(when - now);
now = Nanoseconds();
c <- now;
if closed(c) {
if t.shutdown {
return;
}
c <- now;
}
}
// Tick creates a synchronous 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.
func Tick(ns int64) chan int64 {
// 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
}
c := make(chan int64);
go ticker(ns, c);
return c;
return NewTicker(ns).C;
}
// Ticker returns a new Ticker containing a synchronous 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.
func NewTicker(ns int64) *Ticker {
if ns <= 0 {
return nil
}
c := make(chan int64);
t := &Ticker{c, ns, false};
go t.ticker(c);
return t;
}
......@@ -9,16 +9,17 @@ import (
. "time";
)
func TestTick(t *testing.T) {
func TestTicker(t *testing.T) {
const (
Delta = 100*1e6;
Count = 10;
);
c := Tick(Delta);
ticker := NewTicker(Delta);
t0 := Nanoseconds();
for i := 0; i < Count; i++ {
<-c;
<-ticker.C;
}
ticker.Stop();
t1 := Nanoseconds();
ns := t1 - t0;
target := int64(Delta*Count);
......@@ -26,4 +27,10 @@ func TestTick(t *testing.T) {
if ns < target - slop || ns > target + slop {
t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target));
}
// Now test that the ticker stopped
Sleep(2*Delta);
_, received := <-ticker.C;
if received {
t.Fatalf("Ticker did not shut down");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment