summary refs log tree commit diff
path: root/src/libcore/task.rs
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2012-07-24 20:18:11 -0400
committerBen Blum <bblum@andrew.cmu.edu>2012-07-24 20:21:20 -0400
commitbb5db3bc8a4087c29ff37376edb2a3c01200f65d (patch)
treee4714cc135ae9289b5edd9ffdce8b918fb39deee /src/libcore/task.rs
parentd9c9a2f97e73513030916f646adaed21e0503a4a (diff)
downloadrust-bb5db3bc8a4087c29ff37376edb2a3c01200f65d.tar.gz
rust-bb5db3bc8a4087c29ff37376edb2a3c01200f65d.zip
Add 2-degree familial relations linked failure tests & fix secondborn behaviour
Diffstat (limited to 'src/libcore/task.rs')
-rw-r--r--src/libcore/task.rs72
1 files changed, 62 insertions, 10 deletions
diff --git a/src/libcore/task.rs b/src/libcore/task.rs
index 8af62280656..f09f2fa7f69 100644
--- a/src/libcore/task.rs
+++ b/src/libcore/task.rs
@@ -49,6 +49,7 @@ export run_with;
 
 export spawn;
 export spawn_unlinked;
+export spawn_supervised;
 export spawn_with;
 export spawn_listener;
 export spawn_sched;
@@ -728,12 +729,21 @@ unsafe fn taskgroup_key() -> local_data_key<taskgroup> {
     unsafe::transmute((-2 as uint, 0u))
 }
 
-fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
+// The 'linked' arg tells whether or not to also ref the unidirectionally-
+// linked supervisors' group. False when the spawn is supervised, not linked.
+fn share_spawner_taskgroup(linked: bool)
+        -> (taskgroup_arc, option<taskgroup_arc>, bool) {
     let me = rustrt::rust_get_task();
     alt unsafe { local_get(me, taskgroup_key()) } {
         some(group) {
+            // If they are linked to us, they share our parent group.
+            let parent_arc_opt = if linked {
+                group.parents.map(|x| alt x { (pg,_) { pg.clone() } })
+            } else {
+                none
+            };
             // Clone the shared state for the child; propagate main-ness.
-            (group.tasks.clone(), group.is_main)
+            (group.tasks.clone(), parent_arc_opt, group.is_main)
         }
         none {
             // Main task, doing first spawn ever.
@@ -743,26 +753,30 @@ fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
             let group = @taskgroup(me, tasks.clone(), 0, none, true);
             unsafe { local_set(me, taskgroup_key(), group); }
             // Tell child task it's also in the main group.
-            (tasks, true)
+            // Whether or not it wanted our parent group, we haven't got one.
+            (tasks, none, true)
         }
     }
 }
 
 fn spawn_raw(opts: task_opts, +f: fn~()) {
     // Decide whether the child needs to be in a new linked failure group.
-    let ((child_tg, is_main), parent_tg) = if opts.linked {
+    // This whole conditional should be consolidated with share_spawner above.
+    let (child_tg, parent_tg, is_main) = if opts.linked {
         // It doesn't mean anything for a linked-spawned-task to have a parent
         // group. The spawning task is already bidirectionally linked to it.
-        (share_parent_taskgroup(), none)
+        share_spawner_taskgroup(true)
     } else {
         // Detached from the parent group; create a new (non-main) one.
-        ((arc::exclusive(some((dvec::dvec(),dvec::dvec()))), false),
+        (arc::exclusive(some((dvec::dvec(),dvec::dvec()))),
          // Allow the parent to unidirectionally fail the child?
          if opts.parented {
-             let (pg,_) = share_parent_taskgroup(); some(pg)
+             // Use the spawner's own group as the child's parent group.
+             let (pg,_,_) = share_spawner_taskgroup(false); some(pg)
          } else {
              none
-         })
+         },
+         false)
     };
 
     unsafe {
@@ -1256,12 +1270,38 @@ fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails
     fail;
 }
 
-// A bonus linked failure test
+// A couple bonus linked failure tests - testing for failure propagation even
+// when the middle task exits successfully early before kill signals are sent.
 
 #[test] #[should_fail] // #[ignore(cfg(windows))]
 #[ignore] // FIXME (#1868) (bblum) make this work
-fn test_spawn_unlinked_sup_propagate_grandchild() {
+fn test_spawn_failure_propagate_grandchild() {
+    // Middle task exits; does grandparent's failure propagate across the gap?
+    do spawn_supervised {
+        do spawn_supervised {
+            loop { task::yield(); }
+        }
+    }
+    for iter::repeat(8192) { task::yield(); }
+    fail;
+}
+
+#[test] #[should_fail] #[ignore(cfg(windows))]
+fn test_spawn_failure_propagate_secondborn() {
+    // First-born child exits; does parent's failure propagate to sibling?
     do spawn_supervised {
+        do spawn { // linked
+            loop { task::yield(); }
+        }
+    }
+    for iter::repeat(8192) { task::yield(); }
+    fail;
+}
+
+#[test] #[should_fail] #[ignore(cfg(windows))]
+fn test_spawn_failure_propagate_nephew_or_niece() {
+    // Our sibling exits; does our failure propagate to sibling's child?
+    do spawn { // linked
         do spawn_supervised {
             loop { task::yield(); }
         }
@@ -1270,6 +1310,18 @@ fn test_spawn_unlinked_sup_propagate_grandchild() {
     fail;
 }
 
+#[test] #[should_fail] #[ignore(cfg(windows))]
+fn test_spawn_linked_sup_propagate_sibling() {
+    // Middle sibling exits - does eldest's failure propagate to youngest?
+    do spawn { // linked
+        do spawn { // linked
+            loop { task::yield(); }
+        }
+    }
+    for iter::repeat(8192) { task::yield(); }
+    fail;
+}
+
 #[test]
 #[ignore(cfg(windows))]
 fn test_spawn_raw_notify() {