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.
12 * Utilities for managing and scheduling tasks
14 * An executing Rust program consists of a collection of tasks, each with their
15 * own stack, and sole ownership of their allocated heap data. Tasks communicate
16 * with each other using channels (see `std::comm` for more info about how
17 * communication works).
19 * Failure in one task does not propagate to any others (not to parent, not to
20 * child). Failure propagation is instead handled by using the channel send()
21 * and recv() methods which will fail if the other end has hung up already.
25 * By default, every task is created with the same "flavor" as the calling task.
26 * This flavor refers to the scheduling mode, with two possibilities currently
27 * being 1:1 and M:N modes. Green (M:N) tasks are cooperatively scheduled and
28 * native (1:1) tasks are scheduled by the OS kernel.
34 * println!("Hello, World!");
40 use comm::{Sender, Receiver, channel};
42 use kinds::{Send, marker};
43 use option::{None, Some, Option};
44 use result::{Result, Ok, Err};
47 use str::{Str, SendStr, IntoMaybeOwned};
49 #[cfg(test)] use any::{AnyOwnExt, AnyRefExt};
50 #[cfg(test)] use result;
52 /// Indicates the manner in which a task exited.
54 /// A task that completes without failing is considered to exit successfully.
56 /// If you wish for this result's delivery to block until all
57 /// children tasks complete, recommend using a result future.
58 pub type TaskResult = Result<(), ~Any:Send>;
60 /// Task configuration options
62 /// Enable lifecycle notifications on the given channel
63 pub notify_chan: Option<Sender<TaskResult>>,
64 /// A name for the task-to-be, for identification in failure messages
65 pub name: Option<SendStr>,
66 /// The size of the stack for the spawned task
67 pub stack_size: Option<uint>,
69 pub stdout: Option<~Writer:Send>,
71 pub stderr: Option<~Writer:Send>,
75 * The task builder type.
77 * Provides detailed control over the properties and behavior of new tasks.
79 // NB: Builders are designed to be single-use because they do stateful
80 // things that get weird when reusing - e.g. if you create a result future
81 // it only applies to a single task, so then you have to maintain Some
82 // potentially tricky state to ensure that everything behaves correctly
83 // when you try to reuse the builder to spawn a new task. We'll just
84 // sidestep that whole issue by making builders uncopyable and making
85 // the run function move them in.
86 pub struct TaskBuilder {
87 /// Options to spawn the new task with
89 gen_body: Option<proc(v: proc():Send):Send -> proc():Send>,
90 nocopy: Option<marker::NoCopy>,
94 * Generate the base configuration for spawning a task, off of which more
95 * configuration methods can be chained.
97 pub fn task() -> TaskBuilder {
99 opts: TaskOpts::new(),
106 /// Get a future representing the exit status of the task.
108 /// Taking the value of the future will block until the child task
109 /// terminates. The future result return value will be created *before* the task is
110 /// spawned; as such, do not invoke .get() on it directly;
111 /// rather, store it in an outer variable/list for later use.
114 /// Fails if a future_result was already set for this task.
115 pub fn future_result(&mut self) -> Receiver<TaskResult> {
116 // FIXME (#3725): Once linked failure and notification are
117 // handled in the library, I can imagine implementing this by just
118 // registering an arbitrary number of task::on_exit handlers and
119 // sending out messages.
121 if self.opts.notify_chan.is_some() {
122 fail!("Can't set multiple future_results for one task!");
125 // Construct the future and give it to the caller.
126 let (tx, rx) = channel();
128 // Reconfigure self to use a notify channel.
129 self.opts.notify_chan = Some(tx);
134 /// Name the task-to-be. Currently the name is used for identification
135 /// only in failure messages.
136 pub fn named<S: IntoMaybeOwned<'static>>(mut self, name: S) -> TaskBuilder {
137 self.opts.name = Some(name.into_maybe_owned());
142 * Add a wrapper to the body of the spawned task.
144 * Before the task is spawned it is passed through a 'body generator'
145 * function that may perform local setup operations as well as wrap
146 * the task body in remote setup operations. With this the behavior
147 * of tasks can be extended in simple ways.
149 * This function augments the current body generator with a new body
150 * generator by applying the task body which results from the
151 * existing body generator to the new body generator.
153 pub fn with_wrapper(mut self,
154 wrapper: proc(v: proc():Send):Send -> proc():Send)
157 self.gen_body = match self.gen_body.take() {
158 Some(prev) => Some(proc(body) { wrapper(prev(body)) }),
159 None => Some(wrapper)
165 * Creates and executes a new child task
167 * Sets up a new task with its own call stack and schedules it to run
168 * the provided unique closure. The task has the properties and behavior
169 * specified by the task_builder.
171 pub fn spawn(mut self, f: proc():Send) {
172 let gen_body = self.gen_body.take();
173 let f = match gen_body {
177 let t: ~Task = Local::take();
178 t.spawn_sibling(self.opts, f);
182 * Execute a function in another task and return either the return value
183 * of the function or result::err.
187 * If the function executed successfully then try returns result::ok
188 * containing the value returned by the function. If the function fails
189 * then try returns result::err containing nil.
192 * Fails if a future_result was already set for this task.
194 pub fn try<T:Send>(mut self, f: proc():Send -> T) -> Result<T, ~Any:Send> {
195 let (tx, rx) = channel();
197 let result = self.future_result();
203 match result.recv() {
204 Ok(()) => Ok(rx.recv()),
205 Err(cause) => Err(cause)
210 /* Task construction */
213 pub fn new() -> TaskOpts {
215 * The default task options
228 /* Spawn convenience functions */
230 /// Creates and executes a new child task
232 /// Sets up a new task with its own call stack and schedules it to run
233 /// the provided unique closure.
235 /// This function is equivalent to `task().spawn(f)`.
236 pub fn spawn(f: proc():Send) {
241 pub fn try<T:Send>(f: proc():Send -> T) -> Result<T, ~Any:Send> {
243 * Execute a function in another task and return either the return value
244 * of the function or result::err.
246 * This is equivalent to task().try.
254 /* Lifecycle functions */
256 /// Read the name of the current task.
257 pub fn with_task_name<U>(blk: |Option<&str>| -> U) -> U {
260 let task = Local::borrow(None::<Task>);
262 Some(ref name) => blk(Some(name.as_slice())),
267 pub fn deschedule() {
268 //! Yield control to the task scheduler
270 use rt::local::Local;
272 // FIXME(#7544): Optimize this, since we know we won't block.
273 let task: ~Task = Local::take();
277 pub fn failing() -> bool {
278 //! True if the running task has failed
280 Local::borrow(None::<Task>).unwinder.unwinding()
283 // The following 8 tests test the following 2^3 combinations:
284 // {un,}linked {un,}supervised failure propagation {up,down}wards.
286 // !!! These tests are dangerous. If Something is buggy, they will hang, !!!
287 // !!! instead of exiting cleanly. This might wedge the buildbots. !!!
290 fn test_unnamed_task() {
292 with_task_name(|name| {
293 assert!(name.is_none());
299 fn test_owned_named_task() {
300 task().named(~"ada lovelace").spawn(proc() {
301 with_task_name(|name| {
302 assert!(name.unwrap() == "ada lovelace");
308 fn test_static_named_task() {
309 task().named("ada lovelace").spawn(proc() {
310 with_task_name(|name| {
311 assert!(name.unwrap() == "ada lovelace");
317 fn test_send_named_task() {
318 task().named("ada lovelace".into_maybe_owned()).spawn(proc() {
319 with_task_name(|name| {
320 assert!(name.unwrap() == "ada lovelace");
326 fn test_run_basic() {
327 let (tx, rx) = channel();
328 task().spawn(proc() {
335 fn test_with_wrapper() {
336 let (tx, rx) = channel();
337 task().with_wrapper(proc(body) {
338 let result: proc():Send = proc() {
343 }).spawn(proc() { });
348 fn test_future_result() {
349 let mut builder = task();
350 let result = builder.future_result();
351 builder.spawn(proc() {});
352 assert!(result.recv().is_ok());
354 let mut builder = task();
355 let result = builder.future_result();
356 builder.spawn(proc() {
359 assert!(result.recv().is_err());
362 #[test] #[should_fail]
363 fn test_back_to_the_future_result() {
364 let mut builder = task();
365 builder.future_result();
366 builder.future_result();
370 fn test_try_success() {
373 }).as_ref().map(|s| s.as_slice()) {
374 result::Ok("Success!") => (),
384 result::Err(_) => (),
385 result::Ok(()) => fail!()
390 fn test_spawn_sched() {
393 let (tx, rx) = channel();
395 fn f(i: int, tx: Sender<()>) {
411 fn test_spawn_sched_childs_on_default_sched() {
412 let (tx, rx) = channel();
424 fn avoid_copying_the_body(spawnfn: |v: proc():Send|) {
425 let (tx, rx) = channel::<uint>();
428 let x_in_parent = (&*x) as *int as uint;
431 let x_in_child = (&*x) as *int as uint;
435 let x_in_child = rx.recv();
436 assert_eq!(x_in_parent, x_in_child);
440 fn test_avoid_copying_the_body_spawn() {
441 avoid_copying_the_body(spawn);
445 fn test_avoid_copying_the_body_task_spawn() {
446 avoid_copying_the_body(|f| {
447 let builder = task();
448 builder.spawn(proc() {
455 fn test_avoid_copying_the_body_try() {
456 avoid_copying_the_body(|f| {
464 fn test_child_doesnt_ref_parent() {
465 // If the child refcounts the parent task, this will stack overflow when
466 // climbing the task tree to dereference each ancestor. (See #1789)
467 // (well, it would if the constant were 8000+ - I lowered it to be more
468 // valgrind-friendly. try this at home, instead..!)
469 static generations: uint = 16;
470 fn child_no(x: uint) -> proc():Send {
473 task().spawn(child_no(x+1));
477 task().spawn(child_no(0));
481 fn test_simple_newsched_spawn() {
486 fn test_try_fail_message_static_str() {
488 fail!("static string");
491 type T = &'static str;
492 assert!(e.is::<T>());
493 assert_eq!(*e.move::<T>().unwrap(), "static string");
500 fn test_try_fail_message_owned_str() {
502 fail!(~"owned string");
506 assert!(e.is::<T>());
507 assert_eq!(*e.move::<T>().unwrap(), ~"owned string");
514 fn test_try_fail_message_any() {
516 fail!(~413u16 as ~Any:Send);
520 assert!(e.is::<T>());
521 let any = e.move::<T>().unwrap();
522 assert!(any.is::<u16>());
523 assert_eq!(*any.move::<u16>().unwrap(), 413u16);
530 fn test_try_fail_message_unit_struct() {
536 Err(ref e) if e.is::<Juju>() => {}
537 Err(_) | Ok(()) => fail!()