| Index: common/clock/systemtimer.go
|
| diff --git a/common/clock/systemtimer.go b/common/clock/systemtimer.go
|
| index 0389a2ebf664b91e4790f925c3fe9e5f44c27664..26686a014d43094a206d3a0daf8b5adfedb8b51a 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.
|
| + // base is the underlying timer. It starts as nil, and is initialized on
|
| + // Reset.
|
| + ctx context.Context
|
| +
|
| + // timerC is the current timer channel.
|
| + timerC chan TimerResult
|
| + // timerDoneC is a signal channel to alert our monitor that this timer has
|
| + // been canceled.
|
| + timerStoppedC chan struct{}
|
| + // timerMonitorResultC returns true if the timer monitor was prematurely
|
| + // terminated, false if not.
|
| + timerMonitorResultC chan bool
|
| }
|
|
|
| var _ Timer = (*systemTimer)(nil)
|
|
|
| -func (t *systemTimer) GetC() <-chan time.Time {
|
| - if t.T == nil {
|
| - return nil
|
| - }
|
| - return t.T.C
|
| +func (t *systemTimer) GetC() <-chan TimerResult {
|
| + return t.timerC
|
| }
|
|
|
| -func (t *systemTimer) Reset(d time.Duration) bool {
|
| - if t.T == nil {
|
| - t.T = time.NewTimer(d)
|
| - return false
|
| +func (t *systemTimer) Reset(d time.Duration) (running bool) {
|
| + running = t.Stop()
|
| + t.reset()
|
| +
|
| + // If our Context is already done, finish immediately.
|
| + select {
|
| + case <-t.ctx.Done():
|
| + t.timerC <- TimerResult{Err: t.ctx.Err()}
|
| + return
|
| + default:
|
| + break
|
| }
|
| - 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.
|
| + timerC := t.timerC
|
| + 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():
|
| + timerC <- TimerResult{Err: t.ctx.Err()}
|
| + case t := <-time.After(d):
|
| + timerC <- TimerResult{Time: t}
|
| + }
|
| + }()
|
| +
|
| + 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
|
| +}
|
| +
|
| +func (t *systemTimer) reset() {
|
| + t.timerC = make(chan TimerResult, 1)
|
| }
|
|
|