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

Unified Diff: common/clock/systemtimer.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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « common/clock/systemclock_test.go ('k') | common/clock/systemtimer_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: common/clock/systemtimer.go
diff --git a/common/clock/systemtimer.go b/common/clock/systemtimer.go
index 0389a2ebf664b91e4790f925c3fe9e5f44c27664..9edcc22e35d1d08ec338b6c74d1b19c7985021db 100644
--- a/common/clock/systemtimer.go
+++ b/common/clock/systemtimer.go
@@ -6,32 +6,80 @@ package clock
import (
"time"
+
+ "golang.org/x/net/context"
)
type systemTimer struct {
- T *time.Timer // The underlying timer. Starts as nil, is initialized on Reset.
+ // ctx is the underlying timer. It starts as nil, and is initialized on Reset.
+ ctx context.Context
+
+ // timerC is the timer channel.
+ timerC chan TimerResult
+
+ // timerStoppedC is a signal channel used by Stop to alert our monitor that
+ // this timer has been manually canceled.
+ timerStoppedC chan struct{}
+ // timerMonitorResultC returns true if the timer monitor was prematurely
+ // terminated, false if not. It is used by our timer monitor to indicate its
+ // status when stopped.
+ timerMonitorResultC chan bool
}
var _ Timer = (*systemTimer)(nil)
-func (t *systemTimer) GetC() <-chan time.Time {
- if t.T == nil {
- return nil
+func newSystemTimer(ctx context.Context) Timer {
+ return &systemTimer{
+ ctx: ctx,
+ timerC: make(chan TimerResult, 1),
}
- return t.T.C
}
-func (t *systemTimer) Reset(d time.Duration) bool {
- if t.T == nil {
- t.T = time.NewTimer(d)
- return false
+func (t *systemTimer) GetC() <-chan TimerResult {
+ return t.timerC
+}
+
+func (t *systemTimer) Reset(d time.Duration) (running bool) {
+ running = t.Stop()
+
+ // If our Context is already done, finish immediately.
+ if err := t.ctx.Err(); err != nil {
+ t.timerC <- TimerResult{Time: time.Now(), Err: t.ctx.Err()}
+ return
}
- return t.T.Reset(d)
+
+ // Start a monitor goroutine and our actual timer. Copy our channels, since
+ // future stop/reset will change the systemTimer's values and our goroutine
+ // should only operate on this round's values.
+ timerStoppedC := make(chan struct{})
+ timerMonitorResultC := make(chan bool, 1)
+ go func() {
+ interrupted := false
+ defer func() {
+ timerMonitorResultC <- interrupted
+ }()
+
+ select {
+ case <-timerStoppedC:
+ interrupted = true
+
+ case <-t.ctx.Done():
+ t.timerC <- TimerResult{Time: time.Now(), Err: t.ctx.Err()}
+ case now := <-time.After(d):
+ t.timerC <- TimerResult{Time: now, Err: t.ctx.Err()}
+ }
+ }()
+
+ t.timerStoppedC = timerStoppedC
+ t.timerMonitorResultC = timerMonitorResultC
+ return
}
func (t *systemTimer) Stop() bool {
- if t.T == nil {
+ if t.timerStoppedC == nil {
return false
}
- return t.T.Stop()
+ close(t.timerStoppedC)
+ t.timerStoppedC = nil
+ return <-t.timerMonitorResultC
}
« no previous file with comments | « common/clock/systemclock_test.go ('k') | common/clock/systemtimer_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698