}
func scanstack(gp *g) {
- // TODO(rsc): Due to a precedence error, this was never checked in the original C version.
- // If you enable the check, the gothrow happens.
- /*
- if readgstatus(gp)&_Gscan == 0 {
- print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
- gothrow("mark - bad status")
- }
- */
+
+ if readgstatus(gp)&_Gscan == 0 {
+ print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n")
+ gothrow("scanstack - bad status")
+ }
switch readgstatus(gp) &^ _Gscan {
default:
// Check that transition is valid.
switch oldval {
+ default:
+ print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
+ dumpgstatus(gp)
+ gothrow("casfrom_Gscanstatus:top gp->status is not in scan state")
case _Gscanrunnable,
_Gscanwaiting,
_Gscanrunning,
return false
case _Grunning:
- if gcphase == _GCscan {
- // Running routines not scanned during
- // GCscan phase, we only scan non-running routines.
- gp.gcworkdone = true
- return false
- }
-
// Claim goroutine, so we aren't racing with a status
// transition away from Grunning.
if !castogscanstatus(gp, _Grunning, _Gscanrunning) {
gothrow("runtime: g is running but p is not")
}
if gp.preemptscan {
+ for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) {
+ // Likely to be racing with the GC as it sees a _Gwaiting and does the stack scan.
+ // If so this stack will be scanned twice which does not change correctness.
+ }
gcphasework(gp)
+ casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting)
casgstatus(gp, _Gwaiting, _Grunning)
gp.stackguard0 = gp.stack.lo + _StackGuard
gp.preempt = false