From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LkJpL-0007ux-Ei for qemu-devel@nongnu.org; Thu, 19 Mar 2009 11:06:35 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LkJpG-0007sT-OI for qemu-devel@nongnu.org; Thu, 19 Mar 2009 11:06:34 -0400 Received: from [199.232.76.173] (port=51969 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LkJpG-0007sM-BE for qemu-devel@nongnu.org; Thu, 19 Mar 2009 11:06:30 -0400 Received: from mx2.redhat.com ([66.187.237.31]:36017) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LkJpF-0005wW-Jq for qemu-devel@nongnu.org; Thu, 19 Mar 2009 11:06:30 -0400 Message-Id: <20090319150538.231529048@localhost.localdomain> References: <20090319145705.988576615@localhost.localdomain> Date: Thu, 19 Mar 2009 11:57:10 -0300 From: mtosatti@redhat.com Content-Disposition: inline; filename=pause-stop-threads Subject: [Qemu-devel] [patch 5/7] qemu: pause and resume cpu thread(s) 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 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. Index: qemu/vl.c =================================================================== --- qemu.orig/vl.c +++ qemu/vl.c @@ -271,6 +271,11 @@ QemuMutex qemu_fair_mutex; QemuThread io_thread; QemuThread cpus_thread; +QemuCond qemu_pause_cond; + +static void pause_all_vcpus(void); +static void resume_all_vcpus(void); + /***********************************************************/ /* x86 ISA bus support */ @@ -3461,6 +3466,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); } @@ -3471,6 +3477,7 @@ void vm_stop(int reason) if (vm_running) { cpu_disable_ticks(); vm_running = 0; + pause_all_vcpus(); vm_state_notify(0, reason); } } @@ -3620,7 +3627,9 @@ static int wait_signal(int timeout) static int has_work(CPUState *env) { - if (!vm_running) + if (env->stop) + return 1; + if (!vm_running || env->stopped) return 0; if (!env->halted) return 1; @@ -3644,6 +3653,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); + } } static void cpu_signal(int sig) @@ -3848,6 +3862,21 @@ void main_loop_wait(int timeout) } +static int vm_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; +} + static void *cpu_main_loop(void *arg) { int ret, timeout; @@ -3887,7 +3916,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 (vm_can_run(env)) + ret = cpu_exec(env); #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif @@ -3965,6 +3996,7 @@ static void *cpu_main_loop(void *arg) timeout = 0; } } else { + env = env->next_cpu ?: first_cpu; timeout = 5000; } #ifdef CONFIG_PROFILER @@ -3979,11 +4011,53 @@ static void *cpu_main_loop(void *arg) return NULL; } +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(&cpus_thread, SIGUSR1); + penv = (CPUState *)penv->next_cpu; + } + + while (!all_vcpus_paused()) { + qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); + qemu_thread_signal(&cpus_thread, SIGUSR1); + } +} + +static void resume_all_vcpus(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + penv->stop = 0; + penv->stopped = 0; + qemu_thread_signal(&cpus_thread, SIGUSR1); + penv = (CPUState *)penv->next_cpu; + } +} + static void main_loop(void) { qemu_mutex_init(&qemu_fair_mutex); qemu_mutex_init(&qemu_global_mutex); qemu_mutex_lock(&qemu_global_mutex); + qemu_cond_init(&qemu_pause_cond); qemu_thread_self(&io_thread); @@ -3994,14 +4068,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(); + } } } Index: qemu/cpu-defs.h =================================================================== --- qemu.orig/cpu-defs.h +++ qemu/cpu-defs.h @@ -169,6 +169,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; \ /* The meaning of the MMU modes is defined in the target code. */ \ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ --