// loop if gp->atomicstatus is in a scan state giving
// GC time to finish and change the state to oldval.
for !cas(&gp.atomicstatus, oldval, newval) {
- if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
- gp.preemptscan = false
- systemstack(func() {
- gcphasework(gp)
- })
- }
+ if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
+ systemstack(func() {
+ gothrow("casgstatus: waiting for Gwaiting but is Grunnable")
+ })
+ }
+ // Help GC if needed.
++ // if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
++ // gp.preemptscan = false
++ // systemstack(func() {
++ // gcphasework(gp)
++ // })
++ // }
+ }
+ }
+
+ // casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
+ // Returns old status. Cannot call casgstatus directly, because we are racing with an
+ // async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
+ // it might have become Grunnable by the time we get to the cas. If we called casgstatus,
+ // it would loop waiting for the status to go back to Gwaiting, which it never will.
+ //go:nosplit
+ func casgcopystack(gp *g) uint32 {
+ for {
+ oldstatus := readgstatus(gp) &^ _Gscan
+ if oldstatus != _Gwaiting && oldstatus != _Grunnable {
+ gothrow("copystack: bad status, not Gwaiting or Grunnable")
+ }
+ if cas(&gp.atomicstatus, oldstatus, _Gcopystack) {
+ return oldstatus
+ }
}
}
gothrow("stack overflow")
}
- oldstatus := readgstatus(gp)
- oldstatus &^= _Gscan
- casgstatus(gp, oldstatus, _Gcopystack) // oldstatus is Gwaiting or Grunnable
- // Note that the concurrent GC might be scanning the stack as we try to replace it.
- // copystack takes care of the appropriate coordination with the stack scanner.
++ casgstatus(gp, _Gwaiting, _Gcopystack)
+
+ // The concurrent GC will not scan the stack while we are doing the copy since
+ // the gp is in a Gcopystack status.
copystack(gp, uintptr(newsize))
if stackDebug >= 1 {
print("stack grow done\n")
if stackDebug > 0 {
print("shrinking stack ", oldsize, "->", newsize, "\n")
}
- // This is being done in a Gscan state and was initiated by the GC so no need to move to
- // the Gcopystate.
- // The world is stopped, so the goroutine must be Gwaiting or Grunnable,
- // and what it is is not changing underfoot.
- oldstatus := readgstatus(gp) &^ _Gscan
- if oldstatus != _Gwaiting && oldstatus != _Grunnable {
- gothrow("status is not Gwaiting or Grunnable")
- }
- casgstatus(gp, oldstatus, _Gcopystack)
+
++ oldstatus := casgcopystack(gp)
copystack(gp, newsize)
+ casgstatus(gp, _Gcopystack, oldstatus)
}
// Do any delayed stack freeing that was queued up during GC.