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