关于golang:go-runtime其他函数-gogo-goexit

4次阅读

共计 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()}
正文完
 0