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.
|
|
|
|
|
2014-06-19 17:24:21 -05:00
|
|
|
//! Task creation
|
2014-06-17 16:48:54 -05:00
|
|
|
//!
|
2014-06-19 17:24:21 -05:00
|
|
|
//! An executing Rust program consists of a collection of tasks, each
|
2014-11-14 16:38:41 -06:00
|
|
|
//! with their own stack and local state.
|
2014-06-17 16:48:54 -05:00
|
|
|
//!
|
2014-06-19 17:24:21 -05:00
|
|
|
//! Tasks generally have their memory *isolated* from each other by
|
|
|
|
//! virtue of Rust's owned types (which of course may only be owned by
|
|
|
|
//! a single task at a time). Communication between tasks is primarily
|
|
|
|
//! done through [channels](../../std/comm/index.html), Rust's
|
|
|
|
//! message-passing types, though [other forms of task
|
|
|
|
//! synchronization](../../std/sync/index.html) are often employed to
|
|
|
|
//! achieve particular performance goals. In particular, types that
|
|
|
|
//! are guaranteed to be threadsafe are easily shared between threads
|
|
|
|
//! using the atomically-reference-counted container,
|
|
|
|
//! [`Arc`](../../std/sync/struct.Arc.html).
|
|
|
|
//!
|
2014-10-09 14:17:22 -05:00
|
|
|
//! Fatal logic errors in Rust cause *task panic*, during which
|
2014-06-19 17:24:21 -05:00
|
|
|
//! a task will unwind the stack, running destructors and freeing
|
2014-10-09 14:17:22 -05:00
|
|
|
//! owned resources. Task panic is unrecoverable from within
|
|
|
|
//! the panicking task (i.e. there is no 'try/catch' in Rust), but
|
|
|
|
//! panic may optionally be detected from a different task. If
|
|
|
|
//! the main task panics the application will exit with a non-zero
|
2014-06-19 17:24:21 -05:00
|
|
|
//! exit code.
|
2014-06-17 16:48:54 -05:00
|
|
|
//!
|
2014-12-10 12:54:56 -06:00
|
|
|
//! # Examples
|
2014-06-17 16:48:54 -05:00
|
|
|
//!
|
|
|
|
//! ```rust
|
2014-11-26 09:10:52 -06:00
|
|
|
//! spawn(move|| {
|
2014-06-17 16:48:54 -05:00
|
|
|
//! println!("Hello, World!");
|
|
|
|
//! })
|
|
|
|
//! ```
|
2012-11-18 19:56:50 -06:00
|
|
|
|
2014-11-10 16:04:33 -06:00
|
|
|
#![unstable = "The task spawning model will be changed as part of runtime reform, and the module \
|
|
|
|
will likely be renamed from `task` to `thread`."]
|
2014-06-30 19:22:40 -05:00
|
|
|
|
2013-12-12 20:01:59 -06:00
|
|
|
use any::Any;
|
2014-11-21 16:10:42 -06:00
|
|
|
use borrow::IntoCow;
|
|
|
|
use boxed::Box;
|
2014-06-17 16:48:54 -05:00
|
|
|
use comm::channel;
|
2014-11-26 09:10:52 -06:00
|
|
|
use core::ops::FnOnce;
|
2014-06-03 22:09:39 -05:00
|
|
|
use io::{Writer, stdio};
|
2014-01-26 04:42:46 -06:00
|
|
|
use kinds::{Send, marker};
|
2014-11-28 10:57:41 -06:00
|
|
|
use option::Option;
|
|
|
|
use option::Option::{None, Some};
|
2014-06-17 16:48:54 -05:00
|
|
|
use result::Result;
|
2014-11-14 18:30:16 -06:00
|
|
|
use rustrt::local::Local;
|
|
|
|
use rustrt::task::Task;
|
2014-11-21 16:10:42 -06:00
|
|
|
use rustrt::task;
|
2014-11-27 13:43:55 -06:00
|
|
|
use str::SendStr;
|
2014-11-15 19:38:03 -06:00
|
|
|
use string::{String, ToString};
|
2014-11-26 09:10:52 -06:00
|
|
|
use thunk::{Thunk};
|
2014-06-17 16:48:54 -05:00
|
|
|
use sync::Future;
|
2012-11-18 19:56:50 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// The task builder type.
|
|
|
|
///
|
|
|
|
/// Provides detailed control over the properties and behavior of new tasks.
|
|
|
|
|
2012-11-28 18:20:41 -06:00
|
|
|
// 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.
|
2014-11-14 16:38:41 -06:00
|
|
|
pub struct TaskBuilder {
|
2014-10-09 14:17:22 -05:00
|
|
|
// A name for the task-to-be, for identification in panic messages
|
2014-06-17 16:48:54 -05:00
|
|
|
name: Option<SendStr>,
|
|
|
|
// The size of the stack for the spawned task
|
|
|
|
stack_size: Option<uint>,
|
|
|
|
// Task-local stdout
|
|
|
|
stdout: Option<Box<Writer + Send>>,
|
|
|
|
// Task-local stderr
|
|
|
|
stderr: Option<Box<Writer + Send>>,
|
|
|
|
// Optionally wrap the eventual task body
|
2014-11-26 09:10:52 -06:00
|
|
|
gen_body: Option<Thunk<Thunk, Thunk>>,
|
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-11-14 16:38:41 -06:00
|
|
|
impl TaskBuilder {
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Generate the base configuration for spawning a task, off of which more
|
|
|
|
/// configuration methods can be chained.
|
2014-11-14 16:38:41 -06:00
|
|
|
pub fn new() -> TaskBuilder {
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder {
|
2014-06-17 16:48:54 -05:00
|
|
|
name: None,
|
|
|
|
stack_size: None,
|
|
|
|
stdout: None,
|
|
|
|
stderr: None,
|
2014-04-21 23:19:59 -05:00
|
|
|
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
|
|
|
}
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-11-14 16:38:41 -06:00
|
|
|
impl TaskBuilder {
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Name the task-to-be. Currently the name is used for identification
|
2014-10-09 14:17:22 -05:00
|
|
|
/// only in panic messages.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[unstable = "IntoMaybeOwned will probably change."]
|
2014-11-21 16:10:42 -06:00
|
|
|
pub fn named<T: IntoCow<'static, String, str>>(mut self, name: T) -> TaskBuilder {
|
|
|
|
self.name = Some(name.into_cow());
|
2014-06-17 16:48:54 -05:00
|
|
|
self
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Set the size of the stack for the new task.
|
2014-11-14 16:38:41 -06:00
|
|
|
pub fn stack_size(mut self, size: uint) -> TaskBuilder {
|
2014-06-17 16:48:54 -05:00
|
|
|
self.stack_size = Some(size);
|
|
|
|
self
|
|
|
|
}
|
2013-10-18 03:38:46 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Redirect task-local stdout.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[experimental = "May not want to make stdio overridable here."]
|
2014-11-14 16:38:41 -06:00
|
|
|
pub fn stdout(mut self, stdout: Box<Writer + Send>) -> TaskBuilder {
|
2014-06-17 16:48:54 -05:00
|
|
|
self.stdout = Some(stdout);
|
|
|
|
self
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2013-05-03 15:21:33 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Redirect task-local stderr.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[experimental = "May not want to make stdio overridable here."]
|
2014-11-14 16:38:41 -06:00
|
|
|
pub fn stderr(mut self, stderr: Box<Writer + Send>) -> TaskBuilder {
|
2014-06-17 16:48:54 -05:00
|
|
|
self.stderr = Some(stderr);
|
2014-02-13 00:02:09 -06:00
|
|
|
self
|
2013-07-30 18:20:59 -05:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
// Where spawning actually happens (whether yielding a future or not)
|
2014-11-26 09:10:52 -06:00
|
|
|
fn spawn_internal(
|
|
|
|
self,
|
|
|
|
f: Thunk,
|
|
|
|
on_exit: Option<Thunk<task::Result>>)
|
|
|
|
{
|
2014-06-17 16:48:54 -05:00
|
|
|
let TaskBuilder {
|
2014-11-14 16:38:41 -06:00
|
|
|
name, stack_size, stdout, stderr, mut gen_body, nocopy: _
|
2014-06-17 16:48:54 -05:00
|
|
|
} = self;
|
2014-11-26 09:10:52 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
let f = match gen_body.take() {
|
2014-11-26 09:10:52 -06:00
|
|
|
Some(gen) => gen.invoke(f),
|
2014-01-06 12:26:11 -06:00
|
|
|
None => f
|
2013-04-18 20:22:04 -05:00
|
|
|
};
|
2014-11-26 09:10:52 -06:00
|
|
|
|
2014-06-03 22:09:39 -05:00
|
|
|
let opts = task::TaskOpts {
|
2014-06-17 16:48:54 -05:00
|
|
|
on_exit: on_exit,
|
2014-06-03 22:09:39 -05:00
|
|
|
name: name,
|
|
|
|
stack_size: stack_size,
|
|
|
|
};
|
|
|
|
if stdout.is_some() || stderr.is_some() {
|
2014-11-26 09:10:52 -06:00
|
|
|
Task::spawn(opts, move|:| {
|
2014-06-04 02:01:40 -05:00
|
|
|
let _ = stdout.map(stdio::set_stdout);
|
|
|
|
let _ = stderr.map(stdio::set_stderr);
|
2014-11-26 09:10:52 -06:00
|
|
|
f.invoke(());
|
|
|
|
});
|
2014-06-03 22:09:39 -05:00
|
|
|
} else {
|
2014-11-26 09:10:52 -06:00
|
|
|
Task::spawn(opts, move|:| f.invoke(()))
|
2014-06-03 22:09:39 -05:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2013-05-03 15:21:33 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Creates and executes a new child task.
|
|
|
|
///
|
|
|
|
/// Sets up a new task with its own call stack and schedules it to run
|
2014-11-26 09:10:52 -06:00
|
|
|
/// the provided function. The task has the properties and behavior
|
2014-06-17 16:48:54 -05:00
|
|
|
/// specified by the `TaskBuilder`.
|
2014-11-26 09:10:52 -06:00
|
|
|
pub fn spawn<F:FnOnce()+Send>(self, f: F) {
|
|
|
|
self.spawn_internal(Thunk::new(f), None)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
/// Execute a function in a newly-spawned task and return a future representing
|
2014-06-17 16:48:54 -05:00
|
|
|
/// the task's result. The task has the properties and behavior
|
|
|
|
/// specified by the `TaskBuilder`.
|
|
|
|
///
|
|
|
|
/// Taking the value of the future will block until the child task
|
|
|
|
/// terminates.
|
|
|
|
///
|
|
|
|
/// # Return value
|
|
|
|
///
|
2014-10-09 14:17:22 -05:00
|
|
|
/// If the child task executes successfully (without panicking) then the
|
2014-11-28 10:57:41 -06:00
|
|
|
/// future returns `result::Result::Ok` containing the value returned by the
|
|
|
|
/// function. If the child task panics then the future returns
|
|
|
|
/// `result::Result::Err` containing the argument to `panic!(...)` as an
|
|
|
|
/// `Any` trait object.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[experimental = "Futures are experimental."]
|
2014-11-26 09:10:52 -06:00
|
|
|
pub fn try_future<T:Send,F:FnOnce()->(T)+Send>(self, f: F)
|
|
|
|
-> Future<Result<T, Box<Any + Send>>> {
|
|
|
|
// currently, the on_exit fn provided by librustrt only works for unit
|
2014-06-17 16:48:54 -05:00
|
|
|
// results, so we use an additional side-channel to communicate the
|
|
|
|
// result.
|
|
|
|
|
|
|
|
let (tx_done, rx_done) = channel(); // signal that task has exited
|
|
|
|
let (tx_retv, rx_retv) = channel(); // return value from task
|
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
let on_exit: Thunk<task::Result> = Thunk::with_arg(move |: res: task::Result| {
|
|
|
|
let _ = tx_done.send_opt(res);
|
|
|
|
});
|
|
|
|
self.spawn_internal(Thunk::new(move |:| { let _ = tx_retv.send_opt(f()); }),
|
2014-06-17 16:48:54 -05:00
|
|
|
Some(on_exit));
|
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
Future::from_fn(move|:| {
|
2014-06-17 16:48:54 -05:00
|
|
|
rx_done.recv().map(|_| rx_retv.recv())
|
|
|
|
})
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Execute a function in a newly-spawnedtask and block until the task
|
2014-10-09 14:17:22 -05:00
|
|
|
/// completes or panics. Equivalent to `.try_future(f).unwrap()`.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[unstable = "Error type may change."]
|
2014-11-26 09:10:52 -06:00
|
|
|
pub fn try<T,F>(self, f: F) -> Result<T, Box<Any + Send>>
|
|
|
|
where F : FnOnce() -> T, F : Send, T : Send
|
|
|
|
{
|
2014-11-20 11:23:43 -06:00
|
|
|
self.try_future(f).into_inner()
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/* Convenience functions */
|
2012-11-28 18:20:41 -06:00
|
|
|
|
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-11-26 09:10:52 -06:00
|
|
|
pub fn spawn<F:FnOnce()+Send>(f: F) {
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().spawn(f)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Execute a function in a newly-spawned task and return either the return
|
2014-10-09 14:17:22 -05:00
|
|
|
/// value of the function or an error if the task panicked.
|
2014-04-21 23:19:59 -05:00
|
|
|
///
|
2014-06-17 16:48:54 -05:00
|
|
|
/// This is equivalent to `TaskBuilder::new().try`.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[unstable = "Error type may change."]
|
2014-11-26 09:10:52 -06:00
|
|
|
pub fn try<T,F>(f: F) -> Result<T, Box<Any + Send>>
|
|
|
|
where T : Send, F : FnOnce() -> T, F : Send
|
|
|
|
{
|
2014-04-21 23:19:59 -05:00
|
|
|
TaskBuilder::new().try(f)
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Execute a function in another task and return a future representing the
|
|
|
|
/// task's result.
|
|
|
|
///
|
|
|
|
/// This is equivalent to `TaskBuilder::new().try_future`.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[experimental = "Futures are experimental."]
|
2014-11-26 09:10:52 -06:00
|
|
|
pub fn try_future<T,F>(f: F) -> Future<Result<T, Box<Any + Send>>>
|
|
|
|
where T:Send, F:FnOnce()->T, F:Send
|
|
|
|
{
|
2014-06-17 16:48:54 -05:00
|
|
|
TaskBuilder::new().try_future(f)
|
|
|
|
}
|
|
|
|
|
2012-11-28 18:20:41 -06:00
|
|
|
/* Lifecycle functions */
|
|
|
|
|
2014-07-18 18:02:39 -05:00
|
|
|
/// Read the name of the current task.
|
|
|
|
#[stable]
|
|
|
|
pub fn name() -> Option<String> {
|
2014-11-14 18:30:16 -06:00
|
|
|
use rustrt::task::Task;
|
2014-07-18 18:02:39 -05:00
|
|
|
|
|
|
|
let task = Local::borrow(None::<Task>);
|
|
|
|
match task.name {
|
2014-11-27 13:43:55 -06:00
|
|
|
Some(ref name) => Some(name.to_string()),
|
2014-07-18 18:02:39 -05:00
|
|
|
None => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
/// Yield control to the task scheduler.
|
2014-07-18 18:02:39 -05:00
|
|
|
#[unstable = "Name will change."]
|
2013-08-16 14:49:40 -05:00
|
|
|
pub fn deschedule() {
|
2014-11-14 18:30:16 -06:00
|
|
|
use rustrt::task::Task;
|
2014-11-14 16:38:41 -06:00
|
|
|
Task::yield_now();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-10-09 14:17:22 -05:00
|
|
|
/// True if the running task is currently panicking (e.g. will return `true` inside a
|
|
|
|
/// destructor that is run while unwinding the stack after a call to `panic!()`).
|
2014-07-18 18:02:39 -05:00
|
|
|
#[unstable = "May move to a different module."]
|
2012-11-28 18:20:41 -06:00
|
|
|
pub fn failing() -> bool {
|
2014-11-14 18:30:16 -06:00
|
|
|
use rustrt::task::Task;
|
2014-04-13 16:39:04 -05:00
|
|
|
Local::borrow(None::<Task>).unwinder.unwinding()
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use any::{Any, AnyRefExt};
|
2014-11-21 16:10:42 -06:00
|
|
|
use borrow::IntoCow;
|
2014-07-10 16:19:17 -05:00
|
|
|
use boxed::BoxAny;
|
2014-11-21 16:10:42 -06:00
|
|
|
use prelude::*;
|
2014-11-28 10:57:41 -06:00
|
|
|
use result::Result::{Ok, Err};
|
2014-11-21 16:10:42 -06:00
|
|
|
use result;
|
2014-06-17 16:48:54 -05:00
|
|
|
use std::io::{ChanReader, ChanWriter};
|
2014-11-21 16:10:42 -06:00
|
|
|
use string::String;
|
2014-11-26 09:10:52 -06:00
|
|
|
use thunk::Thunk;
|
|
|
|
use prelude::*;
|
2014-06-17 16:48:54 -05:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
// !!! These tests are dangerous. If something is buggy, they will hang, !!!
|
|
|
|
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_unnamed_task() {
|
2014-11-26 09:10:52 -06:00
|
|
|
try(move|| {
|
2014-07-18 18:02:39 -05:00
|
|
|
assert!(name().is_none());
|
|
|
|
}).map_err(|_| ()).unwrap();
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2013-07-30 18:20:59 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_owned_named_task() {
|
2014-11-26 09:10:52 -06:00
|
|
|
TaskBuilder::new().named("ada lovelace".to_string()).try(move|| {
|
2014-11-27 18:45:47 -06:00
|
|
|
assert!(name().unwrap() == "ada lovelace");
|
2014-07-18 18:02:39 -05:00
|
|
|
}).map_err(|_| ()).unwrap();
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2013-07-30 18:20:59 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_static_named_task() {
|
2014-11-26 09:10:52 -06:00
|
|
|
TaskBuilder::new().named("ada lovelace").try(move|| {
|
2014-11-27 18:45:47 -06:00
|
|
|
assert!(name().unwrap() == "ada lovelace");
|
2014-07-18 18:02:39 -05:00
|
|
|
}).map_err(|_| ()).unwrap();
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2013-10-05 14:01:58 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_send_named_task() {
|
2014-11-26 09:10:52 -06:00
|
|
|
TaskBuilder::new().named("ada lovelace".into_cow()).try(move|| {
|
2014-11-27 18:45:47 -06:00
|
|
|
assert!(name().unwrap() == "ada lovelace");
|
2014-07-18 18:02:39 -05:00
|
|
|
}).map_err(|_| ()).unwrap();
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_run_basic() {
|
|
|
|
let (tx, rx) = channel();
|
2014-11-26 09:10:52 -06:00
|
|
|
TaskBuilder::new().spawn(move|| {
|
2014-03-09 16:58:32 -05:00
|
|
|
tx.send(());
|
2014-06-17 16:48:54 -05:00
|
|
|
});
|
|
|
|
rx.recv();
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_try_future() {
|
2014-11-26 09:10:52 -06:00
|
|
|
let result = TaskBuilder::new().try_future(move|| {});
|
2014-06-17 16:48:54 -05:00
|
|
|
assert!(result.unwrap().is_ok());
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
let result = TaskBuilder::new().try_future(move|| -> () {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!();
|
2014-06-17 16:48:54 -05:00
|
|
|
});
|
|
|
|
assert!(result.unwrap().is_err());
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_try_success() {
|
2014-11-26 09:10:52 -06:00
|
|
|
match try(move|| {
|
2014-06-17 16:48:54 -05:00
|
|
|
"Success!".to_string()
|
|
|
|
}).as_ref().map(|s| s.as_slice()) {
|
2014-11-28 10:57:41 -06:00
|
|
|
result::Result::Ok("Success!") => (),
|
2014-10-09 14:17:22 -05:00
|
|
|
_ => panic!()
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
2014-10-09 14:17:22 -05:00
|
|
|
fn test_try_panic() {
|
2014-11-26 09:10:52 -06:00
|
|
|
match try(move|| {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!()
|
2014-06-17 16:48:54 -05:00
|
|
|
}) {
|
2014-11-28 10:57:41 -06:00
|
|
|
result::Result::Err(_) => (),
|
|
|
|
result::Result::Ok(()) => panic!()
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
|
|
|
}
|
2013-12-12 23:38:57 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_spawn_sched() {
|
|
|
|
use clone::Clone;
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
let (tx, rx) = channel();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
fn f(i: int, tx: Sender<()>) {
|
|
|
|
let tx = tx.clone();
|
2014-11-26 09:10:52 -06:00
|
|
|
spawn(move|| {
|
2014-06-17 16:48:54 -05:00
|
|
|
if i == 0 {
|
|
|
|
tx.send(());
|
|
|
|
} else {
|
|
|
|
f(i - 1, tx);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
f(10, tx);
|
|
|
|
rx.recv();
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_spawn_sched_childs_on_default_sched() {
|
|
|
|
let (tx, rx) = channel();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
spawn(move|| {
|
|
|
|
spawn(move|| {
|
2014-06-17 16:48:54 -05:00
|
|
|
tx.send(());
|
|
|
|
});
|
2014-01-26 21:42:26 -06:00
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
rx.recv();
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-12-07 13:15:25 -06:00
|
|
|
fn avoid_copying_the_body<F>(spawnfn: F) where
|
2014-11-26 09:10:52 -06:00
|
|
|
F: FnOnce(Thunk),
|
2014-12-07 13:15:25 -06:00
|
|
|
{
|
2014-06-17 16:48:54 -05:00
|
|
|
let (tx, rx) = channel::<uint>();
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
let x = box 1;
|
2014-06-25 14:47:34 -05:00
|
|
|
let x_in_parent = (&*x) as *const int as uint;
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
spawnfn(Thunk::new(move|| {
|
2014-06-25 14:47:34 -05:00
|
|
|
let x_in_child = (&*x) as *const int as uint;
|
2014-06-17 16:48:54 -05:00
|
|
|
tx.send(x_in_child);
|
2014-11-26 09:10:52 -06:00
|
|
|
}));
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
let x_in_child = rx.recv();
|
|
|
|
assert_eq!(x_in_parent, x_in_child);
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_avoid_copying_the_body_spawn() {
|
2014-11-26 09:10:52 -06:00
|
|
|
avoid_copying_the_body(|t| spawn(move|| t.invoke(())));
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_avoid_copying_the_body_task_spawn() {
|
|
|
|
avoid_copying_the_body(|f| {
|
|
|
|
let builder = TaskBuilder::new();
|
2014-11-26 09:10:52 -06:00
|
|
|
builder.spawn(move|| f.invoke(()));
|
2014-06-17 16:48:54 -05:00
|
|
|
})
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_avoid_copying_the_body_try() {
|
|
|
|
avoid_copying_the_body(|f| {
|
2014-11-26 09:10:52 -06:00
|
|
|
let _ = try(move|| f.invoke(()));
|
2014-06-17 16:48:54 -05:00
|
|
|
})
|
|
|
|
}
|
2012-11-28 18:20:41 -06:00
|
|
|
|
2014-06-17 16:48:54 -05: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..!)
|
2014-09-12 20:55:37 -05:00
|
|
|
static GENERATIONS: uint = 16;
|
2014-11-26 09:10:52 -06:00
|
|
|
fn child_no(x: uint) -> Thunk {
|
|
|
|
return Thunk::new(move|| {
|
2014-09-12 20:55:37 -05:00
|
|
|
if x < GENERATIONS {
|
2014-11-26 09:10:52 -06:00
|
|
|
TaskBuilder::new().spawn(move|| child_no(x+1).invoke(()));
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2014-11-26 09:10:52 -06:00
|
|
|
});
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
2014-11-26 09:10:52 -06:00
|
|
|
TaskBuilder::new().spawn(|| child_no(0).invoke(()));
|
2012-11-28 18:20:41 -06:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
|
|
|
fn test_simple_newsched_spawn() {
|
2014-11-26 09:10:52 -06:00
|
|
|
spawn(move|| ())
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2013-06-26 18:41:00 -05:00
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
2014-10-09 14:17:22 -05:00
|
|
|
fn test_try_panic_message_static_str() {
|
2014-11-26 09:10:52 -06:00
|
|
|
match try(move|| {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("static string");
|
2014-06-17 16:48:54 -05:00
|
|
|
}) {
|
|
|
|
Err(e) => {
|
|
|
|
type T = &'static str;
|
|
|
|
assert!(e.is::<T>());
|
2014-07-10 16:19:17 -05:00
|
|
|
assert_eq!(*e.downcast::<T>().unwrap(), "static string");
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2014-10-09 14:17:22 -05:00
|
|
|
Ok(()) => panic!()
|
2013-10-27 14:12:40 -05:00
|
|
|
}
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
2014-10-09 14:17:22 -05:00
|
|
|
fn test_try_panic_message_owned_str() {
|
2014-11-26 09:10:52 -06:00
|
|
|
match try(move|| {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("owned string".to_string());
|
2014-06-17 16:48:54 -05:00
|
|
|
}) {
|
|
|
|
Err(e) => {
|
|
|
|
type T = String;
|
|
|
|
assert!(e.is::<T>());
|
2014-11-27 18:45:47 -06:00
|
|
|
assert_eq!(*e.downcast::<T>().unwrap(), "owned string");
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2014-10-09 14:17:22 -05:00
|
|
|
Ok(()) => panic!()
|
2013-10-27 14:12:40 -05:00
|
|
|
}
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
2014-10-09 14:17:22 -05:00
|
|
|
fn test_try_panic_message_any() {
|
2014-11-26 09:10:52 -06:00
|
|
|
match try(move|| {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!(box 413u16 as Box<Any + Send>);
|
2014-06-17 16:48:54 -05:00
|
|
|
}) {
|
|
|
|
Err(e) => {
|
|
|
|
type T = Box<Any + Send>;
|
|
|
|
assert!(e.is::<T>());
|
2014-07-10 16:19:17 -05:00
|
|
|
let any = e.downcast::<T>().unwrap();
|
2014-06-17 16:48:54 -05:00
|
|
|
assert!(any.is::<u16>());
|
2014-07-10 16:19:17 -05:00
|
|
|
assert_eq!(*any.downcast::<u16>().unwrap(), 413u16);
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
2014-10-09 14:17:22 -05:00
|
|
|
Ok(()) => panic!()
|
2013-10-27 14:12:40 -05:00
|
|
|
}
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
|
|
|
|
2014-06-17 16:48:54 -05:00
|
|
|
#[test]
|
2014-10-09 14:17:22 -05:00
|
|
|
fn test_try_panic_message_unit_struct() {
|
2014-06-17 16:48:54 -05:00
|
|
|
struct Juju;
|
|
|
|
|
2014-11-26 09:10:52 -06:00
|
|
|
match try(move|| {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!(Juju)
|
2014-06-17 16:48:54 -05:00
|
|
|
}) {
|
|
|
|
Err(ref e) if e.is::<Juju>() => {}
|
2014-10-09 14:17:22 -05:00
|
|
|
Err(_) | Ok(()) => panic!()
|
2014-06-17 16:48:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_stdout() {
|
|
|
|
let (tx, rx) = channel();
|
|
|
|
let mut reader = ChanReader::new(rx);
|
|
|
|
let stdout = ChanWriter::new(tx);
|
|
|
|
|
2014-06-25 20:18:13 -05:00
|
|
|
let r = TaskBuilder::new().stdout(box stdout as Box<Writer + Send>)
|
2014-11-26 09:10:52 -06:00
|
|
|
.try(move|| {
|
2014-06-25 20:18:13 -05:00
|
|
|
print!("Hello, world!");
|
|
|
|
});
|
|
|
|
assert!(r.is_ok());
|
2013-10-11 16:20:34 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
let output = reader.read_to_string().unwrap();
|
2014-11-27 18:45:47 -06:00
|
|
|
assert_eq!(output, "Hello, world!");
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
2014-06-17 16:48:54 -05:00
|
|
|
|
|
|
|
// NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
|
|
|
|
// to the test harness apparently interfering with stderr configuration.
|
2013-10-11 16:20:34 -05:00
|
|
|
}
|
2014-06-13 18:03:41 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn task_abort_no_kill_runtime() {
|
|
|
|
use std::io::timer;
|
2014-07-30 22:07:41 -05:00
|
|
|
use time::Duration;
|
2014-06-13 18:03:41 -05:00
|
|
|
use mem;
|
|
|
|
|
2014-06-29 11:38:07 -05:00
|
|
|
let tb = TaskBuilder::new();
|
2014-11-26 09:10:52 -06:00
|
|
|
let rx = tb.try_future(move|| {});
|
2014-06-13 18:03:41 -05:00
|
|
|
mem::drop(rx);
|
2014-07-30 22:07:41 -05:00
|
|
|
timer::sleep(Duration::milliseconds(1000));
|
2014-06-13 18:03:41 -05:00
|
|
|
}
|