diff mbox

kvm tools: Use per-VCPU threads for execution

Message ID 1302354032-10655-1-git-send-email-penberg@kernel.org (mailing list archive)
State New, archived
Headers show

Commit Message

Pekka Enberg April 9, 2011, 1 p.m. UTC
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 |    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 mbox

Patch

diff --git a/tools/kvm/include/kvm/kvm-cpu.h b/tools/kvm/include/kvm/kvm-cpu.h
index b4e2134..0d0881e 100644
--- a/tools/kvm/include/kvm/kvm-cpu.h
+++ b/tools/kvm/include/kvm/kvm-cpu.h
@@ -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);
diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c
index 4cbe597..dc40b42 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 <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:
diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c
index dcb7fb8..5670b1d 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 7ca4421..08ff63c 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;