libcore: Remove mutable fields from task::spawn
This commit is contained in:
parent
4dc1c2976d
commit
226ee7d86f
2 changed files with 85 additions and 46 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue