@@ -612,18 +612,23 @@ class taskgroup {
612
612
// Lists of tasks who will kill us if they fail, but whom we won't kill.
613
613
let parents: option < ( taskgroup_arc , uint ) > ;
614
614
let is_main: bool ;
615
+ let notifier: option < auto_notify > ;
615
616
new ( me: * rust_task, -tasks: taskgroup_arc, my_pos: uint,
616
- -parents: option<( taskgroup_arc, uint) >, is_main: bool) {
617
- self . me = me;
618
- self . tasks = tasks;
619
- self . my_pos = my_pos;
620
- self . parents = parents;
621
- self . is_main = is_main;
617
+ -parents: option<( taskgroup_arc, uint) >, is_main: bool,
618
+ -notifier: option<auto_notify>) {
619
+ self . me = me;
620
+ self . tasks = tasks;
621
+ self . my_pos = my_pos;
622
+ self . parents = parents;
623
+ self . is_main = is_main;
624
+ self . notifier = notifier;
625
+ self . notifier . iter ( |x| { x. failed = false ; } ) ;
622
626
}
623
627
// Runs on task exit.
624
628
drop {
625
629
// If we are failing, the whole taskgroup needs to die.
626
630
if rustrt:: rust_task_is_unwinding ( self . me ) {
631
+ self . notifier . iter ( |x| { x. failed = true ; } ) ;
627
632
// Take everybody down with us.
628
633
kill_taskgroup ( self . tasks , self . me , self . my_pos , self . is_main ) ;
629
634
} else {
@@ -641,6 +646,19 @@ class taskgroup {
641
646
}
642
647
}
643
648
649
+ class auto_notify {
650
+ let notify_chan : comm:: chan<notification>;
651
+ let mut failed: bool;
652
+ new ( chan: comm:: chan<notification>) {
653
+ self . notify_chan = chan;
654
+ self . failed = true ; // Un-set above when taskgroup successfully made.
655
+ }
656
+ drop {
657
+ let result = if self . failed { failure } else { success } ;
658
+ comm:: send ( self . notify_chan , exit ( get_task ( ) , result) ) ;
659
+ }
660
+ }
661
+
644
662
fn enlist_in_taskgroup ( group_arc: taskgroup_arc,
645
663
me: * rust_task) -> option<uint> {
646
664
do group_arc. with |_c, state| {
@@ -750,7 +768,7 @@ fn share_spawner_taskgroup(linked: bool)
750
768
let tasks = arc:: exclusive ( some ( ( dvec:: from_elem ( some ( me) ) ,
751
769
dvec:: dvec ( ) ) ) ) ;
752
770
// Main group has no parent group.
753
- let group = @taskgroup ( me, tasks. clone ( ) , 0 , none, true ) ;
771
+ let group = @taskgroup ( me, tasks. clone ( ) , 0 , none, true , none ) ;
754
772
unsafe { local_set ( me, taskgroup_key ( ) , group) ; }
755
773
// Tell child task it's also in the main group.
756
774
// Whether or not it wanted our parent group, we haven't got one.
@@ -796,15 +814,11 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
796
814
// Getting killed after here would leak the task.
797
815
798
816
let child_wrapper =
799
- make_child_wrapper ( new_task, child_tg, parent_tg, is_main, f) ;
817
+ make_child_wrapper ( new_task, child_tg, parent_tg, is_main,
818
+ opts. notify_chan , f) ;
800
819
let fptr = ptr:: addr_of ( child_wrapper) ;
801
820
let closure: * rust_closure = unsafe :: reinterpret_cast ( fptr) ;
802
821
803
- do option:: iter ( opts. notify_chan ) |c| {
804
- // FIXME (#1087): Would like to do notification in Rust
805
- rustrt:: rust_task_config_notify ( new_task, c) ;
806
- }
807
-
808
822
// Getting killed between these two calls would free the child's
809
823
// closure. (Reordering them wouldn't help - then getting killed
810
824
// between them would leak.)
@@ -829,6 +843,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
829
843
// }
830
844
fn make_child_wrapper ( child : * rust_task , -child_tg : taskgroup_arc ,
831
845
-parent_tg : option < taskgroup_arc > , is_main : bool ,
846
+ notify_chan : option < comm:: chan < notification > > ,
832
847
-f : fn ~( ) ) -> fn ~( ) {
833
848
let child_tg_ptr = ~mut some ( ( child_tg, parent_tg) ) ;
834
849
fn ~( ) {
@@ -837,6 +852,11 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
837
852
* child_tg_ptr <-> tg_data_opt;
838
853
let ( child_tg, parent_tg) = option:: unwrap ( tg_data_opt) ;
839
854
// Child task runs this code.
855
+
856
+ // Even if the below code fails to kick the child off, we must
857
+ // send something on the notify channel.
858
+ let notifier = notify_chan. map ( |c| auto_notify ( c) ) ;
859
+
840
860
// Set up membership in taskgroup. If this returns none, some
841
861
// task was already failing, so don't bother doing anything.
842
862
alt enlist_in_taskgroup ( child_tg, child) {
@@ -862,7 +882,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
862
882
} ;
863
883
if enlist_ok {
864
884
let group = @taskgroup ( child, child_tg, my_pos,
865
- pg, is_main) ;
885
+ pg, is_main, notifier ) ;
866
886
unsafe { local_set ( child, taskgroup_key ( ) , group) ; }
867
887
// Run the child's body.
868
888
f ( ) ;
@@ -1129,9 +1149,6 @@ extern mod rustrt {
1129
1149
fn new_task ( ) -> * rust_task ;
1130
1150
fn rust_new_task_in_sched ( id : sched_id ) -> * rust_task ;
1131
1151
1132
- fn rust_task_config_notify (
1133
- task : * rust_task , & & chan: comm:: chan < notification > ) ;
1134
-
1135
1152
fn start_task ( task : * rust_task , closure : * rust_closure ) ;
1136
1153
1137
1154
fn rust_task_is_unwinding ( task : * rust_task ) -> bool ;
0 commit comments