@@ -49,6 +49,7 @@ export run_with;
49
49
50
50
export spawn;
51
51
export spawn_unlinked;
52
+ export spawn_supervised;
52
53
export spawn_with;
53
54
export spawn_listener;
54
55
export spawn_sched;
@@ -728,12 +729,21 @@ unsafe fn taskgroup_key() -> local_data_key<taskgroup> {
728
729
unsafe :: transmute ( ( -2 as uint , 0 u) )
729
730
}
730
731
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 ) {
732
736
let me = rustrt:: rust_get_task ( ) ;
733
737
alt unsafe { local_get ( me, taskgroup_key ( ) ) } {
734
738
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
+ } ;
735
745
// 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 )
737
747
}
738
748
none {
739
749
// Main task, doing first spawn ever.
@@ -743,26 +753,30 @@ fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
743
753
let group = @taskgroup ( me, tasks. clone ( ) , 0 , none, true ) ;
744
754
unsafe { local_set ( me, taskgroup_key ( ) , group) ; }
745
755
// 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 )
747
758
}
748
759
}
749
760
}
750
761
751
762
fn spawn_raw ( opts : task_opts , +f : fn ~( ) ) {
752
763
// 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 {
754
766
// It doesn't mean anything for a linked-spawned-task to have a parent
755
767
// group. The spawning task is already bidirectionally linked to it.
756
- ( share_parent_taskgroup ( ) , none )
768
+ share_spawner_taskgroup ( true )
757
769
} else {
758
770
// 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 ( ) ) ) ) ,
760
772
// Allow the parent to unidirectionally fail the child?
761
773
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)
763
776
} else {
764
777
none
765
- } )
778
+ } ,
779
+ false )
766
780
} ;
767
781
768
782
unsafe {
@@ -1256,12 +1270,38 @@ fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails
1256
1270
fail;
1257
1271
}
1258
1272
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.
1260
1275
1261
1276
#[ test] #[ should_fail] // #[ignore(cfg(windows))]
1262
1277
#[ 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?
1264
1292
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
1265
1305
do spawn_supervised {
1266
1306
loop { task:: yield ( ) ; }
1267
1307
}
@@ -1270,6 +1310,18 @@ fn test_spawn_unlinked_sup_propagate_grandchild() {
1270
1310
fail;
1271
1311
}
1272
1312
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
+
1273
1325
#[ test]
1274
1326
#[ ignore( cfg( windows) ) ]
1275
1327
fn test_spawn_raw_notify ( ) {
0 commit comments