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 ...@@ -7,7 +7,7 @@ package time
// TODO(rsc): This implementation of Tick is a // TODO(rsc): This implementation of Tick is a
// simple placeholder. Eventually, there will need to be // simple placeholder. Eventually, there will need to be
// a single central time server no matter how many tickers // 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, // Also, if timeouts become part of the select statement,
// perhaps the Ticker is just: // perhaps the Ticker is just:
...@@ -19,40 +19,63 @@ package time ...@@ -19,40 +19,63 @@ package time
// c <- nsec; // 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(); now := Nanoseconds();
when := now; when := now;
for { for !t.shutdown {
when += ns; // next alarm when += t.ns; // next alarm
// if c <- now took too long, skip ahead // if c <- now took too long, skip ahead
if when < now { if when < now {
// one big step // one big step
when += (now-when)/ns * ns; when += (now-when)/t.ns * t.ns;
} }
for when <= now { for when <= now {
// little steps until when > now // little steps until when > now
when += ns when += t.ns
} }
Sleep(when - now); Sleep(when - now);
now = Nanoseconds(); now = Nanoseconds();
c <- now; if t.shutdown {
if closed(c) {
return; return;
} }
c <- now;
} }
} }
// Tick creates a synchronous channel that will send the time, in nanoseconds, // Tick is a convenience wrapper for NewTicker providing access to the ticking
// every ns nanoseconds. It adjusts the intervals to make up for pauses in // channel only. Useful for clients that have no need to shut down the ticker.
// delivery of the ticks. func Tick(ns int64) <-chan int64 {
func Tick(ns int64) chan int64 {
if ns <= 0 { if ns <= 0 {
return nil return nil
} }
c := make(chan int64); return NewTicker(ns).C;
go ticker(ns, c);
return 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 ( ...@@ -9,16 +9,17 @@ import (
. "time"; . "time";
) )
func TestTick(t *testing.T) { func TestTicker(t *testing.T) {
const ( const (
Delta = 100*1e6; Delta = 100*1e6;
Count = 10; Count = 10;
); );
c := Tick(Delta); ticker := NewTicker(Delta);
t0 := Nanoseconds(); t0 := Nanoseconds();
for i := 0; i < Count; i++ { for i := 0; i < Count; i++ {
<-c; <-ticker.C;
} }
ticker.Stop();
t1 := Nanoseconds(); t1 := Nanoseconds();
ns := t1 - t0; ns := t1 - t0;
target := int64(Delta*Count); target := int64(Delta*Count);
...@@ -26,4 +27,10 @@ func TestTick(t *testing.T) { ...@@ -26,4 +27,10 @@ func TestTick(t *testing.T) {
if ns < target - slop || ns > target + slop { 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)); 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