From 7c299acd15491b2a09b08a674ca68da4120ca3b3 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sat, 9 Apr 2011 13:53:11 +0300 Subject: [PATCH] kvm tools: Use per-VCPU threads for execution 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 Cc: Cyrill Gorcunov Tested-off-by: Ingo Molnar Signed-off-by: Pekka Enberg --- tools/kvm/include/kvm/kvm-cpu.h | 7 ++- tools/kvm/kvm-cpu.c | 21 +++++--- tools/kvm/kvm-run.c | 95 +++++++++++++++++++++++---------- tools/kvm/kvm.c | 11 ---- 4 files changed, 85 insertions(+), 49 deletions(-) diff --git a/tools/kvm/include/kvm/kvm-cpu.h b/tools/kvm/include/kvm/kvm-cpu.h index b4e2134d70f8..0d0881ee9c1d 100644 --- a/tools/kvm/include/kvm/kvm-cpu.h +++ b/tools/kvm/include/kvm/kvm-cpu.h @@ -3,11 +3,16 @@ #include /* for struct kvm_regs */ +#include #include 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); diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index 4cbe5978ca8b..dc40b428a1db 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/kvm-cpu.c @@ -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 #include +#include #include #include #include @@ -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: diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c index dcb7fb812909..5670b1d8716c 100644 --- a/tools/kvm/kvm-run.c +++ b/tools/kvm/kvm-run.c @@ -29,8 +29,11 @@ #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; } diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index 7ca44210fbf7..08ff63cd7cd9 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -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; -- 2.39.5