diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 022e73121d7f4..28e9338ddfedc 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -48,7 +48,6 @@ #![allow(dead_code)] -use failure; use os; use thunk::Thunk; use kinds::Send; @@ -73,8 +72,8 @@ mod macros; // These should be refactored/moved/made private over time pub mod util; pub mod unwind; +pub mod args; -mod args; mod at_exit_imp; mod libunwind; @@ -82,43 +81,15 @@ mod libunwind; /// of exiting cleanly. pub const DEFAULT_ERROR_CODE: int = 101; -/// One-time runtime initialization. -/// -/// Initializes global state, including frobbing -/// the crate's logging flags, registering GC -/// metadata, and storing the process arguments. -// FIXME: this should be unsafe -#[allow(experimental)] -pub fn init(argc: int, argv: *const *const u8) { - unsafe { - args::init(argc, argv); - thread::init(); - unwind::register(failure::on_fail); - } -} - #[cfg(any(windows, android))] -static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; +const OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; #[cfg(all(unix, not(android)))] -static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); +const OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); #[cfg(not(test))] #[lang = "start"] fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { use mem; - start(argc, argv, Thunk::new(move|| { - let main: extern "Rust" fn() = unsafe { mem::transmute(main) }; - main(); - })) -} - -/// Executes the given procedure after initializing the runtime with the given -/// argc/argv. -/// -/// This procedure is guaranteed to run on the thread calling this function, but -/// the stack bounds for this rust task will *not* be set. Care must be taken -/// for this function to not overflow its stack. -pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int { use prelude::*; use rt; @@ -131,40 +102,59 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int { // frames above our current position. let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE; - // By default, some platforms will send a *signal* when a EPIPE error would - // otherwise be delivered. This runtime doesn't install a SIGPIPE handler, - // causing it to kill the program, which isn't exactly what we want! - // - // Hence, we set SIGPIPE to ignore when the program starts up in order to - // prevent this problem. - #[cfg(windows)] fn ignore_sigpipe() {} - #[cfg(unix)] fn ignore_sigpipe() { - use libc; - use libc::funcs::posix01::signal::signal; - unsafe { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1); + let failed = unsafe { + // First, make sure we don't trigger any __morestack overflow checks, + // and next set up our stack to have a guard page and run through our + // own fault handlers if we hit it. + sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, + my_stack_top); + sys::thread::guard::init(); + sys::stack_overflow::init(); + + // Next, set up the current Thread with the guard information we just + // created. Note that this isn't necessary in general for new threads, + // but we just do this to name the main thread and to give it correct + // info about the stack bounds. + let thread: Thread = NewThread::new(Some("
".into_string())); + thread_info::set((my_stack_bottom, my_stack_top), + sys::thread::guard::main(), + thread); + + // By default, some platforms will send a *signal* when a EPIPE error + // would otherwise be delivered. This runtime doesn't install a SIGPIPE + // handler, causing it to kill the program, which isn't exactly what we + // want! + // + // Hence, we set SIGPIPE to ignore when the program starts up in order + // to prevent this problem. + #[cfg(windows)] fn ignore_sigpipe() {} + #[cfg(unix)] fn ignore_sigpipe() { + use libc; + use libc::funcs::posix01::signal::signal; + unsafe { + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1); + } } - } - ignore_sigpipe(); - - init(argc, argv); - let mut exit_code = None; - - let thread: Thread = NewThread::new(Some("
".into_string())); - thread_info::set((my_stack_bottom, my_stack_top), - unsafe { sys::thread::guard::main() }, - thread); - let mut main_opt = Some(main); // option dance - unsafe { - let _ = unwind::try(|| { - sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); - (main_opt.take().unwrap()).invoke(); - exit_code = Some(os::get_exit_status()); + ignore_sigpipe(); + + // Store our args if necessary in a squirreled away location + args::init(argc, argv); + + // And finally, let's run some code! + let res = unwind::try(|| { + let main: fn() = mem::transmute(main); + main(); }); cleanup(); + res.is_err() + }; + + // If the exit code wasn't set, then the try block must have panicked. + if failed { + rt::DEFAULT_ERROR_CODE + } else { + os::get_exit_status() } - // If the exit code wasn't set, then the task block must have panicked. - return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE); } /// Enqueues a procedure to run when the runtime is cleaned up diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index f9f76e35bd4a0..1beab8be90965 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -59,18 +59,20 @@ use core::prelude::*; -use boxed::Box; -use string::String; -use str::StrAllocating; -use vec::Vec; use any::Any; -use sync::atomic; +use boxed::Box; use cmp; +use failure; use fmt; use intrinsics; +use libc::c_void; use mem; use raw::Closure; -use libc::c_void; +use str::StrAllocating; +use string::String; +use sync::atomic; +use sync::{Once, ONCE_INIT}; +use vec::Vec; use sys_common::thread_info; use rt::libunwind as uw; @@ -541,6 +543,11 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> /// }` from ~1900/3700 (-O/no opts) to 180/590. #[inline(never)] #[cold] // this is the slow path, please never inline this fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> ! { + // Make sure the default failure handler is registered before we look at the + // callbacks. + static INIT: Once = ONCE_INIT; + INIT.doit(|| unsafe { register(failure::on_fail); }); + // First, invoke call the user-defined callbacks triggered on task panic. // // By the time that we see a callback has been registered (by reading