if !atomic.Cas(&mp.preemptExtLock, 0, 1) {
// External code is running. Fail the preemption
// attempt.
- atomic.Xadd(&mp.preemptGen, 1)
+ mp.preemptGen.Add(1)
return
}
// The M hasn't been minit'd yet (or was just unminit'd).
unlock(&mp.threadLock)
atomic.Store(&mp.preemptExtLock, 0)
- atomic.Xadd(&mp.preemptGen, 1)
+ mp.preemptGen.Add(1)
return
}
var thread uintptr
atomic.Store(&mp.preemptExtLock, 0)
// The thread no longer exists. This shouldn't be
// possible, but just acknowledge the request.
- atomic.Xadd(&mp.preemptGen, 1)
+ mp.preemptGen.Add(1)
return
}
atomic.Store(&mp.preemptExtLock, 0)
// Acknowledge the preemption.
- atomic.Xadd(&mp.preemptGen, 1)
+ mp.preemptGen.Add(1)
stdcall1(_ResumeThread, thread)
stdcall1(_CloseHandle, thread)
import (
"internal/abi"
"internal/goarch"
- "runtime/internal/atomic"
)
type suspendGState struct {
case _Grunning:
// Optimization: if there is already a pending preemption request
// (from the previous loop iteration), don't bother with the atomics.
- if gp.preemptStop && gp.preempt && gp.stackguard0 == stackPreempt && asyncM == gp.m && atomic.Load(&asyncM.preemptGen) == asyncGen {
+ if gp.preemptStop && gp.preempt && gp.stackguard0 == stackPreempt && asyncM == gp.m && asyncM.preemptGen.Load() == asyncGen {
break
}
// Prepare for asynchronous preemption.
asyncM2 := gp.m
- asyncGen2 := atomic.Load(&asyncM2.preemptGen)
+ asyncGen2 := asyncM2.preemptGen.Load()
needAsync := asyncM != asyncM2 || asyncGen != asyncGen2
asyncM = asyncM2
asyncGen = asyncGen2
// preemptGen counts the number of completed preemption
// signals. This is used to detect when a preemption is
- // requested, but fails. Accessed atomically.
- preemptGen uint32
+ // requested, but fails.
+ preemptGen atomic.Uint32
// Whether this is a pending preemption signal on this M.
signalPending atomic.Uint32
}
// Acknowledge the preemption.
- atomic.Xadd(&gp.m.preemptGen, 1)
+ gp.m.preemptGen.Add(1)
gp.m.signalPending.Store(0)
if GOOS == "darwin" || GOOS == "ios" {