There are certain cases where cpu context requests a vm stop, such as -ENOSPC handling. IMO its simpler to handle vmstop only through the iothread. Note there is change in behaviour: now the cpu thread which requested vm_stop will actually only stop when it exits back to cpu_main_loop. It might cause further damage in between vmstop and cpu_main_loop. Index: trunk/vl.c =================================================================== --- trunk.orig/vl.c +++ trunk/vl.c @@ -3550,7 +3550,22 @@ void vm_start(void) } } -void vm_stop(int reason) +static int vmstop_requested; + +static int qemu_vmstop_requested(void) +{ + int r = vmstop_requested; + vmstop_requested = 0; + return r; +} + +static void qemu_system_vmstop_request(int reason) +{ + vmstop_requested = reason; + main_loop_break(); +} + +static void __vm_stop(int reason) { if (vm_running) { cpu_disable_ticks(); @@ -3560,6 +3575,21 @@ void vm_stop(int reason) } } +void vm_stop(int reason) +{ + QemuThread me; + qemu_thread_self(&me); + + if (!qemu_thread_equal(&me, &io_thread)) { + qemu_system_vmstop_request(reason); + /* make sure we can't return to cpu_exec */ + if (cpu_single_env) + cpu_single_env->stop = 1; + return; + } + __vm_stop(reason); +} + /* reset/shutdown handler */ typedef struct QEMUResetEntry { @@ -3757,6 +3787,8 @@ static int cpu_can_run(CPUState *env) return 0; if (reset_requested) return 0; + if (vmstop_requested) + return 0; return 1; } @@ -4203,6 +4235,8 @@ static void qemu_init_state(void) static void main_loop(void) { + int r; + qemu_thread_self(&io_thread); setup_iothread_fd(); @@ -4219,12 +4253,14 @@ static void main_loop(void) no_shutdown = 0; else break; - } else if (qemu_powerdown_requested()) + } else if (qemu_powerdown_requested()) { qemu_system_powerdown(); - else if (qemu_reset_requested()) { + } else if (qemu_reset_requested()) { pause_all_vcpus(); qemu_system_reset(); resume_all_vcpus(); + } else if ((r = qemu_vmstop_requested())) { + vm_stop(r); } } }