@@ -584,7 +584,8 @@ type rust_closure = libc::c_void;
584
584
585
585
/* linked failure */
586
586
587
- type taskgroup_arc = arc:: exclusive < option < dvec:: dvec < option < * rust_task > > > > ;
587
+ type taskgroup_arc =
588
+ arc:: exclusive < option < ( dvec:: dvec < option < * rust_task > > , dvec:: dvec < uint > ) > > ;
588
589
589
590
class taskgroup {
590
591
// FIXME (#2816): Change dvec to an O(1) data structure (and change 'me'
@@ -594,9 +595,6 @@ class taskgroup {
594
595
let me: * rust_task ;
595
596
let my_pos: uint ;
596
597
// let parent_group: taskgroup_arc; // FIXME (#1868) (bblum)
597
- // FIXME (#1868) XXX bblum: add a list of empty slots to get runtime back
598
- // Indicates whether this is the main (root) taskgroup. If so, failure
599
- // here should take down the entire runtime.
600
598
let is_main: bool ;
601
599
new ( -tasks: taskgroup_arc, me: * rust_task, my_pos: uint, is_main: bool ) {
602
600
self . tasks = tasks;
@@ -621,29 +619,40 @@ fn enlist_in_taskgroup(group_arc: taskgroup_arc,
621
619
me : * rust_task ) -> option < uint > {
622
620
do group_arc. with |_c, state| {
623
621
// If 'none', the group was failing. Can't enlist.
624
- do state. map |tasks| {
622
+ let mut newstate = none;
623
+ * state <-> newstate;
624
+ if newstate. is_some ( ) {
625
+ let ( tasks, empty_slots) = option:: unwrap ( newstate) ;
625
626
// Try to find an empty slot.
626
- alt tasks. position ( |x| x == none) {
627
- some ( empty_index) {
628
- tasks. set_elt ( empty_index, some ( me) ) ;
629
- empty_index
630
- }
631
- none {
632
- tasks. push ( some ( me) ) ;
633
- tasks. len ( ) - 1
634
- }
635
- }
627
+ let slotno = if empty_slots. len ( ) > 0 {
628
+ let empty_index = empty_slots. pop ( ) ;
629
+ assert tasks[ empty_index] == none;
630
+ tasks. set_elt ( empty_index, some ( me) ) ;
631
+ empty_index
632
+ } else {
633
+ tasks. push ( some ( me) ) ;
634
+ tasks. len ( ) - 1
635
+ } ;
636
+ * state = some ( ( tasks, empty_slots) ) ;
637
+ some ( slotno)
638
+ } else {
639
+ none
636
640
}
637
641
}
638
642
}
639
643
640
644
// NB: Runs in destructor/post-exit context. Can't 'fail'.
641
645
fn leave_taskgroup ( group_arc : taskgroup_arc , me : * rust_task , index : uint ) {
642
646
do group_arc. with |_c, state| {
647
+ let mut newstate = none;
648
+ * state <-> newstate;
643
649
// If 'none', already failing and we've already gotten a kill signal.
644
- do state. map |tasks| {
650
+ if newstate. is_some ( ) {
651
+ let ( tasks, empty_slots) = option:: unwrap ( newstate) ;
645
652
assert tasks[ index] == some ( me) ;
646
653
tasks. set_elt ( index, none) ;
654
+ empty_slots. push ( index) ;
655
+ * state = some ( ( tasks, empty_slots) ) ;
647
656
} ;
648
657
} ;
649
658
}
@@ -664,7 +673,8 @@ fn kill_taskgroup(group_arc: taskgroup_arc, me: *rust_task, index: uint,
664
673
// Might already be none, if somebody is failing simultaneously.
665
674
// That's ok; only one task needs to do the dirty work. (Might also
666
675
// see 'none' if somebody already failed and we got a kill signal.)
667
- do newstate. map |tasks| {
676
+ if newstate. is_some ( ) {
677
+ let ( tasks, _empty_slots) = option:: unwrap ( newstate) ;
668
678
// First remove ourself (killing ourself won't do much good). This
669
679
// is duplicated here to avoid having to lock twice.
670
680
assert tasks[ index] == some ( me) ;
@@ -679,7 +689,9 @@ fn kill_taskgroup(group_arc: taskgroup_arc, me: *rust_task, index: uint,
679
689
if is_main {
680
690
rustrt:: rust_task_kill_all ( me) ;
681
691
}
682
- } ;
692
+ // Do NOT restore state to some(..)! It stays none to indicate
693
+ // that the whole taskgroup is failing, to forbid new spawns.
694
+ }
683
695
// (note: multiple tasks may reach this point)
684
696
} ;
685
697
}
@@ -700,7 +712,8 @@ fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
700
712
}
701
713
none {
702
714
// Main task, doing first spawn ever.
703
- let tasks = arc:: exclusive ( some ( dvec:: from_elem ( some ( me) ) ) ) ;
715
+ let tasks = arc:: exclusive ( some ( ( dvec:: from_elem ( some ( me) ) ,
716
+ dvec:: dvec ( ) ) ) ) ;
704
717
let group = @taskgroup ( tasks. clone ( ) , me, 0 , true ) ;
705
718
unsafe { local_set ( me, taskgroup_key ( ) , group) ; }
706
719
// Tell child task it's also in the main group.
@@ -715,7 +728,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
715
728
share_parent_taskgroup ( )
716
729
} else {
717
730
// Detached from the parent group; create a new (non-main) one.
718
- ( arc:: exclusive ( some ( dvec:: from_elem ( none ) ) ) , false )
731
+ ( arc:: exclusive ( some ( ( dvec:: dvec ( ) , dvec :: dvec ( ) ) ) ) , false )
719
732
} ;
720
733
721
734
unsafe {
0 commit comments