go runtime其他函数 gogo, goexit

Posted xxx小M

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go runtime其他函数 gogo, goexit相关的知识,希望对你有一定的参考价值。

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()
}

以上是关于go runtime其他函数 gogo, goexit的主要内容,如果未能解决你的问题,请参考以下文章

GOGO语言学习笔记一

GOgo.mod

Let‘s GoGo语言入门篇

Let‘s GoGo语言入门篇

Go protobuf v1 败给了gogo protobuf,那 v2 呢?

GOgo 模块化开发