From f8ff013e3cc737b92b5a140dfd0ddcc5ab6773d9 Mon Sep 17 00:00:00 2001 From: Michael Bebenita Date: Fri, 27 Aug 2010 18:26:36 -0700 Subject: Added a few utility classes, cleaned up the include order of .h files, and started to make the Rust kernel own domain message queues rather than the Rust domains themselves. --- src/Makefile | 4 ++ src/rt/rust.cpp | 3 +- src/rt/rust.h | 4 -- src/rt/rust_dom.cpp | 23 ++------- src/rt/rust_dom.h | 13 ++--- src/rt/rust_internal.h | 91 +++++++++++++-------------------- src/rt/rust_kernel.cpp | 43 ++++++++++++++++ src/rt/rust_kernel.h | 21 ++++++++ src/rt/rust_log.cpp | 3 +- src/rt/rust_log.h | 3 +- src/rt/rust_srv.cpp | 8 +-- src/rt/rust_srv.h | 9 +--- src/rt/rust_upcall.cpp | 8 ++- src/rt/sync/lock_free_queue.h | 2 + src/rt/util/indexed_list.h | 70 +++++++++++++++++++++++++ src/rt/util/synchronized_indexed_list.h | 56 ++++++++++++++++++++ 16 files changed, 250 insertions(+), 111 deletions(-) create mode 100644 src/rt/rust_kernel.cpp create mode 100644 src/rt/rust_kernel.h create mode 100644 src/rt/util/indexed_list.h create mode 100644 src/rt/util/synchronized_indexed_list.h (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 18e8edc2..f5aebfc4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -267,6 +267,7 @@ RUNTIME_CS := rt/sync/timer.cpp \ rt/circular_buffer.cpp \ rt/isaac/randport.cpp \ rt/rust_srv.cpp \ + rt/rust_kernel.cpp \ rt/memory_region.cpp RUNTIME_HDR := rt/globals.h \ @@ -283,11 +284,14 @@ RUNTIME_HDR := rt/globals.h \ rt/rust_message.h \ rt/circular_buffer.h \ rt/util/array_list.h \ + rt/util/indexed_list.h \ + rt/util/synchronized_indexed_list.h \ rt/util/hash_map.h \ rt/sync/sync.h \ rt/sync/timer.h \ rt/sync/lock_free_queue.h \ rt/rust_srv.h \ + rt/rust_kernel.h \ rt/memory_region.h \ rt/memory.h diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index 905b0c8a..43818de5 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -1,6 +1,5 @@ #include "rust_internal.h" - struct command_line_args { @@ -80,6 +79,7 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc, char **argv) { rust_srv srv; rust_dom dom(&srv, crate, "main"); + srv.kernel->register_domain(&dom); command_line_args args(dom, argc, argv); dom.log(rust_log::DOM, "startup: %d args", args.argc); @@ -99,6 +99,7 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc, char **argv) sizeof(main_args)); ret = dom.start_main_loop(); + srv.kernel->deregister_domain(&dom); } #if !defined(__WIN32__) diff --git a/src/rt/rust.h b/src/rt/rust.h index 3c534c94..66185727 100644 --- a/src/rt/rust.h +++ b/src/rt/rust.h @@ -17,10 +17,6 @@ #define CDECL #endif -#include "util/array_list.h" - -#include "rust_srv.h" - /* * Local Variables: * fill-column: 78; diff --git a/src/rt/rust_dom.cpp b/src/rt/rust_dom.cpp index dc42286d..a1207ec7 100644 --- a/src/rt/rust_dom.cpp +++ b/src/rt/rust_dom.cpp @@ -4,9 +4,6 @@ template class ptr_vec; -// Keeps track of all live domains, for debugging purposes. -array_list _live_domains; - rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate, const char *name) : interrupt_flag(0), @@ -22,7 +19,8 @@ rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate, caches(this), root_task(NULL), curr_task(NULL), - rval(0) + rval(0), + _kernel(srv->kernel) { logptr("new dom", (uintptr_t)this); isaac_init(this, &rctx); @@ -32,10 +30,6 @@ rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate, pthread_attr_setdetachstate(&attr, true); #endif root_task = new (this) rust_task(this, NULL, name); - - if (_live_domains.replace(NULL, this) == false) { - _live_domains.append(this); - } } static void @@ -86,8 +80,6 @@ rust_dom::~rust_dom() { #endif while (caches.length()) delete caches.pop(); - - _live_domains.replace(this, NULL); } void @@ -375,7 +367,7 @@ rust_dom::schedule_task() { */ bool rust_dom::is_deadlocked() { - if (_live_domains.size() != 1) { + if (_kernel->domains.length() != 1) { // We cannot tell if we are deadlocked if other domains exists. return false; } @@ -388,20 +380,13 @@ rust_dom::is_deadlocked() { if (_incoming_message_queue.is_empty() && blocked_tasks.length() > 0) { // We have no messages to process, no running tasks to schedule // and some blocked tasks therefore we are likely in a deadlock. - log_state(); + _kernel->log_all_domain_state(); return true; } return false; } -void -rust_dom::log_all_state() { - for (uint32_t i = 0; i < _live_domains.size(); i++) { - _live_domains[i]->log_state(); - } -} - void rust_dom::log_state() { if (!running_tasks.is_empty()) { diff --git a/src/rt/rust_dom.h b/src/rt/rust_dom.h index 44f56cc4..5c9c2953 100644 --- a/src/rt/rust_dom.h +++ b/src/rt/rust_dom.h @@ -1,16 +1,6 @@ -/* - * rust_dom.h - */ - #ifndef RUST_DOM_H #define RUST_DOM_H -#include "sync/lock_free_queue.h" -#include "util/hash_map.h" - -#include "rust_proxy.h" -#include "rust_message.h" - struct rust_dom { // Fields known to the compiler: @@ -37,6 +27,9 @@ struct rust_dom rust_task *curr_task; int rval; + rust_kernel *_kernel; + int32_t list_index; + hash_map *> _task_proxies; hash_map *> _port_proxies; diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index d6618873..60d86f61 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -14,11 +14,8 @@ #include #include - #include "rust.h" - #include "rand.h" -#include "rust_log.h" #include "uthash.h" #if defined(__WIN32__) @@ -39,9 +36,28 @@ extern "C" { #error "Platform not supported." #endif +#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/timer.h" #include "sync/condition_variable.h" +#include "sync/lock_free_queue.h" + +class rust_dom; +class rust_log; +class rust_task; +class rust_port; +class rust_chan; +struct rust_token; +class rust_kernel; +class rust_crate; +class rust_crate_cache; + +struct stk_seg; +struct type_desc; +struct frame_glue_fns; #ifndef __i386__ #error "Target CPU not supported." @@ -56,29 +72,13 @@ extern "C" { #define A(dom, e, s, ...) ((e) ? (void)0 : \ (dom)->srv->fatal(#e, __FILE__, __LINE__, s, ## __VA_ARGS__)) -struct rust_task; -struct rust_port; -class rust_chan; -struct rust_token; -struct rust_dom; -class rust_crate; -class rust_crate_cache; -// class lockfree_queue; - -struct stk_seg; -struct type_desc; -struct frame_glue_fns; - // This drives our preemption scheme. static size_t const TIME_SLICE_IN_MS = 10; // Every reference counted object should derive from this base class. -template -struct -rc_base -{ +template struct rc_base { intptr_t ref_count; void ref() { @@ -91,29 +91,25 @@ rc_base } } - rc_base(); - ~rc_base(); + rc_base(); + ~rc_base(); }; -template -struct -dom_owned -{ +template struct dom_owned { rust_dom *get_dom() const { return ((T*)this)->dom; } + void operator delete(void *ptr) { ((T *)ptr)->dom->free(ptr); } }; -template -struct -task_owned -{ +template struct task_owned { rust_dom *get_dom() const { return ((T *)this)->task->dom; } + void operator delete(void *ptr) { ((T *)ptr)->task->dom->free(ptr); } @@ -122,24 +118,16 @@ task_owned // A cond(ition) is something we can block on. This can be a channel // (writing), a port (reading) or a task (waiting). -struct -rust_cond -{ -}; +struct rust_cond { }; // Helper class used regularly elsewhere. -template -class -ptr_vec : public dom_owned > -{ +template class ptr_vec : public dom_owned > { static const size_t INIT_SIZE = 8; - rust_dom *dom; size_t alloc; size_t fill; T **data; - public: ptr_vec(rust_dom *dom); ~ptr_vec(); @@ -160,24 +148,16 @@ public: void swap_delete(T* p); }; +#include "memory_region.h" +#include "rust_srv.h" +#include "rust_log.h" +#include "rust_proxy.h" +#include "rust_message.h" +#include "rust_kernel.h" #include "rust_dom.h" - -template inline T -check_null(rust_dom *dom, T value, char const *expr, - char const *file, size_t line) { - if (value == NULL) { - dom->srv->fatal(expr, file, line, "is null"); - } - return value; -} - -#define CHECK_NULL(dom, e) (check_null(dom, e, #e, __FILE__, __LINE__)) - #include "memory.h" -struct -rust_timer -{ +struct rust_timer { // FIXME: This will probably eventually need replacement // with something more sophisticated and integrated with // an IO event-handling library, when we have such a thing. @@ -568,7 +548,6 @@ struct gc_alloc { }; #include "circular_buffer.h" -#include "rust_proxy.h" #include "rust_task.h" #include "rust_chan.h" #include "rust_port.h" diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp new file mode 100644 index 00000000..b82e4615 --- /dev/null +++ b/src/rt/rust_kernel.cpp @@ -0,0 +1,43 @@ +#include "rust_internal.h" + +rust_kernel::rust_kernel(rust_srv *srv) : + _region(srv->local_region), + _log(srv, NULL), + domains(srv->local_region), + message_queues(srv->local_region) { + // Nop. +} + +rust_kernel::~rust_kernel() { + // Nop. +} + +void +rust_kernel::register_domain(rust_dom *dom) { + domains.append(dom); +} + +void +rust_kernel::deregister_domain(rust_dom *dom) { + domains.remove(dom); +} + +void +rust_kernel::log_all_domain_state() { + log(rust_log::KERN, "log_all_domain_state: %d domains", domains.length()); + for (uint32_t i = 0; i < domains.length(); i++) { + domains[i]->log_state(); + } +} + +void +rust_kernel::log(uint32_t type_bits, char const *fmt, ...) { + char buf[256]; + if (_log.is_tracing(type_bits)) { + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + _log.trace_ln(NULL, type_bits, buf); + va_end(args); + } +} diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h new file mode 100644 index 00000000..478d030c --- /dev/null +++ b/src/rt/rust_kernel.h @@ -0,0 +1,21 @@ +#ifndef RUST_KERNEL_H +#define RUST_KERNEL_H + +/** + * A global object shared by all domains. + */ +class rust_kernel { + memory_region &_region; + rust_log _log; +public: + synchronized_indexed_list domains; + synchronized_indexed_list > message_queues; + rust_kernel(rust_srv *srv); + void register_domain(rust_dom *dom); + void deregister_domain(rust_dom *dom); + void log_all_domain_state(); + void log(uint32_t type_bits, char const *fmt, ...); + virtual ~rust_kernel(); +}; + +#endif /* RUST_KERNEL_H */ diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp index e72a62fa..fab5098d 100644 --- a/src/rt/rust_log.cpp +++ b/src/rt/rust_log.cpp @@ -28,6 +28,7 @@ read_type_bit_mask() { bits |= strstr(env_str, "gc") ? rust_log::GC : 0; bits |= strstr(env_str, "stdlib") ? rust_log::STDLIB : 0; bits |= strstr(env_str, "special") ? rust_log::SPECIAL : 0; + bits |= strstr(env_str, "kern") ? rust_log::KERN : 0; bits |= strstr(env_str, "all") ? rust_log::ALL : 0; bits = strstr(env_str, "none") ? 0 : bits; } @@ -150,7 +151,7 @@ rust_log::trace_ln(rust_task *task, char *message) { uint32_t thread_id = hash((uint32_t) pthread_self()); #endif char prefix[1024] = ""; - if (_dom->name) { + if (_dom && _dom->name) { append_string(prefix, "%04" PRIxPTR ":%.10s:", thread_id, _dom->name); } else { diff --git a/src/rt/rust_log.h b/src/rt/rust_log.h index 5155cb48..66246eb6 100644 --- a/src/rt/rust_log.h +++ b/src/rt/rust_log.h @@ -4,8 +4,6 @@ class rust_dom; class rust_task; - - class rust_log { public: @@ -43,6 +41,7 @@ public: GC = 0x800, STDLIB = 0x1000, SPECIAL = 0x2000, + KERN = 0x4000, ALL = 0xffffffff }; diff --git a/src/rt/rust_srv.cpp b/src/rt/rust_srv.cpp index f2dfef63..d9223562 100644 --- a/src/rt/rust_srv.cpp +++ b/src/rt/rust_srv.cpp @@ -7,7 +7,8 @@ rust_srv::rust_srv() : local_region(this, false), - synchronized_region(this, true) { + synchronized_region(this, true), + kernel(new rust_kernel(this)) { // Nop. } @@ -73,8 +74,3 @@ rust_srv::warning(char const *expression, expression, file, (int)line, buf); log(msg); } - -rust_srv * -rust_srv::clone() { - return new rust_srv(); -} diff --git a/src/rt/rust_srv.h b/src/rt/rust_srv.h index e617c002..ab646ae6 100644 --- a/src/rt/rust_srv.h +++ b/src/rt/rust_srv.h @@ -1,17 +1,13 @@ -/* - * - */ - #ifndef RUST_SRV_H #define RUST_SRV_H -#include "sync/spin_lock.h" -#include "memory_region.h" +#include "rust_internal.h" class rust_srv { public: memory_region local_region; memory_region synchronized_region; + rust_kernel *kernel; virtual void log(char const *msg); virtual void fatal(char const *expression, char const *file, @@ -28,7 +24,6 @@ public: virtual void *realloc(void *, size_t); rust_srv(); virtual ~rust_srv(); - virtual rust_srv *clone(); }; #endif /* RUST_SRV_H */ diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 954e7a13..0e3961bc 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -567,11 +567,9 @@ static void *rust_thread_start(void *ptr) // Start a new rust main loop for this thread. dom->start_main_loop(); - rust_srv *srv = dom->srv; + srv->kernel->deregister_domain(dom); delete dom; - delete srv; - return 0; } @@ -611,10 +609,10 @@ upcall_new_thread(rust_task *task, const char *name) { LOG_UPCALL_ENTRY(task); rust_dom *old_dom = task->dom; - rust_dom *new_dom = new rust_dom(old_dom->srv->clone(), + rust_dom *new_dom = new rust_dom(old_dom->srv, old_dom->root_crate, name); - + old_dom->srv->kernel->register_domain(new_dom); task->log(rust_log::UPCALL | rust_log::MEM, "upcall new_thread(%s) = dom 0x%" PRIxPTR " task 0x%" PRIxPTR, name, new_dom, new_dom->root_task); diff --git a/src/rt/sync/lock_free_queue.h b/src/rt/sync/lock_free_queue.h index ac0c5b04..5ebc70f1 100644 --- a/src/rt/sync/lock_free_queue.h +++ b/src/rt/sync/lock_free_queue.h @@ -98,6 +98,8 @@ class lock_free_queue { } public: + int32_t list_index; + lock_free_queue() { // We can only handle 64bit CAS for counted pointers, so this will // not work with 64bit pointers. diff --git a/src/rt/util/indexed_list.h b/src/rt/util/indexed_list.h new file mode 100644 index 00000000..d869d43e --- /dev/null +++ b/src/rt/util/indexed_list.h @@ -0,0 +1,70 @@ +#ifndef INDEXED_LIST_H +#define INDEXED_LIST_H + +#include +#include "array_list.h" +#include "../memory_region.h" + +class indexed_list_object { +public: + int32_t list_index; +}; + +/** + * 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 { + memory_region ®ion; + array_list list; +public: + indexed_list(memory_region ®ion) : region(region) {} + virtual int32_t append(T *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); +}; + +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 = list.pop(); + 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 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 new file mode 100644 index 00000000..ca02f6ef --- /dev/null +++ b/src/rt/util/synchronized_indexed_list.h @@ -0,0 +1,56 @@ +#ifndef SYNCHRONIZED_INDEXED_LIST_H +#define SYNCHRONIZED_INDEXED_LIST_H + +#include "indexed_list.h" + +template class synchronized_indexed_list : + public indexed_list { + spin_lock _lock; +public: + synchronized_indexed_list(memory_region ®ion) : + indexed_list(region) { + // Nop. + } + + int32_t append(T *value) { + int32_t index = 0; + _lock.lock(); + index = indexed_list::append(value); + _lock.unlock(); + return index; + } + + 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; + } +}; + +#endif /* SYNCHRONIZED_INDEXED_LIST_H */ -- cgit v1.2.3