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
|
|
|
*
|
2014-03-09 16:58:32 -05:00
|
|
|
* An executing Rust program consists of a collection of tasks, each with their
|
|
|
|
* own stack, and sole ownership of their allocated heap data. Tasks communicate
|
|
|
|
* with each other using channels (see `std::comm` for more info about how
|
|
|
|
* communication works).
|
2012-11-28 18:20:41 -06:00
|
|
|
*
|
2014-03-09 16:58:32 -05:00
|
|
|
* Failure in one task does not propagate to any others (not to parent, not to
|
|
|
|
* child). Failure propagation is instead handled by using the channel send()
|
|
|
|
* and recv() methods which will fail if the other end has hung up already.
|
2013-09-27 16:22:16 -05:00
|
|
|
*
|
|
|
|
* Task Scheduling:
|
|
|
|
*
|
2014-03-09 16:58:32 -05:00
|
|
|
* By default, every task is created with the same "flavor" as the calling task.
|
|
|
|
* This flavor refers to the scheduling mode, with two possibilities currently
|
|
|
|
* being 1:1 and M:N modes. Green (M:N) tasks are cooperatively scheduled and
|
|
|
|
* native (1:1) tasks are scheduled by the OS kernel.
|
2012-11-28 18:20:41 -06:00
|
|
|
*
|
|
|
|
* # Example
|
|
|
|
*
|
2014-03-09 16:58:32 -05:00
|
|
|
* ```rust
|
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;
|
2014-03-09 16:58:32 -05:00
|
|
|
use comm::{Sender, Receiver, channel};
|
2014-06-03 22:09:39 -05:00
|
|
|
use io::{Writer, stdio};
|
2014-01-26 04:42:46 -06:00
|
|
|
use kinds::{Send, marker};
|
2013-12-12 20:01:59 -06:00
|
|
|
use option::{None, Some, Option};
|
2014-05-05 20:56:44 -05:00
|
|
|
use owned::Box;
|
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;
|
2014-06-03 22:09:39 -05:00
|
|
|
use rt::task;
|
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
|
|
|
|
2014-05-13 16:58:29 -05:00
|
|
|
#[cfg(test)] use any::AnyRefExt;
|
|
|
|
#[cfg(test)] use owned::AnyOwnExt;
|
2013-10-11 16:20:34 -05:00
|
|
|
#[cfg(test)] use result;
|
2014-05-01 01:06:36 -05:00
|
|
|
#[cfg(test)] use str::StrAllocating;
|
2014-05-22 18:57:53 -05:00
|
|
|
#[cfg(test)] use string::String;
|
2013-03-26 15:38:07 -05:00
|
|
|
|
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
|
2014-06-03 22:09:39 -05:00
|
|
|
pub notify_chan: Option<Sender<task::Result>>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// A name for the task-to-be, for identification in failure messages
|
2014-03-27 17:09:47 -05:00
|
|
|
pub name: Option<SendStr>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// The size of the stack for the spawned task
|
2014-03-27 17:09:47 -05:00
|
|
|
pub stack_size: Option<uint>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Task-local stdout
|
2014-06-14 13:03:34 -05:00
|
|
|
pub stdout: Option<Box<Writer + Send>>,
|
2014-02-13 00:02:09 -06:00
|
|
|
/// Task-local stderr
|
2014-06-14 13:03:34 -05:00
|
|
|
pub stderr: Option<Box<Writer + Send>>,
|
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
|
2014-03-27 17:09:47 -05:00
|
|
|
pub opts: TaskOpts,
|
2014-06-14 13:03:34 -05:00
|
|
|
gen_body: Option<proc(v: proc(): Send): Send -> proc(): Send>,
|
2014-06-06 08:51:42 -05:00
|
|
|
nocopy: marker::NoCopy,
|
2012-12-05 17:06:54 -06:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-04-21 23:19:59 -05:00
|
|
|
impl TaskBuilder {
|
|
|
|
/// Generate the base configuration for spawning a task, off of which more
|
|
|
|
/// configuration methods can be chained.
|
|
|
|
pub fn new() -> TaskBuilder {
|
|
|
|
TaskBuilder {
|
|
|
|
opts: TaskOpts::new(),
|
|
|
|
gen_body: None,
|
2014-06-06 08:51:42 -05:00
|
|
|
nocopy: marker::NoCopy,
|
2014-04-21 23:19:59 -05:00
|
|
|
}
|
2012-12-05 17:06:54 -06:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
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.
|
2014-06-03 22:09:39 -05:00
|
|
|
pub fn future_result(&mut self) -> Receiver<task::Result> {
|
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.
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
// Reconfigure self to use a notify channel.
|
2014-03-09 16:58:32 -05:00
|
|
|
self.opts.notify_chan = Some(tx);
|
2013-10-18 03:38:46 -05:00
|
|
|
|
2014-03-09 16:58:32 -05:00
|
|
|
rx
|
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-03-08 20:21:49 -06:00
|
|
|
pub fn with_wrapper(mut self,
|
2014-06-14 13:03:34 -05:00
|
|
|
wrapper: proc(v: proc(): Send): Send -> proc(): Send)
|
2014-03-08 20:21:49 -06:00
|
|
|
-> TaskBuilder
|
|
|
|
{
|
|
|
|
self.gen_body = match self.gen_body.take() {
|
|
|
|
Some(prev) => Some(proc(body) { wrapper(prev(body)) }),
|
|
|
|
None => Some(wrapper)
|
2013-04-18 20:22:04 -05:00
|
|
|
};
|
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.
|
|
|
|
*/
|
2014-06-14 13:03:34 -05:00
|
|
|
pub fn spawn(mut self, f: proc(): Send) {
|
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
|
|
|
};
|
2014-06-04 12:54:35 -05:00
|
|
|
let t: Box<Task> = match Local::try_take() {
|
|
|
|
Some(t) => t,
|
|
|
|
None => fail!("need a local task to spawn a new task"),
|
|
|
|
};
|
2014-06-03 22:09:39 -05:00
|
|
|
let TaskOpts { notify_chan, name, stack_size, stdout, stderr } = self.opts;
|
|
|
|
|
|
|
|
let opts = task::TaskOpts {
|
|
|
|
on_exit: notify_chan.map(|c| proc(r) c.send(r)),
|
|
|
|
name: name,
|
|
|
|
stack_size: stack_size,
|
|
|
|
};
|
|
|
|
if stdout.is_some() || stderr.is_some() {
|
|
|
|
t.spawn_sibling(opts, proc() {
|
2014-06-04 02:01:40 -05:00
|
|
|
let _ = stdout.map(stdio::set_stdout);
|
|
|
|
let _ = stderr.map(stdio::set_stderr);
|
2014-06-03 22:09:39 -05:00
|
|
|
f();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
t.spawn_sibling(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.
|
|
|
|
*/
|
2014-06-14 13:03:34 -05:00
|
|
|
pub fn try<T: Send>(mut self, f: proc(): Send -> T)
|
|
|
|
-> Result<T, Box<Any + Send>> {
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel();
|
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() {
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.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() {
|
2014-03-09 16:58:32 -05:00
|
|
|
Ok(()) => Ok(rx.recv()),
|
2013-10-11 16:20:34 -05:00
|
|
|
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,
|
|
|
|
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.
|
|
|
|
///
|
2014-04-21 23:19:59 -05:00
|
|
|
/// This function is equivalent to `TaskBuilder::new().spawn(f)`.
|
2014-06-14 13:03:34 -05:00
|
|
|
pub fn spawn(f: proc(): Send) {
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().spawn(f)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-04-21 23:19:59 -05:00
|
|
|
/// Execute a function in another task and return either the return value of
|
|
|
|
/// the function or an error if the task failed
|
|
|
|
///
|
|
|
|
/// This is equivalent to TaskBuilder::new().try
|
2014-06-14 13:03:34 -05:00
|
|
|
pub fn try<T: Send>(f: proc(): Send -> T) -> Result<T, Box<Any + Send>> {
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().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;
|
|
|
|
|
2014-04-13 16:39:04 -05:00
|
|
|
let task = Local::borrow(None::<Task>);
|
|
|
|
match task.name {
|
2013-12-12 20:01:59 -06:00
|
|
|
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.
|
2014-05-05 20:56:44 -05:00
|
|
|
let task: Box<Task> = Local::take();
|
2013-12-12 20:01:59 -06:00
|
|
|
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;
|
2014-04-13 16:39:04 -05:00
|
|
|
Local::borrow(None::<Task>).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-05-25 05:10:11 -05:00
|
|
|
TaskBuilder::new().named("ada lovelace".to_string()).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-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().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-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().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() {
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel();
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().spawn(proc() {
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.send(());
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2014-03-09 16:58:32 -05:00
|
|
|
rx.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-02-13 00:02:09 -06:00
|
|
|
fn test_with_wrapper() {
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel();
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().with_wrapper(proc(body) {
|
2014-06-14 13:03:34 -05:00
|
|
|
let result: proc(): Send = proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
body();
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.send(());
|
2013-03-01 16:32:37 -06:00
|
|
|
};
|
|
|
|
result
|
2014-02-13 00:02:09 -06:00
|
|
|
}).spawn(proc() { });
|
2014-03-09 16:58:32 -05:00
|
|
|
rx.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_future_result() {
|
2014-04-21 23:19:59 -05:00
|
|
|
let mut builder = TaskBuilder::new();
|
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
|
|
|
|
2014-04-21 23:19:59 -05:00
|
|
|
let mut builder = TaskBuilder::new();
|
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() {
|
2014-04-21 23:19:59 -05:00
|
|
|
let mut builder = TaskBuilder::new();
|
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() {
|
2014-05-25 05:10:11 -05:00
|
|
|
"Success!".to_string()
|
2014-03-07 15:15:50 -06:00
|
|
|
}).as_ref().map(|s| s.as_slice()) {
|
|
|
|
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;
|
|
|
|
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-03-09 16:58:32 -05:00
|
|
|
fn f(i: int, tx: Sender<()>) {
|
|
|
|
let tx = tx.clone();
|
2014-01-26 21:42:26 -06:00
|
|
|
spawn(proc() {
|
2014-01-19 02:21:14 -06:00
|
|
|
if i == 0 {
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.send(());
|
2012-11-28 18:20:41 -06:00
|
|
|
} else {
|
2014-03-09 16:58:32 -05:00
|
|
|
f(i - 1, tx);
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
|
|
|
}
|
2014-03-09 16:58:32 -05:00
|
|
|
f(10, tx);
|
|
|
|
rx.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() {
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-01-26 21:42:26 -06:00
|
|
|
spawn(proc() {
|
|
|
|
spawn(proc() {
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.send(());
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-03-09 16:58:32 -05:00
|
|
|
rx.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2014-06-14 13:03:34 -05:00
|
|
|
fn avoid_copying_the_body(spawnfn: |v: proc(): Send|) {
|
2014-03-09 16:58:32 -05:00
|
|
|
let (tx, rx) = channel::<uint>();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-04-25 03:08:02 -05:00
|
|
|
let x = box 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;
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.send(x_in_child);
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-03-09 16:58:32 -05:00
|
|
|
let x_in_child = rx.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| {
|
2014-04-21 23:19:59 -05:00
|
|
|
let builder = TaskBuilder::new();
|
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;
|
2014-06-14 13:03:34 -05:00
|
|
|
fn child_no(x: uint) -> proc(): Send {
|
2013-11-22 01:36:52 -06:00
|
|
|
return proc() {
|
2012-11-28 18:20:41 -06:00
|
|
|
if x < generations {
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().spawn(child_no(x+1));
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().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() {
|
2014-05-25 05:17:19 -05:00
|
|
|
fail!("owned string".to_string());
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-27 14:12:40 -05:00
|
|
|
Err(e) => {
|
2014-05-22 18:57:53 -05:00
|
|
|
type T = String;
|
2013-10-27 14:12:40 -05:00
|
|
|
assert!(e.is::<T>());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(*e.move::<T>().unwrap(), "owned string".to_string());
|
2013-10-27 14:12:40 -05:00
|
|
|
}
|
|
|
|
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() {
|
2014-06-14 13:03:34 -05:00
|
|
|
fail!(box 413u16 as Box<Any + Send>);
|
2014-01-26 21:42:26 -06:00
|
|
|
}) {
|
2013-10-27 14:12:40 -05:00
|
|
|
Err(e) => {
|
2014-06-14 13:03:34 -05:00
|
|
|
type T = Box<Any + Send>;
|
2013-10-27 14:12:40 -05:00
|
|
|
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!()
|
|
|
|
}
|
|
|
|
}
|