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:
Michael Bebenita 2010-08-27 18:26:36 -07:00
parent ffdb5fc858
commit f8ff013e3c
16 changed files with 250 additions and 111 deletions

View File

@ -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

View File

@ -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__)

View File

@ -17,10 +17,6 @@
#define CDECL
#endif
#include "util/array_list.h"
#include "rust_srv.h"
/*
* Local Variables:
* fill-column: 78;

View File

@ -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()) {

View File

@ -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;

View File

@ -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"

43
src/rt/rust_kernel.cpp Normal file
View File

@ -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);
}
}

21
src/rt/rust_kernel.h Normal file
View File

@ -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 */

View File

@ -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 {

View File

@ -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
};

View File

@ -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();
}

View File

@ -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 */

View File

@ -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);

View File

@ -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.

View File

@ -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 */

View File

@ -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 */