Golang runtime.getg() 的实现

2017, Sep 30    

系统环境

系统版本: Fedora Release 25
内核版本:4.12.8-200.fc25.x86_64
GO: 1.8.3 linux/amd64

runtime.getg()

这个函数用于获取当前正在执行的 goroutine 的信息(/usr/local/go/src/runtime/stubs.go#21)。

// getg returns the pointer to the current g.
// The compiler rewrites calls to this function into instructions
// that fetch the g directly (from TLS or from the dedicated register).
func getg() *g

从注释里可以看到,这个函数并不是在 runtime 里实现的,而是由编译器负责写入函数体。而且写明了是来自于 TLS(Thread-local Storage)或者指定的寄存器的。

然后在编译器中搜索 getg 相关的内容,可以在 ssa.go 中发现与之相关的说明(cmd/compile/internal/amd64/ssa.go#712):

case ssa.OpAMD64LoweredGetG:
	r := v.Reg()
	// See the comments in cmd/internal/obj/x86/obj6.go
	// near CanUse1InsnTLS for a detailed explanation of these instructions.
	if x86.CanUse1InsnTLS(gc.Ctxt) {
		// MOVQ (TLS), r
		...
	} else {
		// MOVQ TLS, r
		// MOVQ (r)(TLS*1), r
		...
	}

这里判断了能否使用单命令访问 TLS,可以就用第一种实现,否则使用第二种实现。也就是说,getg() 最终是从当前线程的 TLS 中取得 g 的信息。