diff options
Diffstat (limited to 'src/rt/rust_kernel.cpp')
| -rw-r--r-- | src/rt/rust_kernel.cpp | 165 |
1 files changed, 116 insertions, 49 deletions
diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 8871d133ea1..c365f3cca1e 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -30,21 +30,29 @@ rust_kernel::rust_kernel(rust_env *env) : rval(0), max_sched_id(1), killed(false), + already_exiting(false), sched_reaper(this), osmain_driver(NULL), non_weak_tasks(0), - global_loop_chan(0), - global_env_chan(0), - env(env) - + at_exit_runner(NULL), + at_exit_started(false), + env(env), + global_data(0) { - // Create the single threaded scheduler that will run on the platform's // main thread - rust_manual_sched_launcher_factory *launchfac = + rust_manual_sched_launcher_factory *osmain_launchfac = new rust_manual_sched_launcher_factory(); - osmain_scheduler = create_scheduler(launchfac, 1, false); - osmain_driver = launchfac->get_driver(); + osmain_scheduler = create_scheduler(osmain_launchfac, 1, false); + osmain_driver = osmain_launchfac->get_driver(); + + // Create the primary scheduler + rust_thread_sched_launcher_factory *main_launchfac = + new rust_thread_sched_launcher_factory(); + main_scheduler = create_scheduler(main_launchfac, + env->num_sched_threads, + false); + sched_reaper.start(); } @@ -103,15 +111,22 @@ rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, { scoped_lock with(sched_lock); + /*if (sched_table.size() == 2) { + // The main and OS main schedulers may not exit while there are + // other schedulers + KLOG_("Disallowing main scheduler to exit"); + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->disallow_exit(); + } 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 = + rust_scheduler *osmain_sched = get_scheduler_by_id_nolock(osmain_scheduler); - assert(sched != NULL); - sched->disallow_exit(); - } + assert(osmain_sched != NULL); + osmain_sched->disallow_exit(); + }*/ id = max_sched_id++; assert(id != INTPTR_MAX && "Hit the maximum scheduler id"); @@ -175,14 +190,21 @@ rust_kernel::wait_for_schedulers() sched_table.erase(iter); sched->join_task_threads(); sched->deref(); + /*if (sched_table.size() == 2) { + KLOG_("Allowing main scheduler to exit"); + // It's only the main schedulers left. Tell them to exit + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->allow_exit(); + } 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 = + rust_scheduler *osmain_sched = get_scheduler_by_id_nolock(osmain_scheduler); - assert(sched != NULL); - sched->allow_exit(); - } + assert(osmain_sched != NULL); + osmain_sched->allow_exit(); + }*/ } if (!sched_table.empty()) { sched_lock.wait(); @@ -319,59 +341,63 @@ rust_kernel::register_task() { } void +rust_kernel::allow_scheduler_exit() { + scoped_lock with(sched_lock); + + KLOG_("Allowing main scheduler to exit"); + // It's only the main schedulers left. Tell them to exit + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->allow_exit(); + + KLOG_("Allowing osmain scheduler to exit"); + rust_scheduler *osmain_sched = + get_scheduler_by_id_nolock(osmain_scheduler); + assert(osmain_sched != NULL); + osmain_sched->allow_exit(); +} + +void rust_kernel::unregister_task() { KLOG_("Unregistering task"); uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); if (new_non_weak_tasks == 0) { - end_weak_tasks(); + begin_shutdown(); } } void -rust_kernel::weaken_task(rust_port_id chan) { - { - scoped_lock with(weak_task_lock); - KLOG_("Weakening task with channel %" PRIdPTR, chan); - weak_task_chans.push_back(chan); - } +rust_kernel::inc_weak_task_count() { uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); if (new_non_weak_tasks == 0) { - end_weak_tasks(); + begin_shutdown(); } } void -rust_kernel::unweaken_task(rust_port_id chan) { +rust_kernel::dec_weak_task_count() { uintptr_t new_non_weak_tasks = sync::increment(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); - { - scoped_lock with(weak_task_lock); - KLOG_("Unweakening task with channel %" PRIdPTR, chan); - std::vector<rust_port_id>::iterator iter = - std::find(weak_task_chans.begin(), weak_task_chans.end(), chan); - if (iter != weak_task_chans.end()) { - weak_task_chans.erase(iter); - } - } } void -rust_kernel::end_weak_tasks() { - std::vector<rust_port_id> chancopies; +rust_kernel::begin_shutdown() { { - scoped_lock with(weak_task_lock); - chancopies = weak_task_chans; - weak_task_chans.clear(); - } - while (!chancopies.empty()) { - rust_port_id chan = chancopies.back(); - chancopies.pop_back(); - KLOG_("Notifying weak task " PRIdPTR, chan); - uintptr_t token = 0; - send_to_port(chan, &token); + scoped_lock with(sched_lock); + // FIXME #4410: This shouldn't be necessary, but because of + // unweaken_task this may end up getting called multiple times. + if (already_exiting) { + return; + } else { + already_exiting = true; + } } + + run_exit_functions(); + allow_scheduler_exit(); } bool @@ -389,6 +415,47 @@ rust_kernel::send_to_port(rust_port_id chan, void *sptr) { } } +void +rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) { + scoped_lock with(at_exit_lock); + + assert(!at_exit_started && "registering at_exit function after exit"); + + if (at_exit_runner) { + assert(runner == at_exit_runner + && "there can be only one at_exit_runner"); + } + + at_exit_runner = runner; + at_exit_fns.push_back(f); +} + +void +rust_kernel::run_exit_functions() { + rust_task *task; + + { + scoped_lock with(at_exit_lock); + + assert(!at_exit_started && "running exit functions twice?"); + + at_exit_started = true; + + if (at_exit_runner == NULL) { + return; + } + + rust_scheduler *sched = get_scheduler_by_id(main_sched_id()); + assert(sched); + task = sched->create_task(NULL, "at_exit"); + + final_exit_fns.count = at_exit_fns.size(); + final_exit_fns.start = at_exit_fns.data(); + } + + task->start(at_exit_runner, NULL, &final_exit_fns); +} + // // Local Variables: // mode: C++ |
