共计 2269 个字符,预计需要花费 6 分钟才能阅读完成。
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()} |
正文完