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.
This commit is contained in:
parent
ffdb5fc858
commit
f8ff013e3c
|
@ -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
|
||||
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -17,10 +17,6 @@
|
|||
#define CDECL
|
||||
#endif
|
||||
|
||||
#include "util/array_list.h"
|
||||
|
||||
#include "rust_srv.h"
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* fill-column: 78;
|
||||
|
|
|
@ -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,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()) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ®ion;
|
||||
array_list<T*> 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<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 */
|
|
@ -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 ®ion) :
|
||||
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 */
|
Loading…
Reference in New Issue