runtime: merge timerModifiedEarlier and timerModifierLater

Nothing actually needs to know the difference between these
two states, so merge them.

This is part of a larger simplification of the state set.

[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: Ia30699ac92e66467773942e7df1fb21470a6e51a
Reviewed-on: https://go-review.googlesource.com/c/go/+/564119
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:56:57 -05:00
parent 4a3c3ec996
commit b2bd7ebafc
1 changed files with 23 additions and 53 deletions

View File

@ -72,8 +72,7 @@ type timer struct {
//
// deltimer:
// timerWaiting -> timerModifying -> timerDeleted
// timerModifiedEarlier -> timerModifying -> timerDeleted
// timerModifiedLater -> timerModifying -> timerDeleted
// timerModified -> timerModifying -> timerDeleted
// timerNoStatus -> do nothing
// timerDeleted -> do nothing
// timerRemoving -> do nothing
@ -82,25 +81,25 @@ type timer struct {
// timerMoving -> wait until status changes
// timerModifying -> wait until status changes
// modtimer:
// timerWaiting -> timerModifying -> timerModifiedXX
// timerModifiedXX -> timerModifying -> timerModifiedYY
// timerWaiting -> timerModifying -> timerModified
// timerModified -> timerModifying -> timerModified
// timerNoStatus -> timerModifying -> timerWaiting
// timerRemoved -> timerModifying -> timerWaiting
// timerDeleted -> timerModifying -> timerModifiedXX
// timerDeleted -> timerModifying -> timerModified
// timerRunning -> wait until status changes
// timerMoving -> wait until status changes
// timerRemoving -> wait until status changes
// timerModifying -> wait until status changes
// adjusttimers (looks in P's timer heap):
// timerDeleted -> timerRemoving -> timerRemoved
// timerModifiedXX -> timerMoving -> timerWaiting
// timerModified -> timerMoving -> timerWaiting
// runtimer (looks in P's timer heap):
// timerNoStatus -> panic: uninitialized timer
// timerWaiting -> timerWaiting or
// timerWaiting -> timerRunning -> timerNoStatus or
// timerWaiting -> timerRunning -> timerWaiting
// timerModifying -> wait until status changes
// timerModifiedXX -> timerMoving -> timerWaiting
// timerModified -> timerMoving -> timerWaiting
// timerDeleted -> timerRemoving -> timerRemoved
// timerRunning -> panic: concurrent runtimer calls
// timerRemoved -> panic: inconsistent timer heap
@ -136,15 +135,11 @@ const (
// The timer will only have this status briefly.
timerModifying
// The timer has been modified to an earlier time.
// The timer has been modified to a different time.
// The new when value is in the nextwhen field.
// The timer is in some P's heap, possibly in the wrong place.
timerModifiedEarlier
// The timer has been modified to the same or a later time.
// The new when value is in the nextwhen field.
// The timer is in some P's heap, possibly in the wrong place.
timerModifiedLater
// The timer is in some P's heap, possibly in the wrong place
// (the right place by .when; the wrong place by .nextwhen).
timerModified
// The timer has been modified and is being moved.
// The timer will only have this status briefly.
@ -272,7 +267,7 @@ func doaddtimer(pp *p, t *timer) {
func deltimer(t *timer) bool {
for {
switch s := t.status.Load(); s {
case timerWaiting, timerModifiedLater:
case timerWaiting, timerModified:
// Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070.
mp := acquirem()
@ -291,24 +286,6 @@ func deltimer(t *timer) bool {
} else {
releasem(mp)
}
case timerModifiedEarlier:
// Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070.
mp := acquirem()
if t.status.CompareAndSwap(s, timerModifying) {
// Must fetch t.pp before setting status
// to timerDeleted.
tpp := t.pp.ptr()
if !t.status.CompareAndSwap(timerModifying, timerDeleted) {
badTimer()
}
releasem(mp)
tpp.deletedTimers.Add(1)
// Timer was not yet run.
return true
} else {
releasem(mp)
}
case timerDeleted, timerRemoving, timerRemoved:
// Timer was already run.
return false
@ -375,7 +352,7 @@ func modtimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq u
loop:
for {
switch status = t.status.Load(); status {
case timerWaiting, timerModifiedEarlier, timerModifiedLater:
case timerWaiting, timerModified:
// Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070.
mp = acquirem()
@ -442,26 +419,19 @@ loop:
// nextwhen field, and let the other P set the when field
// when it is prepared to resort the heap.
t.nextwhen = when
newStatus := uint32(timerModifiedLater)
if when < t.when {
newStatus = timerModifiedEarlier
}
tpp := t.pp.ptr()
if newStatus == timerModifiedEarlier {
updateTimerModifiedEarliest(tpp, when)
earlier := when < t.when
if earlier {
updateTimerModifiedEarliest(t.pp.ptr(), when)
}
// Set the new status of the timer.
if !t.status.CompareAndSwap(timerModifying, newStatus) {
if !t.status.CompareAndSwap(timerModifying, timerModified) {
badTimer()
}
releasem(mp)
// If the new status is earlier, wake up the poller.
if newStatus == timerModifiedEarlier {
if earlier {
wakeNetPoller(when)
}
}
@ -509,7 +479,7 @@ func cleantimers(pp *p) {
badTimer()
}
pp.deletedTimers.Add(-1)
case timerModifiedEarlier, timerModifiedLater:
case timerModified:
if !t.status.CompareAndSwap(s, timerMoving) {
continue
}
@ -568,7 +538,7 @@ func moveTimers(pp *p, timers []*timer) {
badTimer()
}
break loop
case timerModifiedEarlier, timerModifiedLater:
case timerModified:
if !t.status.CompareAndSwap(s, timerMoving) {
continue
}
@ -609,7 +579,7 @@ func moveTimers(pp *p, timers []*timer) {
// it also moves timers that have been modified to run later,
// and removes deleted timers. The caller must have locked the timers for pp.
func adjusttimers(pp *p, now int64, force bool) {
// If we haven't yet reached the time of the first timerModifiedEarlier
// If we haven't yet reached the time of the earliest timerModified
// timer, don't do anything. This speeds up programs that adjust
// a lot of timers back and forth if the timers rarely expire.
// We'll postpone looking through all the adjusted timers until
@ -624,7 +594,7 @@ func adjusttimers(pp *p, now int64, force bool) {
}
}
// We are going to clear all timerModifiedEarlier timers.
// We are going to clear all timerModified timers.
pp.timerModifiedEarliest.Store(0)
changed := false
@ -648,7 +618,7 @@ func adjusttimers(pp *p, now int64, force bool) {
i--
changed = true
}
case timerModifiedEarlier, timerModifiedLater:
case timerModified:
if t.status.CompareAndSwap(s, timerMoving) {
// Now we can change the when field.
t.when = t.nextwhen
@ -800,7 +770,7 @@ func runtimer(pp *p, now int64) int64 {
return -1
}
case timerModifiedEarlier, timerModifiedLater:
case timerModified:
if !t.status.CompareAndSwap(s, timerMoving) {
continue
}