Since cpu emulation happens on a separate thread, it is necessary to pause/resume it upon certain events such as reset, debug exception, live migration, etc. Signed-off-by: Marcelo Tosatti Index: trunk/cpu-defs.h =================================================================== --- trunk.orig/cpu-defs.h +++ trunk/cpu-defs.h @@ -172,6 +172,8 @@ typedef struct CPUWatchpoint { target_ulong mem_io_vaddr; /* target virtual addr at which the \ memory was accessed */ \ uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ + uint32_t stop; /* Stop request */ \ + uint32_t stopped; /* Artificially stopped */ \ uint32_t interrupt_request; \ volatile sig_atomic_t exit_request; \ /* The meaning of the MMU modes is defined in the target code. */ \ Index: trunk/vl.c =================================================================== --- trunk.orig/vl.c +++ trunk/vl.c @@ -292,6 +292,11 @@ QemuCond qemu_cpu_cond; /* system init */ QemuCond qemu_system_cond; +QemuCond qemu_pause_cond; + +static void pause_all_vcpus(void); +static void resume_all_vcpus(void); + /***********************************************************/ /* x86 ISA bus support */ @@ -3539,6 +3544,7 @@ void vm_start(void) if (!vm_running) { cpu_enable_ticks(); vm_running = 1; + resume_all_vcpus(); vm_state_notify(1, 0); qemu_rearm_alarm_timer(alarm_timer); } @@ -3549,6 +3555,7 @@ void vm_stop(int reason) if (vm_running) { cpu_disable_ticks(); vm_running = 0; + pause_all_vcpus(); vm_state_notify(0, reason); } } @@ -3737,8 +3744,29 @@ static void host_main_loop_wait(int *tim } #endif +/* Q: is it allowed to enter cpu_exec */ +static int cpu_can_run(CPUState *env) +{ + if (env->stop) + return 0; + if (env->stopped) + return 0; + if (shutdown_requested) + return 0; + if (powerdown_requested) + return 0; + if (reset_requested) + return 0; + return 1; +} + +/* Q: should break out of the wait loop */ static int cpu_has_work(CPUState *env) { + if (env->stop) + return 1; + if (env->stopped) + return 0; if (!env->halted) return 1; if (qemu_cpu_has_work(env)) @@ -3771,6 +3799,11 @@ static void qemu_wait_io_event(CPUState qemu_mutex_unlock(&qemu_fair_mutex); qemu_mutex_lock(&qemu_global_mutex); + if (env->stop) { + env->stop = 0; + env->stopped = 1; + qemu_cond_signal(&qemu_pause_cond); + } } void qemu_cpu_kick(void *_env) @@ -3837,6 +3870,53 @@ static void qemu_signal_lock(unsigned in qemu_mutex_unlock(&qemu_fair_mutex); } +static int all_vcpus_paused(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + if (penv->stop) + return 0; + penv = (CPUState *)penv->next_cpu; + } + + return 1; +} + +static void pause_all_vcpus(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + penv->stop = 1; + qemu_thread_signal(penv->thread, SIGUSR1); + qemu_cpu_kick(penv); + penv = (CPUState *)penv->next_cpu; + } + + while (!all_vcpus_paused()) { + qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); + penv = first_cpu; + while (penv) { + qemu_thread_signal(penv->thread, SIGUSR1); + penv = (CPUState *)penv->next_cpu; + } + } +} + +static void resume_all_vcpus(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + penv->stop = 0; + penv->stopped = 0; + qemu_thread_signal(penv->thread, SIGUSR1); + qemu_cpu_kick(penv); + penv = (CPUState *)penv->next_cpu; + } +} + void main_loop_wait(int timeout) { IOHandlerRecord *ioh; @@ -3999,7 +4079,9 @@ static void *cpu_main_loop(void *arg) env->icount_decr.u16.low = decr; env->icount_extra = count; } - ret = cpu_exec(env); + ret = EXCP_HALTED; + if (cpu_can_run(env)) + ret = cpu_exec(env); #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif @@ -4113,6 +4195,7 @@ void qemu_init_vcpu(void *_env) static void qemu_init_state(void) { + qemu_cond_init(&qemu_pause_cond); qemu_mutex_init(&qemu_fair_mutex); qemu_mutex_init(&qemu_global_mutex); qemu_mutex_lock(&qemu_global_mutex); @@ -4131,14 +4214,18 @@ static void main_loop(void) while (1) { main_loop_wait(1000); if (qemu_shutdown_requested()) { + pause_all_vcpus(); if (no_shutdown) no_shutdown = 0; else break; } 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(); + } } }