gh-liu / myNote

0 stars 0 forks source link

`go runtime`的GMP #4

Open gh-liu opened 5 months ago

gh-liu commented 5 months ago

GMP

go version go1.22.2 linux/amd64

G

G 是被调度的对象,有状态、栈

status

src/runtime/runtime2.go:18

// _Grunnable: 创建一个可运行的 G
func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g {}

// _Grunnable -> _Grunning: 将G调度在M上运行
func execute(gp *g, inheritTime bool) {}

// _Grunning -> _Grunnable: 当前 G 让出当前 CPU,允许其他 G 使用
func goyield() {} // 调用 goyield_m
func goyield_m(gp *g) {}

// _Grunning -> _Gdead: G 表示的任务已经完成
// 
// 每个 G 的调用栈都构造得像是 goexit 调用了该 G 的入口函数,
// 因此当入口函数返回时,它会返回到 goexit,
// goexit 会调用 goexit1 来执行实际的退出操作
func goexit(neverCallThisFunction)
func goexit1() {} // 调用 goexit0
func goexit0(gp *g) {} // 调用 gdestroy
func gdestroy(gp *g) {} // _Grunning -> _Gdead

// _Grunning -> _Gsyscall: 执行 G 的时候,进入系统调用状态
// 
// 此时 G 不在使用 CPU 资源
func entersyscall() {} // 调用 reentersyscall
func reentersyscall(pc, sp uintptr) {}
//
func entersyscallblock() {} // 同上,但是进入了一个阻塞的系统调用

// _Gsyscall -> _Grunning: 
// _Gsyscall -> _Grunnable: 
// 
// 退出系统调用状态:
// 调用 exitsyscallfast 为true,则 _Gsyscall -> _Grunning
// 否则调用 exitsyscall0,则 _Gsyscall -> _Grunnable
func exitsyscall() {}

// _Grunning -> _Gwaiting: 将 G 设置为等待状态
func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceReason traceBlockReason, traceskip int) {} // 调用 park_m
func park_m(gp *g) {} // _Grunning -> _Gwaiting

// _Gwaiting -> _Grunnable: 将 G 设置为可运行状态
func goready(gp *g, traceskip int) {} // 调用 ready
func ready(gp *g, traceskip int, next bool) {}
---
title: G status
---
stateDiagram-v2
    direction LR

    gidle   : _Gidle     
    grunable: _Grunnable 
    grunning: _Grunning   
    gsyscall: _Gsyscall   
    gwaiting: _Gwaiting   
    gdead   : _Gdead      

    [*]      --> gidle
    gdead    --> [*]

    gidle    --> grunable: newproc1

    grunable --> grunning: execute
    grunning --> grunable: goyield

    grunning --> gsyscall: entersyscall/entersyscallblock

    state gsyscall_state <<choice>>
    gsyscall --> gsyscall_state
    gsyscall_state --> grunning: exitsyscall,exitsyscallfast
    gsyscall_state --> grunable: exitsyscall,exitsyscall0

    grunning --> gwaiting: gopark
    gwaiting --> grunable: goready

    grunning --> gdead: goexit

P

P是逻辑CPU,主要保存着可执行的G队列

status

src/runtime/runtime2.go:110

// _Pidle: // // 所有的 P 被设置为 _Pidle 状态 func procresize(nprocs int32) *p {}

// _Pidle -> _Prunning: // // 将 P 和 M 绑定,运行 G 或调度器 func acquirep(pp p) {} // 调用 wirep func wirep(pp p) {} // pp.status = _Prunning

// _Prunning -> _Pidle: // // 将 P 和 M 解绑 func releasep() p {} // 调用 releasepNoTrace func releasepNoTrace() p {} // pp.status = _Pidle

// _Pdead func procresize(nprocs int32) p {} // 重新设置 P 数量时,如果少于原 P 的数量,多余的 P 调用 destroy func (pp p) destroy() {} // pp.status = _Pdead

// _Psyscall // // P 关联了一个进行系统调用的M,也就是没有在运行G,此时可能被其他M窃取的 func entersyscall() {} // atomic.Store(&pp.status, _Psyscall)


```mermaid
---
title: P status
---
stateDiagram-v2

pidle   : _Pidle
prunning: _Prunning
psyscall: _Psyscall
pdead   : _Pdead

pidle --> prunning
prunning --> pidle

prunning --> psyscall

M

M 是OS线程,执行代码,必须绑定一个P才能获取到G进行执行

status

running/spinning: 运行状态或自旋状态


// 运行M: 新建M或唤醒M
// 新建M
func startm(pp *p, spinning, lockheld bool) {} 
func newm(fn func(), pp *p, id int64) {} // 调用 newosproc, 不同`OS`不同实现
func newosproc(mp *m) {}
// 唤醒M
func wakep() {} // 调用 startm
func startm(pp *p, spinning, lockheld bool) {} // 调用 mget
func mget() *m {} 

// 自旋M
func (mp *m) becomeSpinning() {}

// 从自旋中恢复
func resetspinning() {}

// 休眠 M
// M 没有 G 可以执行,也不是自旋状态,进入休眠状态
func stopm() {} // 调用 mput
func mput(mp *m) {}

TODO 状态图