Introduced task handles.

This is the new way to refer to tasks in rust-land. Currently all they
do is serve as a key to look up the old rust_task structure. Ideally
they won't be ref counted, but baby steps.
This commit is contained in:
unknown 2011-08-08 13:38:20 -07:00 committed by Eric Holk
parent f4f057ced1
commit 44bef5f2cb
14 changed files with 75 additions and 38 deletions

View File

@ -4,7 +4,7 @@
// NB: please do not commit code with this uncommented. It's
// hugely expensive and should only be used as a last resort.
//
// #define TRACK_ALLOCATIONS
#define TRACK_ALLOCATIONS
#define MAGIC 0xbadc0ffe

View File

@ -93,7 +93,9 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
rust_srv *srv = new rust_srv(env);
rust_kernel *kernel = new rust_kernel(srv, env->num_sched_threads);
rust_task *root_task = kernel->create_task(NULL, "main");
rust_task_id root_id = kernel->create_task(NULL, "main");
rust_task *root_task = kernel->get_task_by_id(root_id);
I(kernel, root_task != NULL);
rust_scheduler *sched = root_task->sched;
command_line_args *args
= new (kernel, "main command line args")

View File

@ -408,8 +408,11 @@ task_yield(rust_task *task) {
}
extern "C" CDECL intptr_t
task_join(rust_task *task, rust_task *join_task) {
task_join(rust_task *task, rust_task_id tid) {
// If the other task is already dying, we don't have to wait for it.
rust_task *join_task = task->kernel->get_task_by_id(tid);
// FIXME: find task exit status and return that.
if(!join_task) return 0;
join_task->lock.lock();
if (join_task->dead() == false) {
join_task->tasks_waiting_to_join.push(task);

View File

@ -73,16 +73,17 @@ void rust_chan::disassociate() {
* Attempt to send data to the associated port.
*/
void rust_chan::send(void *sptr) {
scoped_lock with(port->lock);
buffer.enqueue(sptr);
if (!is_associated()) {
W(kernel, is_associated(),
"rust_chan::transmit with no associated port.");
return;
}
I(kernel, port != NULL);
scoped_lock with(port->lock);
buffer.enqueue(sptr);
A(kernel, !buffer.is_empty(),
"rust_chan::transmit with nothing to send.");

View File

@ -64,6 +64,8 @@ struct stk_seg;
struct type_desc;
struct frame_glue_fns;
typedef intptr_t rust_task_id;
#ifndef __i386__
#error "Target CPU not supported."
#endif

View File

@ -9,6 +9,7 @@ rust_kernel::rust_kernel(rust_srv *srv, size_t num_threads) :
_region(srv, true),
_log(srv, NULL),
srv(srv),
max_id(0),
num_threads(num_threads),
rval(0),
live_tasks(0),
@ -133,10 +134,31 @@ int rust_kernel::start_task_threads()
return rval;
}
rust_task *
rust_task_id
rust_kernel::create_task(rust_task *spawner, const char *name) {
rust_scheduler *thread = threads[rand(&rctx) % num_threads];
return thread->create_task(spawner, name);
rust_task *t = thread->create_task(spawner, name);
{
scoped_lock with(_kernel_lock);
t->id = max_id++;
task_table.put(t->id, t);
}
return t->id;
}
rust_task *
rust_kernel::get_task_by_id(rust_task_id id) {
scoped_lock with(_kernel_lock);
rust_task *task = NULL;
// get leaves task unchanged if not found.
task_table.get(id, &task);
return task;
}
void
rust_kernel::release_task_id(rust_task_id id) {
scoped_lock with(_kernel_lock);
task_table.remove(id);
}
void rust_kernel::wakeup_schedulers() {

View File

@ -26,8 +26,10 @@ private:
void create_schedulers();
void destroy_schedulers();
public:
rust_task_id max_id;
hash_map<rust_task_id, rust_task *> task_table;
public:
const size_t num_threads;
int rval;
@ -56,7 +58,9 @@ public:
void win32_require(LPCTSTR fn, BOOL ok);
#endif
rust_task *create_task(rust_task *spawner, const char *name);
rust_task_id create_task(rust_task *spawner, const char *name);
rust_task *get_task_by_id(rust_task_id id);
void release_task_id(rust_task_id tid);
};
#endif /* RUST_KERNEL_H */

View File

@ -51,9 +51,6 @@ struct rust_scheduler : public kernel_owned<rust_scheduler>,
rust_kernel *kernel;
int32_t list_index;
hash_map<rust_task *, rust_task *> _task_proxies;
hash_map<rust_port *, rust_port *> _port_proxies;
const int id;
lock_and_signal lock;

View File

@ -95,6 +95,8 @@ rust_task::~rust_task()
DLOG(sched, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
name, (uintptr_t)this, ref_count);
kernel->release_task_id(id);
/* FIXME: tighten this up, there are some more
assertions that hold at task-lifecycle events. */
I(sched, ref_count == 0); // ||

View File

@ -34,7 +34,6 @@ struct gc_alloc {
}
};
struct
rust_task : public kernel_owned<rust_task>, rust_cond
{
@ -59,6 +58,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
size_t gc_alloc_thresh;
size_t gc_alloc_accum;
rust_task_id id;
// Keeps track of the last time this task yielded.
timer yield_timer;

View File

@ -140,9 +140,11 @@ void upcall_del_chan(rust_task *task, rust_chan *chan) {
* has its own copy of the channel.
*/
extern "C" CDECL rust_chan *
upcall_clone_chan(rust_task *task, rust_task *target,
upcall_clone_chan(rust_task *task, rust_task_id tid,
rust_chan *chan) {
// FIXME: This should be removed.
LOG_UPCALL_ENTRY(task);
rust_task *target = task->kernel->get_task_by_id(tid);
return chan->clone(target);
}
@ -203,9 +205,9 @@ upcall_fail(rust_task *task,
* Called whenever a task's ref count drops to zero.
*/
extern "C" CDECL void
upcall_kill(rust_task *task, rust_task *target) {
upcall_kill(rust_task *task, rust_task_id tid) {
LOG_UPCALL_ENTRY(task);
rust_task *target = task->kernel->get_task_by_id(tid);
target->kill();
}
@ -322,9 +324,9 @@ upcall_new_str(rust_task *task, char const *s, size_t fill) {
}
extern "C" CDECL rust_str *
upcall_dup_str(rust_task *task, rust_task *target, rust_str *str) {
upcall_dup_str(rust_task *task, rust_task_id tid, rust_str *str) {
LOG_UPCALL_ENTRY(task);
rust_task *target = task->kernel->get_task_by_id(tid);
return make_str(target, (char const *)str->data, str->fill);
}
@ -482,27 +484,30 @@ upcall_get_type_desc(rust_task *task,
return td;
}
extern "C" CDECL rust_task *
extern "C" CDECL rust_task_id
upcall_new_task(rust_task *spawner, rust_vec *name) {
// name is a rust string structure.
LOG_UPCALL_ENTRY(spawner);
rust_task *task =
rust_task_id tid =
spawner->kernel->create_task(spawner, (const char *)name->data);
rust_task *task = spawner->kernel->get_task_by_id(tid);
task->ref();
return task;
return tid;
}
extern "C" CDECL void
upcall_take_task(rust_task *task, rust_task *target) {
upcall_take_task(rust_task *task, rust_task_id tid) {
LOG_UPCALL_ENTRY(task);
rust_task *target = task->kernel->get_task_by_id(tid);
if(target) {
target->ref();
}
}
extern "C" CDECL void
upcall_drop_task(rust_task *task, rust_task *target) {
upcall_drop_task(rust_task *task, rust_task_id tid) {
LOG_UPCALL_ENTRY(task);
rust_task *target = task->kernel->get_task_by_id(tid);
if(target) {
target->deref();
}
@ -526,13 +531,14 @@ upcall_drop_chan(rust_task *task, rust_chan *target) {
extern "C" CDECL rust_task *
upcall_start_task(rust_task *spawner,
rust_task *task,
rust_task_id tid,
uintptr_t spawnee_fn,
uintptr_t args,
size_t args_sz) {
LOG_UPCALL_ENTRY(spawner);
rust_scheduler *sched = spawner->sched;
rust_task *task = spawner->kernel->get_task_by_id(tid);
DLOG(sched, task,
"upcall start_task(task %s @0x%" PRIxPTR
", spawnee 0x%" PRIxPTR ")",

View File

@ -45,7 +45,8 @@ void task_entry() {
void
rust_task_test::worker::run() {
rust_task *root_task = kernel->create_task(NULL, "main");
rust_task_id root_id = kernel->create_task(NULL, "main");
rust_task *root_task = kernel->get_task_by_id(root_id);
root_task->start((uintptr_t)&task_entry, (uintptr_t)NULL);
root_task->sched->start_main_loop();
}

View File

@ -1,3 +1,4 @@
// -*- c++ -*-
/**
* A C++ wrapper around uthash.
*/

View File

@ -4,12 +4,11 @@ import std::comm;
fn start(pcc: *u8) {
let c = comm::chan_from_unsafe_ptr(pcc);
let p;
let p = comm::mk_port[str]();
c.send(p.mk_chan().unsafe_ptr());
let a;
let b;
p = comm::mk_port[str]();
c.send(p.mk_chan().unsafe_ptr());
a = p.recv();
log_err a;
b = p.recv();
@ -17,15 +16,11 @@ fn start(pcc: *u8) {
}
fn main() {
let p : comm::_port[*u8];
let child;
let p = comm::mk_port[*u8]();
let child = spawn start(p.mk_chan().unsafe_ptr());
p = comm::mk_port();
child = spawn start(p.mk_chan().unsafe_ptr());
let pc; let c;
pc = p.recv();
c = comm::chan_from_unsafe_ptr(pc);
let pc = p.recv();
let c = comm::chan_from_unsafe_ptr(pc);
c.send("A");
c.send("B");
task::yield();