libcore: Remove mutable fields from task::spawn

This commit is contained in:
Patrick Walton 2013-05-03 12:46:35 -07:00
parent 4dc1c2976d
commit 226ee7d86f
2 changed files with 85 additions and 46 deletions

View File

@ -72,6 +72,7 @@
#[doc(hidden)]; // FIXME #3538
use cast::transmute;
use cast;
use cell::Cell;
use container::Map;
@ -117,10 +118,10 @@ pub fn taskset_each(tasks: &TaskSet, blk: &fn(v: *rust_task) -> bool) {
struct TaskGroupData {
// All tasks which might kill this group. When this is empty, the group
// can be "GC"ed (i.e., its link in the ancestor list can be removed).
mut members: TaskSet,
members: TaskSet,
// All tasks unidirectionally supervised by (directly or transitively)
// tasks in this group.
mut descendants: TaskSet,
descendants: TaskSet,
}
type TaskGroupArc = unstable::Exclusive<Option<TaskGroupData>>;
@ -145,11 +146,11 @@ struct AncestorNode {
// Hence we assert that this counter monotonically decreases as we
// approach the tail of the list.
// FIXME(#3068): Make the generation counter togglable with #[cfg(debug)].
generation: uint,
// Should really be an immutable non-option. This way appeases borrowck.
mut parent_group: Option<TaskGroupArc>,
generation: uint,
// Should really be a non-option. This way appeases borrowck.
parent_group: Option<TaskGroupArc>,
// Recursive rest of the list.
mut ancestors: AncestorList,
ancestors: AncestorList,
}
struct AncestorList(Option<unstable::Exclusive<AncestorNode>>);
@ -301,22 +302,26 @@ fn each_ancestor(list: &mut AncestorList,
// One of these per task.
struct TCB {
me: *rust_task,
me: *rust_task,
// List of tasks with whose fates this one's is intertwined.
tasks: TaskGroupArc, // 'none' means the group has failed.
tasks: TaskGroupArc, // 'none' means the group has failed.
// Lists of tasks who will kill us if they fail, but whom we won't kill.
mut ancestors: AncestorList,
is_main: bool,
notifier: Option<AutoNotify>,
ancestors: AncestorList,
is_main: bool,
notifier: Option<AutoNotify>,
}
impl Drop for TCB {
// Runs on task exit.
fn finalize(&self) {
unsafe {
let this: &mut TCB = transmute(self);
// If we are failing, the whole taskgroup needs to die.
if rt::rust_task_is_unwinding(self.me) {
for self.notifier.each |x| { x.failed = true; }
for this.notifier.each_mut |x| {
x.failed = true;
}
// Take everybody down with us.
do access_group(&self.tasks) |tg| {
kill_taskgroup(tg, self.me, self.is_main);
@ -331,16 +336,21 @@ impl Drop for TCB {
// with our own taskgroup, so long as both happen before we die.
// We remove ourself from every ancestor we can, so no cleanup; no
// break.
for each_ancestor(&mut self.ancestors, None) |ancestor_group| {
for each_ancestor(&mut this.ancestors, None) |ancestor_group| {
leave_taskgroup(ancestor_group, self.me, false);
};
}
}
}
fn TCB(me: *rust_task, tasks: TaskGroupArc, ancestors: AncestorList,
is_main: bool, notifier: Option<AutoNotify>) -> TCB {
for notifier.each |x| { x.failed = false; }
fn TCB(me: *rust_task,
tasks: TaskGroupArc,
ancestors: AncestorList,
is_main: bool,
mut notifier: Option<AutoNotify>) -> TCB {
for notifier.each_mut |x| {
x.failed = false;
}
TCB {
me: me,
@ -353,7 +363,7 @@ fn TCB(me: *rust_task, tasks: TaskGroupArc, ancestors: AncestorList,
struct AutoNotify {
notify_chan: Chan<TaskResult>,
mut failed: bool,
failed: bool,
}
impl Drop for AutoNotify {
@ -375,9 +385,12 @@ fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task,
let newstate = util::replace(&mut *state, None);
// If 'None', the group was failing. Can't enlist.
if newstate.is_some() {
let group = newstate.unwrap();
taskset_insert(if is_member { &mut group.members }
else { &mut group.descendants }, me);
let mut group = newstate.unwrap();
taskset_insert(if is_member {
&mut group.members
} else {
&mut group.descendants
}, me);
*state = Some(group);
true
} else {
@ -391,9 +404,12 @@ fn leave_taskgroup(state: TaskGroupInner, me: *rust_task,
let newstate = util::replace(&mut *state, None);
// If 'None', already failing and we've already gotten a kill signal.
if newstate.is_some() {
let group = newstate.unwrap();
taskset_remove(if is_member { &mut group.members }
else { &mut group.descendants }, me);
let mut group = newstate.unwrap();
taskset_remove(if is_member {
&mut group.members
} else {
&mut group.descendants
}, me);
*state = Some(group);
}
}
@ -451,23 +467,30 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
/*##################################################################*
* Step 1. Get spawner's taskgroup info.
*##################################################################*/
let spawner_group = match local_get(OldHandle(spawner), taskgroup_key!()) {
None => {
// Main task, doing first spawn ever. Lazily initialise here.
let mut members = new_taskset();
taskset_insert(&mut members, spawner);
let tasks = unstable::exclusive(Some(TaskGroupData {
members: members,
descendants: new_taskset(),
}));
// Main task/group has no ancestors, no notifier, etc.
let group =
@TCB(spawner, tasks, AncestorList(None), true, None);
local_set(OldHandle(spawner), taskgroup_key!(), group);
group
}
Some(group) => group
};
let mut spawner_group: @@mut TCB =
match local_get(OldHandle(spawner), taskgroup_key!()) {
None => {
// Main task, doing first spawn ever. Lazily initialise
// here.
let mut members = new_taskset();
taskset_insert(&mut members, spawner);
let tasks = unstable::exclusive(Some(TaskGroupData {
members: members,
descendants: new_taskset(),
}));
// Main task/group has no ancestors, no notifier, etc.
let group = @@mut TCB(spawner,
tasks,
AncestorList(None),
true,
None);
local_set(OldHandle(spawner), taskgroup_key!(), group);
group
}
Some(group) => group
};
let spawner_group: &mut TCB = *spawner_group;
/*##################################################################*
* Step 2. Process spawn options for child.
*##################################################################*/
@ -624,8 +647,11 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) {
};
if enlist_many(child, &child_arc, &mut ancestors) {
let group = @TCB(child, child_arc, ancestors,
is_main, notifier);
let group = @@mut TCB(child,
child_arc,
ancestors,
is_main,
notifier);
unsafe {
local_set(OldHandle(child), taskgroup_key!(), group);
}

View File

@ -235,17 +235,30 @@ pub impl LittleLock {
}
}
struct ExData<T> { lock: LittleLock, failed: bool, data: T, }
struct ExData<T> {
lock: LittleLock,
failed: bool,
data: T,
}
/**
* An arc over mutable data that is protected by a lock. For library use only.
*/
pub struct Exclusive<T> { x: SharedMutableState<ExData<T>> }
pub struct Exclusive<T> {
x: SharedMutableState<ExData<T>>
}
pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> {
let data = ExData {
lock: LittleLock(), failed: false, data: user_data
lock: LittleLock(),
failed: false,
data: user_data
};
Exclusive { x: unsafe { shared_mutable_state(data) } }
Exclusive {
x: unsafe {
shared_mutable_state(data)
}
}
}
impl<T:Owned> Clone for Exclusive<T> {