知识卡片

系统调用要交接

普通读书笔记卡 · 1481.c

内容

协程进入系统调用时,M 可能阻塞,运行时会把 P 交给其他 M 继续执行 Go 代码。系统调用返回后再尝试重新绑定 P;这避免一个慢 syscall 拖住并发吞吐。

参考来源

- 位置:《Go语言底层原理剖析》第15章《深入协程设计与调度原理》15.6.4节《执行时间过长的抢占调度》末尾关于系统调用抢占的部分 - 结论依据:原文说明系统调用时抢占"主要是将P的状态转化为_Pidle……我们的目的是让M接管P的执行,主要的逻辑位于handoffp函数中",并列出需要启动新 M 接管 P 的几种条件(本地队列有等待G、需处理GC后台任务等);系统调用返回后,"exitsyscall函数希望能够重新绑定P",优先尝试原 oldp,否则从全局空闲队列获取,因此可以推出"协程陷入系统调用时 M 会与 P 解绑并把 P 交给其他 M,返回后再重新绑定"的结论。 - 原始内容:系统调用时的抢占原理主要是将P的状态转化为_Pidle,这仅仅是完成了第1步。我们的目的是让M接管P的执行,主要的逻辑位于handoffp函数中,该函数需要判断是否需要找到一个新的M来接管当前的P……在执行实际操作系统调用之前,运行时调用了reentersyscall函数。该函数会保存当前G的执行环境,并解除P与M之间的绑定关系,将P放置到oldp中……当操作系统内核返回系统调用后,被堵塞的协程继续执行,调用exitsyscall函数以便协程重新执行……exitsyscall函数希望能够重新绑定P。