2013-02-03 20:15:43 -06:00
|
|
|
// Copyright 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.
|
|
|
|
|
2013-05-07 01:11:02 -05:00
|
|
|
/*! The Rust Runtime, including the task scheduler and I/O
|
|
|
|
|
|
|
|
The `rt` module provides the private runtime infrastructure necessary
|
|
|
|
to support core language features like the exchange and local heap,
|
|
|
|
the garbage collector, logging, local data and unwinding. It also
|
|
|
|
implements the default task scheduler and task model. Initialization
|
|
|
|
routines are provided for setting up runtime resources in common
|
|
|
|
configurations, including that used by `rustc` when generating
|
|
|
|
executables.
|
|
|
|
|
|
|
|
It is intended that the features provided by `rt` can be factored in a
|
|
|
|
way such that the core library can be built with different 'profiles'
|
|
|
|
for different use cases, e.g. excluding the task scheduler. A number
|
|
|
|
of runtime features though are critical to the functioning of the
|
|
|
|
language and an implementation must be provided regardless of the
|
|
|
|
execution environment.
|
|
|
|
|
|
|
|
Of foremost importance is the global exchange heap, in the module
|
|
|
|
`global_heap`. Very little practical Rust code can be written without
|
|
|
|
access to the global heap. Unlike most of `rt` the global heap is
|
|
|
|
truly a global resource and generally operates independently of the
|
|
|
|
rest of the runtime.
|
|
|
|
|
2013-05-19 03:04:01 -05:00
|
|
|
All other runtime features are task-local, including the local heap,
|
2013-05-07 01:11:02 -05:00
|
|
|
the garbage collector, local storage, logging and the stack unwinder.
|
|
|
|
|
|
|
|
The relationship between `rt` and the rest of the core library is
|
|
|
|
not entirely clear yet and some modules will be moving into or
|
|
|
|
out of `rt` as development proceeds.
|
|
|
|
|
|
|
|
Several modules in `core` are clients of `rt`:
|
|
|
|
|
2013-08-16 00:54:14 -05:00
|
|
|
* `std::task` - The user-facing interface to the Rust task model.
|
|
|
|
* `std::task::local_data` - The interface to local data.
|
|
|
|
* `std::gc` - The garbage collector.
|
|
|
|
* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
|
|
|
|
* `std::condition` - Uses local data.
|
|
|
|
* `std::cleanup` - Local heap destruction.
|
|
|
|
* `std::io` - In the future `std::io` will use an `rt` implementation.
|
|
|
|
* `std::logging`
|
|
|
|
* `std::pipes`
|
|
|
|
* `std::comm`
|
|
|
|
* `std::stackwalk`
|
2013-05-07 01:11:02 -05:00
|
|
|
|
|
|
|
*/
|
2013-04-23 21:21:37 -05:00
|
|
|
|
2013-09-19 00:18:38 -05:00
|
|
|
// XXX: this should not be here.
|
|
|
|
#[allow(missing_doc)];
|
2013-03-24 20:59:04 -05:00
|
|
|
|
2013-06-18 02:17:14 -05:00
|
|
|
use clone::Clone;
|
|
|
|
use container::Container;
|
2013-09-08 10:01:16 -05:00
|
|
|
use iter::Iterator;
|
2013-08-08 13:38:10 -05:00
|
|
|
use option::{Option, None, Some};
|
2013-06-03 12:50:29 -05:00
|
|
|
use ptr::RawPtr;
|
2013-07-19 16:25:05 -05:00
|
|
|
use rt::local::Local;
|
2013-06-26 18:41:00 -05:00
|
|
|
use rt::sched::{Scheduler, Shutdown};
|
2013-06-18 02:17:14 -05:00
|
|
|
use rt::sleeper_list::SleeperList;
|
2013-12-05 20:19:06 -06:00
|
|
|
use task::TaskResult;
|
2013-07-29 15:34:08 -05:00
|
|
|
use rt::task::{Task, SchedTask, GreenTask, Sched};
|
2013-11-01 11:16:11 -05:00
|
|
|
use send_str::SendStrStatic;
|
2013-10-05 23:58:55 -05:00
|
|
|
use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
|
2013-08-27 05:00:57 -05:00
|
|
|
use unstable::sync::UnsafeArc;
|
2013-08-29 06:49:55 -05:00
|
|
|
use vec::{OwnedVector, MutableVector, ImmutableVector};
|
2013-10-11 16:20:34 -05:00
|
|
|
use vec;
|
2013-03-12 15:05:45 -05:00
|
|
|
|
2013-10-05 16:44:37 -05:00
|
|
|
use self::thread::Thread;
|
|
|
|
|
2013-10-09 12:34:27 -05:00
|
|
|
// the os module needs to reach into this helper, so allow general access
|
|
|
|
// through this reexport.
|
|
|
|
pub use self::util::set_exit_status;
|
|
|
|
|
|
|
|
// this is somewhat useful when a program wants to spawn a "reasonable" number
|
|
|
|
// of workers based on the constraints of the system that it's running on.
|
|
|
|
// Perhaps this shouldn't be a `pub use` though and there should be another
|
|
|
|
// method...
|
|
|
|
pub use self::util::default_sched_threads;
|
|
|
|
|
2013-10-22 17:09:23 -05:00
|
|
|
// Re-export of the functionality in the kill module
|
2013-11-21 18:55:40 -06:00
|
|
|
pub use self::kill::BlockedTask;
|
2013-10-22 17:09:23 -05:00
|
|
|
|
2013-10-05 16:44:37 -05:00
|
|
|
// XXX: these probably shouldn't be public...
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub mod shouldnt_be_public {
|
2013-11-26 22:23:56 -06:00
|
|
|
pub use super::local_ptr::native::maybe_tls_key;
|
2013-11-28 14:22:53 -06:00
|
|
|
#[cfg(not(windows), not(target_os = "android"))]
|
2013-11-26 22:23:56 -06:00
|
|
|
pub use super::local_ptr::compiled::RT_TLS_PTR;
|
2013-10-05 16:44:37 -05:00
|
|
|
}
|
|
|
|
|
2013-10-09 12:34:27 -05:00
|
|
|
// Internal macros used by the runtime.
|
|
|
|
mod macros;
|
|
|
|
|
2013-10-22 17:00:37 -05:00
|
|
|
/// Basic implementation of an EventLoop, provides no I/O interfaces
|
|
|
|
mod basic;
|
|
|
|
|
2013-05-07 17:54:06 -05:00
|
|
|
/// The global (exchange) heap.
|
|
|
|
pub mod global_heap;
|
|
|
|
|
2013-05-19 03:04:01 -05:00
|
|
|
/// Implementations of language-critical runtime features like @.
|
|
|
|
pub mod task;
|
|
|
|
|
2013-07-02 20:15:34 -05:00
|
|
|
/// Facilities related to task failure, killing, and death.
|
|
|
|
mod kill;
|
|
|
|
|
2013-05-19 03:04:01 -05:00
|
|
|
/// The coroutine task scheduler, built on the `io` event loop.
|
2013-10-22 17:09:23 -05:00
|
|
|
pub mod sched;
|
2013-04-27 01:21:58 -05:00
|
|
|
|
2013-05-07 01:11:02 -05:00
|
|
|
/// The EventLoop and internal synchronous I/O interface.
|
2013-10-22 17:09:23 -05:00
|
|
|
pub mod rtio;
|
2013-04-27 01:21:58 -05:00
|
|
|
|
2013-05-19 03:13:53 -05:00
|
|
|
/// The Local trait for types that are accessible via thread-local
|
|
|
|
/// or task-local storage.
|
|
|
|
pub mod local;
|
|
|
|
|
2013-10-03 21:23:47 -05:00
|
|
|
/// A mostly lock-free multi-producer, single consumer queue.
|
2013-12-05 20:19:06 -06:00
|
|
|
pub mod mpsc_queue;
|
|
|
|
|
|
|
|
/// A lock-free single-producer, single consumer queue.
|
|
|
|
pub mod spsc_queue;
|
2013-10-03 21:23:47 -05:00
|
|
|
|
2013-10-07 02:07:04 -05:00
|
|
|
/// A lock-free multi-producer, multi-consumer bounded queue.
|
|
|
|
mod mpmc_bounded_queue;
|
|
|
|
|
2013-11-26 11:40:24 -06:00
|
|
|
/// A parallel work-stealing deque
|
|
|
|
pub mod deque;
|
|
|
|
|
2013-05-28 20:39:52 -05:00
|
|
|
/// A parallel data structure for tracking sleeping schedulers.
|
2013-10-22 17:09:23 -05:00
|
|
|
pub mod sleeper_list;
|
2013-05-28 20:39:52 -05:00
|
|
|
|
2013-05-07 01:11:02 -05:00
|
|
|
/// Stack segments and caching.
|
2013-08-13 11:10:05 -05:00
|
|
|
pub mod stack;
|
2013-04-27 01:21:58 -05:00
|
|
|
|
2013-05-07 01:11:02 -05:00
|
|
|
/// CPU context swapping.
|
2013-02-03 20:15:43 -06:00
|
|
|
mod context;
|
2013-04-27 01:21:58 -05:00
|
|
|
|
2013-05-07 01:11:02 -05:00
|
|
|
/// Bindings to system threading libraries.
|
2013-10-22 17:09:23 -05:00
|
|
|
pub mod thread;
|
2013-04-27 01:21:58 -05:00
|
|
|
|
2013-08-01 01:12:20 -05:00
|
|
|
/// The runtime configuration, read from environment variables.
|
2013-03-12 14:23:24 -05:00
|
|
|
pub mod env;
|
2013-04-27 01:21:58 -05:00
|
|
|
|
|
|
|
/// The local, managed heap
|
2013-06-22 03:09:06 -05:00
|
|
|
pub mod local_heap;
|
2013-03-15 20:06:19 -05:00
|
|
|
|
2013-04-27 20:57:15 -05:00
|
|
|
/// The Logger trait and implementations
|
|
|
|
pub mod logging;
|
|
|
|
|
2013-09-09 17:04:29 -05:00
|
|
|
/// Crate map
|
|
|
|
pub mod crate_map;
|
|
|
|
|
2013-04-20 02:33:49 -05:00
|
|
|
/// Tools for testing the runtime
|
|
|
|
pub mod test;
|
|
|
|
|
2013-05-03 18:58:20 -05:00
|
|
|
/// Reference counting
|
|
|
|
pub mod rc;
|
|
|
|
|
2013-05-04 19:30:31 -05:00
|
|
|
/// A simple single-threaded channel type for passing buffered data between
|
|
|
|
/// scheduler and task context
|
|
|
|
pub mod tube;
|
|
|
|
|
2013-05-19 16:39:46 -05:00
|
|
|
/// The runtime needs to be able to put a pointer into thread-local storage.
|
2013-10-09 12:34:27 -05:00
|
|
|
mod local_ptr;
|
2013-05-19 16:39:46 -05:00
|
|
|
|
|
|
|
/// Bindings to pthread/windows thread-local storage.
|
2013-10-09 12:34:27 -05:00
|
|
|
mod thread_local_storage;
|
2013-05-19 16:39:46 -05:00
|
|
|
|
2013-06-18 00:17:51 -05:00
|
|
|
/// Just stuff
|
2013-10-09 12:34:27 -05:00
|
|
|
mod util;
|
2013-05-19 16:39:46 -05:00
|
|
|
|
2013-06-21 03:28:23 -05:00
|
|
|
// Global command line argument storage
|
|
|
|
pub mod args;
|
|
|
|
|
2013-06-22 18:52:40 -05:00
|
|
|
// Support for dynamic borrowck
|
|
|
|
pub mod borrowck;
|
|
|
|
|
2013-04-27 01:21:58 -05:00
|
|
|
/// Set up a default runtime configuration, given compiler-supplied arguments.
|
|
|
|
///
|
|
|
|
/// This is invoked by the `start` _language item_ (unstable::lang) to
|
|
|
|
/// run a Rust executable.
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
|
|
|
/// * `argc` & `argv` - The argument vector. On Unix this information is used
|
|
|
|
/// by os::args.
|
|
|
|
///
|
|
|
|
/// # Return value
|
|
|
|
///
|
|
|
|
/// The return value is used as the process return code. 0 on success, 101 on error.
|
2013-11-18 15:25:09 -06:00
|
|
|
pub fn start(argc: int, argv: **u8, main: proc()) -> int {
|
2013-09-18 03:58:52 -05:00
|
|
|
|
|
|
|
init(argc, argv);
|
|
|
|
let exit_code = run(main);
|
2013-11-25 20:27:27 -06:00
|
|
|
// unsafe is ok b/c we're sure that the runtime is gone
|
|
|
|
unsafe { cleanup(); }
|
2013-09-18 03:58:52 -05:00
|
|
|
|
|
|
|
return exit_code;
|
|
|
|
}
|
2013-03-27 17:24:50 -05:00
|
|
|
|
2013-07-17 18:48:46 -05:00
|
|
|
/// Like `start` but creates an additional scheduler on the current thread,
|
|
|
|
/// which in most cases will be the 'main' thread, and pins the main task to it.
|
|
|
|
///
|
|
|
|
/// This is appropriate for running code that must execute on the main thread,
|
|
|
|
/// such as the platform event loop and GUI.
|
2013-11-18 15:25:09 -06:00
|
|
|
pub fn start_on_main_thread(argc: int, argv: **u8, main: proc()) -> int {
|
2013-09-18 03:58:52 -05:00
|
|
|
init(argc, argv);
|
|
|
|
let exit_code = run_on_main_thread(main);
|
2013-11-25 20:27:27 -06:00
|
|
|
// unsafe is ok b/c we're sure that the runtime is gone
|
|
|
|
unsafe { cleanup(); }
|
2013-09-18 03:58:52 -05:00
|
|
|
|
|
|
|
return exit_code;
|
|
|
|
}
|
2013-07-17 18:48:46 -05:00
|
|
|
|
2013-06-21 03:28:23 -05:00
|
|
|
/// One-time runtime initialization.
|
|
|
|
///
|
|
|
|
/// Initializes global state, including frobbing
|
|
|
|
/// the crate's logging flags, registering GC
|
|
|
|
/// metadata, and storing the process arguments.
|
2013-09-18 03:58:52 -05:00
|
|
|
pub fn init(argc: int, argv: **u8) {
|
|
|
|
// XXX: Derefing these pointers is not safe.
|
|
|
|
// Need to propagate the unsafety to `start`.
|
|
|
|
unsafe {
|
|
|
|
args::init(argc, argv);
|
|
|
|
env::init();
|
|
|
|
logging::init();
|
|
|
|
}
|
|
|
|
}
|
2013-05-08 18:53:40 -05:00
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
/// One-time runtime cleanup.
|
2013-11-25 20:27:27 -06:00
|
|
|
///
|
|
|
|
/// This function is unsafe because it performs no checks to ensure that the
|
|
|
|
/// runtime has completely ceased running. It is the responsibility of the
|
|
|
|
/// caller to ensure that the runtime is entirely shut down and nothing will be
|
|
|
|
/// poking around at the internal components.
|
|
|
|
///
|
|
|
|
/// Invoking cleanup while portions of the runtime are still in use may cause
|
|
|
|
/// undefined behavior.
|
|
|
|
pub unsafe fn cleanup() {
|
2013-06-21 03:28:23 -05:00
|
|
|
args::cleanup();
|
2013-11-25 20:27:27 -06:00
|
|
|
local_ptr::cleanup();
|
2013-06-18 01:18:20 -05:00
|
|
|
}
|
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
/// Execute the main function in a scheduler.
|
|
|
|
///
|
|
|
|
/// Configures the runtime according to the environment, by default
|
|
|
|
/// using a task scheduler with the same number of threads as cores.
|
|
|
|
/// Returns a process exit code.
|
2013-11-18 15:25:09 -06:00
|
|
|
pub fn run(main: proc()) -> int {
|
2013-07-17 18:48:46 -05:00
|
|
|
run_(main, false)
|
|
|
|
}
|
2013-06-19 03:08:47 -05:00
|
|
|
|
2013-11-18 15:25:09 -06:00
|
|
|
pub fn run_on_main_thread(main: proc()) -> int {
|
2013-07-17 18:48:46 -05:00
|
|
|
run_(main, true)
|
|
|
|
}
|
|
|
|
|
2013-11-18 15:25:09 -06:00
|
|
|
fn run_(main: proc(), use_main_sched: bool) -> int {
|
2013-06-19 02:39:10 -05:00
|
|
|
static DEFAULT_ERROR_CODE: int = 101;
|
|
|
|
|
2013-07-17 18:48:46 -05:00
|
|
|
let nscheds = util::default_sched_threads();
|
2013-06-18 02:17:14 -05:00
|
|
|
|
2013-12-03 18:44:16 -06:00
|
|
|
let mut main = Some(main);
|
2013-07-29 15:34:08 -05:00
|
|
|
|
2013-08-05 15:06:24 -05:00
|
|
|
// The shared list of sleeping schedulers.
|
2013-06-18 02:17:14 -05:00
|
|
|
let sleepers = SleeperList::new();
|
2013-08-05 15:06:24 -05:00
|
|
|
|
|
|
|
// Create a work queue for each scheduler, ntimes. Create an extra
|
|
|
|
// for the main thread if that flag is set. We won't steal from it.
|
2013-12-03 21:37:57 -06:00
|
|
|
let mut pool = deque::BufferPool::new();
|
2013-11-26 11:40:24 -06:00
|
|
|
let arr = vec::from_fn(nscheds, |_| pool.deque());
|
|
|
|
let (workers, stealers) = vec::unzip(arr.move_iter());
|
2013-06-18 02:17:14 -05:00
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
// The schedulers.
|
2013-06-18 02:17:14 -05:00
|
|
|
let mut scheds = ~[];
|
2013-06-19 03:08:47 -05:00
|
|
|
// Handles to the schedulers. When the main task ends these will be
|
|
|
|
// sent the Shutdown message to terminate the schedulers.
|
|
|
|
let mut handles = ~[];
|
2013-06-18 02:17:14 -05:00
|
|
|
|
2013-11-26 11:40:24 -06:00
|
|
|
for worker in workers.move_iter() {
|
2013-07-31 15:52:22 -05:00
|
|
|
rtdebug!("inserting a regular scheduler");
|
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
// Every scheduler is driven by an I/O event loop.
|
2013-10-22 17:13:18 -05:00
|
|
|
let loop_ = new_event_loop();
|
2013-08-05 15:06:24 -05:00
|
|
|
let mut sched = ~Scheduler::new(loop_,
|
2013-11-26 11:40:24 -06:00
|
|
|
worker,
|
|
|
|
stealers.clone(),
|
2013-08-05 15:06:24 -05:00
|
|
|
sleepers.clone());
|
2013-06-18 02:17:14 -05:00
|
|
|
let handle = sched.make_handle();
|
|
|
|
|
|
|
|
scheds.push(sched);
|
2013-06-19 03:08:47 -05:00
|
|
|
handles.push(handle);
|
2013-06-18 02:17:14 -05:00
|
|
|
}
|
|
|
|
|
2013-07-17 18:48:46 -05:00
|
|
|
// If we need a main-thread task then create a main thread scheduler
|
|
|
|
// that will reject any task that isn't pinned to it
|
2013-07-29 15:34:08 -05:00
|
|
|
let main_sched = if use_main_sched {
|
|
|
|
|
|
|
|
// Create a friend handle.
|
|
|
|
let mut friend_sched = scheds.pop();
|
|
|
|
let friend_handle = friend_sched.make_handle();
|
|
|
|
scheds.push(friend_sched);
|
|
|
|
|
2013-08-05 15:06:24 -05:00
|
|
|
// This scheduler needs a queue that isn't part of the stealee
|
|
|
|
// set.
|
2013-11-26 11:40:24 -06:00
|
|
|
let (worker, _) = pool.deque();
|
2013-08-05 15:06:24 -05:00
|
|
|
|
2013-10-22 17:13:18 -05:00
|
|
|
let main_loop = new_event_loop();
|
2013-07-17 18:48:46 -05:00
|
|
|
let mut main_sched = ~Scheduler::new_special(main_loop,
|
2013-11-26 11:40:24 -06:00
|
|
|
worker,
|
|
|
|
stealers.clone(),
|
2013-07-17 18:48:46 -05:00
|
|
|
sleepers.clone(),
|
2013-07-29 15:34:08 -05:00
|
|
|
false,
|
|
|
|
Some(friend_handle));
|
2013-10-14 18:08:18 -05:00
|
|
|
let mut main_handle = main_sched.make_handle();
|
|
|
|
// Allow the scheduler to exit when the main task exits.
|
|
|
|
// Note: sending the shutdown message also prevents the scheduler
|
|
|
|
// from pushing itself to the sleeper list, which is used for
|
|
|
|
// waking up schedulers for work stealing; since this is a
|
|
|
|
// non-work-stealing scheduler it should not be adding itself
|
|
|
|
// to the list.
|
2013-10-22 17:09:23 -05:00
|
|
|
main_handle.send(Shutdown);
|
2013-07-17 18:48:46 -05:00
|
|
|
Some(main_sched)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
// Create a shared cell for transmitting the process exit
|
|
|
|
// code from the main task to this function.
|
2013-08-27 05:00:57 -05:00
|
|
|
let exit_code = UnsafeArc::new(AtomicInt::new(0));
|
2013-06-19 02:39:10 -05:00
|
|
|
let exit_code_clone = exit_code.clone();
|
|
|
|
|
2013-10-05 23:58:55 -05:00
|
|
|
// Used to sanity check that the runtime only exits once
|
|
|
|
let exited_already = UnsafeArc::new(AtomicBool::new(false));
|
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
// When the main task exits, after all the tasks in the main
|
|
|
|
// task tree, shut down the schedulers and set the exit code.
|
2013-11-22 01:36:52 -06:00
|
|
|
let handles = handles;
|
2013-12-05 20:19:06 -06:00
|
|
|
let on_exit: proc(TaskResult) = proc(exit_success) {
|
2013-10-05 23:58:55 -05:00
|
|
|
unsafe {
|
|
|
|
assert!(!(*exited_already.get()).swap(true, SeqCst),
|
|
|
|
"the runtime already exited");
|
|
|
|
}
|
2013-06-18 02:17:14 -05:00
|
|
|
|
2013-11-22 01:36:52 -06:00
|
|
|
let mut handles = handles;
|
2013-08-03 11:45:23 -05:00
|
|
|
for handle in handles.mut_iter() {
|
2013-06-18 02:17:14 -05:00
|
|
|
handle.send(Shutdown);
|
|
|
|
}
|
|
|
|
|
2013-06-19 02:39:10 -05:00
|
|
|
unsafe {
|
2013-12-05 20:19:06 -06:00
|
|
|
let exit_code = if exit_success.is_ok() {
|
2013-07-09 15:29:05 -05:00
|
|
|
use rt::util;
|
|
|
|
|
|
|
|
// If we're exiting successfully, then return the global
|
|
|
|
// exit status, which can be set programmatically.
|
|
|
|
util::get_exit_status()
|
|
|
|
} else {
|
|
|
|
DEFAULT_ERROR_CODE
|
|
|
|
};
|
2013-06-19 02:39:10 -05:00
|
|
|
(*exit_code_clone.get()).store(exit_code, SeqCst);
|
|
|
|
}
|
2013-06-18 02:17:14 -05:00
|
|
|
};
|
2013-06-19 03:08:47 -05:00
|
|
|
|
2013-06-18 02:17:14 -05:00
|
|
|
let mut threads = ~[];
|
2013-12-03 18:44:16 -06:00
|
|
|
let mut on_exit = Some(on_exit);
|
2013-07-29 15:34:08 -05:00
|
|
|
|
2013-07-19 16:25:05 -05:00
|
|
|
if !use_main_sched {
|
|
|
|
|
|
|
|
// In the case where we do not use a main_thread scheduler we
|
|
|
|
// run the main task in one of our threads.
|
2013-07-29 15:34:08 -05:00
|
|
|
|
2013-12-03 18:44:16 -06:00
|
|
|
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
|
|
|
|
None,
|
|
|
|
::util::replace(&mut main,
|
|
|
|
None).unwrap());
|
2013-11-01 11:16:11 -05:00
|
|
|
main_task.name = Some(SendStrStatic("<main>"));
|
2013-12-03 18:44:16 -06:00
|
|
|
main_task.death.on_exit = ::util::replace(&mut on_exit, None);
|
2013-07-19 16:25:05 -05:00
|
|
|
|
2013-06-18 02:17:14 -05:00
|
|
|
let sched = scheds.pop();
|
2013-12-03 18:44:16 -06:00
|
|
|
let main_task = main_task;
|
2013-06-18 02:17:14 -05:00
|
|
|
let thread = do Thread::start {
|
2013-12-03 18:44:16 -06:00
|
|
|
sched.bootstrap(main_task);
|
2013-06-18 02:17:14 -05:00
|
|
|
};
|
|
|
|
threads.push(thread);
|
|
|
|
}
|
|
|
|
|
2013-07-19 16:25:05 -05:00
|
|
|
// Run each remaining scheduler in a thread.
|
2013-08-29 06:49:55 -05:00
|
|
|
for sched in scheds.move_rev_iter() {
|
2013-07-31 15:52:22 -05:00
|
|
|
rtdebug!("creating regular schedulers");
|
2013-07-19 16:25:05 -05:00
|
|
|
let thread = do Thread::start {
|
2013-12-03 18:44:16 -06:00
|
|
|
let mut sched = sched;
|
2013-08-05 15:10:08 -05:00
|
|
|
let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
|
2013-07-19 16:25:05 -05:00
|
|
|
rtdebug!("boostraping a non-primary scheduler");
|
|
|
|
};
|
|
|
|
sched.bootstrap(bootstrap_task);
|
|
|
|
};
|
|
|
|
threads.push(thread);
|
2013-07-17 18:48:46 -05:00
|
|
|
}
|
|
|
|
|
2013-07-19 16:25:05 -05:00
|
|
|
// If we do have a main thread scheduler, run it now.
|
2013-07-29 15:34:08 -05:00
|
|
|
|
2013-07-19 16:25:05 -05:00
|
|
|
if use_main_sched {
|
2013-07-31 15:52:22 -05:00
|
|
|
rtdebug!("about to create the main scheduler task");
|
|
|
|
|
2013-08-03 18:59:24 -05:00
|
|
|
let mut main_sched = main_sched.unwrap();
|
2013-07-29 15:34:08 -05:00
|
|
|
|
2013-07-19 16:25:05 -05:00
|
|
|
let home = Sched(main_sched.make_handle());
|
2013-12-03 18:44:16 -06:00
|
|
|
let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
|
|
|
|
None,
|
|
|
|
home,
|
|
|
|
::util::replace(&mut main,
|
|
|
|
None).
|
|
|
|
unwrap());
|
2013-11-01 11:16:11 -05:00
|
|
|
main_task.name = Some(SendStrStatic("<main>"));
|
2013-12-03 18:44:16 -06:00
|
|
|
main_task.death.on_exit = ::util::replace(&mut on_exit, None);
|
2013-08-05 15:06:24 -05:00
|
|
|
rtdebug!("bootstrapping main_task");
|
2013-07-31 15:52:22 -05:00
|
|
|
|
2013-07-29 15:34:08 -05:00
|
|
|
main_sched.bootstrap(main_task);
|
2013-07-19 16:25:05 -05:00
|
|
|
}
|
2013-07-29 15:34:08 -05:00
|
|
|
|
2013-07-31 15:52:22 -05:00
|
|
|
rtdebug!("waiting for threads");
|
|
|
|
|
2013-06-18 02:17:14 -05:00
|
|
|
// Wait for schedulers
|
2013-08-07 21:21:36 -05:00
|
|
|
for thread in threads.move_iter() {
|
2013-07-27 14:05:15 -05:00
|
|
|
thread.join();
|
|
|
|
}
|
2013-06-19 02:39:10 -05:00
|
|
|
|
2013-06-19 03:08:47 -05:00
|
|
|
// Return the exit code
|
2013-06-19 02:39:10 -05:00
|
|
|
unsafe {
|
|
|
|
(*exit_code.get()).load(SeqCst)
|
|
|
|
}
|
2013-06-18 02:17:14 -05:00
|
|
|
}
|
|
|
|
|
2013-08-09 03:15:31 -05:00
|
|
|
pub fn in_sched_context() -> bool {
|
|
|
|
unsafe {
|
2013-08-08 13:38:10 -05:00
|
|
|
let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
|
|
|
|
match task_ptr {
|
2013-08-09 03:15:31 -05:00
|
|
|
Some(task) => {
|
|
|
|
match (*task).task_type {
|
|
|
|
SchedTask => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn in_green_task_context() -> bool {
|
|
|
|
unsafe {
|
2013-08-08 13:38:10 -05:00
|
|
|
let task: Option<*mut Task> = Local::try_unsafe_borrow();
|
|
|
|
match task {
|
2013-08-09 03:15:31 -05:00
|
|
|
Some(task) => {
|
|
|
|
match (*task).task_type {
|
|
|
|
GreenTask(_) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => false
|
|
|
|
}
|
|
|
|
}
|
2013-08-01 01:12:20 -05:00
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
|
|
|
|
pub fn new_event_loop() -> ~rtio::EventLoop {
|
|
|
|
match crate_map::get_crate_map() {
|
|
|
|
None => {}
|
|
|
|
Some(map) => {
|
|
|
|
match map.event_loop_factory {
|
|
|
|
None => {}
|
|
|
|
Some(factory) => return factory()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the crate map didn't specify a factory to create an event loop, then
|
|
|
|
// instead just use a basic event loop missing all I/O services to at least
|
|
|
|
// get the scheduler running.
|
|
|
|
return basic::event_loop();
|
|
|
|
}
|