about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-27 11:35:51 -0700
committerbors <bors@rust-lang.org>2013-08-27 11:35:51 -0700
commitc822d1070ac39871165df30ac8d09e733a6e7fb9 (patch)
tree10a9f4f2282ba97a33ecde8d45984183608fafb6 /src/libstd
parent7841b77676662ed657da7b8911dd0989ac743ca0 (diff)
parentcc59d9609740bd325a796ba0831af15b87f502ed (diff)
downloadrust-c822d1070ac39871165df30ac8d09e733a6e7fb9.tar.gz
rust-c822d1070ac39871165df30ac8d09e733a6e7fb9.zip
auto merge of #8581 : FlaPer87/rust/issue/8232, r=bblum
As for now, rekillable is an unsafe function, instead, it should behave
just like unkillable by encapsulating unsafe code within an unsafe
block.

This patch does that and removes unsafe blocks that were encapsulating
rekillable calls throughout rust's libs.

Fixes #8232
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rt/kill.rs6
-rw-r--r--src/libstd/task/mod.rs81
2 files changed, 68 insertions, 19 deletions
diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs
index b0b425e3aee..94df621ce76 100644
--- a/src/libstd/rt/kill.rs
+++ b/src/libstd/rt/kill.rs
@@ -647,7 +647,11 @@ impl Death {
     /// All calls must be paired with a preceding call to inhibit_kill.
     #[inline]
     pub fn allow_kill(&mut self, already_failing: bool) {
-        rtassert!(self.unkillable != 0);
+        if self.unkillable == 0 {
+            // we need to decrement the counter before failing.
+            self.unkillable -= 1;
+            fail!("Cannot enter a rekillable() block without a surrounding unkillable()");
+        }
         self.unkillable -= 1;
         if self.unkillable == 0 {
             rtassert!(self.kill_handle.is_some());
diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs
index e76b81a904d..f872c2614b9 100644
--- a/src/libstd/task/mod.rs
+++ b/src/libstd/task/mod.rs
@@ -597,21 +597,36 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
     }
 }
 
-/// The inverse of unkillable. Only ever to be used nested in unkillable().
-pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
+/**
+ * Makes killable a task marked as unkillable. This
+ * is meant to be used only nested in unkillable.
+ *
+ * # Example
+ *
+ * ~~~
+ * do task::unkillable {
+ *     do task::rekillable {
+ *          // Task is killable
+ *     }
+ *    // Task is unkillable again
+ * }
+ */
+pub fn rekillable<U>(f: &fn() -> U) -> U {
     use rt::task::Task;
 
-    if in_green_task_context() {
-        let t = Local::unsafe_borrow::<Task>();
-        do (|| {
-            (*t).death.allow_kill((*t).unwinder.unwinding);
+    unsafe {
+        if in_green_task_context() {
+            let t = Local::unsafe_borrow::<Task>();
+            do (|| {
+                (*t).death.allow_kill((*t).unwinder.unwinding);
+                f()
+            }).finally {
+                (*t).death.inhibit_kill((*t).unwinder.unwinding);
+            }
+        } else {
+            // FIXME(#3095): As in unkillable().
             f()
-        }).finally {
-            (*t).death.inhibit_kill((*t).unwinder.unwinding);
         }
-    } else {
-        // FIXME(#3095): As in unkillable().
-        f()
     }
 }
 
@@ -636,8 +651,8 @@ fn test_kill_unkillable_task() {
     }
 }
 
-#[ignore(reason = "linked failure")]
 #[test]
+#[ignore(cfg(windows))]
 fn test_kill_rekillable_task() {
     use rt::test::*;
 
@@ -646,11 +661,9 @@ fn test_kill_rekillable_task() {
     do run_in_newsched_task {
         do task::try {
             do task::unkillable {
-                unsafe {
-                    do task::rekillable {
-                        do task::spawn {
-                            fail!();
-                        }
+                do task::rekillable {
+                    do task::spawn {
+                        fail!();
                     }
                 }
             }
@@ -658,7 +671,39 @@ fn test_kill_rekillable_task() {
     }
 }
 
-#[test] #[should_fail]
+#[test]
+#[should_fail]
+#[ignore(cfg(windows))]
+fn test_rekillable_not_nested() {
+    do rekillable {
+        // This should fail before
+        // receiving anything since
+        // this block should be nested
+        // into a unkillable block.
+        deschedule();
+    }
+}
+
+
+#[test]
+#[ignore(cfg(windows))]
+fn test_rekillable_nested_failure() {
+
+    let result = do task::try {
+        do unkillable {
+            do rekillable {
+                let (port,chan) = comm::stream();
+                do task::spawn { chan.send(()); fail!(); }
+                port.recv(); // wait for child to exist
+                port.recv(); // block forever, expect to get killed.
+            }
+        }
+    };
+    assert!(result.is_err());
+}
+
+
+#[test] #[should_fail] #[ignore(cfg(windows))]
 fn test_cant_dup_task_builder() {
     let mut builder = task();
     builder.unlinked();