mirror of
https://github.com/golang/go.git
synced 2025-05-18 13:54:40 +00:00
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:
parent
58911599e8
commit
d1e8dc25ff
@ -657,67 +657,57 @@ func checkTimers(pp *p, now int64) (rnow, pollUntil int64, ran bool) {
|
||||
//
|
||||
//go:systemstack
|
||||
func runtimer(pp *p, now int64) int64 {
|
||||
for {
|
||||
Redo:
|
||||
if len(pp.timers) == 0 {
|
||||
return -1
|
||||
}
|
||||
t := pp.timers[0]
|
||||
if t.pp.ptr() != pp {
|
||||
throw("runtimer: bad p")
|
||||
}
|
||||
switch s := t.status.Load(); s {
|
||||
case timerWaiting:
|
||||
if t.when > now {
|
||||
// Not ready to run.
|
||||
|
||||
if t.status.Load() == timerWaiting && t.when > now {
|
||||
// Fast path: 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
|
||||
}
|
||||
|
||||
if !t.status.CompareAndSwap(s, timerLocked) {
|
||||
continue
|
||||
}
|
||||
// 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 {
|
||||
status, mp := t.lock()
|
||||
if status == timerModified {
|
||||
dodeltimer0(pp)
|
||||
if !t.status.CompareAndSwap(timerLocked, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
if t.nextwhen == 0 {
|
||||
status = timerRemoved
|
||||
pp.deletedTimers.Add(-1)
|
||||
if len(pp.timers) == 0 {
|
||||
return -1
|
||||
}
|
||||
} else {
|
||||
t.when = t.nextwhen
|
||||
dodeltimer0(pp)
|
||||
doaddtimer(pp, t)
|
||||
if !t.status.CompareAndSwap(timerLocked, timerWaiting) {
|
||||
badTimer()
|
||||
status = timerWaiting
|
||||
}
|
||||
t.unlock(status, mp)
|
||||
goto Redo
|
||||
}
|
||||
|
||||
case timerLocked:
|
||||
// Wait for modification to complete.
|
||||
osyield()
|
||||
|
||||
case timerRemoved:
|
||||
// Should not see a new or inactive timer on the heap.
|
||||
badTimer()
|
||||
default:
|
||||
if status != timerWaiting {
|
||||
badTimer()
|
||||
}
|
||||
}
|
||||
|
||||
if t.when > now {
|
||||
// Not ready to run.
|
||||
t.unlock(status, mp)
|
||||
return t.when
|
||||
}
|
||||
|
||||
// runOneTimer runs a single timer.
|
||||
unlockAndRunTimer(pp, t, now, status, mp)
|
||||
return 0
|
||||
}
|
||||
|
||||
// unlockAndRunTimer unlocks and runs a single timer.
|
||||
// The caller must have locked the timers for pp.
|
||||
// This will temporarily unlock the timers while running the timer function.
|
||||
//
|
||||
//go:systemstack
|
||||
func runOneTimer(pp *p, t *timer, now int64) {
|
||||
func unlockAndRunTimer(pp *p, t *timer, now int64, status uint32, mp *m) {
|
||||
if raceenabled {
|
||||
ppcur := getg().m.p.ptr()
|
||||
if ppcur.timerRaceCtx == 0 {
|
||||
@ -738,17 +728,14 @@ func runOneTimer(pp *p, t *timer, now int64) {
|
||||
t.when = maxWhen
|
||||
}
|
||||
siftdownTimer(pp.timers, 0)
|
||||
if !t.status.CompareAndSwap(timerLocked, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
status = timerWaiting
|
||||
updateTimer0When(pp)
|
||||
} else {
|
||||
// Remove from heap.
|
||||
dodeltimer0(pp)
|
||||
if !t.status.CompareAndSwap(timerLocked, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
status = timerRemoved
|
||||
}
|
||||
t.unlock(status, mp)
|
||||
|
||||
if raceenabled {
|
||||
// Temporarily use the current P's racectx for g0.
|
||||
|
Loading…
x
Reference in New Issue
Block a user