diff options
| author | Brian Anderson <banderson@mozilla.com> | 2013-06-20 11:26:29 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-06-20 11:26:29 -0700 |
| commit | bbf5469b750233455e47a48d477a8c9a5a724a9a (patch) | |
| tree | 3a3ceac1a87e2ad87aeb1dd7855f57cab15ddb90 /src | |
| parent | b548c781aa959085474d9e16f11a4dffb8420af5 (diff) | |
| parent | 391bb0b4e7131cd7d30e03deea3eb9756a7c8954 (diff) | |
| download | rust-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.rs | 76 | ||||
| -rw-r--r-- | src/libstd/sys.rs | 13 | ||||
| -rw-r--r-- | src/rt/rust_gc_metadata.cpp | 5 | ||||
| -rw-r--r-- | src/rt/rustrt.def.in | 1 |
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 |
