Skip to content

time: add Ticker.Reset #163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/next.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pkg testing, method (*T) Deadline() (time.Time, bool)
pkg time, method (*Ticker) Reset(Duration)
10 changes: 10 additions & 0 deletions doc/go1.15.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ <h3 id="minor_library_changes">Minor changes to the library</h3>
<p>
TODO
</p>

<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
<dd>
<p><!-- golang.org/issue/33184 -->
The new method
<a href="/pkg/time#Ticker.Reset"><code>Ticker.Reset</code></a>
supports changing the duration of a ticker.
</p>
</dd>
</dl><!-- time -->
8 changes: 7 additions & 1 deletion src/runtime/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ func resetTimer(t *timer, when int64) {
resettimer(t, when)
}

// modTimer modifies an existing timer.
//go:linkname modTimer time.modTimer
func modTimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
modtimer(t, when, period, f, arg, seq)
}

// Go runtime.

// Ready the goroutine arg.
Expand Down Expand Up @@ -402,7 +408,7 @@ func dodeltimer0(pp *p) bool {
}

// modtimer modifies an existing timer.
// This is called by the netpoll code.
// This is called by the netpoll code or time.Ticker.Reset.
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
if when < 0 {
when = maxWhen
Expand Down
1 change: 1 addition & 0 deletions src/time/sleep.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func when(d Duration) int64 {
func startTimer(*runtimeTimer)
func stopTimer(*runtimeTimer) bool
func resetTimer(*runtimeTimer, int64)
func modTimer(t *runtimeTimer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr)

// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
Expand Down
9 changes: 9 additions & 0 deletions src/time/tick.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ func (t *Ticker) Stop() {
stopTimer(&t.r)
}

// Reset stops a ticker and resets its period to the specified duration.
// The next tick will arrive after the new period elapses.
func (t *Ticker) Reset(d Duration) {
if t.r.f == nil {
panic("time: Reset called on uninitialized Ticker")
}
modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq)
}

// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only. While Tick is useful for clients that have no need to shut down
// the Ticker, be aware that without a way to shut it down the underlying
Expand Down
29 changes: 27 additions & 2 deletions src/time/tick_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ func TestTicker(t *testing.T) {
for i := 0; i < 5; i++ {
ticker := NewTicker(delta)
t0 := Now()
for i := 0; i < count; i++ {
for i := 0; i < count/2; i++ {
<-ticker.C
}
ticker.Reset(delta * 2)
for i := count / 2; i < count; i++ {
<-ticker.C
}
ticker.Stop()
t1 := Now()
dt := t1.Sub(t0)
target := delta * Duration(count)
target := 3 * delta * Duration(count/2)
slop := target * 2 / 10
if dt < target-slop || dt > target+slop {
errs = append(errs, fmt.Sprintf("%d %s ticks took %s, expected [%s,%s]", count, delta, dt, target-slop, target+slop))
Expand Down Expand Up @@ -118,3 +122,24 @@ func BenchmarkTicker(b *testing.B) {
ticker.Stop()
})
}

func BenchmarkTickerReset(b *testing.B) {
benchmark(b, func(n int) {
ticker := NewTicker(Nanosecond)
for i := 0; i < n; i++ {
ticker.Reset(Nanosecond * 2)
}
ticker.Stop()
})
}

func BenchmarkTickerResetNaive(b *testing.B) {
benchmark(b, func(n int) {
ticker := NewTicker(Nanosecond)
for i := 0; i < n; i++ {
ticker.Stop()
ticker = NewTicker(Nanosecond * 2)
}
ticker.Stop()
})
}