mirror of
https://github.com/golang/go
synced 2024-11-18 09:04:49 -07:00
runtime: convert timer.status to atomic type
For #53821
Change-Id: I7cb6a16626964d5023b96609d9921bfe4a679d8f
GitHub-Last-Rev: ddfce125be
GitHub-Pull-Request: golang/go#54865
Reviewed-on: https://go-review.googlesource.com/c/go/+/428196
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Jenny Rakoczy <jenny@golang.org>
Auto-Submit: Jenny Rakoczy <jenny@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Michael Pratt <mpratt@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
39b31a3eb2
commit
f78efc0178
@ -36,7 +36,7 @@ type timer struct {
|
||||
nextwhen int64
|
||||
|
||||
// The status field holds one of the values below.
|
||||
status uint32
|
||||
status atomic.Uint32
|
||||
}
|
||||
|
||||
// Code outside this file has to be careful in using a timer value.
|
||||
@ -249,6 +249,7 @@ func goroutineReady(arg any, seq uintptr) {
|
||||
goready(arg.(*g), 0)
|
||||
}
|
||||
|
||||
// Note: this changes some unsynchronized operations to synchronized operations
|
||||
// addtimer adds a timer to the current P.
|
||||
// This should only be called with a newly created timer.
|
||||
// That avoids the risk of changing the when field of a timer in some P's heap,
|
||||
@ -263,10 +264,10 @@ func addtimer(t *timer) {
|
||||
if t.period < 0 {
|
||||
throw("timer period must be non-negative")
|
||||
}
|
||||
if t.status != timerNoStatus {
|
||||
if t.status.Load() != timerNoStatus {
|
||||
throw("addtimer called with initialized timer")
|
||||
}
|
||||
t.status = timerWaiting
|
||||
t.status.Store(timerWaiting)
|
||||
|
||||
when := t.when
|
||||
|
||||
@ -312,17 +313,17 @@ func doaddtimer(pp *p, t *timer) {
|
||||
// Reports whether the timer was removed before it was run.
|
||||
func deltimer(t *timer) bool {
|
||||
for {
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
switch s := t.status.Load(); s {
|
||||
case timerWaiting, timerModifiedLater:
|
||||
// Prevent preemption while the timer is in timerModifying.
|
||||
// This could lead to a self-deadlock. See #38070.
|
||||
mp := acquirem()
|
||||
if atomic.Cas(&t.status, s, timerModifying) {
|
||||
if t.status.CompareAndSwap(s, timerModifying) {
|
||||
// Must fetch t.pp before changing status,
|
||||
// as cleantimers in another goroutine
|
||||
// can clear t.pp of a timerDeleted timer.
|
||||
tpp := t.pp.ptr()
|
||||
if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
|
||||
if !t.status.CompareAndSwap(timerModifying, timerDeleted) {
|
||||
badTimer()
|
||||
}
|
||||
releasem(mp)
|
||||
@ -336,11 +337,11 @@ func deltimer(t *timer) bool {
|
||||
// Prevent preemption while the timer is in timerModifying.
|
||||
// This could lead to a self-deadlock. See #38070.
|
||||
mp := acquirem()
|
||||
if atomic.Cas(&t.status, s, timerModifying) {
|
||||
if t.status.CompareAndSwap(s, timerModifying) {
|
||||
// Must fetch t.pp before setting status
|
||||
// to timerDeleted.
|
||||
tpp := t.pp.ptr()
|
||||
if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
|
||||
if !t.status.CompareAndSwap(timerModifying, timerDeleted) {
|
||||
badTimer()
|
||||
}
|
||||
releasem(mp)
|
||||
@ -449,12 +450,12 @@ func modtimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq u
|
||||
var mp *m
|
||||
loop:
|
||||
for {
|
||||
switch status = atomic.Load(&t.status); status {
|
||||
switch status = t.status.Load(); status {
|
||||
case timerWaiting, timerModifiedEarlier, timerModifiedLater:
|
||||
// Prevent preemption while the timer is in timerModifying.
|
||||
// This could lead to a self-deadlock. See #38070.
|
||||
mp = acquirem()
|
||||
if atomic.Cas(&t.status, status, timerModifying) {
|
||||
if t.status.CompareAndSwap(status, timerModifying) {
|
||||
pending = true // timer not yet run
|
||||
break loop
|
||||
}
|
||||
@ -466,7 +467,7 @@ loop:
|
||||
|
||||
// Timer was already run and t is no longer in a heap.
|
||||
// Act like addtimer.
|
||||
if atomic.Cas(&t.status, status, timerModifying) {
|
||||
if t.status.CompareAndSwap(status, timerModifying) {
|
||||
wasRemoved = true
|
||||
pending = false // timer already run or stopped
|
||||
break loop
|
||||
@ -476,7 +477,7 @@ loop:
|
||||
// Prevent preemption while the timer is in timerModifying.
|
||||
// This could lead to a self-deadlock. See #38070.
|
||||
mp = acquirem()
|
||||
if atomic.Cas(&t.status, status, timerModifying) {
|
||||
if t.status.CompareAndSwap(status, timerModifying) {
|
||||
t.pp.ptr().deletedTimers.Add(-1)
|
||||
pending = false // timer already stopped
|
||||
break loop
|
||||
@ -506,7 +507,7 @@ loop:
|
||||
lock(&pp.timersLock)
|
||||
doaddtimer(pp, t)
|
||||
unlock(&pp.timersLock)
|
||||
if !atomic.Cas(&t.status, timerModifying, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerModifying, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
releasem(mp)
|
||||
@ -531,7 +532,7 @@ loop:
|
||||
}
|
||||
|
||||
// Set the new status of the timer.
|
||||
if !atomic.Cas(&t.status, timerModifying, newStatus) {
|
||||
if !t.status.CompareAndSwap(timerModifying, newStatus) {
|
||||
badTimer()
|
||||
}
|
||||
releasem(mp)
|
||||
@ -577,18 +578,18 @@ func cleantimers(pp *p) {
|
||||
if t.pp.ptr() != pp {
|
||||
throw("cleantimers: bad p")
|
||||
}
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
switch s := t.status.Load(); s {
|
||||
case timerDeleted:
|
||||
if !atomic.Cas(&t.status, s, timerRemoving) {
|
||||
if !t.status.CompareAndSwap(s, timerRemoving) {
|
||||
continue
|
||||
}
|
||||
dodeltimer0(pp)
|
||||
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
|
||||
if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
pp.deletedTimers.Add(-1)
|
||||
case timerModifiedEarlier, timerModifiedLater:
|
||||
if !atomic.Cas(&t.status, s, timerMoving) {
|
||||
if !t.status.CompareAndSwap(s, timerMoving) {
|
||||
continue
|
||||
}
|
||||
// Now we can change the when field.
|
||||
@ -596,7 +597,7 @@ func cleantimers(pp *p) {
|
||||
// Move t to the right position.
|
||||
dodeltimer0(pp)
|
||||
doaddtimer(pp, t)
|
||||
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
default:
|
||||
@ -614,30 +615,30 @@ func moveTimers(pp *p, timers []*timer) {
|
||||
for _, t := range timers {
|
||||
loop:
|
||||
for {
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
switch s := t.status.Load(); s {
|
||||
case timerWaiting:
|
||||
if !atomic.Cas(&t.status, s, timerMoving) {
|
||||
if !t.status.CompareAndSwap(s, timerMoving) {
|
||||
continue
|
||||
}
|
||||
t.pp = 0
|
||||
doaddtimer(pp, t)
|
||||
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
break loop
|
||||
case timerModifiedEarlier, timerModifiedLater:
|
||||
if !atomic.Cas(&t.status, s, timerMoving) {
|
||||
if !t.status.CompareAndSwap(s, timerMoving) {
|
||||
continue
|
||||
}
|
||||
t.when = t.nextwhen
|
||||
t.pp = 0
|
||||
doaddtimer(pp, t)
|
||||
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
break loop
|
||||
case timerDeleted:
|
||||
if !atomic.Cas(&t.status, s, timerRemoved) {
|
||||
if !t.status.CompareAndSwap(s, timerRemoved) {
|
||||
continue
|
||||
}
|
||||
t.pp = 0
|
||||
@ -688,11 +689,11 @@ func adjusttimers(pp *p, now int64) {
|
||||
if t.pp.ptr() != pp {
|
||||
throw("adjusttimers: bad p")
|
||||
}
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
switch s := t.status.Load(); s {
|
||||
case timerDeleted:
|
||||
if atomic.Cas(&t.status, s, timerRemoving) {
|
||||
if t.status.CompareAndSwap(s, timerRemoving) {
|
||||
changed := dodeltimer(pp, i)
|
||||
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
|
||||
if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
pp.deletedTimers.Add(-1)
|
||||
@ -701,7 +702,7 @@ func adjusttimers(pp *p, now int64) {
|
||||
i = changed - 1
|
||||
}
|
||||
case timerModifiedEarlier, timerModifiedLater:
|
||||
if atomic.Cas(&t.status, s, timerMoving) {
|
||||
if t.status.CompareAndSwap(s, timerMoving) {
|
||||
// Now we can change the when field.
|
||||
t.when = t.nextwhen
|
||||
// Take t off the heap, and hold onto it.
|
||||
@ -741,7 +742,7 @@ func adjusttimers(pp *p, now int64) {
|
||||
func addAdjustedTimers(pp *p, moved []*timer) {
|
||||
for _, t := range moved {
|
||||
doaddtimer(pp, t)
|
||||
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
}
|
||||
@ -776,14 +777,14 @@ func runtimer(pp *p, now int64) int64 {
|
||||
if t.pp.ptr() != pp {
|
||||
throw("runtimer: bad p")
|
||||
}
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
switch s := t.status.Load(); s {
|
||||
case timerWaiting:
|
||||
if t.when > now {
|
||||
// Not ready to run.
|
||||
return t.when
|
||||
}
|
||||
|
||||
if !atomic.Cas(&t.status, s, timerRunning) {
|
||||
if !t.status.CompareAndSwap(s, timerRunning) {
|
||||
continue
|
||||
}
|
||||
// Note that runOneTimer may temporarily unlock
|
||||
@ -792,11 +793,11 @@ func runtimer(pp *p, now int64) int64 {
|
||||
return 0
|
||||
|
||||
case timerDeleted:
|
||||
if !atomic.Cas(&t.status, s, timerRemoving) {
|
||||
if !t.status.CompareAndSwap(s, timerRemoving) {
|
||||
continue
|
||||
}
|
||||
dodeltimer0(pp)
|
||||
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
|
||||
if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
pp.deletedTimers.Add(-1)
|
||||
@ -805,13 +806,13 @@ func runtimer(pp *p, now int64) int64 {
|
||||
}
|
||||
|
||||
case timerModifiedEarlier, timerModifiedLater:
|
||||
if !atomic.Cas(&t.status, s, timerMoving) {
|
||||
if !t.status.CompareAndSwap(s, timerMoving) {
|
||||
continue
|
||||
}
|
||||
t.when = t.nextwhen
|
||||
dodeltimer0(pp)
|
||||
doaddtimer(pp, t)
|
||||
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
|
||||
@ -858,14 +859,14 @@ func runOneTimer(pp *p, t *timer, now int64) {
|
||||
t.when = maxWhen
|
||||
}
|
||||
siftdownTimer(pp.timers, 0)
|
||||
if !atomic.Cas(&t.status, timerRunning, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerRunning, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
updateTimer0When(pp)
|
||||
} else {
|
||||
// Remove from heap.
|
||||
dodeltimer0(pp)
|
||||
if !atomic.Cas(&t.status, timerRunning, timerNoStatus) {
|
||||
if !t.status.CompareAndSwap(timerRunning, timerNoStatus) {
|
||||
badTimer()
|
||||
}
|
||||
}
|
||||
@ -912,7 +913,7 @@ func clearDeletedTimers(pp *p) {
|
||||
nextTimer:
|
||||
for _, t := range timers {
|
||||
for {
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
switch s := t.status.Load(); s {
|
||||
case timerWaiting:
|
||||
if changedHeap {
|
||||
timers[to] = t
|
||||
@ -921,22 +922,22 @@ nextTimer:
|
||||
to++
|
||||
continue nextTimer
|
||||
case timerModifiedEarlier, timerModifiedLater:
|
||||
if atomic.Cas(&t.status, s, timerMoving) {
|
||||
if t.status.CompareAndSwap(s, timerMoving) {
|
||||
t.when = t.nextwhen
|
||||
timers[to] = t
|
||||
siftupTimer(timers, to)
|
||||
to++
|
||||
changedHeap = true
|
||||
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
|
||||
if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
|
||||
badTimer()
|
||||
}
|
||||
continue nextTimer
|
||||
}
|
||||
case timerDeleted:
|
||||
if atomic.Cas(&t.status, s, timerRemoving) {
|
||||
if t.status.CompareAndSwap(s, timerRemoving) {
|
||||
t.pp = 0
|
||||
cdel++
|
||||
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
|
||||
if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
changedHeap = true
|
||||
|
Loading…
Reference in New Issue
Block a user