about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-10-18 12:27:09 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-10-18 14:51:20 -0700
commitacf2d208d617d88b91c3d3282bf3e5e1a9a51c10 (patch)
tree999434051977cee282d4cb6dd84e2e980dfd2b92
parent754704ea9442ce92602f8022f6c979824b016842 (diff)
downloadrust-acf2d208d617d88b91c3d3282bf3e5e1a9a51c10.tar.gz
rust-acf2d208d617d88b91c3d3282bf3e5e1a9a51c10.zip
core: add previous-handler save and restore for proper nesting.
-rw-r--r--src/libcore/condition.rs94
1 files changed, 78 insertions, 16 deletions
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<T, U: Copy>(&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, U: Copy>(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;
+}