1
Fork 0

rewrite task tests

This commit is contained in:
Niko Matsakis 2012-01-04 20:11:39 -08:00
parent 98f5109cde
commit 25e81e34ea
6 changed files with 55 additions and 67 deletions

View file

@ -98,7 +98,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
DLOG(sched, dom, "startup: arg[%d] = '%s'", i, args->argv[i]); DLOG(sched, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
} }
root_task->start((spawn_fn)main_fn, (uintptr_t)args->args); root_task->start((spawn_fn)main_fn, NULL, args->args);
root_task->deref(); root_task->deref();
root_task = NULL; root_task = NULL;

View file

@ -421,15 +421,15 @@ rust_get_task() {
} }
struct fn_env_pair { struct fn_env_pair {
intptr_t f; spawn_fn f;
intptr_t env; rust_boxed_closure *env;
}; };
extern "C" CDECL void extern "C" CDECL void
start_task(rust_task_id id, fn_env_pair *f) { start_task(rust_task_id id, fn_env_pair *f) {
rust_task *task = rust_scheduler::get_task(); rust_task *task = rust_scheduler::get_task();
rust_task *target = task->kernel->get_task_by_id(id); rust_task *target = task->kernel->get_task_by_id(id);
target->start((spawn_fn)f->f, f->env); target->start(f->f, f->env, NULL);
target->deref(); target->deref();
} }

View file

@ -292,18 +292,9 @@ rust_task::~rust_task()
struct spawn_args { struct spawn_args {
rust_task *task; rust_task *task;
uintptr_t envptr;
spawn_fn f; spawn_fn f;
}; rust_boxed_closure *envptr;
void *argptr;
struct rust_closure {
const type_desc *td;
// ... see trans_closure.rs for full description ...
};
struct rust_boxed_closure {
intptr_t ref_count;
rust_closure closure;
}; };
struct cleanup_args { struct cleanup_args {
@ -319,14 +310,6 @@ cleanup_task(cleanup_args *args) {
cc::do_cc(task); cc::do_cc(task);
rust_boxed_closure* boxed_env = (rust_boxed_closure*)a->envptr;
if(boxed_env) {
// free the environment.
rust_closure *env = &boxed_env->closure;
env->td->drop_glue(NULL, NULL, &env->td, env);
env->td->free_glue(NULL, NULL, &env->td, env);
}
task->die(); task->die();
if (task->killed && !failed) { if (task->killed && !failed) {
@ -345,6 +328,8 @@ cleanup_task(cleanup_args *args) {
} }
} }
extern "C" void upcall_shared_free(void* ptr);
// This runs on the Rust stack // This runs on the Rust stack
extern "C" CDECL extern "C" CDECL
void task_start_wrapper(spawn_args *a) void task_start_wrapper(spawn_args *a)
@ -355,16 +340,23 @@ void task_start_wrapper(spawn_args *a)
try { try {
// The first argument is the return pointer; as the task fn // The first argument is the return pointer; as the task fn
// must have void return type, we can safely pass 0. // must have void return type, we can safely pass 0.
a->f(0, a->envptr); a->f(0, a->envptr, a->argptr);
} catch (rust_task *ex) { } catch (rust_task *ex) {
A(task->sched, ex == task, A(task->sched, ex == task,
"Expected this task to be thrown for unwinding"); "Expected this task to be thrown for unwinding");
failed = true; failed = true;
} }
cleanup_args ca = {a, failed}; rust_boxed_closure* boxed_env = (rust_boxed_closure*)a->envptr;
if(boxed_env) {
// free the environment.
const type_desc *td = boxed_env->closure.td;
td->drop_glue(NULL, NULL, td->first_param, &boxed_env->closure);
upcall_shared_free(boxed_env);
}
// The cleanup work needs lots of stack // The cleanup work needs lots of stack
cleanup_args ca = {a, failed};
task->sched->c_context.call_shim_on_c_stack(&ca, (void*)cleanup_task); task->sched->c_context.call_shim_on_c_stack(&ca, (void*)cleanup_task);
task->ctx.next->swap(task->ctx); task->ctx.next->swap(task->ctx);
@ -372,10 +364,12 @@ void task_start_wrapper(spawn_args *a)
void void
rust_task::start(spawn_fn spawnee_fn, rust_task::start(spawn_fn spawnee_fn,
uintptr_t env) rust_boxed_closure *envptr,
void *argptr)
{ {
LOG(this, task, "starting task from fn 0x%" PRIxPTR LOG(this, task, "starting task from fn 0x%" PRIxPTR
" with env 0x%" PRIxPTR, spawnee_fn, env); " with env 0x%" PRIxPTR " and arg 0x%" PRIxPTR,
spawnee_fn, envptr, argptr);
I(sched, stk->data != NULL); I(sched, stk->data != NULL);
@ -386,7 +380,8 @@ rust_task::start(spawn_fn spawnee_fn,
spawn_args *a = (spawn_args *)sp; spawn_args *a = (spawn_args *)sp;
a->task = this; a->task = this;
a->envptr = env; a->envptr = envptr;
a->argptr = argptr;
a->f = spawnee_fn; a->f = spawnee_fn;
ctx.call((void *)task_start_wrapper, a, sp); ctx.call((void *)task_start_wrapper, a, sp);

View file

@ -21,7 +21,17 @@ struct chan_handle {
rust_port_id port; rust_port_id port;
}; };
typedef void (*CDECL spawn_fn)(uintptr_t, uintptr_t); struct rust_closure {
const type_desc *td;
// ... see trans_closure.rs for full description ...
};
struct rust_boxed_closure {
intptr_t ref_count;
rust_closure closure;
};
typedef void (*CDECL spawn_fn)(void*, rust_boxed_closure*, void *);
struct rust_box; struct rust_box;
@ -135,7 +145,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
~rust_task(); ~rust_task();
void start(spawn_fn spawnee_fn, void start(spawn_fn spawnee_fn,
uintptr_t args); rust_boxed_closure *env,
void *args);
void start(); void start();
bool running(); bool running();
bool blocked(); bool blocked();

View file

@ -39,7 +39,7 @@ rust_domain_test::run() {
return true; return true;
} }
void task_entry(uintptr_t retptr, uintptr_t env) { void task_entry(void *, rust_boxed_closure *, void *) {
printf("task entry\n"); printf("task entry\n");
} }
@ -47,7 +47,7 @@ void
rust_task_test::worker::run() { rust_task_test::worker::run() {
rust_task_id root_id = 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); rust_task *root_task = kernel->get_task_by_id(root_id);
root_task->start(&task_entry, (uintptr_t)NULL); root_task->start(&task_entry, NULL, NULL);
root_task->sched->start_main_loop(); root_task->sched->start_main_loop();
} }

View file

@ -11,33 +11,29 @@ fn test_sleep() { task::sleep(1000000u); }
#[test] #[test]
#[ignore(cfg(target_os = "win32"))] #[ignore(cfg(target_os = "win32"))]
fn test_unsupervise() { fn test_unsupervise() {
fn f(&&_i: ()) { task::unsupervise(); fail; } fn f() { task::unsupervise(); fail; }
task::spawn((), f); task::spawn {|| f};
} }
#[test] #[test]
fn test_lib_spawn() { fn test_lib_spawn() {
fn foo(&&_i: ()) { #error("Hello, World!"); } fn foo() { #error("Hello, World!"); }
task::spawn((), foo); task::spawn {|| foo};
} }
#[test] #[test]
fn test_lib_spawn2() { fn test_lib_spawn2() {
fn foo(&&x: int) { assert (x == 42); } fn foo(x: int) { assert (x == 42); }
task::spawn(42, foo); task::spawn {|| foo(42);};
} }
#[test] #[test]
fn test_join_chan() { fn test_join_chan() {
fn winner(&&_i: ()) { } fn winner() { }
let p = comm::port(); let t = task::spawn_joinable {|| winner();};
task::spawn_notify((), winner, comm::chan(p)); alt task::join(t) {
let s = comm::recv(p); task::tr_success. {/* yay! */ }
#error("received task status message");
log(error, s);
alt s {
task::exit(_, task::tr_success.) {/* yay! */ }
_ { fail "invalid task status received" } _ { fail "invalid task status received" }
} }
} }
@ -46,32 +42,18 @@ fn test_join_chan() {
#[test] #[test]
#[ignore(cfg(target_os = "win32"))] #[ignore(cfg(target_os = "win32"))]
fn test_join_chan_fail() { fn test_join_chan_fail() {
fn failer(&&_i: ()) { task::unsupervise(); fail } fn failer() { task::unsupervise(); fail }
let p = comm::port(); let t = task::spawn_joinable {|| failer();};
task::spawn_notify((), failer, comm::chan(p)); alt task::join(t) {
let s = comm::recv(p); task::tr_failure. {/* yay! */ }
#error("received task status message");
log(error, s);
alt s {
task::exit(_, task::tr_failure.) {/* yay! */ }
_ { fail "invalid task status received" } _ { fail "invalid task status received" }
} }
} }
#[test] #[test]
fn test_join_convenient() {
fn winner(&&_i: ()) { }
let handle = task::spawn_joinable((), winner);
assert (task::tr_success == task::join(handle));
}
#[test]
#[ignore]
fn spawn_polymorphic() { fn spawn_polymorphic() {
// FIXME #1038: Can't spawn palymorphic functions fn foo<send T>(x: T) { log(error, x); }
/*fn foo<T: send>(x: T) { log(error, x); } task::spawn {|| foo(true);}
task::spawn {|| foo(42);}
task::spawn(true, foo);
task::spawn(42, foo);*/
} }