Go1.18调度器-标准库函数
发表于 · 归类于
代码 · 阅读完需 7 分钟 ·
报告错误 ·
阅读:
标准库函数
标准库里与调度相关的几个函数。了解实现细节,以便放心使用。
runtime.Gosched
让出当前 G
执行绪。与 gopark
的区别,G
会被放回队列,无需 goready
唤醒。
// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched() {
mcall(gosched_m)
}
// Gosched continuation on g0.
func gosched_m(gp *g) {
// 继续运行 G0
goschedImpl(gp)
}
// func mcall(fn func(*g))
// Switch to m->g0's stack, call fn(g).
// Fn must never return. It should gogo(&g->sched)
// to keep running g.
TEXT runtime·mcall<ABIInternal>(SB), NOSPLIT, $0-8
MOVQ AX, DX // DX = fn
// save state in g->sched
MOVQ 0(SP), BX // caller's PC
MOVQ BX, (g_sched+gobuf_pc)(R14)
LEAQ fn+0(FP), B // caller's SP
MOVQ BX, (g_sched+gobuf_sp)(R14)
MOVQ BP, (g_sched+gobuf_bp)(R14)
// switch to m->g0 & its stack, call fn
MOVQ g_m(R14), BX
MOVQ m_g0(BX), SI // SI = g.m.g0
CMPQ SI, R14 // if g == m->g0 call badmcall
JNE goodm
JMP runtime·badmcall(SB)
goodm:
MOVQ R14, AX // AX (and arg 0) = g
MOVQ SI, R14 // g = g.m.g0
get_tls(CX) // Set G in TLS
MOVQ R14, g(CX)
MOVQ (g_sched+gobuf_sp)(R14), SP // sp = g0.sched.sp
PUSHQ AX // open up space for fn's arg spill slot
MOVQ 0(DX), R12
CALL R12 // fn(g)
POPQ AX
JMP runtime·badmcall2(SB)
RET
func goschedImpl(gp *g) {
// 修改状态
status := readgstatus(gp)
if status&^_Gscan != _Grunning {
dumpgstatus(gp)
throw("bad g status")
}
casgstatus(gp, _Grunning, _Grunnable)
// 解除 MP 绑定,放回全局队列
dropg()
lock(&sched.lock)
globrunqput(gp)
unlock(&sched.lock)
// 当前 MP 执行其他任务
schedule()
}
runtime.Goexit
终止当前任务。这与return
返回调用堆栈上一级不同,而是直接结束这个任务。
在 Main Goroutine 调用 Goexit,它会等待其他 Gs 结束后才会崩溃。
注意,终止的是G函数执行,而不是MP。
// panic.go
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine. Because Goexit
// is not a panic, any recover calls in those deferred functions will return nil.
//
// Calling Goexit from the main goroutine terminates that goroutine
// without func main returning. Since func main has not returned,
// the program continues execution of other goroutines.
// If all other goroutines exit, the program crashes.
func Goexit() {
// panic, defer ...
goexit1()
}
// proc.go
// Finishes execution of the current goroutine.
func goexit1() {
mcall(goexit0)
}
// goexit continuation on g0.
func goexit0(gp *g) {
// G 任务结束,清理后放回复用链表。
casgstatus(gp, _Grunning, _Gdead)
dropg()
gfput(_p_, gp)
// 当前 MP 继续执行其他任务。
schedule()
}