Go runtime 调度器中,main goroutine 创建过程如何为?

摘要:原创文章,欢迎转载,转载请注明出处,谢谢。 0. 前言 回顾下 上一讲 的内容。主线程 m0 蓄势待发,准备干活。g0 为 m0 提供了执行环境,P 和 m0 绑定,为 m0 提供活,也就是 goroutine。那么问题来了,活呢?哪里有活
原创文章,欢迎转载,转载请注明出处,谢谢。 0. 前言 回顾下 上一讲 的内容。主线程 m0 蓄势待发,准备干活。g0 为 m0 提供了执行环境,P 和 m0 绑定,为 m0 提供活,也就是 goroutine。那么问题来了,活呢?哪里有活给 m0 干? 这一讲我们将介绍 m0 执行的第一个活,也就是 main goroutine。main gouroutine 就是执行 main 函数的 goroutine,有别于用 go 关键字创建的 goroutine,它们在执行过程中有一些区别(后续会讲)。 1. main goroutine 创建 接着上一讲的内容,调度器初始化之后,执行到 asm_amd64.s/rt0_go:352: TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 ... // create a new goroutine to start program 352 MOVQ $runtime·mainPC(SB), AX // entry 353 PUSHQ AX 354 CALL runtime·newproc(SB) 355 POPQ AX // dlv 进入到指令执行处 dlv exec ./hello Type 'help' for list of commands. (dlv) b /usr/local/go/src/runtime/asm_amd64.s:352 Breakpoint 1 set at 0x45433c for runtime.rt0_go() /usr/local/go/src/runtime/asm_amd64.s:352 (dlv) c (dlv) si > runtime.rt0_go() /usr/local/go/src/runtime/asm_amd64.s:353 (PC: 0x454343) Warning: debugging optimized function asm_amd64.s:349 0x454337 e8e4290000 call $runtime.schedinit asm_amd64.s:352 0x45433c* 488d05659d0200 lea rax, ptr [rip+0x29d65] => asm_amd64.s:353 0x454343 50 push rax 结合 CPU 执行指令和 Go plan9 汇编代码一起分析。 首先,将 $runtime·mainPC(SB) 地址传给 AX 寄存器,CPU 执行的指令是 mov qword ptr [rsp+0x8], rax。使用 regs 可以看到 rax 的值,也就是 $runtime·mainPC(SB) 的地址: (dlv) regs Rip = 0x0000000000454343 Rsp = 0x00007ffd58324080 Rax = 0x000000000047e0a8 // rax = $runtime.mainPC(SB) = [rsp+0x8] 那么 $runtime.mainPC(SB) 的地址指的是什么呢?我们看 $runtime.mainPC(SB) 的定义: // mainPC is a function value for runtime.main, to be passed to newproc. // The reference to runtime.main is made via ABIInternal, since the // actual function (not the ABI0 wrapper) is needed by newproc. DATA runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB) GLOBL runtime·mainPC(SB),RODATA,$8 $runtime.mainPC(SB) 是一个为了执行 runtime.main 的函数值。 继续执行 PUSH AX 将 runtime.mainPC(SB) 放到栈上。注意,这里的栈是 g0 栈,也就是主线程 m0 运行的栈。
阅读全文