diff options
Diffstat (limited to 'src/libstd/rt/mod.rs')
| -rw-r--r-- | src/libstd/rt/mod.rs | 113 |
1 files changed, 79 insertions, 34 deletions
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 581e3addff0..bbf1cf0d9b7 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -58,22 +58,23 @@ Several modules in `core` are clients of `rt`: #[deny(unused_imports)]; #[deny(unused_mut)]; #[deny(unused_variable)]; +#[deny(unused_unsafe)]; use cell::Cell; use clone::Clone; use container::Container; -use from_str::FromStr; +use iter::Times; use iterator::IteratorUtil; -use option::{Some, None}; -use os; +use option::Some; use ptr::RawPtr; -use uint; use rt::sched::{Scheduler, Coroutine, Shutdown}; use rt::sleeper_list::SleeperList; use rt::task::Task; use rt::thread::Thread; use rt::work_queue::WorkQueue; use rt::uv::uvio::UvEventLoop; +use unstable::atomics::{AtomicInt, SeqCst}; +use unstable::sync::UnsafeAtomicRcBox; use vec::{OwnedVector, MutableVector}; /// The global (exchange) heap. @@ -122,7 +123,7 @@ mod thread; pub mod env; /// The local, managed heap -mod local_heap; +pub mod local_heap; /// The Logger trait and implementations pub mod logging; @@ -148,7 +149,7 @@ pub mod local_ptr; /// Bindings to pthread/windows thread-local storage. pub mod thread_local_storage; -/// A concurrent data structure with which parent tasks wait on child tasks. +/// For waiting on child tasks. pub mod join_latch; pub mod metrics; @@ -157,6 +158,12 @@ pub mod metrics; /// Just stuff pub mod util; +// Global command line argument storage +pub mod args; + +// Support for dynamic borrowck +pub mod borrowck; + /// Set up a default runtime configuration, given compiler-supplied arguments. /// /// This is invoked by the `start` _language item_ (unstable::lang) to @@ -171,71 +178,104 @@ pub mod util; /// # Return value /// /// The return value is used as the process return code. 0 on success, 101 on error. -pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int { +pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int { - init(crate_map); - run(main); + init(argc, argv, crate_map); + let exit_code = run(main); cleanup(); - return 0; + return exit_code; } -/// One-time runtime initialization. Currently all this does is set up logging -/// based on the RUST_LOG environment variable. -pub fn init(crate_map: *u8) { - logging::init(crate_map); +/// One-time runtime initialization. +/// +/// Initializes global state, including frobbing +/// the crate's logging flags, registering GC +/// metadata, and storing the process arguments. +pub fn init(argc: int, argv: **u8, crate_map: *u8) { + // XXX: Derefing these pointers is not safe. + // Need to propagate the unsafety to `start`. + unsafe { + args::init(argc, argv); + logging::init(crate_map); + rust_update_gc_metadata(crate_map); + } + + extern { + fn rust_update_gc_metadata(crate_map: *u8); + } } +/// One-time runtime cleanup. pub fn cleanup() { + args::cleanup(); global_heap::cleanup(); } -pub fn run(main: ~fn()) { - let nthreads = match os::getenv("RUST_THREADS") { - Some(nstr) => FromStr::from_str(nstr).get(), - None => unsafe { - // Using more threads than cores in test code - // to force the OS to preempt them frequently. - // Assuming that this help stress test concurrent types. - util::num_cpus() * 2 - } - }; +/// 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. +pub fn run(main: ~fn()) -> int { + + static DEFAULT_ERROR_CODE: int = 101; + let nthreads = util::default_sched_threads(); + + // The shared list of sleeping schedulers. Schedulers wake each other + // occassionally to do new work. let sleepers = SleeperList::new(); + // The shared work queue. Temporary until work stealing is implemented. let work_queue = WorkQueue::new(); - let mut handles = ~[]; + // The schedulers. let mut scheds = ~[]; + // Handles to the schedulers. When the main task ends these will be + // sent the Shutdown message to terminate the schedulers. + let mut handles = ~[]; - for uint::range(0, nthreads) |_| { + for nthreads.times { + // Every scheduler is driven by an I/O event loop. let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone()); let handle = sched.make_handle(); - handles.push(handle); scheds.push(sched); + handles.push(handle); } - let main_cell = Cell::new(main); + // Create a shared cell for transmitting the process exit + // code from the main task to this function. + let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0)); + let exit_code_clone = exit_code.clone(); + + // When the main task exits, after all the tasks in the main + // task tree, shut down the schedulers and set the exit code. let handles = Cell::new(handles); - let mut new_task = ~Task::new_root(); - let on_exit: ~fn(bool) = |exit_status| { + let on_exit: ~fn(bool) = |exit_success| { let mut handles = handles.take(); - // Tell schedulers to exit for handles.mut_iter().advance |handle| { handle.send(Shutdown); } - rtassert!(exit_status); + unsafe { + let exit_code = if exit_success { 0 } else { DEFAULT_ERROR_CODE }; + (*exit_code_clone.get()).store(exit_code, SeqCst); + } }; + + // Create and enqueue the main task. + let main_cell = Cell::new(main); + let mut new_task = ~Task::new_root(); new_task.on_exit = Some(on_exit); let main_task = ~Coroutine::with_task(&mut scheds[0].stack_pool, new_task, main_cell.take()); scheds[0].enqueue_task(main_task); + // Run each scheduler in a thread. let mut threads = ~[]; - while !scheds.is_empty() { let sched = scheds.pop(); let sched_cell = Cell::new(sched); @@ -248,7 +288,12 @@ pub fn run(main: ~fn()) { } // Wait for schedulers - let _threads = threads; + { let _threads = threads; } + + // Return the exit code + unsafe { + (*exit_code.get()).load(SeqCst) + } } /// Possible contexts in which Rust code may be executing. |
