diff --git a/mk/rt.mk b/mk/rt.mk index bd935d660ff..7ada4c00695 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -25,6 +25,9 @@ RUNTIME_CS := rt/sync/timer.cpp \ rt/rust_srv.cpp \ rt/rust_kernel.cpp \ rt/memory_region.cpp \ + rt/test/rust_test_harness.cpp \ + rt/test/rust_test_runtime.cpp \ + rt/test/rust_test_util.cpp \ rt/arch/i386/context.cpp \ RUNTIME_LL := @@ -56,6 +59,9 @@ RUNTIME_HDR := rt/globals.h \ rt/rust_kernel.h \ rt/memory_region.h \ rt/memory.h \ + rt/test/rust_test_harness.h \ + rt/test/rust_test_runtime.h \ + rt/test/rust_test_util.h \ rt/arch/i386/context.h \ RUNTIME_DEF := rt/rustrt$(CFG_DEF_SUFFIX) diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index a57ef607f60..f10e55d40a0 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -249,6 +249,10 @@ typedef ptr_vec rust_wait_queue; #include "rust_port.h" #include "memory.h" +#include "test/rust_test_harness.h" +#include "test/rust_test_util.h" +#include "test/rust_test_runtime.h" + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index a1fba33bf89..bea5afd5de3 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -68,11 +68,11 @@ class rust_kernel : public rust_thread { rust_handle * internal_get_sched_handle(rust_scheduler *sched); + array_list threads; + rust_scheduler *create_scheduler(const char *name); void destroy_scheduler(); - array_list threads; - public: rust_scheduler *sched; lock_and_signal scheduler_lock; diff --git a/src/rt/test/rust_test_harness.cpp b/src/rt/test/rust_test_harness.cpp new file mode 100644 index 00000000000..cca199dcdb9 --- /dev/null +++ b/src/rt/test/rust_test_harness.cpp @@ -0,0 +1,40 @@ +#include "../rust_internal.h" + +bool +rust_test::run() { + return false; +} + +const char * +rust_test::name() { + return "untitled"; +} + +rust_test_suite::rust_test_suite() { + tests.append(new rust_domain_test()); + tests.append(new rust_task_test(this)); + tests.append(new rust_array_list_test()); + tests.append(new rust_synchronized_indexed_list_test()); +} + +rust_test_suite::~rust_test_suite() { + +} + +bool +rust_test_suite::run() { + bool pass = true; + for (size_t i = 0; i < tests.size(); i++) { + rust_test *test = tests[i]; + printf("test: %s running ... \n", test->name()); + timer timer; + bool result = tests[i]->run(); + printf("test: %s %s %.2f ms\n", test->name(), + result ? "PASSED" : "FAILE", timer.get_elapsed_time_in_ms()); + if (result == false) { + pass = false; + } + } + return pass; +} + diff --git a/src/rt/test/rust_test_harness.h b/src/rt/test/rust_test_harness.h new file mode 100644 index 00000000000..401015e4508 --- /dev/null +++ b/src/rt/test/rust_test_harness.h @@ -0,0 +1,22 @@ +#ifndef RUST_TEST_HARNESS_H +#define RUST_TEST_HARNESS_H + +#define CHECK(x) if ((x) == false) \ + { printf("condition: %s failed at file: %s, line: %d\n", #x, \ + __FILE__, __LINE__ ); return false; } + +class rust_test { +public: + virtual bool run(); + virtual const char *name(); +}; + +class rust_test_suite : public rust_test { +public: + array_list tests; + rust_test_suite(); + virtual ~rust_test_suite(); + bool run(); +}; + +#endif /* RUST_TEST_HARNESS_H */ diff --git a/src/rt/test/rust_test_runtime.cpp b/src/rt/test/rust_test_runtime.cpp new file mode 100644 index 00000000000..acb3557b8c1 --- /dev/null +++ b/src/rt/test/rust_test_runtime.cpp @@ -0,0 +1,67 @@ +#include "rust_test_runtime.h" + +rust_test_runtime::rust_test_runtime() { +} + +rust_test_runtime::~rust_test_runtime() { +} + +#define DOMAINS 32 +#define TASKS 32 + +void +rust_domain_test::worker::run() { + rust_scheduler *handle = kernel->get_scheduler(); + for (int i = 0; i < TASKS; i++) { + handle->create_task(NULL, "child"); + } + sync::random_sleep(1000); +} + +bool +rust_domain_test::run() { + rust_srv srv; + rust_kernel kernel(&srv); + + array_list workers; + for (int i = 0; i < DOMAINS; i++) { + worker *worker = new rust_domain_test::worker (&kernel); + workers.append(worker); + worker->start(); + } + + // We don't join the worker threads here in order to simulate ad-hoc + // termination of domains. If we join_all_domains before all domains + // are actually spawned, this could crash, thus the reason for the + // sleep below. + + sync::sleep(100); + return true; +} + +void task_entry() { + printf("task entry\n"); +} + +void +rust_task_test::worker::run() { + rust_scheduler *scheduler = kernel->get_scheduler(); + scheduler->root_task->start((uintptr_t)&task_entry, (uintptr_t)NULL); + scheduler->start_main_loop(0); +} + +bool +rust_task_test::run() { + rust_srv srv; + rust_kernel kernel(&srv); + + array_list workers; + for (int i = 0; i < DOMAINS; i++) { + worker *worker = new rust_task_test::worker (&kernel, this); + workers.append(worker); + worker->start(); + } + + sync::random_sleep(1000); + return true; +} diff --git a/src/rt/test/rust_test_runtime.h b/src/rt/test/rust_test_runtime.h new file mode 100644 index 00000000000..8d4f38ecb79 --- /dev/null +++ b/src/rt/test/rust_test_runtime.h @@ -0,0 +1,51 @@ +#include "../rust_internal.h" + +#ifndef RUST_TEST_RUNTIME_H +#define RUST_TEST_RUNTIME_H + +class rust_test_runtime { +public: + rust_test_runtime(); + virtual ~rust_test_runtime(); +}; + + +class rust_domain_test : public rust_test { +public: + class worker : public rust_thread { + public: + rust_kernel *kernel; + worker(rust_kernel *kernel) : kernel(kernel) { + // Nop. + } + void run(); + }; + bool run(); + const char *name() { + return "rust_domain_test"; + } +}; + +class rust_task_test : public rust_test { +public: + rust_test_suite *suite; + rust_task_test(rust_test_suite *suite) : suite(suite) { + // Nop. + } + class worker : public rust_thread { + public: + rust_kernel *kernel; + rust_task_test *parent; + worker(rust_kernel *kernel, rust_task_test *parent) : + kernel(kernel), parent(parent) { + // Nop. + } + void run(); + }; + bool run(); + const char *name() { + return "rust_task_test"; + } +}; + +#endif /* RUST_TEST_RUNTIME_H */ diff --git a/src/rt/test/rust_test_util.cpp b/src/rt/test/rust_test_util.cpp new file mode 100644 index 00000000000..2e9d764f69b --- /dev/null +++ b/src/rt/test/rust_test_util.cpp @@ -0,0 +1,78 @@ +#include "../rust_internal.h" + +#define COUNT 1000 +#define LARGE_COUNT 10000 +#define THREADS 10 + +bool +rust_array_list_test::run() { + array_list list; + + for (int i = 0; i < COUNT; i++) { + list.append(i); + } + + for (int i = 0; i < COUNT; i++) { + CHECK (list[i] == i); + } + + for (int i = 0; i < COUNT; i++) { + CHECK (list.index_of(i) == i); + } + + for (int i = 0; i < COUNT; i++) { + CHECK (list.replace(i, -i)); + CHECK (list.replace(-i, i)); + CHECK (list.index_of(i) == i); + } + + for (int i = COUNT - 1; i >= 0; i--) { + CHECK (list.pop(NULL)); + } + + return true; +} + +bool +rust_synchronized_indexed_list_test::run() { + array_list workers; + + for (int i = 0; i < THREADS; i++) { + worker *worker = + new rust_synchronized_indexed_list_test::worker(this); + workers.append(worker); + } + + for (uint32_t i = 0; i < workers.size(); i++) { + workers[i]->start(); + } + + while(workers.is_empty() == false) { + worker *worker; + workers.pop(&worker); + worker->join(); + delete worker; + } + + long long expected_items = LARGE_COUNT * THREADS; + + CHECK(list.length() == expected_items); + + long long sum = 0; + for (size_t i = 0; i < list.length(); i++) { + sum += list[i]->value; + } + + long long expected_sum = LARGE_COUNT; + expected_sum = expected_sum * (expected_sum - 1) / 2 * THREADS; + CHECK (sum == expected_sum); + return true; +} + +void +rust_synchronized_indexed_list_test::worker::run() { + for (int i = 0; i < LARGE_COUNT; i++) { + parent->list.append(new indexed_list_element(i)); + } + return; +} diff --git a/src/rt/test/rust_test_util.h b/src/rt/test/rust_test_util.h new file mode 100644 index 00000000000..41c3579043a --- /dev/null +++ b/src/rt/test/rust_test_util.h @@ -0,0 +1,41 @@ +#ifndef RUST_TEST_UTIL_H +#define RUST_TEST_UTIL_H + +class rust_test_util : public rust_test { +public: + +}; + +class rust_array_list_test : public rust_test { +public: + bool run(); + const char *name() { + return "rust_array_list_test"; + } +}; + + +class rust_synchronized_indexed_list_test : public rust_test { +public: + rust_srv srv; + synchronized_indexed_list > list; + + rust_synchronized_indexed_list_test() { + // Nop. + } + + class worker : public rust_thread { + public: + rust_synchronized_indexed_list_test *parent; + worker(rust_synchronized_indexed_list_test *parent) : parent(parent) { + // Nop. + } + void run(); + }; + bool run(); + const char *name() { + return "rust_synchronized_indexed_list_test"; + } +}; + +#endif /* RUST_TEST_UTIL_H */