]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Use per-VCPU threads for execution
authorPekka Enberg <penberg@kernel.org>
Sat, 9 Apr 2011 10:53:11 +0000 (13:53 +0300)
committerPekka Enberg <penberg@kernel.org>
Sat, 9 Apr 2011 12:45:08 +0000 (15:45 +0300)
This patch makes the core hypervisor to use per-VCPU threads for execution.
NOTE: We only start one thread right now because we're unable to let the guest
kernel know about more cores at the moment.

Cc: Asias He <asias.hejun@gmail.com>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Tested-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/include/kvm/kvm-cpu.h
tools/kvm/kvm-cpu.c
tools/kvm/kvm-run.c
tools/kvm/kvm.c

index b4e2134d70f814cf3338b7dffbccf55648fabaed..0d0881ee9c1dd8266e40c0495eb5e7f1e0b937d5 100644 (file)
@@ -3,11 +3,16 @@
 
 #include <linux/kvm.h> /* for struct kvm_regs */
 
+#include <pthread.h>
 #include <stdint.h>
 
 struct kvm;
 
 struct kvm_cpu {
+       pthread_t               thread;         /* VCPU thread */
+
+       unsigned long           cpu_id;
+
        struct kvm              *kvm;           /* parent KVM */
        int                     vcpu_fd;        /* For VCPU ioctls() */
        struct kvm_run          *kvm_run;
@@ -19,7 +24,7 @@ struct kvm_cpu {
        struct kvm_msrs         *msrs;          /* dynamically allocated */
 };
 
-struct kvm_cpu *kvm_cpu__init(struct kvm *kvm);
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id);
 void kvm_cpu__delete(struct kvm_cpu *self);
 void kvm_cpu__reset_vcpu(struct kvm_cpu *self);
 void kvm_cpu__setup_cpuid(struct kvm_cpu *self);
index 4cbe5978ca8bf92a44857ce1234dcf74779ed093..dc40b428a1db9953b811d7806559fd5f06c85764 100644 (file)
@@ -1,12 +1,11 @@
 #include "kvm/kvm-cpu.h"
 
-#include "kvm/virtio-console.h"
-#include "kvm/8250-serial.h"
 #include "kvm/util.h"
 #include "kvm/kvm.h"
 
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <stdio.h>
@@ -61,7 +60,7 @@ void kvm_cpu__delete(struct kvm_cpu *self)
        free(self);
 }
 
-struct kvm_cpu *kvm_cpu__init(struct kvm *kvm)
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
 {
        struct kvm_cpu *self;
        int mmap_size;
@@ -70,7 +69,9 @@ struct kvm_cpu *kvm_cpu__init(struct kvm *kvm)
        if (!self)
                return NULL;
 
-       self->vcpu_fd = ioctl(self->kvm->vm_fd, KVM_CREATE_VCPU, 0);
+       self->cpu_id    = cpu_id;
+
+       self->vcpu_fd = ioctl(self->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
        if (self->vcpu_fd < 0)
                die_perror("KVM_CREATE_VCPU ioctl");
 
@@ -373,6 +374,13 @@ void kvm_cpu__run(struct kvm_cpu *self)
 
 int kvm_cpu__start(struct kvm_cpu *cpu)
 {
+       sigset_t sigset;
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset, SIGALRM);
+
+       pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+
        kvm_cpu__setup_cpuid(cpu);
        kvm_cpu__reset_vcpu(cpu);
 
@@ -412,11 +420,8 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
                                goto panic_kvm;
                        break;
                }
-               case KVM_EXIT_INTR: {
-                       serial8250__inject_interrupt(cpu->kvm);
-                       virtio_console__inject_interrupt(cpu->kvm);
+               case KVM_EXIT_INTR:
                        break;
-               }
                case KVM_EXIT_SHUTDOWN:
                        goto exit_kvm;
                default:
index dcb7fb8129096ba12979b80459fe999f5cf5d5cb..5670b1d8716c056257c1f48b6db2fbe2094b3470 100644 (file)
 #define MIN_RAM_SIZE_MB                (64ULL)
 #define MIN_RAM_SIZE_BYTE      (MIN_RAM_SIZE_MB << MB_SHIFT)
 
+#define NUM_KVM_CPUS           1
+
 static struct kvm *kvm;
-static struct kvm_cpu *cpu;
+static struct kvm_cpu *cpus[NUM_KVM_CPUS];
+static __thread struct kvm_cpu *current_cpu;
 
 static void handle_sigint(int sig)
 {
@@ -39,16 +42,22 @@ static void handle_sigint(int sig)
 
 static void handle_sigquit(int sig)
 {
-       kvm_cpu__show_registers(cpu);
-       kvm_cpu__show_code(cpu);
-       kvm_cpu__show_page_tables(cpu);
+       kvm_cpu__show_registers(current_cpu);
+       kvm_cpu__show_code(current_cpu);
+       kvm_cpu__show_page_tables(current_cpu);
 
-       kvm_cpu__delete(cpu);
+       kvm_cpu__delete(current_cpu);
        kvm__delete(kvm);
 
        exit(1);
 }
 
+static void handle_sigalrm(int sig)
+{
+       serial8250__inject_interrupt(kvm);
+       virtio_console__inject_interrupt(kvm);
+}
+
 static u64 ram_size = MIN_RAM_SIZE_MB;
 static const char *kernel_cmdline;
 static const char *kernel_filename;
@@ -84,10 +93,41 @@ static const struct option options[] = {
        OPT_END()
 };
 
+static void *kvm_cpu_thread(void *arg)
+{
+       current_cpu             = arg;
+
+       if (kvm_cpu__start(current_cpu))
+               goto panic_kvm;
+
+       kvm_cpu__delete(current_cpu);
+
+       return (void *) (intptr_t) 0;
+
+panic_kvm:
+       fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
+               current_cpu->kvm_run->exit_reason,
+               kvm_exit_reasons[current_cpu->kvm_run->exit_reason]);
+       if (current_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
+               fprintf(stderr, "KVM exit code: 0x%Lu\n",
+                       current_cpu->kvm_run->hw.hardware_exit_reason);
+       disk_image__close(kvm->disk_image);
+       kvm_cpu__show_registers(current_cpu);
+       kvm_cpu__show_code(current_cpu);
+       kvm_cpu__show_page_tables(current_cpu);
+
+       kvm_cpu__delete(current_cpu);
+
+       return (void *) (intptr_t) 1;
+}
+
 int kvm_cmd_run(int argc, const char **argv, const char *prefix)
 {
        static char real_cmdline[2048];
+       int exit_code = 0;
+       int i;
 
+       signal(SIGALRM, handle_sigalrm);
        signal(SIGQUIT, handle_sigquit);
        signal(SIGINT, handle_sigint);
 
@@ -132,10 +172,6 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
 
        kvm = kvm__init(kvm_dev, ram_size);
 
-       cpu = kvm_cpu__init(kvm);
-       if (!cpu)
-               die("unable to initialize KVM VCPU");
-
        if (image_filename) {
                kvm->disk_image = disk_image__open(image_filename);
                if (!kvm->disk_image)
@@ -169,32 +205,33 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
 
        kvm__start_timer(kvm);
 
-       if (single_step)
-               kvm_cpu__enable_singlestep(cpu);
+       for (i = 0; i < NUM_KVM_CPUS; i++) {
+               cpus[i] = kvm_cpu__init(kvm, i);
+               if (!cpus[i])
+                       die("unable to initialize KVM VCPU");
 
-       if (kvm_cpu__start(cpu))
-               goto panic_kvm;
+               if (single_step)
+                       kvm_cpu__enable_singlestep(cpus[i]);
 
-       disk_image__close(kvm->disk_image);
-       kvm__delete(kvm);
+               if (pthread_create(&cpus[i]->thread, NULL, kvm_cpu_thread, cpus[i]) != 0)
+                       die("unable to create KVM VCPU thread");
+       }
 
-       printf("\n  # KVM session ended normally.\n");
+       for (i = 0; i < NUM_KVM_CPUS; i++) {
+               void *ret;
 
-       return 0;
+               if (pthread_join(cpus[i]->thread, &ret) != 0)
+                       die("pthread_join");
+
+               if (ret != NULL)
+                       exit_code       = 1;
+       }
 
-panic_kvm:
-       fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
-               cpu->kvm_run->exit_reason,
-               kvm_exit_reasons[cpu->kvm_run->exit_reason]);
-       if (cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
-               fprintf(stderr, "KVM exit code: 0x%Lu\n",
-                       cpu->kvm_run->hw.hardware_exit_reason);
        disk_image__close(kvm->disk_image);
-       kvm_cpu__show_registers(cpu);
-       kvm_cpu__show_code(cpu);
-       kvm_cpu__show_page_tables(cpu);
-       kvm_cpu__delete(cpu);
        kvm__delete(kvm);
 
-       return 1;
+       if (!exit_code)
+               printf("\n  # KVM session ended normally.\n");
+
+       return exit_code;
 }
index 7ca44210fbf7fec8322b2af0e9ef61648d139f29..08ff63cd7cd93c58e0708f47cd580f85324bfaf1 100644 (file)
@@ -412,10 +412,6 @@ void kvm__setup_bios(struct kvm *self)
 
 #define TIMER_INTERVAL_NS 1000000      /* 1 msec */
 
-static void alarm_handler(int sig)
-{
-}
-
 /*
  * This function sets up a timer that's used to inject interrupts from the
  * userspace hypervisor into the guest at periodical intervals. Please note
@@ -424,15 +420,8 @@ static void alarm_handler(int sig)
 void kvm__start_timer(struct kvm *self)
 {
        struct itimerspec its;
-       struct sigaction sa;
        struct sigevent sev;
 
-       sigfillset(&sa.sa_mask);
-       sa.sa_flags                     = 0;
-       sa.sa_handler                   = alarm_handler;
-
-       sigaction(SIGALRM, &sa, NULL);
-
        memset(&sev, 0, sizeof(struct sigevent));
        sev.sigev_value.sival_int       = 0;
        sev.sigev_notify                = SIGEV_SIGNAL;