Skip to content

Commit a7061d0

Browse files
alexcrichtonaturon
authored andcommitted
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.
1 parent 7a6c54c commit a7061d0

File tree

2 files changed

+65
-68
lines changed

2 files changed

+65
-68
lines changed

src/libstd/rt/mod.rs

Lines changed: 52 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848

4949
#![allow(dead_code)]
5050

51-
use failure;
5251
use os;
5352
use thunk::Thunk;
5453
use kinds::Send;
@@ -73,52 +72,24 @@ mod macros;
7372
// These should be refactored/moved/made private over time
7473
pub mod util;
7574
pub mod unwind;
75+
pub mod args;
7676

77-
mod args;
7877
mod at_exit_imp;
7978
mod libunwind;
8079

8180
/// The default error code of the rust runtime if the main task panics instead
8281
/// of exiting cleanly.
8382
pub const DEFAULT_ERROR_CODE: int = 101;
8483

85-
/// One-time runtime initialization.
86-
///
87-
/// Initializes global state, including frobbing
88-
/// the crate's logging flags, registering GC
89-
/// metadata, and storing the process arguments.
90-
// FIXME: this should be unsafe
91-
#[allow(experimental)]
92-
pub fn init(argc: int, argv: *const *const u8) {
93-
unsafe {
94-
args::init(argc, argv);
95-
thread::init();
96-
unwind::register(failure::on_fail);
97-
}
98-
}
99-
10084
#[cfg(any(windows, android))]
101-
static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20;
85+
const OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20;
10286
#[cfg(all(unix, not(android)))]
103-
static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20);
87+
const OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20);
10488

10589
#[cfg(not(test))]
10690
#[lang = "start"]
10791
fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
10892
use mem;
109-
start(argc, argv, Thunk::new(move|| {
110-
let main: extern "Rust" fn() = unsafe { mem::transmute(main) };
111-
main();
112-
}))
113-
}
114-
115-
/// Executes the given procedure after initializing the runtime with the given
116-
/// argc/argv.
117-
///
118-
/// This procedure is guaranteed to run on the thread calling this function, but
119-
/// the stack bounds for this rust task will *not* be set. Care must be taken
120-
/// for this function to not overflow its stack.
121-
pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
12293
use prelude::*;
12394
use rt;
12495

@@ -131,40 +102,59 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
131102
// frames above our current position.
132103
let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE;
133104

134-
// By default, some platforms will send a *signal* when a EPIPE error would
135-
// otherwise be delivered. This runtime doesn't install a SIGPIPE handler,
136-
// causing it to kill the program, which isn't exactly what we want!
137-
//
138-
// Hence, we set SIGPIPE to ignore when the program starts up in order to
139-
// prevent this problem.
140-
#[cfg(windows)] fn ignore_sigpipe() {}
141-
#[cfg(unix)] fn ignore_sigpipe() {
142-
use libc;
143-
use libc::funcs::posix01::signal::signal;
144-
unsafe {
145-
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
105+
let failed = unsafe {
106+
// First, make sure we don't trigger any __morestack overflow checks,
107+
// and next set up our stack to have a guard page and run through our
108+
// own fault handlers if we hit it.
109+
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom,
110+
my_stack_top);
111+
sys::thread::guard::init();
112+
sys::stack_overflow::init();
113+
114+
// Next, set up the current Thread with the guard information we just
115+
// created. Note that this isn't necessary in general for new threads,
116+
// but we just do this to name the main thread and to give it correct
117+
// info about the stack bounds.
118+
let thread: Thread = NewThread::new(Some("<main>".into_string()));
119+
thread_info::set((my_stack_bottom, my_stack_top),
120+
sys::thread::guard::main(),
121+
thread);
122+
123+
// By default, some platforms will send a *signal* when a EPIPE error
124+
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
125+
// handler, causing it to kill the program, which isn't exactly what we
126+
// want!
127+
//
128+
// Hence, we set SIGPIPE to ignore when the program starts up in order
129+
// to prevent this problem.
130+
#[cfg(windows)] fn ignore_sigpipe() {}
131+
#[cfg(unix)] fn ignore_sigpipe() {
132+
use libc;
133+
use libc::funcs::posix01::signal::signal;
134+
unsafe {
135+
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
136+
}
146137
}
147-
}
148-
ignore_sigpipe();
149-
150-
init(argc, argv);
151-
let mut exit_code = None;
152-
153-
let thread: Thread = NewThread::new(Some("<main>".into_string()));
154-
thread_info::set((my_stack_bottom, my_stack_top),
155-
unsafe { sys::thread::guard::main() },
156-
thread);
157-
let mut main_opt = Some(main); // option dance
158-
unsafe {
159-
let _ = unwind::try(|| {
160-
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
161-
(main_opt.take().unwrap()).invoke();
162-
exit_code = Some(os::get_exit_status());
138+
ignore_sigpipe();
139+
140+
// Store our args if necessary in a squirreled away location
141+
args::init(argc, argv);
142+
143+
// And finally, let's run some code!
144+
let res = unwind::try(|| {
145+
let main: fn() = mem::transmute(main);
146+
main();
163147
});
164148
cleanup();
149+
res.is_err()
150+
};
151+
152+
// If the exit code wasn't set, then the try block must have panicked.
153+
if failed {
154+
rt::DEFAULT_ERROR_CODE
155+
} else {
156+
os::get_exit_status()
165157
}
166-
// If the exit code wasn't set, then the task block must have panicked.
167-
return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);
168158
}
169159

170160
/// Enqueues a procedure to run when the runtime is cleaned up

src/libstd/rt/unwind.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,20 @@
5959
6060
use core::prelude::*;
6161

62-
use boxed::Box;
63-
use string::String;
64-
use str::StrAllocating;
65-
use vec::Vec;
6662
use any::Any;
67-
use sync::atomic;
63+
use boxed::Box;
6864
use cmp;
65+
use failure;
6966
use fmt;
7067
use intrinsics;
68+
use libc::c_void;
7169
use mem;
7270
use raw::Closure;
73-
use libc::c_void;
71+
use str::StrAllocating;
72+
use string::String;
73+
use sync::atomic;
74+
use sync::{Once, ONCE_INIT};
75+
use vec::Vec;
7476

7577
use sys_common::thread_info;
7678
use rt::libunwind as uw;
@@ -541,6 +543,11 @@ pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, uint)) ->
541543
/// }` from ~1900/3700 (-O/no opts) to 180/590.
542544
#[inline(never)] #[cold] // this is the slow path, please never inline this
543545
fn begin_unwind_inner(msg: Box<Any + Send>, file_line: &(&'static str, uint)) -> ! {
546+
// Make sure the default failure handler is registered before we look at the
547+
// callbacks.
548+
static INIT: Once = ONCE_INIT;
549+
INIT.doit(|| unsafe { register(failure::on_fail); });
550+
544551
// First, invoke call the user-defined callbacks triggered on task panic.
545552
//
546553
// By the time that we see a callback has been registered (by reading

0 commit comments

Comments
 (0)