for {
switch s := atomic.Load(&t.status); 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) {
// Must fetch t.pp before changing status,
// as cleantimers in another goroutine
if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
badTimer()
}
+ releasem(mp)
atomic.Xadd(&tpp.deletedTimers, 1)
// Timer was not yet run.
return true
+ } 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 atomic.Cas(&t.status, s, timerModifying) {
// Must fetch t.pp before setting status
// to timerDeleted.
if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
badTimer()
}
+ releasem(mp)
atomic.Xadd(&tpp.deletedTimers, 1)
// Timer was not yet run.
return true
+ } else {
+ releasem(mp)
}
case timerDeleted, timerRemoving, timerRemoved:
// Timer was already run.
status := uint32(timerNoStatus)
wasRemoved := false
+ var mp *m
loop:
for {
switch status = atomic.Load(&t.status); 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) {
break loop
}
+ releasem(mp)
case timerNoStatus, timerRemoved:
+ // Prevent preemption while the timer is in timerModifying.
+ // This could lead to a self-deadlock. See #38070.
+ mp = acquirem()
+
// Timer was already run and t is no longer in a heap.
// Act like addtimer.
if atomic.Cas(&t.status, status, timerModifying) {
wasRemoved = true
break loop
}
+ releasem(mp)
case timerDeleted:
+ // 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) {
atomic.Xadd(&t.pp.ptr().deletedTimers, -1)
break loop
}
+ releasem(mp)
case timerRunning, timerRemoving, timerMoving:
// The timer is being run or moved, by a different P.
// Wait for it to complete.
if !atomic.Cas(&t.status, timerModifying, timerWaiting) {
badTimer()
}
+ releasem(mp)
wakeNetPoller(when)
} else {
// The timer is in some other P's heap, so we can't change
if !atomic.Cas(&t.status, timerModifying, newStatus) {
badTimer()
}
+ releasem(mp)
// If the new status is earlier, wake up the poller.
if newStatus == timerModifiedEarlier {