Skip to content

Commit e865db2

Browse files
aykevldeadprogram
authored andcommitted
runtime: implement timers for Go 1.23
There were a number of changes in time.Timer/time.Ticker that need a separate implementation for Go 1.22 and Go 1.23.
1 parent db2a06a commit e865db2

File tree

4 files changed

+105
-28
lines changed

4 files changed

+105
-28
lines changed

src/runtime/scheduler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,13 @@ func scheduler() {
181181
// Check for expired timers to trigger.
182182
if timerQueue != nil && now >= timerQueue.whenTicks() {
183183
scheduleLog("--- timer awoke")
184+
delay := ticksToNanoseconds(now - timerQueue.whenTicks())
184185
// Pop timer from queue.
185186
tn := timerQueue
186187
timerQueue = tn.next
187188
tn.next = nil
188189
// Run the callback stored in this timer node.
189-
tn.callback(tn)
190+
tn.callback(tn, delay)
190191
}
191192

192193
t := runqueue.Pop()

src/runtime/time.go

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,14 @@ package runtime
44
type timerNode struct {
55
next *timerNode
66
timer *timer
7-
callback func(*timerNode)
7+
callback func(node *timerNode, delta int64)
88
}
99

1010
// whenTicks returns the (absolute) time when this timer should trigger next.
1111
func (t *timerNode) whenTicks() timeUnit {
1212
return nanosecondsToTicks(t.timer.when)
1313
}
1414

15-
// Defined in the time package, implemented here in the runtime.
16-
//
17-
//go:linkname startTimer time.startTimer
18-
func startTimer(tim *timer) {
19-
addTimer(&timerNode{
20-
timer: tim,
21-
callback: timerCallback,
22-
})
23-
scheduleLog("adding timer")
24-
}
25-
2615
// timerCallback is called when a timer expires. It makes sure to call the
2716
// callback in the time package and to re-add the timer to the queue if this is
2817
// a ticker (repeating timer).
@@ -32,28 +21,15 @@ func startTimer(tim *timer) {
3221
// dependency causes timerQueue not to get optimized away.
3322
// If timerQueue doesn't get optimized away, small programs (that don't call
3423
// time.NewTimer etc) would still pay the cost of these timers.
35-
func timerCallback(tn *timerNode) {
24+
func timerCallback(tn *timerNode, delta int64) {
3625
// Run timer function (implemented in the time package).
3726
// The seq parameter to the f function is not used in the time
3827
// package so is left zero.
39-
tn.timer.f(tn.timer.arg, 0)
28+
tn.timer.callCallback(delta)
4029

4130
// If this is a periodic timer (a ticker), re-add it to the queue.
4231
if tn.timer.period != 0 {
4332
tn.timer.when += tn.timer.period
4433
addTimer(tn)
4534
}
4635
}
47-
48-
//go:linkname stopTimer time.stopTimer
49-
func stopTimer(tim *timer) bool {
50-
return removeTimer(tim)
51-
}
52-
53-
//go:linkname resetTimer time.resetTimer
54-
func resetTimer(tim *timer, when int64) bool {
55-
tim.when = when
56-
removed := removeTimer(tim)
57-
startTimer(tim)
58-
return removed
59-
}

src/runtime/timer.go renamed to src/runtime/time_go122.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
//go:build !go1.23
2+
13
// Portions copyright 2009 The Go Authors. All rights reserved.
24
// Use of this source code is governed by a BSD-style
35
// license that can be found in the LICENSE file.
46

57
package runtime
68

9+
// Time functions for Go 1.22 and below.
10+
711
type puintptr uintptr
812

913
// Package time knows the layout of this structure.
@@ -31,3 +35,31 @@ type timer struct {
3135
// The status field holds one of the values below.
3236
status uint32
3337
}
38+
39+
func (tim *timer) callCallback(delta int64) {
40+
tim.f(tim.arg, 0)
41+
}
42+
43+
// Defined in the time package, implemented here in the runtime.
44+
//
45+
//go:linkname startTimer time.startTimer
46+
func startTimer(tim *timer) {
47+
addTimer(&timerNode{
48+
timer: tim,
49+
callback: timerCallback,
50+
})
51+
scheduleLog("adding timer")
52+
}
53+
54+
//go:linkname stopTimer time.stopTimer
55+
func stopTimer(tim *timer) bool {
56+
return removeTimer(tim)
57+
}
58+
59+
//go:linkname resetTimer time.resetTimer
60+
func resetTimer(tim *timer, when int64) bool {
61+
tim.when = when
62+
removed := removeTimer(tim)
63+
startTimer(tim)
64+
return removed
65+
}

src/runtime/time_go123.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//go:build go1.23
2+
3+
package runtime
4+
5+
import "unsafe"
6+
7+
// Time functions for Go 1.23 and above.
8+
9+
// This is the timer that's used internally inside the runtime.
10+
type timer struct {
11+
// When to call the timer, and the interval for the ticker.
12+
when int64
13+
period int64
14+
15+
// Callback from the time package.
16+
f func(arg any, seq uintptr, delta int64)
17+
arg any
18+
}
19+
20+
func (tim *timer) callCallback(delta int64) {
21+
tim.f(tim.arg, 0, delta)
22+
}
23+
24+
// This is the struct used internally in the runtime. The first two fields are
25+
// the same as time.Timer and time.Ticker so it can be used as-is in the time
26+
// package.
27+
type timeTimer struct {
28+
c unsafe.Pointer // <-chan time.Time
29+
init bool
30+
timer
31+
}
32+
33+
//go:linkname newTimer time.newTimer
34+
func newTimer(when, period int64, f func(arg any, seq uintptr, delta int64), arg any, c unsafe.Pointer) *timeTimer {
35+
tim := &timeTimer{
36+
c: c,
37+
init: true,
38+
timer: timer{
39+
when: when,
40+
period: period,
41+
f: f,
42+
arg: arg,
43+
},
44+
}
45+
scheduleLog("new timer")
46+
addTimer(&timerNode{
47+
timer: &tim.timer,
48+
callback: timerCallback,
49+
})
50+
return tim
51+
}
52+
53+
//go:linkname stopTimer time.stopTimer
54+
func stopTimer(tim *timeTimer) bool {
55+
return removeTimer(&tim.timer)
56+
}
57+
58+
//go:linkname resetTimer time.resetTimer
59+
func resetTimer(t *timeTimer, when, period int64) bool {
60+
t.timer.when = when
61+
t.timer.period = period
62+
removed := removeTimer(&t.timer)
63+
addTimer(&timerNode{
64+
timer: &t.timer,
65+
callback: timerCallback,
66+
})
67+
return removed
68+
}

0 commit comments

Comments
 (0)