【问题标题】:qemu: prevent a guest from hogging CPUqemu:防止来宾占用 CPU
【发布时间】:2021-03-22 15:38:26
【问题描述】:

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

“跳入客户代码会夺走我们对执行的控制权并将控制权交给客户。当线程运行客户代码时,它不能同时处于事件循环中,因为客户对 CPU 具有(安全)控制权. 通常情况下,客户代码所花费的时间是有限的,因为对模拟设备寄存器的读写和其他异常会导致我们离开客户并将控制权交还给 QEMU。在极端情况下,客户可以花费无限的时间而不给予控制,这将使 QEMU 无响应。 为了解决客户代码占用问题,QEMU 的控制信号线程被用来突破客户。一个 UNIX 信号将控制从当前的执行流程中拉出来并调用一个信号处理函数。这允许 QEMU 采取措施离开客户代码并返回其主循环,在该主循环中事件循环有机会处理未决事件。”

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

【问题讨论】:

    标签: virtualization qemu


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢您的评论。 对于KVM来说,接收到信号也意味着内核会导致vCPU线程从KVM_RUN ioctl调用中返回——这是否意味着KVM拦截了发送给vcpu线程的信号?
    • KVM 不需要“拦截”任何东西。它是主机内核的一部分,主机内核控制信号如何为主机进程工作。如果一个信号被发送到恰好正在执行 KVM_RUN ioctl 的 QEMU 进程线程,内核将导致该 ioctl 退出并且 QEMU 开始运行其信号处理程序代码。如果在 write() 系统调用或任何其他阻塞系统调用的中间将信号发送到进程,则会发生同样的事情。
    猜你喜欢
    • 2018-01-19
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 2022-06-24
    • 2016-06-03
    相关资源
    最近更新 更多