go当中的线程存储与使用

1、settls

从引导代码中可以看到,在执行settls前将m.tls放入了DI。

go/src/runtime/asm_amd64.s:159

TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
....
    LEAQ    runtime·m0+m_tls(SB), DI
    CALL    runtime·settls(SB)
    ....

tls定义是无符号整形指针

type m struct {
    ...  
    tls           [tlsSlots]uintptr // thread-local storage (for x86 extern register)
    ...
}

从上面可知DI保存的是m.tls 的首地址,然后在settls中加上了8字节也就是8x8=64位也就是 m.tls[1]地址用于设置TLS。

// set tls base to DI
TEXT runtime·settls(SB),NOSPLIT,$32
    ADDQ    $8, DI    // ELF wants to use -8(FS) 将DI寄存器的值加上8字节,得到TLS的偏移量。这个偏移量用于设置TLS。
    MOVQ    DI, SI    // 将TLS地址放到SI寄存器,也就是系统调用第二个参数
    MOVQ    $0x1002, DI    // ARCH_SET_FS  设置系统调用号
    MOVQ    $SYS_arch_prctl, AX   // 执行系统调用,将tls 设置到 m.tls[1] 上
    SYSCALL
    CMPQ    AX, $0xfffffffffffff001
    JLS    2(PC)
    MOVL    $0xf1, 0xf1  // crash
    RET

 

2、gettls

TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
....

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

3、gogo函数

go中在excute函数中执行一个goroutine,最后调用gogo函数执行goroutine,可以看到runtime.gogo 中将gogo函数的第一个参数放到了BX寄存器,

将gobuf.g也就是当前goroutine放到了DX寄存器,然后在TEXT gogo 中通过get_tls 获取到当前线程存储的地址放到CX,然后将DX寄存器也就是当前groutine放到当前线程存储中,同步将DX也就是当前goroutine放到R14寄存器(会在栈扩容检查中使用)

后面调度代码不在赘述,总结就是将当前goroutine的 pc 放到BX寄存器,跳到BX也就是pc处开始执行指令。

go/src/runtime/asm_amd64.s:403

// func gogo(buf *gobuf)
// restore state from Gobuf; longjmp
TEXT runtime·gogo(SB), NOSPLIT, $0-8
    MOVQ    buf+0(FP), BX        // gobuf
    MOVQ    gobuf_g(BX), DX      // 将要执行的goroutine放到 DX
    MOVQ    0(DX), CX        // make sure g != nil
    JMP    gogo<>(SB)

TEXT gogo<>(SB), NOSPLIT, $0
    get_tls(CX)  // 将当前线程存储的地址放到 CX
    MOVQ    DX, g(CX) // 将DX也就是要执行的goroutine放到 CX,也就是 m.tls[0]
    MOVQ    DX, R14        // set the g register 将要执行的goroutine 放到R14寄存器
    MOVQ    gobuf_sp(BX), SP    // restore SP
    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 // 将当前goroutine的 pc 放到BX寄存器
    JMP    BX                // 跳到BX也就是pc处开始执行指令

4、栈检查

> gogo() /usr/local/go/src/runtime/asm_amd64.s:422 (PC: 0x45a77e)
Warning: debugging optimized function
        ...
        asm_amd64.s:421 0x45a77a*       488b5b08                mov rbx, qword ptr [rbx+0x8]
=>      asm_amd64.s:422 0x45a77e        ffe3                    jmp rbx  // 跳转到pc 此处也就是main函数执行
(dlv) regs
    Rip = 0x000000000045a77e
    Rsp = 0x000000c00004a7d8
    Rax = 0x0000000000000000
    Rbx = 0x0000000000433180  // 保存了main函数的地址
    ...

(dlv) si
> runtime.main() /usr/local/go/src/runtime/proc.go:145 (PC: 0x433180)
Warning: debugging optimized function
TEXT runtime.main(SB) /usr/local/go/src/runtime/proc.go
        // 扩栈检查,比较rsp 与 r14 也就是当前g 偏移0x10 也就是16个字节中的 stackguard0 比较
=>      proc.go:145     0x433180        493b6610        cmp rsp, qword ptr [r14+0x10]
        proc.go:145     0x433184        0f861c030000    jbe 0x4334a6
        proc.go:145     0x43318a        4883ec58        sub rsp, 0x58
        ...
        proc.go:145             0x4334a6        e855820200              call $runtime.morestack_noctxt  // 执行扩栈
        proc.go:145             0x4334ab        e9d0fcffff              jmp $runtime.main // 扩栈完成,跳转回main执行

g定义

type g struct {
    stack       stack   // offset known to runtime/cgo  16个字节
    stackguard0 uintptr // offset known to liblink     8字节
...
}

// Stack describes a Go execution stack.
// The bounds of the stack are exactly [lo, hi),
// with no implicit data structures on either side.
type stack struct {
    lo uintptr  // 8字节
    hi uintptr  // 8字节
}

 

posted @ 2024-07-03 17:40  G1733  阅读(30)  评论(0编辑  收藏  举报