about summary refs log tree commit diff
path: root/src/libstd/sys/common
diff options
context:
space:
mode:
authorJohannes Hoff <johshoff@gmail.com>2014-12-24 13:22:11 +0100
committerJohannes Hoff <johshoff@gmail.com>2014-12-24 13:22:11 +0100
commit0128159c95d0544e0c30b8b52ce3e7ce348fc114 (patch)
tree8af4db0f2758f86434b895169122a9962fb79b21 /src/libstd/sys/common
parent8f827d33cab1be648120fc8ac34651d9cc079b5e (diff)
parente64a8193b02ce72ef183274994a25eae281cb89c (diff)
downloadrust-0128159c95d0544e0c30b8b52ce3e7ce348fc114.tar.gz
rust-0128159c95d0544e0c30b8b52ce3e7ce348fc114.zip
Merge branch 'master' into cfg_tmp_dir
Conflicts:
	src/etc/rustup.sh
Diffstat (limited to 'src/libstd/sys/common')
-rw-r--r--src/libstd/sys/common/backtrace.rs136
-rw-r--r--src/libstd/sys/common/condvar.rs67
-rw-r--r--src/libstd/sys/common/helper_thread.rs40
-rw-r--r--src/libstd/sys/common/mod.rs23
-rw-r--r--src/libstd/sys/common/mutex.rs62
-rw-r--r--src/libstd/sys/common/net.rs53
-rw-r--r--src/libstd/sys/common/rwlock.rs86
-rw-r--r--src/libstd/sys/common/stack.rs325
-rw-r--r--src/libstd/sys/common/thread.rs35
-rw-r--r--src/libstd/sys/common/thread_info.rs68
-rw-r--r--src/libstd/sys/common/thread_local.rs284
11 files changed, 1131 insertions, 48 deletions
diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs
new file mode 100644
index 00000000000..1d646eb06b1
--- /dev/null
+++ b/src/libstd/sys/common/backtrace.rs
@@ -0,0 +1,136 @@
+// 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 prelude::*;
+
+use io::IoResult;
+
+#[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;
+    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 = inner.slice_to(inner.len() - rest.len()).parse().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(())
+}
diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys/common/condvar.rs
new file mode 100644
index 00000000000..e09d9704029
--- /dev/null
+++ b/src/libstd/sys/common/condvar.rs
@@ -0,0 +1,67 @@
+// 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 time::Duration;
+use sys_common::mutex::{mod, Mutex};
+use sys::condvar as imp;
+
+/// An OS-based condition variable.
+///
+/// This structure is the lowest layer possible on top of the OS-provided
+/// condition variables. It is consequently entirely unsafe to use. It is
+/// recommended to use the safer types at the top level of this crate instead of
+/// this type.
+pub struct Condvar(imp::Condvar);
+
+/// Static initializer for condition variables.
+pub const CONDVAR_INIT: Condvar = Condvar(imp::CONDVAR_INIT);
+
+impl Condvar {
+    /// Creates a new condition variable for use.
+    ///
+    /// Behavior is undefined if the condition variable is moved after it is
+    /// first used with any of the functions below.
+    #[inline]
+    pub unsafe fn new() -> Condvar { Condvar(imp::Condvar::new()) }
+
+    /// Signal one waiter on this condition variable to wake up.
+    #[inline]
+    pub unsafe fn notify_one(&self) { self.0.notify_one() }
+
+    /// Awaken all current waiters on this condition variable.
+    #[inline]
+    pub unsafe fn notify_all(&self) { self.0.notify_all() }
+
+    /// Wait for a signal on the specified mutex.
+    ///
+    /// Behavior is undefined if the mutex is not locked by the current thread.
+    /// Behavior is also undefined if more than one mutex is used concurrently
+    /// on this condition variable.
+    #[inline]
+    pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) }
+
+    /// Wait for a signal on the specified mutex with a timeout duration
+    /// specified by `dur` (a relative time into the future).
+    ///
+    /// Behavior is undefined if the mutex is not locked by the current thread.
+    /// Behavior is also undefined if more than one mutex is used concurrently
+    /// on this condition variable.
+    #[inline]
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        self.0.wait_timeout(mutex::raw(mutex), dur)
+    }
+
+    /// Deallocate all resources associated with this condition variable.
+    ///
+    /// Behavior is undefined if there are current or will be future users of
+    /// this condition variable.
+    #[inline]
+    pub unsafe fn destroy(&self) { self.0.destroy() }
+}
diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs
index 9508d8d9232..421778e2012 100644
--- a/src/libstd/sys/common/helper_thread.rs
+++ b/src/libstd/sys/common/helper_thread.rs
@@ -20,15 +20,15 @@
 //! can be created in the future and there must be no active timers at that
 //! time.
 
-use mem;
-use rustrt::bookkeeping;
-use rustrt::mutex::StaticNativeMutex;
-use rustrt;
+use prelude::*;
+
 use cell::UnsafeCell;
+use mem;
+use sync::{StaticMutex, StaticCondvar};
+use rt;
 use sys::helper_signal;
-use prelude::*;
 
-use task;
+use thread::Thread;
 
 /// A structure for management of a helper thread.
 ///
@@ -39,7 +39,8 @@ use task;
 /// is for static initialization.
 pub struct Helper<M> {
     /// Internal lock which protects the remaining fields
-    pub lock: StaticNativeMutex,
+    pub lock: StaticMutex,
+    pub cond: StaticCondvar,
 
     // You'll notice that the remaining fields are UnsafeCell<T>, and this is
     // because all helper thread operations are done through &self, but we need
@@ -53,6 +54,9 @@ pub struct Helper<M> {
 
     /// Flag if this helper thread has booted and been initialized yet.
     pub initialized: UnsafeCell<bool>,
+
+    /// Flag if this helper thread has shut down
+    pub shutdown: UnsafeCell<bool>,
 }
 
 impl<M: Send> Helper<M> {
@@ -65,9 +69,10 @@ impl<M: Send> Helper<M> {
     /// passed to the helper thread in a separate task.
     ///
     /// This function is safe to be called many times.
-    pub fn boot<T: Send>(&'static self,
-                         f: || -> T,
-                         helper: fn(helper_signal::signal, Receiver<M>, T)) {
+    pub fn boot<T, F>(&'static self, f: F, helper: fn(helper_signal::signal, Receiver<M>, T)) where
+        T: Send,
+        F: FnOnce() -> T,
+    {
         unsafe {
             let _guard = self.lock.lock();
             if !*self.initialized.get() {
@@ -77,13 +82,14 @@ impl<M: Send> Helper<M> {
                 *self.signal.get() = send as uint;
 
                 let t = f();
-                task::spawn(proc() {
-                    bookkeeping::decrement();
+                Thread::spawn(move |:| {
                     helper(receive, rx, t);
-                    self.lock.lock().signal()
-                });
+                    let _g = self.lock.lock();
+                    *self.shutdown.get() = true;
+                    self.cond.notify_one()
+                }).detach();
 
-                rustrt::at_exit(proc() { self.shutdown() });
+                rt::at_exit(move|:| { self.shutdown() });
                 *self.initialized.get() = true;
             }
         }
@@ -119,7 +125,9 @@ impl<M: Send> Helper<M> {
             helper_signal::signal(*self.signal.get() as helper_signal::signal);
 
             // Wait for the child to exit
-            guard.wait();
+            while !*self.shutdown.get() {
+                self.cond.wait(&guard);
+            }
             drop(guard);
 
             // Clean up after ourselves
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs
index cacb128faa5..dc0ad08cdbe 100644
--- a/src/libstd/sys/common/mod.rs
+++ b/src/libstd/sys/common/mod.rs
@@ -13,14 +13,22 @@
 
 use io::{mod, IoError, IoResult};
 use prelude::*;
-use sys::{last_error, retry, fs};
+use sys::{last_error, retry};
 use c_str::CString;
 use num::Int;
 use path::BytesContainer;
 use collections;
 
-pub mod net;
+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_info;
+pub mod thread_local;
 
 // common error constructors
 
@@ -65,7 +73,9 @@ pub fn mkerr_libc<T: Int>(ret: T) -> IoResult<()> {
     }
 }
 
-pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
+pub fn keep_going<F>(data: &[u8], mut f: F) -> i64 where
+    F: FnMut(*const u8, uint) -> i64,
+{
     let origamt = data.len();
     let mut data = data.as_ptr();
     let mut amt = origamt;
@@ -83,10 +93,9 @@ pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
     return (origamt - amt) as i64;
 }
 
-// traits for extracting representations from
-
-pub trait AsFileDesc {
-    fn as_fd(&self) -> &fs::FileDesc;
+// A trait for extracting representations from std::io types
+pub trait AsInner<Inner> {
+    fn as_inner(&self) -> &Inner;
 }
 
 pub trait ProcessConfig<K: BytesContainer, V: BytesContainer> {
diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs
new file mode 100644
index 00000000000..1a8a92a105a
--- /dev/null
+++ b/src/libstd/sys/common/mutex.rs
@@ -0,0 +1,62 @@
+// 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 sys::mutex as imp;
+
+/// An OS-based mutual exclusion lock.
+///
+/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
+/// this mutex is unsafe and it is recommended to instead use the safe wrapper
+/// at the top level of the crate instead of this type.
+pub struct Mutex(imp::Mutex);
+
+/// Constant initializer for statically allocated mutexes.
+pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT);
+
+impl Mutex {
+    /// Creates a newly initialized mutex.
+    ///
+    /// Behavior is undefined if the mutex is moved after the first method is
+    /// called on the mutex.
+    #[inline]
+    pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) }
+
+    /// Lock the mutex blocking the current thread until it is available.
+    ///
+    /// Behavior is undefined if the mutex has been moved between this and any
+    /// previous function call.
+    #[inline]
+    pub unsafe fn lock(&self) { self.0.lock() }
+
+    /// Attempt to lock the mutex without blocking, returning whether it was
+    /// successfully acquired or not.
+    ///
+    /// Behavior is undefined if the mutex has been moved between this and any
+    /// previous function call.
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() }
+
+    /// Unlock the mutex.
+    ///
+    /// Behavior is undefined if the current thread does not actually hold the
+    /// mutex.
+    #[inline]
+    pub unsafe fn unlock(&self) { self.0.unlock() }
+
+    /// Deallocate all resources associated with this mutex.
+    ///
+    /// Behavior is undefined if there are current or will be future users of
+    /// this mutex.
+    #[inline]
+    pub unsafe fn destroy(&self) { self.0.destroy() }
+}
+
+// not meant to be exported to the outside world, just the containing module
+pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }
diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs
index 029fc852742..382f6875b28 100644
--- a/src/libstd/sys/common/net.rs
+++ b/src/libstd/sys/common/net.rs
@@ -8,21 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::SocketStatus::*;
-pub use self::InAddr::*;
+use self::SocketStatus::*;
+use self::InAddr::*;
 
 use alloc::arc::Arc;
 use libc::{mod, c_char, c_int};
 use mem;
 use num::Int;
 use ptr::{mod, null, null_mut};
-use rustrt::mutex;
 use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
 use io::net::addrinfo;
 use io::{IoResult, IoError};
 use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
           wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
           decode_error_detailed};
+use sync::{Mutex, MutexGuard};
 use sys_common::{mod, keep_going, short_write, timeout};
 use prelude::*;
 use cmp;
@@ -344,10 +344,10 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>,
 // [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html
 // [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait
 
-pub fn read<T>(fd: sock_t,
-               deadline: u64,
-               lock: || -> T,
-               read: |bool| -> libc::c_int) -> IoResult<uint> {
+pub fn read<T, L, R>(fd: sock_t, deadline: u64, mut lock: L, mut read: R) -> IoResult<uint> where
+    L: FnMut() -> T,
+    R: FnMut(bool) -> libc::c_int,
+{
     let mut ret = -1;
     if deadline == 0 {
         ret = retry(|| read(false));
@@ -386,12 +386,15 @@ pub fn read<T>(fd: sock_t,
     }
 }
 
-pub fn write<T>(fd: sock_t,
-                deadline: u64,
-                buf: &[u8],
-                write_everything: bool,
-                lock: || -> T,
-                write: |bool, *const u8, uint| -> i64) -> IoResult<uint> {
+pub fn write<T, L, W>(fd: sock_t,
+                      deadline: u64,
+                      buf: &[u8],
+                      write_everything: bool,
+                      mut lock: L,
+                      mut write: W) -> IoResult<uint> where
+    L: FnMut() -> T,
+    W: FnMut(bool, *const u8, uint) -> i64,
+{
     let mut ret = -1;
     let mut written = 0;
     if deadline == 0 {
@@ -557,12 +560,12 @@ struct Inner {
 
     // Unused on Linux, where this lock is not necessary.
     #[allow(dead_code)]
-    lock: mutex::NativeMutex
+    lock: Mutex<()>,
 }
 
 impl Inner {
     fn new(fd: sock_t) -> Inner {
-        Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } }
+        Inner { fd: fd, lock: Mutex::new(()) }
     }
 }
 
@@ -572,7 +575,7 @@ impl Drop for Inner {
 
 pub struct Guard<'a> {
     pub fd: sock_t,
-    pub guard: mutex::LockGuard<'a>,
+    pub guard: MutexGuard<'a, ()>,
 }
 
 #[unsafe_destructor]
@@ -666,7 +669,7 @@ impl TcpStream {
     fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
         let ret = Guard {
             fd: self.fd(),
-            guard: unsafe { self.inner.lock.lock() },
+            guard: self.inner.lock.lock(),
         };
         assert!(set_nonblocking(self.fd(), true).is_ok());
         ret
@@ -674,8 +677,8 @@ impl TcpStream {
 
     pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         let fd = self.fd();
-        let dolock = || self.lock_nonblocking();
-        let doread = |nb| unsafe {
+        let dolock = |&:| self.lock_nonblocking();
+        let doread = |&mut: nb| unsafe {
             let flags = if nb {c::MSG_DONTWAIT} else {0};
             libc::recv(fd,
                        buf.as_mut_ptr() as *mut libc::c_void,
@@ -687,8 +690,8 @@ impl TcpStream {
 
     pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         let fd = self.fd();
-        let dolock = || self.lock_nonblocking();
-        let dowrite = |nb: bool, buf: *const u8, len: uint| unsafe {
+        let dolock = |&:| self.lock_nonblocking();
+        let dowrite = |&: nb: bool, buf: *const u8, len: uint| unsafe {
             let flags = if nb {c::MSG_DONTWAIT} else {0};
             libc::send(fd,
                        buf as *const _,
@@ -805,7 +808,7 @@ impl UdpSocket {
     fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
         let ret = Guard {
             fd: self.fd(),
-            guard: unsafe { self.inner.lock.lock() },
+            guard: self.inner.lock.lock(),
         };
         assert!(set_nonblocking(self.fd(), true).is_ok());
         ret
@@ -822,7 +825,7 @@ impl UdpSocket {
         let mut addrlen: libc::socklen_t =
                 mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
 
-        let dolock = || self.lock_nonblocking();
+        let dolock = |&:| self.lock_nonblocking();
         let n = try!(read(fd, self.read_deadline, dolock, |nb| unsafe {
             let flags = if nb {c::MSG_DONTWAIT} else {0};
             libc::recvfrom(fd,
@@ -843,8 +846,8 @@ impl UdpSocket {
         let dstp = &storage as *const _ as *const libc::sockaddr;
 
         let fd = self.fd();
-        let dolock = || self.lock_nonblocking();
-        let dowrite = |nb, buf: *const u8, len: uint| unsafe {
+        let dolock = |&: | self.lock_nonblocking();
+        let dowrite = |&mut: nb, buf: *const u8, len: uint| unsafe {
             let flags = if nb {c::MSG_DONTWAIT} else {0};
             libc::sendto(fd,
                          buf as *const libc::c_void,
diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs
new file mode 100644
index 00000000000..df016b9e293
--- /dev/null
+++ b/src/libstd/sys/common/rwlock.rs
@@ -0,0 +1,86 @@
+// 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 sys::rwlock as imp;
+
+/// An OS-based reader-writer lock.
+///
+/// This structure is entirely unsafe and serves as the lowest layer of a
+/// cross-platform binding of system rwlocks. It is recommended to use the
+/// safer types at the top level of this crate instead of this type.
+pub struct RWLock(imp::RWLock);
+
+/// Constant initializer for static RWLocks.
+pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT);
+
+impl RWLock {
+    /// Creates a new instance of an RWLock.
+    ///
+    /// Usage of an RWLock is undefined if it is moved after its first use (any
+    /// function calls below).
+    #[inline]
+    pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) }
+
+    /// Acquire shared access to the underlying lock, blocking the current
+    /// thread to do so.
+    ///
+    /// Behavior is undefined if the rwlock has been moved between this and any
+    /// previous methodo call.
+    #[inline]
+    pub unsafe fn read(&self) { self.0.read() }
+
+    /// Attempt to acquire shared access to this lock, returning whether it
+    /// succeeded or not.
+    ///
+    /// This function does not block the current thread.
+    ///
+    /// Behavior is undefined if the rwlock has been moved between this and any
+    /// previous methodo call.
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool { self.0.try_read() }
+
+    /// Acquire write access to the underlying lock, blocking the current thread
+    /// to do so.
+    ///
+    /// Behavior is undefined if the rwlock has been moved between this and any
+    /// previous methodo call.
+    #[inline]
+    pub unsafe fn write(&self) { self.0.write() }
+
+    /// Attempt to acquire exclusive access to this lock, returning whether it
+    /// succeeded or not.
+    ///
+    /// This function does not block the current thread.
+    ///
+    /// Behavior is undefined if the rwlock has been moved between this and any
+    /// previous methodo call.
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool { self.0.try_write() }
+
+    /// Unlock previously acquired shared access to this lock.
+    ///
+    /// Behavior is undefined if the current thread does not have shared access.
+    #[inline]
+    pub unsafe fn read_unlock(&self) { self.0.read_unlock() }
+
+    /// Unlock previously acquired exclusive access to this lock.
+    ///
+    /// Behavior is undefined if the current thread does not currently have
+    /// exclusive access.
+    #[inline]
+    pub unsafe fn write_unlock(&self) { self.0.write_unlock() }
+
+    /// Destroy OS-related resources with this RWLock.
+    ///
+    /// Behavior is undefined if there are any currently active users of this
+    /// lock.
+    #[inline]
+    pub unsafe fn destroy(&self) { self.0.destroy() }
+}
diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs
new file mode 100644
index 00000000000..2a88e20c8fa
--- /dev/null
+++ b/src/libstd/sys/common/stack.rs
@@ -0,0 +1,325 @@
+// 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.
+
+//! Rust stack-limit management
+//!
+//! Currently Rust uses a segmented-stack-like scheme in order to detect stack
+//! overflow for rust tasks. In this scheme, the prologue of all functions are
+//! preceded with a check to see whether the current stack limits are being
+//! exceeded.
+//!
+//! This module provides the functionality necessary in order to manage these
+//! stack limits (which are stored in platform-specific locations). The
+//! functions here are used at the borders of the task lifetime in order to
+//! manage these limits.
+//!
+//! This function is an unstable module because this scheme for stack overflow
+//! detection is not guaranteed to continue in the future. Usage of this module
+//! is discouraged unless absolutely necessary.
+
+// iOS related notes
+//
+// It is possible to implement it using idea from
+// http://www.opensource.apple.com/source/Libc/Libc-825.40.1/pthreads/pthread_machdep.h
+//
+// In short: _pthread_{get,set}_specific_direct allows extremely fast
+// access, exactly what is required for segmented stack
+// There is a pool of reserved slots for Apple internal use (0..119)
+// First dynamic allocated pthread key starts with 257 (on iOS7)
+// So using slot 149 should be pretty safe ASSUMING space is reserved
+// for every key < first dynamic key
+//
+// There is also an opportunity to steal keys reserved for Garbage Collection
+// ranges 80..89 and 110..119, especially considering the fact Garbage Collection
+// never supposed to work on iOS. But as everybody knows it - there is a chance
+// that those slots will be re-used, like it happened with key 95 (moved from
+// JavaScriptCore to CoreText)
+//
+// Unfortunately Apple rejected patch to LLVM which generated
+// corresponding prolog, decision was taken to disable segmented
+// stack support on iOS.
+
+pub const RED_ZONE: uint = 20 * 1024;
+
+/// This function is invoked from rust's current __morestack function. Segmented
+/// stacks are currently not enabled as segmented stacks, but rather one giant
+/// stack segment. This means that whenever we run out of stack, we want to
+/// truly consider it to be stack overflow rather than allocating a new stack.
+#[cfg(not(test))] // in testing, use the original libstd's version
+#[lang = "stack_exhausted"]
+extern fn stack_exhausted() {
+    use intrinsics;
+
+    unsafe {
+        // We're calling this function because the stack just ran out. We need
+        // to call some other rust functions, but if we invoke the functions
+        // right now it'll just trigger this handler being called again. In
+        // order to alleviate this, we move the stack limit to be inside of the
+        // red zone that was allocated for exactly this reason.
+        let limit = get_sp_limit();
+        record_sp_limit(limit - RED_ZONE / 2);
+
+        // This probably isn't the best course of action. Ideally one would want
+        // to unwind the stack here instead of just aborting the entire process.
+        // This is a tricky problem, however. There's a few things which need to
+        // be considered:
+        //
+        //  1. We're here because of a stack overflow, yet unwinding will run
+        //     destructors and hence arbitrary code. What if that code overflows
+        //     the stack? One possibility is to use the above allocation of an
+        //     extra 10k to hope that we don't hit the limit, and if we do then
+        //     abort the whole program. Not the best, but kind of hard to deal
+        //     with unless we want to switch stacks.
+        //
+        //  2. LLVM will optimize functions based on whether they can unwind or
+        //     not. It will flag functions with 'nounwind' if it believes that
+        //     the function cannot trigger unwinding, but if we do unwind on
+        //     stack overflow then it means that we could unwind in any function
+        //     anywhere. We would have to make sure that LLVM only places the
+        //     nounwind flag on functions which don't call any other functions.
+        //
+        //  3. The function that overflowed may have owned arguments. These
+        //     arguments need to have their destructors run, but we haven't even
+        //     begun executing the function yet, so unwinding will not run the
+        //     any landing pads for these functions. If this is ignored, then
+        //     the arguments will just be leaked.
+        //
+        // Exactly what to do here is a very delicate topic, and is possibly
+        // still up in the air for what exactly to do. Some relevant issues:
+        //
+        //  #3555 - out-of-stack failure leaks arguments
+        //  #3695 - should there be a stack limit?
+        //  #9855 - possible strategies which could be taken
+        //  #9854 - unwinding on windows through __morestack has never worked
+        //  #2361 - possible implementation of not using landing pads
+
+        ::rt::util::report_overflow();
+
+        intrinsics::abort();
+    }
+}
+
+// Windows maintains a record of upper and lower stack bounds in the Thread Information
+// Block (TIB), and some syscalls do check that addresses which are supposed to be in
+// the stack, indeed lie between these two values.
+// (See https://github.com/rust-lang/rust/issues/3445#issuecomment-26114839)
+//
+// When using Rust-managed stacks (libgreen), we must maintain these values accordingly.
+// For OS-managed stacks (libnative), we let the OS manage them for us.
+//
+// On all other platforms both variants behave identically.
+
+#[inline(always)]
+pub unsafe fn record_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) {
+    record_sp_limit(stack_lo + RED_ZONE);
+}
+
+#[inline(always)]
+pub unsafe fn record_rust_managed_stack_bounds(stack_lo: uint, stack_hi: uint) {
+    // When the old runtime had segmented stacks, it used a calculation that was
+    // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
+    // symbol resolution, llvm function calls, etc. In theory this red zone
+    // value is 0, but it matters far less when we have gigantic stacks because
+    // we don't need to be so exact about our stack budget. The "fudge factor"
+    // was because LLVM doesn't emit a stack check for functions < 256 bytes in
+    // size. Again though, we have giant stacks, so we round all these
+    // calculations up to the nice round number of 20k.
+    record_sp_limit(stack_lo + RED_ZONE);
+
+    return target_record_stack_bounds(stack_lo, stack_hi);
+
+    #[cfg(not(windows))] #[inline(always)]
+    unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {}
+
+    #[cfg(all(windows, target_arch = "x86"))] #[inline(always)]
+    unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
+        // stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom)
+        asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile");
+        asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile");
+    }
+    #[cfg(all(windows, target_arch = "x86_64"))] #[inline(always)]
+    unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
+        // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
+        asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
+        asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
+    }
+}
+
+/// Records the current limit of the stack as specified by `end`.
+///
+/// This is stored in an OS-dependent location, likely inside of the thread
+/// local storage. The location that the limit is stored is a pre-ordained
+/// location because it's where LLVM has emitted code to check.
+///
+/// Note that this cannot be called under normal circumstances. This function is
+/// changing the stack limit, so upon returning any further function calls will
+/// possibly be triggering the morestack logic if you're not careful.
+///
+/// Also note that this and all of the inside functions are all flagged as
+/// "inline(always)" because they're messing around with the stack limits.  This
+/// would be unfortunate for the functions themselves to trigger a morestack
+/// invocation (if they were an actual function call).
+#[inline(always)]
+pub unsafe fn record_sp_limit(limit: uint) {
+    return target_record_sp_limit(limit);
+
+    // x86-64
+    #[cfg(all(target_arch = "x86_64",
+              any(target_os = "macos", target_os = "ios")))]
+    #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $$0x60+90*8, %rsi
+              movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "windows"))] #[inline(always)]
+    unsafe fn target_record_sp_limit(_: uint) {
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "freebsd"))] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "dragonfly"))] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:32" :: "r"(limit) :: "volatile")
+    }
+
+    // x86
+    #[cfg(all(target_arch = "x86",
+              any(target_os = "macos", target_os = "ios")))]
+    #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movl $$0x48+90*4, %eax
+              movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
+    }
+    #[cfg(all(target_arch = "x86",
+              any(target_os = "linux", target_os = "freebsd")))]
+    #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(all(target_arch = "x86", target_os = "windows"))] #[inline(always)]
+    unsafe fn target_record_sp_limit(_: uint) {
+    }
+
+    // mips, arm - Some brave soul can port these to inline asm, but it's over
+    //             my head personally
+    #[cfg(any(target_arch = "mips",
+              target_arch = "mipsel",
+              all(target_arch = "arm", not(target_os = "ios"))))]
+    #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        use libc::c_void;
+        return record_sp_limit(limit as *const c_void);
+        extern {
+            fn record_sp_limit(limit: *const c_void);
+        }
+    }
+
+    // iOS segmented stack is disabled for now, see related notes
+    #[cfg(all(target_arch = "arm", target_os = "ios"))] #[inline(always)]
+    unsafe fn target_record_sp_limit(_: uint) {
+    }
+}
+
+/// The counterpart of the function above, this function will fetch the current
+/// stack limit stored in TLS.
+///
+/// Note that all of these functions are meant to be exact counterparts of their
+/// brethren above, except that the operands are reversed.
+///
+/// As with the setter, this function does not have a __morestack header and can
+/// therefore be called in a "we're out of stack" situation.
+#[inline(always)]
+pub unsafe fn get_sp_limit() -> uint {
+    return target_get_sp_limit();
+
+    // x86-64
+    #[cfg(all(target_arch = "x86_64",
+              any(target_os = "macos", target_os = "ios")))]
+    #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq $$0x60+90*8, %rsi
+              movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
+        return limit;
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "windows"))] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        return 1024;
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "freebsd"))] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(all(target_arch = "x86_64", target_os = "dragonfly"))] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq %fs:32, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+
+
+    // x86
+    #[cfg(all(target_arch = "x86",
+              any(target_os = "macos", target_os = "ios")))]
+    #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movl $$0x48+90*4, %eax
+              movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
+        return limit;
+    }
+    #[cfg(all(target_arch = "x86",
+              any(target_os = "linux", target_os = "freebsd")))]
+    #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(all(target_arch = "x86", target_os = "windows"))] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        return 1024;
+    }
+
+    // mips, arm - Some brave soul can port these to inline asm, but it's over
+    //             my head personally
+    #[cfg(any(target_arch = "mips",
+              target_arch = "mipsel",
+              all(target_arch = "arm", not(target_os = "ios"))))]
+    #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        use libc::c_void;
+        return get_sp_limit() as uint;
+        extern {
+            fn get_sp_limit() -> *const c_void;
+        }
+    }
+
+    // iOS doesn't support segmented stacks yet. This function might
+    // be called by runtime though so it is unsafe to mark it as
+    // unreachable, let's return a fixed constant.
+    #[cfg(all(target_arch = "arm", target_os = "ios"))] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        1024
+    }
+}
diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs
new file mode 100644
index 00000000000..048e33399a3
--- /dev/null
+++ b/src/libstd/sys/common/thread.rs
@@ -0,0 +1,35 @@
+// 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 thunk::Thunk;
+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<Thunk> = mem::transmute(main);
+        f.invoke(());
+        drop(handler);
+        mem::transmute(0 as thread::rust_thread_return)
+    }
+}
diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs
new file mode 100644
index 00000000000..dc21feb17a8
--- /dev/null
+++ b/src/libstd/sys/common/thread_info.rs
@@ -0,0 +1,68 @@
+// 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 thread::Thread;
+use cell::RefCell;
+use string::String;
+
+struct ThreadInfo {
+    // This field holds the known bounds of the stack in (lo, hi)
+    // form. Not all threads necessarily know their precise bounds,
+    // hence this is optional.
+    stack_bounds: (uint, uint),
+    stack_guard: uint,
+    thread: Thread,
+}
+
+thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
+
+impl ThreadInfo {
+    fn with<R>(f: |&mut ThreadInfo| -> R) -> R {
+        if THREAD_INFO.destroyed() {
+            panic!("Use of std::thread::Thread::current() is not possible after \
+                    the thread's local data has been destroyed");
+        }
+
+        THREAD_INFO.with(|c| {
+            if c.borrow().is_none() {
+                *c.borrow_mut() = Some(ThreadInfo {
+                    stack_bounds: (0, 0),
+                    stack_guard: 0,
+                    thread: NewThread::new(None),
+                })
+            }
+            f(c.borrow_mut().as_mut().unwrap())
+        })
+    }
+}
+
+pub fn current_thread() -> Thread {
+    ThreadInfo::with(|info| info.thread.clone())
+}
+
+pub fn stack_guard() -> uint {
+    ThreadInfo::with(|info| info.stack_guard)
+}
+
+pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) {
+    THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
+    THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
+        stack_bounds: stack_bounds,
+        stack_guard: stack_guard,
+        thread: thread,
+    }));
+}
+
+// a hack to get around privacy restrictions; implemented by `std::thread::Thread`
+pub trait NewThread {
+    fn new(name: Option<String>) -> Self;
+}
diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs
new file mode 100644
index 00000000000..fe7a7d8d037
--- /dev/null
+++ b/src/libstd/sys/common/thread_local.rs
@@ -0,0 +1,284 @@
+// 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.
+
+//! OS-based thread local storage
+//!
+//! This module provides an implementation of OS-based thread local storage,
+//! using the native OS-provided facilities (think `TlsAlloc` or
+//! `pthread_setspecific`). The interface of this differs from the other types
+//! of thread-local-storage provided in this crate in that OS-based TLS can only
+//! get/set pointers,
+//!
+//! This module also provides two flavors of TLS. One is intended for static
+//! initialization, and does not contain a `Drop` implementation to deallocate
+//! the OS-TLS key. The other is a type which does implement `Drop` and hence
+//! has a safe interface.
+//!
+//! # Usage
+//!
+//! This module should likely not be used directly unless other primitives are
+//! being built on. types such as `thread_local::scoped::Key` are likely much
+//! more useful in practice than this OS-based version which likely requires
+//! unsafe code to interoperate with.
+//!
+//! # Example
+//!
+//! Using a dynamically allocated TLS key. Note that this key can be shared
+//! among many threads via an `Arc`.
+//!
+//! ```rust,ignore
+//! let key = Key::new(None);
+//! assert!(key.get().is_null());
+//! key.set(1 as *mut u8);
+//! assert!(!key.get().is_null());
+//!
+//! drop(key); // deallocate this TLS slot.
+//! ```
+//!
+//! Sometimes a statically allocated key is either required or easier to work
+//! with, however.
+//!
+//! ```rust,ignore
+//! static KEY: StaticKey = INIT;
+//!
+//! unsafe {
+//!     assert!(KEY.get().is_null());
+//!     KEY.set(1 as *mut u8);
+//! }
+//! ```
+
+#![allow(non_camel_case_types)]
+
+use prelude::*;
+
+use sync::atomic::{mod, AtomicUint};
+use sync::{Mutex, Once, ONCE_INIT};
+
+use sys::thread_local as imp;
+
+/// A type for TLS keys that are statically allocated.
+///
+/// This type is entirely `unsafe` to use as it does not protect against
+/// use-after-deallocation or use-during-deallocation.
+///
+/// The actual OS-TLS key is lazily allocated when this is used for the first
+/// time. The key is also deallocated when the Rust runtime exits or `destroy`
+/// is called, whichever comes first.
+///
+/// # Example
+///
+/// ```ignore
+/// use tls::os::{StaticKey, INIT};
+///
+/// static KEY: StaticKey = INIT;
+///
+/// unsafe {
+///     assert!(KEY.get().is_null());
+///     KEY.set(1 as *mut u8);
+/// }
+/// ```
+pub struct StaticKey {
+    /// Inner static TLS key (internals), created with by `INIT_INNER` in this
+    /// module.
+    pub inner: StaticKeyInner,
+    /// Destructor for the TLS value.
+    ///
+    /// See `Key::new` for information about when the destructor runs and how
+    /// it runs.
+    pub dtor: Option<unsafe extern fn(*mut u8)>,
+}
+
+/// Inner contents of `StaticKey`, created by the `INIT_INNER` constant.
+pub struct StaticKeyInner {
+    key: AtomicUint,
+}
+
+/// A type for a safely managed OS-based TLS slot.
+///
+/// This type allocates an OS TLS key when it is initialized and will deallocate
+/// the key when it falls out of scope. When compared with `StaticKey`, this
+/// type is entirely safe to use.
+///
+/// Implementations will likely, however, contain unsafe code as this type only
+/// operates on `*mut u8`, an unsafe pointer.
+///
+/// # Example
+///
+/// ```rust,ignore
+/// use tls::os::Key;
+///
+/// let key = Key::new(None);
+/// assert!(key.get().is_null());
+/// key.set(1 as *mut u8);
+/// assert!(!key.get().is_null());
+///
+/// drop(key); // deallocate this TLS slot.
+/// ```
+pub struct Key {
+    key: imp::Key,
+}
+
+/// Constant initialization value for static TLS keys.
+///
+/// This value specifies no destructor by default.
+pub const INIT: StaticKey = StaticKey {
+    inner: INIT_INNER,
+    dtor: None,
+};
+
+/// Constant initialization value for the inner part of static TLS keys.
+///
+/// This value allows specific configuration of the destructor for a TLS key.
+pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
+    key: atomic::INIT_ATOMIC_UINT,
+};
+
+static INIT_KEYS: Once = ONCE_INIT;
+static mut KEYS: *mut Mutex<Vec<imp::Key>> = 0 as *mut _;
+
+impl StaticKey {
+    /// Gets the value associated with this TLS key
+    ///
+    /// This will lazily allocate a TLS key from the OS if one has not already
+    /// been allocated.
+    #[inline]
+    pub unsafe fn get(&self) -> *mut u8 { imp::get(self.key()) }
+
+    /// Sets this TLS key to a new value.
+    ///
+    /// This will lazily allocate a TLS key from the OS if one has not already
+    /// been allocated.
+    #[inline]
+    pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }
+
+    /// Deallocates this OS TLS key.
+    ///
+    /// This function is unsafe as there is no guarantee that the key is not
+    /// currently in use by other threads or will not ever be used again.
+    ///
+    /// Note that this does *not* run the user-provided destructor if one was
+    /// specified at definition time. Doing so must be done manually.
+    pub unsafe fn destroy(&self) {
+        match self.inner.key.swap(0, atomic::SeqCst) {
+            0 => {}
+            n => { imp::destroy(n as imp::Key) }
+        }
+    }
+
+    #[inline]
+    unsafe fn key(&self) -> imp::Key {
+        match self.inner.key.load(atomic::Relaxed) {
+            0 => self.lazy_init() as imp::Key,
+            n => n as imp::Key
+        }
+    }
+
+    unsafe fn lazy_init(&self) -> uint {
+        // POSIX allows the key created here to be 0, but the compare_and_swap
+        // below relies on using 0 as a sentinel value to check who won the
+        // race to set the shared TLS key. As far as I know, there is no
+        // guaranteed value that cannot be returned as a posix_key_create key,
+        // so there is no value we can initialize the inner key with to
+        // prove that it has not yet been set. As such, we'll continue using a
+        // value of 0, but with some gyrations to make sure we have a non-0
+        // value returned from the creation routine.
+        // FIXME: this is clearly a hack, and should be cleaned up.
+        let key1 = imp::create(self.dtor);
+        let key = if key1 != 0 {
+            key1
+        } else {
+            let key2 = imp::create(self.dtor);
+            imp::destroy(key1);
+            key2
+        };
+        assert!(key != 0);
+        match self.inner.key.compare_and_swap(0, key as uint, atomic::SeqCst) {
+            // The CAS succeeded, so we've created the actual key
+            0 => key as uint,
+            // If someone beat us to the punch, use their key instead
+            n => { imp::destroy(key); n }
+        }
+    }
+}
+
+impl Key {
+    /// Create a new managed OS TLS key.
+    ///
+    /// This key will be deallocated when the key falls out of scope.
+    ///
+    /// The argument provided is an optionally-specified destructor for the
+    /// value of this TLS key. When a thread exits and the value for this key
+    /// is non-null the destructor will be invoked. The TLS value will be reset
+    /// to null before the destructor is invoked.
+    ///
+    /// Note that the destructor will not be run when the `Key` goes out of
+    /// scope.
+    #[inline]
+    pub fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+        Key { key: unsafe { imp::create(dtor) } }
+    }
+
+    /// See StaticKey::get
+    #[inline]
+    pub fn get(&self) -> *mut u8 {
+        unsafe { imp::get(self.key) }
+    }
+
+    /// See StaticKey::set
+    #[inline]
+    pub fn set(&self, val: *mut u8) {
+        unsafe { imp::set(self.key, val) }
+    }
+}
+
+impl Drop for Key {
+    fn drop(&mut self) {
+        unsafe { imp::destroy(self.key) }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::{Key, StaticKey, INIT_INNER};
+
+    fn assert_sync<T: Sync>() {}
+    fn assert_send<T: Send>() {}
+
+    #[test]
+    fn smoke() {
+        assert_sync::<Key>();
+        assert_send::<Key>();
+
+        let k1 = Key::new(None);
+        let k2 = Key::new(None);
+        assert!(k1.get().is_null());
+        assert!(k2.get().is_null());
+        k1.set(1 as *mut _);
+        k2.set(2 as *mut _);
+        assert_eq!(k1.get() as uint, 1);
+        assert_eq!(k2.get() as uint, 2);
+    }
+
+    #[test]
+    fn statik() {
+        static K1: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };
+        static K2: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };
+
+        unsafe {
+            assert!(K1.get().is_null());
+            assert!(K2.get().is_null());
+            K1.set(1 as *mut _);
+            K2.set(2 as *mut _);
+            assert_eq!(K1.get() as uint, 1);
+            assert_eq!(K2.get() as uint, 2);
+        }
+    }
+}