// All reads and writes of g's status go through readgstatus, casgstatus // castogscanstatus, casfrom_Gscanstatus. //go:nosplit funcreadgstatus(gp *g)uint32 { return atomic.Load(&gp.atomicstatus) }
// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus // and casfrom_Gscanstatus instead. // casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that // put it in the Gscan state is finished. //go:nosplit funccasgstatus(gp *g, oldval, newval uint32) { if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval { systemstack(func() { print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n") throw("casgstatus: bad incoming values") }) }
// See https://golang.org/cl/21503 for justification of the yield delay. const yieldDelay = 5 * 1000 var nextYield int64
// loop if gp->atomicstatus is in a scan state giving // GC time to finish and change the state to oldval. // 等待GC完成后变成_Grunning,然后再改变值,变为_Grunnable for i := 0; !atomic.Cas(&gp.atomicstatus, oldval, newval); i++ { if oldval == _Gwaiting && gp.atomicstatus == _Grunnable { throw("casgstatus: waiting for Gwaiting but is Grunnable") } if i == 0 { nextYield = nanotime() + yieldDelay } if nanotime() < nextYield { for x := 0; x < 10 && gp.atomicstatus != oldval; x++ { procyield(1) } } else { osyield() nextYield = nanotime() + yieldDelay/2 } } }
// dropg removes the association between m and the current goroutine m->curg (gp for short). // Typically a caller sets gp's status away from Grunning and then // immediately calls dropg to finish the job. The caller is also responsible // for arranging that gp will be restarted using ready at an // appropriate time. After calling dropg and arranging for gp to be // readied later, the caller can do other work but eventually should // call schedule to restart the scheduling of goroutines on this m. funcdropg() { _g_ := getg()
// Put gp on the global runnable queue. // Sched must be locked. // May run during STW, so write barriers are not allowed. //go:nowritebarrierrec funcglobrunqput(gp *g) { //将G放回全局队列中 sched.runq.pushBack(gp) sched.runqsize++ }