From fb528dd7d613964e05dd682a6a98980a1ebdb4d6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 1 Apr 2012 16:38:42 -0700 Subject: rt: Allow some schedulers to stay alive even without tasks to execute --- src/rt/rust_kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rt/rust_kernel.cpp') diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index c7625537f40..5062e4de3c3 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -69,7 +69,7 @@ rust_kernel::create_scheduler(size_t num_threads) { id = max_sched_id++; K(srv, id != INTPTR_MAX, "Hit the maximum scheduler id"); sched = new (this, "rust_scheduler") - rust_scheduler(this, srv, num_threads, id); + rust_scheduler(this, srv, num_threads, id, true); bool is_new = sched_table .insert(std::pair(id, sched)).second; -- cgit 1.4.1-3-g733a5 From e1858882a49bf0666d4ffb3f45989ac9dbe9c843 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 1 Apr 2012 18:42:28 -0700 Subject: rt: Run a single-threaded scheduler on the main thread --- src/rt/rust.cpp | 2 +- src/rt/rust_kernel.cpp | 39 ++++++++++++++++++++++++++++++--------- src/rt/rust_kernel.h | 12 +++++++++++- src/rt/rust_sched_launcher.cpp | 3 ++- src/rt/rust_sched_launcher.h | 13 ++++++++----- src/rt/rust_scheduler.cpp | 6 +++--- src/rt/rust_scheduler.h | 3 ++- 7 files changed, 57 insertions(+), 21 deletions(-) (limited to 'src/rt/rust_kernel.cpp') diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index 00657f8ec0a..e328f81c391 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -93,7 +93,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { root_task->start((spawn_fn)main_fn, NULL, args->args); root_task = NULL; - int ret = kernel->wait_for_exit(); + int ret = kernel->run(); delete args; delete kernel; delete srv; diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 5062e4de3c3..d65837a47d6 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -1,6 +1,7 @@ #include "rust_internal.h" #include "rust_util.h" #include "rust_scheduler.h" +#include "rust_sched_launcher.h" #include @@ -18,8 +19,15 @@ rust_kernel::rust_kernel(rust_srv *srv) : rval(0), max_sched_id(0), sched_reaper(this), + osmain_driver(NULL), env(srv->env) { + // Create the single threaded scheduler that will run on the platform's + // main thread + rust_manual_sched_launcher_factory launchfac; + osmain_scheduler = create_scheduler(&launchfac, 1, false); + osmain_driver = launchfac.get_driver(); + sched_reaper.start(); } void @@ -59,24 +67,25 @@ void rust_kernel::free(void *mem) { rust_sched_id rust_kernel::create_scheduler(size_t num_threads) { + rust_thread_sched_launcher_factory launchfac; + return create_scheduler(&launchfac, num_threads, true); +} + +rust_sched_id +rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, + size_t num_threads, bool allow_exit) { rust_sched_id id; rust_scheduler *sched; { scoped_lock with(sched_lock); - // If this is the first scheduler then we need to launch - // the scheduler reaper. - bool start_reaper = sched_table.empty(); id = max_sched_id++; K(srv, id != INTPTR_MAX, "Hit the maximum scheduler id"); sched = new (this, "rust_scheduler") - rust_scheduler(this, srv, num_threads, id, true); + rust_scheduler(this, srv, num_threads, id, allow_exit, launchfac); bool is_new = sched_table .insert(std::pair(id, sched)).second; A(this, is_new, "Reusing a sched id?"); - if (start_reaper) { - sched_reaper.start(); - } } sched->start_task_threads(); return id; @@ -123,6 +132,15 @@ rust_kernel::wait_for_schedulers() sched_table.erase(iter); sched->join_task_threads(); delete sched; + if (sched_table.size() == 1) { + KLOG_("Allowing osmain scheduler to exit"); + sched_lock.unlock(); + // It's only the osmain scheduler left. Tell it to exit + rust_scheduler *sched = get_scheduler_by_id(osmain_scheduler); + assert(sched != NULL); + sched_lock.lock(); + sched->allow_exit(); + } } if (!sched_table.empty()) { sched_lock.wait(); @@ -130,9 +148,12 @@ rust_kernel::wait_for_schedulers() } } -/* Called on the main thread to wait for the kernel to exit */ +/* Called on the main thread to run the osmain scheduler to completion, + then wait for schedulers to exit */ int -rust_kernel::wait_for_exit() { +rust_kernel::run() { + assert(osmain_driver != NULL); + osmain_driver->start_main_loop(); sched_reaper.join(); return rval; } diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 78548917ee5..8c1d33c6a5e 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -13,6 +13,9 @@ class rust_scheduler; typedef std::map sched_map; +class rust_sched_driver; +class rust_sched_launcher_factory; + /** * A global object shared by all thread domains. Most of the data structures * in this class are synchronized since they are accessed from multiple @@ -48,6 +51,11 @@ private: std::vector join_list; rust_sched_reaper sched_reaper; + // The single-threaded scheduler that uses the main thread + rust_sched_id osmain_scheduler; + // Runs the single-threaded scheduler that executes tasks + // on the main thread + rust_sched_driver *osmain_driver; public: @@ -66,11 +74,13 @@ public: void fail(); rust_sched_id create_scheduler(size_t num_threads); + rust_sched_id create_scheduler(rust_sched_launcher_factory *launchfac, + size_t num_threads, bool allow_exit); rust_scheduler* get_scheduler_by_id(rust_sched_id id); // Called by a scheduler to indicate that it is terminating void release_scheduler_id(rust_sched_id id); void wait_for_schedulers(); - int wait_for_exit(); + int run(); #ifdef __WIN32__ void win32_require(LPCTSTR fn, BOOL ok); diff --git a/src/rt/rust_sched_launcher.cpp b/src/rt/rust_sched_launcher.cpp index dabae31f5b6..330299ec73c 100644 --- a/src/rt/rust_sched_launcher.cpp +++ b/src/rt/rust_sched_launcher.cpp @@ -32,6 +32,7 @@ rust_sched_launcher * rust_manual_sched_launcher_factory::create(rust_scheduler *sched, int id) { assert(launcher == NULL && "I can only track one sched_launcher"); rust_srv *srv = sched->srv->clone(); - return new(sched->kernel, "rust_manual_sched_launcher") + launcher = new(sched->kernel, "rust_manual_sched_launcher") rust_manual_sched_launcher(sched, srv, id); + return launcher; } diff --git a/src/rt/rust_sched_launcher.h b/src/rt/rust_sched_launcher.h index a68c1f500d6..f5db14a397e 100644 --- a/src/rt/rust_sched_launcher.h +++ b/src/rt/rust_sched_launcher.h @@ -36,10 +36,10 @@ public: class rust_manual_sched_launcher : public rust_sched_launcher { public: - rust_manual_sched_launcher(rust_scheduler *sched, rust_srv *srv, int id); - virtual void start() { } - virtual void join() { } - void start_main_loop() { driver.start_main_loop(); } + rust_manual_sched_launcher(rust_scheduler *sched, rust_srv *srv, int id); + virtual void start() { } + virtual void join() { } + rust_sched_driver *get_driver() { return &driver; }; }; class rust_sched_launcher_factory { @@ -62,7 +62,10 @@ private: public: rust_manual_sched_launcher_factory() : launcher(NULL) { } virtual rust_sched_launcher *create(rust_scheduler *sched, int id); - rust_manual_sched_launcher *get_launcher() { return launcher; } + rust_sched_driver *get_driver() { + assert(launcher != NULL); + return launcher->get_driver(); + } }; #endif // RUST_SCHED_LAUNCHER_H diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index 82eac1b1c93..b9f544b4549 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -6,7 +6,8 @@ rust_scheduler::rust_scheduler(rust_kernel *kernel, rust_srv *srv, size_t num_threads, rust_sched_id id, - bool allow_exit) : + bool allow_exit, + rust_sched_launcher_factory *launchfac) : kernel(kernel), srv(srv), env(srv->env), @@ -17,8 +18,7 @@ rust_scheduler::rust_scheduler(rust_kernel *kernel, num_threads(num_threads), id(id) { - rust_thread_sched_launcher_factory launchfac; - create_task_threads(&launchfac); + create_task_threads(launchfac); } rust_scheduler::~rust_scheduler() { diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h index 132fa9e6089..af501511832 100644 --- a/src/rt/rust_scheduler.h +++ b/src/rt/rust_scheduler.h @@ -38,7 +38,8 @@ private: public: rust_scheduler(rust_kernel *kernel, rust_srv *srv, size_t num_threads, - rust_sched_id id, bool allow_exit); + rust_sched_id id, bool allow_exit, + rust_sched_launcher_factory *launchfac); ~rust_scheduler(); void start_task_threads(); -- cgit 1.4.1-3-g733a5 From c0e12854edc10070759688b598a3885cbeb82e28 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 3 Apr 2012 17:39:35 -0700 Subject: rt: Fix bugs in the osmain scheduler --- src/rt/rust_kernel.cpp | 14 +++++++++++++- src/rt/rust_scheduler.cpp | 6 ++++++ src/rt/rust_scheduler.h | 1 + src/test/run-pass/osmain.rs | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src/rt/rust_kernel.cpp') diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index d65837a47d6..228a45bbae4 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -78,6 +78,18 @@ rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, rust_scheduler *sched; { scoped_lock with(sched_lock); + + if (sched_table.size() == 1) { + // The OS main scheduler may not exit while there are other + // schedulers + KLOG_("Disallowing osmain scheduler to exit"); + sched_lock.unlock(); + rust_scheduler *sched = get_scheduler_by_id(osmain_scheduler); + assert(sched != NULL); + sched->disallow_exit(); + sched_lock.lock(); + } + id = max_sched_id++; K(srv, id != INTPTR_MAX, "Hit the maximum scheduler id"); sched = new (this, "rust_scheduler") @@ -138,8 +150,8 @@ rust_kernel::wait_for_schedulers() // It's only the osmain scheduler left. Tell it to exit rust_scheduler *sched = get_scheduler_by_id(osmain_scheduler); assert(sched != NULL); - sched_lock.lock(); sched->allow_exit(); + sched_lock.lock(); } } if (!sched_table.empty()) { diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index b9f544b4549..badb1559791 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -152,3 +152,9 @@ rust_scheduler::allow_exit() { exit(); } } + +void +rust_scheduler::disallow_exit() { + scoped_lock with(lock); + may_exit = false; +} diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h index af501511832..81a0541cc0e 100644 --- a/src/rt/rust_scheduler.h +++ b/src/rt/rust_scheduler.h @@ -58,6 +58,7 @@ public: // Tells the scheduler that as soon as it runs out of tasks // to run it should exit void allow_exit(); + void disallow_exit(); }; #endif /* RUST_SCHEDULER_H */ diff --git a/src/test/run-pass/osmain.rs b/src/test/run-pass/osmain.rs index 4112ee561f7..70f59ee2e1b 100644 --- a/src/test/run-pass/osmain.rs +++ b/src/test/run-pass/osmain.rs @@ -3,7 +3,7 @@ // while it is not in use. fn main() { - run(10); + run(100); } fn run(i: int) { -- cgit 1.4.1-3-g733a5 From 4cf7efc8f7df215b0ff9e3ea15b7890b84db1b51 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 3 Apr 2012 18:54:57 -0700 Subject: rt: Fix bugs in the osmain scheduler --- src/rt/rust_kernel.cpp | 17 +++++++++++------ src/rt/rust_kernel.h | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src/rt/rust_kernel.cpp') diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 228a45bbae4..32e34dc9337 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -83,11 +83,10 @@ rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, // The OS main scheduler may not exit while there are other // schedulers KLOG_("Disallowing osmain scheduler to exit"); - sched_lock.unlock(); - rust_scheduler *sched = get_scheduler_by_id(osmain_scheduler); + rust_scheduler *sched = + get_scheduler_by_id_nolock(osmain_scheduler); assert(sched != NULL); sched->disallow_exit(); - sched_lock.lock(); } id = max_sched_id++; @@ -106,6 +105,12 @@ rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, rust_scheduler * rust_kernel::get_scheduler_by_id(rust_sched_id id) { scoped_lock with(sched_lock); + return get_scheduler_by_id_nolock(id); +} + +rust_scheduler * +rust_kernel::get_scheduler_by_id_nolock(rust_sched_id id) { + sched_lock.must_have_lock(); sched_map::iterator iter = sched_table.find(id); if (iter != sched_table.end()) { return iter->second; @@ -137,6 +142,7 @@ rust_kernel::wait_for_schedulers() while (!sched_table.empty()) { while (!join_list.empty()) { rust_sched_id id = join_list.back(); + KLOG_("Deleting scheduler %d", id); join_list.pop_back(); sched_map::iterator iter = sched_table.find(id); I(this, iter != sched_table.end()); @@ -146,12 +152,11 @@ rust_kernel::wait_for_schedulers() delete sched; if (sched_table.size() == 1) { KLOG_("Allowing osmain scheduler to exit"); - sched_lock.unlock(); // It's only the osmain scheduler left. Tell it to exit - rust_scheduler *sched = get_scheduler_by_id(osmain_scheduler); + rust_scheduler *sched = + get_scheduler_by_id_nolock(osmain_scheduler); assert(sched != NULL); sched->allow_exit(); - sched_lock.lock(); } } if (!sched_table.empty()) { diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 927da963dad..52399cf4e2c 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -57,6 +57,8 @@ private: // on the main thread rust_sched_driver *osmain_driver; + rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id); + public: struct rust_env *env; -- cgit 1.4.1-3-g733a5