about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile4
-rw-r--r--src/rt/rust.cpp3
-rw-r--r--src/rt/rust.h4
-rw-r--r--src/rt/rust_dom.cpp23
-rw-r--r--src/rt/rust_dom.h13
-rw-r--r--src/rt/rust_internal.h91
-rw-r--r--src/rt/rust_kernel.cpp43
-rw-r--r--src/rt/rust_kernel.h21
-rw-r--r--src/rt/rust_log.cpp3
-rw-r--r--src/rt/rust_log.h3
-rw-r--r--src/rt/rust_srv.cpp8
-rw-r--r--src/rt/rust_srv.h9
-rw-r--r--src/rt/rust_upcall.cpp8
-rw-r--r--src/rt/sync/lock_free_queue.h2
-rw-r--r--src/rt/util/indexed_list.h70
-rw-r--r--src/rt/util/synchronized_indexed_list.h56
16 files changed, 250 insertions, 111 deletions
diff --git a/src/Makefile b/src/Makefile
index 18e8edc2a18..f5aebfc42cd 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 905b0c8a359..43818de5514 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 3c534c9444b..66185727cff 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 dc42286da8a..a1207ec738a 100644
--- a/src/rt/rust_dom.cpp
+++ b/src/rt/rust_dom.cpp
@@ -4,9 +4,6 @@
 
 template class ptr_vec<rust_task>;
 
-// Keeps track of all live domains, for debugging purposes.
-array_list<rust_dom*> _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,7 +380,7 @@ 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;
     }
 
@@ -396,13 +388,6 @@ rust_dom::is_deadlocked() {
 }
 
 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()) {
         log(rust_log::TASK, "running tasks:");
diff --git a/src/rt/rust_dom.h b/src/rt/rust_dom.h
index 44f56cc41bb..5c9c29533c4 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<rust_task *, rust_proxy<rust_task> *> _task_proxies;
     hash_map<rust_port *, rust_proxy<rust_port> *> _port_proxies;
 
diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h
index d6618873dff..60d86f6116c 100644
--- a/src/rt/rust_internal.h
+++ b/src/rt/rust_internal.h
@@ -14,11 +14,8 @@
 
 #include <stdio.h>
 #include <string.h>
-
 #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 <typename T>
-struct
-rc_base
-{
+template <typename T> struct rc_base {
     intptr_t ref_count;
 
     void ref() {
@@ -91,29 +91,25 @@ rc_base
         }
     }
 
-  rc_base();
-  ~rc_base();
+    rc_base();
+    ~rc_base();
 };
 
-template <typename T>
-struct
-dom_owned
-{
+template <typename T> struct dom_owned {
     rust_dom *get_dom() const {
         return ((T*)this)->dom;
     }
+
     void operator delete(void *ptr) {
         ((T *)ptr)->dom->free(ptr);
     }
 };
 
-template <typename T>
-struct
-task_owned
-{
+template <typename T> 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 <typename T>
-class
-ptr_vec : public dom_owned<ptr_vec<T> >
-{
+template <typename T> class ptr_vec : public dom_owned<ptr_vec<T> > {
     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 <typename T> 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 00000000000..b82e46152fa
--- /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 00000000000..478d030c177
--- /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<rust_dom> domains;
+    synchronized_indexed_list<lock_free_queue<rust_message*> > 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 e72a62faa30..fab5098d85a 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 5155cb48bc3..66246eb60e4 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 f2dfef63ab6..d92235623de 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 e617c002576..ab646ae6a8f 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 954e7a13ded..0e3961bc24c 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 ac0c5b046a0..5ebc70f12fe 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 00000000000..d869d43e3e2
--- /dev/null
+++ b/src/rt/util/indexed_list.h
@@ -0,0 +1,70 @@
+#ifndef INDEXED_LIST_H
+#define INDEXED_LIST_H
+
+#include <assert.h>
+#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<typename T> class indexed_list {
+    memory_region &region;
+    array_list<T*> list;
+public:
+    indexed_list(memory_region &region) : 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<typename T> int32_t
+indexed_list<T>::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<typename T> int32_t
+indexed_list<T>::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 <typename T> T *
+indexed_list<T>::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 00000000000..ca02f6efdd2
--- /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<typename T> class synchronized_indexed_list :
+    public indexed_list<T> {
+    spin_lock _lock;
+public:
+    synchronized_indexed_list(memory_region &region) :
+        indexed_list<T>(region) {
+        // Nop.
+    }
+
+    int32_t append(T *value) {
+        int32_t index = 0;
+        _lock.lock();
+        index = indexed_list<T>::append(value);
+        _lock.unlock();
+        return index;
+    }
+
+    size_t length() {
+       size_t length = 0;
+       _lock.lock();
+       length = indexed_list<T>::length();
+       _lock.unlock();
+       return length;
+    }
+
+    bool is_empty() {
+        bool empty = false;
+        _lock.lock();
+        empty = indexed_list<T>::is_empty();
+        _lock.unlock();
+        return empty;
+    }
+
+    int32_t remove(T* value) {
+        size_t index = 0;
+        _lock.lock();
+        index = indexed_list<T>::remove(value);
+        _lock.unlock();
+        return index;
+    }
+
+    T *operator[](size_t index) {
+        T *value = NULL;
+        _lock.lock();
+        value = indexed_list<T>::operator[](index);
+        _lock.unlock();
+        return value;
+    }
+};
+
+#endif /* SYNCHRONIZED_INDEXED_LIST_H */