1
0
mirror of https://github.com/golang/go synced 2024-11-18 09:04:49 -07:00

runtime: convert timer.status to atomic type

This commit is contained in:
cui fliter 2022-09-05 00:21:30 +08:00
parent 535fe2b226
commit ddfce125be

View File

@ -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