about summary refs log tree commit diff
path: root/src/libstd/rt/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/rt/mod.rs')
-rw-r--r--src/libstd/rt/mod.rs113
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.