@@ -185,13 +185,12 @@ type task_opts = {
185
185
// when you try to reuse the builder to spawn a new task. We'll just
186
186
// sidestep that whole issue by making builders uncopyable and making
187
187
// the run function move them in.
188
- class dummy { let x: ( ) ; new ( ) { self . x = ( ) ; } drop { } }
189
188
190
189
// FIXME (#2585): Replace the 'consumed' bit with move mode on self
191
190
enum task_builder = {
192
191
opts: task_opts,
193
192
gen_body: fn @( +fn ~( ) ) -> fn ~( ) ,
194
- can_not_copy : option < dummy > ,
193
+ can_not_copy : option < util :: noncopyable > ,
195
194
mut consumed: bool ,
196
195
} ;
197
196
@@ -598,8 +597,8 @@ unsafe fn atomically<U>(f: fn() -> U) -> U {
598
597
*
599
598
* A new one of these is created each spawn_linked or spawn_supervised.
600
599
*
601
- * (2) The "taskgroup " is a per-task control structure that tracks a task's
602
- * spawn configuration. It contains a reference to its taskgroup_arc,
600
+ * (2) The "tcb " is a per-task control structure that tracks a task's spawn
601
+ * configuration. It contains a reference to its taskgroup_arc, a
603
602
* a reference to its node in the ancestor list (below), a flag for
604
603
* whether it's part of the 'main'/'root' taskgroup, and an optionally
605
604
* configured notification port. These are stored in TLS.
@@ -641,8 +640,8 @@ unsafe fn atomically<U>(f: fn() -> U) -> U {
641
640
* ( E )- - - - - - - > | {E} {} |
642
641
* \___/ |_________|
643
642
*
644
- * "taskgroup" "taskgroup_arc"
645
- * "ancestor_list"
643
+ * "tcb" "taskgroup_arc"
644
+ * "ancestor_list"
646
645
*
647
646
****************************************************************************/
648
647
@@ -694,6 +693,7 @@ type taskgroup_arc = arc::exclusive<option<taskgroup_data>>;
694
693
695
694
type taskgroup_inner = & mut option < taskgroup_data > ;
696
695
696
+ // A taskgroup is 'dead' when nothing can cause it to fail; only members can.
697
697
fn taskgroup_is_dead ( tg : taskgroup_data ) -> bool {
698
698
( & mut tg. members ) . is_empty ( )
699
699
}
@@ -705,7 +705,7 @@ fn taskgroup_is_dead(tg: taskgroup_data) -> bool {
705
705
// taskgroup which was spawned-unlinked. Tasks from intermediate generations
706
706
// have references to the middle of the list; when intermediate generations
707
707
// die, their node in the list will be collected at a descendant's spawn-time.
708
- enum ancestor_list = option<arc : : exclusive< {
708
+ type ancestor_node = {
709
709
// Since the ancestor list is recursive, we end up with references to
710
710
// exclusives within other exclusives. This is dangerous business (if
711
711
// circular references arise, deadlock and memory leaks are imminent).
@@ -717,7 +717,19 @@ enum ancestor_list = option<arc::exclusive<{
717
717
mut parent_group : option < taskgroup_arc > ,
718
718
// Recursive rest of the list.
719
719
mut ancestors : ancestor_list ,
720
- } >>;
720
+ } ;
721
+ enum ancestor_list = option< arc : : exclusive < ancestor_node > > ;
722
+
723
+ // Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety.
724
+ #[ inline( always) ]
725
+ fn access_group < U > ( x : taskgroup_arc , blk : fn ( taskgroup_inner ) -> U ) -> U {
726
+ unsafe { x. with ( |_c, tg| blk ( tg) ) }
727
+ }
728
+ #[ inline( always) ]
729
+ fn access_ancestors < U > ( x : arc:: exclusive < ancestor_node > ,
730
+ blk : fn ( x : & mut ancestor_node ) -> U ) -> U {
731
+ unsafe { x. with ( |_c, nobe| blk ( nobe) ) }
732
+ }
721
733
722
734
// Iterates over an ancestor list.
723
735
// (1) Runs forward_blk on each ancestral taskgroup in the list
@@ -782,7 +794,7 @@ fn each_ancestor(list: &mut ancestor_list,
782
794
// the end of the list, which doesn't make sense to coalesce.
783
795
return do ( * ancestors) . map_default ( ( none, false ) ) |ancestor_arc| {
784
796
// NB: Takes a lock! (this ancestor node)
785
- do ancestor_arc. with |_c , nobe| {
797
+ do access_ancestors ( ancestor_arc) | nobe| {
786
798
// Check monotonicity
787
799
assert last_generation > nobe. generation ;
788
800
/*##########################################################*
@@ -847,15 +859,15 @@ fn each_ancestor(list: &mut ancestor_list,
847
859
// If this trips, more likely the problem is 'blk' failed inside.
848
860
assert tmp. is_some ( ) ;
849
861
let tmp_arc = option:: unwrap ( tmp) ;
850
- let result = do tmp_arc. with |_c , tg_opt| { blk ( tg_opt) } ;
862
+ let result = do access_group ( tmp_arc) | tg_opt| { blk ( tg_opt) } ;
851
863
* parent_group <- some ( tmp_arc) ;
852
864
result
853
865
}
854
866
}
855
867
}
856
868
857
869
// One of these per task.
858
- class taskgroup {
870
+ class tcb {
859
871
let me: * rust_task;
860
872
// List of tasks with whose fates this one's is intertwined.
861
873
let tasks: taskgroup_arc ; // 'none' means the group has failed.
@@ -878,12 +890,12 @@ class taskgroup {
878
890
if rustrt:: rust_task_is_unwinding ( self . me ) {
879
891
self . notifier . iter ( |x| { x. failed = true ; } ) ;
880
892
// Take everybody down with us.
881
- do self. tasks . with |_c , tg| {
893
+ do access_group ( self . tasks ) | tg| {
882
894
kill_taskgroup ( tg, self . me , self . is_main ) ;
883
895
}
884
896
} else {
885
897
// Remove ourselves from the group(s).
886
- do self. tasks . with |_c , tg| {
898
+ do access_group ( self . tasks ) | tg| {
887
899
leave_taskgroup ( tg, self . me , true ) ;
888
900
}
889
901
}
@@ -977,7 +989,7 @@ fn kill_taskgroup(state: taskgroup_inner, me: *rust_task, is_main: bool) {
977
989
978
990
// FIXME (#2912): Work around core-vs-coretest function duplication. Can't use
979
991
// a proper closure because the #[test]s won't understand. Have to fake it.
980
- unsafe fn taskgroup_key ( ) -> local_data_key < taskgroup > {
992
+ unsafe fn taskgroup_key ( ) -> local_data_key < tcb > {
981
993
// Use a "code pointer" value that will never be a real code pointer.
982
994
unsafe :: transmute ( ( -2 as uint , 0 u) )
983
995
}
@@ -998,13 +1010,12 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
998
1010
mut descendants: new_taskset ( ) } ) ) ;
999
1011
// Main task/group has no ancestors, no notifier, etc.
1000
1012
let group =
1001
- @taskgroup ( spawner, tasks, ancestor_list ( none) , true , none) ;
1013
+ @tcb ( spawner, tasks, ancestor_list ( none) , true , none) ;
1002
1014
unsafe { local_set ( spawner, taskgroup_key ( ) , group) ; }
1003
1015
group
1004
1016
}
1005
1017
some ( group) { group }
1006
1018
} ;
1007
- //for each_ancestor(&mut spawner_group.ancestors, none) |_a| { };
1008
1019
/*######################################################################*
1009
1020
* Step 2. Process spawn options for child.
1010
1021
*######################################################################*/
@@ -1027,7 +1038,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
1027
1038
// it should be enabled only in debug builds.
1028
1039
let new_generation =
1029
1040
alt * old_ancestors {
1030
- some( arc) { do arc. with |_c , nobe| { nobe . generation +1 } }
1041
+ some( arc) { access_ancestors ( arc, |a| a . generation +1 ) }
1031
1042
none { 0 } // the actual value doesn't really matter.
1032
1043
} ;
1033
1044
assert new_generation < uint:: max_value;
@@ -1118,8 +1129,8 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
1118
1129
let notifier = notify_chan. map ( |c| auto_notify ( c) ) ;
1119
1130
1120
1131
if enlist_many ( child, child_arc, & mut ancestors) {
1121
- let group = @taskgroup ( child, child_arc, ancestors,
1122
- is_main, notifier) ;
1132
+ let group = @tcb ( child, child_arc, ancestors,
1133
+ is_main, notifier) ;
1123
1134
unsafe { local_set ( child, taskgroup_key ( ) , group) ; }
1124
1135
// Run the child's body.
1125
1136
f ( ) ;
@@ -1134,7 +1145,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
1134
1145
ancestors : & mut ancestor_list ) -> bool {
1135
1146
// Join this taskgroup.
1136
1147
let mut result =
1137
- do child_arc. with |_c , child_tg| {
1148
+ do access_group ( child_arc) | child_tg| {
1138
1149
enlist_in_taskgroup ( child_tg, child, true ) // member
1139
1150
} ;
1140
1151
if result {
@@ -1151,7 +1162,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
1151
1162
} ;
1152
1163
// If any ancestor group fails, need to exit this group too.
1153
1164
if !result {
1154
- do child_arc. with |_c , child_tg| {
1165
+ do access_group ( child_arc) | child_tg| {
1155
1166
leave_taskgroup ( child_tg, child, true ) ; // member
1156
1167
}
1157
1168
}
@@ -1485,7 +1496,7 @@ fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port
1485
1496
do spawn_unlinked {
1486
1497
do spawn_unlinked {
1487
1498
// Give middle task a chance to fail-but-not-kill-us.
1488
- for iter:: repeat( 128 ) { task:: yield( ) ; }
1499
+ for iter:: repeat ( 16 ) { task:: yield ( ) ; }
1489
1500
comm:: send ( ch, ( ) ) ; // If killed first, grandparent hangs.
1490
1501
}
1491
1502
fail; // Shouldn't kill either (grand)parent or (grand)child.
@@ -1500,7 +1511,7 @@ fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails
1500
1511
fn test_spawn_unlinked_sup_no_fail_up ( ) { // child unlinked fails
1501
1512
do spawn_supervised { fail; }
1502
1513
// Give child a chance to fail-but-not-kill-us.
1503
- for iter:: repeat( 128 ) { task:: yield( ) ; }
1514
+ for iter:: repeat( 16 ) { task:: yield ( ) ; }
1504
1515
}
1505
1516
#[ test] #[ should_fail] #[ ignore( cfg( windows) ) ]
1506
1517
fn test_spawn_unlinked_sup_fail_down ( ) {
@@ -1569,7 +1580,7 @@ fn test_spawn_failure_propagate_grandchild() {
1569
1580
loop { task:: yield ( ) ; }
1570
1581
}
1571
1582
}
1572
- for iter:: repeat( 128 ) { task:: yield( ) ; }
1583
+ for iter:: repeat( 16 ) { task:: yield ( ) ; }
1573
1584
fail;
1574
1585
}
1575
1586
@@ -1581,7 +1592,7 @@ fn test_spawn_failure_propagate_secondborn() {
1581
1592
loop { task:: yield ( ) ; }
1582
1593
}
1583
1594
}
1584
- for iter:: repeat( 128 ) { task:: yield( ) ; }
1595
+ for iter:: repeat( 16 ) { task:: yield ( ) ; }
1585
1596
fail;
1586
1597
}
1587
1598
@@ -1593,7 +1604,7 @@ fn test_spawn_failure_propagate_nephew_or_niece() {
1593
1604
loop { task:: yield ( ) ; }
1594
1605
}
1595
1606
}
1596
- for iter:: repeat( 128 ) { task:: yield( ) ; }
1607
+ for iter:: repeat( 16 ) { task:: yield ( ) ; }
1597
1608
fail;
1598
1609
}
1599
1610
@@ -1605,7 +1616,7 @@ fn test_spawn_linked_sup_propagate_sibling() {
1605
1616
loop { task:: yield ( ) ; }
1606
1617
}
1607
1618
}
1608
- for iter:: repeat( 128 ) { task:: yield( ) ; }
1619
+ for iter:: repeat( 16 ) { task:: yield ( ) ; }
1609
1620
fail;
1610
1621
}
1611
1622
@@ -2006,7 +2017,9 @@ fn test_atomically_nested() {
2006
2017
fn test_child_doesnt_ref_parent() {
2007
2018
// If the child refcounts the parent task, this will stack overflow when
2008
2019
// climbing the task tree to dereference each ancestor. (See #1789)
2009
- const generations: uint = 128;
2020
+ // (well, it would if the constant were 8000+ - I lowered it to be more
2021
+ // valgrind-friendly. try this at home, instead..!)
2022
+ const generations: uint = 16;
2010
2023
fn child_no(x: uint) -> fn~() {
2011
2024
return || {
2012
2025
if x < generations {
0 commit comments