diff --git a/src/runtime/proc.go b/src/runtime/proc.go index dc2957b939..3991a48b10 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -5071,14 +5071,15 @@ func checkdead() { // Maybe jump time forward for playground. if faketime != 0 { - when, _p_ := timeSleepUntil() - if _p_ != nil { + if when := timeSleepUntil(); when < maxWhen { faketime = when - for pp := &sched.pidle; *pp != 0; pp = &(*pp).ptr().link { - if (*pp).ptr() == _p_ { - *pp = _p_.link - break - } + + // Start an M to steal the timer. + pp, _ := pidleget(faketime) + if pp == nil { + // There should always be a free P since + // nothing is running. + throw("checkdead: no p for timer") } mp := mget() if mp == nil { @@ -5086,7 +5087,12 @@ func checkdead() { // nothing is running. throw("checkdead: no m for timer") } - mp.nextp.set(_p_) + // M must be spinning to steal. We set this to be + // explicit, but since this is the only M it would + // become spinning on its own anyways. + atomic.Xadd(&sched.nmspinning, 1) + mp.spinning = true + mp.nextp.set(pp) notewakeup(&mp.park) return } @@ -5158,7 +5164,7 @@ func sysmon() { lock(&sched.lock) if atomic.Load(&sched.gcwaiting) != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs) { syscallWake := false - next, _ := timeSleepUntil() + next := timeSleepUntil() if next > now { atomic.Store(&sched.sysmonwait, 1) unlock(&sched.lock) @@ -5231,7 +5237,7 @@ func sysmon() { // // See issue 42515 and // https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50094. - if next, _ := timeSleepUntil(); next < now { + if next := timeSleepUntil(); next < now { startm(nil, false) } } diff --git a/src/runtime/time.go b/src/runtime/time.go index e4d8269987..aec39083b4 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -1016,12 +1016,11 @@ func updateTimerModifiedEarliest(pp *p, nextwhen int64) { } } -// timeSleepUntil returns the time when the next timer should fire, -// and the P that holds the timer heap that that timer is on. +// timeSleepUntil returns the time when the next timer should fire. Returns +// maxWhen if there are no timers. // This is only called by sysmon and checkdead. -func timeSleepUntil() (int64, *p) { +func timeSleepUntil() int64 { next := int64(maxWhen) - var pret *p // Prevent allp slice changes. This is like retake. lock(&allpLock) @@ -1035,18 +1034,16 @@ func timeSleepUntil() (int64, *p) { w := int64(atomic.Load64(&pp.timer0When)) if w != 0 && w < next { next = w - pret = pp } w = int64(atomic.Load64(&pp.timerModifiedEarliest)) if w != 0 && w < next { next = w - pret = pp } } unlock(&allpLock) - return next, pret + return next } // Heap maintenance algorithms.