runtime: use timer.lock in runtimer

Continue using timer.lock to simplify timer operations.

[This is one CL in a refactoring stack making very small changes
in each step, so that any subtle bugs that we miss can be more
easily pinpointed to a small change.]

Change-Id: I504335a010d6eb4d7d627145b64a896582158406
Reviewed-on: https://go-review.googlesource.com/c/go/+/564129
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Russ Cox 2024-02-14 11:57:03 -05:00
parent 58911599e8
commit d1e8dc25ff

View File

@ -657,67 +657,57 @@ func checkTimers(pp *p, now int64) (rnow, pollUntil int64, ran bool) {
// //
//go:systemstack //go:systemstack
func runtimer(pp *p, now int64) int64 { func runtimer(pp *p, now int64) int64 {
for { Redo:
if len(pp.timers) == 0 {
return -1
}
t := pp.timers[0] t := pp.timers[0]
if t.pp.ptr() != pp { if t.pp.ptr() != pp {
throw("runtimer: bad p") throw("runtimer: bad p")
} }
switch s := t.status.Load(); s {
case timerWaiting: if t.status.Load() == timerWaiting && t.when > now {
if t.when > now { // Fast path: not ready to run.
// Not ready to run. // The access of t.when is protected by the caller holding
// pp.timersLock, even though t itself is unlocked.
return t.when return t.when
} }
if !t.status.CompareAndSwap(s, timerLocked) { status, mp := t.lock()
continue if status == timerModified {
}
// Note that runOneTimer may temporarily unlock
// pp.timersLock.
runOneTimer(pp, t, now)
return 0
case timerModified:
if !t.status.CompareAndSwap(s, timerLocked) {
continue
}
if t.nextwhen == 0 {
dodeltimer0(pp) dodeltimer0(pp)
if !t.status.CompareAndSwap(timerLocked, timerRemoved) { if t.nextwhen == 0 {
badTimer() status = timerRemoved
}
pp.deletedTimers.Add(-1) pp.deletedTimers.Add(-1)
if len(pp.timers) == 0 {
return -1
}
} else { } else {
t.when = t.nextwhen t.when = t.nextwhen
dodeltimer0(pp)
doaddtimer(pp, t) doaddtimer(pp, t)
if !t.status.CompareAndSwap(timerLocked, timerWaiting) { status = timerWaiting
badTimer()
} }
t.unlock(status, mp)
goto Redo
} }
case timerLocked: if status != timerWaiting {
// Wait for modification to complete. badTimer()
osyield() }
case timerRemoved: if t.when > now {
// Should not see a new or inactive timer on the heap. // Not ready to run.
badTimer() t.unlock(status, mp)
default: return t.when
badTimer()
}
} }
unlockAndRunTimer(pp, t, now, status, mp)
return 0
} }
// runOneTimer runs a single timer. // unlockAndRunTimer unlocks and runs a single timer.
// The caller must have locked the timers for pp. // The caller must have locked the timers for pp.
// This will temporarily unlock the timers while running the timer function. // This will temporarily unlock the timers while running the timer function.
// //
//go:systemstack //go:systemstack
func runOneTimer(pp *p, t *timer, now int64) { func unlockAndRunTimer(pp *p, t *timer, now int64, status uint32, mp *m) {
if raceenabled { if raceenabled {
ppcur := getg().m.p.ptr() ppcur := getg().m.p.ptr()
if ppcur.timerRaceCtx == 0 { if ppcur.timerRaceCtx == 0 {
@ -738,17 +728,14 @@ func runOneTimer(pp *p, t *timer, now int64) {
t.when = maxWhen t.when = maxWhen
} }
siftdownTimer(pp.timers, 0) siftdownTimer(pp.timers, 0)
if !t.status.CompareAndSwap(timerLocked, timerWaiting) { status = timerWaiting
badTimer()
}
updateTimer0When(pp) updateTimer0When(pp)
} else { } else {
// Remove from heap. // Remove from heap.
dodeltimer0(pp) dodeltimer0(pp)
if !t.status.CompareAndSwap(timerLocked, timerRemoved) { status = timerRemoved
badTimer()
}
} }
t.unlock(status, mp)
if raceenabled { if raceenabled {
// Temporarily use the current P's racectx for g0. // Temporarily use the current P's racectx for g0.