about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-11-26 13:32:43 -0800
committerbors <bors@rust-lang.org>2013-11-26 13:32:43 -0800
commit35ebf0348905a3a78025af4019e23ab97c86ec34 (patch)
tree3a1a084d2e09d55ed9023320fd8d8b242a35a4d5 /src/libstd/rt
parente9a1869a5f4164d5311963b1b25b05f003d43699 (diff)
parenta5af479bb479a2a4d3289f9feed9ac3ff299a395 (diff)
downloadrust-35ebf0348905a3a78025af4019e23ab97c86ec34.tar.gz
rust-35ebf0348905a3a78025af4019e23ab97c86ec34.zip
auto merge of #10312 : thestinger/rust/thread_local, r=alexcritchton
This provides a building block for fast thread-local storage. It does
not change the safety semantics of `static mut`.

Closes #10310
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/local_ptr.rs106
-rw-r--r--src/libstd/rt/mod.rs4
2 files changed, 105 insertions, 5 deletions
diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs
index eb7d8ef2f5f..e0e8750e146 100644
--- a/src/libstd/rt/local_ptr.rs
+++ b/src/libstd/rt/local_ptr.rs
@@ -17,16 +17,35 @@
 
 use libc::c_void;
 use cast;
+#[cfg(stage0)]
+#[cfg(windows)]
 use ptr;
 use cell::Cell;
 use option::{Option, Some, None};
 use unstable::finally::Finally;
+#[cfg(stage0)]
+#[cfg(windows)]
 use unstable::mutex::{Mutex, MUTEX_INIT};
+#[cfg(stage0)]
+#[cfg(windows)]
 use tls = rt::thread_local_storage;
 
+#[cfg(not(stage0), not(windows), test)]
+#[thread_local]
+pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;
+
+#[cfg(not(stage0), not(windows), not(test))]
+#[thread_local]
+pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void;
+
+#[cfg(stage0)]
+#[cfg(windows)]
 static mut RT_TLS_KEY: tls::Key = -1;
 
 /// Initialize the TLS key. Other ops will fail if this isn't executed first.
+#[inline(never)]
+#[cfg(stage0)]
+#[cfg(windows)]
 pub fn init_tls_key() {
     static mut lock: Mutex = MUTEX_INIT;
     static mut initialized: bool = false;
@@ -41,24 +60,42 @@ pub fn init_tls_key() {
     }
 }
 
+#[cfg(not(stage0), not(windows))]
+pub fn init_tls_key() {}
+
 /// Give a pointer to thread-local storage.
 ///
 /// # Safety note
 ///
 /// Does not validate the pointer type.
 #[inline]
+#[cfg(stage0)]
+#[cfg(windows)]
 pub unsafe fn put<T>(sched: ~T) {
     let key = tls_key();
     let void_ptr: *mut c_void = cast::transmute(sched);
     tls::set(key, void_ptr);
 }
 
+/// Give a pointer to thread-local storage.
+///
+/// # Safety note
+///
+/// Does not validate the pointer type.
+#[inline]
+#[cfg(not(stage0), not(windows))]
+pub unsafe fn put<T>(sched: ~T) {
+    RT_TLS_PTR = cast::transmute(sched)
+}
+
 /// Take ownership of a pointer from thread-local storage.
 ///
 /// # Safety note
 ///
 /// Does not validate the pointer type.
 #[inline]
+#[cfg(stage0)]
+#[cfg(windows)]
 pub unsafe fn take<T>() -> ~T {
     let key = tls_key();
     let void_ptr: *mut c_void = tls::get(key);
@@ -75,8 +112,23 @@ pub unsafe fn take<T>() -> ~T {
 /// # Safety note
 ///
 /// Does not validate the pointer type.
+#[inline]
+#[cfg(not(stage0), not(windows))]
+pub unsafe fn take<T>() -> ~T {
+    let ptr: ~T = cast::transmute(RT_TLS_PTR);
+    RT_TLS_PTR = cast::transmute(0); // can't use `as`, due to type not matching with `cfg(test)`
+    ptr
+}
+
+/// Take ownership of a pointer from thread-local storage.
+///
+/// # Safety note
+///
+/// Does not validate the pointer type.
 /// Leaves the old pointer in TLS for speed.
 #[inline]
+#[cfg(stage0)]
+#[cfg(windows)]
 pub unsafe fn unsafe_take<T>() -> ~T {
     let key = tls_key();
     let void_ptr: *mut c_void = tls::get(key);
@@ -87,7 +139,21 @@ pub unsafe fn unsafe_take<T>() -> ~T {
     return ptr;
 }
 
+/// Take ownership of a pointer from thread-local storage.
+///
+/// # Safety note
+///
+/// Does not validate the pointer type.
+/// Leaves the old pointer in TLS for speed.
+#[inline]
+#[cfg(not(stage0), not(windows))]
+pub unsafe fn unsafe_take<T>() -> ~T {
+    cast::transmute(RT_TLS_PTR)
+}
+
 /// Check whether there is a thread-local pointer installed.
+#[cfg(stage0)]
+#[cfg(windows)]
 pub fn exists() -> bool {
     unsafe {
         match maybe_tls_key() {
@@ -97,6 +163,14 @@ pub fn exists() -> bool {
     }
 }
 
+/// Check whether there is a thread-local pointer installed.
+#[cfg(not(stage0), not(windows))]
+pub fn exists() -> bool {
+    unsafe {
+        RT_TLS_PTR.is_not_null()
+    }
+}
+
 /// Borrow the thread-local value from thread-local storage.
 /// While the value is borrowed it is not available in TLS.
 ///
@@ -119,6 +193,8 @@ pub unsafe fn borrow<T>(f: |&mut T|) {
 ///
 /// Because this leaves the value in thread-local storage it is possible
 /// For the Scheduler pointer to be aliased
+#[cfg(stage0)]
+#[cfg(windows)]
 pub unsafe fn unsafe_borrow<T>() -> *mut T {
     let key = tls_key();
     let void_ptr = tls::get(key);
@@ -128,6 +204,16 @@ pub unsafe fn unsafe_borrow<T>() -> *mut T {
     void_ptr as *mut T
 }
 
+#[cfg(not(stage0), not(windows))]
+pub unsafe fn unsafe_borrow<T>() -> *mut T {
+    if RT_TLS_PTR.is_null() {
+        rtabort!("thread-local pointer is null. bogus!");
+    }
+    RT_TLS_PTR as *mut T
+}
+
+#[cfg(stage0)]
+#[cfg(windows)]
 pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
     match maybe_tls_key() {
         Some(key) => {
@@ -142,7 +228,18 @@ pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
     }
 }
 
+#[cfg(not(stage0), not(windows))]
+pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
+    if RT_TLS_PTR.is_null() {
+        None
+    } else {
+        Some(RT_TLS_PTR as *mut T)
+    }
+}
+
 #[inline]
+#[cfg(stage0)]
+#[cfg(windows)]
 fn tls_key() -> tls::Key {
     match maybe_tls_key() {
         Some(key) => key,
@@ -151,7 +248,8 @@ fn tls_key() -> tls::Key {
 }
 
 #[inline]
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
+#[cfg(not(test), windows)]
 pub fn maybe_tls_key() -> Option<tls::Key> {
     unsafe {
         // NB: This is a little racy because, while the key is
@@ -172,11 +270,9 @@ pub fn maybe_tls_key() -> Option<tls::Key> {
     }
 }
 
-// XXX: The boundary between the running runtime and the testing runtime
-// seems to be fuzzy at the moment, and trying to use two different keys
-// results in disaster. This should not be necessary.
 #[inline]
-#[cfg(test)]
+#[cfg(test, stage0)]
+#[cfg(test, windows)]
 pub fn maybe_tls_key() -> Option<tls::Key> {
     unsafe { ::cast::transmute(::realstd::rt::shouldnt_be_public::maybe_tls_key()) }
 }
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index a8b510cbed7..860b65b20c6 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -95,7 +95,11 @@ pub use self::kill::BlockedTask;
 pub mod shouldnt_be_public {
     pub use super::select::SelectInner;
     pub use super::select::{SelectInner, SelectPortInner};
+    #[cfg(stage0)]
+    #[cfg(windows)]
     pub use super::local_ptr::maybe_tls_key;
+    #[cfg(not(stage0), not(windows))]
+    pub use super::local_ptr::RT_TLS_PTR;
 }
 
 // Internal macros used by the runtime.