diff --git a/mk/rt.mk b/mk/rt.mk index a0f3991c4261..06ecc6c5d7cd 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -43,6 +43,7 @@ RUNTIME_CS_$(1) := \ rt/rust_crate_cache.cpp \ rt/rust_env.cpp \ rt/rust_task_thread.cpp \ + rt/rust_scheduler.cpp \ rt/rust_task.cpp \ rt/rust_task_list.cpp \ rt/rust_port.cpp \ @@ -80,6 +81,7 @@ RUNTIME_HDR_$(1) := rt/globals.h \ rt/rust_upcall.h \ rt/rust_port.h \ rt/rust_task_thread.h \ + rt/rust_scheduler.h \ rt/rust_shape.h \ rt/rust_task.h \ rt/rust_task_list.h \ diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index aa1e05c04004..9f9af2c5e8c7 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -105,7 +105,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { root_task->deref(); root_task = NULL; - int ret = kernel->start_task_threads(); + int ret = kernel->start_schedulers(); delete args; delete kernel; delete srv; diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index bccd55f4288c..8ac85c4ece77 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -4,6 +4,7 @@ #include "rust_task_thread.h" #include "rust_task.h" #include "rust_util.h" +#include "rust_scheduler.h" #include "sync/timer.h" #if !defined(__WIN32__) @@ -416,7 +417,7 @@ start_task(rust_task_id id, fn_env_pair *f) { extern "C" CDECL int sched_threads() { rust_task *task = rust_task_thread::get_task(); - return task->kernel->num_threads; + return task->thread->sched->number_of_threads(); } extern "C" CDECL rust_port* diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index f1ce434cd347..c04a8d9d427b 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -1,5 +1,6 @@ #include "rust_internal.h" #include "rust_util.h" +#include "rust_scheduler.h" #define KLOG_(...) \ KLOG(this, kern, __VA_ARGS__) @@ -12,64 +13,11 @@ rust_kernel::rust_kernel(rust_srv *srv, size_t num_threads) : srv(srv), max_id(0), rval(0), - num_threads(num_threads), live_tasks(0), env(srv->env) { - isaac_init(this, &rctx); - create_schedulers(); -} - -rust_task_thread * -rust_kernel::create_scheduler(int id) { - _kernel_lock.lock(); - rust_srv *srv = this->srv->clone(); - rust_task_thread *thread = - new (this, "rust_task_thread") rust_task_thread(this, srv, id); - KLOG_("created scheduler: " PTR ", id: %d, index: %d", - thread, id, thread->list_index); - _kernel_lock.unlock(); - return thread; -} - -void -rust_kernel::destroy_scheduler(rust_task_thread *thread) { - _kernel_lock.lock(); - KLOG_("deleting scheduler: " PTR ", name: %s, index: %d", - thread, thread->name, thread->list_index); - rust_srv *srv = thread->srv; - delete thread; - delete srv; - _kernel_lock.unlock(); -} - -void rust_kernel::create_schedulers() { - KLOG_("Using %d scheduler threads.", num_threads); - - for(size_t i = 0; i < num_threads; ++i) { - threads.push(create_scheduler(i)); - } -} - -void rust_kernel::destroy_schedulers() { - for(size_t i = 0; i < num_threads; ++i) { - destroy_scheduler(threads[i]); - } -} - -void -rust_kernel::log_all_scheduler_state() { - for(size_t i = 0; i < num_threads; ++i) { - threads[i]->log_state(); - } -} - -/** - * Checks for simple deadlocks. - */ -bool -rust_kernel::is_deadlocked() { - return false; + sched = new (this, "rust_scheduler") + rust_scheduler(this, srv, num_threads); } void @@ -94,7 +42,7 @@ rust_kernel::fatal(char const *fmt, ...) { } rust_kernel::~rust_kernel() { - destroy_schedulers(); + delete sched; } void * @@ -111,24 +59,9 @@ void rust_kernel::free(void *mem) { _region.free(mem); } -void -rust_kernel::signal_kernel_lock() { - _kernel_lock.lock(); - _kernel_lock.unlock(); -} - -int rust_kernel::start_task_threads() +int rust_kernel::start_schedulers() { - for(size_t i = 0; i < num_threads; ++i) { - rust_task_thread *thread = threads[i]; - thread->start(); - } - - for(size_t i = 0; i < num_threads; ++i) { - rust_task_thread *thread = threads[i]; - thread->join(); - } - + sched->start_task_threads(); return rval; } @@ -141,21 +74,13 @@ rust_kernel::fail() { #if defined(__WIN32__) exit(rval); #endif - for(size_t i = 0; i < num_threads; ++i) { - rust_task_thread *thread = threads[i]; - thread->kill_all_tasks(); - } + sched->kill_all_tasks(); } rust_task_id rust_kernel::create_task(rust_task *spawner, const char *name, size_t init_stack_sz) { - scoped_lock with(_kernel_lock); - rust_task_thread *thread = threads[isaac_rand(&rctx) % num_threads]; - rust_task *t = thread->create_task(spawner, name, init_stack_sz); - t->user.id = max_id++; - task_table.put(t->user.id, t); - return t->user.id; + return sched->create_task(spawner, name, init_stack_sz); } rust_task_id @@ -163,6 +88,13 @@ rust_kernel::create_task(rust_task *spawner, const char *name) { return create_task(spawner, name, env->min_stack_size); } +void +rust_kernel::register_task(rust_task *task) { + scoped_lock with(_kernel_lock); + task->user.id = max_id++; + task_table.put(task->user.id, task); +} + rust_task * rust_kernel::get_task_by_id(rust_task_id id) { scoped_lock with(_kernel_lock); @@ -190,9 +122,7 @@ rust_kernel::release_task_id(rust_task_id id) { } void rust_kernel::exit_schedulers() { - for(size_t i = 0; i < num_threads; ++i) { - threads[i]->exit(); - } + sched->exit(); } #ifdef __WIN32__ diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 963c503bee51..d6a1d0f19c22 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -6,6 +6,7 @@ #include "rust_log.h" struct rust_task_thread; +struct rust_scheduler; /** * A global object shared by all thread domains. Most of the data structures @@ -20,36 +21,21 @@ public: rust_srv *srv; private: lock_and_signal _kernel_lock; - - array_list threads; - - randctx rctx; - - rust_task_thread *create_scheduler(int id); - void destroy_scheduler(rust_task_thread *thread); - - void create_schedulers(); - void destroy_schedulers(); + rust_scheduler *sched; rust_task_id max_id; hash_map task_table; - int rval; public: - const size_t num_threads; volatile int live_tasks; struct rust_env *env; rust_kernel(rust_srv *srv, size_t num_threads); - bool is_deadlocked(); - - void signal_kernel_lock(); void exit_schedulers(); - void log_all_scheduler_state(); void log(uint32_t level, char const *fmt, ...); void fatal(char const *fmt, ...); virtual ~rust_kernel(); @@ -60,7 +46,7 @@ public: void fail(); - int start_task_threads(); + int start_schedulers(); #ifdef __WIN32__ void win32_require(LPCTSTR fn, BOOL ok); @@ -69,6 +55,7 @@ public: rust_task_id create_task(rust_task *spawner, const char *name, size_t init_stack_size); rust_task_id create_task(rust_task * spawner, const char *name); + void register_task(rust_task *task); rust_task *get_task_by_id(rust_task_id id); void release_task_id(rust_task_id tid); void set_exit_status(int code); diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp new file mode 100644 index 000000000000..9f0e8be9482f --- /dev/null +++ b/src/rt/rust_scheduler.cpp @@ -0,0 +1,110 @@ +#include "rust_scheduler.h" +#include "rust_util.h" + +rust_scheduler::rust_scheduler(rust_kernel *kernel, + rust_srv *srv, + size_t num_threads) : + kernel(kernel), + srv(srv), + env(srv->env), + num_threads(num_threads) +{ + isaac_init(this, &rctx); + create_task_threads(); +} + +rust_scheduler::~rust_scheduler() { + destroy_task_threads(); +} + +rust_task_thread * +rust_scheduler::create_task_thread(int id) { + lock.lock(); + rust_srv *srv = this->srv->clone(); + rust_task_thread *thread = + new (kernel, "rust_task_thread") rust_task_thread(this, srv, id); + KLOG(kernel, kern, "created task thread: " PTR ", id: %d, index: %d", + thread, id, thread->list_index); + lock.unlock(); + return thread; +} + +void +rust_scheduler::destroy_task_thread(rust_task_thread *thread) { + lock.lock(); + KLOG(kernel, kern, "deleting task thread: " PTR ", name: %s, index: %d", + thread, thread->name, thread->list_index); + rust_srv *srv = thread->srv; + delete thread; + delete srv; + lock.unlock(); +} + +void +rust_scheduler::create_task_threads() { + KLOG(kernel, kern, "Using %d scheduler threads.", num_threads); + + for(size_t i = 0; i < num_threads; ++i) { + threads.push(create_task_thread(i)); + } +} + +void +rust_scheduler::destroy_task_threads() { + for(size_t i = 0; i < num_threads; ++i) { + destroy_task_thread(threads[i]); + } +} + +void +rust_scheduler::start_task_threads() +{ + for(size_t i = 0; i < num_threads; ++i) { + rust_task_thread *thread = threads[i]; + thread->start(); + } + + for(size_t i = 0; i < num_threads; ++i) { + rust_task_thread *thread = threads[i]; + thread->join(); + } +} + +void +rust_scheduler::kill_all_tasks() { + for(size_t i = 0; i < num_threads; ++i) { + rust_task_thread *thread = threads[i]; + thread->kill_all_tasks(); + } +} + +rust_task_id +rust_scheduler::create_task(rust_task *spawner, const char *name, + size_t init_stack_sz) { + size_t thread_no; + { + scoped_lock with(lock); + thread_no = isaac_rand(&rctx) % num_threads; + } + rust_task_thread *thread = threads[thread_no]; + rust_task *t = thread->create_task(spawner, name, init_stack_sz); + kernel->register_task(t); + return t->user.id; +} + +rust_task_id +rust_scheduler::create_task(rust_task *spawner, const char *name) { + return create_task(spawner, name, env->min_stack_size); +} + +void +rust_scheduler::exit() { + for(size_t i = 0; i < num_threads; ++i) { + threads[i]->exit(); + } +} + +size_t +rust_scheduler::number_of_threads() { + return num_threads; +} diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h new file mode 100644 index 000000000000..03eb3186ed34 --- /dev/null +++ b/src/rt/rust_scheduler.h @@ -0,0 +1,39 @@ +#ifndef RUST_SCHEDULER_H +#define RUST_SCHEDULER_H + +#include "rust_internal.h" + +class rust_scheduler : public kernel_owned { + // FIXME: Make these private +public: + rust_kernel *kernel; + rust_srv *srv; + rust_env *env; +private: + lock_and_signal lock; + array_list threads; + randctx rctx; + const size_t num_threads; + int rval; + + void create_task_threads(); + void destroy_task_threads(); + + rust_task_thread *create_task_thread(int id); + void destroy_task_thread(rust_task_thread *thread); + +public: + rust_scheduler(rust_kernel *kernel, rust_srv *srv, size_t num_threads); + ~rust_scheduler(); + + void start_task_threads(); + void kill_all_tasks(); + rust_task_id create_task(rust_task *spawner, + const char *name, + size_t init_stack_sz); + rust_task_id create_task(rust_task *spawner, const char *name); + void exit(); + size_t number_of_threads(); +}; + +#endif /* RUST_SCHEDULER_H */ diff --git a/src/rt/rust_task_thread.cpp b/src/rt/rust_task_thread.cpp index 774e71f24aaf..b1363e1806ea 100644 --- a/src/rt/rust_task_thread.cpp +++ b/src/rt/rust_task_thread.cpp @@ -5,6 +5,7 @@ #include "rust_internal.h" #include "rust_util.h" #include "globals.h" +#include "rust_scheduler.h" #ifndef _WIN32 pthread_key_t rust_task_thread::task_key; @@ -14,9 +15,9 @@ DWORD rust_task_thread::task_key; bool rust_task_thread::tls_initialized = false; -rust_task_thread::rust_task_thread(rust_kernel *kernel, - rust_srv *srv, - int id) : +rust_task_thread::rust_task_thread(rust_scheduler *sched, + rust_srv *srv, + int id) : ref_count(1), _log(srv, this), log_lvl(log_debug), @@ -28,7 +29,8 @@ rust_task_thread::rust_task_thread(rust_kernel *kernel, blocked_tasks(this, "blocked"), dead_tasks(this, "dead"), cache(this), - kernel(kernel), + kernel(sched->kernel), + sched(sched), id(id), min_stack_size(kernel->env->min_stack_size), env(kernel->env), @@ -217,8 +219,6 @@ rust_task_thread::start_main_loop() { DLOG(this, dom, "started domain loop %d", id); while (!should_exit) { - A(this, kernel->is_deadlocked() == false, "deadlock"); - DLOG(this, dom, "worker %d, number_of_live_tasks = %d, total = %d", id, number_of_live_tasks(), kernel->live_tasks); diff --git a/src/rt/rust_task_thread.h b/src/rt/rust_task_thread.h index 194866337134..9155019d3ffb 100644 --- a/src/rt/rust_task_thread.h +++ b/src/rt/rust_task_thread.h @@ -69,6 +69,7 @@ struct rust_task_thread : public kernel_owned, randctx rctx; rust_kernel *kernel; + rust_scheduler *sched; int32_t list_index; const int id; @@ -92,7 +93,7 @@ struct rust_task_thread : public kernel_owned, // Only a pointer to 'name' is kept, so it must live as long as this // domain. - rust_task_thread(rust_kernel *kernel, rust_srv *srv, int id); + rust_task_thread(rust_scheduler *sched, rust_srv *srv, int id); ~rust_task_thread(); void activate(rust_task *task); void log(rust_task *task, uint32_t level, char const *fmt, ...);