1
0
mirror of https://github.com/golang/go synced 2024-11-18 10:04:43 -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 nextwhen int64
// The status field holds one of the values below. // 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. // 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) goready(arg.(*g), 0)
} }
// Note: this changes some unsynchronized operations to synchronized operations
// addtimer adds a timer to the current P. // addtimer adds a timer to the current P.
// This should only be called with a newly created timer. // 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, // 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 { if t.period < 0 {
throw("timer period must be non-negative") throw("timer period must be non-negative")
} }
if t.status != timerNoStatus { if t.status.Load() != timerNoStatus {
throw("addtimer called with initialized timer") throw("addtimer called with initialized timer")
} }
t.status = timerWaiting t.status.Store(timerWaiting)
when := t.when when := t.when
@ -312,17 +313,17 @@ func doaddtimer(pp *p, t *timer) {
// Reports whether the timer was removed before it was run. // Reports whether the timer was removed before it was run.
func deltimer(t *timer) bool { func deltimer(t *timer) bool {
for { for {
switch s := atomic.Load(&t.status); s { switch s := t.status.Load(); s {
case timerWaiting, timerModifiedLater: case timerWaiting, timerModifiedLater:
// Prevent preemption while the timer is in timerModifying. // Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070. // This could lead to a self-deadlock. See #38070.
mp := acquirem() mp := acquirem()
if atomic.Cas(&t.status, s, timerModifying) { if t.status.CompareAndSwap(s, timerModifying) {
// Must fetch t.pp before changing status, // Must fetch t.pp before changing status,
// as cleantimers in another goroutine // as cleantimers in another goroutine
// can clear t.pp of a timerDeleted timer. // can clear t.pp of a timerDeleted timer.
tpp := t.pp.ptr() tpp := t.pp.ptr()
if !atomic.Cas(&t.status, timerModifying, timerDeleted) { if !t.status.CompareAndSwap(timerModifying, timerDeleted) {
badTimer() badTimer()
} }
releasem(mp) releasem(mp)
@ -336,11 +337,11 @@ func deltimer(t *timer) bool {
// Prevent preemption while the timer is in timerModifying. // Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070. // This could lead to a self-deadlock. See #38070.
mp := acquirem() mp := acquirem()
if atomic.Cas(&t.status, s, timerModifying) { if t.status.CompareAndSwap(s, timerModifying) {
// Must fetch t.pp before setting status // Must fetch t.pp before setting status
// to timerDeleted. // to timerDeleted.
tpp := t.pp.ptr() tpp := t.pp.ptr()
if !atomic.Cas(&t.status, timerModifying, timerDeleted) { if !t.status.CompareAndSwap(timerModifying, timerDeleted) {
badTimer() badTimer()
} }
releasem(mp) releasem(mp)
@ -449,12 +450,12 @@ func modtimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq u
var mp *m var mp *m
loop: loop:
for { for {
switch status = atomic.Load(&t.status); status { switch status = t.status.Load(); status {
case timerWaiting, timerModifiedEarlier, timerModifiedLater: case timerWaiting, timerModifiedEarlier, timerModifiedLater:
// Prevent preemption while the timer is in timerModifying. // Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070. // This could lead to a self-deadlock. See #38070.
mp = acquirem() mp = acquirem()
if atomic.Cas(&t.status, status, timerModifying) { if t.status.CompareAndSwap(status, timerModifying) {
pending = true // timer not yet run pending = true // timer not yet run
break loop break loop
} }
@ -466,7 +467,7 @@ loop:
// Timer was already run and t is no longer in a heap. // Timer was already run and t is no longer in a heap.
// Act like addtimer. // Act like addtimer.
if atomic.Cas(&t.status, status, timerModifying) { if t.status.CompareAndSwap(status, timerModifying) {
wasRemoved = true wasRemoved = true
pending = false // timer already run or stopped pending = false // timer already run or stopped
break loop break loop
@ -476,7 +477,7 @@ loop:
// Prevent preemption while the timer is in timerModifying. // Prevent preemption while the timer is in timerModifying.
// This could lead to a self-deadlock. See #38070. // This could lead to a self-deadlock. See #38070.
mp = acquirem() mp = acquirem()
if atomic.Cas(&t.status, status, timerModifying) { if t.status.CompareAndSwap(status, timerModifying) {
t.pp.ptr().deletedTimers.Add(-1) t.pp.ptr().deletedTimers.Add(-1)
pending = false // timer already stopped pending = false // timer already stopped
break loop break loop
@ -506,7 +507,7 @@ loop:
lock(&pp.timersLock) lock(&pp.timersLock)
doaddtimer(pp, t) doaddtimer(pp, t)
unlock(&pp.timersLock) unlock(&pp.timersLock)
if !atomic.Cas(&t.status, timerModifying, timerWaiting) { if !t.status.CompareAndSwap(timerModifying, timerWaiting) {
badTimer() badTimer()
} }
releasem(mp) releasem(mp)
@ -531,7 +532,7 @@ loop:
} }
// Set the new status of the timer. // Set the new status of the timer.
if !atomic.Cas(&t.status, timerModifying, newStatus) { if !t.status.CompareAndSwap(timerModifying, newStatus) {
badTimer() badTimer()
} }
releasem(mp) releasem(mp)
@ -577,18 +578,18 @@ func cleantimers(pp *p) {
if t.pp.ptr() != pp { if t.pp.ptr() != pp {
throw("cleantimers: bad p") throw("cleantimers: bad p")
} }
switch s := atomic.Load(&t.status); s { switch s := t.status.Load(); s {
case timerDeleted: case timerDeleted:
if !atomic.Cas(&t.status, s, timerRemoving) { if !t.status.CompareAndSwap(s, timerRemoving) {
continue continue
} }
dodeltimer0(pp) dodeltimer0(pp)
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) { if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
badTimer() badTimer()
} }
pp.deletedTimers.Add(-1) pp.deletedTimers.Add(-1)
case timerModifiedEarlier, timerModifiedLater: case timerModifiedEarlier, timerModifiedLater:
if !atomic.Cas(&t.status, s, timerMoving) { if !t.status.CompareAndSwap(s, timerMoving) {
continue continue
} }
// Now we can change the when field. // Now we can change the when field.
@ -596,7 +597,7 @@ func cleantimers(pp *p) {
// Move t to the right position. // Move t to the right position.
dodeltimer0(pp) dodeltimer0(pp)
doaddtimer(pp, t) doaddtimer(pp, t)
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
badTimer() badTimer()
} }
default: default:
@ -614,30 +615,30 @@ func moveTimers(pp *p, timers []*timer) {
for _, t := range timers { for _, t := range timers {
loop: loop:
for { for {
switch s := atomic.Load(&t.status); s { switch s := t.status.Load(); s {
case timerWaiting: case timerWaiting:
if !atomic.Cas(&t.status, s, timerMoving) { if !t.status.CompareAndSwap(s, timerMoving) {
continue continue
} }
t.pp = 0 t.pp = 0
doaddtimer(pp, t) doaddtimer(pp, t)
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
badTimer() badTimer()
} }
break loop break loop
case timerModifiedEarlier, timerModifiedLater: case timerModifiedEarlier, timerModifiedLater:
if !atomic.Cas(&t.status, s, timerMoving) { if !t.status.CompareAndSwap(s, timerMoving) {
continue continue
} }
t.when = t.nextwhen t.when = t.nextwhen
t.pp = 0 t.pp = 0
doaddtimer(pp, t) doaddtimer(pp, t)
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
badTimer() badTimer()
} }
break loop break loop
case timerDeleted: case timerDeleted:
if !atomic.Cas(&t.status, s, timerRemoved) { if !t.status.CompareAndSwap(s, timerRemoved) {
continue continue
} }
t.pp = 0 t.pp = 0
@ -688,11 +689,11 @@ func adjusttimers(pp *p, now int64) {
if t.pp.ptr() != pp { if t.pp.ptr() != pp {
throw("adjusttimers: bad p") throw("adjusttimers: bad p")
} }
switch s := atomic.Load(&t.status); s { switch s := t.status.Load(); s {
case timerDeleted: case timerDeleted:
if atomic.Cas(&t.status, s, timerRemoving) { if t.status.CompareAndSwap(s, timerRemoving) {
changed := dodeltimer(pp, i) changed := dodeltimer(pp, i)
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) { if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
badTimer() badTimer()
} }
pp.deletedTimers.Add(-1) pp.deletedTimers.Add(-1)
@ -701,7 +702,7 @@ func adjusttimers(pp *p, now int64) {
i = changed - 1 i = changed - 1
} }
case timerModifiedEarlier, timerModifiedLater: case timerModifiedEarlier, timerModifiedLater:
if atomic.Cas(&t.status, s, timerMoving) { if t.status.CompareAndSwap(s, timerMoving) {
// Now we can change the when field. // Now we can change the when field.
t.when = t.nextwhen t.when = t.nextwhen
// Take t off the heap, and hold onto it. // 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) { func addAdjustedTimers(pp *p, moved []*timer) {
for _, t := range moved { for _, t := range moved {
doaddtimer(pp, t) doaddtimer(pp, t)
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
badTimer() badTimer()
} }
} }
@ -776,14 +777,14 @@ func runtimer(pp *p, now int64) int64 {
if t.pp.ptr() != pp { if t.pp.ptr() != pp {
throw("runtimer: bad p") throw("runtimer: bad p")
} }
switch s := atomic.Load(&t.status); s { switch s := t.status.Load(); s {
case timerWaiting: case timerWaiting:
if t.when > now { if t.when > now {
// Not ready to run. // Not ready to run.
return t.when return t.when
} }
if !atomic.Cas(&t.status, s, timerRunning) { if !t.status.CompareAndSwap(s, timerRunning) {
continue continue
} }
// Note that runOneTimer may temporarily unlock // Note that runOneTimer may temporarily unlock
@ -792,11 +793,11 @@ func runtimer(pp *p, now int64) int64 {
return 0 return 0
case timerDeleted: case timerDeleted:
if !atomic.Cas(&t.status, s, timerRemoving) { if !t.status.CompareAndSwap(s, timerRemoving) {
continue continue
} }
dodeltimer0(pp) dodeltimer0(pp)
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) { if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
badTimer() badTimer()
} }
pp.deletedTimers.Add(-1) pp.deletedTimers.Add(-1)
@ -805,13 +806,13 @@ func runtimer(pp *p, now int64) int64 {
} }
case timerModifiedEarlier, timerModifiedLater: case timerModifiedEarlier, timerModifiedLater:
if !atomic.Cas(&t.status, s, timerMoving) { if !t.status.CompareAndSwap(s, timerMoving) {
continue continue
} }
t.when = t.nextwhen t.when = t.nextwhen
dodeltimer0(pp) dodeltimer0(pp)
doaddtimer(pp, t) doaddtimer(pp, t)
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
badTimer() badTimer()
} }
@ -858,14 +859,14 @@ func runOneTimer(pp *p, t *timer, now int64) {
t.when = maxWhen t.when = maxWhen
} }
siftdownTimer(pp.timers, 0) siftdownTimer(pp.timers, 0)
if !atomic.Cas(&t.status, timerRunning, timerWaiting) { if !t.status.CompareAndSwap(timerRunning, timerWaiting) {
badTimer() badTimer()
} }
updateTimer0When(pp) updateTimer0When(pp)
} else { } else {
// Remove from heap. // Remove from heap.
dodeltimer0(pp) dodeltimer0(pp)
if !atomic.Cas(&t.status, timerRunning, timerNoStatus) { if !t.status.CompareAndSwap(timerRunning, timerNoStatus) {
badTimer() badTimer()
} }
} }
@ -912,7 +913,7 @@ func clearDeletedTimers(pp *p) {
nextTimer: nextTimer:
for _, t := range timers { for _, t := range timers {
for { for {
switch s := atomic.Load(&t.status); s { switch s := t.status.Load(); s {
case timerWaiting: case timerWaiting:
if changedHeap { if changedHeap {
timers[to] = t timers[to] = t
@ -921,22 +922,22 @@ nextTimer:
to++ to++
continue nextTimer continue nextTimer
case timerModifiedEarlier, timerModifiedLater: case timerModifiedEarlier, timerModifiedLater:
if atomic.Cas(&t.status, s, timerMoving) { if t.status.CompareAndSwap(s, timerMoving) {
t.when = t.nextwhen t.when = t.nextwhen
timers[to] = t timers[to] = t
siftupTimer(timers, to) siftupTimer(timers, to)
to++ to++
changedHeap = true changedHeap = true
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
badTimer() badTimer()
} }
continue nextTimer continue nextTimer
} }
case timerDeleted: case timerDeleted:
if atomic.Cas(&t.status, s, timerRemoving) { if t.status.CompareAndSwap(s, timerRemoving) {
t.pp = 0 t.pp = 0
cdel++ cdel++
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) { if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
badTimer() badTimer()
} }
changedHeap = true changedHeap = true