about summary refs log tree commit diff
path: root/src/libstd/task
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-12-12 18:01:59 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-12-24 19:59:52 -0800
commit51abdee5f1ad932671350fdd8a7911fe144d08b8 (patch)
treee65726bf152c97cb9854a3e13b3818c0ecde5493 /src/libstd/task
parent6aadc9d18856f8e7ea8038e2c4b2ba0f9507e26a (diff)
downloadrust-51abdee5f1ad932671350fdd8a7911fe144d08b8.tar.gz
rust-51abdee5f1ad932671350fdd8a7911fe144d08b8.zip
green: Rip the bandaid off, introduce libgreen
This extracts everything related to green scheduling from libstd and introduces
a new libgreen crate. This mostly involves deleting most of std::rt and moving
it to libgreen.

Along with the movement of code, this commit rearchitects many functions in the
scheduler in order to adapt to the fact that Local::take now *only* works on a
Task, not a scheduler. This mostly just involved threading the current green
task through in a few locations, but there were one or two spots where things
got hairy.

There are a few repercussions of this commit:

* tube/rc have been removed (the runtime implementation of rc)
* There is no longer a "single threaded" spawning mode for tasks. This is now
  encompassed by 1:1 scheduling + communication. Convenience methods have been
  introduced that are specific to libgreen to assist in the spawning of pools of
  schedulers.
Diffstat (limited to 'src/libstd/task')
-rw-r--r--src/libstd/task/mod.rs799
-rw-r--r--src/libstd/task/spawn.rs233
2 files changed, 0 insertions, 1032 deletions
diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs
deleted file mode 100644
index 3310dddc327..00000000000
--- a/src/libstd/task/mod.rs
+++ /dev/null
@@ -1,799 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-/*!
- * Task management.
- *
- * 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
- * with each other using ports and channels (see std::rt::comm for more info
- * about how communication works).
- *
- * Tasks can be spawned in 3 different modes.
- *
- *  * Bidirectionally linked: This is the default mode and it's what ```spawn``` does.
- *  Failures will be propagated from parent to child and vice versa.
- *
- *  * Unidirectionally linked (parent->child): This type of task can be created with
- *  ```spawn_supervised```. In this case, failures are propagated from parent to child
- *  but not the other way around.
- *
- *  * Unlinked: Tasks can be completely unlinked. These tasks can be created by using
- *  ```spawn_unlinked```. In this case failures are not propagated at all.
- *
- * Tasks' failure modes can be further configured. For instance, parent tasks can (un)watch
- * children failures. Please, refer to TaskBuilder's documentation bellow for more information.
- *
- * When a (bi|uni)directionally linked task fails, its failure will be propagated to all tasks
- * linked to it, this will cause such tasks to fail by a `linked failure`.
- *
- * 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.
- *
- * # Example
- *
- * ```
- * do spawn {
- *     log(error, "Hello, World!");
- * }
- * ```
- */
-
-#[allow(missing_doc)];
-
-use prelude::*;
-
-use comm::{Chan, Port};
-use result::{Result, Ok, Err};
-use rt::in_green_task_context;
-use rt::local::Local;
-use send_str::{SendStr, IntoSendStr};
-use util;
-
-#[cfg(test)] use any::Any;
-#[cfg(test)] use comm::SharedChan;
-#[cfg(test)] use ptr;
-#[cfg(test)] use result;
-
-pub mod spawn;
-
-/// Indicates the manner in which a task exited.
-///
-/// A task that completes without failing is considered to exit successfully.
-/// Supervised ancestors and linked siblings may yet fail after this task
-/// succeeds. Also note that in such a case, it may be nondeterministic whether
-/// linked failure or successful exit happen first.
-///
-/// If you wish for this result's delivery to block until all linked and/or
-/// children tasks complete, recommend using a result future.
-pub type TaskResult = Result<(), ~Any>;
-
-/// Scheduler modes
-#[deriving(Eq)]
-pub enum SchedMode {
-    /// Run task on the default scheduler
-    DefaultScheduler,
-    /// All tasks run in the same OS thread
-    SingleThreaded,
-}
-
-/**
- * Scheduler configuration options
- *
- * # Fields
- *
- * * sched_mode - The operating mode of the scheduler
- *
- */
-pub struct SchedOpts {
-    priv mode: SchedMode,
-}
-
-/**
- * Task configuration options
- *
- * # Fields
- *
- * * watched - Make parent task collect exit status notifications from child
- *             before reporting its own exit status. (This delays the parent
- *             task's death and cleanup until after all transitively watched
- *             children also exit.) True by default.
- *
- * * notify_chan - Enable lifecycle notifications on the given channel
- *
- * * name - A name for the task-to-be, for identification in failure messages.
- *
- * * sched - Specify the configuration of a new scheduler to create the task
- *           in. This is of particular importance for libraries which want to call
- *           into foreign code that blocks. Without doing so in a different
- *           scheduler other tasks will be impeded or even blocked indefinitely.
- */
-pub struct TaskOpts {
-    priv watched: bool,
-    priv notify_chan: Option<Chan<TaskResult>>,
-    name: Option<SendStr>,
-    sched: SchedOpts,
-    stack_size: Option<uint>
-}
-
-/**
- * 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.
-pub struct TaskBuilder {
-    opts: TaskOpts,
-    priv gen_body: Option<proc(v: proc()) -> proc()>,
-    priv can_not_copy: Option<util::NonCopyable>,
-}
-
-/**
- * Generate the base configuration for spawning a task, off of which more
- * configuration methods can be chained.
- * For example, task().unlinked().spawn is equivalent to spawn_unlinked.
- */
-pub fn task() -> TaskBuilder {
-    TaskBuilder {
-        opts: default_task_opts(),
-        gen_body: None,
-        can_not_copy: None,
-    }
-}
-
-impl TaskBuilder {
-    fn consume(mut self) -> TaskBuilder {
-        let gen_body = self.gen_body.take();
-        let notify_chan = self.opts.notify_chan.take();
-        let name = self.opts.name.take();
-        TaskBuilder {
-            opts: TaskOpts {
-                watched: self.opts.watched,
-                notify_chan: notify_chan,
-                name: name,
-                sched: self.opts.sched,
-                stack_size: self.opts.stack_size
-            },
-            gen_body: gen_body,
-            can_not_copy: None,
-        }
-    }
-
-    /// Cause the parent task to collect the child's exit status (and that of
-    /// all transitively-watched grandchildren) before reporting its own.
-    pub fn watched(&mut self) {
-        self.opts.watched = true;
-    }
-
-    /// Allow the child task to outlive the parent task, at the possible cost
-    /// of the parent reporting success even if the child task fails later.
-    pub fn unwatched(&mut self) {
-        self.opts.watched = false;
-    }
-
-    /// 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.
-    ///
-    /// Note that the future returned by this function is only useful for
-    /// obtaining the value of the next task to be spawning with the
-    /// builder. If additional tasks are spawned with the same builder
-    /// then a new result future must be obtained prior to spawning each
-    /// task.
-    ///
-    /// # Failure
-    /// Fails if a future_result was already set for this task.
-    pub fn future_result(&mut self) -> Port<TaskResult> {
-        // 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() {
-            fail!("Can't set multiple future_results for one task!");
-        }
-
-        // Construct the future and give it to the caller.
-        let (notify_pipe_po, notify_pipe_ch) = Chan::new();
-
-        // Reconfigure self to use a notify channel.
-        self.opts.notify_chan = Some(notify_pipe_ch);
-
-        notify_pipe_po
-    }
-
-    /// Name the task-to-be. Currently the name is used for identification
-    /// only in failure messages.
-    pub fn name<S: IntoSendStr>(&mut self, name: S) {
-        self.opts.name = Some(name.into_send_str());
-    }
-
-    /// Configure a custom scheduler mode for the task.
-    pub fn sched_mode(&mut self, mode: SchedMode) {
-        self.opts.sched.mode = mode;
-    }
-
-    /**
-     * 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.
-     */
-    pub fn add_wrapper(&mut self, wrapper: proc(v: proc()) -> proc()) {
-        let prev_gen_body = self.gen_body.take();
-        let prev_gen_body = match prev_gen_body {
-            Some(gen) => gen,
-            None => {
-                let f: proc(proc()) -> proc() = proc(body) body;
-                f
-            }
-        };
-        let next_gen_body = {
-            let f: proc(proc()) -> proc() = proc(body) {
-                wrapper(prev_gen_body(body))
-            };
-            f
-        };
-        self.gen_body = Some(next_gen_body);
-    }
-
-    /**
-     * 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.
-     *
-     * # Failure
-     *
-     * When spawning into a new scheduler, the number of threads requested
-     * must be greater than zero.
-     */
-    pub fn spawn(mut self, f: proc()) {
-        let gen_body = self.gen_body.take();
-        let notify_chan = self.opts.notify_chan.take();
-        let name = self.opts.name.take();
-        let x = self.consume();
-        let opts = TaskOpts {
-            watched: x.opts.watched,
-            notify_chan: notify_chan,
-            name: name,
-            sched: x.opts.sched,
-            stack_size: x.opts.stack_size
-        };
-        let f = match gen_body {
-            Some(gen) => {
-                gen(f)
-            }
-            None => {
-                f
-            }
-        };
-        spawn::spawn_raw(opts, f);
-    }
-
-    /**
-     * 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.
-     */
-    pub fn try<T:Send>(mut self, f: proc() -> T) -> Result<T, ~Any> {
-        let (po, ch) = Chan::new();
-
-        let result = self.future_result();
-
-        do self.spawn {
-            ch.send(f());
-        }
-
-        match result.recv() {
-            Ok(())     => Ok(po.recv()),
-            Err(cause) => Err(cause)
-        }
-    }
-}
-
-
-/* Task construction */
-
-pub fn default_task_opts() -> TaskOpts {
-    /*!
-     * The default task options
-     *
-     * By default all tasks are supervised by their parent, are spawned
-     * into the same scheduler, and do not post lifecycle notifications.
-     */
-
-    TaskOpts {
-        watched: true,
-        notify_chan: None,
-        name: None,
-        sched: SchedOpts {
-            mode: DefaultScheduler,
-        },
-        stack_size: None
-    }
-}
-
-/* Spawn convenience functions */
-
-/// 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)`.
-pub fn spawn(f: proc()) {
-    let task = task();
-    task.spawn(f)
-}
-
-pub fn spawn_sched(mode: SchedMode, f: proc()) {
-    /*!
-     * Creates a new task on a new or existing scheduler.
-     *
-     * When there are no more tasks to execute the
-     * scheduler terminates.
-     *
-     * # Failure
-     *
-     * In manual threads mode the number of threads requested must be
-     * greater than zero.
-     */
-
-    let mut task = task();
-    task.sched_mode(mode);
-    task.spawn(f)
-}
-
-pub fn try<T:Send>(f: proc() -> T) -> Result<T, ~Any> {
-    /*!
-     * Execute a function in another task and return either the return value
-     * of the function or result::err.
-     *
-     * This is equivalent to task().supervised().try.
-     */
-
-    let task = task();
-    task.try(f)
-}
-
-
-/* Lifecycle functions */
-
-/// Read the name of the current task.
-pub fn with_task_name<U>(blk: |Option<&str>| -> U) -> U {
-    use rt::task::Task;
-
-    if in_green_task_context() {
-        let mut task = Local::borrow(None::<Task>);
-        match task.get().name {
-            Some(ref name) => blk(Some(name.as_slice())),
-            None => blk(None)
-        }
-    } else {
-        fail!("no task name exists in non-green task context")
-    }
-}
-
-pub fn deschedule() {
-    //! Yield control to the task scheduler
-
-    use rt::local::Local;
-    use rt::sched::Scheduler;
-
-    // FIXME(#7544): Optimize this, since we know we won't block.
-    let sched: ~Scheduler = Local::take();
-    sched.yield_now();
-}
-
-pub fn failing() -> bool {
-    //! True if the running task has failed
-
-    use rt::task::Task;
-
-    let mut local = Local::borrow(None::<Task>);
-    local.get().unwinder.unwinding
-}
-
-// 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.       !!!
-
-#[test]
-fn test_unnamed_task() {
-    use rt::test::run_in_uv_task;
-
-    do run_in_uv_task {
-        do spawn {
-            with_task_name(|name| {
-                assert!(name.is_none());
-            })
-        }
-    }
-}
-
-#[test]
-fn test_owned_named_task() {
-    use rt::test::run_in_uv_task;
-
-    do run_in_uv_task {
-        let mut t = task();
-        t.name(~"ada lovelace");
-        do t.spawn {
-            with_task_name(|name| {
-                assert!(name.unwrap() == "ada lovelace");
-            })
-        }
-    }
-}
-
-#[test]
-fn test_static_named_task() {
-    use rt::test::run_in_uv_task;
-
-    do run_in_uv_task {
-        let mut t = task();
-        t.name("ada lovelace");
-        do t.spawn {
-            with_task_name(|name| {
-                assert!(name.unwrap() == "ada lovelace");
-            })
-        }
-    }
-}
-
-#[test]
-fn test_send_named_task() {
-    use rt::test::run_in_uv_task;
-
-    do run_in_uv_task {
-        let mut t = task();
-        t.name("ada lovelace".into_send_str());
-        do t.spawn {
-            with_task_name(|name| {
-                assert!(name.unwrap() == "ada lovelace");
-            })
-        }
-    }
-}
-
-#[test]
-fn test_run_basic() {
-    let (po, ch) = Chan::new();
-    do task().spawn {
-        ch.send(());
-    }
-    po.recv();
-}
-
-#[test]
-fn test_add_wrapper() {
-    let (po, ch) = Chan::new();
-    let mut b0 = task();
-    do b0.add_wrapper |body| {
-        let ch = ch;
-        let result: proc() = proc() {
-            body();
-            ch.send(());
-        };
-        result
-    };
-    do b0.spawn { }
-    po.recv();
-}
-
-#[test]
-fn test_future_result() {
-    let mut builder = task();
-    let result = builder.future_result();
-    do builder.spawn {}
-    assert!(result.recv().is_ok());
-
-    let mut builder = task();
-    let result = builder.future_result();
-    do builder.spawn {
-        fail!();
-    }
-    assert!(result.recv().is_err());
-}
-
-#[test] #[should_fail]
-fn test_back_to_the_future_result() {
-    let mut builder = task();
-    builder.future_result();
-    builder.future_result();
-}
-
-#[test]
-fn test_try_success() {
-    match do try {
-        ~"Success!"
-    } {
-        result::Ok(~"Success!") => (),
-        _ => fail!()
-    }
-}
-
-#[test]
-fn test_try_fail() {
-    match do try {
-        fail!()
-    } {
-        result::Err(_) => (),
-        result::Ok(()) => fail!()
-    }
-}
-
-#[cfg(test)]
-fn get_sched_id() -> int {
-    use rt::sched::Scheduler;
-    let mut sched = Local::borrow(None::<Scheduler>);
-    sched.get().sched_id() as int
-}
-
-#[test]
-fn test_spawn_sched() {
-    let (po, ch) = SharedChan::new();
-
-    fn f(i: int, ch: SharedChan<()>) {
-        let parent_sched_id = get_sched_id();
-
-        do spawn_sched(SingleThreaded) {
-            let child_sched_id = get_sched_id();
-            assert!(parent_sched_id != child_sched_id);
-
-            if (i == 0) {
-                ch.send(());
-            } else {
-                f(i - 1, ch.clone());
-            }
-        };
-
-    }
-    f(10, ch);
-    po.recv();
-}
-
-#[test]
-fn test_spawn_sched_childs_on_default_sched() {
-    let (po, ch) = Chan::new();
-
-    // Assuming tests run on the default scheduler
-    let default_id = get_sched_id();
-
-    do spawn_sched(SingleThreaded) {
-        let ch = ch;
-        let parent_sched_id = get_sched_id();
-        do spawn {
-            let child_sched_id = get_sched_id();
-            assert!(parent_sched_id != child_sched_id);
-            assert_eq!(child_sched_id, default_id);
-            ch.send(());
-        };
-    };
-
-    po.recv();
-}
-
-#[test]
-fn test_spawn_sched_blocking() {
-    use unstable::mutex::Mutex;
-
-    unsafe {
-
-        // Testing that a task in one scheduler can block in foreign code
-        // without affecting other schedulers
-        20u.times(|| {
-            let (start_po, start_ch) = Chan::new();
-            let (fin_po, fin_ch) = Chan::new();
-
-            let mut lock = Mutex::new();
-            let lock2 = lock.clone();
-
-            do spawn_sched(SingleThreaded) {
-                let mut lock = lock2;
-                lock.lock();
-
-                start_ch.send(());
-
-                // Block the scheduler thread
-                lock.wait();
-                lock.unlock();
-
-                fin_ch.send(());
-            };
-
-            // Wait until the other task has its lock
-            start_po.recv();
-
-            fn pingpong(po: &Port<int>, ch: &Chan<int>) {
-                let mut val = 20;
-                while val > 0 {
-                    val = po.recv();
-                    ch.try_send(val - 1);
-                }
-            }
-
-            let (setup_po, setup_ch) = Chan::new();
-            let (parent_po, parent_ch) = Chan::new();
-            do spawn {
-                let (child_po, child_ch) = Chan::new();
-                setup_ch.send(child_ch);
-                pingpong(&child_po, &parent_ch);
-            };
-
-            let child_ch = setup_po.recv();
-            child_ch.send(20);
-            pingpong(&parent_po, &child_ch);
-            lock.lock();
-            lock.signal();
-            lock.unlock();
-            fin_po.recv();
-            lock.destroy();
-        })
-    }
-}
-
-#[cfg(test)]
-fn avoid_copying_the_body(spawnfn: |v: proc()|) {
-    let (p, ch) = Chan::<uint>::new();
-
-    let x = ~1;
-    let x_in_parent = ptr::to_unsafe_ptr(&*x) as uint;
-
-    do spawnfn {
-        let x_in_child = ptr::to_unsafe_ptr(&*x) as uint;
-        ch.send(x_in_child);
-    }
-
-    let x_in_child = p.recv();
-    assert_eq!(x_in_parent, x_in_child);
-}
-
-#[test]
-fn test_avoid_copying_the_body_spawn() {
-    avoid_copying_the_body(spawn);
-}
-
-#[test]
-fn test_avoid_copying_the_body_task_spawn() {
-    avoid_copying_the_body(|f| {
-        let builder = task();
-        do builder.spawn || {
-            f();
-        }
-    })
-}
-
-#[test]
-fn test_avoid_copying_the_body_try() {
-    avoid_copying_the_body(|f| {
-        do try || {
-            f()
-        };
-    })
-}
-
-#[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..!)
-    static generations: uint = 16;
-    fn child_no(x: uint) -> proc() {
-        return proc() {
-            if x < generations {
-                let mut t = task();
-                t.unwatched();
-                t.spawn(child_no(x+1));
-            }
-        }
-    }
-    let mut t = task();
-    t.unwatched();
-    t.spawn(child_no(0));
-}
-
-#[test]
-fn test_simple_newsched_spawn() {
-    use rt::test::run_in_uv_task;
-
-    do run_in_uv_task {
-        spawn(proc()())
-    }
-}
-
-#[test]
-fn test_try_fail_message_static_str() {
-    match do try {
-        fail!("static string");
-    } {
-        Err(e) => {
-            type T = &'static str;
-            assert!(e.is::<T>());
-            assert_eq!(*e.move::<T>().unwrap(), "static string");
-        }
-        Ok(()) => fail!()
-    }
-}
-
-#[test]
-fn test_try_fail_message_owned_str() {
-    match do try {
-        fail!(~"owned string");
-    } {
-        Err(e) => {
-            type T = ~str;
-            assert!(e.is::<T>());
-            assert_eq!(*e.move::<T>().unwrap(), ~"owned string");
-        }
-        Ok(()) => fail!()
-    }
-}
-
-#[test]
-fn test_try_fail_message_any() {
-    match do try {
-        fail!(~413u16 as ~Any);
-    } {
-        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!()
-    }
-}
-
-#[test]
-fn test_try_fail_message_unit_struct() {
-    struct Juju;
-
-    match do try {
-        fail!(Juju)
-    } {
-        Err(ref e) if e.is::<Juju>() => {}
-        Err(_) | Ok(()) => fail!()
-    }
-}
diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs
deleted file mode 100644
index 1148774020a..00000000000
--- a/src/libstd/task/spawn.rs
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-/*!**************************************************************************
- *
- * WARNING: linked failure has been removed since this doc comment was written,
- *          but it was so pretty that I didn't want to remove it.
- *
- * Spawning & linked failure
- *
- * Several data structures are involved in task management to allow properly
- * propagating failure across linked/supervised tasks.
- *
- * (1) The "taskgroup_arc" is an unsafe::exclusive which contains a hashset of
- *     all tasks that are part of the group. Some tasks are 'members', which
- *     means if they fail, they will kill everybody else in the taskgroup.
- *     Other tasks are 'descendants', which means they will not kill tasks
- *     from this group, but can be killed by failing members.
- *
- *     A new one of these is created each spawn_linked or spawn_supervised.
- *
- * (2) The "taskgroup" is a per-task control structure that tracks a task's
- *     spawn configuration. It contains a reference to its taskgroup_arc, a
- *     reference to its node in the ancestor list (below), and an optionally
- *     configured notification port. These are stored in TLS.
- *
- * (3) The "ancestor_list" is a cons-style list of unsafe::exclusives which
- *     tracks 'generations' of taskgroups -- a group's ancestors are groups
- *     which (directly or transitively) spawn_supervised-ed them. Each task
- *     is recorded in the 'descendants' of each of its ancestor groups.
- *
- *     Spawning a supervised task is O(n) in the number of generations still
- *     alive, and exiting (by success or failure) that task is also O(n).
- *
- * This diagram depicts the references between these data structures:
- *
- *          linked_________________________________
- *        ___/                   _________         \___
- *       /   \                  | group X |        /   \
- *      (  A  ) - - - - - - - > | {A,B} {}|< - - -(  B  )
- *       \___/                  |_________|        \___/
- *      unlinked
- *         |      __ (nil)
- *         |      //|                         The following code causes this:
- *         |__   //   /\         _________
- *        /   \ //    ||        | group Y |     fn taskA() {
- *       (  C  )- - - ||- - - > |{C} {D,E}|         spawn(taskB);
- *        \___/      /  \=====> |_________|         spawn_unlinked(taskC);
- *      supervise   /gen \                          ...
- *         |    __  \ 00 /                      }
- *         |    //|  \__/                       fn taskB() { ... }
- *         |__ //     /\         _________      fn taskC() {
- *        /   \/      ||        | group Z |         spawn_supervised(taskD);
- *       (  D  )- - - ||- - - > | {D} {E} |         ...
- *        \___/      /  \=====> |_________|     }
- *      supervise   /gen \                      fn taskD() {
- *         |    __  \ 01 /                          spawn_supervised(taskE);
- *         |    //|  \__/                           ...
- *         |__ //                _________      }
- *        /   \/                | group W |     fn taskE() { ... }
- *       (  E  )- - - - - - - > | {E}  {} |
- *        \___/                 |_________|
- *
- *        "tcb"               "taskgroup_arc"
- *             "ancestor_list"
- *
- ****************************************************************************/
-
-#[doc(hidden)];
-
-use prelude::*;
-
-use comm::Chan;
-use rt::local::Local;
-use rt::sched::{Scheduler, Shutdown, TaskFromFriend};
-use rt::task::{Task, Sched};
-use rt::thread::Thread;
-use rt::{in_green_task_context, new_event_loop};
-use task::{SingleThreaded, TaskOpts, TaskResult};
-
-#[cfg(test)] use task::default_task_opts;
-#[cfg(test)] use task;
-
-pub fn spawn_raw(mut opts: TaskOpts, f: proc()) {
-    assert!(in_green_task_context());
-
-    let mut task = if opts.sched.mode != SingleThreaded {
-        if opts.watched {
-            Task::build_child(opts.stack_size, f)
-        } else {
-            Task::build_root(opts.stack_size, f)
-        }
-    } else {
-        unsafe {
-            // Creating a 1:1 task:thread ...
-            let sched: *mut Scheduler = Local::unsafe_borrow();
-            let sched_handle = (*sched).make_handle();
-
-            // Since this is a 1:1 scheduler we create a queue not in
-            // the stealee set. The run_anything flag is set false
-            // which will disable stealing.
-            let (worker, _stealer) = (*sched).work_queue.pool().deque();
-
-            // Create a new scheduler to hold the new task
-            let mut new_sched = ~Scheduler::new_special(new_event_loop(),
-                                                        worker,
-                                                        (*sched).work_queues.clone(),
-                                                        (*sched).sleeper_list.clone(),
-                                                        false,
-                                                        Some(sched_handle));
-            let mut new_sched_handle = new_sched.make_handle();
-
-            // Allow the scheduler to exit when the pinned task exits
-            new_sched_handle.send(Shutdown);
-
-            // Pin the new task to the new scheduler
-            let new_task = if opts.watched {
-                Task::build_homed_child(opts.stack_size, f, Sched(new_sched_handle))
-            } else {
-                Task::build_homed_root(opts.stack_size, f, Sched(new_sched_handle))
-            };
-
-            // Create a task that will later be used to join with the new scheduler
-            // thread when it is ready to terminate
-            let (thread_port, thread_chan) = Chan::new();
-            let join_task = do Task::build_child(None) {
-                debug!("running join task");
-                let thread: Thread<()> = thread_port.recv();
-                thread.join();
-            };
-
-            // Put the scheduler into another thread
-            let orig_sched_handle = (*sched).make_handle();
-
-            let new_sched = new_sched;
-            let thread = do Thread::start {
-                let mut new_sched = new_sched;
-                let mut orig_sched_handle = orig_sched_handle;
-
-                let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool, None) || {
-                    debug!("boostrapping a 1:1 scheduler");
-                };
-                new_sched.bootstrap(bootstrap_task);
-
-                // Now tell the original scheduler to join with this thread
-                // by scheduling a thread-joining task on the original scheduler
-                orig_sched_handle.send(TaskFromFriend(join_task));
-
-                // NB: We can't simply send a message from here to another task
-                // because this code isn't running in a task and message passing doesn't
-                // work outside of tasks. Hence we're sending a scheduler message
-                // to execute a new task directly to a scheduler.
-            };
-
-            // Give the thread handle to the join task
-            thread_chan.send(thread);
-
-            // When this task is enqueued on the current scheduler it will then get
-            // forwarded to the scheduler to which it is pinned
-            new_task
-        }
-    };
-
-    if opts.notify_chan.is_some() {
-        let notify_chan = opts.notify_chan.take_unwrap();
-        let on_exit: proc(TaskResult) = proc(task_result) {
-            notify_chan.try_send(task_result);
-        };
-        task.death.on_exit = Some(on_exit);
-    }
-
-    task.name = opts.name.take();
-    debug!("spawn calling run_task");
-    Scheduler::run_task(task);
-
-}
-
-#[test]
-fn test_spawn_raw_simple() {
-    let (po, ch) = Chan::new();
-    do spawn_raw(default_task_opts()) {
-        ch.send(());
-    }
-    po.recv();
-}
-
-#[test]
-fn test_spawn_raw_unsupervise() {
-    let opts = task::TaskOpts {
-        watched: false,
-        notify_chan: None,
-        .. default_task_opts()
-    };
-    do spawn_raw(opts) {
-        fail!();
-    }
-}
-
-#[test]
-fn test_spawn_raw_notify_success() {
-    let (notify_po, notify_ch) = Chan::new();
-
-    let opts = task::TaskOpts {
-        notify_chan: Some(notify_ch),
-        .. default_task_opts()
-    };
-    do spawn_raw(opts) {
-    }
-    assert!(notify_po.recv().is_ok());
-}
-
-#[test]
-fn test_spawn_raw_notify_failure() {
-    // New bindings for these
-    let (notify_po, notify_ch) = Chan::new();
-
-    let opts = task::TaskOpts {
-        watched: false,
-        notify_chan: Some(notify_ch),
-        .. default_task_opts()
-    };
-    do spawn_raw(opts) {
-        fail!();
-    }
-    assert!(notify_po.recv().is_err());
-}