core: add previous-handler save and restore for proper nesting.
This commit is contained in:
parent
754704ea94
commit
acf2d208d6
|
@ -6,9 +6,8 @@ struct Condition {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Handler {
|
struct Handler {
|
||||||
// Handler should link to previous handler and
|
handle: RustClosure,
|
||||||
// reinstall it when popped.
|
prev: Option<@Handler>
|
||||||
handle: RustClosure
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +20,17 @@ struct PopHandler {
|
||||||
cond: &Condition,
|
cond: &Condition,
|
||||||
drop {
|
drop {
|
||||||
unsafe {
|
unsafe {
|
||||||
task::local_data::local_data_pop(self.cond.key);
|
debug!("PopHandler: popping handler from TLS");
|
||||||
|
match task::local_data::local_data_pop(self.cond.key) {
|
||||||
|
None => (),
|
||||||
|
Some(h) => {
|
||||||
|
match h.prev {
|
||||||
|
None => (),
|
||||||
|
Some(p) =>
|
||||||
|
task::local_data::local_data_set(self.cond.key, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,13 +40,16 @@ struct HandleBlock {
|
||||||
handler: @Handler,
|
handler: @Handler,
|
||||||
drop {
|
drop {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
debug!("HandleBlock: pushing handler to TLS");
|
||||||
task::local_data::local_data_set(self.pb.cond.key,
|
task::local_data::local_data_set(self.pb.cond.key,
|
||||||
self.handler);
|
self.handler);
|
||||||
let _pop = PopHandler { cond: self.pb.cond };
|
let _pop = PopHandler { cond: self.pb.cond };
|
||||||
// transmutation to avoid copying non-copyable, should
|
// transmutation to avoid copying non-copyable, should
|
||||||
// be fixable by tracking closure pointees in regionck.
|
// be fixable by tracking closure pointees in regionck.
|
||||||
let f : &fn() = ::cast::transmute(self.pb.inner);
|
let f : &fn() = ::cast::transmute(self.pb.inner);
|
||||||
|
debug!("HandleBlock: invoking protected code");
|
||||||
f();
|
f();
|
||||||
|
debug!("HandleBlock: returned from protected code");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,9 +57,11 @@ struct HandleBlock {
|
||||||
impl ProtectBlock {
|
impl ProtectBlock {
|
||||||
fn handle<T, U: Copy>(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self {
|
fn handle<T, U: Copy>(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
debug!("ProtectBlock.handle: setting up handler block");
|
||||||
let p : *RustClosure = ::cast::transmute(&h);
|
let p : *RustClosure = ::cast::transmute(&h);
|
||||||
|
let prev = task::local_data::local_data_get(self.cond.key);
|
||||||
HandleBlock { pb: self,
|
HandleBlock { pb: self,
|
||||||
handler: @Handler{handle: *p} }
|
handler: @Handler{handle: *p, prev: prev} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,17 +73,23 @@ impl Condition {
|
||||||
unsafe {
|
unsafe {
|
||||||
// transmutation to avoid copying non-copyable, should
|
// transmutation to avoid copying non-copyable, should
|
||||||
// be fixable by tracking closure pointees in regionck.
|
// be fixable by tracking closure pointees in regionck.
|
||||||
|
debug!("Condition.protect: setting up protected block");
|
||||||
let p : *RustClosure = ::cast::transmute(&inner);
|
let p : *RustClosure = ::cast::transmute(&inner);
|
||||||
ProtectBlock { cond: self,
|
ProtectBlock { cond: self,
|
||||||
inner: *p } }
|
inner: *p }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raise<T, U: Copy>(t:&T) -> U {
|
fn raise<T, U: Copy>(t:&T) -> U {
|
||||||
unsafe {
|
unsafe {
|
||||||
match task::local_data::local_data_get(self.key) {
|
match task::local_data::local_data_get(self.key) {
|
||||||
None => fail,
|
None => {
|
||||||
|
debug!("Condition.raise: found no handler");
|
||||||
|
fail
|
||||||
|
}
|
||||||
|
|
||||||
Some(handler) => {
|
Some(handler) => {
|
||||||
io::println("got handler");
|
debug!("Condition.raise: found handler");
|
||||||
let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
|
let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
|
||||||
f(t)
|
f(t)
|
||||||
}
|
}
|
||||||
|
@ -79,39 +99,81 @@ impl Condition {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn happiness_key(_x: @Handler) { }
|
fn happiness_key(_x: @Handler) { }
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn sadness_key(_x: @Handler) { }
|
fn sadness_key(_x: @Handler) { }
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn trouble(i: int) {
|
fn trouble(i: int) {
|
||||||
// Condition should work as a const, just limitations in consts.
|
// Condition should work as a const, just limitations in consts.
|
||||||
let sadness_condition : Condition = Condition { key: sadness_key };
|
let sadness_condition : Condition = Condition { key: sadness_key };
|
||||||
io::println("raising");
|
debug!("trouble: raising conition");
|
||||||
let j = sadness_condition.raise(&i);
|
let j = sadness_condition.raise(&i);
|
||||||
io::println(fmt!("handler recovered with %d", j));
|
debug!("trouble: handler recovered with %d", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test1() {
|
||||||
|
|
||||||
let sadness_condition : Condition = Condition { key: sadness_key };
|
let sadness_condition : Condition = Condition { key: sadness_key };
|
||||||
|
|
||||||
let mut i = 10;
|
let mut i = 10;
|
||||||
|
|
||||||
let b = do sadness_condition.protect {
|
let b = do sadness_condition.protect {
|
||||||
io::println("in protected block");
|
debug!("test1: in protected block");
|
||||||
trouble(1);
|
trouble(1);
|
||||||
trouble(2);
|
trouble(2);
|
||||||
trouble(3);
|
trouble(3);
|
||||||
};
|
};
|
||||||
|
|
||||||
do b.handle |j| {
|
do b.handle |j| {
|
||||||
|
debug!("test1: in handler");
|
||||||
i += *j;
|
i += *j;
|
||||||
i
|
i
|
||||||
};
|
};
|
||||||
|
|
||||||
assert i == 16;
|
assert i == 16;
|
||||||
}
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
fn nested_test_inner() {
|
||||||
|
let sadness_condition : Condition = Condition { key: sadness_key };
|
||||||
|
|
||||||
|
let mut inner_trapped = false;
|
||||||
|
|
||||||
|
let b = do sadness_condition.protect {
|
||||||
|
debug!("nested_test_inner: in protected block");
|
||||||
|
trouble(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
do b.handle |_j:&int| {
|
||||||
|
debug!("nested_test_inner: in handler");
|
||||||
|
inner_trapped = true;
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
assert inner_trapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_test_outer() {
|
||||||
|
|
||||||
|
let sadness_condition : Condition = Condition { key: sadness_key };
|
||||||
|
|
||||||
|
let mut outer_trapped = false;
|
||||||
|
|
||||||
|
let b = do sadness_condition.protect {
|
||||||
|
debug!("nested_test_outer: in protected block");
|
||||||
|
nested_test_inner();
|
||||||
|
trouble(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
do b.handle |_j:&int| {
|
||||||
|
debug!("nested_test_outer: in handler");
|
||||||
|
outer_trapped = true;
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
assert outer_trapped;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue