mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-04 04:39:16 +00:00
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.
This commit is contained in:
parent
7a6c54c46e
commit
a7061d02e1
@ -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();
|
||||
ignore_sigpipe();
|
||||
|
||||
init(argc, argv);
|
||||
let mut exit_code = None;
|
||||
// Store our args if necessary in a squirreled away location
|
||||
args::init(argc, argv);
|
||||
|
||||
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());
|
||||
// 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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user