about summary refs log tree commit diff
path: root/src/libstd/task/spawn.rs
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/spawn.rs
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/spawn.rs')
-rw-r--r--src/libstd/task/spawn.rs233
1 files changed, 0 insertions, 233 deletions
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());
-}