about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-06-20 11:26:29 -0700
committerBrian Anderson <banderson@mozilla.com>2013-06-20 11:26:29 -0700
commitbbf5469b750233455e47a48d477a8c9a5a724a9a (patch)
tree3a3ceac1a87e2ad87aeb1dd7855f57cab15ddb90 /src
parentb548c781aa959085474d9e16f11a4dffb8420af5 (diff)
parent391bb0b4e7131cd7d30e03deea3eb9756a7c8954 (diff)
downloadrust-bbf5469b750233455e47a48d477a8c9a5a724a9a.tar.gz
rust-bbf5469b750233455e47a48d477a8c9a5a724a9a.zip
Merge remote-tracking branch 'brson/io-wip' into io
Diffstat (limited to 'src')
-rw-r--r--src/libstd/rt/mod.rs76
-rw-r--r--src/libstd/sys.rs13
-rw-r--r--src/rt/rust_gc_metadata.cpp5
-rw-r--r--src/rt/rustrt.def.in1
4 files changed, 72 insertions, 23 deletions
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 581e3addff0..a80fb15bad7 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -63,17 +63,19 @@ 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 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.
@@ -148,7 +150,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;
@@ -174,68 +176,95 @@ pub mod util;
 pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int {
 
     init(crate_map);
-    run(main);
+    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);
+    unsafe { rust_update_gc_metadata(crate_map) }
+
+    extern {
+        fn rust_update_gc_metadata(crate_map: *u8);
+    }
 }
 
+/// One-time runtime cleanup.
 pub fn cleanup() {
     global_heap::cleanup();
 }
 
-pub fn run(main: ~fn()) {
+/// 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 = 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
-        }
+        None => unsafe { util::num_cpus() }
     };
 
+    // 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 +277,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.
diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs
index e49ad348542..f2591996e3a 100644
--- a/src/libstd/sys.rs
+++ b/src/libstd/sys.rs
@@ -180,10 +180,13 @@ impl FailWithCause for &'static str {
 
 // FIXME #4427: Temporary until rt::rt_fail_ goes away
 pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
+    use cell::Cell;
     use option::Option;
+    use either::Left;
     use rt::{context, OldTaskContext, TaskContext};
     use rt::task::{Task, Unwinder};
     use rt::local::Local;
+    use rt::logging::Logger;
 
     let context = context();
     match context {
@@ -200,12 +203,18 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
                 let msg = str::raw::from_c_str(msg);
                 let file = str::raw::from_c_str(file);
 
-                let outmsg = fmt!("%s at line %i of file %s", msg, line as int, file);
+                let outmsg = fmt!("task failed: '%s' at line %i of file %s",
+                                  msg, line as int, file);
 
                 // XXX: Logging doesn't work correctly in non-task context because it
                 // invokes the local heap
                 if context == TaskContext {
-                    error!(outmsg);
+                    // XXX: Logging doesn't work here - the check to call the log
+                    // function never passes - so calling the log function directly.
+                    let outmsg = Cell::new(outmsg);
+                    do Local::borrow::<Task, ()> |task| {
+                        task.logger.log(Left(outmsg.take()));
+                    }
                 } else {
                     rtdebug!("%s", outmsg);
                 }
diff --git a/src/rt/rust_gc_metadata.cpp b/src/rt/rust_gc_metadata.cpp
index fbf0575b31d..e37856255a7 100644
--- a/src/rt/rust_gc_metadata.cpp
+++ b/src/rt/rust_gc_metadata.cpp
@@ -79,6 +79,11 @@ rust_gc_metadata() {
     return (void *)global_safe_points;
 }
 
+extern "C" CDECL void
+rust_update_gc_metadata(const void* map) {
+    update_gc_metadata(map);
+}
+
 //
 // Local Variables:
 // mode: C++
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index 9b49583519e..c93d29f6148 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -178,6 +178,7 @@ rust_call_tydesc_glue
 tdefl_compress_mem_to_heap
 tinfl_decompress_mem_to_heap
 rust_gc_metadata
+rust_update_gc_metadata
 rust_uv_ip4_port
 rust_uv_ip6_port
 rust_uv_tcp_getpeername