]> Cypherpunks repositories - gostls13.git/commitdiff
expand ticker interface to allow a client to shut down a ticker.
authorRob Pike <r@golang.org>
Wed, 23 Sep 2009 20:02:14 +0000 (13:02 -0700)
committerRob Pike <r@golang.org>
Wed, 23 Sep 2009 20:02:14 +0000 (13:02 -0700)
existing interface still works.

R=rsc
DELTA=50  (32 added, 2 deleted, 16 changed)
OCL=34930
CL=34932

src/pkg/time/tick.go
src/pkg/time/tick_test.go

index e716ba57a3a46f6192e9adb0f62048c26f58b3cf..b664077c1b89e1856586e110d62df047b79483c2 100644 (file)
@@ -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;
+}
index c7cad1217eba5ff0f1b487342e64fb2744b33a56..4a82eee74373b24afc62af2fda05712ab4bd2765 100644 (file)
@@ -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");
+       }
 }