aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/time.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2024-02-14 11:57:03 -0500
committerRuss Cox <rsc@golang.org>2024-02-28 16:44:11 +0000
commitd1e8dc25ff36694b5fdc8045325502e186b702f2 (patch)
tree10bf503a6f1f94f8f8cec90546b78f215c461dca /src/runtime/time.go
parent58911599e8dc25898c3017dd6655540fb9b976b1 (diff)
downloadgo-d1e8dc25ff36694b5fdc8045325502e186b702f2.tar.xz
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>
Diffstat (limited to 'src/runtime/time.go')
-rw-r--r--src/runtime/time.go99
1 files changed, 43 insertions, 56 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 2b82306812..f94ad99196 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -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 {
- 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.
- return t.when
- }
+Redo:
+ if len(pp.timers) == 0 {
+ return -1
+ }
+ t := pp.timers[0]
+ if t.pp.ptr() != pp {
+ throw("runtimer: bad p")
+ }
- if !t.status.CompareAndSwap(s, timerLocked) {
- continue
- }
- // Note that runOneTimer may temporarily unlock
- // pp.timersLock.
- runOneTimer(pp, t, now)
- return 0
+ 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
+ }
- case timerModified:
- if !t.status.CompareAndSwap(s, timerLocked) {
- continue
- }
- if t.nextwhen == 0 {
- dodeltimer0(pp)
- if !t.status.CompareAndSwap(timerLocked, timerRemoved) {
- badTimer()
- }
- 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, mp := t.lock()
+ if status == timerModified {
+ dodeltimer0(pp)
+ if t.nextwhen == 0 {
+ status = timerRemoved
+ pp.deletedTimers.Add(-1)
+ } else {
+ t.when = t.nextwhen
+ doaddtimer(pp, t)
+ status = timerWaiting
+ }
+ t.unlock(status, mp)
+ goto Redo
+ }
- case timerLocked:
- // Wait for modification to complete.
- osyield()
+ if status != timerWaiting {
+ badTimer()
+ }
- case timerRemoved:
- // Should not see a new or inactive timer on the heap.
- badTimer()
- default:
- badTimer()
- }
+ if t.when > now {
+ // Not ready to run.
+ t.unlock(status, mp)
+ return t.when
}
+
+ 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.
// 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.