qemu:防止客人霸占 CPU

qemu: prevent a guest from hogging CPU

我正在阅读一些关于 qemu 内部的材料,here 它提到:

“跳入来宾代码会剥夺我们对执行的控制权,并将控制权交给来宾。虽然线程是 运行 来宾代码,但它不能同时处于事件循环中,因为来宾拥有 CPU 的(安全)控制权。通常,来宾代码花费的时间有限,因为对模拟设备寄存器的读写和其他异常导致我们离开来宾并将控制权交还给 QEMU。在极端情况下在这种情况下,来宾可以在不放弃控制的情况下花费无限量的时间,这会使 QEMU 无响应。 为了解决来宾代码占用问题,QEMU 的线程控制信号被用来突破来宾。 UNIX 信号将控制权从当前执行流程中抽离出来,并调用信号处理函数。这允许 QEMU 采取措施将访客代码和 return 留在其主循环中,事件循环可以获得处理未决事件的机会。"

所以我不清楚是什么生成信号(qemu 的 IO 线程还是内核?)以及它如何帮助中断执行访客代码的线程?如果内核向 qemu 进程发送这样的信号,那么我会假设 qemu 故意在客户代码中注入某些指令(二进制翻译),从而导致异常然后发出信号?

不,QEMU 没有向访客代码中注入任何东西。通常,(主机)信号由另一个 QEMU 线程(如 iothread)发送到 vCPU 线程。这样做的要点是信号的整个机制是当主机内核向线程发送信号时,它会停止该线程做它正在做的任何事情(即 运行ning 客户代码)并使其 运行 改为信号处理程序(即 QEMU 进程代码)。 None 这与来宾看到的任何东西有关,例如来宾 CPU 异常,除了在非常间接的意义上,一旦 QEMU 再次获得控制权,它可能会决定这种情况意味着它现在应该告诉来宾通过传递异常或中断来了解某事(例如“IO 事件已完成,仿真 SCSI 控制器已向您发送中断”)。

对于KVM来说,接收到信号也意味着内核会导致vCPU线程从KVM_RUN ioctl调用return,然后重新进入QEMU 主循环。

对于 TCG,我认为博客 post 现在有点过时了(毕竟它已有 10 年历史了[*])——我们不需要向vCPU 线程使其停止 运行ning 访客代码,因为当我们翻译访客代码时,我们在每个翻译代码块的开头包含一个片段,上面写着“如果设置了标志,停止”。所以iothread可以通过设置标志来停止vCPU线程。

[*] 更一般地说,不要相信那个博客 post 中的细节今天仍然是正确的。最值得注意的是,QEMU 现在 支持“iothread”模型,并且“non-iothread”处理已完全删除;在许多情况下,TCG 可以支持多个 vCPU 线程,并且不需要 运行 单个主机线程上的所有 vCPU。