Skip to content

Commit bb5db3b

Browse files
committed
Add 2-degree familial relations linked failure tests & fix secondborn behaviour
1 parent d9c9a2f commit bb5db3b

File tree

1 file changed

+62
-10
lines changed

1 file changed

+62
-10
lines changed

src/libcore/task.rs

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export run_with;
4949

5050
export spawn;
5151
export spawn_unlinked;
52+
export spawn_supervised;
5253
export spawn_with;
5354
export spawn_listener;
5455
export spawn_sched;
@@ -728,12 +729,21 @@ unsafe fn taskgroup_key() -> local_data_key<taskgroup> {
728729
unsafe::transmute((-2 as uint, 0u))
729730
}
730731

731-
fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
732+
// The 'linked' arg tells whether or not to also ref the unidirectionally-
733+
// linked supervisors' group. False when the spawn is supervised, not linked.
734+
fn share_spawner_taskgroup(linked: bool)
735+
-> (taskgroup_arc, option<taskgroup_arc>, bool) {
732736
let me = rustrt::rust_get_task();
733737
alt unsafe { local_get(me, taskgroup_key()) } {
734738
some(group) {
739+
// If they are linked to us, they share our parent group.
740+
let parent_arc_opt = if linked {
741+
group.parents.map(|x| alt x { (pg,_) { pg.clone() } })
742+
} else {
743+
none
744+
};
735745
// Clone the shared state for the child; propagate main-ness.
736-
(group.tasks.clone(), group.is_main)
746+
(group.tasks.clone(), parent_arc_opt, group.is_main)
737747
}
738748
none {
739749
// Main task, doing first spawn ever.
@@ -743,26 +753,30 @@ fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
743753
let group = @taskgroup(me, tasks.clone(), 0, none, true);
744754
unsafe { local_set(me, taskgroup_key(), group); }
745755
// Tell child task it's also in the main group.
746-
(tasks, true)
756+
// Whether or not it wanted our parent group, we haven't got one.
757+
(tasks, none, true)
747758
}
748759
}
749760
}
750761

751762
fn spawn_raw(opts: task_opts, +f: fn~()) {
752763
// Decide whether the child needs to be in a new linked failure group.
753-
let ((child_tg, is_main), parent_tg) = if opts.linked {
764+
// This whole conditional should be consolidated with share_spawner above.
765+
let (child_tg, parent_tg, is_main) = if opts.linked {
754766
// It doesn't mean anything for a linked-spawned-task to have a parent
755767
// group. The spawning task is already bidirectionally linked to it.
756-
(share_parent_taskgroup(), none)
768+
share_spawner_taskgroup(true)
757769
} else {
758770
// Detached from the parent group; create a new (non-main) one.
759-
((arc::exclusive(some((dvec::dvec(),dvec::dvec()))), false),
771+
(arc::exclusive(some((dvec::dvec(),dvec::dvec()))),
760772
// Allow the parent to unidirectionally fail the child?
761773
if opts.parented {
762-
let (pg,_) = share_parent_taskgroup(); some(pg)
774+
// Use the spawner's own group as the child's parent group.
775+
let (pg,_,_) = share_spawner_taskgroup(false); some(pg)
763776
} else {
764777
none
765-
})
778+
},
779+
false)
766780
};
767781

768782
unsafe {
@@ -1256,12 +1270,38 @@ fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails
12561270
fail;
12571271
}
12581272

1259-
// A bonus linked failure test
1273+
// A couple bonus linked failure tests - testing for failure propagation even
1274+
// when the middle task exits successfully early before kill signals are sent.
12601275

12611276
#[test] #[should_fail] // #[ignore(cfg(windows))]
12621277
#[ignore] // FIXME (#1868) (bblum) make this work
1263-
fn test_spawn_unlinked_sup_propagate_grandchild() {
1278+
fn test_spawn_failure_propagate_grandchild() {
1279+
// Middle task exits; does grandparent's failure propagate across the gap?
1280+
do spawn_supervised {
1281+
do spawn_supervised {
1282+
loop { task::yield(); }
1283+
}
1284+
}
1285+
for iter::repeat(8192) { task::yield(); }
1286+
fail;
1287+
}
1288+
1289+
#[test] #[should_fail] #[ignore(cfg(windows))]
1290+
fn test_spawn_failure_propagate_secondborn() {
1291+
// First-born child exits; does parent's failure propagate to sibling?
12641292
do spawn_supervised {
1293+
do spawn { // linked
1294+
loop { task::yield(); }
1295+
}
1296+
}
1297+
for iter::repeat(8192) { task::yield(); }
1298+
fail;
1299+
}
1300+
1301+
#[test] #[should_fail] #[ignore(cfg(windows))]
1302+
fn test_spawn_failure_propagate_nephew_or_niece() {
1303+
// Our sibling exits; does our failure propagate to sibling's child?
1304+
do spawn { // linked
12651305
do spawn_supervised {
12661306
loop { task::yield(); }
12671307
}
@@ -1270,6 +1310,18 @@ fn test_spawn_unlinked_sup_propagate_grandchild() {
12701310
fail;
12711311
}
12721312

1313+
#[test] #[should_fail] #[ignore(cfg(windows))]
1314+
fn test_spawn_linked_sup_propagate_sibling() {
1315+
// Middle sibling exits - does eldest's failure propagate to youngest?
1316+
do spawn { // linked
1317+
do spawn { // linked
1318+
loop { task::yield(); }
1319+
}
1320+
}
1321+
for iter::repeat(8192) { task::yield(); }
1322+
fail;
1323+
}
1324+
12731325
#[test]
12741326
#[ignore(cfg(windows))]
12751327
fn test_spawn_raw_notify() {

0 commit comments

Comments
 (0)