about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-12-10 07:37:56 -0800
committerAaron Turon <aturon@mozilla.com>2014-12-18 23:31:52 -0800
commita7061d02e16d0821d3af2b753155fe44bab7725c (patch)
tree79cb020fe5ff6d7c2d7f5be49c7e8e947e34e48e /src/libstd/rt
parent7a6c54c46e6ac28d82f940f1d1bf8d0a5fd7e820 (diff)
downloadrust-a7061d02e16d0821d3af2b753155fe44bab7725c.tar.gz
rust-a7061d02e16d0821d3af2b753155fe44bab7725c.zip
Tweak the startup routine to pass on linux
We need to be sure to init thread_info before we init args for example because
args is grabbing locks which may entail looking at the local thread eventually.
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/mod.rs114
-rw-r--r--src/libstd/rt/unwind.rs19
2 files changed, 65 insertions, 68 deletions
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 022e73121d7..28e9338ddfe 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("<main>".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("<main>".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 f9f76e35bd4..1beab8be909 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<M: Any + Send>(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<Any + Send>, 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