Copyright © 2022-2024 aizws.net · 网站版本: v1.2.6·内部版本: v1.23.3·
页面加载耗时 0.00 毫秒·物理内存 63.6MB ·虚拟内存 1300.0MB
欢迎来到 AI 中文社区(简称 AI 中文社),这里是学习交流 AI 人工智能技术的中文社区。 为了更好的体验,本站推荐使用 Chrome 浏览器。
func mcall(fn func(*g)) 的主要作用是协程切换,它将当前正在执行的协程 g 的状态保存起来,然后在 m->g0 的堆栈上调用新的函数 fn(g),在函数 fn 内会将之前运行的协程 g 放弃,然后调用一次 schedule() 来挑选新的协程运行。
mcall 函数是一段汇编程序,位于 asm_amd64.s 文件中。
mcall 函数代码如下:
TEXT runtime·mcall(SB), NOSPLIT, $0-8 // 将 fn 函数指针存到 DI 寄存器 MOVQ fn+0(FP), DI // get_tls 是一个宏,其中 tls 是线程局部存储,最终替换为 FS 寄存器,将 tls 内容保存到存到 CX 寄存器 get_tls(CX) // g(CX) 是一个宏,在 tls 上可得到 g,也就是当前正在运行的 g,把这个 g 的地址存到 AX 寄存器 MOVQ g(CX), AX // save state in g->sched // go 函数栈的大小,不包含传入的参数和返回值,这两个部分由调用者管理。mcall 的 fn 是传入参数,这个参数 fn 放在【调用 mcall 的函数】的函数栈里。 // mcall 除了一个传入参数 fn,没有其他变量,所以 mcall 的栈大小为 0。// 一个栈大小为 0 的函数,它的栈顶,也就是 SP 指向的位置,存放了调用 mcall 的函数的下一条指令,也就是这里所谓的 caller 的 PC。 // PC 值的存放,是由 CALL 指令自动做的事情,也就是 go 编译器做的事情。调用某函数时,先把本函数的下一掉指令 push 进栈。// 将 caller‘s PC 存放到 BX 里。 MOVQ 0(SP), BX // caller's PC // AX 存放了 g 的地址,BX 存放了caller's PC,把 caller's PC 存放到 g 结构体的 sched 的 gobuf 的 pc 字段。 MOVQ BX, (g_sched+gobuf_pc)(AX) LEAQ fn+0(FP), BX // caller's SP // BX 存放了 caller 的 SP,存放到 g 的相应位置 MOVQ BX, (g_sched+gobuf_sp)(AX) // AX 存放的就是 g 本身,存放到 g 的相应位置 MOVQ AX, (g_sched+gobuf_g)(AX) // 将 BP 寄存器的值存放到 g 的相应位置 MOVQ BP, (g_sched+gobuf_bp)(AX) // 切换到 m->g0 的栈,然后调用fn MOVQ g(CX), BX // 把当前g的地址存到BX里 MOVQ g(CX), BX // 根据 g,可以得到 m MOVQ g_m(BX), BX // 根据 m,可以得到 g0 MOVQ m_g0(BX), SI // 如果 g0 就是 g,调用 badmcall。 CMPQ SI, AX // if g == m->g0 call badmcall // 如果 g != g0,就跳过 3 条指令,继续执行。 JNE 3(PC) // g != g0 的 错误处理 badmcallMOVQ $runtime·badmcall(SB), AX JMP AX // SI 存的是 g0,将 g0 变成当前 g。 MOVQ SI, g(CX) // g = m->g0 // 将 g0 的 SP 值,放到寄存器 SP,开始切换,调用 fn(g) MOVQ (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp // AX 存的就是刚才的 g,不是现在的 g0,将 g 放到栈上。这一步就是普通的,我要调用fn函数了,我要把参数g,先放到栈上。 PUSHQ AX// 调用fnMOVQ DI, DX MOVQ 0(DI), DI CALL DI POPQ AX MOVQ $runtime·badmcall2(SB), AX JMP AX RET
1. goroutinegoroutine 是 Go 语言实现的用户态线程,主要用来解决操作系统线程太重的问题,主要表现在以下两个方面:创建和切换太重操作系统线程的创建和切换都 ...