From f4be2026dfb507e5db919cc5df8fd934e05fa0b8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Sep 2015 15:53:46 -0700 Subject: [PATCH] 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. --- src/doc/nomicon/destructors.md | 24 +++- src/doc/nomicon/vec-alloc.md | 7 +- src/doc/nomicon/vec-final.md | 9 +- src/libarena/lib.rs | 3 +- src/liblog/lib.rs | 19 --- src/libstd/collections/hash/table.rs | 13 +- src/libstd/io/lazy.rs | 4 +- src/libstd/panicking.rs | 3 +- src/libstd/process.rs | 2 +- src/libstd/rt.rs | 65 +++++++++ src/libstd/rt/backtrace.rs | 76 ---------- src/libstd/rt/macros.rs | 51 ------- src/libstd/rt/mod.rs | 135 ------------------ src/libstd/{rt => sys/common}/args.rs | 85 ++--------- src/libstd/{rt => sys/common}/at_exit_imp.rs | 2 +- src/libstd/sys/common/backtrace.rs | 65 ++++++++- src/libstd/{rt => sys/common}/dwarf/eh.rs | 2 +- src/libstd/{rt => sys/common}/dwarf/mod.rs | 0 src/libstd/{rt => sys/common}/libunwind.rs | 0 src/libstd/sys/common/mod.rs | 48 ++++++- src/libstd/{rt => sys/common}/unwind/gcc.rs | 10 +- src/libstd/{rt => sys/common}/unwind/mod.rs | 4 +- src/libstd/{rt => sys/common}/unwind/seh.rs | 7 +- .../{rt => sys/common}/unwind/seh64_gnu.rs | 10 +- src/libstd/{rt => sys/common}/util.rs | 19 +-- src/libstd/sys/unix/mod.rs | 14 ++ src/libstd/sys/unix/os.rs | 4 +- src/libstd/sys/unix/stack_overflow.rs | 2 +- src/libstd/sys/windows/mod.rs | 2 + src/libstd/sys/windows/net.rs | 5 +- src/libstd/sys/windows/stack_overflow.rs | 2 +- src/libstd/sys/windows/thread_local.rs | 4 +- src/libstd/thread/mod.rs | 7 +- 33 files changed, 272 insertions(+), 431 deletions(-) create mode 100644 src/libstd/rt.rs delete mode 100644 src/libstd/rt/backtrace.rs delete mode 100644 src/libstd/rt/macros.rs delete mode 100644 src/libstd/rt/mod.rs rename src/libstd/{rt => sys/common}/args.rs (54%) rename src/libstd/{rt => sys/common}/at_exit_imp.rs (98%) rename src/libstd/{rt => sys/common}/dwarf/eh.rs (99%) rename src/libstd/{rt => sys/common}/dwarf/mod.rs (100%) rename src/libstd/{rt => sys/common}/libunwind.rs (100%) rename src/libstd/{rt => sys/common}/unwind/gcc.rs (97%) rename src/libstd/{rt => sys/common}/unwind/mod.rs (98%) rename src/libstd/{rt => sys/common}/unwind/seh.rs (97%) rename src/libstd/{rt => sys/common}/unwind/seh64_gnu.rs (94%) rename src/libstd/{rt => sys/common}/util.rs (72%) diff --git a/src/doc/nomicon/destructors.md b/src/doc/nomicon/destructors.md index 29a866063e996..4492e2a92fae9 100644 --- a/src/doc/nomicon/destructors.md +++ b/src/doc/nomicon/destructors.md @@ -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{ ptr: Unique } impl Drop for Box { @@ -45,6 +48,7 @@ impl Drop for Box { } } } +# 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{ ptr: Unique } impl Drop for Box { @@ -87,6 +94,7 @@ impl Drop for SuperBox { } } } +# 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{ ptr: Unique } impl Drop for Box { @@ -165,6 +176,7 @@ impl Drop for SuperBox { } } } +# fn main() {} ``` However this has fairly odd semantics: you're saying that a field that *should* diff --git a/src/doc/nomicon/vec-alloc.md b/src/doc/nomicon/vec-alloc.md index fc7feba2356d5..c2ae1a4eb6d26 100644 --- a/src/doc/nomicon/vec-alloc.md +++ b/src/doc/nomicon/vec-alloc.md @@ -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 Vec { fn new() -> Self { assert!(mem::size_of::() != 0, "We're not ready to handle ZSTs"); diff --git a/src/doc/nomicon/vec-final.md b/src/doc/nomicon/vec-final.md index ba4537f164093..52c22f65076f9 100644 --- a/src/doc/nomicon/vec-final.md +++ b/src/doc/nomicon/vec-final.md @@ -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 { ptr: Unique, diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index f48443e52b3e9..57e82720e8bea 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -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 diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4517c2f915773..d59e40fb1493c 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -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 _; - } - }); } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index e3601f1349c32..f8bd791f6819c 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -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 diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 5424fec81104b..65667f24dda6c 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -12,8 +12,8 @@ use prelude::v1::*; use cell::Cell; use ptr; -use rt; use sync::{StaticMutex, Arc}; +use sys_common; pub struct Lazy { lock: StaticMutex, @@ -51,7 +51,7 @@ impl Lazy { // `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 _); diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index bb4375c1b8826..9715939d644aa 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -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>> = { diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 79f2d16fef4ee..5f5d5a69003f2 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -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) } diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs new file mode 100644 index 0000000000000..8be0c6f3b3d99 --- /dev/null +++ b/src/libstd/rt.rs @@ -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 or the MIT license +// , 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("
".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 + } +} diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs deleted file mode 100644 index 9e7ed89bae1b7..0000000000000 --- a/src/libstd/rt/backtrace.rs +++ /dev/null @@ -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 or the MIT license -// , 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"); - } -} diff --git a/src/libstd/rt/macros.rs b/src/libstd/rt/macros.rs deleted file mode 100644 index 414ccc911afeb..0000000000000 --- a/src/libstd/rt/macros.rs +++ /dev/null @@ -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 or the MIT license -// , 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)*))) -} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs deleted file mode 100644 index 95cba13220133..0000000000000 --- a/src/libstd/rt/mod.rs +++ /dev/null @@ -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 or the MIT license -// , 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("
".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: 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(); - }); -} diff --git a/src/libstd/rt/args.rs b/src/libstd/sys/common/args.rs similarity index 54% rename from src/libstd/rt/args.rs rename to src/libstd/sys/common/args.rs index 8de713aeac8e8..4cfddb036e9c2 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/sys/common/args.rs @@ -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>> { imp::take() } - -/// Give the global arguments to global storage. -/// -/// It is an error if the arguments already exist. -pub fn put(args: Vec>) { imp::put(args) } - /// Make a clone of the global arguments. pub fn clone() -> Option>> { imp::clone() } @@ -48,7 +42,7 @@ pub fn clone() -> Option>> { 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(); - pub unsafe fn cleanup() { - take(); - } - - pub fn take() -> Option>> { let _guard = LOCK.lock(); - unsafe { - let ptr = get_global_ptr(); - let val = mem::replace(&mut *ptr, None); - val.as_ref().map(|s: &Box>>| (**s).clone()) - } + let ptr = get_global_ptr(); + assert!((*ptr).is_none()); + (*ptr) = Some(box args); } - pub fn put(args: Vec>) { + pub unsafe fn cleanup() { 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>> { let _guard = LOCK.lock(); unsafe { let ptr = get_global_ptr(); - (*ptr).as_ref().map(|s: &Box>>| (**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> { - 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>> { - panic!() - } - - pub fn put(_args: Vec>) { - panic!() - } - pub fn clone() -> Option>> { panic!() } diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/sys/common/at_exit_imp.rs similarity index 98% rename from src/libstd/rt/at_exit_imp.rs rename to src/libstd/sys/common/at_exit_imp.rs index 7a1215bf382b2..b2683750d67e2 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/sys/common/at_exit_imp.rs @@ -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 { diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index 7845714e7f647..e7bda9a7ba2db 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -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"); + } +} diff --git a/src/libstd/rt/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs similarity index 99% rename from src/libstd/rt/dwarf/eh.rs rename to src/libstd/sys/common/dwarf/eh.rs index f4799703d996d..319be245bde98 100644 --- a/src/libstd/rt/dwarf/eh.rs +++ b/src/libstd/sys/common/dwarf/eh.rs @@ -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; diff --git a/src/libstd/rt/dwarf/mod.rs b/src/libstd/sys/common/dwarf/mod.rs similarity index 100% rename from src/libstd/rt/dwarf/mod.rs rename to src/libstd/sys/common/dwarf/mod.rs diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/sys/common/libunwind.rs similarity index 100% rename from src/libstd/rt/libunwind.rs rename to src/libstd/sys/common/libunwind.rs diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index b8074235fb2a5..44c55d1e2c45f 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -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 { pub trait FromInner { 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: 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(); + }); +} diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs similarity index 97% rename from src/libstd/rt/unwind/gcc.rs rename to src/libstd/sys/common/unwind/gcc.rs index 55deb048b7ee5..361cef08c11a5 100644 --- a/src/libstd/rt/unwind/gcc.rs +++ b/src/libstd/sys/common/unwind/gcc.rs @@ -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) -> ! { extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code, exception: *mut uw::_Unwind_Exception) { - rtdebug!("exception_cleanup()"); unsafe { let _: Box = Box::from_raw(exception as *mut Exception); } @@ -44,7 +43,6 @@ pub unsafe fn panic(data: Box) -> ! { pub unsafe fn cleanup(ptr: *mut u8) -> Box { 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 { diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs similarity index 98% rename from src/libstd/rt/unwind/mod.rs rename to src/libstd/sys/common/unwind/mod.rs index 4feb2d49a98ba..ff93d0526b7ef 100644 --- a/src/libstd/rt/unwind/mod.rs +++ b/src/libstd/sys/common/unwind/mod.rs @@ -184,7 +184,6 @@ pub fn panicking() -> bool { #[no_mangle] #[allow(private_no_mangle_fns)] fn rust_panic(cause: Box) -> ! { - rtdebug!("begin_unwind()"); unsafe { imp::panic(cause) } @@ -288,7 +287,8 @@ fn begin_unwind_inner(msg: Box, // 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)); diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/sys/common/unwind/seh.rs similarity index 97% rename from src/libstd/rt/unwind/seh.rs rename to src/libstd/sys/common/unwind/seh.rs index 8c7937581665b..a201e406a23ea 100644 --- a/src/libstd/rt/unwind/seh.rs +++ b/src/libstd/sys/common/unwind/seh.rs @@ -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 } diff --git a/src/libstd/rt/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs similarity index 94% rename from src/libstd/rt/unwind/seh64_gnu.rs rename to src/libstd/sys/common/unwind/seh64_gnu.rs index 78f969bfbeb5b..4d23794de2445 100644 --- a/src/libstd/rt/unwind/seh64_gnu.rs +++ b/src/libstd/sys/common/unwind/seh64_gnu.rs @@ -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) -> ! { 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) -> ! { } pub unsafe fn cleanup(ptr: *mut u8) -> Box { - 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, diff --git a/src/libstd/rt/util.rs b/src/libstd/sys/common/util.rs similarity index 72% rename from src/libstd/rt/util.rs rename to src/libstd/sys/common/util.rs index 23a3c3e38c467..979f1f4866983 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/sys/common/util.rs @@ -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("")); + dumb_print(format_args!("\nthread '{}' has overflowed its stack", + thread::current().name().unwrap_or(""))); } diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index bbed42cc31d75..964bc08ff4e10 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -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, diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index af0d8da05f49a..94c4d04ea30bb 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -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 = bytes.into_iter().map(|v| { OsStringExt::from_vec(v) }).collect(); diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index de9e8cf97e68f..441313bc63993 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -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, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 732e2e65864fd..04bb5e5ea3833 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -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, diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index e62b2d8cb18ff..998b4fcb1a121 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -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(); }); }); } diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs index f93f7c756deff..d1c2144ef0d78 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -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; diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 17bc7ee887693..c544eec7fce85 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -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 _; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 3a4c3e7eef1dd..2b7a3deceb7c4 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -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> { 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: F) -> Result 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()) }