std: Internalize almost all of std::rt
This commit does some refactoring to make almost all of the `std::rt` private. Specifically, the following items are no longer part of its API: * DEFAULT_ERROR_CODE * backtrace * unwind * args * at_exit * cleanup * heap (this is just alloc::heap) * min_stack * util The module is now tagged as `#[doc(hidden)]` as the only purpose it's serve is an entry point for the `panic!` macro via the `begin_unwind` and `begin_unwind_fmt` reexports.
This commit is contained in:
parent
192c37537b
commit
f4be2026df
33 changed files with 273 additions and 432 deletions
|
@ -26,13 +26,16 @@ this is totally fine.
|
||||||
For instance, a custom implementation of `Box` might write `Drop` like this:
|
For instance, a custom implementation of `Box` might write `Drop` like this:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(heap_api, core_intrinsics, unique)]
|
#![feature(alloc, heap_api, core_intrinsics, unique)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use std::rt::heap;
|
|
||||||
use std::ptr::Unique;
|
use std::ptr::Unique;
|
||||||
use std::intrinsics::drop_in_place;
|
use std::intrinsics::drop_in_place;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use alloc::heap;
|
||||||
|
|
||||||
struct Box<T>{ ptr: Unique<T> }
|
struct Box<T>{ ptr: Unique<T> }
|
||||||
|
|
||||||
impl<T> Drop for Box<T> {
|
impl<T> Drop for Box<T> {
|
||||||
|
@ -45,6 +48,7 @@ impl<T> Drop for Box<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# fn main() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
and this works fine because when Rust goes to drop the `ptr` field it just sees
|
and this works fine because when Rust goes to drop the `ptr` field it just sees
|
||||||
|
@ -54,13 +58,16 @@ use-after-free the `ptr` because when drop exits, it becomes inacessible.
|
||||||
However this wouldn't work:
|
However this wouldn't work:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(heap_api, core_intrinsics, unique)]
|
#![feature(alloc, heap_api, core_intrinsics, unique)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use std::rt::heap;
|
|
||||||
use std::ptr::Unique;
|
use std::ptr::Unique;
|
||||||
use std::intrinsics::drop_in_place;
|
use std::intrinsics::drop_in_place;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use alloc::heap;
|
||||||
|
|
||||||
struct Box<T>{ ptr: Unique<T> }
|
struct Box<T>{ ptr: Unique<T> }
|
||||||
|
|
||||||
impl<T> Drop for Box<T> {
|
impl<T> Drop for Box<T> {
|
||||||
|
@ -87,6 +94,7 @@ impl<T> Drop for SuperBox<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# fn main() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
|
After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
|
||||||
|
@ -129,13 +137,16 @@ The classic safe solution to overriding recursive drop and allowing moving out
|
||||||
of Self during `drop` is to use an Option:
|
of Self during `drop` is to use an Option:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(heap_api, core_intrinsics, unique)]
|
#![feature(alloc, heap_api, core_intrinsics, unique)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use std::rt::heap;
|
|
||||||
use std::ptr::Unique;
|
use std::ptr::Unique;
|
||||||
use std::intrinsics::drop_in_place;
|
use std::intrinsics::drop_in_place;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use alloc::heap;
|
||||||
|
|
||||||
struct Box<T>{ ptr: Unique<T> }
|
struct Box<T>{ ptr: Unique<T> }
|
||||||
|
|
||||||
impl<T> Drop for Box<T> {
|
impl<T> Drop for Box<T> {
|
||||||
|
@ -165,6 +176,7 @@ impl<T> Drop for SuperBox<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# fn main() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
However this has fairly odd semantics: you're saying that a field that *should*
|
However this has fairly odd semantics: you're saying that a field that *should*
|
||||||
|
|
|
@ -9,7 +9,7 @@ This is perfectly fine because we already have `cap == 0` as our sentinel for no
|
||||||
allocation. We don't even need to handle it specially in almost any code because
|
allocation. We don't even need to handle it specially in almost any code because
|
||||||
we usually need to check if `cap > len` or `len > 0` anyway. The traditional
|
we usually need to check if `cap > len` or `len > 0` anyway. The traditional
|
||||||
Rust value to put here is `0x01`. The standard library actually exposes this
|
Rust value to put here is `0x01`. The standard library actually exposes this
|
||||||
as `std::rt::heap::EMPTY`. There are quite a few places where we'll
|
as `alloc::heap::EMPTY`. There are quite a few places where we'll
|
||||||
want to use `heap::EMPTY` because there's no real allocation to talk about but
|
want to use `heap::EMPTY` because there's no real allocation to talk about but
|
||||||
`null` would make the compiler do bad things.
|
`null` would make the compiler do bad things.
|
||||||
|
|
||||||
|
@ -20,11 +20,12 @@ the `heap` API anyway, so let's just get that dependency over with.
|
||||||
So:
|
So:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
#![feature(heap_api)]
|
#![feature(alloc, heap_api)]
|
||||||
|
|
||||||
use std::rt::heap::EMPTY;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use alloc::heap::EMPTY;
|
||||||
|
|
||||||
impl<T> Vec<T> {
|
impl<T> Vec<T> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
|
assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
|
||||||
|
|
|
@ -2,17 +2,16 @@
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(unique)]
|
#![feature(unique)]
|
||||||
#![feature(heap_api)]
|
#![feature(alloc, heap_api)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use std::ptr::{Unique, self};
|
use std::ptr::{Unique, self};
|
||||||
use std::rt::heap;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use alloc::heap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct RawVec<T> {
|
struct RawVec<T> {
|
||||||
ptr: Unique<T>,
|
ptr: Unique<T>,
|
||||||
|
|
|
@ -49,7 +49,8 @@ use std::marker;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::rt::heap::{allocate, deallocate};
|
|
||||||
|
use alloc::heap::{allocate, deallocate};
|
||||||
|
|
||||||
// The way arena uses arrays is really deeply awful. The arrays are
|
// The way arena uses arrays is really deeply awful. The arrays are
|
||||||
// allocated, and have capacities reserved, but the fill for the array
|
// allocated, and have capacities reserved, but the fill for the array
|
||||||
|
|
|
@ -174,7 +174,6 @@
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(iter_cmp)]
|
#![feature(iter_cmp)]
|
||||||
#![feature(rt)]
|
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(static_mutex)]
|
#![feature(static_mutex)]
|
||||||
|
|
||||||
|
@ -185,7 +184,6 @@ use std::io::prelude::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rt;
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::{Once, StaticMutex};
|
use std::sync::{Once, StaticMutex};
|
||||||
|
|
||||||
|
@ -292,7 +290,6 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
|
||||||
let _g = LOCK.lock();
|
let _g = LOCK.lock();
|
||||||
match FILTER as usize {
|
match FILTER as usize {
|
||||||
0 => {}
|
0 => {}
|
||||||
1 => panic!("cannot log after main thread has exited"),
|
|
||||||
n => {
|
n => {
|
||||||
let filter = mem::transmute::<_, &String>(n);
|
let filter = mem::transmute::<_, &String>(n);
|
||||||
if !args.to_string().contains(filter) {
|
if !args.to_string().contains(filter) {
|
||||||
|
@ -385,9 +382,6 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
|
||||||
let _g = LOCK.lock();
|
let _g = LOCK.lock();
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(DIRECTIVES as usize != 0);
|
assert!(DIRECTIVES as usize != 0);
|
||||||
assert!(DIRECTIVES as usize != 1,
|
|
||||||
"cannot log after the main thread has exited");
|
|
||||||
|
|
||||||
enabled(level, module, (*DIRECTIVES).iter())
|
enabled(level, module, (*DIRECTIVES).iter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,19 +436,6 @@ fn init() {
|
||||||
|
|
||||||
assert!(DIRECTIVES.is_null());
|
assert!(DIRECTIVES.is_null());
|
||||||
DIRECTIVES = Box::into_raw(box directives);
|
DIRECTIVES = Box::into_raw(box directives);
|
||||||
|
|
||||||
// Schedule the cleanup for the globals for when the runtime exits.
|
|
||||||
let _ = rt::at_exit(move || {
|
|
||||||
let _g = LOCK.lock();
|
|
||||||
assert!(!DIRECTIVES.is_null());
|
|
||||||
let _directives = Box::from_raw(DIRECTIVES);
|
|
||||||
DIRECTIVES = 1 as *mut _;
|
|
||||||
|
|
||||||
if !FILTER.is_null() {
|
|
||||||
let _filter = Box::from_raw(FILTER);
|
|
||||||
FILTER = 1 as *mut _;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,23 +8,20 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use self::BucketState::*;
|
use alloc::heap::{allocate, deallocate, EMPTY};
|
||||||
|
|
||||||
use clone::Clone;
|
|
||||||
use cmp;
|
use cmp;
|
||||||
use hash::{Hash, Hasher};
|
use hash::{Hash, Hasher};
|
||||||
use iter::{Iterator, ExactSizeIterator};
|
use marker;
|
||||||
use marker::{Copy, Send, Sync, Sized, self};
|
|
||||||
use mem::{align_of, size_of};
|
use mem::{align_of, size_of};
|
||||||
use mem;
|
use mem;
|
||||||
use num::wrapping::OverflowingOps;
|
use num::wrapping::OverflowingOps;
|
||||||
use ops::{Deref, DerefMut, Drop};
|
use ops::{Deref, DerefMut};
|
||||||
use option::Option;
|
|
||||||
use option::Option::{Some, None};
|
|
||||||
use ptr::{self, Unique};
|
use ptr::{self, Unique};
|
||||||
use rt::heap::{allocate, deallocate, EMPTY};
|
|
||||||
use collections::hash_state::HashState;
|
use collections::hash_state::HashState;
|
||||||
|
|
||||||
|
use self::BucketState::*;
|
||||||
|
|
||||||
const EMPTY_BUCKET: u64 = 0;
|
const EMPTY_BUCKET: u64 = 0;
|
||||||
|
|
||||||
/// The raw hashtable, providing safe-ish access to the unzipped and highly
|
/// The raw hashtable, providing safe-ish access to the unzipped and highly
|
||||||
|
|
|
@ -12,8 +12,8 @@ use prelude::v1::*;
|
||||||
|
|
||||||
use cell::Cell;
|
use cell::Cell;
|
||||||
use ptr;
|
use ptr;
|
||||||
use rt;
|
|
||||||
use sync::{StaticMutex, Arc};
|
use sync::{StaticMutex, Arc};
|
||||||
|
use sys_common;
|
||||||
|
|
||||||
pub struct Lazy<T> {
|
pub struct Lazy<T> {
|
||||||
lock: StaticMutex,
|
lock: StaticMutex,
|
||||||
|
@ -51,7 +51,7 @@ impl<T: Send + Sync + 'static> Lazy<T> {
|
||||||
// `Arc` allocation in our own internal box (it will get deallocated by
|
// `Arc` allocation in our own internal box (it will get deallocated by
|
||||||
// the at exit handler). Otherwise we just return the freshly allocated
|
// the at exit handler). Otherwise we just return the freshly allocated
|
||||||
// `Arc`.
|
// `Arc`.
|
||||||
let registered = rt::at_exit(move || {
|
let registered = sys_common::at_exit(move || {
|
||||||
let g = self.lock.lock();
|
let g = self.lock.lock();
|
||||||
let ptr = self.ptr.get();
|
let ptr = self.ptr.get();
|
||||||
self.ptr.set(1 as *mut _);
|
self.ptr.set(1 as *mut _);
|
||||||
|
|
|
@ -13,9 +13,10 @@ use io::prelude::*;
|
||||||
|
|
||||||
use any::Any;
|
use any::Any;
|
||||||
use cell::RefCell;
|
use cell::RefCell;
|
||||||
use rt::{backtrace, unwind};
|
|
||||||
use sys::stdio::Stderr;
|
use sys::stdio::Stderr;
|
||||||
|
use sys_common::backtrace;
|
||||||
use sys_common::thread_info;
|
use sys_common::thread_info;
|
||||||
|
use sys_common::unwind;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
|
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
|
||||||
|
|
|
@ -582,7 +582,7 @@ impl Child {
|
||||||
/// to run.
|
/// to run.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn exit(code: i32) -> ! {
|
pub fn exit(code: i32) -> ! {
|
||||||
::rt::cleanup();
|
::sys_common::cleanup();
|
||||||
::sys::os::exit(code)
|
::sys::os::exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
65
src/libstd/rt.rs
Normal file
65
src/libstd/rt.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Runtime services
|
||||||
|
//!
|
||||||
|
//! The `rt` module provides a narrow set of runtime services,
|
||||||
|
//! including the global heap (exported in `heap`) and unwinding and
|
||||||
|
//! backtrace support. The APIs in this module are highly unstable,
|
||||||
|
//! and should be considered as private implementation details for the
|
||||||
|
//! time being.
|
||||||
|
|
||||||
|
#![unstable(feature = "rt",
|
||||||
|
reason = "this public module should not exist and is highly likely \
|
||||||
|
to disappear",
|
||||||
|
issue = "0")]
|
||||||
|
#![doc(hidden)]
|
||||||
|
|
||||||
|
use borrow::ToOwned;
|
||||||
|
use mem;
|
||||||
|
use sys;
|
||||||
|
use sys_common::thread_info::{self, NewThread};
|
||||||
|
use sys_common;
|
||||||
|
use thread::{self, Thread};
|
||||||
|
|
||||||
|
// Reexport some of our utilities which are expected by other crates.
|
||||||
|
pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt};
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[lang = "start"]
|
||||||
|
fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
|
||||||
|
sys::init();
|
||||||
|
|
||||||
|
let failed = unsafe {
|
||||||
|
let main_guard = 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>".to_owned()));
|
||||||
|
thread_info::set(main_guard, thread);
|
||||||
|
|
||||||
|
// Store our args if necessary in a squirreled away location
|
||||||
|
sys_common::args::init(argc, argv);
|
||||||
|
|
||||||
|
// Let's run some code!
|
||||||
|
let res = thread::catch_panic(mem::transmute::<_, fn()>(main));
|
||||||
|
sys_common::cleanup();
|
||||||
|
res.is_err()
|
||||||
|
};
|
||||||
|
|
||||||
|
if failed {
|
||||||
|
101
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Simple backtrace functionality (to print on panic)
|
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
|
||||||
|
|
||||||
use env;
|
|
||||||
use sync::atomic::{self, Ordering};
|
|
||||||
|
|
||||||
pub use sys::backtrace::write;
|
|
||||||
|
|
||||||
// For now logging is turned off by default, and this function checks to see
|
|
||||||
// whether the magical environment variable is present to see if it's turned on.
|
|
||||||
pub fn log_enabled() -> bool {
|
|
||||||
static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
|
|
||||||
match ENABLED.load(Ordering::SeqCst) {
|
|
||||||
1 => return false,
|
|
||||||
2 => return true,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let val = match env::var_os("RUST_BACKTRACE") {
|
|
||||||
Some(..) => 2,
|
|
||||||
None => 1,
|
|
||||||
};
|
|
||||||
ENABLED.store(val, Ordering::SeqCst);
|
|
||||||
val == 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use prelude::v1::*;
|
|
||||||
use sys_common;
|
|
||||||
macro_rules! t { ($a:expr, $b:expr) => ({
|
|
||||||
let mut m = Vec::new();
|
|
||||||
sys_common::backtrace::demangle(&mut m, $a).unwrap();
|
|
||||||
assert_eq!(String::from_utf8(m).unwrap(), $b);
|
|
||||||
}) }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn demangle() {
|
|
||||||
t!("test", "test");
|
|
||||||
t!("_ZN4testE", "test");
|
|
||||||
t!("_ZN4test", "_ZN4test");
|
|
||||||
t!("_ZN4test1a2bcE", "test::a::bc");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn demangle_dollars() {
|
|
||||||
t!("_ZN4$RP$E", ")");
|
|
||||||
t!("_ZN8$RF$testE", "&test");
|
|
||||||
t!("_ZN8$BP$test4foobE", "*test::foob");
|
|
||||||
t!("_ZN9$u20$test4foobE", " test::foob");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn demangle_many_dollars() {
|
|
||||||
t!("_ZN13test$u20$test4foobE", "test test::foob");
|
|
||||||
t!("_ZN12test$BP$test4foobE", "test*test::foob");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn demangle_windows() {
|
|
||||||
t!("ZN4testE", "test");
|
|
||||||
t!("ZN13test$u20$test4foobE", "test test::foob");
|
|
||||||
t!("ZN12test$RF$test4foobE", "test&test::foob");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Macros used by the runtime.
|
|
||||||
//!
|
|
||||||
//! These macros call functions which are only accessible in the `rt` module, so
|
|
||||||
//! they aren't defined anywhere outside of the `rt` module.
|
|
||||||
|
|
||||||
macro_rules! rterrln {
|
|
||||||
($fmt:expr) => ( {
|
|
||||||
::rt::util::dumb_print(format_args!(concat!($fmt, "\n")))
|
|
||||||
} );
|
|
||||||
($fmt:expr, $($arg:expr),*) => ( {
|
|
||||||
::rt::util::dumb_print(format_args!(concat!($fmt, "\n"), $($arg),*))
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some basic logging. Enabled by passing `--cfg rtdebug` to the libstd build.
|
|
||||||
macro_rules! rtdebug {
|
|
||||||
($arg:expr) => ( {
|
|
||||||
if cfg!(rtdebug) {
|
|
||||||
rterrln!($arg)
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
($str:expr, $($arg:expr),*) => ( {
|
|
||||||
if cfg!(rtdebug) {
|
|
||||||
rterrln!($str, $($arg),*)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! rtassert {
|
|
||||||
( $arg:expr ) => ( {
|
|
||||||
if ::rt::util::ENFORCE_SANITY {
|
|
||||||
if !$arg {
|
|
||||||
rtabort!(" assertion failed: {}", stringify!($arg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! rtabort {
|
|
||||||
($($arg:tt)*) => (::rt::util::abort(format_args!($($arg)*)))
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Runtime services
|
|
||||||
//!
|
|
||||||
//! The `rt` module provides a narrow set of runtime services,
|
|
||||||
//! including the global heap (exported in `heap`) and unwinding and
|
|
||||||
//! backtrace support. The APIs in this module are highly unstable,
|
|
||||||
//! and should be considered as private implementation details for the
|
|
||||||
//! time being.
|
|
||||||
|
|
||||||
#![unstable(feature = "rt",
|
|
||||||
reason = "this public module should not exist and is highly likely \
|
|
||||||
to disappear",
|
|
||||||
issue = "0")]
|
|
||||||
#![allow(missing_docs)]
|
|
||||||
|
|
||||||
use prelude::v1::*;
|
|
||||||
use sync::Once;
|
|
||||||
use sys;
|
|
||||||
use thread;
|
|
||||||
|
|
||||||
// Reexport some of our utilities which are expected by other crates.
|
|
||||||
pub use self::util::min_stack;
|
|
||||||
pub use self::unwind::{begin_unwind, begin_unwind_fmt};
|
|
||||||
|
|
||||||
// Reexport some functionality from liballoc.
|
|
||||||
pub use alloc::heap;
|
|
||||||
|
|
||||||
// Simple backtrace functionality (to print on panic)
|
|
||||||
pub mod backtrace;
|
|
||||||
|
|
||||||
// Internals
|
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
// These should be refactored/moved/made private over time
|
|
||||||
pub mod util;
|
|
||||||
pub mod unwind;
|
|
||||||
pub mod args;
|
|
||||||
|
|
||||||
mod at_exit_imp;
|
|
||||||
mod libunwind;
|
|
||||||
|
|
||||||
mod dwarf;
|
|
||||||
|
|
||||||
/// The default error code of the rust runtime if the main thread panics instead
|
|
||||||
/// of exiting cleanly.
|
|
||||||
pub const DEFAULT_ERROR_CODE: isize = 101;
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
#[lang = "start"]
|
|
||||||
fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
|
|
||||||
use prelude::v1::*;
|
|
||||||
|
|
||||||
use mem;
|
|
||||||
use rt;
|
|
||||||
use sys_common::thread_info::{self, NewThread};
|
|
||||||
use thread::Thread;
|
|
||||||
|
|
||||||
let failed = unsafe {
|
|
||||||
let main_guard = 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>".to_owned()));
|
|
||||||
thread_info::set(main_guard, 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) != !0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 = thread::catch_panic(mem::transmute::<_, fn()>(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 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enqueues a procedure to run when the main thread exits.
|
|
||||||
///
|
|
||||||
/// Currently these closures are only run once the main *Rust* thread exits.
|
|
||||||
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
|
|
||||||
/// infinitely so. Eventually a handler registration will be forced to fail.
|
|
||||||
///
|
|
||||||
/// Returns `Ok` if the handler was successfully registered, meaning that the
|
|
||||||
/// closure will be run once the main thread exits. Returns `Err` to indicate
|
|
||||||
/// that the closure could not be registered, meaning that it is not scheduled
|
|
||||||
/// to be run.
|
|
||||||
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
|
|
||||||
if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// One-time runtime cleanup.
|
|
||||||
pub fn cleanup() {
|
|
||||||
static CLEANUP: Once = Once::new();
|
|
||||||
CLEANUP.call_once(|| unsafe {
|
|
||||||
args::cleanup();
|
|
||||||
sys::stack_overflow::cleanup();
|
|
||||||
at_exit_imp::cleanup();
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -19,6 +19,8 @@
|
||||||
//!
|
//!
|
||||||
//! FIXME #7756: Would be nice for this to not exist.
|
//! FIXME #7756: Would be nice for this to not exist.
|
||||||
|
|
||||||
|
#![allow(dead_code)] // different code on OSX/linux/etc
|
||||||
|
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
|
|
||||||
/// One-time global initialization.
|
/// One-time global initialization.
|
||||||
|
@ -27,14 +29,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv)
|
||||||
/// One-time global cleanup.
|
/// One-time global cleanup.
|
||||||
pub unsafe fn cleanup() { imp::cleanup() }
|
pub unsafe fn cleanup() { imp::cleanup() }
|
||||||
|
|
||||||
/// Take the global arguments from global storage.
|
|
||||||
pub fn take() -> Option<Vec<Vec<u8>>> { imp::take() }
|
|
||||||
|
|
||||||
/// Give the global arguments to global storage.
|
|
||||||
///
|
|
||||||
/// It is an error if the arguments already exist.
|
|
||||||
pub fn put(args: Vec<Vec<u8>>) { imp::put(args) }
|
|
||||||
|
|
||||||
/// Make a clone of the global arguments.
|
/// Make a clone of the global arguments.
|
||||||
pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
|
pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
|
||||||
|
|
||||||
|
@ -48,7 +42,7 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
|
||||||
mod imp {
|
mod imp {
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use libc;
|
use libc::c_char;
|
||||||
use mem;
|
use mem;
|
||||||
use ffi::CStr;
|
use ffi::CStr;
|
||||||
|
|
||||||
|
@ -58,37 +52,26 @@ mod imp {
|
||||||
static LOCK: StaticMutex = StaticMutex::new();
|
static LOCK: StaticMutex = StaticMutex::new();
|
||||||
|
|
||||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||||
let args = load_argc_and_argv(argc, argv);
|
let args = (0..argc).map(|i| {
|
||||||
put(args);
|
CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec()
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let _guard = LOCK.lock();
|
||||||
|
let ptr = get_global_ptr();
|
||||||
|
assert!((*ptr).is_none());
|
||||||
|
(*ptr) = Some(box args);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn cleanup() {
|
pub unsafe fn cleanup() {
|
||||||
take();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take() -> Option<Vec<Vec<u8>>> {
|
|
||||||
let _guard = LOCK.lock();
|
let _guard = LOCK.lock();
|
||||||
unsafe {
|
*get_global_ptr() = None;
|
||||||
let ptr = get_global_ptr();
|
|
||||||
let val = mem::replace(&mut *ptr, None);
|
|
||||||
val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put(args: Vec<Vec<u8>>) {
|
|
||||||
let _guard = LOCK.lock();
|
|
||||||
unsafe {
|
|
||||||
let ptr = get_global_ptr();
|
|
||||||
rtassert!((*ptr).is_none());
|
|
||||||
(*ptr) = Some(box args.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone() -> Option<Vec<Vec<u8>>> {
|
pub fn clone() -> Option<Vec<Vec<u8>>> {
|
||||||
let _guard = LOCK.lock();
|
let _guard = LOCK.lock();
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = get_global_ptr();
|
let ptr = get_global_ptr();
|
||||||
(*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
|
(*ptr).as_ref().map(|s| (**s).clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,42 +79,6 @@ mod imp {
|
||||||
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
|
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn load_argc_and_argv(argc: isize,
|
|
||||||
argv: *const *const u8) -> Vec<Vec<u8>> {
|
|
||||||
let argv = argv as *const *const libc::c_char;
|
|
||||||
(0..argc).map(|i| {
|
|
||||||
CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec()
|
|
||||||
}).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use prelude::v1::*;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoke_test() {
|
|
||||||
// Preserve the actual global state.
|
|
||||||
let saved_value = take();
|
|
||||||
|
|
||||||
let expected = vec![
|
|
||||||
b"happy".to_vec(),
|
|
||||||
b"today?".to_vec(),
|
|
||||||
];
|
|
||||||
|
|
||||||
put(expected.clone());
|
|
||||||
assert!(clone() == Some(expected.clone()));
|
|
||||||
assert!(take() == Some(expected.clone()));
|
|
||||||
assert!(take() == None);
|
|
||||||
|
|
||||||
// Restore the actual global state.
|
|
||||||
match saved_value {
|
|
||||||
Some(ref args) => put(args.clone()),
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos",
|
#[cfg(any(target_os = "macos",
|
||||||
|
@ -146,14 +93,6 @@ mod imp {
|
||||||
pub fn cleanup() {
|
pub fn cleanup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take() -> Option<Vec<Vec<u8>>> {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put(_args: Vec<Vec<u8>>) {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone() -> Option<Vec<Vec<u8>>> {
|
pub fn clone() -> Option<Vec<Vec<u8>>> {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
|
@ -54,7 +54,7 @@ pub fn cleanup() {
|
||||||
LOCK.unlock();
|
LOCK.unlock();
|
||||||
|
|
||||||
// make sure we're not recursively cleaning up
|
// make sure we're not recursively cleaning up
|
||||||
rtassert!(queue as usize != 1);
|
assert!(queue as usize != 1);
|
||||||
|
|
||||||
// If we never called init, not need to cleanup!
|
// If we never called init, not need to cleanup!
|
||||||
if queue as usize != 0 {
|
if queue as usize != 0 {
|
|
@ -8,10 +8,14 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use io;
|
use env;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
use str;
|
use io;
|
||||||
use libc;
|
use libc;
|
||||||
|
use str;
|
||||||
|
use sync::atomic::{self, Ordering};
|
||||||
|
|
||||||
|
pub use sys::backtrace::write;
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
pub const HEX_WIDTH: usize = 18;
|
pub const HEX_WIDTH: usize = 18;
|
||||||
|
@ -19,6 +23,23 @@ pub const HEX_WIDTH: usize = 18;
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
pub const HEX_WIDTH: usize = 10;
|
pub const HEX_WIDTH: usize = 10;
|
||||||
|
|
||||||
|
// For now logging is turned off by default, and this function checks to see
|
||||||
|
// whether the magical environment variable is present to see if it's turned on.
|
||||||
|
pub fn log_enabled() -> bool {
|
||||||
|
static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
|
||||||
|
match ENABLED.load(Ordering::SeqCst) {
|
||||||
|
1 => return false,
|
||||||
|
2 => return true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let val = match env::var_os("RUST_BACKTRACE") {
|
||||||
|
Some(..) => 2,
|
||||||
|
None => 1,
|
||||||
|
};
|
||||||
|
ENABLED.store(val, Ordering::SeqCst);
|
||||||
|
val == 2
|
||||||
|
}
|
||||||
|
|
||||||
// These output functions should now be used everywhere to ensure consistency.
|
// These output functions should now be used everywhere to ensure consistency.
|
||||||
pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
|
pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
|
||||||
|
@ -163,3 +184,43 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use prelude::v1::*;
|
||||||
|
use sys_common;
|
||||||
|
macro_rules! t { ($a:expr, $b:expr) => ({
|
||||||
|
let mut m = Vec::new();
|
||||||
|
sys_common::backtrace::demangle(&mut m, $a).unwrap();
|
||||||
|
assert_eq!(String::from_utf8(m).unwrap(), $b);
|
||||||
|
}) }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn demangle() {
|
||||||
|
t!("test", "test");
|
||||||
|
t!("_ZN4testE", "test");
|
||||||
|
t!("_ZN4test", "_ZN4test");
|
||||||
|
t!("_ZN4test1a2bcE", "test::a::bc");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn demangle_dollars() {
|
||||||
|
t!("_ZN4$RP$E", ")");
|
||||||
|
t!("_ZN8$RF$testE", "&test");
|
||||||
|
t!("_ZN8$BP$test4foobE", "*test::foob");
|
||||||
|
t!("_ZN9$u20$test4foobE", " test::foob");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn demangle_many_dollars() {
|
||||||
|
t!("_ZN13test$u20$test4foobE", "test test::foob");
|
||||||
|
t!("_ZN12test$BP$test4foobE", "test*test::foob");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn demangle_windows() {
|
||||||
|
t!("ZN4testE", "test");
|
||||||
|
t!("ZN13test$u20$test4foobE", "test test::foob");
|
||||||
|
t!("ZN12test$RF$test4foobE", "test&test::foob");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
use rt::dwarf::DwarfReader;
|
use sys_common::dwarf::DwarfReader;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
pub const DW_EH_PE_omit : u8 = 0xFF;
|
pub const DW_EH_PE_omit : u8 = 0xFF;
|
|
@ -10,17 +10,39 @@
|
||||||
|
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
|
use boxed::Box;
|
||||||
|
use sync::Once;
|
||||||
|
use sys;
|
||||||
|
|
||||||
|
macro_rules! rtabort {
|
||||||
|
($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! rtassert {
|
||||||
|
($e:expr) => ({
|
||||||
|
if !$e {
|
||||||
|
rtabort!(concat!("assertion failed: ", stringify!($e)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod args;
|
||||||
|
pub mod at_exit_imp;
|
||||||
pub mod backtrace;
|
pub mod backtrace;
|
||||||
pub mod condvar;
|
pub mod condvar;
|
||||||
|
pub mod dwarf;
|
||||||
|
pub mod io;
|
||||||
|
pub mod libunwind;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod io;
|
|
||||||
pub mod poison;
|
pub mod poison;
|
||||||
pub mod remutex;
|
pub mod remutex;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
pub mod thread_info;
|
pub mod thread_info;
|
||||||
pub mod thread_local;
|
pub mod thread_local;
|
||||||
|
pub mod unwind;
|
||||||
|
pub mod util;
|
||||||
pub mod wtf8;
|
pub mod wtf8;
|
||||||
|
|
||||||
#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios"))),
|
#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios"))),
|
||||||
|
@ -52,3 +74,27 @@ pub trait IntoInner<Inner> {
|
||||||
pub trait FromInner<Inner> {
|
pub trait FromInner<Inner> {
|
||||||
fn from_inner(inner: Inner) -> Self;
|
fn from_inner(inner: Inner) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enqueues a procedure to run when the main thread exits.
|
||||||
|
///
|
||||||
|
/// Currently these closures are only run once the main *Rust* thread exits.
|
||||||
|
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
|
||||||
|
/// infinitely so. Eventually a handler registration will be forced to fail.
|
||||||
|
///
|
||||||
|
/// Returns `Ok` if the handler was successfully registered, meaning that the
|
||||||
|
/// closure will be run once the main thread exits. Returns `Err` to indicate
|
||||||
|
/// that the closure could not be registered, meaning that it is not scheduled
|
||||||
|
/// to be run.
|
||||||
|
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
|
||||||
|
if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One-time runtime cleanup.
|
||||||
|
pub fn cleanup() {
|
||||||
|
static CLEANUP: Once = Once::new();
|
||||||
|
CLEANUP.call_once(|| unsafe {
|
||||||
|
args::cleanup();
|
||||||
|
sys::stack_overflow::cleanup();
|
||||||
|
at_exit_imp::cleanup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
use any::Any;
|
use any::Any;
|
||||||
use rt::libunwind as uw;
|
use sys_common::libunwind as uw;
|
||||||
|
|
||||||
struct Exception {
|
struct Exception {
|
||||||
uwe: uw::_Unwind_Exception,
|
uwe: uw::_Unwind_Exception,
|
||||||
|
@ -35,7 +35,6 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||||
|
|
||||||
extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||||
exception: *mut uw::_Unwind_Exception) {
|
exception: *mut uw::_Unwind_Exception) {
|
||||||
rtdebug!("exception_cleanup()");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
|
let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +43,6 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||||
|
|
||||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
||||||
let my_ep = ptr as *mut Exception;
|
let my_ep = ptr as *mut Exception;
|
||||||
rtdebug!("caught {}", (*my_ep).uwe.exception_class);
|
|
||||||
let cause = (*my_ep).cause.take();
|
let cause = (*my_ep).cause.take();
|
||||||
uw::_Unwind_DeleteException(ptr as *mut _);
|
uw::_Unwind_DeleteException(ptr as *mut _);
|
||||||
cause.unwrap()
|
cause.unwrap()
|
||||||
|
@ -80,7 +78,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
||||||
not(all(windows, target_arch = "x86_64")),
|
not(all(windows, target_arch = "x86_64")),
|
||||||
not(test)))]
|
not(test)))]
|
||||||
pub mod eabi {
|
pub mod eabi {
|
||||||
use rt::libunwind as uw;
|
use sys_common::libunwind as uw;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
@ -136,7 +134,7 @@ pub mod eabi {
|
||||||
|
|
||||||
#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
|
#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
|
||||||
pub mod eabi {
|
pub mod eabi {
|
||||||
use rt::libunwind as uw;
|
use sys_common::libunwind as uw;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
@ -191,7 +189,7 @@ pub mod eabi {
|
||||||
// but otherwise works the same.
|
// but otherwise works the same.
|
||||||
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
|
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
|
||||||
pub mod eabi {
|
pub mod eabi {
|
||||||
use rt::libunwind as uw;
|
use sys_common::libunwind as uw;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
extern {
|
extern {
|
|
@ -184,7 +184,6 @@ pub fn panicking() -> bool {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(private_no_mangle_fns)]
|
#[allow(private_no_mangle_fns)]
|
||||||
fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
|
fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
|
||||||
rtdebug!("begin_unwind()");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
imp::panic(cause)
|
imp::panic(cause)
|
||||||
}
|
}
|
||||||
|
@ -288,7 +287,8 @@ fn begin_unwind_inner(msg: Box<Any + Send>,
|
||||||
// have limited options. Currently our preference is to
|
// have limited options. Currently our preference is to
|
||||||
// just abort. In the future we may consider resuming
|
// just abort. In the future we may consider resuming
|
||||||
// unwinding or otherwise exiting the thread cleanly.
|
// unwinding or otherwise exiting the thread cleanly.
|
||||||
rterrln!("thread panicked while panicking. aborting.");
|
super::util::dumb_print(format_args!("thread panicked while panicking. \
|
||||||
|
aborting."));
|
||||||
unsafe { intrinsics::abort() }
|
unsafe { intrinsics::abort() }
|
||||||
}
|
}
|
||||||
PANICKING.with(|s| s.set(true));
|
PANICKING.with(|s| s.set(true));
|
|
@ -135,9 +135,10 @@ fn rust_eh_personality() {
|
||||||
// This function just takes a look at the current EXCEPTION_RECORD being thrown
|
// This function just takes a look at the current EXCEPTION_RECORD being thrown
|
||||||
// to ensure that it's code is RUST_PANIC, which was set by the call to
|
// to ensure that it's code is RUST_PANIC, which was set by the call to
|
||||||
// `RaiseException` above in the `panic` function.
|
// `RaiseException` above in the `panic` function.
|
||||||
#[no_mangle]
|
|
||||||
#[lang = "msvc_try_filter"]
|
#[lang = "msvc_try_filter"]
|
||||||
pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
|
#[linkage = "external"]
|
||||||
|
#[allow(private_no_mangle_fns)]
|
||||||
|
extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
|
||||||
_rbp: *mut u8) -> i32 {
|
_rbp: *mut u8) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
|
((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
|
|
@ -18,7 +18,7 @@ use prelude::v1::*;
|
||||||
|
|
||||||
use any::Any;
|
use any::Any;
|
||||||
use self::EXCEPTION_DISPOSITION::*;
|
use self::EXCEPTION_DISPOSITION::*;
|
||||||
use rt::dwarf::eh;
|
use sys_common::dwarf::eh;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use libc::{c_void, c_ulonglong, DWORD, LPVOID};
|
use libc::{c_void, c_ulonglong, DWORD, LPVOID};
|
||||||
|
@ -114,7 +114,6 @@ struct PanicData {
|
||||||
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||||
let panic_ctx = Box::new(PanicData { data: data });
|
let panic_ctx = Box::new(PanicData { data: data });
|
||||||
let params = [Box::into_raw(panic_ctx) as ULONG_PTR];
|
let params = [Box::into_raw(panic_ctx) as ULONG_PTR];
|
||||||
rtdebug!("panic: ctx={:X}", params[0]);
|
|
||||||
RaiseException(RUST_PANIC,
|
RaiseException(RUST_PANIC,
|
||||||
EXCEPTION_NONCONTINUABLE,
|
EXCEPTION_NONCONTINUABLE,
|
||||||
params.len() as DWORD,
|
params.len() as DWORD,
|
||||||
|
@ -123,7 +122,6 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
||||||
rtdebug!("cleanup: ctx={:X}", ptr as usize);
|
|
||||||
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
|
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
|
||||||
return panic_ctx.data;
|
return panic_ctx.data;
|
||||||
}
|
}
|
||||||
|
@ -174,15 +172,10 @@ unsafe extern fn rust_eh_personality(
|
||||||
{
|
{
|
||||||
let er = &*exceptionRecord;
|
let er = &*exceptionRecord;
|
||||||
let dc = &*dispatcherContext;
|
let dc = &*dispatcherContext;
|
||||||
rtdebug!("rust_eh_personality: code={:X}, flags={:X}, frame={:X}, ip={:X}",
|
|
||||||
er.ExceptionCode, er.ExceptionFlags,
|
|
||||||
establisherFrame as usize, dc.ControlPc as usize);
|
|
||||||
|
|
||||||
if er.ExceptionFlags & EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
|
if er.ExceptionFlags & EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
|
||||||
if er.ExceptionCode == RUST_PANIC {
|
if er.ExceptionCode == RUST_PANIC {
|
||||||
if let Some(lpad) = find_landing_pad(dc) {
|
if let Some(lpad) = find_landing_pad(dc) {
|
||||||
rtdebug!("unwinding to landing pad {:X}", lpad);
|
|
||||||
|
|
||||||
RtlUnwindEx(establisherFrame,
|
RtlUnwindEx(establisherFrame,
|
||||||
lpad as LPVOID,
|
lpad as LPVOID,
|
||||||
exceptionRecord,
|
exceptionRecord,
|
||||||
|
@ -206,7 +199,6 @@ unsafe extern fn rust_eh_personality(
|
||||||
#[lang = "eh_unwind_resume"]
|
#[lang = "eh_unwind_resume"]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) {
|
unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) {
|
||||||
rtdebug!("rust_eh_unwind_resume: ctx={:X}", panic_ctx as usize);
|
|
||||||
let params = [panic_ctx as ULONG_PTR];
|
let params = [panic_ctx as ULONG_PTR];
|
||||||
RaiseException(RUST_PANIC,
|
RaiseException(RUST_PANIC,
|
||||||
EXCEPTION_NONCONTINUABLE,
|
EXCEPTION_NONCONTINUABLE,
|
|
@ -8,13 +8,13 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use io::prelude::*;
|
|
||||||
|
|
||||||
use env;
|
use env;
|
||||||
use fmt;
|
use fmt;
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
|
use io::prelude::*;
|
||||||
use sync::atomic::{self, Ordering};
|
use sync::atomic::{self, Ordering};
|
||||||
use sys::stdio::Stderr;
|
use sys::stdio::Stderr;
|
||||||
|
use thread;
|
||||||
|
|
||||||
pub fn min_stack() -> usize {
|
pub fn min_stack() -> usize {
|
||||||
static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||||
|
@ -30,24 +30,17 @@ pub fn min_stack() -> usize {
|
||||||
amt
|
amt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates whether we should perform expensive sanity checks, including rtassert!
|
|
||||||
//
|
|
||||||
// FIXME: Once the runtime matures remove the `true` below to turn off rtassert,
|
|
||||||
// etc.
|
|
||||||
pub const ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) ||
|
|
||||||
cfg!(rtassert);
|
|
||||||
|
|
||||||
pub fn dumb_print(args: fmt::Arguments) {
|
pub fn dumb_print(args: fmt::Arguments) {
|
||||||
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
|
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abort(args: fmt::Arguments) -> ! {
|
pub fn abort(args: fmt::Arguments) -> ! {
|
||||||
rterrln!("fatal runtime error: {}", args);
|
dumb_print(format_args!("fatal runtime error: {}", args));
|
||||||
unsafe { intrinsics::abort(); }
|
unsafe { intrinsics::abort(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // stack overflow detection not enabled on all platforms
|
||||||
pub unsafe fn report_overflow() {
|
pub unsafe fn report_overflow() {
|
||||||
use thread;
|
dumb_print(format_args!("\nthread '{}' has overflowed its stack",
|
||||||
rterrln!("\nthread '{}' has overflowed its stack",
|
thread::current().name().unwrap_or("<unknown>")));
|
||||||
thread::current().name().unwrap_or("<unknown>"));
|
|
||||||
}
|
}
|
|
@ -12,6 +12,7 @@
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use io::{self, ErrorKind};
|
use io::{self, ErrorKind};
|
||||||
|
use libc::funcs::posix01::signal::signal;
|
||||||
use libc;
|
use libc;
|
||||||
use num::One;
|
use num::One;
|
||||||
use ops::Neg;
|
use ops::Neg;
|
||||||
|
@ -47,6 +48,19 @@ pub mod thread_local;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod stdio;
|
pub mod stdio;
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
// 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.
|
||||||
|
unsafe {
|
||||||
|
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
||||||
match errno as libc::c_int {
|
match errno as libc::c_int {
|
||||||
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
|
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
|
||||||
|
|
|
@ -358,8 +358,8 @@ pub fn args() -> Args {
|
||||||
target_os = "netbsd",
|
target_os = "netbsd",
|
||||||
target_os = "openbsd"))]
|
target_os = "openbsd"))]
|
||||||
pub fn args() -> Args {
|
pub fn args() -> Args {
|
||||||
use rt;
|
use sys_common;
|
||||||
let bytes = rt::args::clone().unwrap_or(Vec::new());
|
let bytes = sys_common::args::clone().unwrap_or(Vec::new());
|
||||||
let v: Vec<OsString> = bytes.into_iter().map(|v| {
|
let v: Vec<OsString> = bytes.into_iter().map(|v| {
|
||||||
OsStringExt::from_vec(v)
|
OsStringExt::from_vec(v)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl Drop for Handler {
|
||||||
target_os = "openbsd"))]
|
target_os = "openbsd"))]
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::Handler;
|
use super::Handler;
|
||||||
use rt::util::report_overflow;
|
use sys_common::util::report_overflow;
|
||||||
use mem;
|
use mem;
|
||||||
use ptr;
|
use ptr;
|
||||||
use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
|
use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
|
||||||
|
|
|
@ -43,6 +43,8 @@ pub mod thread_local;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod stdio;
|
pub mod stdio;
|
||||||
|
|
||||||
|
pub fn init() {}
|
||||||
|
|
||||||
pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
||||||
match errno as libc::c_int {
|
match errno as libc::c_int {
|
||||||
libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,
|
libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,
|
||||||
|
|
|
@ -16,11 +16,10 @@ use net::SocketAddr;
|
||||||
use num::One;
|
use num::One;
|
||||||
use ops::Neg;
|
use ops::Neg;
|
||||||
use ptr;
|
use ptr;
|
||||||
use rt;
|
|
||||||
use sync::Once;
|
use sync::Once;
|
||||||
use sys;
|
use sys;
|
||||||
use sys::c;
|
use sys::c;
|
||||||
use sys_common::{AsInner, FromInner, IntoInner};
|
use sys_common::{self, AsInner, FromInner, IntoInner};
|
||||||
use sys_common::net::{setsockopt, getsockopt};
|
use sys_common::net::{setsockopt, getsockopt};
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ pub fn init() {
|
||||||
&mut data);
|
&mut data);
|
||||||
assert_eq!(ret, 0);
|
assert_eq!(ret, 0);
|
||||||
|
|
||||||
let _ = rt::at_exit(|| { c::WSACleanup(); });
|
let _ = sys_common::at_exit(|| { c::WSACleanup(); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use libc::{self, LONG};
|
use libc::{self, LONG};
|
||||||
use rt::util::report_overflow;
|
use sys_common::util::report_overflow;
|
||||||
use sys::c;
|
use sys::c;
|
||||||
|
|
||||||
pub struct Handler;
|
pub struct Handler;
|
||||||
|
|
|
@ -13,7 +13,7 @@ use prelude::v1::*;
|
||||||
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
|
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
|
||||||
|
|
||||||
use ptr;
|
use ptr;
|
||||||
use rt;
|
use sys_common;
|
||||||
use sys_common::mutex::Mutex;
|
use sys_common::mutex::Mutex;
|
||||||
|
|
||||||
pub type Key = DWORD;
|
pub type Key = DWORD;
|
||||||
|
@ -133,7 +133,7 @@ unsafe fn init_dtors() {
|
||||||
|
|
||||||
let dtors = box Vec::<(Key, Dtor)>::new();
|
let dtors = box Vec::<(Key, Dtor)>::new();
|
||||||
|
|
||||||
let res = rt::at_exit(move|| {
|
let res = sys_common::at_exit(move|| {
|
||||||
DTOR_LOCK.lock();
|
DTOR_LOCK.lock();
|
||||||
let dtors = DTORS;
|
let dtors = DTORS;
|
||||||
DTORS = 1 as *mut _;
|
DTORS = 1 as *mut _;
|
||||||
|
|
|
@ -167,10 +167,11 @@ use any::Any;
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
use fmt;
|
use fmt;
|
||||||
use io;
|
use io;
|
||||||
use rt::{self, unwind};
|
|
||||||
use sync::{Mutex, Condvar, Arc};
|
use sync::{Mutex, Condvar, Arc};
|
||||||
use sys::thread as imp;
|
use sys::thread as imp;
|
||||||
use sys_common::thread_info;
|
use sys_common::thread_info;
|
||||||
|
use sys_common::unwind;
|
||||||
|
use sys_common::util;
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -260,7 +261,7 @@ impl Builder {
|
||||||
-> io::Result<JoinInner<T>> {
|
-> io::Result<JoinInner<T>> {
|
||||||
let Builder { name, stack_size } = self;
|
let Builder { name, stack_size } = self;
|
||||||
|
|
||||||
let stack_size = stack_size.unwrap_or(rt::min_stack());
|
let stack_size = stack_size.unwrap_or(util::min_stack());
|
||||||
|
|
||||||
let my_thread = Thread::new(name);
|
let my_thread = Thread::new(name);
|
||||||
let their_thread = my_thread.clone();
|
let their_thread = my_thread.clone();
|
||||||
|
@ -383,7 +384,7 @@ pub fn catch_panic<F, R>(f: F) -> Result<R>
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
unsafe {
|
unsafe {
|
||||||
let result = &mut result;
|
let result = &mut result;
|
||||||
try!(::rt::unwind::try(move || *result = Some(f())))
|
try!(unwind::try(move || *result = Some(f())))
|
||||||
}
|
}
|
||||||
Ok(result.unwrap())
|
Ok(result.unwrap())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue