diff --git a/mk/rt.mk b/mk/rt.mk index eee3f9cf3ea5b..72d500664fc02 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -50,6 +50,7 @@ RUNTIME_CS_$(1) := \ rt/rust_builtin.cpp \ rt/rust_run_program.cpp \ rt/rust_env.cpp \ + rt/rust_task_queue.cpp \ rt/rust_sched_loop.cpp \ rt/rust_sched_launcher.cpp \ rt/rust_sched_driver.cpp \ diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index 0b9102b8ff79a..fa25ca079b291 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -3,8 +3,6 @@ #include "rust_globals.h" #include "util/array_list.h" -#include "util/indexed_list.h" -#include "util/synchronized_indexed_list.h" #include "util/hash_map.h" #include "sync/sync.h" #include "sync/lock_and_signal.h" diff --git a/src/rt/rust_port_selector.cpp b/src/rt/rust_port_selector.cpp index 520fe680fa4a4..2e016a337f601 100644 --- a/src/rt/rust_port_selector.cpp +++ b/src/rt/rust_port_selector.cpp @@ -1,8 +1,10 @@ #include "rust_port.h" #include "rust_port_selector.h" +#include "rust_util.h" -rust_port_selector::rust_port_selector() +rust_port_selector::rust_port_selector(rust_kernel * kernel) : ports(NULL), n_ports(0) { + isaac_init(kernel, &rctx); } void @@ -27,7 +29,7 @@ rust_port_selector::select(rust_task *task, rust_port **dptr, // message. // Start looking for ports from a different index each time. - size_t j = isaac_rand(&task->sched_loop->rctx); + size_t j = isaac_rand(&rctx); for (size_t i = 0; i < n_ports; i++) { size_t k = (i + j) % n_ports; rust_port *port = ports[k]; diff --git a/src/rt/rust_port_selector.h b/src/rt/rust_port_selector.h index 3bfc454aaf85c..d0c2890bf0479 100644 --- a/src/rt/rust_port_selector.h +++ b/src/rt/rust_port_selector.h @@ -11,9 +11,10 @@ class rust_port_selector : public rust_cond { rust_port **ports; size_t n_ports; lock_and_signal rendezvous_lock; + randctx rctx; public: - rust_port_selector(); + rust_port_selector(rust_kernel *kernel); void select(rust_task *task, rust_port **dptr, diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp index 6a9668f418e55..987f152c3a899 100644 --- a/src/rt/rust_sched_loop.cpp +++ b/src/rt/rust_sched_loop.cpp @@ -24,6 +24,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, id(id), should_exit(false), cached_c_stack(NULL), + extra_c_stack(NULL), dead_task(NULL), pump_signal(NULL), kernel(sched->kernel), @@ -36,7 +37,6 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, name("main") { LOGPTR(this, "new dom", (uintptr_t)this); - isaac_init(kernel, &rctx); if (!tls_initialized) init_tls(); @@ -73,35 +73,27 @@ rust_sched_loop::fail() { kernel->fail(); } +static void +kill_task(rust_task * task) +{ + task->unsupervise(); + task->kill(); +} + void rust_sched_loop::kill_all_tasks() { - std::vector all_tasks; - - { - scoped_lock with(lock); - - for (size_t i = 0; i < running_tasks.length(); i++) { - all_tasks.push_back(running_tasks[i]); - } - - for (size_t i = 0; i < blocked_tasks.length(); i++) { - all_tasks.push_back(blocked_tasks[i]); - } - } + rust_task_iterator it = running_tasks.iterator(); + while (it.hasNext()) + kill_task(it.next()); - while (!all_tasks.empty()) { - rust_task *task = all_tasks.back(); - all_tasks.pop_back(); - // We don't want the failure of these tasks to propagate back - // to the kernel again since we're already failing everything - task->unsupervise(); - task->kill(); - } + it = blocked_tasks.iterator(); + while (it.hasNext()) + kill_task(it.next()); } size_t rust_sched_loop::number_of_live_tasks() { - return running_tasks.length() + blocked_tasks.length(); + return running_tasks.size() + blocked_tasks.size(); } /** @@ -152,38 +144,34 @@ rust_sched_loop::schedule_task() { I(this, this); // FIXME: in the face of failing tasks, this is not always right. // I(this, n_live_tasks() > 0); - if (running_tasks.length() > 0) { - size_t k = isaac_rand(&rctx); - // Look around for a runnable task, starting at k. - for(size_t j = 0; j < running_tasks.length(); ++j) { - size_t i = (j + k) % running_tasks.length(); - return (rust_task *)running_tasks[i]; - } - } - return NULL; + return running_tasks.next(); } void rust_sched_loop::log_state() { if (log_rt_task < log_debug) return; - if (!running_tasks.is_empty()) { + if (running_tasks.size() != 0) { log(NULL, log_debug, "running tasks:"); - for (size_t i = 0; i < running_tasks.length(); i++) { + rust_task_iterator it = running_tasks.iterator(); + while (it.hasNext()) { + rust_task * task = it.next(); log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR, - running_tasks[i]->name, - running_tasks[i]); + task->name, + task); } } - if (!blocked_tasks.is_empty()) { + if (blocked_tasks.size() != 0) { log(NULL, log_debug, "blocked tasks:"); - for (size_t i = 0; i < blocked_tasks.length(); i++) { + rust_task_iterator it = blocked_tasks.iterator(); + while (it.hasNext()) { + rust_task * task = it.next(); log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR ", blocked on: 0x%" PRIxPTR " '%s'", - blocked_tasks[i]->name, blocked_tasks[i], - blocked_tasks[i]->get_cond(), - blocked_tasks[i]->get_cond_name()); + task->name, task, + task->get_cond(), + task->get_cond_name()); } } } @@ -252,12 +240,11 @@ rust_sched_loop::run_single_turn() { id); reap_dead_tasks(); - lock.unlock(); return sched_loop_state_keep_going; } else { - A(this, running_tasks.is_empty(), "Should have no running tasks"); - A(this, blocked_tasks.is_empty(), "Should have no blocked tasks"); + A(this, running_tasks.size() == 0, "Should have no running tasks"); + A(this, blocked_tasks.size() == 0, "Should have no blocked tasks"); A(this, dead_task == NULL, "Should have no dead tasks"); DLOG(this, dom, "finished main-loop %d", id); @@ -288,7 +275,7 @@ rust_sched_loop::create_task(rust_task *spawner, const char *name) { return task; } -rust_task_list * +rust_task_queue * rust_sched_loop::state_list(rust_task_state state) { switch (state) { case task_state_running: @@ -327,14 +314,15 @@ rust_sched_loop::transition(rust_task *task, name, (uintptr_t)this, state_name(src), state_name(dst), state_name(task->get_state())); I(this, task->get_state() == src); - rust_task_list *src_list = state_list(src); - if (src_list) { + + rust_task_queue *src_list = state_list(src); + if (src_list) src_list->remove(task); - } - rust_task_list *dst_list = state_list(dst); - if (dst_list) { - dst_list->append(task); - } + + rust_task_queue *dst_list = state_list(dst); + if (dst_list) + dst_list->insert(task); + if (dst == task_state_dead) { I(this, dead_task == NULL); dead_task = task; diff --git a/src/rt/rust_sched_loop.h b/src/rt/rust_sched_loop.h index e89e9a6313b85..f676d727d51c1 100644 --- a/src/rt/rust_sched_loop.h +++ b/src/rt/rust_sched_loop.h @@ -5,6 +5,7 @@ #include "rust_stack.h" #include "rust_signal.h" #include "context.h" +#include "rust_task_queue.h" enum rust_task_state { task_state_newborn, @@ -25,8 +26,6 @@ enum rust_sched_loop_state { struct rust_task; -typedef indexed_list rust_task_list; - struct rust_sched_loop { private: @@ -52,8 +51,9 @@ struct rust_sched_loop stk_seg *cached_c_stack; stk_seg *extra_c_stack; - rust_task_list running_tasks; - rust_task_list blocked_tasks; + rust_task_queue running_tasks; + rust_task_queue blocked_tasks; + rust_task *dead_task; rust_signal *pump_signal; @@ -61,7 +61,7 @@ struct rust_sched_loop void prepare_c_stack(rust_task *task); void unprepare_c_stack(); - rust_task_list *state_list(rust_task_state state); + rust_task_queue *state_list(rust_task_state state); const char *state_name(rust_task_state state); void pump_loop(); @@ -82,8 +82,6 @@ struct rust_sched_loop size_t min_stack_size; rust_env *env; - randctx rctx; - // FIXME: Neither of these are used int32_t list_index; const char *const name; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 15f8e19be1dd4..bfe765bf6d874 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -25,7 +25,6 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, sched_loop(sched_loop), kernel(sched_loop->kernel), name(name), - list_index(-1), rendezvous_ptr(0), local_region(&sched_loop->srv->local_region), boxed(&local_region), @@ -33,6 +32,8 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, propagate_failure(true), cc_counter(0), total_stack_sz(0), + next(NULL), + prev(NULL), state(state), cond(NULL), cond_name("none"), @@ -41,6 +42,7 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, c_stack(NULL), next_c_sp(0), next_rust_sp(0), + port_selector(kernel), supervisor(spawner) { LOGPTR(sched_loop, "new task", (uintptr_t)this); diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index f1c7ae0269985..0561d197e4309 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -117,7 +117,6 @@ rust_task : public kernel_owned, rust_cond // Fields known only to the runtime. rust_kernel *kernel; const char *const name; - int32_t list_index; // Rendezvous pointer for receiving data when blocked on a port. If we're // trying to read data and no data is available on any incoming channel, @@ -143,6 +142,10 @@ rust_task : public kernel_owned, rust_cond // The amount of stack we're using, excluding red zones size_t total_stack_sz; + // for linked list in rust_task_queue + rust_task * next; + rust_task * prev; + private: // Protects state, cond, cond_name diff --git a/src/rt/rust_task_queue.cpp b/src/rt/rust_task_queue.cpp new file mode 100644 index 0000000000000..e94fe0f16112b --- /dev/null +++ b/src/rt/rust_task_queue.cpp @@ -0,0 +1,59 @@ + +#include "rust_task_queue.h" +#include "rust_internal.h" + +rust_task_iterator::rust_task_iterator(rust_task * h, size_t m) : + count(0), cur(h), max(m) +{ +} + +rust_task * +rust_task_iterator::next() { + count++; + rust_task *ret = cur; + cur = cur->next; + return ret; +} + +rust_task_queue::rust_task_queue() : head(NULL), sz(0) +{ +} + +rust_task * +rust_task_queue::next() { + if (sz == 0) + return NULL; + rust_task *ret = head; + head = head->next; + return ret; +} + +void +rust_task_queue::insert(rust_task *elem) { + if (++sz == 1) { + head = elem; + head->next = head; + head->prev = head; + } else { + elem->prev = head->prev; + elem->next = head; + head->prev->next = elem; + head->prev = elem; + } +} + +void +rust_task_queue::remove(rust_task *elem) { + if (sz == 0 || elem->next == NULL || elem->prev == NULL) + return; + if (--sz == 0) + head = NULL; + else { + if (elem == head) + head = elem->next; + elem->next->prev = elem->prev; + elem->prev->next = elem->next; + } + elem->next = NULL; + elem->prev = NULL; +} diff --git a/src/rt/rust_task_queue.h b/src/rt/rust_task_queue.h new file mode 100644 index 0000000000000..80b62c1857903 --- /dev/null +++ b/src/rt/rust_task_queue.h @@ -0,0 +1,51 @@ + +#ifndef RUST_TASK_QUEUE_H +#define RUST_TASK_QUEUE_H + +#include + +struct rust_task; + +class rust_task_iterator { + public: + rust_task_iterator(rust_task *h, size_t m); + + inline bool hasNext() { + return count < max; + } + + rust_task *next(); + + private: + size_t count; + rust_task * cur; + size_t max; +}; + +class rust_task_queue { + public: + + rust_task_queue(); + + inline rust_task_iterator iterator() + { + return rust_task_iterator(head, sz); + } + + inline size_t size() { + return sz; + } + + rust_task *next(); + void insert(rust_task *elem); + void remove(rust_task *elem); + + private: + + rust_task *head; + size_t sz; + +}; + + +#endif diff --git a/src/rt/util/indexed_list.h b/src/rt/util/indexed_list.h deleted file mode 100644 index d58927156a6fc..0000000000000 --- a/src/rt/util/indexed_list.h +++ /dev/null @@ -1,97 +0,0 @@ -// -*- c++ -*- -#ifndef INDEXED_LIST_H -#define INDEXED_LIST_H - -#include -#include "array_list.h" - -class indexed_list_object { -public: - int32_t list_index; -}; - -template -class indexed_list_element : public indexed_list_object { -public: - T value; - indexed_list_element(T value) : value(value) { - } -}; - -/** - * An array list of objects that are aware of their position in the list. - * Normally, objects in this list should derive from the base class - * "indexed_list_object" however because of nasty Rust compiler dependencies - * on the layout of runtime objects we cannot always derive from this - * base class, so instead we just enforce the informal protocol that any - * object inserted in this list must define a "int32_t list_index" member. - */ -template class indexed_list { - array_list list; -public: - virtual int32_t append(T *value); - virtual bool pop(T **value); - /** - * Same as pop(), except that it returns NULL if the list is empty. - */ - virtual T* pop_value(); - virtual size_t length() { - return list.size(); - } - virtual bool is_empty() { - return list.is_empty(); - } - virtual int32_t remove(T* value); - virtual T * operator[](int32_t index); - virtual ~indexed_list() {} -}; - -template int32_t -indexed_list::append(T *value) { - value->list_index = list.push(value); - return value->list_index; -} - -/** - * Swap delete the last object in the list with the specified object. - */ -template int32_t -indexed_list::remove(T *value) { - assert (value->list_index >= 0); - assert (value->list_index < (int32_t)list.size()); - int32_t removeIndex = value->list_index; - T *last = 0; - list.pop(&last); - if (last->list_index == removeIndex) { - last->list_index = -1; - return removeIndex; - } else { - value->list_index = -1; - list[removeIndex] = last; - last->list_index = removeIndex; - return removeIndex; - } -} - -template bool -indexed_list::pop(T **value) { - return list.pop(value); -} - -template T* -indexed_list::pop_value() { - T *value = NULL; - if (list.pop(&value)) { - return value; - } - return NULL; -} - -template T * -indexed_list::operator[](int32_t index) { - T *value = list[index]; - assert(value->list_index == index); - return value; -} - -#endif /* INDEXED_LIST_H */ diff --git a/src/rt/util/synchronized_indexed_list.h b/src/rt/util/synchronized_indexed_list.h deleted file mode 100644 index f7c451ee5b140..0000000000000 --- a/src/rt/util/synchronized_indexed_list.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef SYNCHRONIZED_INDEXED_LIST_H -#define SYNCHRONIZED_INDEXED_LIST_H - -#include "indexed_list.h" -#include "../sync/lock_and_signal.h" - -template class synchronized_indexed_list : - public indexed_list { - lock_and_signal _lock; - -public: - synchronized_indexed_list() { - } - - int32_t append(T *value) { - int32_t index = 0; - _lock.lock(); - index = indexed_list::append(value); - _lock.unlock(); - return index; - } - - bool pop(T **value) { - _lock.lock(); - bool result = indexed_list::pop(value); - _lock.unlock(); - return result; - } - - size_t length() { - size_t length = 0; - _lock.lock(); - length = indexed_list::length(); - _lock.unlock(); - return length; - } - - bool is_empty() { - bool empty = false; - _lock.lock(); - empty = indexed_list::is_empty(); - _lock.unlock(); - return empty; - } - - int32_t remove(T* value) { - size_t index = 0; - _lock.lock(); - index = indexed_list::remove(value); - _lock.unlock(); - return index; - } - - T *operator[](size_t index) { - T *value = NULL; - _lock.lock(); - value = indexed_list::operator[](index); - _lock.unlock(); - return value; - } -}; - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; -// End: -// - -#endif /* SYNCHRONIZED_INDEXED_LIST_H */