// checkTimers here because it calls adjusttimers which may need to allocate
// memory, and that isn't allowed when we don't have an active P.
for _, _p_ := range allpSnapshot {
- // This is similar to nobarrierWakeTime, but minimizes calls to
- // nanotime.
- if atomic.Load(&_p_.adjustTimers) > 0 {
- if now == 0 {
- now = nanotime()
- }
- pollUntil = now
- } else {
- w := int64(atomic.Load64(&_p_.timer0When))
- if w != 0 && (pollUntil == 0 || w < pollUntil) {
- pollUntil = w
- }
+ w := nobarrierWakeTime(_p_)
+ if w != 0 && (pollUntil == 0 || w < pollUntil) {
+ pollUntil = w
}
}
if pollUntil != 0 {
// nobarrierWakeTime looks at P's timers and returns the time when we
// should wake up the netpoller. It returns 0 if there are no timers.
// This function is invoked when dropping a P, and must run without
-// any write barriers. Therefore, if there are any timers that needs
-// to be moved earlier, it conservatively returns the current time.
-// The netpoller M will wake up and adjust timers before sleeping again.
+// any write barriers.
//go:nowritebarrierrec
func nobarrierWakeTime(pp *p) int64 {
- if atomic.Load(&pp.adjustTimers) > 0 {
- return nanotime()
- } else {
- return int64(atomic.Load64(&pp.timer0When))
+ next := int64(atomic.Load64(&pp.timer0When))
+ nextAdj := int64(atomic.Load64(&pp.timerModifiedEarliest))
+ if next == 0 || (nextAdj != 0 && nextAdj < next) {
+ next = nextAdj
}
+ return next
}
// runtimer examines the first timer in timers. If it is ready based on now,