From patchwork Fri May 27 12:19:05 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 823702 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p4RCJu7N003853 for ; Fri, 27 May 2011 12:19:57 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753989Ab1E0MTn (ORCPT ); Fri, 27 May 2011 08:19:43 -0400 Received: from david.siemens.de ([192.35.17.14]:16469 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753732Ab1E0MTa (ORCPT ); Fri, 27 May 2011 08:19:30 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.13.6/8.13.6) with ESMTP id p4RCJPRV002995; Fri, 27 May 2011 14:19:25 +0200 Received: from mchn199C.mchp.siemens.de ([139.25.109.49]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id p4RCJOKb005557; Fri, 27 May 2011 14:19:25 +0200 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org Subject: [PATCH 01/20] qemu-kvm: Move thread-related code to cpus.c Date: Fri, 27 May 2011 14:19:05 +0200 Message-Id: X-Mailer: git-send-email 1.7.1 In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 27 May 2011 12:19:57 +0000 (UTC) As a first step towards unified threading support, move all the related qemu-kvm-specific bits from qemu-kvm.c to cpus.c. This already allows to drop 3 identical functions (sigbus_reraise, sigbus_handler, sigfd_handler) and should provide the environment for consolidating the rest. Signed-off-by: Jan Kiszka --- cpus.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++++++ cpus.h | 1 + kvm-all.c | 2 +- qemu-kvm.c | 494 +----------------------------------------------------------- qemu-kvm.h | 1 + 5 files changed, 430 insertions(+), 493 deletions(-) diff --git a/cpus.c b/cpus.c index b64c29f..d209535 100644 --- a/cpus.c +++ b/cpus.c @@ -1179,3 +1179,428 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) cpu_list(f, cpu_fprintf); /* deprecated */ #endif } + + + +/* + * qemu-kvm threading code, integration zone + */ +#ifdef CONFIG_KVM + +#include + +#include "qemu-thread.h" + +pthread_mutex_t qemu_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t qemu_vcpu_cond = PTHREAD_COND_INITIALIZER; +pthread_cond_t qemu_system_cond = PTHREAD_COND_INITIALIZER; +pthread_cond_t qemu_pause_cond = PTHREAD_COND_INITIALIZER; +pthread_cond_t qemu_work_cond = PTHREAD_COND_INITIALIZER; +__thread CPUState *current_env; + +static int qemu_system_ready; + +static CPUState *kvm_debug_cpu_requested; + +unsigned long kvm_get_thread_id(void) +{ + return syscall(SYS_gettid); +} + +static void kvm_cond_wait(pthread_cond_t *cond) +{ + CPUState *env = cpu_single_env; + + pthread_cond_wait(cond, &qemu_mutex); + cpu_single_env = env; +} + +static void sig_ipi_handler(int n) +{ +} + +void on_vcpu(CPUState *env, void (*func)(void *data), void *data) +{ + struct qemu_work_item wi; + + if (env == current_env) { + func(data); + return; + } + + wi.func = func; + wi.data = data; + if (!env->kvm_cpu_state.queued_work_first) { + env->kvm_cpu_state.queued_work_first = &wi; + } else { + env->kvm_cpu_state.queued_work_last->next = &wi; + } + env->kvm_cpu_state.queued_work_last = &wi; + wi.next = NULL; + wi.done = false; + + pthread_kill(env->thread->thread, SIG_IPI); + while (!wi.done) { + kvm_cond_wait(&qemu_work_cond); + } +} + +void kvm_update_interrupt_request(CPUState *env) +{ + int signal = 0; + + if (env) { + if (!current_env || !current_env->created) { + signal = 1; + } + /* + * Testing for created here is really redundant + */ + if (current_env && current_env->created && + env != current_env && !env->thread_kicked) { + signal = 1; + } + + if (signal) { + env->thread_kicked = true; + if (env->thread) { + pthread_kill(env->thread->thread, SIG_IPI); + } + } + } +} + +static int kvm_cpu_is_stopped(CPUState *env) +{ + return !vm_running || env->stopped; +} + +static void flush_queued_work(CPUState *env) +{ + struct qemu_work_item *wi; + + if (!env->kvm_cpu_state.queued_work_first) { + return; + } + + while ((wi = env->kvm_cpu_state.queued_work_first)) { + env->kvm_cpu_state.queued_work_first = wi->next; + wi->func(wi->data); + wi->done = true; + } + env->kvm_cpu_state.queued_work_last = NULL; + pthread_cond_broadcast(&qemu_work_cond); +} + +static void kvm_main_loop_wait(CPUState *env, int timeout) +{ + struct timespec ts; + int r, e; + siginfo_t siginfo; + sigset_t waitset; + sigset_t chkset; + + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + sigemptyset(&waitset); + sigaddset(&waitset, SIG_IPI); + sigaddset(&waitset, SIGBUS); + + do { + pthread_mutex_unlock(&qemu_mutex); + + r = sigtimedwait(&waitset, &siginfo, &ts); + e = errno; + + pthread_mutex_lock(&qemu_mutex); + + if (r == -1 && !(e == EAGAIN || e == EINTR)) { + printf("sigtimedwait: %s\n", strerror(e)); + exit(1); + } + + switch (r) { + case SIGBUS: + if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) + sigbus_reraise(); + break; + default: + break; + } + + r = sigpending(&chkset); + if (r == -1) { + printf("sigpending: %s\n", strerror(e)); + exit(1); + } + } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS)); + + cpu_single_env = env; + flush_queued_work(env); + + if (env->stop) { + env->stop = 0; + env->stopped = 1; + pthread_cond_signal(&qemu_pause_cond); + } + + env->thread_kicked = false; +} + +static int all_threads_paused(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + if (penv->stop) { + return 0; + } + penv = (CPUState *) penv->next_cpu; + } + + return 1; +} + +static void pause_all_threads(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + if (penv != cpu_single_env) { + penv->stop = 1; + pthread_kill(penv->thread->thread, SIG_IPI); + } else { + penv->stop = 0; + penv->stopped = 1; + cpu_exit(penv); + } + penv = (CPUState *) penv->next_cpu; + } + + while (!all_threads_paused()) { + kvm_cond_wait(&qemu_pause_cond); + } +} + +static void resume_all_threads(void) +{ + CPUState *penv = first_cpu; + + assert(!cpu_single_env); + + while (penv) { + penv->stop = 0; + penv->stopped = 0; + pthread_kill(penv->thread->thread, SIG_IPI); + penv = (CPUState *) penv->next_cpu; + } +} + +static void kvm_vm_state_change_handler(void *context, int running, int reason) +{ + if (running) { + resume_all_threads(); + } else { + pause_all_threads(); + } +} + +static void setup_kernel_sigmask(CPUState *env) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + sigprocmask(SIG_BLOCK, &set, NULL); + + sigprocmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + sigdelset(&set, SIGBUS); + + kvm_set_signal_mask(env, &set); +} + +static void qemu_kvm_system_reset(void) +{ + pause_all_threads(); + + cpu_synchronize_all_states(); + qemu_system_reset(); + + resume_all_threads(); +} + +static int kvm_main_loop_cpu(CPUState *env) +{ + while (1) { + int timeout = 1000; + if (!kvm_cpu_is_stopped(env)) { + switch (kvm_cpu_exec(env)) { + case EXCP_HLT: + break; + case EXCP_DEBUG: + kvm_debug_cpu_requested = env; + env->stopped = 1; + break; + default: + timeout = 0; + break; + } + } + kvm_main_loop_wait(env, timeout); + } + pthread_mutex_unlock(&qemu_mutex); + return 0; +} + +static void *ap_main_loop(void *_env) +{ + CPUState *env = _env; + + current_env = env; + env->thread_id = kvm_get_thread_id(); + + pthread_mutex_lock(&qemu_mutex); + cpu_single_env = env; + + if (kvm_create_vcpu(env) < 0) { + abort(); + } + setup_kernel_sigmask(env); + + /* signal VCPU creation */ + current_env->created = 1; + pthread_cond_signal(&qemu_vcpu_cond); + + /* and wait for machine initialization */ + while (!qemu_system_ready) { + kvm_cond_wait(&qemu_system_cond); + } + + /* re-initialize cpu_single_env after re-acquiring qemu_mutex */ + cpu_single_env = env; + + kvm_main_loop_cpu(env); + return NULL; +} + +int kvm_init_vcpu(CPUState *env) +{ + env->thread = qemu_mallocz(sizeof(QemuThread)); + qemu_thread_create(env->thread, ap_main_loop, env); + + while (env->created == 0) { + kvm_cond_wait(&qemu_vcpu_cond); + } + + return 0; +} + +int kvm_init_ap(void) +{ + struct sigaction action; + + pthread_mutex_lock(&qemu_mutex); + + qemu_add_vm_change_state_handler(kvm_vm_state_change_handler, NULL); + + signal(SIG_IPI, sig_ipi_handler); + + memset(&action, 0, sizeof(action)); + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler; + sigaction(SIGBUS, &action, NULL); + prctl(PR_MCE_KILL, 1, 1, 0, 0); + return 0; +} + +bool qemu_system_is_ready(void) +{ + return qemu_system_ready; +} + +int kvm_main_loop(void) +{ + sigset_t mask; + int sigfd; + + qemu_system_ready = 1; + + sigemptyset(&mask); + sigaddset(&mask, SIGIO); + sigaddset(&mask, SIGALRM); + sigaddset(&mask, SIGBUS); + sigprocmask(SIG_BLOCK, &mask, NULL); + + sigfd = qemu_signalfd(&mask); + if (sigfd == -1) { + fprintf(stderr, "failed to create signalfd\n"); + return -errno; + } + + fcntl(sigfd, F_SETFL, O_NONBLOCK); + + qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, + (void *)(unsigned long) sigfd); + + pthread_cond_broadcast(&qemu_system_cond); + + cpu_single_env = NULL; + + while (1) { + main_loop_wait(0); + if (qemu_shutdown_requested()) { + monitor_protocol_event(QEVENT_SHUTDOWN, NULL); + if (qemu_no_shutdown()) { + vm_stop(VMSTOP_SHUTDOWN); + } else { + break; + } + } else if (qemu_powerdown_requested()) { + monitor_protocol_event(QEVENT_POWERDOWN, NULL); + qemu_irq_raise(qemu_system_powerdown); + } else if (qemu_reset_requested()) { + qemu_kvm_system_reset(); + } else if (kvm_debug_cpu_requested) { + gdb_set_stop_cpu(kvm_debug_cpu_requested); + vm_stop(VMSTOP_DEBUG); + kvm_debug_cpu_requested = NULL; + } + } + + bdrv_close_all(); + pause_all_threads(); + pthread_mutex_unlock(&qemu_mutex); + + return 0; +} + +static void kvm_mutex_unlock(void) +{ + assert(!cpu_single_env); + pthread_mutex_unlock(&qemu_mutex); +} + +static void kvm_mutex_lock(void) +{ + pthread_mutex_lock(&qemu_mutex); + cpu_single_env = NULL; +} + +void qemu_mutex_unlock_iothread(void) +{ + if (kvm_enabled()) { + kvm_mutex_unlock(); + } +} + +void qemu_mutex_lock_iothread(void) +{ + if (kvm_enabled()) { + kvm_mutex_lock(); + } +} + +#endif /* CONFIG_KVM */ diff --git a/cpus.h b/cpus.h index 6fdeb0d..4838b16 100644 --- a/cpus.h +++ b/cpus.h @@ -7,6 +7,7 @@ void qemu_main_loop_start(void); void resume_all_vcpus(void); void pause_all_vcpus(void); void cpu_stop_current(void); +bool qemu_system_is_ready(void); void cpu_synchronize_all_states(void); void cpu_synchronize_all_post_reset(void); diff --git a/kvm-all.c b/kvm-all.c index 88d0785..bd53422 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -208,7 +208,7 @@ int kvm_pit_in_kernel(void) return kvm_state->pit_in_kernel; } -static int kvm_create_vcpu(CPUState *env) +int kvm_create_vcpu(CPUState *env) { KVMState *s = kvm_state; long mmap_size; diff --git a/qemu-kvm.c b/qemu-kvm.c index 94e12f3..dfbf045 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -19,29 +19,9 @@ #include "gdbstub.h" #include "monitor.h" #include "cpus.h" -#include "qemu-thread.h" #include "qemu-kvm.h" -#include -#include -#include -#include -#include -#include "compatfd.h" -#include - -#ifndef PR_MCE_KILL -#define PR_MCE_KILL 33 -#endif - -#ifndef BUS_MCEERR_AR -#define BUS_MCEERR_AR 4 -#endif -#ifndef BUS_MCEERR_AO -#define BUS_MCEERR_AO 5 -#endif - #define EXPECTED_KVM_API_VERSION 12 #if EXPECTED_KVM_API_VERSION != KVM_API_VERSION @@ -53,19 +33,6 @@ int kvm_pit = 1; int kvm_pit_reinject = 1; int kvm_nested = 0; -pthread_mutex_t qemu_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t qemu_vcpu_cond = PTHREAD_COND_INITIALIZER; -pthread_cond_t qemu_system_cond = PTHREAD_COND_INITIALIZER; -pthread_cond_t qemu_pause_cond = PTHREAD_COND_INITIALIZER; -pthread_cond_t qemu_work_cond = PTHREAD_COND_INITIALIZER; -__thread CPUState *current_env; - -static int qemu_system_ready; - -#define SIG_IPI (SIGRTMIN+4) - -CPUState *kvm_debug_cpu_requested; - #define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1)) static inline void set_gsi(KVMState *s, unsigned int gsi) @@ -571,326 +538,6 @@ int kvm_assign_set_msix_entry(KVMState *s, } #endif -unsigned long kvm_get_thread_id(void) -{ - return syscall(SYS_gettid); -} - -static void kvm_cond_wait(pthread_cond_t *cond) -{ - CPUState *env = cpu_single_env; - - pthread_cond_wait(cond, &qemu_mutex); - cpu_single_env = env; -} - -static void sig_ipi_handler(int n) -{ -} - -static void sigbus_reraise(void) -{ - sigset_t set; - struct sigaction action; - - memset(&action, 0, sizeof(action)); - action.sa_handler = SIG_DFL; - if (!sigaction(SIGBUS, &action, NULL)) { - raise(SIGBUS); - sigemptyset(&set); - sigaddset(&set, SIGBUS); - sigprocmask(SIG_UNBLOCK, &set, NULL); - } - perror("Failed to re-raise SIGBUS!\n"); - abort(); -} - -static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo, - void *ctx) -{ - if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr)) - sigbus_reraise(); -} - -void on_vcpu(CPUState *env, void (*func)(void *data), void *data) -{ - struct qemu_work_item wi; - - if (env == current_env) { - func(data); - return; - } - - wi.func = func; - wi.data = data; - if (!env->kvm_cpu_state.queued_work_first) { - env->kvm_cpu_state.queued_work_first = &wi; - } else { - env->kvm_cpu_state.queued_work_last->next = &wi; - } - env->kvm_cpu_state.queued_work_last = &wi; - wi.next = NULL; - wi.done = false; - - pthread_kill(env->thread->thread, SIG_IPI); - while (!wi.done) { - kvm_cond_wait(&qemu_work_cond); - } -} - -void kvm_update_interrupt_request(CPUState *env) -{ - int signal = 0; - - if (env) { - if (!current_env || !current_env->created) { - signal = 1; - } - /* - * Testing for created here is really redundant - */ - if (current_env && current_env->created && - env != current_env && !env->thread_kicked) { - signal = 1; - } - - if (signal) { - env->thread_kicked = true; - if (env->thread) { - pthread_kill(env->thread->thread, SIG_IPI); - } - } - } -} - -static int kvm_cpu_is_stopped(CPUState *env) -{ - return !vm_running || env->stopped; -} - -static void flush_queued_work(CPUState *env) -{ - struct qemu_work_item *wi; - - if (!env->kvm_cpu_state.queued_work_first) { - return; - } - - while ((wi = env->kvm_cpu_state.queued_work_first)) { - env->kvm_cpu_state.queued_work_first = wi->next; - wi->func(wi->data); - wi->done = true; - } - env->kvm_cpu_state.queued_work_last = NULL; - pthread_cond_broadcast(&qemu_work_cond); -} - -static void kvm_main_loop_wait(CPUState *env, int timeout) -{ - struct timespec ts; - int r, e; - siginfo_t siginfo; - sigset_t waitset; - sigset_t chkset; - - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - sigemptyset(&waitset); - sigaddset(&waitset, SIG_IPI); - sigaddset(&waitset, SIGBUS); - - do { - pthread_mutex_unlock(&qemu_mutex); - - r = sigtimedwait(&waitset, &siginfo, &ts); - e = errno; - - pthread_mutex_lock(&qemu_mutex); - - if (r == -1 && !(e == EAGAIN || e == EINTR)) { - printf("sigtimedwait: %s\n", strerror(e)); - exit(1); - } - - switch (r) { - case SIGBUS: - if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) - sigbus_reraise(); - break; - default: - break; - } - - r = sigpending(&chkset); - if (r == -1) { - printf("sigpending: %s\n", strerror(e)); - exit(1); - } - } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS)); - - cpu_single_env = env; - flush_queued_work(env); - - if (env->stop) { - env->stop = 0; - env->stopped = 1; - pthread_cond_signal(&qemu_pause_cond); - } - - env->thread_kicked = false; -} - -static int all_threads_paused(void) -{ - CPUState *penv = first_cpu; - - while (penv) { - if (penv->stop) { - return 0; - } - penv = (CPUState *) penv->next_cpu; - } - - return 1; -} - -static void pause_all_threads(void) -{ - CPUState *penv = first_cpu; - - while (penv) { - if (penv != cpu_single_env) { - penv->stop = 1; - pthread_kill(penv->thread->thread, SIG_IPI); - } else { - penv->stop = 0; - penv->stopped = 1; - cpu_exit(penv); - } - penv = (CPUState *) penv->next_cpu; - } - - while (!all_threads_paused()) { - kvm_cond_wait(&qemu_pause_cond); - } -} - -static void resume_all_threads(void) -{ - CPUState *penv = first_cpu; - - assert(!cpu_single_env); - - while (penv) { - penv->stop = 0; - penv->stopped = 0; - pthread_kill(penv->thread->thread, SIG_IPI); - penv = (CPUState *) penv->next_cpu; - } -} - -static void kvm_vm_state_change_handler(void *context, int running, int reason) -{ - if (running) { - resume_all_threads(); - } else { - pause_all_threads(); - } -} - -static void setup_kernel_sigmask(CPUState *env) -{ - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigprocmask(SIG_BLOCK, &set, NULL); - - sigprocmask(SIG_BLOCK, NULL, &set); - sigdelset(&set, SIG_IPI); - sigdelset(&set, SIGBUS); - - kvm_set_signal_mask(env, &set); -} - -static void qemu_kvm_system_reset(void) -{ - pause_all_threads(); - - cpu_synchronize_all_states(); - qemu_system_reset(); - - resume_all_threads(); -} - -static int kvm_main_loop_cpu(CPUState *env) -{ - while (1) { - int timeout = 1000; - if (!kvm_cpu_is_stopped(env)) { - switch (kvm_cpu_exec(env)) { - case EXCP_HLT: - break; - case EXCP_DEBUG: - kvm_debug_cpu_requested = env; - env->stopped = 1; - break; - default: - timeout = 0; - break; - } - } - kvm_main_loop_wait(env, timeout); - } - pthread_mutex_unlock(&qemu_mutex); - return 0; -} - -static void *ap_main_loop(void *_env) -{ - CPUState *env = _env; - - current_env = env; - env->thread_id = kvm_get_thread_id(); - - pthread_mutex_lock(&qemu_mutex); - cpu_single_env = env; - - if (kvm_create_vcpu(env) < 0) { - abort(); - } - setup_kernel_sigmask(env); - - /* signal VCPU creation */ - current_env->created = 1; - pthread_cond_signal(&qemu_vcpu_cond); - - /* and wait for machine initialization */ - while (!qemu_system_ready) { - kvm_cond_wait(&qemu_system_cond); - } - - /* re-initialize cpu_single_env after re-acquiring qemu_mutex */ - cpu_single_env = env; - - kvm_main_loop_cpu(env); - return NULL; -} - -int kvm_init_vcpu(CPUState *env) -{ - env->thread = qemu_mallocz(sizeof(QemuThread)); - qemu_thread_create(env->thread, ap_main_loop, env); - - while (env->created == 0) { - kvm_cond_wait(&qemu_vcpu_cond); - } - - return 0; -} - #ifdef TARGET_I386 void kvm_hpet_disable_kpit(void) { @@ -911,116 +558,6 @@ void kvm_hpet_enable_kpit(void) } #endif -int kvm_init_ap(void) -{ - struct sigaction action; - - pthread_mutex_lock(&qemu_mutex); - - qemu_add_vm_change_state_handler(kvm_vm_state_change_handler, NULL); - - signal(SIG_IPI, sig_ipi_handler); - - memset(&action, 0, sizeof(action)); - action.sa_flags = SA_SIGINFO; - action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler; - sigaction(SIGBUS, &action, NULL); - prctl(PR_MCE_KILL, 1, 1, 0, 0); - return 0; -} - -/* If we have signalfd, we mask out the signals we want to handle and then - * use signalfd to listen for them. We rely on whatever the current signal - * handler is to dispatch the signals when we receive them. - */ - -static void sigfd_handler(void *opaque) -{ - int fd = (unsigned long) opaque; - struct qemu_signalfd_siginfo info; - struct sigaction action; - ssize_t len; - - while (1) { - do { - len = read(fd, &info, sizeof(info)); - } while (len == -1 && errno == EINTR); - - if (len == -1 && errno == EAGAIN) { - break; - } - - if (len != sizeof(info)) { - printf("read from sigfd returned %zd: %m\n", len); - return; - } - - sigaction(info.ssi_signo, NULL, &action); - if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) { - action.sa_sigaction(info.ssi_signo, - (siginfo_t *)&info, NULL); - } else if (action.sa_handler) { - action.sa_handler(info.ssi_signo); - } - } -} - -int kvm_main_loop(void) -{ - sigset_t mask; - int sigfd; - - qemu_system_ready = 1; - - sigemptyset(&mask); - sigaddset(&mask, SIGIO); - sigaddset(&mask, SIGALRM); - sigaddset(&mask, SIGBUS); - sigprocmask(SIG_BLOCK, &mask, NULL); - - sigfd = qemu_signalfd(&mask); - if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); - return -errno; - } - - fcntl(sigfd, F_SETFL, O_NONBLOCK); - - qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, - (void *)(unsigned long) sigfd); - - pthread_cond_broadcast(&qemu_system_cond); - - cpu_single_env = NULL; - - while (1) { - main_loop_wait(0); - if (qemu_shutdown_requested()) { - monitor_protocol_event(QEVENT_SHUTDOWN, NULL); - if (qemu_no_shutdown()) { - vm_stop(VMSTOP_SHUTDOWN); - } else { - break; - } - } else if (qemu_powerdown_requested()) { - monitor_protocol_event(QEVENT_POWERDOWN, NULL); - qemu_irq_raise(qemu_system_powerdown); - } else if (qemu_reset_requested()) { - qemu_kvm_system_reset(); - } else if (kvm_debug_cpu_requested) { - gdb_set_stop_cpu(kvm_debug_cpu_requested); - vm_stop(VMSTOP_DEBUG); - kvm_debug_cpu_requested = NULL; - } - } - - bdrv_close_all(); - pause_all_threads(); - pthread_mutex_unlock(&qemu_mutex); - - return 0; -} - #if !defined(TARGET_I386) int kvm_arch_init_irq_routing(void) { @@ -1028,32 +565,6 @@ int kvm_arch_init_irq_routing(void) } #endif -static void kvm_mutex_unlock(void) -{ - assert(!cpu_single_env); - pthread_mutex_unlock(&qemu_mutex); -} - -static void kvm_mutex_lock(void) -{ - pthread_mutex_lock(&qemu_mutex); - cpu_single_env = NULL; -} - -void qemu_mutex_unlock_iothread(void) -{ - if (kvm_enabled()) { - kvm_mutex_unlock(); - } -} - -void qemu_mutex_lock_iothread(void) -{ - if (kvm_enabled()) { - kvm_mutex_lock(); - } -} - #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT typedef struct KVMIOPortRegion { unsigned long start; @@ -1089,7 +600,7 @@ int kvm_add_ioport_region(unsigned long start, unsigned long size) region->status = 1; QLIST_INSERT_HEAD(&ioport_regions, region, entry); - if (qemu_system_ready) { + if (qemu_system_is_ready()) { for (env = first_cpu; env != NULL; env = env->next_cpu) { on_vcpu(env, do_set_ioport_access, region); if (region->status < 0) { @@ -1112,7 +623,7 @@ int kvm_remove_ioport_region(unsigned long start, unsigned long size) if (region->start == start && region->size == size) { region->status = 0; } - if (qemu_system_ready) { + if (qemu_system_is_ready()) { for (env = first_cpu; env != NULL; env = env->next_cpu) { on_vcpu(env, do_set_ioport_access, region); } @@ -1155,4 +666,3 @@ int kvm_set_boot_cpu_id(KVMState *s, uint32_t id) #endif return -ENOSYS; } - diff --git a/qemu-kvm.h b/qemu-kvm.h index 094aef2..0ebd3eb 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -265,6 +265,7 @@ struct kvm_pit_state { #endif /* !CONFIG_KVM */ +int kvm_create_vcpu(CPUState *env); int kvm_main_loop(void); int kvm_init_ap(void); void kvm_save_lapic(CPUState *env);