Skip to content

Commit d9e8efc

Browse files
committed
Handle notification channels in task.rs
1 parent 1e241b5 commit d9e8efc

File tree

1 file changed

+34
-17
lines changed

1 file changed

+34
-17
lines changed

src/libcore/task.rs

+34-17
Original file line numberDiff line numberDiff line change
@@ -612,18 +612,23 @@ class taskgroup {
612612
// Lists of tasks who will kill us if they fail, but whom we won't kill.
613613
let parents: option<(taskgroup_arc,uint)>;
614614
let is_main: bool;
615+
let notifier: option<auto_notify>;
615616
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; });
622626
}
623627
// Runs on task exit.
624628
drop {
625629
// If we are failing, the whole taskgroup needs to die.
626630
if rustrt::rust_task_is_unwinding(self.me) {
631+
self.notifier.iter(|x| { x.failed = true; });
627632
// Take everybody down with us.
628633
kill_taskgroup(self.tasks, self.me, self.my_pos, self.is_main);
629634
} else {
@@ -641,6 +646,19 @@ class taskgroup {
641646
}
642647
}
643648

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+
644662
fn enlist_in_taskgroup(group_arc: taskgroup_arc,
645663
me: *rust_task) -> option<uint> {
646664
do group_arc.with |_c, state| {
@@ -750,7 +768,7 @@ fn share_spawner_taskgroup(linked: bool)
750768
let tasks = arc::exclusive(some((dvec::from_elem(some(me)),
751769
dvec::dvec())));
752770
// 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);
754772
unsafe { local_set(me, taskgroup_key(), group); }
755773
// Tell child task it's also in the main group.
756774
// 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~()) {
796814
// Getting killed after here would leak the task.
797815

798816
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);
800819
let fptr = ptr::addr_of(child_wrapper);
801820
let closure: *rust_closure = unsafe::reinterpret_cast(fptr);
802821

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-
808822
// Getting killed between these two calls would free the child's
809823
// closure. (Reordering them wouldn't help - then getting killed
810824
// between them would leak.)
@@ -829,6 +843,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
829843
// }
830844
fn make_child_wrapper(child: *rust_task, -child_tg: taskgroup_arc,
831845
-parent_tg: option<taskgroup_arc>, is_main: bool,
846+
notify_chan: option<comm::chan<notification>>,
832847
-f: fn~()) -> fn~() {
833848
let child_tg_ptr = ~mut some((child_tg, parent_tg));
834849
fn~() {
@@ -837,6 +852,11 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
837852
*child_tg_ptr <-> tg_data_opt;
838853
let (child_tg, parent_tg) = option::unwrap(tg_data_opt);
839854
// 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+
840860
// Set up membership in taskgroup. If this returns none, some
841861
// task was already failing, so don't bother doing anything.
842862
alt enlist_in_taskgroup(child_tg, child) {
@@ -862,7 +882,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
862882
};
863883
if enlist_ok {
864884
let group = @taskgroup(child, child_tg, my_pos,
865-
pg, is_main);
885+
pg, is_main, notifier);
866886
unsafe { local_set(child, taskgroup_key(), group); }
867887
// Run the child's body.
868888
f();
@@ -1129,9 +1149,6 @@ extern mod rustrt {
11291149
fn new_task() -> *rust_task;
11301150
fn rust_new_task_in_sched(id: sched_id) -> *rust_task;
11311151

1132-
fn rust_task_config_notify(
1133-
task: *rust_task, &&chan: comm::chan<notification>);
1134-
11351152
fn start_task(task: *rust_task, closure: *rust_closure);
11361153

11371154
fn rust_task_is_unwinding(task: *rust_task) -> bool;

0 commit comments

Comments
 (0)