libcore: Remove mutable fields from the task builder API

This commit is contained in:
Patrick Walton 2013-05-03 13:21:33 -07:00
parent 226ee7d86f
commit 803a4f45fa
8 changed files with 87 additions and 131 deletions

View File

@ -156,7 +156,7 @@ pub struct SchedOpts {
pub struct TaskOpts {
linked: bool,
supervised: bool,
mut notify_chan: Option<Chan<TaskResult>>,
notify_chan: Option<Chan<TaskResult>>,
sched: SchedOpts
}
@ -176,9 +176,9 @@ pub struct TaskOpts {
// FIXME (#3724): Replace the 'consumed' bit with move mode on self
pub struct TaskBuilder {
opts: TaskOpts,
mut gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
can_not_copy: Option<util::NonCopyable>,
mut consumed: bool,
consumed: bool,
}
/**
@ -191,13 +191,13 @@ pub fn task() -> TaskBuilder {
opts: default_task_opts(),
gen_body: None,
can_not_copy: None,
mut consumed: false,
consumed: false,
}
}
#[doc(hidden)] // FIXME #3538
priv impl TaskBuilder {
fn consume(&self) -> TaskBuilder {
fn consume(&mut self) -> TaskBuilder {
if self.consumed {
fail!(~"Cannot copy a task_builder"); // Fake move mode on self
}
@ -219,57 +219,23 @@ priv impl TaskBuilder {
}
pub impl TaskBuilder {
/**
* Decouple the child task's failure from the parent's. If either fails,
* the other will not be killed.
*/
fn unlinked(&self) -> TaskBuilder {
let notify_chan = replace(&mut self.opts.notify_chan, None);
TaskBuilder {
opts: TaskOpts {
linked: false,
supervised: self.opts.supervised,
notify_chan: notify_chan,
sched: self.opts.sched
},
can_not_copy: None,
.. self.consume()
}
/// Decouple the child task's failure from the parent's. If either fails,
/// the other will not be killed.
fn unlinked(&mut self) {
self.opts.linked = false;
}
/**
* Unidirectionally link the child task's failure with the parent's. The
* child's failure will not kill the parent, but the parent's will kill
* the child.
*/
fn supervised(&self) -> TaskBuilder {
let notify_chan = replace(&mut self.opts.notify_chan, None);
TaskBuilder {
opts: TaskOpts {
linked: false,
supervised: true,
notify_chan: notify_chan,
sched: self.opts.sched
},
can_not_copy: None,
.. self.consume()
}
/// Unidirectionally link the child task's failure with the parent's. The
/// child's failure will not kill the parent, but the parent's will kill
/// the child.
fn supervised(&mut self) {
self.opts.supervised = true;
}
/**
* Link the child task's and parent task's failures. If either fails, the
* other will be killed.
*/
fn linked(&self) -> TaskBuilder {
let notify_chan = replace(&mut self.opts.notify_chan, None);
TaskBuilder {
opts: TaskOpts {
linked: true,
supervised: false,
notify_chan: notify_chan,
sched: self.opts.sched
},
can_not_copy: None,
.. self.consume()
}
/// Link the child task's and parent task's failures. If either fails, the
/// other will be killed.
fn linked(&mut self) {
self.opts.linked = true;
}
/**
@ -289,7 +255,7 @@ pub impl TaskBuilder {
* # Failure
* Fails if a future_result was already set for this task.
*/
fn future_result(&self, blk: &fn(v: Port<TaskResult>)) -> TaskBuilder {
fn future_result(&mut self, blk: &fn(v: Port<TaskResult>)) {
// FIXME (#3725): Once linked failure and notification are
// handled in the library, I can imagine implementing this by just
// registering an arbitrary number of task::on_exit handlers and
@ -305,30 +271,12 @@ pub impl TaskBuilder {
blk(notify_pipe_po);
// Reconfigure self to use a notify channel.
TaskBuilder {
opts: TaskOpts {
linked: self.opts.linked,
supervised: self.opts.supervised,
notify_chan: Some(notify_pipe_ch),
sched: self.opts.sched
},
can_not_copy: None,
.. self.consume()
}
self.opts.notify_chan = Some(notify_pipe_ch);
}
/// Configure a custom scheduler mode for the task.
fn sched_mode(&self, mode: SchedMode) -> TaskBuilder {
let notify_chan = replace(&mut self.opts.notify_chan, None);
TaskBuilder {
opts: TaskOpts {
linked: self.opts.linked,
supervised: self.opts.supervised,
notify_chan: notify_chan,
sched: SchedOpts { mode: mode, foreign_stack_size: None}
},
can_not_copy: None,
.. self.consume()
}
fn sched_mode(&mut self, mode: SchedMode) {
self.opts.sched.mode = mode;
}
/**
@ -343,7 +291,7 @@ pub impl TaskBuilder {
* generator by applying the task body which results from the
* existing body generator to the new body generator.
*/
fn add_wrapper(&self, wrapper: ~fn(v: ~fn()) -> ~fn()) -> TaskBuilder {
fn add_wrapper(&mut self, wrapper: ~fn(v: ~fn()) -> ~fn()) {
let prev_gen_body = replace(&mut self.gen_body, None);
let prev_gen_body = match prev_gen_body {
Some(gen) => gen,
@ -360,18 +308,7 @@ pub impl TaskBuilder {
};
f
};
let notify_chan = replace(&mut self.opts.notify_chan, None);
TaskBuilder {
opts: TaskOpts {
linked: self.opts.linked,
supervised: self.opts.supervised,
notify_chan: notify_chan,
sched: self.opts.sched
},
gen_body: Some(next_gen_body),
can_not_copy: None,
.. self.consume()
}
self.gen_body = Some(next_gen_body);
}
/**
@ -386,7 +323,7 @@ pub impl TaskBuilder {
* When spawning into a new scheduler, the number of threads requested
* must be greater than zero.
*/
fn spawn(&self, f: ~fn()) {
fn spawn(&mut self, f: ~fn()) {
let gen_body = replace(&mut self.gen_body, None);
let notify_chan = replace(&mut self.opts.notify_chan, None);
let x = self.consume();
@ -406,8 +343,9 @@ pub impl TaskBuilder {
};
spawn::spawn_raw(opts, f);
}
/// Runs a task, while transfering ownership of one argument to the child.
fn spawn_with<A:Owned>(&self, arg: A, f: ~fn(v: A)) {
fn spawn_with<A:Owned>(&mut self, arg: A, f: ~fn(v: A)) {
let arg = Cell(arg);
do self.spawn {
f(arg.take());
@ -427,16 +365,16 @@ pub impl TaskBuilder {
* # Failure
* Fails if a future_result was already set for this task.
*/
fn try<T:Owned>(&self, f: ~fn() -> T) -> Result<T,()> {
fn try<T:Owned>(&mut self, f: ~fn() -> T) -> Result<T,()> {
let (po, ch) = stream::<T>();
let mut result = None;
let fr_task_builder = self.future_result(|+r| {
result = Some(r);
});
do fr_task_builder.spawn || {
self.future_result(|+r| { result = Some(r); });
do self.spawn {
ch.send(f());
}
match result.unwrap().recv() {
Success => result::Ok(po.recv()),
Failure => result::Err(())
@ -468,26 +406,23 @@ pub fn default_task_opts() -> TaskOpts {
/* Spawn convenience functions */
/// Creates and executes a new child task
///
/// Sets up a new task with its own call stack and schedules it to run
/// the provided unique closure.
///
/// This function is equivalent to `task().spawn(f)`.
pub fn spawn(f: ~fn()) {
/*!
* Creates and executes a new child task
*
* Sets up a new task with its own call stack and schedules it to run
* the provided unique closure.
*
* This function is equivalent to `task().spawn(f)`.
*/
task().spawn(f)
let mut task = task();
task.spawn(f)
}
/// Creates a child task unlinked from the current one. If either this
/// task or the child task fails, the other will not be killed.
pub fn spawn_unlinked(f: ~fn()) {
/*!
* Creates a child task unlinked from the current one. If either this
* task or the child task fails, the other will not be killed.
*/
task().unlinked().spawn(f)
let mut task = task();
task.unlinked();
task.spawn(f)
}
pub fn spawn_supervised(f: ~fn()) {
@ -497,7 +432,9 @@ pub fn spawn_supervised(f: ~fn()) {
* the child will be killed.
*/
task().supervised().spawn(f)
let mut task = task();
task.supervised();
task.spawn(f)
}
pub fn spawn_with<A:Owned>(arg: A, f: ~fn(v: A)) {
@ -511,7 +448,8 @@ pub fn spawn_with<A:Owned>(arg: A, f: ~fn(v: A)) {
* This function is equivalent to `task().spawn_with(arg, f)`.
*/
task().spawn_with(arg, f)
let mut task = task();
task.spawn_with(arg, f)
}
pub fn spawn_sched(mode: SchedMode, f: ~fn()) {
@ -527,7 +465,9 @@ pub fn spawn_sched(mode: SchedMode, f: ~fn()) {
* greater than zero.
*/
task().sched_mode(mode).spawn(f)
let mut task = task();
task.sched_mode(mode);
task.spawn(f)
}
pub fn try<T:Owned>(f: ~fn() -> T) -> Result<T,()> {
@ -538,7 +478,9 @@ pub fn try<T:Owned>(f: ~fn() -> T) -> Result<T,()> {
* This is equivalent to task().supervised().try.
*/
task().supervised().try(f)
let mut task = task();
task.supervised();
task.try(f)
}
@ -822,7 +764,7 @@ fn test_run_basic() {
#[cfg(test)]
struct Wrapper {
mut f: Option<Chan<()>>
f: Option<Chan<()>>
}
#[test]

View File

@ -580,7 +580,7 @@ fn spawn_raw_newsched(_opts: TaskOpts, f: ~fn()) {
sched.schedule_new_task(task);
}
fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) {
fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) {
let (child_tg, ancestors, is_main) =
gen_child_taskgroup(opts.linked, opts.supervised);

View File

@ -70,7 +70,9 @@ fn exit_runner(exit_fns: *ExitFunctions) {
while !exit_fns_vec.is_empty() {
match exit_fns_vec.pop() {
~f => {
task::task().supervised().spawn(f);
let mut task = task::task();
task.supervised();
task.spawn(f);
}
}
}

View File

@ -72,7 +72,9 @@ fn create_global_service() -> ~WeakTaskService {
let chan = SharedChan::new(chan);
let chan_clone = chan.clone();
do task().unlinked().spawn {
let mut task = task();
task.unlinked();
do task.spawn {
debug!("running global weak task service");
let port = Cell(port.take());
do (|| {

View File

@ -70,7 +70,9 @@ pub impl<T> TaskPool<T> {
task::spawn(task_body);
}
Some(sched_mode) => {
task::task().sched_mode(sched_mode).spawn(task_body);
let mut task = task::task();
task.sched_mode(sched_mode);
task.spawn(task_body);
}
}

View File

@ -556,9 +556,12 @@ pub fn run_test(force_ignore: bool,
let testfn_cell = ::core::cell::Cell(testfn);
do task::spawn {
let mut result_future = None; // task::future_result(builder);
task::task().unlinked().future_result(|+r| {
result_future = Some(r);
}).spawn(testfn_cell.take());
let mut task = task::task();
task.unlinked();
task.future_result(|+r| { result_future = Some(r) });
task.spawn(testfn_cell.take());
let task_result = result_future.unwrap().recv();
let test_result = calc_result(&desc,
task_result == task::Success);

View File

@ -62,7 +62,9 @@ fn get_monitor_task_gl() -> IoTask {
}
};
if installed {
do task().unlinked().spawn() {
let mut task = task();
task.unlinked();
do task.spawn {
unsafe {
debug!("global monitor task starting");
// As a weak task the runtime will notify us
@ -88,7 +90,9 @@ fn get_monitor_task_gl() -> IoTask {
}
fn spawn_loop() -> IoTask {
let builder = do task().add_wrapper |task_body| {
let mut builder = task();
do builder.add_wrapper |task_body| {
let result: ~fn() = || {
// The I/O loop task also needs to be weak so it doesn't keep
// the runtime alive
@ -107,7 +111,8 @@ fn spawn_loop() -> IoTask {
};
result
};
let builder = builder.unlinked();
builder.unlinked();
spawn_iotask(builder)
}

View File

@ -36,11 +36,11 @@ impl Clone for IoTask {
}
}
pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask {
pub fn spawn_iotask(mut task: task::TaskBuilder) -> IoTask {
let (iotask_port, iotask_chan) = stream();
do task.sched_mode(task::SingleThreaded).spawn {
task.sched_mode(task::SingleThreaded);
do task.spawn {
debug!("entering libuv task");
run_loop(&iotask_chan);
debug!("libuv task exiting");