Patchwork [6/8] kvm: consume internal signal with sigtimedwait

login
register
mail settings
Submitter Marcelo Tosatti
Date Feb. 22, 2010, 9:26 p.m.
Message ID <cc84de9570ffe01a9c3c169bd62ab9586a9a080c.1266874009.git.mtosatti@redhat.com>
Download mbox | patch
Permalink /patch/46019/
State New
Headers show

Comments

Marcelo Tosatti - Feb. 22, 2010, 9:26 p.m.
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 <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
 kvm-all.c |   19 +++++++++++++
 kvm.h     |    1 +
 vl.c      |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 97 insertions(+), 12 deletions(-)
Andreas Färber - March 6, 2011, 5:46 p.m.
Hello,

Am 22.02.2010 um 22:26 schrieb Marcelo Tosatti:

> 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.

Mac OS X v10.5 does not seem to support sigtimedwait():

   CC    arm-softmmu/cpus.o
/Users/andreas/QEMU/qemu/cpus.c: In function ‘qemu_kvm_eat_signals’:
/Users/andreas/QEMU/qemu/cpus.c:379: warning: implicit declaration of  
function ‘sigtimedwait’
/Users/andreas/QEMU/qemu/cpus.c:379: warning: nested extern  
declaration of ‘sigtimedwait’
/Users/andreas/QEMU/qemu/cpus.c:388: warning: implicit declaration of  
function ‘sigbus_reraise’
/Users/andreas/QEMU/qemu/cpus.c:388: warning: nested extern  
declaration of ‘sigbus_reraise’

Could you please add some #ifdef? It used to be an optional POSIX  
extension.

Thanks,
Andreas

> 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 <mtosatti@redhat.com>
> Signed-off-by: Avi Kivity <avi@redhat.com>
> ---
> kvm-all.c |   19 +++++++++++++
> kvm.h     |    1 +
> vl.c      |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++ 
> +--------
> 3 files changed, 97 insertions(+), 12 deletions(-)

> diff --git a/vl.c b/vl.c
> index af198c1..dc05da3 100644
> --- a/vl.c
> +++ b/vl.c

> @@ -3432,11 +3439,36 @@ static void qemu_wait_io_event(CPUState *env)
>     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);
> +    }
> +}

Patch

diff --git a/kvm-all.c b/kvm-all.c
index 79345b2..38c372f 100644
--- a/kvm-all.c
+++ b/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 *current_env)
 {
 }
 #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;
+}
diff --git a/kvm.h b/kvm.h
index e24bbde..9a9cdd5 100644
--- a/kvm.h
+++ b/kvm.h
@@ -53,6 +53,7 @@  int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
                           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);
diff --git a/vl.c b/vl.c
index af198c1..dc05da3 100644
--- a/vl.c
+++ b/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;
@@ -3380,7 +3386,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);
@@ -3432,11 +3439,36 @@  static void qemu_wait_io_event(CPUState *env)
     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);
 }
 
@@ -3446,11 +3478,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;
@@ -3475,7 +3508,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 */
@@ -3501,7 +3534,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)
@@ -3520,7 +3553,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;
@@ -3533,12 +3566,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)
@@ -3552,7 +3617,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);
 }
 
@@ -3561,7 +3626,7 @@  static void qemu_signal_lock(unsigned int msecs)
     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;
     }
@@ -3602,7 +3667,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;
     }
@@ -3611,7 +3676,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;
         }
     }
@@ -3624,7 +3689,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;
     }