From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Lmc13-00029H-TT for qemu-devel@nongnu.org; Wed, 25 Mar 2009 18:56:10 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lmc0y-00021C-7w for qemu-devel@nongnu.org; Wed, 25 Mar 2009 18:56:08 -0400 Received: from [199.232.76.173] (port=49791 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lmc0w-000205-P2 for qemu-devel@nongnu.org; Wed, 25 Mar 2009 18:56:02 -0400 Received: from mx2.redhat.com ([66.187.237.31]:51076) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Lmc0w-0006I6-6U for qemu-devel@nongnu.org; Wed, 25 Mar 2009 18:56:02 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n2PMu1fo032459 for ; Wed, 25 Mar 2009 18:56:01 -0400 Message-Id: <20090325225439.270426058@amt.cnet> Date: Wed, 25 Mar 2009 19:47:22 -0300 From: Marcelo Tosatti References: <20090325224714.853788328@amt.cnet> Content-Disposition: inline; filename=pause-stop-threads-2 Subject: [Qemu-devel] [patch 08/10] qemu: pause and resume cpu threads Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Marcelo Tosatti 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(); + } } }