vmm: Add vthread_test
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 13 Sep 2017 21:14:43 +0000 (17:14 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 15 Sep 2017 13:33:40 +0000 (09:33 -0400)
This creates and joins on a few threads, basically a 'hello world.'  It
also has examples of vthread apps adding their own vmcalls.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tests/vmm/Makefrag
tests/vmm/vthread_test.c [new file with mode: 0644]

index 6eb1eea..49eb20f 100644 (file)
@@ -1,6 +1,6 @@
 VMM_TESTS_DIR = $(TESTS_DIR)/vmm
 
-VMM_TESTS_CFLAGS += $(CFLAGS_TESTS) -Wunused -Werror
+VMM_TESTS_CFLAGS += $(CFLAGS_TESTS)
 
 ALL_VMM_TEST_FILES := $(wildcard $(VMM_TESTS_DIR)/*.c)
 
diff --git a/tests/vmm/vthread_test.c b/tests/vmm/vthread_test.c
new file mode 100644 (file)
index 0000000..489d72d
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (c) 2017 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * vthread_test: mostly create/join/vmcalls */
+
+#include <vmm/vmm.h>
+#include <vmm/vthread.h>
+#include <parlib/stdio.h>
+#include <parlib/uthread.h>
+
+enum {
+       MY_VMCALL_TEST1 = VTH_VMCALL_NEXT,
+       MY_VMCALL_TEST2,
+};
+
+/* Here's how you can make your own vmcalls and still use the vth vmcalls for
+ * the stuff you don't want to reimplement. */
+static bool extended_handle_vmcall(struct guest_thread *gth,
+                                   struct vm_trapframe *vm_tf)
+{
+       switch (vm_tf->tf_rax) {
+       case MY_VMCALL_TEST1:
+               goto out_ok;
+       }
+       return vth_handle_vmcall(gth, vm_tf);
+out_ok:
+       vm_tf->tf_rip += 3;
+       return TRUE;
+};
+
+static struct virtual_machine vm = {.vmcall = extended_handle_vmcall,
+                                    .mtx = UTH_MUTEX_INIT};
+
+static void thread_entry(void *arg)
+{
+       const char nums[] = "123456789";
+
+       for (int i = 0; i < sizeof(nums); i++)
+               vmcall(VTH_VMCALL_PRINTC, nums[i]);
+       vmcall(MY_VMCALL_TEST1);
+       vmcall(VTH_VMCALL_EXIT, arg, 0, 0, 0);
+}
+
+int main(int argc, char **argv)
+{
+       #define NR_VTHS 5
+       struct vthread *vths[NR_VTHS];
+       void *retvals[NR_VTHS];
+
+       /* Tests multiple threads at once */
+       for (long i = 0; i < NR_VTHS; i++)
+               vths[i] = vthread_create(&vm, thread_entry, (void*)i);
+       for (long i = 0; i < NR_VTHS; i++) {
+               vthread_join(vths[i], &retvals[i]);
+               assert(retvals[i] == (void*)i);
+       }
+
+       /* Tests reuse / GPC leakage */
+       for (long i = 0; i < NR_VTHS * 2; i++) {
+               vths[0] = vthread_create(&vm, thread_entry, (void*)i);
+               vthread_join(vths[0], &retvals[0]);
+               assert(retvals[0] == (void*)i);
+       }
+       assert(vm.nr_gpcs == NR_VTHS);
+
+       return 0;
+}