package runtime import "unsafe" // 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) != nil } //go:linkname resetTimer time.resetTimer func resetTimer(t *timeTimer, when, period int64) bool { n := removeTimer(&t.timer) removed := n != nil if n == nil { n = new(timerNode) } t.timer.when = when t.timer.period = period n.timer = &t.timer n.callback = timerCallback addTimer(n) return removed } //go:linkname time_runtimeNano time.runtimeNano func time_runtimeNano() int64 { // Note: we're ignoring sync groups here (package testing/synctest). // See: https://github.com/golang/go/issues/67434 return nanotime() } //go:linkname time_runtimeNow time.runtimeNow func time_runtimeNow() (sec int64, nsec int32, mono int64) { // Also ignoring the sync group here, like time_runtimeNano above. return now() } // timerNode is an element in a linked list of timers. type timerNode struct { next *timerNode timer *timer callback func(node *timerNode, delta int64) // The following fields are only used by schedulers that run timer // callbacks concurrently with user goroutines (the threads and cores // schedulers). They make it possible to stop or reset a periodic timer (a // ticker) while its callback is running, without the callback re-adding the // timer to the queue afterwards. They are protected by the scheduler's // timer lock. // // firingNext links nodes whose callback is currently running into the // firingTimers list. stopped is set when the timer was stopped or reset // while its callback was running, so that timerCallback does not re-add it. firingNext *timerNode stopped bool } // whenTicks returns the (absolute) time when this timer should trigger next. func (t *timerNode) whenTicks() timeUnit { return nanosecondsToTicks(t.timer.when) } // 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). // This is intentionally used as a callback and not a direct call (even though a // direct call would be trivial), because otherwise a circular dependency // between scheduler, addTimer and timerQueue would form. Such a circular // 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, 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.callCallback(delta) // If this is a periodic timer (a ticker), re-add it to the queue. if tn.timer.period != 0 { reAddTimer(tn) } } //go:linkname time_runtimeIsBubbled time.runtimeIsBubbled func time_runtimeIsBubbled() bool { // We don't currently support bubbles. return false }