1
Fork 0

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:
Alex Crichton 2015-09-08 15:53:46 -07:00
parent 192c37537b
commit f4be2026df
33 changed files with 273 additions and 432 deletions

View file

@ -26,13 +26,16 @@ this is totally fine.
For instance, a custom implementation of `Box` might write `Drop` like this:
```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::intrinsics::drop_in_place;
use std::mem;
use alloc::heap;
struct Box<T>{ ptr: Unique<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
@ -54,13 +58,16 @@ use-after-free the `ptr` because when drop exits, it becomes inacessible.
However this wouldn't work:
```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::intrinsics::drop_in_place;
use std::mem;
use alloc::heap;
struct Box<T>{ ptr: Unique<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
@ -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:
```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::intrinsics::drop_in_place;
use std::mem;
use alloc::heap;
struct Box<T>{ ptr: Unique<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*

View file

@ -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
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
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
`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:
```rust,ignore
#![feature(heap_api)]
#![feature(alloc, heap_api)]
use std::rt::heap::EMPTY;
use std::mem;
use alloc::heap::EMPTY;
impl<T> Vec<T> {
fn new() -> Self {
assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");

View file

@ -2,17 +2,16 @@
```rust
#![feature(unique)]
#![feature(heap_api)]
#![feature(alloc, heap_api)]
extern crate alloc;
use std::ptr::{Unique, self};
use std::rt::heap;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use alloc::heap;
struct RawVec<T> {
ptr: Unique<T>,

View file

@ -49,7 +49,8 @@ use std::marker;
use std::mem;
use std::ptr;
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
// allocated, and have capacities reserved, but the fill for the array

View file

@ -174,7 +174,6 @@
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(iter_cmp)]
#![feature(rt)]
#![feature(staged_api)]
#![feature(static_mutex)]
@ -185,7 +184,6 @@ use std::io::prelude::*;
use std::mem;
use std::env;
use std::ptr;
use std::rt;
use std::slice;
use std::sync::{Once, StaticMutex};
@ -292,7 +290,6 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
let _g = LOCK.lock();
match FILTER as usize {
0 => {}
1 => panic!("cannot log after main thread has exited"),
n => {
let filter = mem::transmute::<_, &String>(n);
if !args.to_string().contains(filter) {
@ -385,9 +382,6 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
let _g = LOCK.lock();
unsafe {
assert!(DIRECTIVES as usize != 0);
assert!(DIRECTIVES as usize != 1,
"cannot log after the main thread has exited");
enabled(level, module, (*DIRECTIVES).iter())
}
}
@ -442,19 +436,6 @@ fn init() {
assert!(DIRECTIVES.is_null());
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 _;
}
});
}
}

View file

@ -8,23 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use self::BucketState::*;
use alloc::heap::{allocate, deallocate, EMPTY};
use clone::Clone;
use cmp;
use hash::{Hash, Hasher};
use iter::{Iterator, ExactSizeIterator};
use marker::{Copy, Send, Sync, Sized, self};
use marker;
use mem::{align_of, size_of};
use mem;
use num::wrapping::OverflowingOps;
use ops::{Deref, DerefMut, Drop};
use option::Option;
use option::Option::{Some, None};
use ops::{Deref, DerefMut};
use ptr::{self, Unique};
use rt::heap::{allocate, deallocate, EMPTY};
use collections::hash_state::HashState;
use self::BucketState::*;
const EMPTY_BUCKET: u64 = 0;
/// The raw hashtable, providing safe-ish access to the unzipped and highly

View file

@ -12,8 +12,8 @@ use prelude::v1::*;
use cell::Cell;
use ptr;
use rt;
use sync::{StaticMutex, Arc};
use sys_common;
pub struct Lazy<T> {
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
// the at exit handler). Otherwise we just return the freshly allocated
// `Arc`.
let registered = rt::at_exit(move || {
let registered = sys_common::at_exit(move || {
let g = self.lock.lock();
let ptr = self.ptr.get();
self.ptr.set(1 as *mut _);

View file

@ -13,9 +13,10 @@ use io::prelude::*;
use any::Any;
use cell::RefCell;
use rt::{backtrace, unwind};
use sys::stdio::Stderr;
use sys_common::backtrace;
use sys_common::thread_info;
use sys_common::unwind;
thread_local! {
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {

View file

@ -582,7 +582,7 @@ impl Child {
/// to run.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn exit(code: i32) -> ! {
::rt::cleanup();
::sys_common::cleanup();
::sys::os::exit(code)
}

65
src/libstd/rt.rs Normal file
View 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
}
}

View file

@ -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");
}
}

View file

@ -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)*)))
}

View file

@ -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();
});
}

View file

@ -19,6 +19,8 @@
//!
//! FIXME #7756: Would be nice for this to not exist.
#![allow(dead_code)] // different code on OSX/linux/etc
use vec::Vec;
/// 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.
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.
pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
@ -48,7 +42,7 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
mod imp {
use prelude::v1::*;
use libc;
use libc::c_char;
use mem;
use ffi::CStr;
@ -58,37 +52,26 @@ mod imp {
static LOCK: StaticMutex = StaticMutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let args = load_argc_and_argv(argc, argv);
put(args);
let args = (0..argc).map(|i| {
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() {
take();
}
pub fn take() -> Option<Vec<Vec<u8>>> {
let _guard = LOCK.lock();
unsafe {
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());
}
*get_global_ptr() = None;
}
pub fn clone() -> Option<Vec<Vec<u8>>> {
let _guard = LOCK.lock();
unsafe {
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 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",
@ -146,14 +93,6 @@ mod imp {
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>>> {
panic!()
}

View file

@ -54,7 +54,7 @@ pub fn cleanup() {
LOCK.unlock();
// 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 queue as usize != 0 {

View file

@ -8,10 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use io;
use env;
use io::prelude::*;
use str;
use io;
use libc;
use str;
use sync::atomic::{self, Ordering};
pub use sys::backtrace::write;
#[cfg(target_pointer_width = "64")]
pub const HEX_WIDTH: usize = 18;
@ -19,6 +23,23 @@ pub const HEX_WIDTH: usize = 18;
#[cfg(target_pointer_width = "32")]
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.
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(())
}
#[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");
}
}

View file

@ -22,7 +22,7 @@
#![allow(unused)]
use prelude::v1::*;
use rt::dwarf::DwarfReader;
use sys_common::dwarf::DwarfReader;
use core::mem;
pub const DW_EH_PE_omit : u8 = 0xFF;

View file

@ -10,17 +10,39 @@
#![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 condvar;
pub mod dwarf;
pub mod io;
pub mod libunwind;
pub mod mutex;
pub mod net;
pub mod io;
pub mod poison;
pub mod remutex;
pub mod rwlock;
pub mod thread;
pub mod thread_info;
pub mod thread_local;
pub mod unwind;
pub mod util;
pub mod wtf8;
#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios"))),
@ -52,3 +74,27 @@ pub trait IntoInner<Inner> {
pub trait FromInner<Inner> {
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();
});
}

View file

@ -13,7 +13,7 @@
use prelude::v1::*;
use any::Any;
use rt::libunwind as uw;
use sys_common::libunwind as uw;
struct 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,
exception: *mut uw::_Unwind_Exception) {
rtdebug!("exception_cleanup()");
unsafe {
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> {
let my_ep = ptr as *mut Exception;
rtdebug!("caught {}", (*my_ep).uwe.exception_class);
let cause = (*my_ep).cause.take();
uw::_Unwind_DeleteException(ptr as *mut _);
cause.unwrap()
@ -80,7 +78,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
not(all(windows, target_arch = "x86_64")),
not(test)))]
pub mod eabi {
use rt::libunwind as uw;
use sys_common::libunwind as uw;
use libc::c_int;
extern {
@ -136,7 +134,7 @@ pub mod eabi {
#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
pub mod eabi {
use rt::libunwind as uw;
use sys_common::libunwind as uw;
use libc::c_int;
extern {
@ -191,7 +189,7 @@ pub mod eabi {
// but otherwise works the same.
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
pub mod eabi {
use rt::libunwind as uw;
use sys_common::libunwind as uw;
use libc::c_int;
extern {

View file

@ -184,7 +184,6 @@ pub fn panicking() -> bool {
#[no_mangle]
#[allow(private_no_mangle_fns)]
fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
rtdebug!("begin_unwind()");
unsafe {
imp::panic(cause)
}
@ -288,7 +287,8 @@ fn begin_unwind_inner(msg: Box<Any + Send>,
// have limited options. Currently our preference is to
// just abort. In the future we may consider resuming
// 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() }
}
PANICKING.with(|s| s.set(true));

View file

@ -135,10 +135,11 @@ fn rust_eh_personality() {
// 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
// `RaiseException` above in the `panic` function.
#[no_mangle]
#[lang = "msvc_try_filter"]
pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
_rbp: *mut u8) -> i32 {
#[linkage = "external"]
#[allow(private_no_mangle_fns)]
extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
_rbp: *mut u8) -> i32 {
unsafe {
((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
}

View file

@ -18,7 +18,7 @@ use prelude::v1::*;
use any::Any;
use self::EXCEPTION_DISPOSITION::*;
use rt::dwarf::eh;
use sys_common::dwarf::eh;
use core::mem;
use core::ptr;
use libc::{c_void, c_ulonglong, DWORD, LPVOID};
@ -114,7 +114,6 @@ struct PanicData {
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
let panic_ctx = Box::new(PanicData { data: data });
let params = [Box::into_raw(panic_ctx) as ULONG_PTR];
rtdebug!("panic: ctx={:X}", params[0]);
RaiseException(RUST_PANIC,
EXCEPTION_NONCONTINUABLE,
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> {
rtdebug!("cleanup: ctx={:X}", ptr as usize);
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
return panic_ctx.data;
}
@ -174,15 +172,10 @@ unsafe extern fn rust_eh_personality(
{
let er = &*exceptionRecord;
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.ExceptionCode == RUST_PANIC {
if let Some(lpad) = find_landing_pad(dc) {
rtdebug!("unwinding to landing pad {:X}", lpad);
RtlUnwindEx(establisherFrame,
lpad as LPVOID,
exceptionRecord,
@ -206,7 +199,6 @@ unsafe extern fn rust_eh_personality(
#[lang = "eh_unwind_resume"]
#[cfg(not(test))]
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];
RaiseException(RUST_PANIC,
EXCEPTION_NONCONTINUABLE,

View file

@ -8,13 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use io::prelude::*;
use env;
use fmt;
use intrinsics;
use io::prelude::*;
use sync::atomic::{self, Ordering};
use sys::stdio::Stderr;
use thread;
pub fn min_stack() -> usize {
static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
@ -30,24 +30,17 @@ pub fn min_stack() -> usize {
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) {
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
}
pub fn abort(args: fmt::Arguments) -> ! {
rterrln!("fatal runtime error: {}", args);
dumb_print(format_args!("fatal runtime error: {}", args));
unsafe { intrinsics::abort(); }
}
#[allow(dead_code)] // stack overflow detection not enabled on all platforms
pub unsafe fn report_overflow() {
use thread;
rterrln!("\nthread '{}' has overflowed its stack",
thread::current().name().unwrap_or("<unknown>"));
dumb_print(format_args!("\nthread '{}' has overflowed its stack",
thread::current().name().unwrap_or("<unknown>")));
}

View file

@ -12,6 +12,7 @@
#![allow(non_camel_case_types)]
use io::{self, ErrorKind};
use libc::funcs::posix01::signal::signal;
use libc;
use num::One;
use ops::Neg;
@ -47,6 +48,19 @@ pub mod thread_local;
pub mod time;
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 {
match errno as libc::c_int {
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,

View file

@ -358,8 +358,8 @@ pub fn args() -> Args {
target_os = "netbsd",
target_os = "openbsd"))]
pub fn args() -> Args {
use rt;
let bytes = rt::args::clone().unwrap_or(Vec::new());
use sys_common;
let bytes = sys_common::args::clone().unwrap_or(Vec::new());
let v: Vec<OsString> = bytes.into_iter().map(|v| {
OsStringExt::from_vec(v)
}).collect();

View file

@ -38,7 +38,7 @@ impl Drop for Handler {
target_os = "openbsd"))]
mod imp {
use super::Handler;
use rt::util::report_overflow;
use sys_common::util::report_overflow;
use mem;
use ptr;
use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,

View file

@ -43,6 +43,8 @@ pub mod thread_local;
pub mod time;
pub mod stdio;
pub fn init() {}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,

View file

@ -16,11 +16,10 @@ use net::SocketAddr;
use num::One;
use ops::Neg;
use ptr;
use rt;
use sync::Once;
use sys;
use sys::c;
use sys_common::{AsInner, FromInner, IntoInner};
use sys_common::{self, AsInner, FromInner, IntoInner};
use sys_common::net::{setsockopt, getsockopt};
use time::Duration;
@ -39,7 +38,7 @@ pub fn init() {
&mut data);
assert_eq!(ret, 0);
let _ = rt::at_exit(|| { c::WSACleanup(); });
let _ = sys_common::at_exit(|| { c::WSACleanup(); });
});
}

View file

@ -9,7 +9,7 @@
// except according to those terms.
use libc::{self, LONG};
use rt::util::report_overflow;
use sys_common::util::report_overflow;
use sys::c;
pub struct Handler;

View file

@ -13,7 +13,7 @@ use prelude::v1::*;
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
use ptr;
use rt;
use sys_common;
use sys_common::mutex::Mutex;
pub type Key = DWORD;
@ -133,7 +133,7 @@ unsafe fn init_dtors() {
let dtors = box Vec::<(Key, Dtor)>::new();
let res = rt::at_exit(move|| {
let res = sys_common::at_exit(move|| {
DTOR_LOCK.lock();
let dtors = DTORS;
DTORS = 1 as *mut _;

View file

@ -167,10 +167,11 @@ use any::Any;
use cell::UnsafeCell;
use fmt;
use io;
use rt::{self, unwind};
use sync::{Mutex, Condvar, Arc};
use sys::thread as imp;
use sys_common::thread_info;
use sys_common::unwind;
use sys_common::util;
use time::Duration;
////////////////////////////////////////////////////////////////////////////////
@ -260,7 +261,7 @@ impl Builder {
-> io::Result<JoinInner<T>> {
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 their_thread = my_thread.clone();
@ -383,7 +384,7 @@ pub fn catch_panic<F, R>(f: F) -> Result<R>
let mut result = None;
unsafe {
let result = &mut result;
try!(::rt::unwind::try(move || *result = Some(f())))
try!(unwind::try(move || *result = Some(f())))
}
Ok(result.unwrap())
}