1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 //! An executing Rust program consists of a collection of tasks, each
14 //! with their own stack and local state.
16 //! Tasks generally have their memory *isolated* from each other by
17 //! virtue of Rust's owned types (which of course may only be owned by
18 //! a single task at a time). Communication between tasks is primarily
19 //! done through [channels](../../std/comm/index.html), Rust's
20 //! message-passing types, though [other forms of task
21 //! synchronization](../../std/sync/index.html) are often employed to
22 //! achieve particular performance goals. In particular, types that
23 //! are guaranteed to be threadsafe are easily shared between threads
24 //! using the atomically-reference-counted container,
25 //! [`Arc`](../../std/sync/struct.Arc.html).
27 //! Fatal logic errors in Rust cause *task panic*, during which
28 //! a task will unwind the stack, running destructors and freeing
29 //! owned resources. Task panic is unrecoverable from within
30 //! the panicking task (i.e. there is no 'try/catch' in Rust), but
31 //! panic may optionally be detected from a different task. If
32 //! the main task panics the application will exit with a non-zero
39 //! println!("Hello, World!");
43 #![unstable = "The task spawning model will be changed as part of runtime reform, and the module \
44 will likely be renamed from `task` to `thread`."]
50 use io::{Writer, stdio};
51 use kinds::{Send, marker};
53 use option::Option::{None, Some};
55 use rustrt::local::Local;
56 use rustrt::task::Task;
59 use string::{String, ToString};
62 /// The task builder type.
64 /// Provides detailed control over the properties and behavior of new tasks.
66 // NB: Builders are designed to be single-use because they do stateful
67 // things that get weird when reusing - e.g. if you create a result future
68 // it only applies to a single task, so then you have to maintain Some
69 // potentially tricky state to ensure that everything behaves correctly
70 // when you try to reuse the builder to spawn a new task. We'll just
71 // sidestep that whole issue by making builders uncopyable and making
72 // the run function move them in.
73 pub struct TaskBuilder {
74 // A name for the task-to-be, for identification in panic messages
75 name: Option<SendStr>,
76 // The size of the stack for the spawned task
77 stack_size: Option<uint>,
79 stdout: Option<Box<Writer + Send>>,
81 stderr: Option<Box<Writer + Send>>,
82 // Optionally wrap the eventual task body
83 gen_body: Option<proc(v: proc():Send):Send -> proc():Send>,
84 nocopy: marker::NoCopy,
88 /// Generate the base configuration for spawning a task, off of which more
89 /// configuration methods can be chained.
90 pub fn new() -> TaskBuilder {
97 nocopy: marker::NoCopy,
103 /// Name the task-to-be. Currently the name is used for identification
104 /// only in panic messages.
105 #[unstable = "IntoMaybeOwned will probably change."]
106 pub fn named<T: IntoCow<'static, String, str>>(mut self, name: T) -> TaskBuilder {
107 self.name = Some(name.into_cow());
111 /// Set the size of the stack for the new task.
112 pub fn stack_size(mut self, size: uint) -> TaskBuilder {
113 self.stack_size = Some(size);
117 /// Redirect task-local stdout.
118 #[experimental = "May not want to make stdio overridable here."]
119 pub fn stdout(mut self, stdout: Box<Writer + Send>) -> TaskBuilder {
120 self.stdout = Some(stdout);
124 /// Redirect task-local stderr.
125 #[experimental = "May not want to make stdio overridable here."]
126 pub fn stderr(mut self, stderr: Box<Writer + Send>) -> TaskBuilder {
127 self.stderr = Some(stderr);
131 // Where spawning actually happens (whether yielding a future or not)
132 fn spawn_internal(self, f: proc():Send,
133 on_exit: Option<proc(Result<(), Box<Any + Send>>):Send>) {
135 name, stack_size, stdout, stderr, mut gen_body, nocopy: _
137 let f = match gen_body.take() {
141 let opts = task::TaskOpts {
144 stack_size: stack_size,
146 if stdout.is_some() || stderr.is_some() {
147 Task::spawn(opts, proc() {
148 let _ = stdout.map(stdio::set_stdout);
149 let _ = stderr.map(stdio::set_stderr);
157 /// Creates and executes a new child task.
159 /// Sets up a new task with its own call stack and schedules it to run
160 /// the provided proc. The task has the properties and behavior
161 /// specified by the `TaskBuilder`.
162 pub fn spawn(self, f: proc():Send) {
163 self.spawn_internal(f, None)
166 /// Execute a proc in a newly-spawned task and return a future representing
167 /// the task's result. The task has the properties and behavior
168 /// specified by the `TaskBuilder`.
170 /// Taking the value of the future will block until the child task
175 /// If the child task executes successfully (without panicking) then the
176 /// future returns `result::Result::Ok` containing the value returned by the
177 /// function. If the child task panics then the future returns
178 /// `result::Result::Err` containing the argument to `panic!(...)` as an
179 /// `Any` trait object.
180 #[experimental = "Futures are experimental."]
181 pub fn try_future<T:Send>(self, f: proc():Send -> T)
182 -> Future<Result<T, Box<Any + Send>>> {
183 // currently, the on_exit proc provided by librustrt only works for unit
184 // results, so we use an additional side-channel to communicate the
187 let (tx_done, rx_done) = channel(); // signal that task has exited
188 let (tx_retv, rx_retv) = channel(); // return value from task
190 let on_exit = proc(res) { let _ = tx_done.send_opt(res); };
191 self.spawn_internal(proc() { let _ = tx_retv.send_opt(f()); },
194 Future::from_fn(proc() {
195 rx_done.recv().map(|_| rx_retv.recv())
199 /// Execute a function in a newly-spawnedtask and block until the task
200 /// completes or panics. Equivalent to `.try_future(f).unwrap()`.
201 #[unstable = "Error type may change."]
202 pub fn try<T:Send>(self, f: proc():Send -> T) -> Result<T, Box<Any + Send>> {
203 self.try_future(f).into_inner()
207 /* Convenience functions */
209 /// Creates and executes a new child task
211 /// Sets up a new task with its own call stack and schedules it to run
212 /// the provided unique closure.
214 /// This function is equivalent to `TaskBuilder::new().spawn(f)`.
215 pub fn spawn(f: proc(): Send) {
216 TaskBuilder::new().spawn(f)
219 /// Execute a function in a newly-spawned task and return either the return
220 /// value of the function or an error if the task panicked.
222 /// This is equivalent to `TaskBuilder::new().try`.
223 #[unstable = "Error type may change."]
224 pub fn try<T: Send>(f: proc(): Send -> T) -> Result<T, Box<Any + Send>> {
225 TaskBuilder::new().try(f)
228 /// Execute a function in another task and return a future representing the
231 /// This is equivalent to `TaskBuilder::new().try_future`.
232 #[experimental = "Futures are experimental."]
233 pub fn try_future<T:Send>(f: proc():Send -> T) -> Future<Result<T, Box<Any + Send>>> {
234 TaskBuilder::new().try_future(f)
238 /* Lifecycle functions */
240 /// Read the name of the current task.
242 pub fn name() -> Option<String> {
243 use rustrt::task::Task;
245 let task = Local::borrow(None::<Task>);
247 Some(ref name) => Some(name.to_string()),
252 /// Yield control to the task scheduler.
253 #[unstable = "Name will change."]
254 pub fn deschedule() {
255 use rustrt::task::Task;
259 /// True if the running task is currently panicking (e.g. will return `true` inside a
260 /// destructor that is run while unwinding the stack after a call to `panic!()`).
261 #[unstable = "May move to a different module."]
262 pub fn failing() -> bool {
263 use rustrt::task::Task;
264 Local::borrow(None::<Task>).unwinder.unwinding()
269 use any::{Any, AnyRefExt};
273 use result::Result::{Ok, Err};
275 use std::io::{ChanReader, ChanWriter};
279 // !!! These tests are dangerous. If something is buggy, they will hang, !!!
280 // !!! instead of exiting cleanly. This might wedge the buildbots. !!!
283 fn test_unnamed_task() {
285 assert!(name().is_none());
286 }).map_err(|_| ()).unwrap();
290 fn test_owned_named_task() {
291 TaskBuilder::new().named("ada lovelace".to_string()).try(proc() {
292 assert!(name().unwrap() == "ada lovelace");
293 }).map_err(|_| ()).unwrap();
297 fn test_static_named_task() {
298 TaskBuilder::new().named("ada lovelace").try(proc() {
299 assert!(name().unwrap() == "ada lovelace");
300 }).map_err(|_| ()).unwrap();
304 fn test_send_named_task() {
305 TaskBuilder::new().named("ada lovelace".into_cow()).try(proc() {
306 assert!(name().unwrap() == "ada lovelace");
307 }).map_err(|_| ()).unwrap();
311 fn test_run_basic() {
312 let (tx, rx) = channel();
313 TaskBuilder::new().spawn(proc() {
320 fn test_try_future() {
321 let result = TaskBuilder::new().try_future(proc() {});
322 assert!(result.unwrap().is_ok());
324 let result = TaskBuilder::new().try_future(proc() -> () {
327 assert!(result.unwrap().is_err());
331 fn test_try_success() {
333 "Success!".to_string()
334 }).as_ref().map(|s| s.as_slice()) {
335 result::Result::Ok("Success!") => (),
341 fn test_try_panic() {
345 result::Result::Err(_) => (),
346 result::Result::Ok(()) => panic!()
351 fn test_spawn_sched() {
354 let (tx, rx) = channel();
356 fn f(i: int, tx: Sender<()>) {
372 fn test_spawn_sched_childs_on_default_sched() {
373 let (tx, rx) = channel();
384 fn avoid_copying_the_body(spawnfn: |v: proc():Send|) {
385 let (tx, rx) = channel::<uint>();
388 let x_in_parent = (&*x) as *const int as uint;
391 let x_in_child = (&*x) as *const int as uint;
395 let x_in_child = rx.recv();
396 assert_eq!(x_in_parent, x_in_child);
400 fn test_avoid_copying_the_body_spawn() {
401 avoid_copying_the_body(spawn);
405 fn test_avoid_copying_the_body_task_spawn() {
406 avoid_copying_the_body(|f| {
407 let builder = TaskBuilder::new();
408 builder.spawn(proc() {
415 fn test_avoid_copying_the_body_try() {
416 avoid_copying_the_body(|f| {
424 fn test_child_doesnt_ref_parent() {
425 // If the child refcounts the parent task, this will stack overflow when
426 // climbing the task tree to dereference each ancestor. (See #1789)
427 // (well, it would if the constant were 8000+ - I lowered it to be more
428 // valgrind-friendly. try this at home, instead..!)
429 static GENERATIONS: uint = 16;
430 fn child_no(x: uint) -> proc(): Send {
433 TaskBuilder::new().spawn(child_no(x+1));
437 TaskBuilder::new().spawn(child_no(0));
441 fn test_simple_newsched_spawn() {
446 fn test_try_panic_message_static_str() {
448 panic!("static string");
451 type T = &'static str;
452 assert!(e.is::<T>());
453 assert_eq!(*e.downcast::<T>().unwrap(), "static string");
460 fn test_try_panic_message_owned_str() {
462 panic!("owned string".to_string());
466 assert!(e.is::<T>());
467 assert_eq!(*e.downcast::<T>().unwrap(), "owned string");
474 fn test_try_panic_message_any() {
476 panic!(box 413u16 as Box<Any + Send>);
479 type T = Box<Any + Send>;
480 assert!(e.is::<T>());
481 let any = e.downcast::<T>().unwrap();
482 assert!(any.is::<u16>());
483 assert_eq!(*any.downcast::<u16>().unwrap(), 413u16);
490 fn test_try_panic_message_unit_struct() {
496 Err(ref e) if e.is::<Juju>() => {}
497 Err(_) | Ok(()) => panic!()
503 let (tx, rx) = channel();
504 let mut reader = ChanReader::new(rx);
505 let stdout = ChanWriter::new(tx);
507 let r = TaskBuilder::new().stdout(box stdout as Box<Writer + Send>)
509 print!("Hello, world!");
513 let output = reader.read_to_string().unwrap();
514 assert_eq!(output, "Hello, world!");
517 // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
518 // to the test harness apparently interfering with stderr configuration.
522 fn task_abort_no_kill_runtime() {
527 let tb = TaskBuilder::new();
528 let rx = tb.try_future(proc() {});
530 timer::sleep(Duration::milliseconds(1000));