gogo
gogo 由汇编实现,次要是由 g0 切换到 g 栈,而后执行函数。
// func gogo(buf *gobuf)
// restore state from Gobuf; longjmp
TEXT runtime·gogo(SB), NOSPLIT, $16-8
MOVQ buf+0(FP), BX // gobuf
MOVQ gobuf_g(BX), DX
MOVQ 0(DX), CX // make sure g != nil
get_tls(CX)
MOVQ DX, g(CX)
MOVQ gobuf_sp(BX), SP // restore SP, 复原 sp 寄存器值切换到 g 栈
MOVQ gobuf_ret(BX), AX
MOVQ gobuf_ctxt(BX), DX
MOVQ gobuf_bp(BX), BP
MOVQ $0, gobuf_sp(BX) // clear to help garbage collector
MOVQ $0, gobuf_ret(BX)
MOVQ $0, gobuf_ctxt(BX)
MOVQ $0, gobuf_bp(BX)
MOVQ gobuf_pc(BX), BX // 获取 G 工作函数的地址
JMP BX // 转到工作函数执行
goexit
当调用工作函数完结返回的时候,会执行到咱们在创立 g 流程中就初始化好的指令:goexit
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return 调用 goexit1 函数
// traceback from goexit1 must hit code range of goexit
BYTE $0x90 // NOP
// Finishes execution of the current goroutine.
func goexit1() {
if raceenabled {racegoend()
}
if trace.enabled {traceGoEnd()
}
mcall(goexit0) // 切换到 g0 执行 goexit0
}
// goexit continuation on g0.
func goexit0(gp *g) {_g_ := getg()
// gp 的状态置为_Gdead
casgstatus(gp, _Grunning, _Gdead)
if isSystemGoroutine(gp, false) {atomic.Xadd(&sched.ngsys, -1)
}
// 状态重置
gp.m = nil
// G 和 M 是否锁定
locked := gp.lockedm != 0
// G 和 M 解除锁定
gp.lockedm = 0
_g_.m.lockedg = 0
gp.preemptStop = false
gp.paniconfault = false
gp._defer = nil // should be true already but just in case.
gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
gp.writebuf = nil
gp.waitreason = 0
gp.param = nil
gp.labels = nil
gp.timer = nil
if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 {
// Flush assist credit to the global pool. This gives
// better information to pacing if the application is
// rapidly creating an exiting goroutines.
assistWorkPerByte := float64frombits(atomic.Load64(&gcController.assistWorkPerByte))
scanCredit := int64(assistWorkPerByte * float64(gp.gcAssistBytes))
atomic.Xaddint64(&gcController.bgScanCredit, scanCredit)
gp.gcAssistBytes = 0
}
// 解决 G 和 M 的革除工作
dropg()
if GOARCH == "wasm" { // no threads yet on wasm
gfput(_g_.m.p.ptr(), gp)
schedule() // never returns}
if _g_.m.lockedInt != 0 {print("invalid m->lockedInt =", _g_.m.lockedInt, "\n")
throw("internal lockOSThread error")
}
// 将 G 放入 P 的 G 闲暇链表
gfput(_g_.m.p.ptr(), gp)
if locked {
// The goroutine may have locked this thread because
// it put it in an unusual kernel state. Kill it
// rather than returning it to the thread pool.
// Return to mstart, which will release the P and exit
// the thread.
if GOOS != "plan9" { // See golang.org/issue/22227.
gogo(&_g_.m.g0.sched)
} else {
// Clear lockedExt on plan9 since we may end up re-using
// this thread.
_g_.m.lockedExt = 0
}
}
// 再次进入调度
schedule()}