go gmp --- 启动流程源码分析

本文深入探讨Go程序的启动流程,包括`schedinit`、`mcommoninit`、`procresize`等阶段,分析了如何初始化调度器、创建M和P,以及`newproc`和`mstart`如何启动线程进入调度循环。文章通过源码分析,详细解释了从`gogo`到`main`函数执行的整个过程。
摘要由CSDN通过智能技术生成

这里我们已经知道了go程序的入口,这篇文章主要是介绍go在启动时是怎么初始化的。先来看一下go启动函数rt0_go()的汇编代码。

启动流程

//go程序启动时初始化工作
TEXT runtime·rt0_go(SB),NOSPLIT,$0
    // 拷贝argc、argv
	// copy arguments forward on an even stack
	MOVQ	DI, AX		// argc
	MOVQ	SI, BX		// argv
	SUBQ	$(4*8+7), SP		// 2args 2auto
	ANDQ	$~15, SP //sp16字节对齐
	MOVQ	AX, 16(SP) //argc放在sp+16处
	MOVQ	BX, 24(SP) //argv放在sp+24处

	// create istack out of the given (operating system) stack.
	// _cgo_init may update stackguard.
	//初始化g0
	//下面这段代码从主线程栈中分出一部分作为g0栈
	MOVQ	$runtime·g0(SB), DI//g0的地址放入DI寄存器
	LEAQ	(-64*1024+104)(SP), BX//BX=SP- 64*1024 + 104
	MOVQ	BX, g_stackguard0(DI)//g0.stackguard0 =SP- 64*1024 + 104
	MOVQ	BX, g_stackguard1(DI)//g0.stackguard1 =SP- 64*1024 + 104
	MOVQ	BX, (g_stack+stack_lo)(DI)//g0.stack.lo =SP- 64*1024 + 104
	MOVQ	SP, (g_stack+stack_hi)(DI)//g0.stack.hi =SP  g0栈大小约64kb

	// find out information about the processor we're on
#ifdef
	...... // xxxx,一些cpu型号检查相关代码先忽略
	
#endif
    //设置线程本地变量thread local storage,完后会有m0.tls[0]=&g0
	LEAQ	runtime·m0+m_tls(SB), DI//取m0.tls到DI寄存器
	CALL	runtime·settls(SB)//调用settls

	// store through it, to make sure it works
	get_tls(BX)
	MOVQ	$0x123, g(BX)//m0.tls[0]=0x123
	MOVQ	runtime·m0+m_tls(SB), AX//AX=m0.tls[0]
	CMPQ	AX, $0x123//
	JEQ 2(PC)
	CALL	runtime·abort(SB)
ok:
	// set the per-goroutine and per-mach "registers"
	get_tls(BX)
	LEAQ	runtime·g0(SB), CX//CX=&g0
	MOVQ	CX, g(BX)//m0.tls[0]=&g0
	LEAQ	runtime·m0(SB), AX//AX=&m0

    //绑定g0和m0
	// save m->g0 = g0
	MOVQ	CX, m_g0(AX)//m0.g0=g0
	// save m0 to g0->m
	MOVQ	AX, g_m(CX)//g0.m=m0

	CLD				// convention is D is always left cleared
	CALL	runtime·check(SB)

	MOVL	16(SP), AX		// copy argc
	MOVL	AX, 0(SP)   //m0放入sp
	MOVQ	24(SP), AX		// copy argv
	MOVQ	AX, 8(SP)   //g0放入sp+8
	CALL	runtime·args(SB)//除以操作系统传来的参数和env,忽略
	CALL	runtime·osinit(SB)//设置全局变量ncpu的值
	CALL	runtime·schedinit(SB)//调度器初始化

	// create a new goroutine to start program
	MOVQ	$runtime·mainPC(SB), AX		// entry
	PUSHQ	AX
	PUSHQ	$0			// arg size
	CALL	runtime·newproc(SB) //创建第一个goroutine,习惯成为main goroutine
	POPQ	AX
	POPQ	AX

	// start this M
	CALL	runtime·mstart(SB) //主线程调度上面创建的main goroutine
    //mstart永远不会返回,如果返回了则立马abort
	CALL	runtime·abort(SB)	// mstart should never return
	RET

go启动过程初始化可以通过下面这个流程图来加深理解(忽略了一些不重要环节)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值