diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index 5f61f2cd53b..b82f60a9c77 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -6,9 +6,8 @@ struct Condition { } struct Handler { - // Handler should link to previous handler and - // reinstall it when popped. - handle: RustClosure + handle: RustClosure, + prev: Option<@Handler> } @@ -21,7 +20,17 @@ struct PopHandler { cond: &Condition, drop { 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, drop { unsafe { + debug!("HandleBlock: pushing handler to TLS"); task::local_data::local_data_set(self.pb.cond.key, self.handler); let _pop = PopHandler { cond: self.pb.cond }; // transmutation to avoid copying non-copyable, should // be fixable by tracking closure pointees in regionck. let f : &fn() = ::cast::transmute(self.pb.inner); + debug!("HandleBlock: invoking protected code"); f(); + debug!("HandleBlock: returned from protected code"); } } } @@ -45,9 +57,11 @@ struct HandleBlock { impl ProtectBlock { fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self { unsafe { + debug!("ProtectBlock.handle: setting up handler block"); let p : *RustClosure = ::cast::transmute(&h); + let prev = task::local_data::local_data_get(self.cond.key); HandleBlock { pb: self, - handler: @Handler{handle: *p} } + handler: @Handler{handle: *p, prev: prev} } } } } @@ -59,17 +73,23 @@ impl Condition { unsafe { // transmutation to avoid copying non-copyable, should // be fixable by tracking closure pointees in regionck. + debug!("Condition.protect: setting up protected block"); let p : *RustClosure = ::cast::transmute(&inner); ProtectBlock { cond: self, - inner: *p } } + inner: *p } + } } fn raise(t:&T) -> U { unsafe { match task::local_data::local_data_get(self.key) { - None => fail, + None => { + debug!("Condition.raise: found no handler"); + fail + } + Some(handler) => { - io::println("got handler"); + debug!("Condition.raise: found handler"); let f : &fn(&T) -> U = ::cast::transmute(handler.handle); f(t) } @@ -79,39 +99,81 @@ impl Condition { } -#[test] +#[cfg(test)] fn happiness_key(_x: @Handler) { } -#[test] +#[cfg(test)] fn sadness_key(_x: @Handler) { } -#[test] +#[cfg(test)] fn trouble(i: int) { // Condition should work as a const, just limitations in consts. let sadness_condition : Condition = Condition { key: sadness_key }; - io::println("raising"); + debug!("trouble: raising conition"); let j = sadness_condition.raise(&i); - io::println(fmt!("handler recovered with %d", j)); + debug!("trouble: handler recovered with %d", j); } #[test] -fn test() { +fn test1() { let sadness_condition : Condition = Condition { key: sadness_key }; let mut i = 10; let b = do sadness_condition.protect { - io::println("in protected block"); + debug!("test1: in protected block"); trouble(1); trouble(2); trouble(3); }; do b.handle |j| { + debug!("test1: in handler"); i += *j; i }; assert i == 16; -} \ No newline at end of file +} +#[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; +}