Skip to the content.

Big QEMU Lock

使用 Big QEMU Lock (下面简称为 BQL) 是因为设备的模拟是串行的。 比如 pic 中断控制器在 QEMU 中描述在 hw/intc/i8259.c 中, pic 的状态保存在 PICCommonState 中,多个 vCPU thread 访问 pic 的时候, 那就需要靠 BQL 来实现互斥,只能逐个调用 pic 的模拟函数,也就是 pic_ioport_read / pic_ioport_write 。 如果一个 vCPU 在执行 pic_ioport_write,另一个 vCPU 在 pic_ioport_read 的时候,其获取的状态可能错误的中间状态。

回忆一下,QEMU 中的线程和事件循环 中 QEMU 的执行模型:

按照这种指导思想可以很容易确认下面的位置的 BQL 的使用:

BQL Advanced Topic

但是实际上,BQL 的使用位置要上面多一点,这些是高级话题,可以暂时跳过。

migration

实际上,和 migration 相关的还有 qemu_mutex_lock_ramlist,从原则上将当持有了 BQL 的时候,就屏蔽了所有的 lock 的。 但是在 ram_init_bitmaps 首先上锁 BQL,然后是 ramlist 的。 具体可以从 b2a8658ef5dc57ea 分析,有待进一步跟进。

main loop

main loop 中上锁位置非常的早,在 pc_init1 => qemu_init_subsystems 中几乎是 BQL 初始化之后就会获取。

创建的 vCPU 例如 mttcg_cpu_thread_fn 因为无法获取 BQL 而无法进一步执行,一切都需要等待 main loop 初始化好。

如果 cpu realize 失败,会调用 x86_cpu_unrealizefn => cpu_remove_sync 来清理资源包括释放 vCPU 的,为了让 vCPU 进一步执行,所以 cpu_remove_sync 中需要短暂的释放 BQL

QEMU 中的线程和事件循环中,我们分析了 main loop 如何实现事件监听。 当 vCPU thread 需要模拟设备操作,比如 DMA 的时候,最后会调用具体设备的 callback 函数, 但是 vCPU thread 不会等待下去,而是将其中 callback 函数让 main loop 执行。 而 main loop 就是靠事件监听来知道有 vCPU 提交任务给他了。 当 main loop 执行完成之后, 只需要向 vCPU 发送一个中断,也即是最后调用到 tcg_handle_interrupt, 向 CPUState::interrupt_request 插入一个中断,而 tcg 执行的时候,每一个 tb 都会检查这个,如果插入了中断,就会退出 , 最后在 cpu_handle_interrupt 地方处理。

- main
  - qemu_main_loop
    - main_loop_wait
      - qemu_clock_run_all_timers
        - timerlist_run_timers
          - timerlist_run_timers
            - update_irq
              - qemu_irq_pulse
                - gsi_handler
                  - ioapic_set_irq
                    - ioapic_service
                      - stl_le_phys
                        - address_space_stl_le
                          - address_space_stl_internal
                            - memory_region_dispatch_write
                              - access_with_adjusted_size
                                - memory_region_write_accessor
                                  - apic_mem_write
                                    - apic_send_msi

interrupt_request

因为一个 CPU 利用 ipi 机制给另一个 vCPU 发送中断,所以 interrupt_request 需要被 BQL 保护,其调用位置为:

因为中断的注入可能来自于 main loop 或者是其他的 vCPU thread,所以同样这个需要 BQL 的保护

qemu_mutex_iothread_locked

下面来讨论一下一些持有 BQL 的位置

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。