From patchwork Wed Feb 17 22:14:42 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Tosatti X-Patchwork-Id: 45776 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DACD6B7D25 for ; Fri, 19 Feb 2010 01:07:22 +1100 (EST) Received: from localhost ([127.0.0.1]:41995 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ni6yq-0006mx-JM for incoming@patchwork.ozlabs.org; Thu, 18 Feb 2010 09:03:48 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Ni6su-0005o9-9s for qemu-devel@nongnu.org; Thu, 18 Feb 2010 08:57:40 -0500 Received: from [199.232.76.173] (port=50296 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ni6st-0005nx-Li for qemu-devel@nongnu.org; Thu, 18 Feb 2010 08:57:39 -0500 Received: from Debian-exim by monty-python.gnu.org with spam-scanned (Exim 4.60) (envelope-from ) id 1Ni6ss-0001Pb-Ia for qemu-devel@nongnu.org; Thu, 18 Feb 2010 08:57:39 -0500 Received: from mx1.redhat.com ([209.132.183.28]:63762) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Ni6sr-0001P5-Cd for qemu-devel@nongnu.org; Thu, 18 Feb 2010 08:57:37 -0500 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o1IDvZEK009400 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 18 Feb 2010 08:57:35 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx04.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o1IDvYTg011716; Thu, 18 Feb 2010 08:57:35 -0500 Received: from amt.cnet (vpn-8-98.rdu.redhat.com [10.11.8.98]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id o1IDvVgv025564; Thu, 18 Feb 2010 08:57:32 -0500 Received: from amt.cnet (amt.cnet [127.0.0.1]) by amt.cnet (Postfix) with ESMTP id 1910B68A97B; Thu, 18 Feb 2010 11:57:23 -0200 (BRST) Received: (from marcelo@localhost) by amt.cnet (8.14.3/8.14.3/Submit) id o1IDvLd6007756; Thu, 18 Feb 2010 11:57:21 -0200 Message-Id: <20100217221701.109038421@redhat.com> User-Agent: quilt/0.47-1 Date: Wed, 17 Feb 2010 20:14:42 -0200 From: Marcelo Tosatti To: kvm@vger.kernel.org, qemu-devel@nongnu.org References: <20100217221439.351652889@redhat.com> Content-Disposition: inline; filename=kvm-block-cpu-exit-signal X-Scanned-By: MIMEDefang 2.67 on 10.5.11.17 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Marcelo Tosatti , avi@redhat.com Subject: [Qemu-devel] [patch uq/master 3/4] qemu: kvm: consume internal signal with sigtimedwait X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Change the way the internal qemu signal, used for communication between iothread and vcpus, is handled. Block and consume it with sigtimedwait on the outer vcpu loop, which allows more precise timing control. Change from standard signal (SIGUSR1) to real-time one, so multiple signals are not collapsed. Set the signal number on KVM's in-kernel allowed sigmask. Signed-off-by: Marcelo Tosatti Index: qemu-kvm/vl.c =================================================================== --- qemu-kvm.orig/vl.c +++ qemu-kvm/vl.c @@ -271,6 +271,12 @@ uint8_t qemu_uuid[16]; static QEMUBootSetHandler *boot_set_handler; static void *boot_set_opaque; +#ifdef SIGRTMIN +#define SIG_IPI (SIGRTMIN+4) +#else +#define SIG_IPI SIGUSR1 +#endif + static int default_serial = 1; static int default_parallel = 1; static int default_virtcon = 1; @@ -3379,7 +3385,8 @@ static QemuCond qemu_cpu_cond; static QemuCond qemu_system_cond; static QemuCond qemu_pause_cond; -static void block_io_signals(void); +static void tcg_block_io_signals(void); +static void kvm_block_io_signals(CPUState *env); static void unblock_io_signals(void); static int tcg_has_work(void); static int cpu_has_work(CPUState *env); @@ -3431,11 +3438,36 @@ static void qemu_wait_io_event(CPUState qemu_wait_io_event_common(env); } +static void qemu_kvm_eat_signal(CPUState *env, int timeout) +{ + struct timespec ts; + int r, e; + siginfo_t siginfo; + sigset_t waitset; + + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + sigemptyset(&waitset); + sigaddset(&waitset, SIG_IPI); + + qemu_mutex_unlock(&qemu_global_mutex); + r = sigtimedwait(&waitset, &siginfo, &ts); + e = errno; + qemu_mutex_lock(&qemu_global_mutex); + + if (r == -1 && !(e == EAGAIN || e == EINTR)) { + fprintf(stderr, "sigtimedwait: %s\n", strerror(e)); + exit(1); + } +} + static void qemu_kvm_wait_io_event(CPUState *env) { while (!cpu_has_work(env)) qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); + qemu_kvm_eat_signal(env, 0); qemu_wait_io_event_common(env); } @@ -3445,11 +3477,12 @@ static void *kvm_cpu_thread_fn(void *arg { CPUState *env = arg; - block_io_signals(); qemu_thread_self(env->thread); if (kvm_enabled()) kvm_init_vcpu(env); + kvm_block_io_signals(env); + /* signal CPU creation */ qemu_mutex_lock(&qemu_global_mutex); env->created = 1; @@ -3474,7 +3507,7 @@ static void *tcg_cpu_thread_fn(void *arg { CPUState *env = arg; - block_io_signals(); + tcg_block_io_signals(); qemu_thread_self(env->thread); /* signal CPU creation */ @@ -3500,7 +3533,7 @@ void qemu_cpu_kick(void *_env) CPUState *env = _env; qemu_cond_broadcast(env->halt_cond); if (kvm_enabled()) - qemu_thread_signal(env->thread, SIGUSR1); + qemu_thread_signal(env->thread, SIG_IPI); } int qemu_cpu_self(void *_env) @@ -3519,7 +3552,7 @@ static void cpu_signal(int sig) cpu_exit(cpu_single_env); } -static void block_io_signals(void) +static void tcg_block_io_signals(void) { sigset_t set; struct sigaction sigact; @@ -3532,12 +3565,44 @@ static void block_io_signals(void) pthread_sigmask(SIG_BLOCK, &set, NULL); sigemptyset(&set); - sigaddset(&set, SIGUSR1); + sigaddset(&set, SIG_IPI); pthread_sigmask(SIG_UNBLOCK, &set, NULL); memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = cpu_signal; - sigaction(SIGUSR1, &sigact, NULL); + sigaction(SIG_IPI, &sigact, NULL); +} + +static void dummy_signal(int sig) +{ +} + +static void kvm_block_io_signals(CPUState *env) +{ + int r; + sigset_t set; + struct sigaction sigact; + + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIGCHLD); + sigaddset(&set, SIG_IPI); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + pthread_sigmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = dummy_signal; + sigaction(SIG_IPI, &sigact, NULL); + + r = kvm_set_signal_mask(env, &set); + if (r) { + fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r)); + exit(1); + } } static void unblock_io_signals(void) @@ -3551,7 +3616,7 @@ static void unblock_io_signals(void) pthread_sigmask(SIG_UNBLOCK, &set, NULL); sigemptyset(&set); - sigaddset(&set, SIGUSR1); + sigaddset(&set, SIG_IPI); pthread_sigmask(SIG_BLOCK, &set, NULL); } @@ -3560,7 +3625,7 @@ static void qemu_signal_lock(unsigned in qemu_mutex_lock(&qemu_fair_mutex); while (qemu_mutex_trylock(&qemu_global_mutex)) { - qemu_thread_signal(tcg_cpu_thread, SIGUSR1); + qemu_thread_signal(tcg_cpu_thread, SIG_IPI); if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs)) break; } @@ -3601,7 +3666,7 @@ static void pause_all_vcpus(void) while (penv) { penv->stop = 1; - qemu_thread_signal(penv->thread, SIGUSR1); + qemu_thread_signal(penv->thread, SIG_IPI); qemu_cpu_kick(penv); penv = (CPUState *)penv->next_cpu; } @@ -3610,7 +3675,7 @@ static void pause_all_vcpus(void) qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); penv = first_cpu; while (penv) { - qemu_thread_signal(penv->thread, SIGUSR1); + qemu_thread_signal(penv->thread, SIG_IPI); penv = (CPUState *)penv->next_cpu; } } @@ -3623,7 +3688,7 @@ static void resume_all_vcpus(void) while (penv) { penv->stop = 0; penv->stopped = 0; - qemu_thread_signal(penv->thread, SIGUSR1); + qemu_thread_signal(penv->thread, SIG_IPI); qemu_cpu_kick(penv); penv = (CPUState *)penv->next_cpu; } Index: qemu-kvm/kvm-all.c =================================================================== --- qemu-kvm.orig/kvm-all.c +++ qemu-kvm/kvm-all.c @@ -771,6 +771,7 @@ int kvm_cpu_exec(CPUState *env) kvm_arch_post_run(env, run); if (ret == -EINTR || ret == -EAGAIN) { + cpu_exit(env); dprintf("io window exit\n"); ret = 0; break; @@ -1116,3 +1117,21 @@ void kvm_remove_all_breakpoints(CPUState { } #endif /* !KVM_CAP_SET_GUEST_DEBUG */ + +int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset) +{ + struct kvm_signal_mask *sigmask; + int r; + + if (!sigset) + return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL); + + sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset)); + + sigmask->len = 8; + memcpy(sigmask->sigset, sigset, sizeof(*sigset)); + r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask); + free(sigmask); + + return r; +} Index: qemu-kvm/kvm.h =================================================================== --- qemu-kvm.orig/kvm.h +++ qemu-kvm/kvm.h @@ -53,6 +53,7 @@ int kvm_remove_breakpoint(CPUState *curr target_ulong len, int type); void kvm_remove_all_breakpoints(CPUState *current_env); int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); +int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset); int kvm_pit_in_kernel(void); int kvm_irqchip_in_kernel(void);