我们都知道对于多核CPU需要IPI机制进行通知或者唤醒,当CPU接收到的中断不是本地中断的时候,需要通过IPI唤醒对端CPU,然后进行中断的传递
那么QEMU中如何实现不同VCPU通知的呢
首先在初始化KVM虚拟机的时候,注册了核间通信处理函数,这个函数完成了IPI的功能
int kvm_init(QEMUMachine *machine){
/** 注册CPU见通信接口 */
cpu_interrupt_handler = kvm_handle_interrupt;
}
/*
* CPU的IPI通信接口 */ static void kvm_handle_interrupt(CPUState *cpu, int mask) { /*记录中断请求号*/ cpu->interrupt_request |= mask; /*如果不是本地CPU,启动相应的VCPU接收中断*/ if (!qemu_cpu_is_self(cpu)) { qemu_cpu_kick(cpu); } } /* * 启动指定的VCPU, */ void qemu_cpu_kick(CPUState *cpu) { /* * 唤醒所有等待在cpu->halt_cond上的VCPU线程,关于QEMUCond,请参考《QEMU VCPU线程同步机制之QemuCond(基于QEMU2.0.0)》 */ qemu_cond_broadcast(cpu->halt_cond); /* * 对于不是TCG的且还没有被kick的VCPU线程进行唤醒 */ if (!tcg_enabled() && !cpu->thread_kicked) { qemu_cpu_kick_thread(cpu); cpu->thread_kicked = true; //标明指定的VCPU线程已被唤醒 } } /* * 唤醒指定的VCPU线程 */ static void qemu_cpu_kick_thread(CPUState *cpu) { #ifndef _WIN32 int err; /* * 通过pthread_kill将SIG_IPI信号发送到指定的VCPU线程,将其唤醒 */ err = pthread_kill(cpu->thread->thread, SIG_IPI); if (err) { fprintf(stderr, "qemu:%s: %s", __func__, strerror(err)); exit(1); } #else /* _WIN32 */ #endif } |
我们下面来看一下IPI的使用示例,
pic_irq_request是通过pc_init->pc_allocate_cpu_irq,注册的irq的handler
pic_irq_request
-> cpu_interrupt
-> cpu_interrupt_handler
//这里调用kvm_handle_interrupt
-> kvm_handle_interrupt //唤醒指定VCPU的线程,发送中断