Skip to content

Spawn #398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 21, 2011
Merged
16 changes: 13 additions & 3 deletions src/comp/back/upcall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
[T_ptr(T_crate(tn)), T_size_t(), T_size_t(),
T_size_t(), T_ptr(T_ptr(T_tydesc(tn)))],
T_ptr(T_tydesc(tn))),
new_task=d("new_task", [T_ptr(T_i8())], T_taskptr(tn)),
start_task=d("start_task", [T_taskptr(tn), T_int(), T_int(),
T_int(), T_size_t()],
new_task=d("new_task", [T_ptr(T_str())], T_taskptr(tn)),
start_task=d("start_task", [T_taskptr(tn),
T_int(), T_int(), T_size_t()],
T_taskptr(tn)),
new_thread=d("new_thread", [T_ptr(T_i8())], T_taskptr(tn)),
start_thread=d("start_thread", [T_taskptr(tn), T_int(), T_int(),
Expand All @@ -133,3 +133,13 @@ fn declare_upcalls(type_names tn, ModuleRef llmod) -> @upcalls {
);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
5 changes: 4 additions & 1 deletion src/comp/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1539,7 +1539,10 @@ fn type_to_str_inner(type_names names,
ret s;
}

case (10) { ret "Array"; }
case (10) {
auto el_ty = llvm::LLVMGetElementType(ty);
ret "[" + type_to_str_inner(names, outer, el_ty) + "]";
}

case (11) {
let uint i = 0u;
Expand Down
163 changes: 162 additions & 1 deletion src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5543,6 +5543,10 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
ret trans_recv(cx, lhs, rhs, ann);
}

case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) {
ret trans_spawn(cx, dom, name, func, args, ann);
}

case (_) {
// The expression is an lvalue. Fall through.
}
Expand Down Expand Up @@ -5879,9 +5883,166 @@ fn trans_chan(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
ret res(bcx, chan_val);
}

fn trans_spawn(&@block_ctxt cx,
&ast::spawn_dom dom, &option::t[str] name,
&@ast::expr func, &vec[@ast::expr] args,
&ast::ann ann) -> result {
auto bcx = cx;

// Make the task name
auto tname = alt(name) {
case(none) {
auto argss = vec::map(common::expr_to_str, args);
#fmt("%s(%s)",
common::expr_to_str(func),
str::connect(argss, ", "))
}
case(some[str](?n)) {
n
}
};

// dump a bunch of information
log_err "Translating Spawn " +
"(The compiled program is not actually running yet, don't worry!";
log_err #fmt("task name: %s", tname);

// Generate code
//
// This is a several step process. The following things need to happen
// (not necessarily in order):
//
// 1. Evaluate all the arguments to the spawnee.
//
// 2. Alloca a tuple that holds these arguments (they must be in reverse
// order, so that they match the expected stack layout for the spawnee)
//
// 3. Fill the tuple with the arguments we evaluated.
//
// 4. Pass a pointer to the spawnee function and the argument tuple to
// upcall_start_task.
//
// 5. Oh yeah, we have to create the task before we start it...

// Translate the arguments, remembering their types and where the values
// ended up.
let vec[ty::t] arg_tys = [];
let vec[ValueRef] arg_vals = [];
for(@ast::expr e in args) {
auto arg = trans_expr(bcx, e);

bcx = arg.bcx;

vec::push[ValueRef](arg_vals, arg.val);
vec::push[ty::t](arg_tys,
ty::expr_ty(cx.fcx.lcx.ccx.tcx,
e));
}

// Make the tuple. We have to reverse the types first though.
vec::reverse[ty::t](arg_tys);
vec::reverse[ValueRef](arg_vals);
auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);

// Allocate and fill the tuple.
auto llargs = alloc_ty(bcx, args_ty);

auto i = vec::len[ValueRef](arg_vals) - 1u;
for(ValueRef v in arg_vals) {
// log_err #fmt("ty(llargs) = %s",
// val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
auto target = bcx.build.GEP(llargs.val, [C_int(0), C_int(i as int)]);

// log_err #fmt("ty(v) = %s", val_str(bcx.fcx.lcx.ccx.tn, v));
// log_err #fmt("ty(target) = %s",
// val_str(bcx.fcx.lcx.ccx.tn, target));

bcx.build.Store(v, target);

i -= 1u;
}

// Now we're ready to do the upcall.

// But first, we'll create a task.
let ValueRef lltname = C_str(bcx.fcx.lcx.ccx, tname);
log_err #fmt("ty(new_task) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
bcx.fcx.lcx.ccx.upcalls.new_task));
log_err #fmt("ty(lltaskptr) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
bcx.fcx.lltaskptr));
log_err #fmt("ty(lltname) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
lltname));

log_err "Building upcall_new_task";
auto new_task = bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_task,
[bcx.fcx.lltaskptr, lltname]);
log_err "Done";

// Okay, start the task.
// First we find the function
auto fnptr = trans_lval(bcx, func).res;
bcx = fnptr.bcx;

auto num_args = vec::len[@ast::expr](args);

auto llfnptr = bcx.build.GEP(fnptr.val,
[C_int(0), C_int(0)]);
log_err "Casting llfnptr";
auto llfnptr_i = bcx.build.PointerCast(llfnptr,
T_int());
log_err "Cassting llargs";
auto llargs_i = bcx.build.PointerCast(llargs.val,
T_int());

log_err "Building call to start_task";
log_err #fmt("ty(start_task) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
bcx.fcx.lcx.ccx.upcalls.start_task));
log_err #fmt("ty(lltaskptr) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
bcx.fcx.lltaskptr));
log_err #fmt("ty(new_task) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
new_task));
log_err #fmt("ty(llfnptr) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
llfnptr_i));
log_err #fmt("ty(llargs) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
llargs_i));
log_err #fmt("ty(num_args) = %s",
val_str(bcx.fcx.lcx.ccx.tn,
C_int(num_args as int)));
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
[bcx.fcx.lltaskptr, new_task,
llfnptr_i, llargs_i, C_int(num_args as int)]);
log_err "Done";

/*
alt(dom) {
case(ast::dom_implicit) {
// TODO
log_err "Spawning implicit domain tasks is not implemented.";
//fail;
}

case(ast::dom_thread) {
// TODO
log_err "Spawining new thread tasks is not implemented.";
// TODO: for now use the normal unimpl thing.
fail;
}
}
*/

ret res(bcx, new_task);
}

fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
&ast::ann ann) -> result {

auto bcx = cx;
auto chn = trans_expr(bcx, lhs);
bcx = chn.bcx;
Expand Down
14 changes: 7 additions & 7 deletions src/rt/rust_upcall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,30 +538,30 @@ upcall_get_type_desc(rust_task *task,
}

extern "C" CDECL rust_task *
upcall_new_task(rust_task *spawner, const char *name) {
upcall_new_task(rust_task *spawner, rust_vec *name) {
// name is a rust string structure.
LOG_UPCALL_ENTRY(spawner);
rust_dom *dom = spawner->dom;
rust_task *task = dom->create_task(spawner, name);
rust_task *task = dom->create_task(spawner, (const char *)name->data);
return task;
}

extern "C" CDECL rust_task *
upcall_start_task(rust_task *spawner,
rust_task *task,
uintptr_t exit_task_glue,
uintptr_t spawnee_fn,
uintptr_t args,
size_t callsz) {
LOG_UPCALL_ENTRY(spawner);

rust_dom *dom = spawner->dom;
DLOG(dom, task,
"upcall start_task(task %s @0x%" PRIxPTR
" exit_task_glue 0x%" PRIxPTR
", spawnee 0x%" PRIxPTR
", callsz %" PRIdPTR ")", task->name, task, exit_task_glue,
", callsz %" PRIdPTR ")", task->name, task,
spawnee_fn, callsz);
task->start(exit_task_glue, spawnee_fn,
spawner->rust_sp, callsz);
task->start((uintptr_t)rust_new_exit_task_glue, spawnee_fn,
args, callsz);
return task;
}

Expand Down
14 changes: 14 additions & 0 deletions src/test/run-fail/trivial-message2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
This program should hang on the r <- po line.
*/

fn main() {
let port[int] po = port();
let chan[int] ch = chan(po);

auto r <- po;

ch <| 42;

log_err r;
}
15 changes: 15 additions & 0 deletions src/test/run-pass/trivial-message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
This is about the simplest program that can successfully send a
message.
*/

fn main() {
let port[int] po = port();
let chan[int] ch = chan(po);

ch <| 42;

auto r <- po;

log_err r;
}