Generate try_send versions for all the messages. Fixes #3128

This commit is contained in:
Eric Holk 2012-08-07 11:46:52 -07:00
parent 672bfa5773
commit abf4421e7c
3 changed files with 127 additions and 83 deletions

View File

@ -337,7 +337,7 @@ struct buffer_resource<T: send> {
#[doc(hidden)]
fn send<T: send, Tbuffer: send>(-p: send_packet_buffered<T, Tbuffer>,
-payload: T) {
-payload: T) -> bool {
let header = p.header();
let p_ = p.unwrap();
let p = unsafe { &*p_ };
@ -346,29 +346,32 @@ fn send<T: send, Tbuffer: send>(-p: send_packet_buffered<T, Tbuffer>,
p.payload <- some(payload);
let old_state = swap_state_rel(p.header.state, full);
match old_state {
empty => {
// Yay, fastpath.
empty => {
// Yay, fastpath.
// The receiver will eventually clean this up.
//unsafe { forget(p); }
}
full => fail ~"duplicate send",
blocked => {
debug!{"waking up task for %?", p_};
let old_task = swap_task(p.header.blocked_task, ptr::null());
if !old_task.is_null() {
rustrt::task_signal_event(
old_task, ptr::addr_of(p.header) as *libc::c_void);
rustrt::rust_task_deref(old_task);
// The receiver will eventually clean this up.
//unsafe { forget(p); }
return true;
}
full => fail ~"duplicate send",
blocked => {
debug!{"waking up task for %?", p_};
let old_task = swap_task(p.header.blocked_task, ptr::null());
if !old_task.is_null() {
rustrt::task_signal_event(
old_task, ptr::addr_of(p.header) as *libc::c_void);
rustrt::rust_task_deref(old_task);
}
// The receiver will eventually clean this up.
//unsafe { forget(p); }
}
terminated => {
// The receiver will never receive this. Rely on drop_glue
// to clean everything up.
}
// The receiver will eventually clean this up.
//unsafe { forget(p); }
return true;
}
terminated => {
// The receiver will never receive this. Rely on drop_glue
// to clean everything up.
return false;
}
}
}

View File

@ -15,8 +15,8 @@ mod syntax {
export parse;
}
fn ident(s: ~str) -> ast::ident {
@(copy s)
fn ident(s: &str) -> ast::ident {
@(s.to_unique())
}
fn path(id: ident, span: span) -> @ast::path {
@ -86,9 +86,15 @@ trait ext_ctxt_ast_builder {
fn stmt_expr(e: @ast::expr) -> @ast::stmt;
fn block_expr(b: ast::blk) -> @ast::expr;
fn empty_span() -> span;
fn ty_option(ty: @ast::ty) -> @ast::ty;
}
impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
fn ty_option(ty: @ast::ty) -> @ast::ty {
self.ty_path_ast_builder(path(@~"option", self.empty_span())
.add_ty(ty))
}
fn empty_span() -> span {
{lo: 0, hi: 0, expn_info: self.backtrace()}
}

View File

@ -31,7 +31,7 @@ mod syntax {
}
trait gen_send {
fn gen_send(cx: ext_ctxt) -> @ast::item;
fn gen_send(cx: ext_ctxt, try: bool) -> @ast::item;
}
trait to_type_decls {
@ -45,12 +45,12 @@ trait gen_init {
}
impl compile of gen_send for message {
fn gen_send(cx: ext_ctxt) -> @ast::item {
fn gen_send(cx: ext_ctxt, try: bool) -> @ast::item {
debug!{"pipec: gen_send"};
match self {
message(id, span, tys, this,
some({state: next, tys: next_tys})) => {
debug!{"pipec: next state exists"};
debug!("pipec: next state exists");
let next = this.proto.get_state(next);
assert next_tys.len() == next.ty_params.len();
let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
@ -79,85 +79,119 @@ impl compile of gen_send for message {
};
body += ~"let b = pipe.reuse_buffer();\n";
body += fmt!{"let %s = pipes::send_packet_buffered(\
body += fmt!("let %s = pipes::send_packet_buffered(\
ptr::addr_of(b.buffer.data.%s));\n",
sp, *next.name};
body += fmt!{"let %s = pipes::recv_packet_buffered(\
sp, *next.name);
body += fmt!("let %s = pipes::recv_packet_buffered(\
ptr::addr_of(b.buffer.data.%s));\n",
rp, *next.name};
rp, *next.name);
}
else {
let pat = match (this.dir, next.dir) {
(send, send) => ~"(c, s)",
(send, recv) => ~"(s, c)",
(recv, send) => ~"(s, c)",
(recv, recv) => ~"(c, s)"
(send, send) => "(c, s)",
(send, recv) => "(s, c)",
(recv, send) => "(s, c)",
(recv, recv) => "(c, s)"
};
body += fmt!{"let %s = pipes::entangle();\n", pat};
body += fmt!("let %s = pipes::entangle();\n", pat);
}
body += fmt!{"let message = %s::%s(%s);\n",
body += fmt!("let message = %s::%s(%s);\n",
*this.proto.name,
*self.name(),
str::connect(vec::append_one(arg_names, @~"s")
.map(|x| *x),
~", ")};
body += fmt!{"pipes::send(pipe, message);\n"};
// return the new channel
body += ~"c }";
~", "));
let body = cx.parse_expr(body);
cx.item_fn_poly(self.name(),
args_ast,
cx.ty_path_ast_builder(path(next.data_name(),
span)
.add_tys(next_tys)),
self.get_params(),
cx.expr_block(body))
}
message(id, span, tys, this, none) => {
debug!{"pipec: no next state"};
let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
let args_ast = (arg_names, tys).map(
|n, t| cx.arg_mode(n, t, ast::by_copy)
);
let args_ast = vec::append(
~[cx.arg_mode(@~"pipe",
cx.ty_path_ast_builder(path(this.data_name(),
span)
.add_tys(cx.ty_vars(this.ty_params))),
ast::by_copy)],
args_ast);
let message_args = if arg_names.len() == 0 {
~""
if !try {
body += fmt!{"pipes::send(pipe, message);\n"};
// return the new channel
body += ~"c }";
}
else {
~"(" + str::connect(arg_names.map(|x| *x), ~", ") + ~")"
};
let mut body = ~"{ ";
body += fmt!{"let message = %s::%s%s;\n",
*this.proto.name,
*self.name(),
message_args};
body += fmt!{"pipes::send(pipe, message);\n"};
body += ~" }";
body += fmt!("if pipes::send(pipe, message) {\n \
some(c) \
} else { none } }");
}
let body = cx.parse_expr(body);
cx.item_fn_poly(self.name(),
let mut rty = cx.ty_path_ast_builder(path(next.data_name(),
span)
.add_tys(next_tys));
if try {
rty = cx.ty_option(rty);
}
let name = if try {
@(~"try_" + *self.name())
}
else { self.name() };
cx.item_fn_poly(name,
args_ast,
cx.ty_nil_ast_builder(),
rty,
self.get_params(),
cx.expr_block(body))
}
message(id, span, tys, this, none) => {
debug!{"pipec: no next state"};
let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
let args_ast = (arg_names, tys).map(
|n, t| cx.arg_mode(n, t, ast::by_copy)
);
let args_ast = vec::append(
~[cx.arg_mode(@~"pipe",
cx.ty_path_ast_builder(
path(this.data_name(), span)
.add_tys(cx.ty_vars(this.ty_params))),
ast::by_copy)],
args_ast);
let message_args = if arg_names.len() == 0 {
~""
}
else {
~"(" + str::connect(arg_names.map(|x| *x), ~", ") + ~")"
};
let mut body = ~"{ ";
body += fmt!{"let message = %s::%s%s;\n",
*this.proto.name,
*self.name(),
message_args};
if !try {
body += fmt!{"pipes::send(pipe, message);\n"};
body += ~" }";
} else {
body += fmt!("if pipes::send(pipe, message) { \
some(()) \
} else { none } }");
}
let body = cx.parse_expr(body);
let name = if try {
@(~"try_" + *self.name())
}
else { self.name() };
cx.item_fn_poly(name,
args_ast,
if try {
cx.ty_option(cx.ty_nil_ast_builder())
} else {
cx.ty_nil_ast_builder()
},
self.get_params(),
cx.expr_block(body))
}
}
}
}
fn to_ty(cx: ext_ctxt) -> @ast::ty {
cx.ty_path_ast_builder(path(self.name(), self.span())
@ -215,7 +249,8 @@ impl compile of to_type_decls for state {
let mut items = ~[];
for self.messages.each |m| {
if dir == send {
vec::push(items, m.gen_send(cx))
vec::push(items, m.gen_send(cx, true));
vec::push(items, m.gen_send(cx, false));
}
}