diff --git a/src/runtime/scheduler.go b/src/runtime/scheduler.go index 618f6a94f..30b2da8a6 100644 --- a/src/runtime/scheduler.go +++ b/src/runtime/scheduler.go @@ -181,12 +181,13 @@ func scheduler() { // Check for expired timers to trigger. if timerQueue != nil && now >= timerQueue.whenTicks() { scheduleLog("--- timer awoke") + delay := ticksToNanoseconds(now - timerQueue.whenTicks()) // Pop timer from queue. tn := timerQueue timerQueue = tn.next tn.next = nil // Run the callback stored in this timer node. - tn.callback(tn) + tn.callback(tn, delay) } t := runqueue.Pop() diff --git a/src/runtime/time.go b/src/runtime/time.go index 4fa3a418b..50bf61cf3 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -4,7 +4,7 @@ package runtime type timerNode struct { next *timerNode timer *timer - callback func(*timerNode) + callback func(node *timerNode, delta int64) } // whenTicks returns the (absolute) time when this timer should trigger next. @@ -12,17 +12,6 @@ func (t *timerNode) whenTicks() timeUnit { return nanosecondsToTicks(t.timer.when) } -// Defined in the time package, implemented here in the runtime. -// -//go:linkname startTimer time.startTimer -func startTimer(tim *timer) { - addTimer(&timerNode{ - timer: tim, - callback: timerCallback, - }) - scheduleLog("adding timer") -} - // timerCallback is called when a timer expires. It makes sure to call the // callback in the time package and to re-add the timer to the queue if this is // a ticker (repeating timer). @@ -32,11 +21,11 @@ func startTimer(tim *timer) { // dependency causes timerQueue not to get optimized away. // If timerQueue doesn't get optimized away, small programs (that don't call // time.NewTimer etc) would still pay the cost of these timers. -func timerCallback(tn *timerNode) { +func timerCallback(tn *timerNode, delta int64) { // Run timer function (implemented in the time package). // The seq parameter to the f function is not used in the time // package so is left zero. - tn.timer.f(tn.timer.arg, 0) + tn.timer.callCallback(delta) // If this is a periodic timer (a ticker), re-add it to the queue. if tn.timer.period != 0 { @@ -44,16 +33,3 @@ func timerCallback(tn *timerNode) { addTimer(tn) } } - -//go:linkname stopTimer time.stopTimer -func stopTimer(tim *timer) bool { - return removeTimer(tim) -} - -//go:linkname resetTimer time.resetTimer -func resetTimer(tim *timer, when int64) bool { - tim.when = when - removed := removeTimer(tim) - startTimer(tim) - return removed -} diff --git a/src/runtime/timer.go b/src/runtime/time_go122.go similarity index 60% rename from src/runtime/timer.go rename to src/runtime/time_go122.go index 134f9b9ac..2994c2722 100644 --- a/src/runtime/timer.go +++ b/src/runtime/time_go122.go @@ -1,9 +1,13 @@ +//go:build !go1.23 + // Portions copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package runtime +// Time functions for Go 1.22 and below. + type puintptr uintptr // Package time knows the layout of this structure. @@ -31,3 +35,31 @@ type timer struct { // The status field holds one of the values below. status uint32 } + +func (tim *timer) callCallback(delta int64) { + tim.f(tim.arg, 0) +} + +// Defined in the time package, implemented here in the runtime. +// +//go:linkname startTimer time.startTimer +func startTimer(tim *timer) { + addTimer(&timerNode{ + timer: tim, + callback: timerCallback, + }) + scheduleLog("adding timer") +} + +//go:linkname stopTimer time.stopTimer +func stopTimer(tim *timer) bool { + return removeTimer(tim) +} + +//go:linkname resetTimer time.resetTimer +func resetTimer(tim *timer, when int64) bool { + tim.when = when + removed := removeTimer(tim) + startTimer(tim) + return removed +} diff --git a/src/runtime/time_go123.go b/src/runtime/time_go123.go new file mode 100644 index 000000000..cfef4d393 --- /dev/null +++ b/src/runtime/time_go123.go @@ -0,0 +1,68 @@ +//go:build go1.23 + +package runtime + +import "unsafe" + +// Time functions for Go 1.23 and above. + +// This is the timer that's used internally inside the runtime. +type timer struct { + // When to call the timer, and the interval for the ticker. + when int64 + period int64 + + // Callback from the time package. + f func(arg any, seq uintptr, delta int64) + arg any +} + +func (tim *timer) callCallback(delta int64) { + tim.f(tim.arg, 0, delta) +} + +// This is the struct used internally in the runtime. The first two fields are +// the same as time.Timer and time.Ticker so it can be used as-is in the time +// package. +type timeTimer struct { + c unsafe.Pointer // <-chan time.Time + init bool + timer +} + +//go:linkname newTimer time.newTimer +func newTimer(when, period int64, f func(arg any, seq uintptr, delta int64), arg any, c unsafe.Pointer) *timeTimer { + tim := &timeTimer{ + c: c, + init: true, + timer: timer{ + when: when, + period: period, + f: f, + arg: arg, + }, + } + scheduleLog("new timer") + addTimer(&timerNode{ + timer: &tim.timer, + callback: timerCallback, + }) + return tim +} + +//go:linkname stopTimer time.stopTimer +func stopTimer(tim *timeTimer) bool { + return removeTimer(&tim.timer) +} + +//go:linkname resetTimer time.resetTimer +func resetTimer(t *timeTimer, when, period int64) bool { + t.timer.when = when + t.timer.period = period + removed := removeTimer(&t.timer) + addTimer(&timerNode{ + timer: &t.timer, + callback: timerCallback, + }) + return removed +}