Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: common/clock/testclock/testtimer.go

Issue 1679023005: Add Context cancellation to clock. (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Actually upload the patch. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « common/clock/testclock/testclock_test.go ('k') | common/clock/testclock/testtimer_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package testclock 5 package testclock
6 6
7 import ( 7 import (
8 "time" 8 "time"
9 9
10 "github.com/luci/luci-go/common/clock" 10 "github.com/luci/luci-go/common/clock"
11 "golang.org/x/net/context"
11 ) 12 )
12 13
13 // timer is an implementation of clock.TestTimer that uses a channel 14 // timer is an implementation of clock.TestTimer that uses a channel
14 // to signal the timer to fire. 15 // to signal the timer to fire.
15 // 16 //
16 // The channel is buffered so it can be used without requiring a separate 17 // The channel is buffered so it can be used without requiring a separate
17 // signalling goroutine. 18 // signalling goroutine.
18 type timer struct { 19 type timer struct {
19 » clock *testClock 20 » ctx context.Context
20 » signalC chan time.Time 21 » clock *testClock
21 22
22 » // Cancels callback from clock.invokeAt. Being not nil implies that the timer 23 » // tags is the set of tags in the Context when this timer was created.
24 » tags []string
25
26 » // afterC will have the TimerResult of the timer's expiration written to it
27 » // when this timer triggers or is canceled.
28 » afterC chan clock.TimerResult
29
30 » // Cancels callback from clock.invokeAt. Being non-nil implies that the timer
23 // is active. 31 // is active.
24 » cancelFunc cancelFunc 32 » cancelFunc context.CancelFunc
25 } 33 }
26 34
27 var _ clock.Timer = (*timer)(nil) 35 var _ clock.Timer = (*timer)(nil)
28 36
29 // NewTimer returns a new, instantiated timer. 37 // NewTimer returns a new, instantiated timer.
30 func newTimer(clock *testClock) clock.Timer { 38 func newTimer(ctx context.Context, clk *testClock) *timer {
31 return &timer{ 39 return &timer{
32 » » clock: clock, 40 » » ctx: ctx,
41 » » clock: clk,
42 » » tags: clock.Tags(ctx),
43 » » afterC: make(chan clock.TimerResult, 1),
33 } 44 }
34 } 45 }
35 46
36 func (t *timer) GetC() (c <-chan time.Time) { 47 func (t *timer) GetC() <-chan clock.TimerResult {
37 » if t.cancelFunc != nil { 48 » return t.afterC
38 » » c = t.signalC
39 » }
40 » return
41 } 49 }
42 50
43 func (t *timer) Reset(d time.Duration) (active bool) { 51 func (t *timer) Reset(d time.Duration) (active bool) {
44 now := t.clock.Now() 52 now := t.clock.Now()
45 triggerTime := now.Add(d) 53 triggerTime := now.Add(d)
46 54
47 // Signal our timerSet callback. 55 // Signal our timerSet callback.
48 t.clock.signalTimerSet(d, t) 56 t.clock.signalTimerSet(d, t)
49 57
50 // Stop our current polling goroutine, if it's running. 58 // Stop our current polling goroutine, if it's running.
51 active = t.Stop() 59 active = t.Stop()
52 60
53 // Set timer properties. 61 // Set timer properties.
54 » t.signalC = make(chan time.Time, 1) 62 » var ctx context.Context
55 » t.cancelFunc = t.clock.invokeAt(triggerTime, t.signal) 63 » ctx, t.cancelFunc = context.WithCancel(t.ctx)
64 » t.clock.invokeAt(ctx, triggerTime, func(tr clock.TimerResult) {
65 » » // If our cancelFunc is nil, then we were stopped and should NOT signal our
66 » » // timer channel.
67 » » if t.cancelFunc != nil {
68 » » » t.afterC <- tr
69 » » » t.cancelFunc = nil
70 » » }
71 » })
56 return 72 return
57 } 73 }
58 74
59 func (t *timer) Stop() bool { 75 func (t *timer) Stop() bool {
60 // If the timer is not running, we're done. 76 // If the timer is not running, we're done.
61 » if t.cancelFunc == nil { 77 » cf := t.cancelFunc
78 » if cf == nil {
62 return false 79 return false
63 } 80 }
64 81
65 » // Clear our state. 82 » // Clear our state. Set our cancelFunc to nil so our callback knows that we
66 » t.cancelFunc() 83 » // were stopped.
67 t.cancelFunc = nil 84 t.cancelFunc = nil
85 cf()
68 return true 86 return true
69 } 87 }
70 88
71 // Sends a single time signal. 89 // GetTags returns the tags associated with the specified timer. If the timer
72 func (t *timer) signal(now time.Time) { 90 // has no tags, an empty slice (nil) will be returned.
73 » if t.signalC != nil { 91 func GetTags(t clock.Timer) []string {
74 » » t.signalC <- now 92 » if tt, ok := t.(*timer); ok {
93 » » return clock.Tags(tt.ctx)
75 } 94 }
95 return nil
76 } 96 }
97
98 // HasTags tests if a given timer has the same tags.
99 func HasTags(t clock.Timer, first string, tags ...string) bool {
100 timerTags := GetTags(t)
101 if len(timerTags) == 0 {
102 return false
103 }
104
105 if first != timerTags[0] {
106 return false
107 }
108
109 if len(timerTags) > 1 {
110 // Compare the remainder.
111 timerTags = timerTags[1:]
112 if len(timerTags) != len(tags) {
113 return false
114 }
115
116 for i, tag := range timerTags {
117 if tags[i] != tag {
118 return false
119 }
120 }
121 }
122 return true
123 }
OLDNEW
« no previous file with comments | « common/clock/testclock/testclock_test.go ('k') | common/clock/testclock/testtimer_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698