about summary refs log tree commit diff
path: root/src/rt/rust_kernel.cpp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-04-03 20:29:12 -0700
committerBrian Anderson <banderson@mozilla.com>2012-04-03 20:30:01 -0700
commite325146eb436c4995385d8220ff7ac3a4a5f62ab (patch)
tree999875912f33a00906c76f1eac278251bf63658a /src/rt/rust_kernel.cpp
parentbd97ee65200966e6c3b0fb45de1fc771c3cf5f3f (diff)
parent4cf7efc8f7df215b0ff9e3ea15b7890b84db1b51 (diff)
downloadrust-e325146eb436c4995385d8220ff7ac3a4a5f62ab.tar.gz
rust-e325146eb436c4995385d8220ff7ac3a4a5f62ab.zip
Merge remote-tracking branch 'brson/mainthread'
Conflicts:
	src/rt/rust_kernel.cpp
	src/rt/rust_scheduler.cpp
	src/rt/rust_scheduler.h
Diffstat (limited to 'src/rt/rust_kernel.cpp')
-rw-r--r--src/rt/rust_kernel.cpp56
1 files changed, 47 insertions, 9 deletions
diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp
index e8e7e4af171..ff6b0e1056c 100644
--- a/src/rt/rust_kernel.cpp
+++ b/src/rt/rust_kernel.cpp
@@ -5,6 +5,7 @@
 #include "rust_port.h"
 #include "rust_util.h"
 #include "rust_scheduler.h"
+#include "rust_sched_launcher.h"
 
 #define KLOG_(...)                              \
     KLOG(this, kern, __VA_ARGS__)
@@ -19,8 +20,15 @@ rust_kernel::rust_kernel(rust_env *env) :
     rval(0),
     max_sched_id(0),
     sched_reaper(this),
+    osmain_driver(NULL),
     env(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
@@ -60,24 +68,36 @@ 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();
+
+        if (sched_table.size() == 1) {
+            // The OS main scheduler may not exit while there are other
+            // schedulers
+            KLOG_("Disallowing osmain scheduler to exit");
+            rust_scheduler *sched =
+                get_scheduler_by_id_nolock(osmain_scheduler);
+            assert(sched != NULL);
+            sched->disallow_exit();
+        }
+
         id = max_sched_id++;
         assert(id != INTPTR_MAX && "Hit the maximum scheduler id");
         sched = new (this, "rust_scheduler")
-            rust_scheduler(this, num_threads, id);
+            rust_scheduler(this, num_threads, id, allow_exit, launchfac);
         bool is_new = sched_table
             .insert(std::pair<rust_sched_id,
                               rust_scheduler*>(id, sched)).second;
         assert(is_new && "Reusing a sched id?");
-        if (start_reaper) {
-            sched_reaper.start();
-        }
     }
     sched->start_task_threads();
     return id;
@@ -86,6 +106,12 @@ rust_kernel::create_scheduler(size_t num_threads) {
 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;
@@ -117,6 +143,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);
             assert(iter != sched_table.end());
@@ -124,6 +151,14 @@ 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");
+                // It's only the osmain scheduler left. Tell it to exit
+                rust_scheduler *sched =
+                    get_scheduler_by_id_nolock(osmain_scheduler);
+                assert(sched != NULL);
+                sched->allow_exit();
+            }
         }
         if (!sched_table.empty()) {
             sched_lock.wait();
@@ -131,9 +166,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;
 }