gogo

gogo由汇编实现,次要是由g0切换到g栈,而后执行函数。

// func gogo(buf *gobuf)// restore state from Gobuf; longjmpTEXT 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()}