port the runtime to #[thread_local]

This commit is contained in:
Daniel Micay 2013-11-06 01:17:04 -05:00
parent 1795ae4e8a
commit 2cf3d8adf2
2 changed files with 105 additions and 5 deletions

View file

@ -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);
@ -70,6 +107,19 @@ pub unsafe fn take<T>() -> ~T {
return ptr;
}
/// Take ownership of a pointer from thread-local storage.
///
/// # 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
@ -77,6 +127,8 @@ pub unsafe fn take<T>() -> ~T {
/// 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.
///
@ -123,6 +197,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);
@ -132,6 +208,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) => {
@ -146,7 +232,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,
@ -155,7 +252,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
@ -176,11 +274,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()) }
}

View file

@ -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.