2013-05-30 05:16:33 -05:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-11-28 18:20:41 -06:00
|
|
|
/*!
|
2013-12-24 10:08:28 -06:00
|
|
|
* Utilities for managing and scheduling tasks
|
2012-11-28 18:20:41 -06:00
|
|
|
*
|
|
|
|
* An executing Rust program consists of a tree of tasks, each with their own
|
|
|
|
* stack, and sole ownership of their allocated heap data. Tasks communicate
|
2014-02-13 00:02:09 -06:00
|
|
|
* with each other using ports and channels (see std::comm for more info
|
2013-09-27 16:22:16 -05:00
|
|
|
* about how communication works).
|
2012-11-28 18:20:41 -06:00
|
|
|
*
|
2014-02-13 00:02:09 -06:00
|
|
|
* Failure in one task does not propagate to any others (not to parent, not to child).
|
|
|
|
* Failure propagation is instead handled by using Chan.send() and Port.recv(), which
|
|
|
|
* will fail if the other end has hung up already.
|
2013-09-27 16:22:16 -05:00
|
|
|
*
|
|
|
|
* Task Scheduling:
|
|
|
|
*
|
|
|
|
* By default, every task is created in the same scheduler as its parent, where it
|
|
|
|
* is scheduled cooperatively with all other tasks in that scheduler. Some specialized
|
|
|
|
* applications may want more control over their scheduling, in which case they can be
|
|
|
|
* spawned into a new scheduler with the specific properties required. See TaskBuilder's
|
|
|
|
* documentation bellow for more information.
|
2012-11-28 18:20:41 -06:00
|
|
|
*
|
|
|
|
* # Example
|
|
|
|
*
|
2013-09-23 19:20:36 -05:00
|
|
|
* ```
|
2014-01-26 21:42:26 -06:00
|
|
|
* spawn(proc() {
|
2014-02-15 01:44:22 -06:00
|
|
|
* println!("Hello, World!");
|
2014-01-26 21:42:26 -06:00
|
|
|
* })
|
2013-09-23 19:20:36 -05:00
|
|
|
* ```
|
2012-11-28 18:20:41 -06:00
|
|
|
*/
|
2012-11-18 19:56:50 -06:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
use any::Any;
|
2013-12-05 20:19:06 -06:00
|
|
|
use comm::{Chan, Port};
|
2014-01-06 12:26:11 -06:00
|
|
|
use io::Writer;
|
2014-01-26 04:42:46 -06:00
|
|
|
use kinds::{Send, marker};
|
2014-01-06 12:26:11 -06:00
|
|
|
use logging::Logger;
|
2013-12-12 20:01:59 -06:00
|
|
|
use option::{None, Some, Option};
|
2013-10-11 16:20:34 -05:00
|
|
|
use result::{Result, Ok, Err};
|
2013-07-08 12:48:57 -05:00
|
|
|
use rt::local::Local;
|
2013-12-12 20:01:59 -06:00
|
|
|
use rt::task::Task;
|
2014-02-07 18:36:59 -06:00
|
|
|
use str::{Str, SendStr, IntoMaybeOwned};
|
2012-11-18 19:56:50 -06:00
|
|
|
|
2013-12-12 23:38:57 -06:00
|
|
|
#[cfg(test)] use any::{AnyOwnExt, AnyRefExt};
|
2013-10-11 16:20:34 -05:00
|
|
|
#[cfg(test)] use result;
|
2013-03-26 15:38:07 -05:00
|
|
|
|
2013-10-11 16:20:34 -05:00
|
|
|
/// Indicates the manner in which a task exited.
|
|
|
|
///
|
|
|
|
/// A task that completes without failing is considered to exit successfully.
|
|
|
|
///
|
2014-02-13 00:02:09 -06:00
|
|
|
/// If you wish for this result's delivery to block until all
|
2013-10-11 16:20:34 -05:00
|
|
|
/// children tasks complete, recommend using a result future.
|
|
|
|
pub type TaskResult = Result<(), ~Any>;
|
|
|
|
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Task configuration options
|
2013-01-22 10:12:52 -06:00
|
|
|
pub struct TaskOpts {
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Enable lifecycle notifications on the given channel
|
2013-12-12 20:01:59 -06:00
|
|
|
notify_chan: Option<Chan<TaskResult>>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// A name for the task-to-be, for identification in failure messages
|
2013-10-19 22:26:42 -05:00
|
|
|
name: Option<SendStr>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// The size of the stack for the spawned task
|
2014-01-06 12:26:11 -06:00
|
|
|
stack_size: Option<uint>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Task-local logger (see std::logging)
|
2014-01-06 12:26:11 -06:00
|
|
|
logger: Option<~Logger>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Task-local stdout
|
2014-01-06 12:26:11 -06:00
|
|
|
stdout: Option<~Writer>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Task-local stderr
|
2014-01-06 12:26:11 -06:00
|
|
|
stderr: Option<~Writer>,
|
2013-01-22 10:12:52 -06:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The task builder type.
|
|
|
|
*
|
|
|
|
* Provides detailed control over the properties and behavior of new tasks.
|
|
|
|
*/
|
|
|
|
// NB: Builders are designed to be single-use because they do stateful
|
|
|
|
// things that get weird when reusing - e.g. if you create a result future
|
|
|
|
// it only applies to a single task, so then you have to maintain Some
|
|
|
|
// potentially tricky state to ensure that everything behaves correctly
|
|
|
|
// when you try to reuse the builder to spawn a new task. We'll just
|
|
|
|
// sidestep that whole issue by making builders uncopyable and making
|
|
|
|
// the run function move them in.
|
2012-12-05 17:06:54 -06:00
|
|
|
pub struct TaskBuilder {
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Options to spawn the new task with
|
2012-11-28 18:20:41 -06:00
|
|
|
opts: TaskOpts,
|
2013-11-18 15:25:09 -06:00
|
|
|
priv gen_body: Option<proc(v: proc()) -> proc()>,
|
2014-01-26 04:42:46 -06:00
|
|
|
priv nopod: Option<marker::NoPod>,
|
2012-12-05 17:06:54 -06:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate the base configuration for spawning a task, off of which more
|
|
|
|
* configuration methods can be chained.
|
|
|
|
*/
|
|
|
|
pub fn task() -> TaskBuilder {
|
2012-12-05 17:06:54 -06:00
|
|
|
TaskBuilder {
|
2013-12-13 18:26:02 -06:00
|
|
|
opts: TaskOpts::new(),
|
2013-04-18 20:22:04 -05:00
|
|
|
gen_body: None,
|
2014-01-26 04:42:46 -06:00
|
|
|
nopod: None,
|
2012-12-05 17:06:54 -06:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl TaskBuilder {
|
2013-10-18 03:38:46 -05:00
|
|
|
/// Get a future representing the exit status of the task.
|
|
|
|
///
|
|
|
|
/// Taking the value of the future will block until the child task
|
|
|
|
/// terminates. The future result return value will be created *before* the task is
|
|
|
|
/// spawned; as such, do not invoke .get() on it directly;
|
|
|
|
/// rather, store it in an outer variable/list for later use.
|
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
/// Fails if a future_result was already set for this task.
|
2013-12-05 20:19:06 -06:00
|
|
|
pub fn future_result(&mut self) -> Port<TaskResult> {
|
2012-11-28 18:20:41 -06:00
|
|
|
// 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
|
|
|
|
// sending out messages.
|
|
|
|
|
|
|
|
if self.opts.notify_chan.is_some() {
|
2013-10-21 15:08:31 -05:00
|
|
|
fail!("Can't set multiple future_results for one task!");
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the future and give it to the caller.
|
2013-12-05 20:19:06 -06:00
|
|
|
let (notify_pipe_po, notify_pipe_ch) = Chan::new();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
// Reconfigure self to use a notify channel.
|
2013-05-03 15:21:33 -05:00
|
|
|
self.opts.notify_chan = Some(notify_pipe_ch);
|
2013-10-18 03:38:46 -05:00
|
|
|
|
2013-12-05 20:19:06 -06:00
|
|
|
notify_pipe_po
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2013-05-03 15:21:33 -05:00
|
|
|
|
2013-07-30 18:20:59 -05:00
|
|
|
/// Name the task-to-be. Currently the name is used for identification
|
|
|
|
/// only in failure messages.
|
2014-02-13 00:02:09 -06:00
|
|
|
pub fn named<S: IntoMaybeOwned<'static>>(mut self, name: S) -> TaskBuilder {
|
2014-02-07 18:36:59 -06:00
|
|
|
self.opts.name = Some(name.into_maybe_owned());
|
2014-02-13 00:02:09 -06:00
|
|
|
self
|
2013-07-30 18:20:59 -05:00
|
|
|
}
|
|
|
|
|
2012-11-28 18:20:41 -06:00
|
|
|
/**
|
|
|
|
* Add a wrapper to the body of the spawned task.
|
|
|
|
*
|
|
|
|
* Before the task is spawned it is passed through a 'body generator'
|
|
|
|
* function that may perform local setup operations as well as wrap
|
|
|
|
* the task body in remote setup operations. With this the behavior
|
|
|
|
* of tasks can be extended in simple ways.
|
|
|
|
*
|
|
|
|
* This function augments the current body generator with a new body
|
|
|
|
* generator by applying the task body which results from the
|
|
|
|
* existing body generator to the new body generator.
|
|
|
|
*/
|
2014-02-13 00:02:09 -06:00
|
|
|
pub fn with_wrapper(mut self, wrapper: proc(v: proc()) -> proc()) -> TaskBuilder {
|
2013-07-17 16:41:50 -05:00
|
|
|
let prev_gen_body = self.gen_body.take();
|
2013-04-18 20:22:04 -05:00
|
|
|
let prev_gen_body = match prev_gen_body {
|
|
|
|
Some(gen) => gen,
|
|
|
|
None => {
|
2013-11-22 01:36:52 -06:00
|
|
|
let f: proc(proc()) -> proc() = proc(body) body;
|
2013-04-18 20:22:04 -05:00
|
|
|
f
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let next_gen_body = {
|
2013-11-22 01:36:52 -06:00
|
|
|
let f: proc(proc()) -> proc() = proc(body) {
|
2013-04-18 20:22:04 -05:00
|
|
|
wrapper(prev_gen_body(body))
|
|
|
|
};
|
|
|
|
f
|
|
|
|
};
|
2013-05-03 15:21:33 -05:00
|
|
|
self.gen_body = Some(next_gen_body);
|
2014-02-13 00:02:09 -06:00
|
|
|
self
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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. The task has the properties and behavior
|
|
|
|
* specified by the task_builder.
|
|
|
|
*/
|
2013-11-21 18:55:40 -06:00
|
|
|
pub fn spawn(mut self, f: proc()) {
|
2013-07-17 16:41:50 -05:00
|
|
|
let gen_body = self.gen_body.take();
|
2013-04-18 20:22:04 -05:00
|
|
|
let f = match gen_body {
|
2014-01-06 12:26:11 -06:00
|
|
|
Some(gen) => gen(f),
|
|
|
|
None => f
|
2013-04-18 20:22:04 -05:00
|
|
|
};
|
2013-12-12 20:01:59 -06:00
|
|
|
let t: ~Task = Local::take();
|
2014-01-06 12:26:11 -06:00
|
|
|
t.spawn_sibling(self.opts, f);
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2013-05-03 15:21:33 -05:00
|
|
|
|
2012-11-28 18:20:41 -06:00
|
|
|
/**
|
|
|
|
* Execute a function in another task and return either the return value
|
|
|
|
* of the function or result::err.
|
|
|
|
*
|
|
|
|
* # Return value
|
|
|
|
*
|
|
|
|
* If the function executed successfully then try returns result::ok
|
|
|
|
* containing the value returned by the function. If the function fails
|
|
|
|
* then try returns result::err containing nil.
|
|
|
|
*
|
|
|
|
* # Failure
|
|
|
|
* Fails if a future_result was already set for this task.
|
|
|
|
*/
|
2013-11-21 18:55:40 -06:00
|
|
|
pub fn try<T:Send>(mut self, f: proc() -> T) -> Result<T, ~Any> {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (po, ch) = Chan::new();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2013-10-18 03:38:46 -05:00
|
|
|
let result = self.future_result();
|
2013-05-03 15:21:33 -05:00
|
|
|
|
2014-01-26 21:42:26 -06:00
|
|
|
self.spawn(proc() {
|
2013-01-22 14:38:08 -06:00
|
|
|
ch.send(f());
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2013-05-03 15:21:33 -05:00
|
|
|
|
2013-10-18 03:38:46 -05:00
|
|
|
match result.recv() {
|
2013-10-11 16:20:34 -05:00
|
|
|
Ok(()) => Ok(po.recv()),
|
|
|
|
Err(cause) => Err(cause)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Task construction */
|
|
|
|
|
2013-12-13 18:26:02 -06:00
|
|
|
impl TaskOpts {
|
|
|
|
pub fn new() -> TaskOpts {
|
|
|
|
/*!
|
|
|
|
* The default task options
|
|
|
|
*/
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2013-12-13 18:26:02 -06:00
|
|
|
TaskOpts {
|
|
|
|
notify_chan: None,
|
|
|
|
name: None,
|
2014-01-06 12:26:11 -06:00
|
|
|
stack_size: None,
|
|
|
|
logger: None,
|
|
|
|
stdout: None,
|
|
|
|
stderr: None,
|
2013-12-13 18:26:02 -06:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Spawn convenience functions */
|
|
|
|
|
2013-05-03 15:21:33 -05:00
|
|
|
/// 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)`.
|
2013-11-18 15:25:09 -06:00
|
|
|
pub fn spawn(f: proc()) {
|
2013-11-21 18:55:40 -06:00
|
|
|
let task = task();
|
2013-05-03 15:21:33 -05:00
|
|
|
task.spawn(f)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2013-11-18 15:25:09 -06:00
|
|
|
pub fn try<T:Send>(f: proc() -> T) -> Result<T, ~Any> {
|
2012-11-28 18:20:41 -06:00
|
|
|
/*!
|
|
|
|
* Execute a function in another task and return either the return value
|
|
|
|
* of the function or result::err.
|
|
|
|
*
|
2014-02-13 00:02:09 -06:00
|
|
|
* This is equivalent to task().try.
|
2012-11-28 18:20:41 -06:00
|
|
|
*/
|
|
|
|
|
2013-11-21 18:55:40 -06:00
|
|
|
let task = task();
|
2013-05-03 15:21:33 -05:00
|
|
|
task.try(f)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Lifecycle functions */
|
|
|
|
|
2013-07-30 18:20:59 -05:00
|
|
|
/// Read the name of the current task.
|
2013-11-18 23:15:42 -06:00
|
|
|
pub fn with_task_name<U>(blk: |Option<&str>| -> U) -> U {
|
2013-07-30 18:20:59 -05:00
|
|
|
use rt::task::Task;
|
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
let mut task = Local::borrow(None::<Task>);
|
|
|
|
match task.get().name {
|
|
|
|
Some(ref name) => blk(Some(name.as_slice())),
|
|
|
|
None => blk(None)
|
2013-07-30 18:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-16 14:49:40 -05:00
|
|
|
pub fn deschedule() {
|
2012-11-28 18:20:41 -06:00
|
|
|
//! Yield control to the task scheduler
|
|
|
|
|
2013-07-08 20:06:17 -05:00
|
|
|
use rt::local::Local;
|
|
|
|
|
2013-08-01 01:12:20 -05:00
|
|
|
// FIXME(#7544): Optimize this, since we know we won't block.
|
2013-12-12 20:01:59 -06:00
|
|
|
let task: ~Task = Local::take();
|
|
|
|
task.yield_now();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn failing() -> bool {
|
|
|
|
//! True if the running task has failed
|
|
|
|
|
2013-05-19 18:50:21 -05:00
|
|
|
use rt::task::Task;
|
2013-04-22 19:15:31 -05:00
|
|
|
|
2013-12-03 21:18:58 -06:00
|
|
|
let mut local = Local::borrow(None::<Task>);
|
2013-12-12 20:01:59 -06:00
|
|
|
local.get().unwinder.unwinding()
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// The following 8 tests test the following 2^3 combinations:
|
|
|
|
// {un,}linked {un,}supervised failure propagation {up,down}wards.
|
|
|
|
|
|
|
|
// !!! These tests are dangerous. If Something is buggy, they will hang, !!!
|
|
|
|
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
|
|
|
|
|
2013-07-30 18:20:59 -05:00
|
|
|
#[test]
|
|
|
|
fn test_unnamed_task() {
|
2014-01-26 21:42:26 -06:00
|
|
|
spawn(proc() {
|
2013-12-12 23:38:57 -06:00
|
|
|
with_task_name(|name| {
|
|
|
|
assert!(name.is_none());
|
|
|
|
})
|
2014-01-26 21:42:26 -06:00
|
|
|
})
|
2013-07-30 18:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-10-05 14:01:58 -05:00
|
|
|
fn test_owned_named_task() {
|
2014-02-13 00:02:09 -06:00
|
|
|
task().named(~"ada lovelace").spawn(proc() {
|
2013-12-12 23:38:57 -06:00
|
|
|
with_task_name(|name| {
|
|
|
|
assert!(name.unwrap() == "ada lovelace");
|
|
|
|
})
|
2014-01-26 21:42:26 -06:00
|
|
|
})
|
2013-07-30 18:20:59 -05:00
|
|
|
}
|
|
|
|
|
2013-10-05 14:01:58 -05:00
|
|
|
#[test]
|
|
|
|
fn test_static_named_task() {
|
2014-02-13 00:02:09 -06:00
|
|
|
task().named("ada lovelace").spawn(proc() {
|
2013-12-12 23:38:57 -06:00
|
|
|
with_task_name(|name| {
|
|
|
|
assert!(name.unwrap() == "ada lovelace");
|
|
|
|
})
|
2014-01-26 21:42:26 -06:00
|
|
|
})
|
2013-10-05 14:01:58 -05:00
|
|
|
}
|
|
|
|
|
2013-10-05 14:23:24 -05:00
|
|
|
#[test]
|
|
|
|
fn test_send_named_task() {
|
2014-02-13 00:02:09 -06:00
|
|
|
task().named("ada lovelace".into_maybe_owned()).spawn(proc() {
|
2013-12-12 23:38:57 -06:00
|
|
|
with_task_name(|name| {
|
|
|
|
assert!(name.unwrap() == "ada lovelace");
|
|
|
|
})
|
2014-01-26 21:42:26 -06:00
|
|
|
})
|
2013-10-05 14:23:24 -05:00
|
|
|
}
|
|
|
|
|
2012-11-28 18:20:41 -06:00
|
|
|
#[test]
|
|
|
|
fn test_run_basic() {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (po, ch) = Chan::new();
|
2014-01-26 21:42:26 -06:00
|
|
|
task().spawn(proc() {
|
2013-01-22 14:38:08 -06:00
|
|
|
ch.send(());
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2013-01-22 14:38:08 -06:00
|
|
|
po.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-02-13 00:02:09 -06:00
|
|
|
fn test_with_wrapper() {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (po, ch) = Chan::new();
|
2014-02-13 00:02:09 -06:00
|
|
|
task().with_wrapper(proc(body) {
|
2013-12-03 18:44:16 -06:00
|
|
|
let ch = ch;
|
2013-11-22 01:36:52 -06:00
|
|
|
let result: proc() = proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
body();
|
2013-01-22 14:38:08 -06:00
|
|
|
ch.send(());
|
2013-03-01 16:32:37 -06:00
|
|
|
};
|
|
|
|
result
|
2014-02-13 00:02:09 -06:00
|
|
|
}).spawn(proc() { });
|
2013-01-22 14:38:08 -06:00
|
|
|
po.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_future_result() {
|
2013-05-07 19:57:58 -05:00
|
|
|
let mut builder = task();
|
2013-10-18 03:38:46 -05:00
|
|
|
let result = builder.future_result();
|
2014-01-26 21:42:26 -06:00
|
|
|
builder.spawn(proc() {});
|
2013-10-11 16:20:34 -05:00
|
|
|
assert!(result.recv().is_ok());
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2013-05-07 19:57:58 -05:00
|
|
|
let mut builder = task();
|
2013-10-18 03:38:46 -05:00
|
|
|
let result = builder.future_result();
|
2014-01-26 21:42:26 -06:00
|
|
|
builder.spawn(proc() {
|
2013-10-21 15:08:31 -05:00
|
|
|
fail!();
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2013-10-11 16:20:34 -05:00
|
|
|
assert!(result.recv().is_err());
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2013-08-19 17:40:37 -05:00
|
|
|
#[test] #[should_fail]
|
2012-11-28 18:20:41 -06:00
|
|
|
fn test_back_to_the_future_result() {
|
2013-05-07 19:57:58 -05:00
|
|
|
let mut builder = task();
|
2013-10-18 03:38:46 -05:00
|
|
|
builder.future_result();
|
|
|
|
builder.future_result();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_try_success() {
|
2014-01-26 21:42:26 -06:00
|
|
|
match try(proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
~"Success!"
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2012-11-28 18:20:41 -06:00
|
|
|
result::Ok(~"Success!") => (),
|
2013-10-21 15:08:31 -05:00
|
|
|
_ => fail!()
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_try_fail() {
|
2014-01-26 21:42:26 -06:00
|
|
|
match try(proc() {
|
2013-10-21 15:08:31 -05:00
|
|
|
fail!()
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-11 16:20:34 -05:00
|
|
|
result::Err(_) => (),
|
2013-10-21 15:08:31 -05:00
|
|
|
result::Ok(()) => fail!()
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_spawn_sched() {
|
2013-12-12 23:38:57 -06:00
|
|
|
use clone::Clone;
|
|
|
|
|
Rewrite channels yet again for upgradeability
This, the Nth rewrite of channels, is not a rewrite of the core logic behind
channels, but rather their API usage. In the past, we had the distinction
between oneshot, stream, and shared channels, but the most recent rewrite
dropped oneshots in favor of streams and shared channels.
This distinction of stream vs shared has shown that it's not quite what we'd
like either, and this moves the `std::comm` module in the direction of "one
channel to rule them all". There now remains only one Chan and one Port.
This new channel is actually a hybrid oneshot/stream/shared channel under the
hood in order to optimize for the use cases in question. Additionally, this also
reduces the cognitive burden of having to choose between a Chan or a SharedChan
in an API.
My simple benchmarks show no reduction in efficiency over the existing channels
today, and a 3x improvement in the oneshot case. I sadly don't have a
pre-last-rewrite compiler to test out the old old oneshots, but I would imagine
that the performance is comparable, but slightly slower (due to atomic reference
counting).
This commit also brings the bonus bugfix to channels that the pending queue of
messages are all dropped when a Port disappears rather then when both the Port
and the Chan disappear.
2014-01-08 20:31:48 -06:00
|
|
|
let (po, ch) = Chan::new();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
Rewrite channels yet again for upgradeability
This, the Nth rewrite of channels, is not a rewrite of the core logic behind
channels, but rather their API usage. In the past, we had the distinction
between oneshot, stream, and shared channels, but the most recent rewrite
dropped oneshots in favor of streams and shared channels.
This distinction of stream vs shared has shown that it's not quite what we'd
like either, and this moves the `std::comm` module in the direction of "one
channel to rule them all". There now remains only one Chan and one Port.
This new channel is actually a hybrid oneshot/stream/shared channel under the
hood in order to optimize for the use cases in question. Additionally, this also
reduces the cognitive burden of having to choose between a Chan or a SharedChan
in an API.
My simple benchmarks show no reduction in efficiency over the existing channels
today, and a 3x improvement in the oneshot case. I sadly don't have a
pre-last-rewrite compiler to test out the old old oneshots, but I would imagine
that the performance is comparable, but slightly slower (due to atomic reference
counting).
This commit also brings the bonus bugfix to channels that the pending queue of
messages are all dropped when a Port disappears rather then when both the Port
and the Chan disappear.
2014-01-08 20:31:48 -06:00
|
|
|
fn f(i: int, ch: Chan<()>) {
|
2013-12-12 23:38:57 -06:00
|
|
|
let ch = ch.clone();
|
2014-01-26 21:42:26 -06:00
|
|
|
spawn(proc() {
|
2014-01-19 02:21:14 -06:00
|
|
|
if i == 0 {
|
2013-01-22 14:38:08 -06:00
|
|
|
ch.send(());
|
2012-11-28 18:20:41 -06:00
|
|
|
} else {
|
2013-12-12 23:38:57 -06:00
|
|
|
f(i - 1, ch);
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
}
|
|
|
|
f(10, ch);
|
2013-01-22 14:38:08 -06:00
|
|
|
po.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-01-08 21:46:12 -06:00
|
|
|
fn test_spawn_sched_childs_on_default_sched() {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (po, ch) = Chan::new();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-01-26 21:42:26 -06:00
|
|
|
spawn(proc() {
|
2013-12-03 18:44:16 -06:00
|
|
|
let ch = ch;
|
2014-01-26 21:42:26 -06:00
|
|
|
spawn(proc() {
|
2013-01-22 14:38:08 -06:00
|
|
|
ch.send(());
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2013-01-22 14:38:08 -06:00
|
|
|
po.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2013-11-18 23:15:42 -06:00
|
|
|
fn avoid_copying_the_body(spawnfn: |v: proc()|) {
|
2013-12-05 20:19:06 -06:00
|
|
|
let (p, ch) = Chan::<uint>::new();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
let x = ~1;
|
2014-02-14 17:42:01 -06:00
|
|
|
let x_in_parent = (&*x) as *int as uint;
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-01-26 21:42:26 -06:00
|
|
|
spawnfn(proc() {
|
2014-02-14 17:42:01 -06:00
|
|
|
let x_in_child = (&*x) as *int as uint;
|
2013-01-22 14:38:08 -06:00
|
|
|
ch.send(x_in_child);
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2013-01-22 14:38:08 -06:00
|
|
|
let x_in_child = p.recv();
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(x_in_parent, x_in_child);
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_avoid_copying_the_body_spawn() {
|
|
|
|
avoid_copying_the_body(spawn);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_avoid_copying_the_body_task_spawn() {
|
2013-11-21 19:23:21 -06:00
|
|
|
avoid_copying_the_body(|f| {
|
2013-11-21 18:55:40 -06:00
|
|
|
let builder = task();
|
2014-01-26 21:42:26 -06:00
|
|
|
builder.spawn(proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
f();
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2013-11-21 19:23:21 -06:00
|
|
|
})
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_avoid_copying_the_body_try() {
|
2013-11-21 19:23:21 -06:00
|
|
|
avoid_copying_the_body(|f| {
|
2014-01-30 16:10:53 -06:00
|
|
|
let _ = try(proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
f()
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2013-11-21 19:23:21 -06:00
|
|
|
})
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_child_doesnt_ref_parent() {
|
|
|
|
// If the child refcounts the parent task, this will stack overflow when
|
|
|
|
// climbing the task tree to dereference each ancestor. (See #1789)
|
|
|
|
// (well, it would if the constant were 8000+ - I lowered it to be more
|
|
|
|
// valgrind-friendly. try this at home, instead..!)
|
2013-03-22 16:00:15 -05:00
|
|
|
static generations: uint = 16;
|
2013-11-18 15:25:09 -06:00
|
|
|
fn child_no(x: uint) -> proc() {
|
2013-11-22 01:36:52 -06:00
|
|
|
return proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
if x < generations {
|
2014-02-13 00:02:09 -06:00
|
|
|
task().spawn(child_no(x+1));
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-13 00:02:09 -06:00
|
|
|
task().spawn(child_no(0));
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2013-04-18 20:38:12 -05:00
|
|
|
#[test]
|
|
|
|
fn test_simple_newsched_spawn() {
|
2013-12-12 23:38:57 -06:00
|
|
|
spawn(proc()())
|
2013-04-18 20:38:12 -05:00
|
|
|
}
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2013-10-11 16:20:34 -05:00
|
|
|
#[test]
|
2013-10-27 14:12:40 -05:00
|
|
|
fn test_try_fail_message_static_str() {
|
2014-01-26 21:42:26 -06:00
|
|
|
match try(proc() {
|
2013-10-11 16:20:34 -05:00
|
|
|
fail!("static string");
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-27 14:12:40 -05:00
|
|
|
Err(e) => {
|
|
|
|
type T = &'static str;
|
|
|
|
assert!(e.is::<T>());
|
|
|
|
assert_eq!(*e.move::<T>().unwrap(), "static string");
|
|
|
|
}
|
|
|
|
Ok(()) => fail!()
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-10-27 14:12:40 -05:00
|
|
|
fn test_try_fail_message_owned_str() {
|
2014-01-26 21:42:26 -06:00
|
|
|
match try(proc() {
|
2013-10-11 16:20:34 -05:00
|
|
|
fail!(~"owned string");
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-27 14:12:40 -05:00
|
|
|
Err(e) => {
|
|
|
|
type T = ~str;
|
|
|
|
assert!(e.is::<T>());
|
|
|
|
assert_eq!(*e.move::<T>().unwrap(), ~"owned string");
|
|
|
|
}
|
|
|
|
Ok(()) => fail!()
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-10-27 14:12:40 -05:00
|
|
|
fn test_try_fail_message_any() {
|
2014-01-26 21:42:26 -06:00
|
|
|
match try(proc() {
|
2013-10-11 16:20:34 -05:00
|
|
|
fail!(~413u16 as ~Any);
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-27 14:12:40 -05:00
|
|
|
Err(e) => {
|
|
|
|
type T = ~Any;
|
|
|
|
assert!(e.is::<T>());
|
|
|
|
let any = e.move::<T>().unwrap();
|
|
|
|
assert!(any.is::<u16>());
|
|
|
|
assert_eq!(*any.move::<u16>().unwrap(), 413u16);
|
|
|
|
}
|
|
|
|
Ok(()) => fail!()
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-10-27 14:12:40 -05:00
|
|
|
fn test_try_fail_message_unit_struct() {
|
2013-10-11 16:20:34 -05:00
|
|
|
struct Juju;
|
|
|
|
|
2014-01-26 21:42:26 -06:00
|
|
|
match try(proc() {
|
2013-10-27 14:12:40 -05:00
|
|
|
fail!(Juju)
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-11 16:20:34 -05:00
|
|
|
Err(ref e) if e.is::<Juju>() => {}
|
|
|
|
Err(_) | Ok(()) => fail!()
|
|
|
|
}
|
|
|
|
}
|