about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Turon <aturon@mozilla.com>2014-11-23 19:21:17 -0800
committerAaron Turon <aturon@mozilla.com>2014-12-18 23:31:34 -0800
commit2b3477d373603527d23cc578f3737857b7b253d7 (patch)
tree56022ebf11d5d27a6ef15f15d00d014a84a35837
parent840de072085df360733c48396224e9966e2dc72c (diff)
downloadrust-2b3477d373603527d23cc578f3737857b7b253d7.tar.gz
rust-2b3477d373603527d23cc578f3737857b7b253d7.zip
libs: merge librustrt into libstd
This commit merges the `rustrt` crate into `std`, undoing part of the
facade. This merger continues the paring down of the runtime system.

Code relying on the public API of `rustrt` will break; some of this API
is now available through `std::rt`, but is likely to change and/or be
removed very soon.

[breaking-change]
-rw-r--r--mk/crates.mk7
-rw-r--r--src/libcollections/slice.rs12
-rw-r--r--src/librustrt/util.rs136
-rw-r--r--src/libstd/c_str.rs (renamed from src/librustrt/c_str.rs)30
-rw-r--r--src/libstd/comm/mod.rs11
-rw-r--r--src/libstd/comm/oneshot.rs4
-rw-r--r--src/libstd/comm/select.rs4
-rw-r--r--src/libstd/comm/shared.rs6
-rw-r--r--src/libstd/comm/stream.rs6
-rw-r--r--src/libstd/comm/sync.rs6
-rw-r--r--src/libstd/failure.rs6
-rw-r--r--src/libstd/io/stdio.rs7
-rw-r--r--src/libstd/lib.rs9
-rw-r--r--src/libstd/os.rs4
-rw-r--r--src/libstd/rt/args.rs (renamed from src/librustrt/args.rs)14
-rw-r--r--src/libstd/rt/at_exit_imp.rs (renamed from src/librustrt/at_exit_imp.rs)12
-rw-r--r--src/libstd/rt/backtrace.rs978
-rw-r--r--src/libstd/rt/bookkeeping.rs (renamed from src/librustrt/bookkeeping.rs)6
-rw-r--r--src/libstd/rt/exclusive.rs (renamed from src/librustrt/exclusive.rs)10
-rw-r--r--src/libstd/rt/libunwind.rs (renamed from src/librustrt/libunwind.rs)0
-rw-r--r--src/libstd/rt/local.rs (renamed from src/librustrt/local.rs)12
-rw-r--r--src/libstd/rt/local_ptr.rs (renamed from src/librustrt/local_ptr.rs)22
-rw-r--r--src/libstd/rt/macros.rs (renamed from src/librustrt/macros.rs)7
-rw-r--r--src/libstd/rt/mod.rs88
-rw-r--r--src/libstd/rt/mutex.rs (renamed from src/librustrt/mutex.rs)337
-rw-r--r--src/libstd/rt/task.rs (renamed from src/librustrt/task.rs)48
-rw-r--r--src/libstd/rt/thread.rs171
-rw-r--r--src/libstd/rt/thread_local_storage.rs (renamed from src/librustrt/thread_local_storage.rs)6
-rw-r--r--src/libstd/rt/unwind.rs (renamed from src/librustrt/unwind.rs)39
-rw-r--r--src/libstd/rt/util.rs147
-rw-r--r--src/libstd/rtdeps.rs2
-rw-r--r--src/libstd/sys/common/backtrace.rs131
-rw-r--r--src/libstd/sys/common/helper_thread.rs5
-rw-r--r--src/libstd/sys/common/mod.rs3
-rw-r--r--src/libstd/sys/common/stack.rs (renamed from src/librustrt/stack.rs)4
-rw-r--r--src/libstd/sys/common/thread.rs34
-rw-r--r--src/libstd/sys/common/thread_local.rs4
-rw-r--r--src/libstd/sys/unix/backtrace.rs493
-rw-r--r--src/libstd/sys/unix/mod.rs3
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs (renamed from src/librustrt/stack_overflow.rs)166
-rw-r--r--src/libstd/sys/unix/thread.rs270
-rw-r--r--src/libstd/sys/windows/backtrace.rs371
-rw-r--r--src/libstd/sys/windows/mod.rs3
-rw-r--r--src/libstd/sys/windows/stack_overflow.rs120
-rw-r--r--src/libstd/sys/windows/thread.rs95
-rw-r--r--src/libstd/sys/windows/thread_local.rs6
-rw-r--r--src/libstd/task.rs12
-rw-r--r--src/libstd/thread_local/mod.rs2
-rw-r--r--src/libstd/thunk.rs (renamed from src/librustrt/thunk.rs)0
-rw-r--r--src/rt/rust_try.ll2
-rw-r--r--src/test/run-pass/foreign-call-no-runtime.rs3
-rw-r--r--src/test/run-pass/match-ref-binding-in-guard-3256.rs4
-rw-r--r--src/test/run-pass/running-with-no-runtime.rs4
-rw-r--r--src/test/run-pass/writealias.rs4
54 files changed, 2111 insertions, 1775 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index a47d4871326..fafe77c78da 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -51,7 +51,7 @@
 
 TARGET_CRATES := libc std flate arena term \
                  serialize getopts collections test time rand \
-                 log regex graphviz core rbml alloc rustrt \
+                 log regex graphviz core rbml alloc \
                  unicode
 RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_driver rustc_trans rustc_back rustc_llvm 
 HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc regex_macros fmt_macros
@@ -62,9 +62,8 @@ DEPS_core :=
 DEPS_libc := core
 DEPS_unicode := core
 DEPS_alloc := core libc native:jemalloc
-DEPS_rustrt := alloc core libc collections native:rustrt_native
-DEPS_std := core libc rand alloc collections rustrt unicode \
-	native:rust_builtin native:backtrace
+DEPS_std := core libc rand alloc collections unicode \
+	native:rust_builtin native:backtrace native:rustrt_native
 DEPS_graphviz := std
 DEPS_syntax := std term serialize log fmt_macros arena libc
 DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index bba00a80f68..c2ed28d81df 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -1344,8 +1344,6 @@ pub mod raw {
 
 #[cfg(test)]
 mod tests {
-    extern crate rustrt;
-
     use std::cell::Cell;
     use std::default::Default;
     use std::mem;
@@ -1629,9 +1627,9 @@ mod tests {
     #[test]
     fn test_swap_remove_noncopyable() {
         // Tests that we don't accidentally run destructors twice.
-        let mut v = vec![rustrt::exclusive::Exclusive::new(()),
-                         rustrt::exclusive::Exclusive::new(()),
-                         rustrt::exclusive::Exclusive::new(())];
+        let mut v = vec![rt::exclusive::Exclusive::new(()),
+                         rt::exclusive::Exclusive::new(()),
+                         rt::exclusive::Exclusive::new(())];
         let mut _e = v.swap_remove(0);
         assert_eq!(v.len(), 2);
         _e = v.swap_remove(1);
@@ -1736,7 +1734,7 @@ mod tests {
         v2.dedup();
         /*
          * If the boxed pointers were leaked or otherwise misused, valgrind
-         * and/or rustrt should raise errors.
+         * and/or rt should raise errors.
          */
     }
 
@@ -1750,7 +1748,7 @@ mod tests {
         v2.dedup();
         /*
          * If the pointers were leaked or otherwise misused, valgrind and/or
-         * rustrt should raise errors.
+         * rt should raise errors.
          */
     }
 
diff --git a/src/librustrt/util.rs b/src/librustrt/util.rs
deleted file mode 100644
index 74f918b8ee3..00000000000
--- a/src/librustrt/util.rs
+++ /dev/null
@@ -1,136 +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.
-//
-// ignore-lexer-test FIXME #15677
-
-use core::prelude::*;
-
-use core::cmp;
-use core::fmt;
-use core::intrinsics;
-use core::slice;
-use core::str;
-use libc;
-
-// 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 struct Stdio(libc::c_int);
-
-#[allow(non_upper_case_globals)]
-impl Copy for Stdio {}
-
-#[allow(non_upper_case_globals)]
-pub const Stdout: Stdio = Stdio(libc::STDOUT_FILENO);
-#[allow(non_upper_case_globals)]
-pub const Stderr: Stdio = Stdio(libc::STDERR_FILENO);
-
-impl fmt::FormatWriter for Stdio {
-    fn write(&mut self, data: &[u8]) -> fmt::Result {
-        #[cfg(unix)]
-        type WriteLen = libc::size_t;
-        #[cfg(windows)]
-        type WriteLen = libc::c_uint;
-        unsafe {
-            let Stdio(fd) = *self;
-            libc::write(fd,
-                        data.as_ptr() as *const libc::c_void,
-                        data.len() as WriteLen);
-        }
-        Ok(()) // yes, we're lying
-    }
-}
-
-pub fn dumb_print(args: &fmt::Arguments) {
-    use core::fmt::FormatWriter;
-    let mut w = Stderr;
-    let _ = w.write_fmt(args);
-}
-
-pub fn abort(args: &fmt::Arguments) -> ! {
-    use core::fmt::FormatWriter;
-
-    struct BufWriter<'a> {
-        buf: &'a mut [u8],
-        pos: uint,
-    }
-    impl<'a> FormatWriter for BufWriter<'a> {
-        fn write(&mut self, bytes: &[u8]) -> fmt::Result {
-            let left = self.buf[mut self.pos..];
-            let to_write = bytes[..cmp::min(bytes.len(), left.len())];
-            slice::bytes::copy_memory(left, to_write);
-            self.pos += to_write.len();
-            Ok(())
-        }
-    }
-
-    // Convert the arguments into a stack-allocated string
-    let mut msg = [0u8, ..512];
-    let mut w = BufWriter { buf: &mut msg, pos: 0 };
-    let _ = write!(&mut w, "{}", args);
-    let msg = str::from_utf8(w.buf[mut ..w.pos]).unwrap_or("aborted");
-    let msg = if msg.is_empty() {"aborted"} else {msg};
-
-    // Give some context to the message
-    let hash = msg.bytes().fold(0, |accum, val| accum + (val as uint) );
-    let quote = match hash % 10 {
-        0 => "
-It was from the artists and poets that the pertinent answers came, and I
-know that panic would have broken loose had they been able to compare notes.
-As it was, lacking their original letters, I half suspected the compiler of
-having asked leading questions, or of having edited the correspondence in
-corroboration of what he had latently resolved to see.",
-        1 => "
-There are not many persons who know what wonders are opened to them in the
-stories and visions of their youth; for when as children we listen and dream,
-we think but half-formed thoughts, and when as men we try to remember, we are
-dulled and prosaic with the poison of life. But some of us awake in the night
-with strange phantasms of enchanted hills and gardens, of fountains that sing
-in the sun, of golden cliffs overhanging murmuring seas, of plains that stretch
-down to sleeping cities of bronze and stone, and of shadowy companies of heroes
-that ride caparisoned white horses along the edges of thick forests; and then
-we know that we have looked back through the ivory gates into that world of
-wonder which was ours before we were wise and unhappy.",
-        2 => "
-Instead of the poems I had hoped for, there came only a shuddering blackness
-and ineffable loneliness; and I saw at last a fearful truth which no one had
-ever dared to breathe before — the unwhisperable secret of secrets — The fact
-that this city of stone and stridor is not a sentient perpetuation of Old New
-York as London is of Old London and Paris of Old Paris, but that it is in fact
-quite dead, its sprawling body imperfectly embalmed and infested with queer
-animate things which have nothing to do with it as it was in life.",
-        3 => "
-The ocean ate the last of the land and poured into the smoking gulf, thereby
-giving up all it had ever conquered. From the new-flooded lands it flowed
-again, uncovering death and decay; and from its ancient and immemorial bed it
-trickled loathsomely, uncovering nighted secrets of the years when Time was
-young and the gods unborn. Above the waves rose weedy remembered spires. The
-moon laid pale lilies of light on dead London, and Paris stood up from its damp
-grave to be sanctified with star-dust. Then rose spires and monoliths that were
-weedy but not remembered; terrible spires and monoliths of lands that men never
-knew were lands...",
-        4 => "
-There was a night when winds from unknown spaces whirled us irresistibly into
-limitless vacuum beyond all thought and entity. Perceptions of the most
-maddeningly untransmissible sort thronged upon us; perceptions of infinity
-which at the time convulsed us with joy, yet which are now partly lost to my
-memory and partly incapable of presentation to others.",
-        _ => "You've met with a terrible fate, haven't you?"
-    };
-    rterrln!("{}", "");
-    rterrln!("{}", quote);
-    rterrln!("{}", "");
-    rterrln!("fatal runtime error: {}", msg);
-    unsafe { intrinsics::abort(); }
-}
diff --git a/src/librustrt/c_str.rs b/src/libstd/c_str.rs
index 6649b93e4b0..27a139835c9 100644
--- a/src/librustrt/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -67,17 +67,17 @@
 //! }
 //! ```
 
+use string::String;
+use hash;
+use fmt;
+use kinds::marker;
+use mem;
 use core::prelude::*;
 
-use collections::string::String;
-use core::hash;
-use core::fmt;
-use core::kinds::{Sized, marker};
-use core::mem;
-use core::ptr;
-use core::raw::Slice;
-use core::slice;
-use core::str;
+use ptr;
+use raw::Slice;
+use slice;
+use str;
 use libc;
 
 /// The representation of a C String.
@@ -534,9 +534,9 @@ pub unsafe fn from_c_multistring<F>(buf: *const libc::c_char,
 
 #[cfg(test)]
 mod tests {
-    use std::prelude::*;
-    use std::ptr;
-    use std::task;
+    use prelude::*;
+    use ptr;
+    use task;
     use libc;
 
     use super::*;
@@ -726,9 +726,11 @@ mod tests {
 
 #[cfg(test)]
 mod bench {
-    use test::Bencher;
+    extern crate test;
+
+    use self::test::Bencher;
     use libc;
-    use std::prelude::*;
+    use prelude::*;
 
     #[inline]
     fn check(s: &str, c_str: *const libc::c_char) {
diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs
index 29a7b0dd0cc..dfbb09d26b5 100644
--- a/src/libstd/comm/mod.rs
+++ b/src/libstd/comm/mod.rs
@@ -327,7 +327,7 @@ use alloc::arc::Arc;
 use core::kinds::marker;
 use core::mem;
 use core::cell::UnsafeCell;
-use rustrt::task::BlockedTask;
+use rt::task::BlockedTask;
 
 pub use comm::select::{Select, Handle};
 
@@ -336,9 +336,8 @@ macro_rules! test {
         mod $name {
             #![allow(unused_imports)]
 
-            extern crate rustrt;
-
             use prelude::*;
+            use rt;
 
             use comm::*;
             use super::*;
@@ -1519,7 +1518,7 @@ mod test {
     } }
 
     test! { fn sends_off_the_runtime() {
-        use rustrt::thread::Thread;
+        use rt::thread::Thread;
 
         let (tx, rx) = channel();
         let t = Thread::start(move|| {
@@ -1534,7 +1533,7 @@ mod test {
     } }
 
     test! { fn try_recvs_off_the_runtime() {
-        use rustrt::thread::Thread;
+        use rt::thread::Thread;
 
         let (tx, rx) = channel();
         let (cdone, pdone) = channel();
@@ -1984,7 +1983,7 @@ mod sync_tests {
     } }
 
     test! { fn try_recvs_off_the_runtime() {
-        use rustrt::thread::Thread;
+        use rt::thread::Thread;
 
         let (tx, rx) = sync_channel::<()>(0);
         let (cdone, pdone) = channel();
diff --git a/src/libstd/comm/oneshot.rs b/src/libstd/comm/oneshot.rs
index bc34c3e8c52..2c5248c0897 100644
--- a/src/libstd/comm/oneshot.rs
+++ b/src/libstd/comm/oneshot.rs
@@ -41,8 +41,8 @@ use core::prelude::*;
 
 use alloc::boxed::Box;
 use core::mem;
-use rustrt::local::Local;
-use rustrt::task::{Task, BlockedTask};
+use rt::local::Local;
+use rt::task::{Task, BlockedTask};
 
 use sync::atomic;
 use comm::Receiver;
diff --git a/src/libstd/comm/select.rs b/src/libstd/comm/select.rs
index de2b84b083c..4da9b4cfa36 100644
--- a/src/libstd/comm/select.rs
+++ b/src/libstd/comm/select.rs
@@ -59,8 +59,8 @@ use core::cell::Cell;
 use core::kinds::marker;
 use core::mem;
 use core::uint;
-use rustrt::local::Local;
-use rustrt::task::{Task, BlockedTask};
+use rt::local::Local;
+use rt::task::{Task, BlockedTask};
 
 use comm::Receiver;
 
diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs
index 13b5e10fcd3..b3856e588e2 100644
--- a/src/libstd/comm/shared.rs
+++ b/src/libstd/comm/shared.rs
@@ -25,9 +25,9 @@ use core::prelude::*;
 use alloc::boxed::Box;
 use core::cmp;
 use core::int;
-use rustrt::local::Local;
-use rustrt::task::{Task, BlockedTask};
-use rustrt::thread::Thread;
+use rt::local::Local;
+use rt::task::{Task, BlockedTask};
+use rt::thread::Thread;
 
 use sync::{atomic, Mutex, MutexGuard};
 use comm::mpsc_queue as mpsc;
diff --git a/src/libstd/comm/stream.rs b/src/libstd/comm/stream.rs
index 06ab4f4427a..827b1d51ac4 100644
--- a/src/libstd/comm/stream.rs
+++ b/src/libstd/comm/stream.rs
@@ -27,9 +27,9 @@ use core::prelude::*;
 use alloc::boxed::Box;
 use core::cmp;
 use core::int;
-use rustrt::local::Local;
-use rustrt::task::{Task, BlockedTask};
-use rustrt::thread::Thread;
+use rt::local::Local;
+use rt::task::{Task, BlockedTask};
+use rt::thread::Thread;
 
 use sync::atomic;
 use comm::spsc_queue as spsc;
diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs
index a2e839e134c..933cd43c662 100644
--- a/src/libstd/comm/sync.rs
+++ b/src/libstd/comm/sync.rs
@@ -42,9 +42,9 @@ use alloc::boxed::Box;
 use vec::Vec;
 use core::mem;
 use core::cell::UnsafeCell;
-use rustrt::local::Local;
-use rustrt::mutex::{NativeMutex, LockGuard};
-use rustrt::task::{Task, BlockedTask};
+use rt::local::Local;
+use rt::mutex::{NativeMutex, LockGuard};
+use rt::task::{Task, BlockedTask};
 
 use sync::atomic;
 
diff --git a/src/libstd/failure.rs b/src/libstd/failure.rs
index 89bccb8b99f..5438f1920d6 100644
--- a/src/libstd/failure.rs
+++ b/src/libstd/failure.rs
@@ -20,9 +20,9 @@ use option::Option;
 use option::Option::{Some, None};
 use result::Result::Ok;
 use rt::backtrace;
-use rustrt::{Stderr, Stdio};
-use rustrt::local::Local;
-use rustrt::task::Task;
+use rt::util::{Stderr, Stdio};
+use rt::local::Local;
+use rt::task::Task;
 use str::Str;
 use string::String;
 
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 73be389bb91..7b5cbf7d58f 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -42,9 +42,8 @@ use option::Option::{Some, None};
 use ops::{Deref, DerefMut, FnOnce};
 use result::Result::{Ok, Err};
 use rt;
-use rustrt;
-use rustrt::local::Local;
-use rustrt::task::Task;
+use rt::local::Local;
+use rt::task::Task;
 use slice::SliceExt;
 use str::StrPrelude;
 use string::String;
@@ -345,7 +344,7 @@ fn with_task_stdout<F>(f: F) where
         });
         result
     } else {
-        let mut io = rustrt::Stdout;
+        let mut io = rt::util::Stdout;
         f(&mut io as &mut Writer)
     };
     match result {
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index e99aba9b673..d7f331b6c23 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -104,7 +104,7 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![allow(unknown_features)]
-#![feature(macro_rules, globs, linkage)]
+#![feature(macro_rules, globs, linkage, thread_local, asm)]
 #![feature(default_type_params, phase, lang_items, unsafe_destructor)]
 #![feature(import_shadowing, slicing_syntax)]
 #![feature(unboxed_closures)]
@@ -124,7 +124,6 @@ extern crate core;
 extern crate "collections" as core_collections;
 extern crate "rand" as core_rand;
 extern crate libc;
-extern crate rustrt;
 
 // Make std testable by not duplicating lang items. See #2912
 #[cfg(test)] extern crate "std" as realstd;
@@ -167,12 +166,8 @@ pub use core_collections::str;
 pub use core_collections::string;
 pub use core_collections::vec;
 
-pub use rustrt::c_str;
-
 pub use unicode::char;
 
-pub use rustrt::thunk;
-
 /* Exported macros */
 
 pub mod macros;
@@ -207,6 +202,7 @@ pub mod prelude;
 #[path = "num/f64.rs"]   pub mod f64;
 
 pub mod ascii;
+pub mod thunk;
 
 /* Common traits */
 
@@ -216,6 +212,7 @@ pub mod num;
 /* Runtime and platform support */
 
 pub mod thread_local;
+pub mod c_str;
 pub mod c_vec;
 pub mod dynamic_lib;
 pub mod fmt;
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 860f9d2670a..6e02c03602f 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -1042,9 +1042,9 @@ fn real_args_as_bytes() -> Vec<Vec<u8>> {
           target_os = "freebsd",
           target_os = "dragonfly"))]
 fn real_args_as_bytes() -> Vec<Vec<u8>> {
-    use rustrt;
+    use rt;
 
-    match rustrt::args::clone() {
+    match rt::args::clone() {
         Some(args) => args,
         None => panic!("process arguments not initialized")
     }
diff --git a/src/librustrt/args.rs b/src/libstd/rt/args.rs
index c1b48e989a1..8b9dbf73c53 100644
--- a/src/librustrt/args.rs
+++ b/src/libstd/rt/args.rs
@@ -20,7 +20,7 @@
 //! FIXME #7756: Would be nice for this to not exist.
 
 use core::prelude::*;
-use collections::vec::Vec;
+use vec::Vec;
 
 /// One-time global initialization.
 pub unsafe fn init(argc: int, argv: *const *const u8) { imp::init(argc, argv) }
@@ -46,12 +46,12 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
 mod imp {
     use core::prelude::*;
 
-    use alloc::boxed::Box;
-    use collections::vec::Vec;
-    use collections::string::String;
-    use core::mem;
+    use boxed::Box;
+    use vec::Vec;
+    use string::String;
+    use mem;
 
-    use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+    use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
 
     static mut GLOBAL_ARGS_PTR: uint = 0;
     static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
@@ -145,7 +145,7 @@ mod imp {
           target_os = "windows"))]
 mod imp {
     use core::prelude::*;
-    use collections::vec::Vec;
+    use vec::Vec;
 
     pub unsafe fn init(_argc: int, _argv: *const *const u8) {
     }
diff --git a/src/librustrt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs
index 8be77d9b34d..086079c312a 100644
--- a/src/librustrt/at_exit_imp.rs
+++ b/src/libstd/rt/at_exit_imp.rs
@@ -14,13 +14,13 @@
 
 use core::prelude::*;
 
-use alloc::boxed::Box;
-use collections::vec::Vec;
-use core::atomic;
-use core::mem;
-use thunk::{Thunk};
+use boxed::Box;
+use vec::Vec;
+use sync::atomic;
+use mem;
+use thunk::Thunk;
 
-use exclusive::Exclusive;
+use rt::exclusive::Exclusive;
 
 type Queue = Exclusive<Vec<Thunk>>;
 
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
index d815a5ea4f7..40885823a05 100644
--- a/src/libstd/rt/backtrace.rs
+++ b/src/libstd/rt/backtrace.rs
@@ -19,9 +19,8 @@ use os;
 use result::Result::{Ok, Err};
 use str::{StrPrelude, from_str};
 use sync::atomic;
-use unicode::char::UnicodeChar;
 
-pub use self::imp::write;
+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.
@@ -41,984 +40,13 @@ pub fn log_enabled() -> bool {
     val == 2
 }
 
-#[cfg(target_word_size = "64")] const HEX_WIDTH: uint = 18;
-#[cfg(target_word_size = "32")] const HEX_WIDTH: uint = 10;
-
-// All rust symbols are in theory lists of "::"-separated identifiers. Some
-// assemblers, however, can't handle these characters in symbol names. To get
-// around this, we use C++-style mangling. The mangling method is:
-//
-// 1. Prefix the symbol with "_ZN"
-// 2. For each element of the path, emit the length plus the element
-// 3. End the path with "E"
-//
-// For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar".
-//
-// We're the ones printing our backtraces, so we can't rely on anything else to
-// demangle our symbols. It's *much* nicer to look at demangled symbols, so
-// this function is implemented to give us nice pretty output.
-//
-// Note that this demangler isn't quite as fancy as it could be. We have lots
-// of other information in our symbols like hashes, version, type information,
-// etc. Additionally, this doesn't handle glue symbols at all.
-fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
-    // First validate the symbol. If it doesn't look like anything we're
-    // expecting, we just print it literally. Note that we must handle non-rust
-    // symbols because we could have any function in the backtrace.
-    let mut valid = true;
-    let mut inner = s;
-    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
-        inner = s.slice(3, s.len() - 1);
-    // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
-    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
-        inner = s.slice(2, s.len() - 1);
-    } else {
-        valid = false;
-    }
-
-    if valid {
-        let mut chars = inner.chars();
-        while valid {
-            let mut i = 0;
-            for c in chars {
-                if c.is_numeric() {
-                    i = i * 10 + c as uint - '0' as uint;
-                } else {
-                    break
-                }
-            }
-            if i == 0 {
-                valid = chars.next().is_none();
-                break
-            } else if chars.by_ref().take(i - 1).count() != i - 1 {
-                valid = false;
-            }
-        }
-    }
-
-    // Alright, let's do this.
-    if !valid {
-        try!(writer.write_str(s));
-    } else {
-        let mut first = true;
-        while inner.len() > 0 {
-            if !first {
-                try!(writer.write_str("::"));
-            } else {
-                first = false;
-            }
-            let mut rest = inner;
-            while rest.char_at(0).is_numeric() {
-                rest = rest.slice_from(1);
-            }
-            let i: uint = from_str(inner.slice_to(inner.len() - rest.len())).unwrap();
-            inner = rest.slice_from(i);
-            rest = rest.slice_to(i);
-            while rest.len() > 0 {
-                if rest.starts_with("$") {
-                    macro_rules! demangle {
-                        ($($pat:expr => $demangled:expr),*) => ({
-                            $(if rest.starts_with($pat) {
-                                try!(writer.write_str($demangled));
-                                rest = rest.slice_from($pat.len());
-                              } else)*
-                            {
-                                try!(writer.write_str(rest));
-                                break;
-                            }
-
-                        })
-                    }
-
-                    // see src/librustc/back/link.rs for these mappings
-                    demangle! (
-                        "$SP$" => "@",
-                        "$UP$" => "Box",
-                        "$RP$" => "*",
-                        "$BP$" => "&",
-                        "$LT$" => "<",
-                        "$GT$" => ">",
-                        "$LP$" => "(",
-                        "$RP$" => ")",
-                        "$C$"  => ",",
-
-                        // in theory we can demangle any Unicode code point, but
-                        // for simplicity we just catch the common ones.
-                        "$x20" => " ",
-                        "$x27" => "'",
-                        "$x5b" => "[",
-                        "$x5d" => "]"
-                    )
-                } else {
-                    let idx = match rest.find('$') {
-                        None => rest.len(),
-                        Some(i) => i,
-                    };
-                    try!(writer.write_str(rest.slice_to(idx)));
-                    rest = rest.slice_from(idx);
-                }
-            }
-        }
-    }
-
-    Ok(())
-}
-
-/// Backtrace support built on libgcc with some extra OS-specific support
-///
-/// Some methods of getting a backtrace:
-///
-/// * The backtrace() functions on unix. It turns out this doesn't work very
-///   well for green threads on OSX, and the address to symbol portion of it
-///   suffers problems that are described below.
-///
-/// * Using libunwind. This is more difficult than it sounds because libunwind
-///   isn't installed everywhere by default. It's also a bit of a hefty library,
-///   so possibly not the best option. When testing, libunwind was excellent at
-///   getting both accurate backtraces and accurate symbols across platforms.
-///   This route was not chosen in favor of the next option, however.
-///
-/// * We're already using libgcc_s for exceptions in rust (triggering task
-///   unwinding and running destructors on the stack), and it turns out that it
-///   conveniently comes with a function that also gives us a backtrace. All of
-///   these functions look like _Unwind_*, but it's not quite the full
-///   repertoire of the libunwind API. Due to it already being in use, this was
-///   the chosen route of getting a backtrace.
-///
-/// After choosing libgcc_s for backtraces, the sad part is that it will only
-/// give us a stack trace of instruction pointers. Thankfully these instruction
-/// pointers are accurate (they work for green and native threads), but it's
-/// then up to us again to figure out how to translate these addresses to
-/// symbols. As with before, we have a few options. Before, that, a little bit
-/// of an interlude about symbols. This is my very limited knowledge about
-/// symbol tables, and this information is likely slightly wrong, but the
-/// general idea should be correct.
-///
-/// When talking about symbols, it's helpful to know a few things about where
-/// symbols are located. Some symbols are located in the dynamic symbol table
-/// of the executable which in theory means that they're available for dynamic
-/// linking and lookup. Other symbols end up only in the local symbol table of
-/// the file. This loosely corresponds to pub and priv functions in Rust.
-///
-/// Armed with this knowledge, we know that our solution for address to symbol
-/// translation will need to consult both the local and dynamic symbol tables.
-/// With that in mind, here's our options of translating an address to
-/// a symbol.
-///
-/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
-///   behind the scenes to translate, and this is why backtrace() was not used.
-///   Conveniently, this method works fantastically on OSX. It appears dladdr()
-///   uses magic to consult the local symbol table, or we're putting everything
-///   in the dynamic symbol table anyway. Regardless, for OSX, this is the
-///   method used for translation. It's provided by the system and easy to do.o
-///
-///   Sadly, all other systems have a dladdr() implementation that does not
-///   consult the local symbol table. This means that most functions are blank
-///   because they don't have symbols. This means that we need another solution.
-///
-/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
-///   libgcc_s version of the libunwind api), but involves taking a dependency
-///   to libunwind. We may pursue this route in the future if we bundle
-///   libunwind, but libunwind was unwieldy enough that it was not chosen at
-///   this time to provide this functionality.
-///
-/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
-///   semi-reasonable solution. The stdlib already knows how to spawn processes,
-///   so in theory it could invoke readelf, parse the output, and consult the
-///   local/dynamic symbol tables from there. This ended up not getting chosen
-///   due to the craziness of the idea plus the advent of the next option.
-///
-/// * Use `libbacktrace`. It turns out that this is a small library bundled in
-///   the gcc repository which provides backtrace and symbol translation
-///   functionality. All we really need from it is the backtrace functionality,
-///   and we only really need this on everything that's not OSX, so this is the
-///   chosen route for now.
-///
-/// In summary, the current situation uses libgcc_s to get a trace of stack
-/// pointers, and we use dladdr() or libbacktrace to translate these addresses
-/// to symbols. This is a bit of a hokey implementation as-is, but it works for
-/// all unix platforms we support right now, so it at least gets the job done.
-#[cfg(unix)]
-mod imp {
-    use prelude::*;
-
-    use c_str::CString;
-    use io::IoResult;
-    use libc;
-    use mem;
-    use sync::{StaticMutex, MUTEX_INIT};
-
-    /// As always - iOS on arm uses SjLj exceptions and
-    /// _Unwind_Backtrace is even not available there. Still,
-    /// backtraces could be extracted using a backtrace function,
-    /// which thanks god is public
-    ///
-    /// As mentioned in a huge comment block above, backtrace doesn't
-    /// play well with green threads, so while it is extremely nice
-    /// and simple to use it should be used only on iOS devices as the
-    /// only viable option.
-    #[cfg(all(target_os = "ios", target_arch = "arm"))]
-    #[inline(never)]
-    pub fn write(w: &mut Writer) -> IoResult<()> {
-        use result;
-
-        extern {
-            fn backtrace(buf: *mut *mut libc::c_void,
-                         sz: libc::c_int) -> libc::c_int;
-        }
-
-        // while it doesn't requires lock for work as everything is
-        // local, it still displays much nicer backtraces when a
-        // couple of tasks panic simultaneously
-        static LOCK: StaticMutex = MUTEX_INIT;
-        let _g = LOCK.lock();
-
-        try!(writeln!(w, "stack backtrace:"));
-        // 100 lines should be enough
-        const SIZE: uint = 100;
-        let mut buf: [*mut libc::c_void, ..SIZE] = unsafe {mem::zeroed()};
-        let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as uint};
-
-        // skipping the first one as it is write itself
-        let iter = range(1, cnt).map(|i| {
-            print(w, i as int, buf[i])
-        });
-        result::fold(iter, (), |_, _| ())
-    }
-
-    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-    #[inline(never)] // if we know this is a function call, we can skip it when
-                     // tracing
-    pub fn write(w: &mut Writer) -> IoResult<()> {
-        use io::IoError;
-
-        struct Context<'a> {
-            idx: int,
-            writer: &'a mut (Writer+'a),
-            last_error: Option<IoError>,
-        }
-
-        // When using libbacktrace, we use some necessary global state, so we
-        // need to prevent more than one thread from entering this block. This
-        // is semi-reasonable in terms of printing anyway, and we know that all
-        // I/O done here is blocking I/O, not green I/O, so we don't have to
-        // worry about this being a native vs green mutex.
-        static LOCK: StaticMutex = MUTEX_INIT;
-        let _g = LOCK.lock();
-
-        try!(writeln!(w, "stack backtrace:"));
-
-        let mut cx = Context { writer: w, last_error: None, idx: 0 };
-        return match unsafe {
-            uw::_Unwind_Backtrace(trace_fn,
-                                  &mut cx as *mut Context as *mut libc::c_void)
-        } {
-            uw::_URC_NO_REASON => {
-                match cx.last_error {
-                    Some(err) => Err(err),
-                    None => Ok(())
-                }
-            }
-            _ => Ok(()),
-        };
-
-        extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
-                           arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
-            let cx: &mut Context = unsafe { mem::transmute(arg) };
-            let ip = unsafe { uw::_Unwind_GetIP(ctx) as *mut libc::c_void };
-            // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
-            // it appears to work fine without it, so we only use
-            // FindEnclosingFunction on non-osx platforms. In doing so, we get a
-            // slightly more accurate stack trace in the process.
-            //
-            // This is often because panic involves the last instruction of a
-            // function being "call std::rt::begin_unwind", with no ret
-            // instructions after it. This means that the return instruction
-            // pointer points *outside* of the calling function, and by
-            // unwinding it we go back to the original function.
-            let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
-                ip
-            } else {
-                unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
-            };
-
-            // Don't print out the first few frames (they're not user frames)
-            cx.idx += 1;
-            if cx.idx <= 0 { return uw::_URC_NO_REASON }
-            // Don't print ginormous backtraces
-            if cx.idx > 100 {
-                match write!(cx.writer, " ... <frames omitted>\n") {
-                    Ok(()) => {}
-                    Err(e) => { cx.last_error = Some(e); }
-                }
-                return uw::_URC_FAILURE
-            }
-
-            // Once we hit an error, stop trying to print more frames
-            if cx.last_error.is_some() { return uw::_URC_FAILURE }
-
-            match print(cx.writer, cx.idx, ip) {
-                Ok(()) => {}
-                Err(e) => { cx.last_error = Some(e); }
-            }
-
-            // keep going
-            return uw::_URC_NO_REASON
-        }
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
-    fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
-        use intrinsics;
-        #[repr(C)]
-        struct Dl_info {
-            dli_fname: *const libc::c_char,
-            dli_fbase: *mut libc::c_void,
-            dli_sname: *const libc::c_char,
-            dli_saddr: *mut libc::c_void,
-        }
-        extern {
-            fn dladdr(addr: *const libc::c_void,
-                      info: *mut Dl_info) -> libc::c_int;
-        }
-
-        let mut info: Dl_info = unsafe { intrinsics::init() };
-        if unsafe { dladdr(addr as *const libc::c_void, &mut info) == 0 } {
-            output(w, idx,addr, None)
-        } else {
-            output(w, idx, addr, Some(unsafe {
-                CString::new(info.dli_sname, false)
-            }))
-        }
-    }
-
-    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
-    fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
-        use os;
-        use ptr;
-
-        ////////////////////////////////////////////////////////////////////////
-        // libbacktrace.h API
-        ////////////////////////////////////////////////////////////////////////
-        type backtrace_syminfo_callback =
-            extern "C" fn(data: *mut libc::c_void,
-                          pc: libc::uintptr_t,
-                          symname: *const libc::c_char,
-                          symval: libc::uintptr_t,
-                          symsize: libc::uintptr_t);
-        type backtrace_error_callback =
-            extern "C" fn(data: *mut libc::c_void,
-                          msg: *const libc::c_char,
-                          errnum: libc::c_int);
-        enum backtrace_state {}
-        #[link(name = "backtrace", kind = "static")]
-        #[cfg(not(test))]
-        extern {}
-
-        extern {
-            fn backtrace_create_state(filename: *const libc::c_char,
-                                      threaded: libc::c_int,
-                                      error: backtrace_error_callback,
-                                      data: *mut libc::c_void)
-                                            -> *mut backtrace_state;
-            fn backtrace_syminfo(state: *mut backtrace_state,
-                                 addr: libc::uintptr_t,
-                                 cb: backtrace_syminfo_callback,
-                                 error: backtrace_error_callback,
-                                 data: *mut libc::c_void) -> libc::c_int;
-        }
-
-        ////////////////////////////////////////////////////////////////////////
-        // helper callbacks
-        ////////////////////////////////////////////////////////////////////////
-
-        extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
-                           _errnum: libc::c_int) {
-            // do nothing for now
-        }
-        extern fn syminfo_cb(data: *mut libc::c_void,
-                             _pc: libc::uintptr_t,
-                             symname: *const libc::c_char,
-                             _symval: libc::uintptr_t,
-                             _symsize: libc::uintptr_t) {
-            let slot = data as *mut *const libc::c_char;
-            unsafe { *slot = symname; }
-        }
-
-        // The libbacktrace API supports creating a state, but it does not
-        // support destroying a state. I personally take this to mean that a
-        // state is meant to be created and then live forever.
-        //
-        // I would love to register an at_exit() handler which cleans up this
-        // state, but libbacktrace provides no way to do so.
-        //
-        // With these constraints, this function has a statically cached state
-        // that is calculated the first time this is requested. Remember that
-        // backtracing all happens serially (one global lock).
-        //
-        // An additionally oddity in this function is that we initialize the
-        // filename via self_exe_name() to pass to libbacktrace. It turns out
-        // that on Linux libbacktrace seamlessly gets the filename of the
-        // current executable, but this fails on freebsd. by always providing
-        // it, we make sure that libbacktrace never has a reason to not look up
-        // the symbols. The libbacktrace API also states that the filename must
-        // be in "permanent memory", so we copy it to a static and then use the
-        // static as the pointer.
-        //
-        // FIXME: We also call self_exe_name() on DragonFly BSD. I haven't
-        //        tested if this is required or not.
-        unsafe fn init_state() -> *mut backtrace_state {
-            static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
-            static mut LAST_FILENAME: [libc::c_char, ..256] = [0, ..256];
-            if !STATE.is_null() { return STATE }
-            let selfname = if cfg!(target_os = "freebsd") ||
-                              cfg!(target_os = "dragonfly") {
-                os::self_exe_name()
-            } else {
-                None
-            };
-            let filename = match selfname {
-                Some(path) => {
-                    let bytes = path.as_vec();
-                    if bytes.len() < LAST_FILENAME.len() {
-                        let i = bytes.iter();
-                        for (slot, val) in LAST_FILENAME.iter_mut().zip(i) {
-                            *slot = *val as libc::c_char;
-                        }
-                        LAST_FILENAME.as_ptr()
-                    } else {
-                        ptr::null()
-                    }
-                }
-                None => ptr::null(),
-            };
-            STATE = backtrace_create_state(filename, 0, error_cb,
-                                           ptr::null_mut());
-            return STATE
-        }
-
-        ////////////////////////////////////////////////////////////////////////
-        // translation
-        ////////////////////////////////////////////////////////////////////////
-
-        // backtrace errors are currently swept under the rug, only I/O
-        // errors are reported
-        let state = unsafe { init_state() };
-        if state.is_null() {
-            return output(w, idx, addr, None)
-        }
-        let mut data = 0 as *const libc::c_char;
-        let data_addr = &mut data as *mut *const libc::c_char;
-        let ret = unsafe {
-            backtrace_syminfo(state, addr as libc::uintptr_t,
-                              syminfo_cb, error_cb,
-                              data_addr as *mut libc::c_void)
-        };
-        if ret == 0 || data.is_null() {
-            output(w, idx, addr, None)
-        } else {
-            output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
-        }
-    }
-
-    // Finally, after all that work above, we can emit a symbol.
-    fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
-              s: Option<CString>) -> IoResult<()> {
-        try!(write!(w, "  {:2}: {:2$} - ", idx, addr, super::HEX_WIDTH));
-        match s.as_ref().and_then(|c| c.as_str()) {
-            Some(string) => try!(super::demangle(w, string)),
-            None => try!(write!(w, "<unknown>")),
-        }
-        w.write(&['\n' as u8])
-    }
-
-    /// Unwind library interface used for backtraces
-    ///
-    /// Note that the native libraries come from librustrt, not this
-    /// module.
-    /// Note that dead code is allowed as here are just bindings
-    /// iOS doesn't use all of them it but adding more
-    /// platform-specific configs pollutes the code too much
-    #[allow(non_camel_case_types)]
-    #[allow(non_snake_case)]
-    #[allow(dead_code)]
-    mod uw {
-        pub use self::_Unwind_Reason_Code::*;
-
-        use libc;
-
-        #[repr(C)]
-        pub enum _Unwind_Reason_Code {
-            _URC_NO_REASON = 0,
-            _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
-            _URC_FATAL_PHASE2_ERROR = 2,
-            _URC_FATAL_PHASE1_ERROR = 3,
-            _URC_NORMAL_STOP = 4,
-            _URC_END_OF_STACK = 5,
-            _URC_HANDLER_FOUND = 6,
-            _URC_INSTALL_CONTEXT = 7,
-            _URC_CONTINUE_UNWIND = 8,
-            _URC_FAILURE = 9, // used only by ARM EABI
-        }
-
-        pub enum _Unwind_Context {}
-
-        pub type _Unwind_Trace_Fn =
-                extern fn(ctx: *mut _Unwind_Context,
-                          arg: *mut libc::c_void) -> _Unwind_Reason_Code;
-
-        extern {
-            // No native _Unwind_Backtrace on iOS
-            #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-            pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
-                                     trace_argument: *mut libc::c_void)
-                        -> _Unwind_Reason_Code;
-
-            #[cfg(all(not(target_os = "android"),
-                      not(all(target_os = "linux", target_arch = "arm"))))]
-            pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
-
-            #[cfg(all(not(target_os = "android"),
-                      not(all(target_os = "linux", target_arch = "arm"))))]
-            pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
-                -> *mut libc::c_void;
-        }
-
-        // On android, the function _Unwind_GetIP is a macro, and this is the
-        // expansion of the macro. This is all copy/pasted directly from the
-        // header file with the definition of _Unwind_GetIP.
-        #[cfg(any(target_os = "android",
-                  all(target_os = "linux", target_arch = "arm")))]
-        pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
-            #[repr(C)]
-            enum _Unwind_VRS_Result {
-                _UVRSR_OK = 0,
-                _UVRSR_NOT_IMPLEMENTED = 1,
-                _UVRSR_FAILED = 2,
-            }
-            #[repr(C)]
-            enum _Unwind_VRS_RegClass {
-                _UVRSC_CORE = 0,
-                _UVRSC_VFP = 1,
-                _UVRSC_FPA = 2,
-                _UVRSC_WMMXD = 3,
-                _UVRSC_WMMXC = 4,
-            }
-            #[repr(C)]
-            enum _Unwind_VRS_DataRepresentation {
-                _UVRSD_UINT32 = 0,
-                _UVRSD_VFPX = 1,
-                _UVRSD_FPAX = 2,
-                _UVRSD_UINT64 = 3,
-                _UVRSD_FLOAT = 4,
-                _UVRSD_DOUBLE = 5,
-            }
-
-            type _Unwind_Word = libc::c_uint;
-            extern {
-                fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
-                                   klass: _Unwind_VRS_RegClass,
-                                   word: _Unwind_Word,
-                                   repr: _Unwind_VRS_DataRepresentation,
-                                   data: *mut libc::c_void)
-                    -> _Unwind_VRS_Result;
-            }
-
-            let mut val: _Unwind_Word = 0;
-            let ptr = &mut val as *mut _Unwind_Word;
-            let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
-                                    _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
-                                    ptr as *mut libc::c_void);
-            (val & !1) as libc::uintptr_t
-        }
-
-        // This function also doesn't exist on Android or ARM/Linux, so make it
-        // a no-op
-        #[cfg(any(target_os = "android",
-                  all(target_os = "linux", target_arch = "arm")))]
-        pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
-            -> *mut libc::c_void
-        {
-            pc
-        }
-    }
-}
-
-/// As always, windows has something very different than unix, we mainly want
-/// to avoid having to depend too much on libunwind for windows.
-///
-/// If you google around, you'll find a fair bit of references to built-in
-/// functions to get backtraces on windows. It turns out that most of these are
-/// in an external library called dbghelp. I was unable to find this library
-/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
-/// of it.
-///
-/// You'll also find that there's a function called CaptureStackBackTrace
-/// mentioned frequently (which is also easy to use), but sadly I didn't have a
-/// copy of that function in my mingw install (maybe it was broken?). Instead,
-/// this takes the route of using StackWalk64 in order to walk the stack.
-#[cfg(windows)]
-#[allow(dead_code, non_snake_case)]
-mod imp {
-    use c_str::CString;
-    use intrinsics;
-    use io::{IoResult, Writer};
-    use libc;
-    use mem;
-    use ops::Drop;
-    use option::Option::{Some, None};
-    use path::Path;
-    use result::Result::{Ok, Err};
-    use sync::{StaticMutex, MUTEX_INIT};
-    use slice::SliceExt;
-    use str::StrPrelude;
-    use dynamic_lib::DynamicLibrary;
-
-    #[allow(non_snake_case)]
-    extern "system" {
-        fn GetCurrentProcess() -> libc::HANDLE;
-        fn GetCurrentThread() -> libc::HANDLE;
-        fn RtlCaptureContext(ctx: *mut arch::CONTEXT);
-    }
-
-    type SymFromAddrFn =
-        extern "system" fn(libc::HANDLE, u64, *mut u64,
-                           *mut SYMBOL_INFO) -> libc::BOOL;
-    type SymInitializeFn =
-        extern "system" fn(libc::HANDLE, *mut libc::c_void,
-                           libc::BOOL) -> libc::BOOL;
-    type SymCleanupFn =
-        extern "system" fn(libc::HANDLE) -> libc::BOOL;
-
-    type StackWalk64Fn =
-        extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE,
-                           *mut STACKFRAME64, *mut arch::CONTEXT,
-                           *mut libc::c_void, *mut libc::c_void,
-                           *mut libc::c_void, *mut libc::c_void) -> libc::BOOL;
-
-    const MAX_SYM_NAME: uint = 2000;
-    const IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c;
-    const IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
-    const IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
-
-    #[repr(C)]
-    struct SYMBOL_INFO {
-        SizeOfStruct: libc::c_ulong,
-        TypeIndex: libc::c_ulong,
-        Reserved: [u64, ..2],
-        Index: libc::c_ulong,
-        Size: libc::c_ulong,
-        ModBase: u64,
-        Flags: libc::c_ulong,
-        Value: u64,
-        Address: u64,
-        Register: libc::c_ulong,
-        Scope: libc::c_ulong,
-        Tag: libc::c_ulong,
-        NameLen: libc::c_ulong,
-        MaxNameLen: libc::c_ulong,
-        // note that windows has this as 1, but it basically just means that
-        // the name is inline at the end of the struct. For us, we just bump
-        // the struct size up to MAX_SYM_NAME.
-        Name: [libc::c_char, ..MAX_SYM_NAME],
-    }
-
-
-    #[repr(C)]
-    enum ADDRESS_MODE {
-        AddrMode1616,
-        AddrMode1632,
-        AddrModeReal,
-        AddrModeFlat,
-    }
-
-    struct ADDRESS64 {
-        Offset: u64,
-        Segment: u16,
-        Mode: ADDRESS_MODE,
-    }
-
-    struct STACKFRAME64 {
-        AddrPC: ADDRESS64,
-        AddrReturn: ADDRESS64,
-        AddrFrame: ADDRESS64,
-        AddrStack: ADDRESS64,
-        AddrBStore: ADDRESS64,
-        FuncTableEntry: *mut libc::c_void,
-        Params: [u64, ..4],
-        Far: libc::BOOL,
-        Virtual: libc::BOOL,
-        Reserved: [u64, ..3],
-        KdHelp: KDHELP64,
-    }
-
-    struct KDHELP64 {
-        Thread: u64,
-        ThCallbackStack: libc::DWORD,
-        ThCallbackBStore: libc::DWORD,
-        NextCallback: libc::DWORD,
-        FramePointer: libc::DWORD,
-        KiCallUserMode: u64,
-        KeUserCallbackDispatcher: u64,
-        SystemRangeStart: u64,
-        KiUserExceptionDispatcher: u64,
-        StackBase: u64,
-        StackLimit: u64,
-        Reserved: [u64, ..5],
-    }
-
-    #[cfg(target_arch = "x86")]
-    mod arch {
-        use libc;
-
-        const MAXIMUM_SUPPORTED_EXTENSION: uint = 512;
-
-        #[repr(C)]
-        pub struct CONTEXT {
-            ContextFlags: libc::DWORD,
-            Dr0: libc::DWORD,
-            Dr1: libc::DWORD,
-            Dr2: libc::DWORD,
-            Dr3: libc::DWORD,
-            Dr6: libc::DWORD,
-            Dr7: libc::DWORD,
-            FloatSave: FLOATING_SAVE_AREA,
-            SegGs: libc::DWORD,
-            SegFs: libc::DWORD,
-            SegEs: libc::DWORD,
-            SegDs: libc::DWORD,
-            Edi: libc::DWORD,
-            Esi: libc::DWORD,
-            Ebx: libc::DWORD,
-            Edx: libc::DWORD,
-            Ecx: libc::DWORD,
-            Eax: libc::DWORD,
-            Ebp: libc::DWORD,
-            Eip: libc::DWORD,
-            SegCs: libc::DWORD,
-            EFlags: libc::DWORD,
-            Esp: libc::DWORD,
-            SegSs: libc::DWORD,
-            ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION],
-        }
-
-        #[repr(C)]
-        pub struct FLOATING_SAVE_AREA {
-            ControlWord: libc::DWORD,
-            StatusWord: libc::DWORD,
-            TagWord: libc::DWORD,
-            ErrorOffset: libc::DWORD,
-            ErrorSelector: libc::DWORD,
-            DataOffset: libc::DWORD,
-            DataSelector: libc::DWORD,
-            RegisterArea: [u8, ..80],
-            Cr0NpxState: libc::DWORD,
-        }
-
-        pub fn init_frame(frame: &mut super::STACKFRAME64,
-                          ctx: &CONTEXT) -> libc::DWORD {
-            frame.AddrPC.Offset = ctx.Eip as u64;
-            frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
-            frame.AddrStack.Offset = ctx.Esp as u64;
-            frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
-            frame.AddrFrame.Offset = ctx.Ebp as u64;
-            frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
-            super::IMAGE_FILE_MACHINE_I386
-        }
-    }
-
-    #[cfg(target_arch = "x86_64")]
-    mod arch {
-        use libc::{c_longlong, c_ulonglong};
-        use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG};
-        use simd;
-
-        #[repr(C)]
-        pub struct CONTEXT {
-            _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
-            P1Home: DWORDLONG,
-            P2Home: DWORDLONG,
-            P3Home: DWORDLONG,
-            P4Home: DWORDLONG,
-            P5Home: DWORDLONG,
-            P6Home: DWORDLONG,
-
-            ContextFlags: DWORD,
-            MxCsr: DWORD,
-
-            SegCs: WORD,
-            SegDs: WORD,
-            SegEs: WORD,
-            SegFs: WORD,
-            SegGs: WORD,
-            SegSs: WORD,
-            EFlags: DWORD,
-
-            Dr0: DWORDLONG,
-            Dr1: DWORDLONG,
-            Dr2: DWORDLONG,
-            Dr3: DWORDLONG,
-            Dr6: DWORDLONG,
-            Dr7: DWORDLONG,
-
-            Rax: DWORDLONG,
-            Rcx: DWORDLONG,
-            Rdx: DWORDLONG,
-            Rbx: DWORDLONG,
-            Rsp: DWORDLONG,
-            Rbp: DWORDLONG,
-            Rsi: DWORDLONG,
-            Rdi: DWORDLONG,
-            R8:  DWORDLONG,
-            R9:  DWORDLONG,
-            R10: DWORDLONG,
-            R11: DWORDLONG,
-            R12: DWORDLONG,
-            R13: DWORDLONG,
-            R14: DWORDLONG,
-            R15: DWORDLONG,
-
-            Rip: DWORDLONG,
-
-            FltSave: FLOATING_SAVE_AREA,
-
-            VectorRegister: [M128A, .. 26],
-            VectorControl: DWORDLONG,
-
-            DebugControl: DWORDLONG,
-            LastBranchToRip: DWORDLONG,
-            LastBranchFromRip: DWORDLONG,
-            LastExceptionToRip: DWORDLONG,
-            LastExceptionFromRip: DWORDLONG,
-        }
-
-        #[repr(C)]
-        pub struct M128A {
-            _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
-            Low:  c_ulonglong,
-            High: c_longlong
-        }
-
-        #[repr(C)]
-        pub struct FLOATING_SAVE_AREA {
-            _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
-            _Dummy: [u8, ..512] // FIXME: Fill this out
-        }
-
-        pub fn init_frame(frame: &mut super::STACKFRAME64,
-                          ctx: &CONTEXT) -> DWORD {
-            frame.AddrPC.Offset = ctx.Rip as u64;
-            frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
-            frame.AddrStack.Offset = ctx.Rsp as u64;
-            frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
-            frame.AddrFrame.Offset = ctx.Rbp as u64;
-            frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
-            super::IMAGE_FILE_MACHINE_AMD64
-        }
-    }
-
-    #[repr(C)]
-    struct Cleanup {
-        handle: libc::HANDLE,
-        SymCleanup: SymCleanupFn,
-    }
-
-    impl Drop for Cleanup {
-        fn drop(&mut self) { (self.SymCleanup)(self.handle); }
-    }
-
-    pub fn write(w: &mut Writer) -> IoResult<()> {
-        // According to windows documentation, all dbghelp functions are
-        // single-threaded.
-        static LOCK: StaticMutex = MUTEX_INIT;
-        let _g = LOCK.lock();
-
-        // Open up dbghelp.dll, we don't link to it explicitly because it can't
-        // always be found. Additionally, it's nice having fewer dependencies.
-        let path = Path::new("dbghelp.dll");
-        let lib = match DynamicLibrary::open(Some(&path)) {
-            Ok(lib) => lib,
-            Err(..) => return Ok(()),
-        };
-
-        macro_rules! sym { ($e:expr, $t:ident) => (unsafe {
-            match lib.symbol($e) {
-                Ok(f) => mem::transmute::<*mut u8, $t>(f),
-                Err(..) => return Ok(())
-            }
-        }) }
-
-        // Fetch the symbols necessary from dbghelp.dll
-        let SymFromAddr = sym!("SymFromAddr", SymFromAddrFn);
-        let SymInitialize = sym!("SymInitialize", SymInitializeFn);
-        let SymCleanup = sym!("SymCleanup", SymCleanupFn);
-        let StackWalk64 = sym!("StackWalk64", StackWalk64Fn);
-
-        // Allocate necessary structures for doing the stack walk
-        let process = unsafe { GetCurrentProcess() };
-        let thread = unsafe { GetCurrentThread() };
-        let mut context: arch::CONTEXT = unsafe { intrinsics::init() };
-        unsafe { RtlCaptureContext(&mut context); }
-        let mut frame: STACKFRAME64 = unsafe { intrinsics::init() };
-        let image = arch::init_frame(&mut frame, &context);
-
-        // Initialize this process's symbols
-        let ret = SymInitialize(process, 0 as *mut libc::c_void, libc::TRUE);
-        if ret != libc::TRUE { return Ok(()) }
-        let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
-
-        // And now that we're done with all the setup, do the stack walking!
-        let mut i = 0i;
-        try!(write!(w, "stack backtrace:\n"));
-        while StackWalk64(image, process, thread, &mut frame, &mut context,
-                          0 as *mut libc::c_void,
-                          0 as *mut libc::c_void,
-                          0 as *mut libc::c_void,
-                          0 as *mut libc::c_void) == libc::TRUE{
-            let addr = frame.AddrPC.Offset;
-            if addr == frame.AddrReturn.Offset || addr == 0 ||
-               frame.AddrReturn.Offset == 0 { break }
-
-            i += 1;
-            try!(write!(w, "  {:2}: {:#2$x}", i, addr, super::HEX_WIDTH));
-            let mut info: SYMBOL_INFO = unsafe { intrinsics::init() };
-            info.MaxNameLen = MAX_SYM_NAME as libc::c_ulong;
-            // the struct size in C.  the value is different to
-            // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
-            // due to struct alignment.
-            info.SizeOfStruct = 88;
-
-            let mut displacement = 0u64;
-            let ret = SymFromAddr(process, addr as u64, &mut displacement,
-                                  &mut info);
-
-            if ret == libc::TRUE {
-                try!(write!(w, " - "));
-                let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
-                let bytes = cstr.as_bytes();
-                match cstr.as_str() {
-                    Some(s) => try!(super::demangle(w, s)),
-                    None => try!(w.write(bytes[..bytes.len()-1])),
-                }
-                if displacement != 0 {
-                    try!(write!(w, "+{:#x}", displacement));
-                }
-            }
-            try!(w.write(&['\n' as u8]));
-        }
-
-        Ok(())
-    }
-}
-
 #[cfg(test)]
 mod test {
     use prelude::*;
-    use io::MemWriter;
-
+    use sys_common;
     macro_rules! t { ($a:expr, $b:expr) => ({
         let mut m = Vec::new();
-        super::demangle(&mut m, $a).unwrap();
+        sys_common::backtrace::demangle(&mut m, $a).unwrap();
         assert_eq!(String::from_utf8(m).unwrap(), $b);
     }) }
 
diff --git a/src/librustrt/bookkeeping.rs b/src/libstd/rt/bookkeeping.rs
index e918a496d55..aca520fc088 100644
--- a/src/librustrt/bookkeeping.rs
+++ b/src/libstd/rt/bookkeeping.rs
@@ -18,10 +18,10 @@
 //! each respective runtime to make sure that they call increment() and
 //! decrement() manually.
 
-use core::atomic;
-use core::ops::Drop;
+use sync::atomic;
+use ops::Drop;
 
-use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
 
 static TASK_COUNT: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
 static TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
diff --git a/src/librustrt/exclusive.rs b/src/libstd/rt/exclusive.rs
index 1d8ea2202bf..1d3082d1b4c 100644
--- a/src/librustrt/exclusive.rs
+++ b/src/libstd/rt/exclusive.rs
@@ -10,8 +10,8 @@
 
 use core::prelude::*;
 
-use core::cell::UnsafeCell;
-use mutex;
+use cell::UnsafeCell;
+use rt::mutex;
 
 /// An OS mutex over some data.
 ///
@@ -79,10 +79,10 @@ impl<'a, T: Send> DerefMut<T> for ExclusiveGuard<'a, T> {
 
 #[cfg(test)]
 mod tests {
-    use std::prelude::*;
-    use alloc::arc::Arc;
+    use prelude::*;
+    use sync::Arc;
     use super::Exclusive;
-    use std::task;
+    use task;
 
     #[test]
     fn exclusive_new_arc() {
diff --git a/src/librustrt/libunwind.rs b/src/libstd/rt/libunwind.rs
index 2feea7fa0a4..2feea7fa0a4 100644
--- a/src/librustrt/libunwind.rs
+++ b/src/libstd/rt/libunwind.rs
diff --git a/src/librustrt/local.rs b/src/libstd/rt/local.rs
index df733d7ee22..089960a6bc8 100644
--- a/src/librustrt/local.rs
+++ b/src/libstd/rt/local.rs
@@ -10,9 +10,9 @@
 
 use core::prelude::*;
 
-use alloc::boxed::Box;
-use local_ptr;
-use task::Task;
+use boxed::Box;
+use rt::local_ptr;
+use rt::task::Task;
 
 /// Encapsulates some task-local data.
 pub trait Local<Borrowed> {
@@ -52,10 +52,10 @@ impl Local<local_ptr::Borrowed<Task>> for Task {
 
 #[cfg(test)]
 mod test {
-    use std::prelude::*;
-    use thread::Thread;
+    use prelude::*;
     use super::*;
-    use task::Task;
+    use super::super::thread::Thread;
+    use super::super::task::Task;
 
     #[test]
     fn thread_local_task_smoke_test() {
diff --git a/src/librustrt/local_ptr.rs b/src/libstd/rt/local_ptr.rs
index 58f8f8b310f..a87bc3d2766 100644
--- a/src/librustrt/local_ptr.rs
+++ b/src/libstd/rt/local_ptr.rs
@@ -19,8 +19,8 @@
 
 use core::prelude::*;
 
-use core::mem;
-use alloc::boxed::Box;
+use mem;
+use boxed::Box;
 
 #[cfg(any(windows, // mingw-w32 doesn't like thread_local things
           target_os = "android", // see #10686
@@ -86,11 +86,11 @@ pub unsafe fn borrow<T>() -> Borrowed<T> {
 pub mod compiled {
     use core::prelude::*;
 
-    use alloc::boxed::Box;
-    use core::mem;
+    use boxed::Box;
+    use mem;
 
     #[cfg(test)]
-    pub use realrustrt::shouldnt_be_public::RT_TLS_PTR;
+    pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;
 
     #[cfg(not(test))]
     #[thread_local]
@@ -237,10 +237,10 @@ pub mod compiled {
 pub mod native {
     use core::prelude::*;
 
-    use alloc::boxed::Box;
-    use core::mem;
-    use core::ptr;
-    use thread_local_storage as tls;
+    use boxed::Box;
+    use mem;
+    use ptr;
+    use rt::thread_local_storage as tls;
 
     static mut RT_TLS_KEY: tls::Key = -1;
 
@@ -396,9 +396,9 @@ pub mod native {
 
     #[inline] #[cfg(test)]
     pub fn maybe_tls_key() -> Option<tls::Key> {
-        use realrustrt;
+        use rt;
         unsafe {
-            mem::transmute(realrustrt::shouldnt_be_public::maybe_tls_key())
+            mem::transmute(::realstd::rt::shouldnt_be_public::maybe_tls_key())
         }
     }
 }
diff --git a/src/librustrt/macros.rs b/src/libstd/rt/macros.rs
index 45144308535..bee8b5b82f4 100644
--- a/src/librustrt/macros.rs
+++ b/src/libstd/rt/macros.rs
@@ -17,7 +17,7 @@
 
 macro_rules! rterrln {
     ($fmt:expr $($arg:tt)*) => ( {
-        format_args!(::util::dumb_print, concat!($fmt, "\n") $($arg)*)
+        format_args!(::rt::util::dumb_print, concat!($fmt, "\n") $($arg)*)
     } )
 }
 
@@ -32,7 +32,7 @@ macro_rules! rtdebug {
 
 macro_rules! rtassert {
     ( $arg:expr ) => ( {
-        if ::util::ENFORCE_SANITY {
+        if ::rt::util::ENFORCE_SANITY {
             if !$arg {
                 rtabort!(" assertion failed: {}", stringify!($arg));
             }
@@ -40,7 +40,6 @@ macro_rules! rtassert {
     } )
 }
 
-
 macro_rules! rtabort {
-    ($($arg:tt)*) => (format_args!(::util::abort, $($arg)*))
+    ($($arg:tt)*) => (format_args!(::rt::util::abort, $($arg)*))
 }
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index eb517047ddc..21c8197ef05 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -50,23 +50,43 @@
 
 use borrow::IntoCow;
 use failure;
-use rustrt;
 use os;
 use thunk::Thunk;
+use kinds::Send;
+use sys_common;
 
 // Reexport some of our utilities which are expected by other crates.
 pub use self::util::{default_sched_threads, min_stack, running_on_valgrind};
+pub use self::unwind::{begin_unwind, begin_unwind_fmt};
 
-// Reexport functionality from librustrt and other crates underneath the
-// standard library which work together to create the entire runtime.
+// Reexport some functionality from liballoc.
 pub use alloc::heap;
-pub use rustrt::{begin_unwind, begin_unwind_fmt, at_exit};
 
 // Simple backtrace functionality (to print on panic)
 pub mod backtrace;
 
-// Just stuff
-mod util;
+// Internals
+mod macros;
+
+// These should be refactored/moved/made private over time
+pub mod mutex;
+pub mod thread;
+pub mod exclusive;
+pub mod util;
+pub mod bookkeeping;
+pub mod local;
+pub mod task;
+pub mod unwind;
+
+mod args;
+mod at_exit_imp;
+mod libunwind;
+mod local_ptr;
+mod thread_local_storage;
+
+/// The default error code of the rust runtime if the main task panics instead
+/// of exiting cleanly.
+pub const DEFAULT_ERROR_CODE: int = 101;
 
 /// One-time runtime initialization.
 ///
@@ -75,8 +95,15 @@ mod util;
 /// metadata, and storing the process arguments.
 #[allow(experimental)]
 pub fn init(argc: int, argv: *const *const u8) {
-    rustrt::init(argc, argv);
-    unsafe { rustrt::unwind::register(failure::on_fail); }
+    // FIXME: Derefing these pointers is not safe.
+    // Need to propagate the unsafety to `start`.
+    unsafe {
+        args::init(argc, argv);
+        local_ptr::init();
+        at_exit_imp::init();
+        thread::init();
+        unwind::register(failure::on_fail);
+    }
 }
 
 #[cfg(any(windows, android))]
@@ -106,7 +133,8 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
 pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
     use prelude::*;
     use rt;
-    use rustrt::task::Task;
+    use rt::task::Task;
+    use str;
 
     let something_around_the_top_of_the_stack = 1;
     let addr = &something_around_the_top_of_the_stack as *const int;
@@ -139,18 +167,35 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
     let mut exit_code = None;
     let mut main = Some(main);
     let mut task = box Task::new(Some((my_stack_bottom, my_stack_top)),
-                                 Some(rustrt::thread::main_guard_page()));
-    task.name = Some("<main>".into_cow());
+                                 Some(rt::thread::main_guard_page()));
+    task.name = Some(str::Slice("<main>"));
     drop(task.run(|| {
         unsafe {
-            rustrt::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
+            sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
         }
         (main.take().unwrap()).invoke(());
         exit_code = Some(os::get_exit_status());
     }).destroy());
-    unsafe { rt::cleanup(); }
+    unsafe { cleanup(); }
     // If the exit code wasn't set, then the task block must have panicked.
-    return exit_code.unwrap_or(rustrt::DEFAULT_ERROR_CODE);
+    return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);
+}
+
+/// Enqueues a procedure to run when the runtime is cleaned up
+///
+/// The procedure passed to this function will be executed as part of the
+/// runtime cleanup phase. For normal rust programs, this means that it will run
+/// after all other tasks have exited.
+///
+/// The procedure is *not* executed with a local `Task` available to it, so
+/// primitives like logging, I/O, channels, spawning, etc, are *not* available.
+/// This is meant for "bare bones" usage to clean up runtime details, this is
+/// not meant as a general-purpose "let's clean everything up" function.
+///
+/// It is forbidden for procedures to register more `at_exit` handlers when they
+/// are running, and doing so will lead to a process abort.
+pub fn at_exit(f: proc():Send) {
+    at_exit_imp::push(f);
 }
 
 /// One-time runtime cleanup.
@@ -163,5 +208,18 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
 /// Invoking cleanup while portions of the runtime are still in use may cause
 /// undefined behavior.
 pub unsafe fn cleanup() {
-    rustrt::cleanup();
+    bookkeeping::wait_for_other_tasks();
+    args::cleanup();
+    thread::cleanup();
+    local_ptr::cleanup();
+    at_exit_imp::run();
+}
+
+// FIXME: these probably shouldn't be public...
+#[doc(hidden)]
+pub mod shouldnt_be_public {
+    #[cfg(not(test))]
+    pub use super::local_ptr::native::maybe_tls_key;
+    #[cfg(all(not(windows), not(target_os = "android"), not(target_os = "ios")))]
+    pub use super::local_ptr::compiled::RT_TLS_PTR;
 }
diff --git a/src/librustrt/mutex.rs b/src/libstd/rt/mutex.rs
index cbfb86a6ac7..381f14570df 100644
--- a/src/librustrt/mutex.rs
+++ b/src/libstd/rt/mutex.rs
@@ -33,7 +33,7 @@
 //! # Example
 //!
 //! ```rust
-//! use rustrt::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT};
+//! use rt::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT};
 //!
 //! // Use a statically initialized mutex
 //! static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
@@ -60,6 +60,8 @@
 
 use core::prelude::*;
 
+use sys::mutex as imp;
+
 /// A native mutex suitable for storing in statics (that is, it has
 /// the `destroy` method rather than a destructor).
 ///
@@ -108,7 +110,7 @@ impl StaticNativeMutex {
     /// # Example
     ///
     /// ```rust
-    /// use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+    /// use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
     /// static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
     /// unsafe {
     ///     let _guard = LOCK.lock();
@@ -225,7 +227,7 @@ impl NativeMutex {
     /// # Example
     ///
     /// ```rust
-    /// use rustrt::mutex::NativeMutex;
+    /// use rt::mutex::NativeMutex;
     /// unsafe {
     ///     let mut lock = NativeMutex::new();
     ///
@@ -336,336 +338,13 @@ impl<'a> Drop for LockGuard<'a> {
     }
 }
 
-#[cfg(unix)]
-mod imp {
-    use libc;
-    use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,
-                   pthread_mutex_t, pthread_cond_t};
-    use core::cell::UnsafeCell;
-
-    type pthread_mutexattr_t = libc::c_void;
-    type pthread_condattr_t = libc::c_void;
-
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-    mod os {
-        use libc;
-
-        pub type pthread_mutex_t = *mut libc::c_void;
-        pub type pthread_cond_t = *mut libc::c_void;
-
-        pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t =
-            0 as pthread_mutex_t;
-        pub const PTHREAD_COND_INITIALIZER: pthread_cond_t =
-            0 as pthread_cond_t;
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
-    mod os {
-        use core::kinds::Copy;
-        use libc;
-
-        #[cfg(target_arch = "x86_64")]
-        const __PTHREAD_MUTEX_SIZE__: uint = 56;
-        #[cfg(target_arch = "x86_64")]
-        const __PTHREAD_COND_SIZE__: uint = 40;
-        #[cfg(target_arch = "x86")]
-        const __PTHREAD_MUTEX_SIZE__: uint = 40;
-        #[cfg(target_arch = "x86")]
-        const __PTHREAD_COND_SIZE__: uint = 24;
-        #[cfg(target_arch = "arm")]
-        const __PTHREAD_MUTEX_SIZE__: uint = 40;
-        #[cfg(target_arch = "arm")]
-        const __PTHREAD_COND_SIZE__: uint = 24;
-
-        const _PTHREAD_MUTEX_SIG_INIT: libc::c_long = 0x32AAABA7;
-        const _PTHREAD_COND_SIG_INIT: libc::c_long = 0x3CB0B1BB;
-
-        #[repr(C)]
-        pub struct pthread_mutex_t {
-            __sig: libc::c_long,
-            __opaque: [u8, ..__PTHREAD_MUTEX_SIZE__],
-        }
-
-        impl Copy for pthread_mutex_t {}
-
-        #[repr(C)]
-        pub struct pthread_cond_t {
-            __sig: libc::c_long,
-            __opaque: [u8, ..__PTHREAD_COND_SIZE__],
-        }
-
-        impl Copy for pthread_cond_t {}
-
-        pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
-            __sig: _PTHREAD_MUTEX_SIG_INIT,
-            __opaque: [0, ..__PTHREAD_MUTEX_SIZE__],
-        };
-        pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
-            __sig: _PTHREAD_COND_SIG_INIT,
-            __opaque: [0, ..__PTHREAD_COND_SIZE__],
-        };
-    }
-
-    #[cfg(target_os = "linux")]
-    mod os {
-        use core::kinds::Copy;
-        use libc;
-
-        // minus 8 because we have an 'align' field
-        #[cfg(target_arch = "x86_64")]
-        const __SIZEOF_PTHREAD_MUTEX_T: uint = 40 - 8;
-        #[cfg(target_arch = "x86")]
-        const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "arm")]
-        const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "mips")]
-        const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "mipsel")]
-        const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "x86_64")]
-        const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "x86")]
-        const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "arm")]
-        const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "mips")]
-        const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "mipsel")]
-        const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-
-        #[repr(C)]
-        pub struct pthread_mutex_t {
-            __align: libc::c_longlong,
-            size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T],
-        }
-
-        impl Copy for pthread_mutex_t {}
-
-        #[repr(C)]
-        pub struct pthread_cond_t {
-            __align: libc::c_longlong,
-            size: [u8, ..__SIZEOF_PTHREAD_COND_T],
-        }
-
-        impl Copy for pthread_cond_t {}
-
-        pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
-            __align: 0,
-            size: [0, ..__SIZEOF_PTHREAD_MUTEX_T],
-        };
-        pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
-            __align: 0,
-            size: [0, ..__SIZEOF_PTHREAD_COND_T],
-        };
-    }
-    #[cfg(target_os = "android")]
-    mod os {
-        use libc;
-
-        #[repr(C)]
-        pub struct pthread_mutex_t { value: libc::c_int }
-        #[repr(C)]
-        pub struct pthread_cond_t { value: libc::c_int }
-
-        pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
-            value: 0,
-        };
-        pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
-            value: 0,
-        };
-    }
-
-    pub struct Mutex {
-        lock: UnsafeCell<pthread_mutex_t>,
-        cond: UnsafeCell<pthread_cond_t>,
-    }
-
-    pub const MUTEX_INIT: Mutex = Mutex {
-        lock: UnsafeCell { value: PTHREAD_MUTEX_INITIALIZER },
-        cond: UnsafeCell { value: PTHREAD_COND_INITIALIZER },
-    };
-
-    impl Mutex {
-        pub unsafe fn new() -> Mutex {
-            // As mutex might be moved and address is changing it
-            // is better to avoid initialization of potentially
-            // opaque OS data before it landed
-            let m = Mutex {
-                lock: UnsafeCell::new(PTHREAD_MUTEX_INITIALIZER),
-                cond: UnsafeCell::new(PTHREAD_COND_INITIALIZER),
-            };
-
-            return m;
-        }
-
-        pub unsafe fn lock(&self) { pthread_mutex_lock(self.lock.get()); }
-        pub unsafe fn unlock(&self) { pthread_mutex_unlock(self.lock.get()); }
-        pub unsafe fn signal(&self) { pthread_cond_signal(self.cond.get()); }
-        pub unsafe fn wait(&self) {
-            pthread_cond_wait(self.cond.get(), self.lock.get());
-        }
-        pub unsafe fn trylock(&self) -> bool {
-            pthread_mutex_trylock(self.lock.get()) == 0
-        }
-        pub unsafe fn destroy(&self) {
-            pthread_mutex_destroy(self.lock.get());
-            pthread_cond_destroy(self.cond.get());
-        }
-    }
-
-    extern {
-        fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
-        fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;
-
-        fn pthread_cond_wait(cond: *mut pthread_cond_t,
-                             lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
-    }
-}
-
-#[cfg(windows)]
-mod imp {
-    use alloc::heap;
-    use core::atomic;
-    use core::ptr;
-    use core::ptr::RawPtr;
-    use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
-    use libc;
-
-    type LPCRITICAL_SECTION = *mut c_void;
-    const SPIN_COUNT: DWORD = 4000;
-    #[cfg(target_arch = "x86")]
-    const CRIT_SECTION_SIZE: uint = 24;
-    #[cfg(target_arch = "x86_64")]
-    const CRIT_SECTION_SIZE: uint = 40;
-
-    pub struct Mutex {
-        // pointers for the lock/cond handles, atomically updated
-        lock: atomic::AtomicUint,
-        cond: atomic::AtomicUint,
-    }
-
-    pub const MUTEX_INIT: Mutex = Mutex {
-        lock: atomic::INIT_ATOMIC_UINT,
-        cond: atomic::INIT_ATOMIC_UINT,
-    };
-
-    impl Mutex {
-        pub unsafe fn new() -> Mutex {
-            Mutex {
-                lock: atomic::AtomicUint::new(init_lock()),
-                cond: atomic::AtomicUint::new(init_cond()),
-            }
-        }
-        pub unsafe fn lock(&self) {
-            EnterCriticalSection(self.getlock() as LPCRITICAL_SECTION)
-        }
-        pub unsafe fn trylock(&self) -> bool {
-            TryEnterCriticalSection(self.getlock() as LPCRITICAL_SECTION) != 0
-        }
-        pub unsafe fn unlock(&self) {
-            LeaveCriticalSection(self.getlock() as LPCRITICAL_SECTION)
-        }
-
-        pub unsafe fn wait(&self) {
-            self.unlock();
-            WaitForSingleObject(self.getcond() as HANDLE, libc::INFINITE);
-            self.lock();
-        }
-
-        pub unsafe fn signal(&self) {
-            assert!(SetEvent(self.getcond() as HANDLE) != 0);
-        }
-
-        /// This function is especially unsafe because there are no guarantees made
-        /// that no other thread is currently holding the lock or waiting on the
-        /// condition variable contained inside.
-        pub unsafe fn destroy(&self) {
-            let lock = self.lock.swap(0, atomic::SeqCst);
-            let cond = self.cond.swap(0, atomic::SeqCst);
-            if lock != 0 { free_lock(lock) }
-            if cond != 0 { free_cond(cond) }
-        }
-
-        unsafe fn getlock(&self) -> *mut c_void {
-            match self.lock.load(atomic::SeqCst) {
-                0 => {}
-                n => return n as *mut c_void
-            }
-            let lock = init_lock();
-            match self.lock.compare_and_swap(0, lock, atomic::SeqCst) {
-                0 => return lock as *mut c_void,
-                _ => {}
-            }
-            free_lock(lock);
-            return self.lock.load(atomic::SeqCst) as *mut c_void;
-        }
-
-        unsafe fn getcond(&self) -> *mut c_void {
-            match self.cond.load(atomic::SeqCst) {
-                0 => {}
-                n => return n as *mut c_void
-            }
-            let cond = init_cond();
-            match self.cond.compare_and_swap(0, cond, atomic::SeqCst) {
-                0 => return cond as *mut c_void,
-                _ => {}
-            }
-            free_cond(cond);
-            return self.cond.load(atomic::SeqCst) as *mut c_void;
-        }
-    }
-
-    pub unsafe fn init_lock() -> uint {
-        let block = heap::allocate(CRIT_SECTION_SIZE, 8) as *mut c_void;
-        if block.is_null() { ::alloc::oom() }
-        InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
-        return block as uint;
-    }
-
-    pub unsafe fn init_cond() -> uint {
-        return CreateEventA(ptr::null_mut(), libc::FALSE, libc::FALSE,
-                            ptr::null()) as uint;
-    }
-
-    pub unsafe fn free_lock(h: uint) {
-        DeleteCriticalSection(h as LPCRITICAL_SECTION);
-        heap::deallocate(h as *mut u8, CRIT_SECTION_SIZE, 8);
-    }
-
-    pub unsafe fn free_cond(h: uint) {
-        let block = h as HANDLE;
-        libc::CloseHandle(block);
-    }
-
-    #[allow(non_snake_case)]
-    extern "system" {
-        fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
-                        bManualReset: BOOL,
-                        bInitialState: BOOL,
-                        lpName: LPCSTR) -> HANDLE;
-        fn InitializeCriticalSectionAndSpinCount(
-                        lpCriticalSection: LPCRITICAL_SECTION,
-                        dwSpinCount: DWORD) -> BOOL;
-        fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-        fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-        fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-        fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
-        fn SetEvent(hEvent: HANDLE) -> BOOL;
-        fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
-    }
-}
-
 #[cfg(test)]
 mod test {
-    use std::prelude::*;
+    use prelude::*;
 
-    use std::mem::drop;
+    use mem::drop;
     use super::{StaticNativeMutex, NATIVE_MUTEX_INIT};
-    use thread::Thread;
+    use rt::thread::Thread;
 
     #[test]
     fn smoke_lock() {
diff --git a/src/librustrt/task.rs b/src/libstd/rt/task.rs
index b942a3819cc..babd111b3c2 100644
--- a/src/librustrt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -15,27 +15,28 @@
 pub use self::BlockedTask::*;
 use self::TaskState::*;
 
-use alloc::arc::Arc;
-use alloc::boxed::Box;
-use core::any::Any;
-use core::atomic::{AtomicUint, SeqCst};
-use core::iter::{IteratorExt, Take};
-use core::ops::FnOnce;
-use core::mem;
-use core::ops::FnMut;
+use any::Any;
+use boxed::Box;
+use sync::Arc;
+use sync::atomic::{AtomicUint, SeqCst};
+use iter::{IteratorExt, Take};
+use kinds::marker;
+use mem;
+use ops::FnMut;
 use core::prelude::{Clone, Drop, Err, Iterator, None, Ok, Option, Send, Some};
 use core::prelude::{drop};
-
-use bookkeeping;
-use mutex::NativeMutex;
-use local::Local;
-use thread::{mod, Thread};
-use stack;
-use unwind;
-use unwind::Unwinder;
-use collections::str::SendStr;
+use str::SendStr;
 use thunk::Thunk;
 
+use rt;
+use rt::bookkeeping;
+use rt::mutex::NativeMutex;
+use rt::local::Local;
+use rt::thread::{mod, Thread};
+use sys_common::stack;
+use rt::unwind;
+use rt::unwind::Unwinder;
+
 /// State associated with Rust tasks.
 ///
 /// This structure is currently undergoing major changes, and is
@@ -129,9 +130,7 @@ impl Task {
         task.name = name;
         task.death.on_exit = on_exit;
 
-        // FIXME: change this back after moving rustrt into std
-        // let stack = stack_size.unwrap_or(rt::min_stack());
-        let stack = stack_size.unwrap_or(2 * 1024 * 1024);
+        let stack = stack_size.unwrap_or(rt::min_stack());
 
         // Note that this increment must happen *before* the spawn in order to
         // guarantee that if this task exits it will always end up waiting for
@@ -504,8 +503,9 @@ impl Death {
 #[cfg(test)]
 mod test {
     use super::*;
-    use std::prelude::*;
-    use std::task;
+    use prelude::*;
+    use task;
+    use rt::unwind;
 
     #[test]
     fn unwind() {
@@ -519,7 +519,7 @@ mod test {
 
     #[test]
     fn rng() {
-        use std::rand::{StdRng, Rng};
+        use rand::{StdRng, Rng};
         let mut r = StdRng::new().ok().unwrap();
         let _ = r.next_u32();
     }
@@ -541,7 +541,7 @@ mod test {
     #[test]
     #[should_fail]
     fn test_begin_unwind() {
-        use unwind::begin_unwind;
+        use rt::unwind::begin_unwind;
         begin_unwind("cause", &(file!(), line!()))
     }
 
diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs
new file mode 100644
index 00000000000..c10338b1bce
--- /dev/null
+++ b/src/libstd/rt/thread.rs
@@ -0,0 +1,171 @@
+// Copyright 2013-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.
+
+//! Native os-thread management
+//!
+//! This modules contains bindings necessary for managing OS-level threads.
+//! These functions operate outside of the rust runtime, creating threads
+//! which are not used for scheduling in any way.
+
+#![allow(non_camel_case_types)]
+
+use core::prelude::*;
+
+use boxed::Box;
+use mem;
+use sys::stack_overflow;
+use sys::thread as imp;
+
+pub unsafe fn init() {
+    imp::guard::init();
+    stack_overflow::init();
+}
+
+pub unsafe fn cleanup() {
+    stack_overflow::cleanup();
+}
+
+/// This struct represents a native thread's state. This is used to join on an
+/// existing thread created in the join-able state.
+pub struct Thread<T> {
+    native: imp::rust_thread,
+    joined: bool,
+    packet: Box<Option<T>>,
+}
+
+static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
+
+/// Returns the last writable byte of the main thread's stack next to the guard
+/// page. Must be called from the main thread.
+pub fn main_guard_page() -> uint {
+    unsafe {
+        imp::guard::main()
+    }
+}
+
+/// Returns the last writable byte of the current thread's stack next to the
+/// guard page. Must not be called from the main thread.
+pub fn current_guard_page() -> uint {
+    unsafe {
+        imp::guard::current()
+    }
+}
+
+// There are two impl blocks b/c if T were specified at the top then it's just a
+// pain to specify a type parameter on Thread::spawn (which doesn't need the
+// type parameter).
+impl Thread<()> {
+
+    /// Starts execution of a new OS thread.
+    ///
+    /// This function will not wait for the thread to join, but a handle to the
+    /// thread will be returned.
+    ///
+    /// Note that the handle returned is used to acquire the return value of the
+    /// procedure `main`. The `join` function will wait for the thread to finish
+    /// and return the value that `main` generated.
+    ///
+    /// Also note that the `Thread` returned will *always* wait for the thread
+    /// to finish executing. This means that even if `join` is not explicitly
+    /// called, when the `Thread` falls out of scope its destructor will block
+    /// waiting for the OS thread.
+    pub fn start<T: Send>(main: proc():Send -> T) -> Thread<T> {
+        Thread::start_stack(DEFAULT_STACK_SIZE, main)
+    }
+
+    /// Performs the same functionality as `start`, but specifies an explicit
+    /// stack size for the new thread.
+    pub fn start_stack<T: Send>(stack: uint, main: proc():Send -> T) -> Thread<T> {
+
+        // We need the address of the packet to fill in to be stable so when
+        // `main` fills it in it's still valid, so allocate an extra box to do
+        // so.
+        let packet = box None;
+        let packet2: *mut Option<T> = unsafe {
+            *mem::transmute::<&Box<Option<T>>, *const *mut Option<T>>(&packet)
+        };
+        let main = proc() unsafe { *packet2 = Some(main()); };
+        let native = unsafe { imp::create(stack, box main) };
+
+        Thread {
+            native: native,
+            joined: false,
+            packet: packet,
+        }
+    }
+
+    /// This will spawn a new thread, but it will not wait for the thread to
+    /// finish, nor is it possible to wait for the thread to finish.
+    ///
+    /// This corresponds to creating threads in the 'detached' state on unix
+    /// systems. Note that platforms may not keep the main program alive even if
+    /// there are detached thread still running around.
+    pub fn spawn(main: proc():Send) {
+        Thread::spawn_stack(DEFAULT_STACK_SIZE, main)
+    }
+
+    /// Performs the same functionality as `spawn`, but explicitly specifies a
+    /// stack size for the new thread.
+    pub fn spawn_stack(stack: uint, main: proc():Send) {
+        unsafe {
+            let handle = imp::create(stack, box main);
+            imp::detach(handle);
+        }
+    }
+
+    /// Relinquishes the CPU slot that this OS-thread is currently using,
+    /// allowing another thread to run for awhile.
+    pub fn yield_now() {
+        unsafe { imp::yield_now(); }
+    }
+}
+
+impl<T: Send> Thread<T> {
+    /// Wait for this thread to finish, returning the result of the thread's
+    /// calculation.
+    pub fn join(mut self) -> T {
+        assert!(!self.joined);
+        unsafe { imp::join(self.native) };
+        self.joined = true;
+        assert!(self.packet.is_some());
+        self.packet.take().unwrap()
+    }
+}
+
+#[unsafe_destructor]
+impl<T: Send> Drop for Thread<T> {
+    fn drop(&mut self) {
+        // This is required for correctness. If this is not done then the thread
+        // would fill in a return box which no longer exists.
+        if !self.joined {
+            unsafe { imp::join(self.native) };
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::Thread;
+
+    #[test]
+    fn smoke() { Thread::start(proc (){}).join(); }
+
+    #[test]
+    fn data() { assert_eq!(Thread::start(proc () { 1i }).join(), 1); }
+
+    #[test]
+    fn detached() { Thread::spawn(proc () {}) }
+
+    #[test]
+    fn small_stacks() {
+        assert_eq!(42i, Thread::start_stack(0, proc () 42i).join());
+        assert_eq!(42i, Thread::start_stack(1, proc () 42i).join());
+    }
+}
diff --git a/src/librustrt/thread_local_storage.rs b/src/libstd/rt/thread_local_storage.rs
index aee70980bba..ee6ad8a4e08 100644
--- a/src/librustrt/thread_local_storage.rs
+++ b/src/libstd/rt/thread_local_storage.rs
@@ -11,7 +11,7 @@
 #![allow(dead_code)]
 
 #[cfg(unix)] use libc::c_int;
-#[cfg(unix)] use core::ptr::null;
+#[cfg(unix)] use ptr::null;
 #[cfg(windows)] use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
 
 #[cfg(unix)]
@@ -93,12 +93,12 @@ extern "system" {
 
 #[cfg(test)]
 mod test {
-    use std::prelude::*;
+    use prelude::*;
     use super::*;
 
     #[test]
     fn tls_smoke_test() {
-        use std::mem::transmute;
+        use mem::transmute;
         unsafe {
             let mut key = 0;
             let value = box 20i;
diff --git a/src/librustrt/unwind.rs b/src/libstd/rt/unwind.rs
index 5bc542a84e6..1ac06270851 100644
--- a/src/librustrt/unwind.rs
+++ b/src/libstd/rt/unwind.rs
@@ -59,23 +59,23 @@
 
 use core::prelude::*;
 
-use alloc::boxed::Box;
-use collections::string::String;
-use collections::str::StrAllocating;
-use collections::vec::Vec;
-use core::any::Any;
-use core::atomic;
-use core::cmp;
-use core::fmt;
-use core::intrinsics;
-use core::mem;
-use core::raw::Closure;
+use boxed::Box;
+use string::String;
+use str::StrAllocating;
+use vec::Vec;
+use any::Any;
+use sync::atomic;
+use cmp;
+use fmt;
+use intrinsics;
+use mem;
+use raw::Closure;
 use libc::c_void;
 
-use local::Local;
-use task::Task;
+use rt::local::Local;
+use rt::task::Task;
 
-use libunwind as uw;
+use rt::libunwind as uw;
 
 #[allow(missing_copy_implementations)]
 pub struct Unwinder {
@@ -241,7 +241,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
           not(test)))]
 #[doc(hidden)]
 pub mod eabi {
-    use libunwind as uw;
+    use rt::libunwind as uw;
     use libc::c_int;
 
     extern "C" {
@@ -294,7 +294,7 @@ pub mod eabi {
 #[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
 #[doc(hidden)]
 pub mod eabi {
-    use libunwind as uw;
+    use rt::libunwind as uw;
     use libc::c_int;
 
     extern "C" {
@@ -349,7 +349,7 @@ pub mod eabi {
 #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
 #[doc(hidden)]
 pub mod eabi {
-    use libunwind as uw;
+    use rt::libunwind as uw;
     use libc::c_int;
 
     extern "C" {
@@ -400,8 +400,7 @@ pub mod eabi {
 #[allow(non_camel_case_types, non_snake_case)]
 pub mod eabi {
     pub use self::EXCEPTION_DISPOSITION::*;
-    use core::prelude::*;
-    use libunwind as uw;
+    use rt::libunwind as uw;
     use libc::{c_void, c_int};
 
     #[repr(C)]
@@ -513,7 +512,7 @@ pub extern fn rust_begin_unwind(msg: &fmt::Arguments,
 /// the actual formatting into this shared place.
 #[inline(never)] #[cold]
 pub fn begin_unwind_fmt(msg: &fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
-    use core::fmt::FormatWriter;
+    use fmt::FormatWriter;
 
     // We do two allocations here, unfortunately. But (a) they're
     // required with the current scheme, and (b) we don't handle
diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs
index ce359c7b0e0..d3cfccab9d0 100644
--- a/src/libstd/rt/util.rs
+++ b/src/libstd/rt/util.rs
@@ -7,10 +7,18 @@
 // <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.
+//
+// ignore-lexer-test FIXME #15677
+
+use core::prelude::*;
 
-use libc::uintptr_t;
-use option::Option;
-use option::Option::{Some, None};
+use core::cmp;
+use core::fmt;
+use core::intrinsics;
+use core::slice;
+use core::str;
+
+use libc::{mod, uintptr_t};
 use os;
 use str::{FromStr, from_str, Str};
 use sync::atomic;
@@ -73,3 +81,136 @@ pub fn default_sched_threads() -> uint {
         }
     }
 }
+
+// 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 struct Stdio(libc::c_int);
+
+#[allow(non_upper_case_globals)]
+pub const Stdout: Stdio = Stdio(libc::STDOUT_FILENO);
+#[allow(non_upper_case_globals)]
+pub const Stderr: Stdio = Stdio(libc::STDERR_FILENO);
+
+impl fmt::FormatWriter for Stdio {
+    fn write(&mut self, data: &[u8]) -> fmt::Result {
+        #[cfg(unix)]
+        type WriteLen = libc::size_t;
+        #[cfg(windows)]
+        type WriteLen = libc::c_uint;
+        unsafe {
+            let Stdio(fd) = *self;
+            libc::write(fd,
+                        data.as_ptr() as *const libc::c_void,
+                        data.len() as WriteLen);
+        }
+        Ok(()) // yes, we're lying
+    }
+}
+
+pub fn dumb_print(args: &fmt::Arguments) {
+    use fmt::FormatWriter;
+    let mut w = Stderr;
+    let _ = w.write_fmt(args);
+}
+
+pub fn abort(args: &fmt::Arguments) -> ! {
+    use fmt::FormatWriter;
+
+    struct BufWriter<'a> {
+        buf: &'a mut [u8],
+        pos: uint,
+    }
+    impl<'a> FormatWriter for BufWriter<'a> {
+        fn write(&mut self, bytes: &[u8]) -> fmt::Result {
+            let left = self.buf[mut self.pos..];
+            let to_write = bytes[..cmp::min(bytes.len(), left.len())];
+            slice::bytes::copy_memory(left, to_write);
+            self.pos += to_write.len();
+            Ok(())
+        }
+    }
+
+    // Convert the arguments into a stack-allocated string
+    let mut msg = [0u8, ..512];
+    let mut w = BufWriter { buf: &mut msg, pos: 0 };
+    let _ = write!(&mut w, "{}", args);
+    let msg = str::from_utf8(w.buf[mut ..w.pos]).unwrap_or("aborted");
+    let msg = if msg.is_empty() {"aborted"} else {msg};
+
+    // Give some context to the message
+    let hash = msg.bytes().fold(0, |accum, val| accum + (val as uint) );
+    let quote = match hash % 10 {
+        0 => "
+It was from the artists and poets that the pertinent answers came, and I
+know that panic would have broken loose had they been able to compare notes.
+As it was, lacking their original letters, I half suspected the compiler of
+having asked leading questions, or of having edited the correspondence in
+corroboration of what he had latently resolved to see.",
+        1 => "
+There are not many persons who know what wonders are opened to them in the
+stories and visions of their youth; for when as children we listen and dream,
+we think but half-formed thoughts, and when as men we try to remember, we are
+dulled and prosaic with the poison of life. But some of us awake in the night
+with strange phantasms of enchanted hills and gardens, of fountains that sing
+in the sun, of golden cliffs overhanging murmuring seas, of plains that stretch
+down to sleeping cities of bronze and stone, and of shadowy companies of heroes
+that ride caparisoned white horses along the edges of thick forests; and then
+we know that we have looked back through the ivory gates into that world of
+wonder which was ours before we were wise and unhappy.",
+        2 => "
+Instead of the poems I had hoped for, there came only a shuddering blackness
+and ineffable loneliness; and I saw at last a fearful truth which no one had
+ever dared to breathe before — the unwhisperable secret of secrets — The fact
+that this city of stone and stridor is not a sentient perpetuation of Old New
+York as London is of Old London and Paris of Old Paris, but that it is in fact
+quite dead, its sprawling body imperfectly embalmed and infested with queer
+animate things which have nothing to do with it as it was in life.",
+        3 => "
+The ocean ate the last of the land and poured into the smoking gulf, thereby
+giving up all it had ever conquered. From the new-flooded lands it flowed
+again, uncovering death and decay; and from its ancient and immemorial bed it
+trickled loathsomely, uncovering nighted secrets of the years when Time was
+young and the gods unborn. Above the waves rose weedy remembered spires. The
+moon laid pale lilies of light on dead London, and Paris stood up from its damp
+grave to be sanctified with star-dust. Then rose spires and monoliths that were
+weedy but not remembered; terrible spires and monoliths of lands that men never
+knew were lands...",
+        4 => "
+There was a night when winds from unknown spaces whirled us irresistibly into
+limitless vacuum beyond all thought and entity. Perceptions of the most
+maddeningly untransmissible sort thronged upon us; perceptions of infinity
+which at the time convulsed us with joy, yet which are now partly lost to my
+memory and partly incapable of presentation to others.",
+        _ => "You've met with a terrible fate, haven't you?"
+    };
+    rterrln!("{}", "");
+    rterrln!("{}", quote);
+    rterrln!("{}", "");
+    rterrln!("fatal runtime error: {}", msg);
+    unsafe { intrinsics::abort(); }
+}
+
+pub unsafe fn report_overflow() {
+    use rt::task::Task;
+    use rt::local::Local;
+
+    // See the message below for why this is not emitted to the
+    // ^ Where did the message below go?
+    // task's logger. This has the additional conundrum of the
+    // logger may not be initialized just yet, meaning that an FFI
+    // call would happen to initialized it (calling out to libuv),
+    // and the FFI call needs 2MB of stack when we just ran out.
+
+    let task: Option<*mut Task> = Local::try_unsafe_borrow();
+
+    let name = task.and_then(|task| {
+        (*task).name.as_ref().map(|n| n.as_slice())
+    });
+
+    rterrln!("\ntask '{}' has overflowed its stack", name.unwrap_or("<unknown>"));
+}
diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs
index 35a87137115..862808a9e3d 100644
--- a/src/libstd/rtdeps.rs
+++ b/src/libstd/rtdeps.rs
@@ -22,7 +22,7 @@ extern {}
 // LLVM implements the `frem` instruction as a call to `fmod`, which lives in
 // libm. Hence, we must explicitly link to it.
 //
-// On Linux, librt and libdl are indirect dependencies via rustrt,
+// On Linux, librt and libdl are indirect dependencies via std,
 // and binutils 2.22+ won't add them automatically
 #[cfg(target_os = "linux")]
 #[link(name = "dl")]
diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs
new file mode 100644
index 00000000000..0c03060b314
--- /dev/null
+++ b/src/libstd/sys/common/backtrace.rs
@@ -0,0 +1,131 @@
+// 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.
+
+use io::{IoResult, Writer};
+use iter::Iterator;
+use option::{Some, None};
+use result::{Ok, Err};
+use str::{StrPrelude, from_str};
+use unicode::char::UnicodeChar;
+
+#[cfg(target_word_size = "64")] pub const HEX_WIDTH: uint = 18;
+#[cfg(target_word_size = "32")] pub const HEX_WIDTH: uint = 10;
+
+// All rust symbols are in theory lists of "::"-separated identifiers. Some
+// assemblers, however, can't handle these characters in symbol names. To get
+// around this, we use C++-style mangling. The mangling method is:
+//
+// 1. Prefix the symbol with "_ZN"
+// 2. For each element of the path, emit the length plus the element
+// 3. End the path with "E"
+//
+// For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar".
+//
+// We're the ones printing our backtraces, so we can't rely on anything else to
+// demangle our symbols. It's *much* nicer to look at demangled symbols, so
+// this function is implemented to give us nice pretty output.
+//
+// Note that this demangler isn't quite as fancy as it could be. We have lots
+// of other information in our symbols like hashes, version, type information,
+// etc. Additionally, this doesn't handle glue symbols at all.
+pub fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
+    // First validate the symbol. If it doesn't look like anything we're
+    // expecting, we just print it literally. Note that we must handle non-rust
+    // symbols because we could have any function in the backtrace.
+    let mut valid = true;
+    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
+        let mut chars = s.slice(3, s.len() - 1).chars();
+        while valid {
+            let mut i = 0;
+            for c in chars {
+                if c.is_numeric() {
+                    i = i * 10 + c as uint - '0' as uint;
+                } else {
+                    break
+                }
+            }
+            if i == 0 {
+                valid = chars.next().is_none();
+                break
+            } else if chars.by_ref().take(i - 1).count() != i - 1 {
+                valid = false;
+            }
+        }
+    } else {
+        valid = false;
+    }
+
+    // Alright, let's do this.
+    if !valid {
+        try!(writer.write_str(s));
+    } else {
+        let mut s = s.slice_from(3);
+        let mut first = true;
+        while s.len() > 1 {
+            if !first {
+                try!(writer.write_str("::"));
+            } else {
+                first = false;
+            }
+            let mut rest = s;
+            while rest.char_at(0).is_numeric() {
+                rest = rest.slice_from(1);
+            }
+            let i: uint = from_str(s.slice_to(s.len() - rest.len())).unwrap();
+            s = rest.slice_from(i);
+            rest = rest.slice_to(i);
+            while rest.len() > 0 {
+                if rest.starts_with("$") {
+                    macro_rules! demangle(
+                        ($($pat:expr => $demangled:expr),*) => ({
+                            $(if rest.starts_with($pat) {
+                                try!(writer.write_str($demangled));
+                                rest = rest.slice_from($pat.len());
+                              } else)*
+                            {
+                                try!(writer.write_str(rest));
+                                break;
+                            }
+
+                        })
+                    )
+                    // see src/librustc/back/link.rs for these mappings
+                    demangle! (
+                        "$SP$" => "@",
+                        "$UP$" => "Box",
+                        "$RP$" => "*",
+                        "$BP$" => "&",
+                        "$LT$" => "<",
+                        "$GT$" => ">",
+                        "$LP$" => "(",
+                        "$RP$" => ")",
+                        "$C$"  => ",",
+
+                        // in theory we can demangle any Unicode code point, but
+                        // for simplicity we just catch the common ones.
+                        "$x20" => " ",
+                        "$x27" => "'",
+                        "$x5b" => "[",
+                        "$x5d" => "]"
+                    )
+                } else {
+                    let idx = match rest.find('$') {
+                        None => rest.len(),
+                        Some(i) => i,
+                    };
+                    try!(writer.write_str(rest.slice_to(idx)));
+                    rest = rest.slice_from(idx);
+                }
+            }
+        }
+    }
+
+    Ok(())
+}
diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs
index 96b4accd4bd..ffb053e852e 100644
--- a/src/libstd/sys/common/helper_thread.rs
+++ b/src/libstd/sys/common/helper_thread.rs
@@ -24,9 +24,8 @@ use prelude::*;
 
 use cell::UnsafeCell;
 use mem;
-use rustrt::bookkeeping;
-use rustrt;
 use sync::{StaticMutex, StaticCondvar};
+use rt::{mod, bookkeeping};
 use sys::helper_signal;
 
 use task;
@@ -91,7 +90,7 @@ impl<M: Send> Helper<M> {
                     self.cond.notify_one()
                 });
 
-                rustrt::at_exit(move|:| { self.shutdown() });
+                rt::at_exit(move|:| { self.shutdown() });
                 *self.initialized.get() = true;
             }
         }
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs
index 73e1c7bd9e5..aeee4cf01cd 100644
--- a/src/libstd/sys/common/mod.rs
+++ b/src/libstd/sys/common/mod.rs
@@ -19,11 +19,14 @@ use num::Int;
 use path::BytesContainer;
 use collections;
 
+pub mod backtrace;
 pub mod condvar;
 pub mod helper_thread;
 pub mod mutex;
 pub mod net;
 pub mod rwlock;
+pub mod stack;
+pub mod thread;
 pub mod thread_local;
 
 // common error constructors
diff --git a/src/librustrt/stack.rs b/src/libstd/sys/common/stack.rs
index 4874f642a93..2a88e20c8fa 100644
--- a/src/librustrt/stack.rs
+++ b/src/libstd/sys/common/stack.rs
@@ -55,7 +55,7 @@ pub const RED_ZONE: uint = 20 * 1024;
 #[cfg(not(test))] // in testing, use the original libstd's version
 #[lang = "stack_exhausted"]
 extern fn stack_exhausted() {
-    use core::intrinsics;
+    use intrinsics;
 
     unsafe {
         // We're calling this function because the stack just ran out. We need
@@ -100,7 +100,7 @@ extern fn stack_exhausted() {
         //  #9854 - unwinding on windows through __morestack has never worked
         //  #2361 - possible implementation of not using landing pads
 
-        ::stack_overflow::report();
+        ::rt::util::report_overflow();
 
         intrinsics::abort();
     }
diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs
new file mode 100644
index 00000000000..5e1adfb8714
--- /dev/null
+++ b/src/libstd/sys/common/thread.rs
@@ -0,0 +1,34 @@
+// 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.
+
+use core::prelude::*;
+
+use boxed::Box;
+use mem;
+use uint;
+use libc;
+use sys_common::stack;
+use sys::{thread, stack_overflow};
+
+// This is the starting point of rust os threads. The first thing we do
+// is make sure that we don't trigger __morestack (also why this has a
+// no_stack_check annotation), and then we extract the main function
+// and invoke it.
+#[no_stack_check]
+pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return {
+    unsafe {
+        stack::record_os_managed_stack_bounds(0, uint::MAX);
+        let handler = stack_overflow::Handler::new();
+        let f: Box<proc()> = mem::transmute(main);
+        (*f)();
+        drop(handler);
+        mem::transmute(0 as thread::rust_thread_return)
+    }
+}
diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs
index cf56a71d67a..a8bc6bf9d0d 100644
--- a/src/libstd/sys/common/thread_local.rs
+++ b/src/libstd/sys/common/thread_local.rs
@@ -58,7 +58,8 @@
 
 use prelude::*;
 
-use rustrt::exclusive::Exclusive;
+use rt::exclusive::Exclusive;
+use rt;
 use sync::atomic::{mod, AtomicUint};
 use sync::{Once, ONCE_INIT};
 
@@ -283,4 +284,3 @@ mod tests {
         }
     }
 }
-
diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs
new file mode 100644
index 00000000000..c139dba2c46
--- /dev/null
+++ b/src/libstd/sys/unix/backtrace.rs
@@ -0,0 +1,493 @@
+// 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.
+
+/// Backtrace support built on libgcc with some extra OS-specific support
+///
+/// Some methods of getting a backtrace:
+///
+/// * The backtrace() functions on unix. It turns out this doesn't work very
+///   well for green threads on OSX, and the address to symbol portion of it
+///   suffers problems that are described below.
+///
+/// * Using libunwind. This is more difficult than it sounds because libunwind
+///   isn't installed everywhere by default. It's also a bit of a hefty library,
+///   so possibly not the best option. When testing, libunwind was excellent at
+///   getting both accurate backtraces and accurate symbols across platforms.
+///   This route was not chosen in favor of the next option, however.
+///
+/// * We're already using libgcc_s for exceptions in rust (triggering task
+///   unwinding and running destructors on the stack), and it turns out that it
+///   conveniently comes with a function that also gives us a backtrace. All of
+///   these functions look like _Unwind_*, but it's not quite the full
+///   repertoire of the libunwind API. Due to it already being in use, this was
+///   the chosen route of getting a backtrace.
+///
+/// After choosing libgcc_s for backtraces, the sad part is that it will only
+/// give us a stack trace of instruction pointers. Thankfully these instruction
+/// pointers are accurate (they work for green and native threads), but it's
+/// then up to us again to figure out how to translate these addresses to
+/// symbols. As with before, we have a few options. Before, that, a little bit
+/// of an interlude about symbols. This is my very limited knowledge about
+/// symbol tables, and this information is likely slightly wrong, but the
+/// general idea should be correct.
+///
+/// When talking about symbols, it's helpful to know a few things about where
+/// symbols are located. Some symbols are located in the dynamic symbol table
+/// of the executable which in theory means that they're available for dynamic
+/// linking and lookup. Other symbols end up only in the local symbol table of
+/// the file. This loosely corresponds to pub and priv functions in Rust.
+///
+/// Armed with this knowledge, we know that our solution for address to symbol
+/// translation will need to consult both the local and dynamic symbol tables.
+/// With that in mind, here's our options of translating an address to
+/// a symbol.
+///
+/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
+///   behind the scenes to translate, and this is why backtrace() was not used.
+///   Conveniently, this method works fantastically on OSX. It appears dladdr()
+///   uses magic to consult the local symbol table, or we're putting everything
+///   in the dynamic symbol table anyway. Regardless, for OSX, this is the
+///   method used for translation. It's provided by the system and easy to do.o
+///
+///   Sadly, all other systems have a dladdr() implementation that does not
+///   consult the local symbol table. This means that most functions are blank
+///   because they don't have symbols. This means that we need another solution.
+///
+/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
+///   libgcc_s version of the libunwind api), but involves taking a dependency
+///   to libunwind. We may pursue this route in the future if we bundle
+///   libunwind, but libunwind was unwieldy enough that it was not chosen at
+///   this time to provide this functionality.
+///
+/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
+///   semi-reasonable solution. The stdlib already knows how to spawn processes,
+///   so in theory it could invoke readelf, parse the output, and consult the
+///   local/dynamic symbol tables from there. This ended up not getting chosen
+///   due to the craziness of the idea plus the advent of the next option.
+///
+/// * Use `libbacktrace`. It turns out that this is a small library bundled in
+///   the gcc repository which provides backtrace and symbol translation
+///   functionality. All we really need from it is the backtrace functionality,
+///   and we only really need this on everything that's not OSX, so this is the
+///   chosen route for now.
+///
+/// In summary, the current situation uses libgcc_s to get a trace of stack
+/// pointers, and we use dladdr() or libbacktrace to translate these addresses
+/// to symbols. This is a bit of a hokey implementation as-is, but it works for
+/// all unix platforms we support right now, so it at least gets the job done.
+
+use c_str::CString;
+use io::{IoResult, Writer};
+use libc;
+use mem;
+use option::{Some, None, Option};
+use result::{Ok, Err};
+use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+
+use sys_common::backtrace::*;
+
+/// As always - iOS on arm uses SjLj exceptions and
+/// _Unwind_Backtrace is even not available there. Still,
+/// backtraces could be extracted using a backtrace function,
+/// which thanks god is public
+///
+/// As mentioned in a huge comment block above, backtrace doesn't
+/// play well with green threads, so while it is extremely nice
+/// and simple to use it should be used only on iOS devices as the
+/// only viable option.
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+#[inline(never)]
+pub fn write(w: &mut Writer) -> IoResult<()> {
+    use iter::{Iterator, range};
+    use result;
+    use slice::SliceExt;
+
+    extern {
+        fn backtrace(buf: *mut *mut libc::c_void,
+                     sz: libc::c_int) -> libc::c_int;
+    }
+
+    // while it doesn't requires lock for work as everything is
+    // local, it still displays much nicer backtraces when a
+    // couple of tasks panic simultaneously
+    static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+    let _g = unsafe { LOCK.lock() };
+
+    try!(writeln!(w, "stack backtrace:"));
+    // 100 lines should be enough
+    const SIZE: uint = 100;
+    let mut buf: [*mut libc::c_void, ..SIZE] = unsafe {mem::zeroed()};
+    let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as uint};
+
+    // skipping the first one as it is write itself
+    let iter = range(1, cnt).map(|i| {
+        print(w, i as int, buf[i])
+    });
+    result::fold(iter, (), |_, _| ())
+}
+
+#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn write(w: &mut Writer) -> IoResult<()> {
+    use io::IoError;
+
+    struct Context<'a> {
+        idx: int,
+        writer: &'a mut Writer+'a,
+        last_error: Option<IoError>,
+    }
+
+    // When using libbacktrace, we use some necessary global state, so we
+    // need to prevent more than one thread from entering this block. This
+    // is semi-reasonable in terms of printing anyway, and we know that all
+    // I/O done here is blocking I/O, not green I/O, so we don't have to
+    // worry about this being a native vs green mutex.
+    static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+    let _g = unsafe { LOCK.lock() };
+
+    try!(writeln!(w, "stack backtrace:"));
+
+    let mut cx = Context { writer: w, last_error: None, idx: 0 };
+    return match unsafe {
+        uw::_Unwind_Backtrace(trace_fn,
+                              &mut cx as *mut Context as *mut libc::c_void)
+    } {
+        uw::_URC_NO_REASON => {
+            match cx.last_error {
+                Some(err) => Err(err),
+                None => Ok(())
+            }
+        }
+        _ => Ok(()),
+    };
+
+    extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+                       arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+        let cx: &mut Context = unsafe { mem::transmute(arg) };
+        let ip = unsafe { uw::_Unwind_GetIP(ctx) as *mut libc::c_void };
+        // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+        // it appears to work fine without it, so we only use
+        // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+        // slightly more accurate stack trace in the process.
+        //
+        // This is often because panic involves the last instruction of a
+        // function being "call std::rt::begin_unwind", with no ret
+        // instructions after it. This means that the return instruction
+        // pointer points *outside* of the calling function, and by
+        // unwinding it we go back to the original function.
+        let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+            ip
+        } else {
+            unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+        };
+
+        // Don't print out the first few frames (they're not user frames)
+        cx.idx += 1;
+        if cx.idx <= 0 { return uw::_URC_NO_REASON }
+        // Don't print ginormous backtraces
+        if cx.idx > 100 {
+            match write!(cx.writer, " ... <frames omitted>\n") {
+                Ok(()) => {}
+                Err(e) => { cx.last_error = Some(e); }
+            }
+            return uw::_URC_FAILURE
+        }
+
+        // Once we hit an error, stop trying to print more frames
+        if cx.last_error.is_some() { return uw::_URC_FAILURE }
+
+        match print(cx.writer, cx.idx, ip) {
+            Ok(()) => {}
+            Err(e) => { cx.last_error = Some(e); }
+        }
+
+        // keep going
+        return uw::_URC_NO_REASON
+    }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
+    use intrinsics;
+    #[repr(C)]
+    struct Dl_info {
+        dli_fname: *const libc::c_char,
+        dli_fbase: *mut libc::c_void,
+        dli_sname: *const libc::c_char,
+        dli_saddr: *mut libc::c_void,
+    }
+    extern {
+        fn dladdr(addr: *const libc::c_void,
+                  info: *mut Dl_info) -> libc::c_int;
+    }
+
+    let mut info: Dl_info = unsafe { intrinsics::init() };
+    if unsafe { dladdr(addr as *const libc::c_void, &mut info) == 0 } {
+        output(w, idx,addr, None)
+    } else {
+        output(w, idx, addr, Some(unsafe {
+            CString::new(info.dli_sname, false)
+        }))
+    }
+}
+
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
+    use iter::Iterator;
+    use os;
+    use path::GenericPath;
+    use ptr::RawPtr;
+    use ptr;
+    use slice::SliceExt;
+
+    ////////////////////////////////////////////////////////////////////////
+    // libbacktrace.h API
+    ////////////////////////////////////////////////////////////////////////
+    type backtrace_syminfo_callback =
+        extern "C" fn(data: *mut libc::c_void,
+                      pc: libc::uintptr_t,
+                      symname: *const libc::c_char,
+                      symval: libc::uintptr_t,
+                      symsize: libc::uintptr_t);
+    type backtrace_error_callback =
+        extern "C" fn(data: *mut libc::c_void,
+                      msg: *const libc::c_char,
+                      errnum: libc::c_int);
+    enum backtrace_state {}
+    #[link(name = "backtrace", kind = "static")]
+    #[cfg(not(test))]
+    extern {}
+
+    extern {
+        fn backtrace_create_state(filename: *const libc::c_char,
+                                  threaded: libc::c_int,
+                                  error: backtrace_error_callback,
+                                  data: *mut libc::c_void)
+                                        -> *mut backtrace_state;
+        fn backtrace_syminfo(state: *mut backtrace_state,
+                             addr: libc::uintptr_t,
+                             cb: backtrace_syminfo_callback,
+                             error: backtrace_error_callback,
+                             data: *mut libc::c_void) -> libc::c_int;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // helper callbacks
+    ////////////////////////////////////////////////////////////////////////
+
+    extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
+                       _errnum: libc::c_int) {
+        // do nothing for now
+    }
+    extern fn syminfo_cb(data: *mut libc::c_void,
+                         _pc: libc::uintptr_t,
+                         symname: *const libc::c_char,
+                         _symval: libc::uintptr_t,
+                         _symsize: libc::uintptr_t) {
+        let slot = data as *mut *const libc::c_char;
+        unsafe { *slot = symname; }
+    }
+
+    // The libbacktrace API supports creating a state, but it does not
+    // support destroying a state. I personally take this to mean that a
+    // state is meant to be created and then live forever.
+    //
+    // I would love to register an at_exit() handler which cleans up this
+    // state, but libbacktrace provides no way to do so.
+    //
+    // With these constraints, this function has a statically cached state
+    // that is calculated the first time this is requested. Remember that
+    // backtracing all happens serially (one global lock).
+    //
+    // An additionally oddity in this function is that we initialize the
+    // filename via self_exe_name() to pass to libbacktrace. It turns out
+    // that on Linux libbacktrace seamlessly gets the filename of the
+    // current executable, but this fails on freebsd. by always providing
+    // it, we make sure that libbacktrace never has a reason to not look up
+    // the symbols. The libbacktrace API also states that the filename must
+    // be in "permanent memory", so we copy it to a static and then use the
+    // static as the pointer.
+    //
+    // FIXME: We also call self_exe_name() on DragonFly BSD. I haven't
+    //        tested if this is required or not.
+    unsafe fn init_state() -> *mut backtrace_state {
+        static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
+        static mut LAST_FILENAME: [libc::c_char, ..256] = [0, ..256];
+        if !STATE.is_null() { return STATE }
+        let selfname = if cfg!(target_os = "freebsd") ||
+                          cfg!(target_os = "dragonfly") {
+            os::self_exe_name()
+        } else {
+            None
+        };
+        let filename = match selfname {
+            Some(path) => {
+                let bytes = path.as_vec();
+                if bytes.len() < LAST_FILENAME.len() {
+                    let i = bytes.iter();
+                    for (slot, val) in LAST_FILENAME.iter_mut().zip(i) {
+                        *slot = *val as libc::c_char;
+                    }
+                    LAST_FILENAME.as_ptr()
+                } else {
+                    ptr::null()
+                }
+            }
+            None => ptr::null(),
+        };
+        STATE = backtrace_create_state(filename, 0, error_cb,
+                                       ptr::null_mut());
+        return STATE
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // translation
+    ////////////////////////////////////////////////////////////////////////
+
+    // backtrace errors are currently swept under the rug, only I/O
+    // errors are reported
+    let state = unsafe { init_state() };
+    if state.is_null() {
+        return output(w, idx, addr, None)
+    }
+    let mut data = 0 as *const libc::c_char;
+    let data_addr = &mut data as *mut *const libc::c_char;
+    let ret = unsafe {
+        backtrace_syminfo(state, addr as libc::uintptr_t,
+                          syminfo_cb, error_cb,
+                          data_addr as *mut libc::c_void)
+    };
+    if ret == 0 || data.is_null() {
+        output(w, idx, addr, None)
+    } else {
+        output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
+    }
+}
+
+// Finally, after all that work above, we can emit a symbol.
+fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
+          s: Option<CString>) -> IoResult<()> {
+    try!(write!(w, "  {:2}: {:2$} - ", idx, addr, HEX_WIDTH));
+    match s.as_ref().and_then(|c| c.as_str()) {
+        Some(string) => try!(demangle(w, string)),
+        None => try!(write!(w, "<unknown>")),
+    }
+    w.write(&['\n' as u8])
+}
+
+/// Unwind library interface used for backtraces
+///
+/// Note that dead code is allowed as here are just bindings
+/// iOS doesn't use all of them it but adding more
+/// platform-specific configs pollutes the code too much
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+#[allow(dead_code)]
+mod uw {
+    pub use self::_Unwind_Reason_Code::*;
+
+    use libc;
+
+    #[repr(C)]
+    pub enum _Unwind_Reason_Code {
+        _URC_NO_REASON = 0,
+        _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+        _URC_FATAL_PHASE2_ERROR = 2,
+        _URC_FATAL_PHASE1_ERROR = 3,
+        _URC_NORMAL_STOP = 4,
+        _URC_END_OF_STACK = 5,
+        _URC_HANDLER_FOUND = 6,
+        _URC_INSTALL_CONTEXT = 7,
+        _URC_CONTINUE_UNWIND = 8,
+        _URC_FAILURE = 9, // used only by ARM EABI
+    }
+
+    pub enum _Unwind_Context {}
+
+    pub type _Unwind_Trace_Fn =
+            extern fn(ctx: *mut _Unwind_Context,
+                      arg: *mut libc::c_void) -> _Unwind_Reason_Code;
+
+    extern {
+        // No native _Unwind_Backtrace on iOS
+        #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+        pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
+                                 trace_argument: *mut libc::c_void)
+                    -> _Unwind_Reason_Code;
+
+        #[cfg(all(not(target_os = "android"),
+                  not(all(target_os = "linux", target_arch = "arm"))))]
+        pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
+
+        #[cfg(all(not(target_os = "android"),
+                  not(all(target_os = "linux", target_arch = "arm"))))]
+        pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
+            -> *mut libc::c_void;
+    }
+
+    // On android, the function _Unwind_GetIP is a macro, and this is the
+    // expansion of the macro. This is all copy/pasted directly from the
+    // header file with the definition of _Unwind_GetIP.
+    #[cfg(any(target_os = "android",
+              all(target_os = "linux", target_arch = "arm")))]
+    pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
+        #[repr(C)]
+        enum _Unwind_VRS_Result {
+            _UVRSR_OK = 0,
+            _UVRSR_NOT_IMPLEMENTED = 1,
+            _UVRSR_FAILED = 2,
+        }
+        #[repr(C)]
+        enum _Unwind_VRS_RegClass {
+            _UVRSC_CORE = 0,
+            _UVRSC_VFP = 1,
+            _UVRSC_FPA = 2,
+            _UVRSC_WMMXD = 3,
+            _UVRSC_WMMXC = 4,
+        }
+        #[repr(C)]
+        enum _Unwind_VRS_DataRepresentation {
+            _UVRSD_UINT32 = 0,
+            _UVRSD_VFPX = 1,
+            _UVRSD_FPAX = 2,
+            _UVRSD_UINT64 = 3,
+            _UVRSD_FLOAT = 4,
+            _UVRSD_DOUBLE = 5,
+        }
+
+        type _Unwind_Word = libc::c_uint;
+        extern {
+            fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
+                               klass: _Unwind_VRS_RegClass,
+                               word: _Unwind_Word,
+                               repr: _Unwind_VRS_DataRepresentation,
+                               data: *mut libc::c_void)
+                -> _Unwind_VRS_Result;
+        }
+
+        let mut val: _Unwind_Word = 0;
+        let ptr = &mut val as *mut _Unwind_Word;
+        let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
+                                _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
+                                ptr as *mut libc::c_void);
+        (val & !1) as libc::uintptr_t
+    }
+
+    // This function also doesn't exist on Android or ARM/Linux, so make it
+    // a no-op
+    #[cfg(any(target_os = "android",
+              all(target_os = "linux", target_arch = "arm")))]
+    pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
+        -> *mut libc::c_void
+    {
+        pc
+    }
+}
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index acbf2096326..f3babca3287 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -34,6 +34,7 @@ macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
     };
 ) }
 
+pub mod backtrace;
 pub mod c;
 pub mod ext;
 pub mod condvar;
@@ -44,8 +45,10 @@ pub mod os;
 pub mod pipe;
 pub mod process;
 pub mod rwlock;
+pub mod stack_overflow;
 pub mod sync;
 pub mod tcp;
+pub mod thread;
 pub mod thread_local;
 pub mod timer;
 pub mod tty;
diff --git a/src/librustrt/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 05f9f6287c4..73b98f762b4 100644
--- a/src/librustrt/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -8,20 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-
-use core::prelude::*;
 use libc;
-use local::Local;
-use task::Task;
-
-pub unsafe fn init() {
-    imp::init();
-}
+use core::prelude::*;
+use self::imp::{make_handler, drop_handler};
 
-pub unsafe fn cleanup() {
-    imp::cleanup();
-}
+pub use self::imp::{init, cleanup};
 
 pub struct Handler {
     _data: *mut libc::c_void
@@ -29,149 +20,33 @@ pub struct Handler {
 
 impl Handler {
     pub unsafe fn new() -> Handler {
-        imp::make_handler()
+        make_handler()
     }
 }
 
 impl Drop for Handler {
     fn drop(&mut self) {
         unsafe {
-            imp::drop_handler(self);
-        }
-    }
-}
-
-pub unsafe fn report() {
-    // See the message below for why this is not emitted to the
-    // ^ Where did the message below go?
-    // task's logger. This has the additional conundrum of the
-    // logger may not be initialized just yet, meaning that an FFI
-    // call would happen to initialized it (calling out to libuv),
-    // and the FFI call needs 2MB of stack when we just ran out.
-
-    let task: Option<*mut Task> = Local::try_unsafe_borrow();
-
-    let name = task.and_then(|task| {
-        (*task).name.as_ref().map(|n| n.as_slice())
-    });
-
-    rterrln!("\ntask '{}' has overflowed its stack", name.unwrap_or("<unknown>"));
-}
-
-// get_task_info is called from an exception / signal handler.
-// It returns the guard page of the current task or 0 if that
-// guard page doesn't exist. None is returned if there's currently
-// no local task.
-#[cfg(any(windows, target_os = "linux", target_os = "macos"))]
-unsafe fn get_task_guard_page() -> Option<uint> {
-    let task: Option<*mut Task> = Local::try_unsafe_borrow();
-    task.map(|task| (&*task).stack_guard().unwrap_or(0))
-}
-
-#[cfg(windows)]
-#[allow(non_snake_case)]
-mod imp {
-    use core::ptr;
-    use core::mem;
-    use libc;
-    use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
-    use stack;
-    use super::{Handler, get_task_guard_page, report};
-
-    // This is initialized in init() and only read from after
-    static mut PAGE_SIZE: uint = 0;
-
-    #[no_stack_check]
-    extern "system" fn vectored_handler(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG {
-        unsafe {
-            let rec = &(*(*ExceptionInfo).ExceptionRecord);
-            let code = rec.ExceptionCode;
-
-            if code != EXCEPTION_STACK_OVERFLOW {
-                return EXCEPTION_CONTINUE_SEARCH;
-            }
-
-            // We're calling into functions with stack checks,
-            // however stack checks by limit should be disabled on Windows
-            stack::record_sp_limit(0);
-
-            if get_task_guard_page().is_some() {
-               report();
-            }
-
-            EXCEPTION_CONTINUE_SEARCH
-        }
-    }
-
-    pub unsafe fn init() {
-        let mut info = mem::zeroed();
-        libc::GetSystemInfo(&mut info);
-        PAGE_SIZE = info.dwPageSize as uint;
-
-        if AddVectoredExceptionHandler(0, vectored_handler) == ptr::null_mut() {
-            panic!("failed to install exception handler");
+            drop_handler(self);
         }
-
-        mem::forget(make_handler());
-    }
-
-    pub unsafe fn cleanup() {
-    }
-
-    pub unsafe fn make_handler() -> Handler {
-        if SetThreadStackGuarantee(&mut 0x5000) == 0 {
-            panic!("failed to reserve stack space for exception handling");
-        }
-
-        super::Handler { _data: 0i as *mut libc::c_void }
-    }
-
-    pub unsafe fn drop_handler(_handler: &mut Handler) {
-    }
-
-    pub struct EXCEPTION_RECORD {
-        pub ExceptionCode: DWORD,
-        pub ExceptionFlags: DWORD,
-        pub ExceptionRecord: *mut EXCEPTION_RECORD,
-        pub ExceptionAddress: LPVOID,
-        pub NumberParameters: DWORD,
-        pub ExceptionInformation: [LPVOID, ..EXCEPTION_MAXIMUM_PARAMETERS]
-    }
-
-    pub struct EXCEPTION_POINTERS {
-        pub ExceptionRecord: *mut EXCEPTION_RECORD,
-        pub ContextRecord: LPVOID
-    }
-
-    pub type PVECTORED_EXCEPTION_HANDLER = extern "system"
-            fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
-
-    pub type ULONG = libc::c_ulong;
-
-    const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
-    const EXCEPTION_MAXIMUM_PARAMETERS: uint = 15;
-    const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
-
-    extern "system" {
-        fn AddVectoredExceptionHandler(FirstHandler: ULONG,
-                                       VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
-                                      -> LPVOID;
-        fn SetThreadStackGuarantee(StackSizeInBytes: *mut ULONG) -> BOOL;
     }
 }
 
 #[cfg(any(target_os = "linux", target_os = "macos"))]
 mod imp {
     use core::prelude::*;
-    use stack;
+    use sys_common::stack;
 
-    use super::{Handler, get_task_guard_page, report};
-    use core::mem;
-    use core::ptr;
-    use core::intrinsics;
+    use super::Handler;
+    use rt::util::report_overflow;
+    use mem;
+    use ptr;
+    use intrinsics;
     use self::signal::{siginfo, sigaction, SIGBUS, SIG_DFL,
                        SA_SIGINFO, SA_ONSTACK, sigaltstack,
                        SIGSTKSZ};
+    use rt::local::Local;
+    use rt::task::Task;
     use libc;
     use libc::funcs::posix88::mman::{mmap, munmap};
     use libc::consts::os::posix88::{SIGSEGV,
@@ -185,6 +60,16 @@ mod imp {
     // This is initialized in init() and only read from after
     static mut PAGE_SIZE: uint = 0;
 
+    // get_task_info is called from an exception / signal handler.
+    // It returns the guard page of the current task or 0 if that
+    // guard page doesn't exist. None is returned if there's currently
+    // no local task.
+    unsafe fn get_task_guard_page() -> Option<uint> {
+        let task: Option<*mut Task> = Local::try_unsafe_borrow();
+        task.map(|task| (&*task).stack_guard().unwrap_or(0))
+    }
+
+
     #[no_stack_check]
     unsafe extern fn signal_handler(signum: libc::c_int,
                                      info: *mut siginfo,
@@ -212,7 +97,7 @@ mod imp {
                     term(signum);
                 }
 
-                report();
+                report_overflow();
 
                 intrinsics::abort()
             }
@@ -387,8 +272,7 @@ mod imp {
 }
 
 #[cfg(not(any(target_os = "linux",
-              target_os = "macos",
-              windows)))]
+              target_os = "macos")))]
 mod imp {
     use libc;
 
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
new file mode 100644
index 00000000000..02da3a19818
--- /dev/null
+++ b/src/libstd/sys/unix/thread.rs
@@ -0,0 +1,270 @@
+// 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.
+
+use core::prelude::*;
+
+use boxed::Box;
+use cmp;
+use mem;
+use ptr;
+use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
+use libc;
+
+use sys_common::stack::RED_ZONE;
+use sys_common::thread::*;
+
+pub type rust_thread = libc::pthread_t;
+pub type rust_thread_return = *mut u8;
+pub type StartFn = extern "C" fn(*mut libc::c_void) -> rust_thread_return;
+
+#[no_stack_check]
+pub extern fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
+    return start_thread(main);
+}
+
+#[cfg(all(not(target_os = "linux"), not(target_os = "macos")))]
+pub mod guard {
+    pub unsafe fn current() -> uint {
+        0
+    }
+
+    pub unsafe fn main() -> uint {
+        0
+    }
+
+    pub unsafe fn init() {
+    }
+}
+
+#[cfg(any(target_os = "linux", target_os = "macos"))]
+pub mod guard {
+    use super::*;
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    use mem;
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    use ptr;
+    use libc;
+    use libc::funcs::posix88::mman::{mmap};
+    use libc::consts::os::posix88::{PROT_NONE,
+                                    MAP_PRIVATE,
+                                    MAP_ANON,
+                                    MAP_FAILED,
+                                    MAP_FIXED};
+
+    // These are initialized in init() and only read from after
+    static mut PAGE_SIZE: uint = 0;
+    static mut GUARD_PAGE: uint = 0;
+
+    #[cfg(target_os = "macos")]
+    unsafe fn get_stack_start() -> *mut libc::c_void {
+        current() as *mut libc::c_void
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    unsafe fn get_stack_start() -> *mut libc::c_void {
+        let mut attr: libc::pthread_attr_t = mem::zeroed();
+        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
+            panic!("failed to get thread attributes");
+        }
+        let mut stackaddr = ptr::null_mut();
+        let mut stacksize = 0;
+        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
+            panic!("failed to get stack information");
+        }
+        if pthread_attr_destroy(&mut attr) != 0 {
+            panic!("failed to destroy thread attributes");
+        }
+        stackaddr
+    }
+
+    pub unsafe fn init() {
+        let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
+        if psize == -1 {
+            panic!("failed to get page size");
+        }
+
+        PAGE_SIZE = psize as uint;
+
+        let stackaddr = get_stack_start();
+
+        // Rellocate the last page of the stack.
+        // This ensures SIGBUS will be raised on
+        // stack overflow.
+        let result = mmap(stackaddr,
+                          PAGE_SIZE as libc::size_t,
+                          PROT_NONE,
+                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+                          -1,
+                          0);
+
+        if result != stackaddr || result == MAP_FAILED {
+            panic!("failed to allocate a guard page");
+        }
+
+        let offset = if cfg!(target_os = "linux") {
+            2
+        } else {
+            1
+        };
+
+        GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
+    }
+
+    pub unsafe fn main() -> uint {
+        GUARD_PAGE
+    }
+
+    #[cfg(target_os = "macos")]
+    pub unsafe fn current() -> uint {
+        (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
+         pthread_get_stacksize_np(pthread_self())) as uint
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    pub unsafe fn current() -> uint {
+        let mut attr: libc::pthread_attr_t = mem::zeroed();
+        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
+            panic!("failed to get thread attributes");
+        }
+        let mut guardsize = 0;
+        if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
+            panic!("failed to get stack guard page");
+        }
+        if guardsize == 0 {
+            panic!("there is no guard page");
+        }
+        let mut stackaddr = ptr::null_mut();
+        let mut stacksize = 0;
+        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
+            panic!("failed to get stack information");
+        }
+        if pthread_attr_destroy(&mut attr) != 0 {
+            panic!("failed to destroy thread attributes");
+        }
+
+        stackaddr as uint + guardsize as uint
+    }
+}
+
+pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
+    let mut native: libc::pthread_t = mem::zeroed();
+    let mut attr: libc::pthread_attr_t = mem::zeroed();
+    assert_eq!(pthread_attr_init(&mut attr), 0);
+    assert_eq!(pthread_attr_setdetachstate(&mut attr,
+                                           PTHREAD_CREATE_JOINABLE), 0);
+
+    // Reserve room for the red zone, the runtime's stack of last resort.
+    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
+    match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
+        0 => {
+        },
+        libc::EINVAL => {
+            // EINVAL means |stack_size| is either too small or not a
+            // multiple of the system page size.  Because it's definitely
+            // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+            // Round up to the nearest page and try again.
+            let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
+            let stack_size = (stack_size + page_size - 1) &
+                             (-(page_size as int - 1) as uint - 1);
+            assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
+        },
+        errno => {
+            // This cannot really happen.
+            panic!("pthread_attr_setstacksize() error: {}", errno);
+        },
+    };
+
+    let arg: *mut libc::c_void = mem::transmute(p);
+    let ret = pthread_create(&mut native, &attr, thread_start, arg);
+    assert_eq!(pthread_attr_destroy(&mut attr), 0);
+
+    if ret != 0 {
+        // be sure to not leak the closure
+        let _p: Box<proc():Send> = mem::transmute(arg);
+        panic!("failed to spawn native thread: {}", ret);
+    }
+    native
+}
+
+pub unsafe fn join(native: rust_thread) {
+    assert_eq!(pthread_join(native, ptr::null_mut()), 0);
+}
+
+pub unsafe fn detach(native: rust_thread) {
+    assert_eq!(pthread_detach(native), 0);
+}
+
+pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
+// glibc >= 2.15 has a __pthread_get_minstack() function that returns
+// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
+// storage.  We need that information to avoid blowing up when a small stack
+// is created in an application with big thread-local storage requirements.
+// See #6233 for rationale and details.
+//
+// Link weakly to the symbol for compatibility with older versions of glibc.
+// Assumes that we've been dynamically linked to libpthread but that is
+// currently always the case.  Note that you need to check that the symbol
+// is non-null before calling it!
+#[cfg(target_os = "linux")]
+fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
+    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
+    extern {
+        #[linkage = "extern_weak"]
+        static __pthread_get_minstack: *const ();
+    }
+    if __pthread_get_minstack.is_null() {
+        PTHREAD_STACK_MIN
+    } else {
+        unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) }
+    }
+}
+
+// __pthread_get_minstack() is marked as weak but extern_weak linkage is
+// not supported on OS X, hence this kludge...
+#[cfg(not(target_os = "linux"))]
+fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
+    PTHREAD_STACK_MIN
+}
+
+#[cfg(any(target_os = "linux"))]
+extern {
+    pub fn pthread_self() -> libc::pthread_t;
+    pub fn pthread_getattr_np(native: libc::pthread_t,
+                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
+    pub fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
+                                     guardsize: *mut libc::size_t) -> libc::c_int;
+    pub fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
+                                 stackaddr: *mut *mut libc::c_void,
+                                 stacksize: *mut libc::size_t) -> libc::c_int;
+}
+
+#[cfg(target_os = "macos")]
+extern {
+    pub fn pthread_self() -> libc::pthread_t;
+    pub fn pthread_get_stackaddr_np(thread: libc::pthread_t) -> *mut libc::c_void;
+    pub fn pthread_get_stacksize_np(thread: libc::pthread_t) -> libc::size_t;
+}
+
+extern {
+    fn pthread_create(native: *mut libc::pthread_t,
+                      attr: *const libc::pthread_attr_t,
+                      f: StartFn,
+                      value: *mut libc::c_void) -> libc::c_int;
+    fn pthread_join(native: libc::pthread_t,
+                    value: *mut *mut libc::c_void) -> libc::c_int;
+    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
+    pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
+    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
+                                 stack_size: libc::size_t) -> libc::c_int;
+    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
+                                   state: libc::c_int) -> libc::c_int;
+    fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
+    fn sched_yield() -> libc::c_int;
+}
diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs
new file mode 100644
index 00000000000..833b69d6cbe
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace.rs
@@ -0,0 +1,371 @@
+// 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.
+/// As always, windows has something very different than unix, we mainly want
+/// to avoid having to depend too much on libunwind for windows.
+///
+/// If you google around, you'll find a fair bit of references to built-in
+/// functions to get backtraces on windows. It turns out that most of these are
+/// in an external library called dbghelp. I was unable to find this library
+/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
+/// of it.
+///
+/// You'll also find that there's a function called CaptureStackBackTrace
+/// mentioned frequently (which is also easy to use), but sadly I didn't have a
+/// copy of that function in my mingw install (maybe it was broken?). Instead,
+/// this takes the route of using StackWalk64 in order to walk the stack.
+
+use c_str::CString;
+use intrinsics;
+use io::{IoResult, Writer};
+use libc;
+use mem;
+use ops::Drop;
+use option::{Some, None};
+use path::Path;
+use result::{Ok, Err};
+use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+use slice::SliceExt;
+use str::StrPrelude;
+use dynamic_lib::DynamicLibrary;
+
+use sys_common::backtrace::*;
+
+#[allow(non_snake_case)]
+extern "system" {
+    fn GetCurrentProcess() -> libc::HANDLE;
+    fn GetCurrentThread() -> libc::HANDLE;
+    fn RtlCaptureContext(ctx: *mut arch::CONTEXT);
+}
+
+type SymFromAddrFn =
+    extern "system" fn(libc::HANDLE, u64, *mut u64,
+                       *mut SYMBOL_INFO) -> libc::BOOL;
+type SymInitializeFn =
+    extern "system" fn(libc::HANDLE, *mut libc::c_void,
+                       libc::BOOL) -> libc::BOOL;
+type SymCleanupFn =
+    extern "system" fn(libc::HANDLE) -> libc::BOOL;
+
+type StackWalk64Fn =
+    extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE,
+                       *mut STACKFRAME64, *mut arch::CONTEXT,
+                       *mut libc::c_void, *mut libc::c_void,
+                       *mut libc::c_void, *mut libc::c_void) -> libc::BOOL;
+
+const MAX_SYM_NAME: uint = 2000;
+const IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c;
+const IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
+const IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
+
+#[repr(C)]
+struct SYMBOL_INFO {
+    SizeOfStruct: libc::c_ulong,
+    TypeIndex: libc::c_ulong,
+    Reserved: [u64, ..2],
+    Index: libc::c_ulong,
+    Size: libc::c_ulong,
+    ModBase: u64,
+    Flags: libc::c_ulong,
+    Value: u64,
+    Address: u64,
+    Register: libc::c_ulong,
+    Scope: libc::c_ulong,
+    Tag: libc::c_ulong,
+    NameLen: libc::c_ulong,
+    MaxNameLen: libc::c_ulong,
+    // note that windows has this as 1, but it basically just means that
+    // the name is inline at the end of the struct. For us, we just bump
+    // the struct size up to MAX_SYM_NAME.
+    Name: [libc::c_char, ..MAX_SYM_NAME],
+}
+
+
+#[repr(C)]
+enum ADDRESS_MODE {
+    AddrMode1616,
+    AddrMode1632,
+    AddrModeReal,
+    AddrModeFlat,
+}
+
+struct ADDRESS64 {
+    Offset: u64,
+    Segment: u16,
+    Mode: ADDRESS_MODE,
+}
+
+struct STACKFRAME64 {
+    AddrPC: ADDRESS64,
+    AddrReturn: ADDRESS64,
+    AddrFrame: ADDRESS64,
+    AddrStack: ADDRESS64,
+    AddrBStore: ADDRESS64,
+    FuncTableEntry: *mut libc::c_void,
+    Params: [u64, ..4],
+    Far: libc::BOOL,
+    Virtual: libc::BOOL,
+    Reserved: [u64, ..3],
+    KdHelp: KDHELP64,
+}
+
+struct KDHELP64 {
+    Thread: u64,
+    ThCallbackStack: libc::DWORD,
+    ThCallbackBStore: libc::DWORD,
+    NextCallback: libc::DWORD,
+    FramePointer: libc::DWORD,
+    KiCallUserMode: u64,
+    KeUserCallbackDispatcher: u64,
+    SystemRangeStart: u64,
+    KiUserExceptionDispatcher: u64,
+    StackBase: u64,
+    StackLimit: u64,
+    Reserved: [u64, ..5],
+}
+
+#[cfg(target_arch = "x86")]
+mod arch {
+    use libc;
+
+    const MAXIMUM_SUPPORTED_EXTENSION: uint = 512;
+
+    #[repr(C)]
+    pub struct CONTEXT {
+        ContextFlags: libc::DWORD,
+        Dr0: libc::DWORD,
+        Dr1: libc::DWORD,
+        Dr2: libc::DWORD,
+        Dr3: libc::DWORD,
+        Dr6: libc::DWORD,
+        Dr7: libc::DWORD,
+        FloatSave: FLOATING_SAVE_AREA,
+        SegGs: libc::DWORD,
+        SegFs: libc::DWORD,
+        SegEs: libc::DWORD,
+        SegDs: libc::DWORD,
+        Edi: libc::DWORD,
+        Esi: libc::DWORD,
+        Ebx: libc::DWORD,
+        Edx: libc::DWORD,
+        Ecx: libc::DWORD,
+        Eax: libc::DWORD,
+        Ebp: libc::DWORD,
+        Eip: libc::DWORD,
+        SegCs: libc::DWORD,
+        EFlags: libc::DWORD,
+        Esp: libc::DWORD,
+        SegSs: libc::DWORD,
+        ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION],
+    }
+
+    #[repr(C)]
+    pub struct FLOATING_SAVE_AREA {
+        ControlWord: libc::DWORD,
+        StatusWord: libc::DWORD,
+        TagWord: libc::DWORD,
+        ErrorOffset: libc::DWORD,
+        ErrorSelector: libc::DWORD,
+        DataOffset: libc::DWORD,
+        DataSelector: libc::DWORD,
+        RegisterArea: [u8, ..80],
+        Cr0NpxState: libc::DWORD,
+    }
+
+    pub fn init_frame(frame: &mut super::STACKFRAME64,
+                      ctx: &CONTEXT) -> libc::DWORD {
+        frame.AddrPC.Offset = ctx.Eip as u64;
+        frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
+        frame.AddrStack.Offset = ctx.Esp as u64;
+        frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
+        frame.AddrFrame.Offset = ctx.Ebp as u64;
+        frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
+        super::IMAGE_FILE_MACHINE_I386
+    }
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+    use libc::{c_longlong, c_ulonglong};
+    use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG};
+    use simd;
+
+    #[repr(C)]
+    pub struct CONTEXT {
+        _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
+        P1Home: DWORDLONG,
+        P2Home: DWORDLONG,
+        P3Home: DWORDLONG,
+        P4Home: DWORDLONG,
+        P5Home: DWORDLONG,
+        P6Home: DWORDLONG,
+
+        ContextFlags: DWORD,
+        MxCsr: DWORD,
+
+        SegCs: WORD,
+        SegDs: WORD,
+        SegEs: WORD,
+        SegFs: WORD,
+        SegGs: WORD,
+        SegSs: WORD,
+        EFlags: DWORD,
+
+        Dr0: DWORDLONG,
+        Dr1: DWORDLONG,
+        Dr2: DWORDLONG,
+        Dr3: DWORDLONG,
+        Dr6: DWORDLONG,
+        Dr7: DWORDLONG,
+
+        Rax: DWORDLONG,
+        Rcx: DWORDLONG,
+        Rdx: DWORDLONG,
+        Rbx: DWORDLONG,
+        Rsp: DWORDLONG,
+        Rbp: DWORDLONG,
+        Rsi: DWORDLONG,
+        Rdi: DWORDLONG,
+        R8:  DWORDLONG,
+        R9:  DWORDLONG,
+        R10: DWORDLONG,
+        R11: DWORDLONG,
+        R12: DWORDLONG,
+        R13: DWORDLONG,
+        R14: DWORDLONG,
+        R15: DWORDLONG,
+
+        Rip: DWORDLONG,
+
+        FltSave: FLOATING_SAVE_AREA,
+
+        VectorRegister: [M128A, .. 26],
+        VectorControl: DWORDLONG,
+
+        DebugControl: DWORDLONG,
+        LastBranchToRip: DWORDLONG,
+        LastBranchFromRip: DWORDLONG,
+        LastExceptionToRip: DWORDLONG,
+        LastExceptionFromRip: DWORDLONG,
+    }
+
+    #[repr(C)]
+    pub struct M128A {
+        _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
+        Low:  c_ulonglong,
+        High: c_longlong
+    }
+
+    #[repr(C)]
+    pub struct FLOATING_SAVE_AREA {
+        _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
+        _Dummy: [u8, ..512] // FIXME: Fill this out
+    }
+
+    pub fn init_frame(frame: &mut super::STACKFRAME64,
+                      ctx: &CONTEXT) -> DWORD {
+        frame.AddrPC.Offset = ctx.Rip as u64;
+        frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
+        frame.AddrStack.Offset = ctx.Rsp as u64;
+        frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
+        frame.AddrFrame.Offset = ctx.Rbp as u64;
+        frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
+        super::IMAGE_FILE_MACHINE_AMD64
+    }
+}
+
+#[repr(C)]
+struct Cleanup {
+    handle: libc::HANDLE,
+    SymCleanup: SymCleanupFn,
+}
+
+impl Drop for Cleanup {
+    fn drop(&mut self) { (self.SymCleanup)(self.handle); }
+}
+
+pub fn write(w: &mut Writer) -> IoResult<()> {
+    // According to windows documentation, all dbghelp functions are
+    // single-threaded.
+    static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+    let _g = unsafe { LOCK.lock() };
+
+    // Open up dbghelp.dll, we don't link to it explicitly because it can't
+    // always be found. Additionally, it's nice having fewer dependencies.
+    let path = Path::new("dbghelp.dll");
+    let lib = match DynamicLibrary::open(Some(&path)) {
+        Ok(lib) => lib,
+        Err(..) => return Ok(()),
+    };
+
+    macro_rules! sym( ($e:expr, $t:ident) => (unsafe {
+        match lib.symbol($e) {
+            Ok(f) => mem::transmute::<*mut u8, $t>(f),
+            Err(..) => return Ok(())
+        }
+    }) )
+
+    // Fetch the symbols necessary from dbghelp.dll
+    let SymFromAddr = sym!("SymFromAddr", SymFromAddrFn);
+    let SymInitialize = sym!("SymInitialize", SymInitializeFn);
+    let SymCleanup = sym!("SymCleanup", SymCleanupFn);
+    let StackWalk64 = sym!("StackWalk64", StackWalk64Fn);
+
+    // Allocate necessary structures for doing the stack walk
+    let process = unsafe { GetCurrentProcess() };
+    let thread = unsafe { GetCurrentThread() };
+    let mut context: arch::CONTEXT = unsafe { intrinsics::init() };
+    unsafe { RtlCaptureContext(&mut context); }
+    let mut frame: STACKFRAME64 = unsafe { intrinsics::init() };
+    let image = arch::init_frame(&mut frame, &context);
+
+    // Initialize this process's symbols
+    let ret = SymInitialize(process, 0 as *mut libc::c_void, libc::TRUE);
+    if ret != libc::TRUE { return Ok(()) }
+    let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
+
+    // And now that we're done with all the setup, do the stack walking!
+    let mut i = 0i;
+    try!(write!(w, "stack backtrace:\n"));
+    while StackWalk64(image, process, thread, &mut frame, &mut context,
+                      0 as *mut libc::c_void,
+                      0 as *mut libc::c_void,
+                      0 as *mut libc::c_void,
+                      0 as *mut libc::c_void) == libc::TRUE{
+        let addr = frame.AddrPC.Offset;
+        if addr == frame.AddrReturn.Offset || addr == 0 ||
+           frame.AddrReturn.Offset == 0 { break }
+
+        i += 1;
+        try!(write!(w, "  {:2}: {:#2$x}", i, addr, HEX_WIDTH));
+        let mut info: SYMBOL_INFO = unsafe { intrinsics::init() };
+        info.MaxNameLen = MAX_SYM_NAME as libc::c_ulong;
+        // the struct size in C.  the value is different to
+        // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
+        // due to struct alignment.
+        info.SizeOfStruct = 88;
+
+        let mut displacement = 0u64;
+        let ret = SymFromAddr(process, addr as u64, &mut displacement,
+                              &mut info);
+
+        if ret == libc::TRUE {
+            try!(write!(w, " - "));
+            let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
+            let bytes = cstr.as_bytes();
+            match cstr.as_str() {
+                Some(s) => try!(demangle(w, s)),
+                None => try!(w.write(bytes[..bytes.len()-1])),
+            }
+        }
+        try!(w.write(&['\n' as u8]));
+    }
+
+    Ok(())
+}
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index d22d4e0f534..6924687d8c4 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -35,6 +35,7 @@ macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
     };
 ) }
 
+pub mod backtrace;
 pub mod c;
 pub mod ext;
 pub mod condvar;
@@ -46,7 +47,9 @@ pub mod pipe;
 pub mod process;
 pub mod rwlock;
 pub mod sync;
+pub mod stack_overflow;
 pub mod tcp;
+pub mod thread;
 pub mod thread_local;
 pub mod timer;
 pub mod tty;
diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs
new file mode 100644
index 00000000000..e3d96a054f4
--- /dev/null
+++ b/src/libstd/sys/windows/stack_overflow.rs
@@ -0,0 +1,120 @@
+// 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.
+
+use rt::local::Local;
+use rt::task::Task;
+use rt::util::report_overflow;
+use core::prelude::*;
+use ptr;
+use mem;
+use libc;
+use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
+use sys_common::stack;
+
+pub struct Handler {
+    _data: *mut libc::c_void
+}
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        make_handler()
+    }
+}
+
+impl Drop for Handler {
+    fn drop(&mut self) {}
+}
+
+// get_task_info is called from an exception / signal handler.
+// It returns the guard page of the current task or 0 if that
+// guard page doesn't exist. None is returned if there's currently
+// no local task.
+unsafe fn get_task_guard_page() -> Option<uint> {
+    let task: Option<*mut Task> = Local::try_unsafe_borrow();
+    task.map(|task| (&*task).stack_guard().unwrap_or(0))
+}
+
+// This is initialized in init() and only read from after
+static mut PAGE_SIZE: uint = 0;
+
+#[no_stack_check]
+extern "system" fn vectored_handler(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG {
+    unsafe {
+        let rec = &(*(*ExceptionInfo).ExceptionRecord);
+        let code = rec.ExceptionCode;
+
+        if code != EXCEPTION_STACK_OVERFLOW {
+            return EXCEPTION_CONTINUE_SEARCH;
+        }
+
+        // We're calling into functions with stack checks,
+        // however stack checks by limit should be disabled on Windows
+        stack::record_sp_limit(0);
+
+        if get_task_guard_page().is_some() {
+           report_overflow();
+        }
+
+        EXCEPTION_CONTINUE_SEARCH
+    }
+}
+
+pub unsafe fn init() {
+    let mut info = mem::zeroed();
+    libc::GetSystemInfo(&mut info);
+    PAGE_SIZE = info.dwPageSize as uint;
+
+    if AddVectoredExceptionHandler(0, vectored_handler) == ptr::null_mut() {
+        panic!("failed to install exception handler");
+    }
+
+    mem::forget(make_handler());
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub unsafe fn make_handler() -> Handler {
+    if SetThreadStackGuarantee(&mut 0x5000) == 0 {
+        panic!("failed to reserve stack space for exception handling");
+    }
+
+    Handler { _data: 0i as *mut libc::c_void }
+}
+
+pub struct EXCEPTION_RECORD {
+    pub ExceptionCode: DWORD,
+    pub ExceptionFlags: DWORD,
+    pub ExceptionRecord: *mut EXCEPTION_RECORD,
+    pub ExceptionAddress: LPVOID,
+    pub NumberParameters: DWORD,
+    pub ExceptionInformation: [LPVOID, ..EXCEPTION_MAXIMUM_PARAMETERS]
+}
+
+pub struct EXCEPTION_POINTERS {
+    pub ExceptionRecord: *mut EXCEPTION_RECORD,
+    pub ContextRecord: LPVOID
+}
+
+pub type PVECTORED_EXCEPTION_HANDLER = extern "system"
+        fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
+
+pub type ULONG = libc::c_ulong;
+
+const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
+const EXCEPTION_MAXIMUM_PARAMETERS: uint = 15;
+const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
+
+extern "system" {
+    fn AddVectoredExceptionHandler(FirstHandler: ULONG,
+                                   VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
+                                  -> LPVOID;
+    fn SetThreadStackGuarantee(StackSizeInBytes: *mut ULONG) -> BOOL;
+}
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
new file mode 100644
index 00000000000..00f1e9767f5
--- /dev/null
+++ b/src/libstd/sys/windows/thread.rs
@@ -0,0 +1,95 @@
+// 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.
+
+use core::prelude::*;
+
+use boxed::Box;
+use cmp;
+use mem;
+use ptr;
+use libc;
+use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
+                                   LPVOID, DWORD, LPDWORD, HANDLE};
+use sys_common::stack::RED_ZONE;
+use sys_common::thread::*;
+
+pub type rust_thread = HANDLE;
+pub type rust_thread_return = DWORD;
+
+pub type StartFn = extern "system" fn(*mut libc::c_void) -> rust_thread_return;
+
+#[no_stack_check]
+pub extern "system" fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
+    return start_thread(main);
+}
+
+pub mod guard {
+    pub unsafe fn main() -> uint {
+        0
+    }
+
+    pub unsafe fn current() -> uint {
+        0
+    }
+
+    pub unsafe fn init() {
+    }
+}
+
+pub unsafe fn create(stack: uint, p: Box<proc():Send>) -> rust_thread {
+    let arg: *mut libc::c_void = mem::transmute(p);
+    // FIXME On UNIX, we guard against stack sizes that are too small but
+    // that's because pthreads enforces that stacks are at least
+    // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
+    // just that below a certain threshold you can't do anything useful.
+    // That threshold is application and architecture-specific, however.
+    // For now, the only requirement is that it's big enough to hold the
+    // red zone.  Round up to the next 64 kB because that's what the NT
+    // kernel does, might as well make it explicit.  With the current
+    // 20 kB red zone, that makes for a 64 kB minimum stack.
+    let stack_size = (cmp::max(stack, RED_ZONE) + 0xfffe) & (-0xfffe - 1);
+    let ret = CreateThread(ptr::null_mut(), stack_size as libc::size_t,
+                           thread_start, arg, 0, ptr::null_mut());
+
+    if ret as uint == 0 {
+        // be sure to not leak the closure
+        let _p: Box<proc():Send> = mem::transmute(arg);
+        panic!("failed to spawn native thread: {}", ret);
+    }
+    return ret;
+}
+
+pub unsafe fn join(native: rust_thread) {
+    use libc::consts::os::extra::INFINITE;
+    WaitForSingleObject(native, INFINITE);
+}
+
+pub unsafe fn detach(native: rust_thread) {
+    assert!(libc::CloseHandle(native) != 0);
+}
+
+pub unsafe fn yield_now() {
+    // This function will return 0 if there are no other threads to execute,
+    // but this also means that the yield was useless so this isn't really a
+    // case that needs to be worried about.
+    SwitchToThread();
+}
+
+#[allow(non_snake_case)]
+extern "system" {
+    fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
+                    dwStackSize: SIZE_T,
+                    lpStartAddress: StartFn,
+                    lpParameter: LPVOID,
+                    dwCreationFlags: DWORD,
+                    lpThreadId: LPDWORD) -> HANDLE;
+    fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
+    fn SwitchToThread() -> BOOL;
+}
diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs
index 969b322af99..6c8d9639d5c 100644
--- a/src/libstd/sys/windows/thread_local.rs
+++ b/src/libstd/sys/windows/thread_local.rs
@@ -13,8 +13,8 @@ use prelude::*;
 use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
 
 use mem;
-use rustrt;
-use rustrt::exclusive::Exclusive;
+use rt;
+use rt::exclusive::Exclusive;
 use sync::{ONCE_INIT, Once};
 
 pub type Key = DWORD;
@@ -131,7 +131,7 @@ fn init_dtors() {
         DTORS = mem::transmute(dtors);
     }
 
-    rustrt::at_exit(move|| unsafe {
+    rt::at_exit(move|| unsafe {
         mem::transmute::<_, Box<Exclusive<Vec<(Key, Dtor)>>>>(DTORS);
         DTORS = 0 as *mut _;
     });
diff --git a/src/libstd/task.rs b/src/libstd/task.rs
index 324b594209a..127cad186f6 100644
--- a/src/libstd/task.rs
+++ b/src/libstd/task.rs
@@ -53,9 +53,9 @@ use kinds::Send;
 use option::Option;
 use option::Option::{None, Some};
 use result::Result;
-use rustrt::local::Local;
-use rustrt::task::Task;
-use rustrt::task;
+use rt::local::Local;
+use rt::task;
+use rt::task::Task;
 use str::SendStr;
 use string::{String, ToString};
 use thunk::{Thunk};
@@ -252,7 +252,7 @@ pub fn try_future<T,F>(f: F) -> Future<Result<T, Box<Any + Send>>>
 /// Read the name of the current task.
 #[stable]
 pub fn name() -> Option<String> {
-    use rustrt::task::Task;
+    use rt::task::Task;
 
     let task = Local::borrow(None::<Task>);
     match task.name {
@@ -264,7 +264,7 @@ pub fn name() -> Option<String> {
 /// Yield control to the task scheduler.
 #[unstable = "Name will change."]
 pub fn deschedule() {
-    use rustrt::task::Task;
+    use rt::task::Task;
     Task::yield_now();
 }
 
@@ -272,7 +272,7 @@ pub fn deschedule() {
 /// destructor that is run while unwinding the stack after a call to `panic!()`).
 #[unstable = "May move to a different module."]
 pub fn failing() -> bool {
-    use rustrt::task::Task;
+    use rt::task::Task;
     Local::borrow(None::<Task>).unwinder.unwinding()
 }
 
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
index 1268ab8e0cf..b78428d69de 100644
--- a/src/libstd/thread_local/mod.rs
+++ b/src/libstd/thread_local/mod.rs
@@ -446,7 +446,7 @@ mod tests {
     use prelude::*;
 
     use cell::UnsafeCell;
-    use rustrt::thread::Thread;
+    use rt::thread::Thread;
 
     struct Foo(Sender<()>);
 
diff --git a/src/librustrt/thunk.rs b/src/libstd/thunk.rs
index 42e78495990..42e78495990 100644
--- a/src/librustrt/thunk.rs
+++ b/src/libstd/thunk.rs
diff --git a/src/rt/rust_try.ll b/src/rt/rust_try.ll
index 33d2d31a2e0..18b23b4143a 100644
--- a/src/rt/rust_try.ll
+++ b/src/rt/rust_try.ll
@@ -12,7 +12,7 @@
 ; When f(...) returns normally, the return value is null.
 ; When f(...) throws, the return value is a pointer to the caught exception object.
 
-; See also: librustrt/unwind.rs
+; See also: libstd/rt/unwind.rs
 
 define i8* @rust_try(void (i8*,i8*)* %f, i8* %fptr, i8* %env) {
 
diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs
index 3f659f1dbfb..0bfae8498e2 100644
--- a/src/test/run-pass/foreign-call-no-runtime.rs
+++ b/src/test/run-pass/foreign-call-no-runtime.rs
@@ -9,10 +9,9 @@
 // except according to those terms.
 
 extern crate libc;
-extern crate rustrt;
 
 use std::mem;
-use rustrt::thread::Thread;
+use std::rt::thread::Thread;
 
 #[link(name = "rust_test_helpers")]
 extern {
diff --git a/src/test/run-pass/match-ref-binding-in-guard-3256.rs b/src/test/run-pass/match-ref-binding-in-guard-3256.rs
index ac783961b50..9a822ddbbcc 100644
--- a/src/test/run-pass/match-ref-binding-in-guard-3256.rs
+++ b/src/test/run-pass/match-ref-binding-in-guard-3256.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern crate rustrt;
+use std::rt::exclusive;
 
 pub fn main() {
     unsafe {
-        let x = Some(::rustrt::exclusive::Exclusive::new(true));
+        let x = Some(exclusive::Exclusive::new(true));
         match x {
             Some(ref z) if *z.lock() => {
                 assert!(*z.lock());
diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs
index 36b90a9168f..067b0e8dfb4 100644
--- a/src/test/run-pass/running-with-no-runtime.rs
+++ b/src/test/run-pass/running-with-no-runtime.rs
@@ -8,15 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern crate rustrt;
-
 use std::io::process::{Command, ProcessOutput};
 use std::os;
 use std::str;
 use std::rt;
 use std::thunk::Thunk;
 
-use rustrt::unwind::try;
+use std::rt::unwind::try;
 
 #[start]
 fn start(argc: int, argv: *const *const u8) -> int {
diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs
index c8d281a791c..a86aedd757a 100644
--- a/src/test/run-pass/writealias.rs
+++ b/src/test/run-pass/writealias.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern crate rustrt;
+use std::rt::exclusive;
 
 struct Point {x: int, y: int, z: int}
 
@@ -16,7 +16,7 @@ fn f(p: &mut Point) { p.z = 13; }
 
 pub fn main() {
     unsafe {
-        let x = Some(::rustrt::exclusive::Exclusive::new(true));
+        let x = Some(exclusive::Exclusive::new(true));
         match x {
             Some(ref z) if *z.lock() => {
                 assert!(*z.lock());