diff --git a/src/libcore/rt/local_ptr.rs b/src/libcore/rt/local_ptr.rs new file mode 100644 index 00000000000..3d706fbbdae --- /dev/null +++ b/src/libcore/rt/local_ptr.rs @@ -0,0 +1,63 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Access to a single thread-local pointer + +use libc::c_void; +use cast; +use option::{Option, Some, None}; +use tls = rt::thread_local_storage; + +/// Initialize the TLS key. Other ops will fail if this isn't executed first. +pub fn init_tls_key() { + unsafe { + rust_initialize_rt_tls_key(); + extern { + fn rust_initialize_rt_tls_key(); + } + } +} + +pub fn tls_key() -> tls::Key { + match maybe_tls_key() { + Some(key) => key, + None => abort!("runtime tls key not initialized") + } +} + +pub fn maybe_tls_key() -> Option { + unsafe { + let key: *mut c_void = rust_get_rt_tls_key(); + let key: &mut tls::Key = cast::transmute(key); + let key = *key; + // Check that the key has been initialized. + + // NB: This is a little racy because, while the key is + // initalized under a mutex and it's assumed to be initalized + // in the Scheduler ctor by any thread that needs to use it, + // we are not accessing the key under a mutex. Threads that + // are not using the new Scheduler but still *want to check* + // whether they are running under a new Scheduler may see a 0 + // value here that is in the process of being initialized in + // another thread. I think this is fine since the only action + // they could take if it was initialized would be to check the + // thread-local value and see that it's not set. + if key != -1 { + return Some(key); + } else { + return None; + } + } +} + +extern { + #[fast_ffi] + fn rust_get_rt_tls_key() -> *mut c_void; +} diff --git a/src/libcore/rt/local_sched.rs b/src/libcore/rt/local_sched.rs index 5f7f8509a7b..6b3bc373d22 100644 --- a/src/libcore/rt/local_sched.rs +++ b/src/libcore/rt/local_sched.rs @@ -18,25 +18,16 @@ use cell::Cell; use rt::sched::Scheduler; use rt::rtio::{EventLoop, IoFactoryObject}; -use tls = rt::thread_local_storage; use unstable::finally::Finally; +use rt::local_ptr; +use tls = rt::thread_local_storage; #[cfg(test)] use rt::uv::uvio::UvEventLoop; -/// Initialize the TLS key. Other ops will fail if this isn't executed first. -pub fn init_tls_key() { - unsafe { - rust_initialize_rt_tls_key(); - extern { - fn rust_initialize_rt_tls_key(); - } - } -} - /// Give the Scheduler to thread-local storage pub fn put(sched: ~Scheduler) { unsafe { - let key = tls_key(); + let key = local_ptr::tls_key(); let void_sched: *mut c_void = cast::transmute(sched); tls::set(key, void_sched); } @@ -45,7 +36,7 @@ pub fn put(sched: ~Scheduler) { /// Take ownership of the Scheduler from thread-local storage pub fn take() -> ~Scheduler { unsafe { - let key = tls_key(); + let key = local_ptr::tls_key(); let void_sched: *mut c_void = tls::get(key); rtassert!(void_sched.is_not_null()); let sched: ~Scheduler = cast::transmute(void_sched); @@ -57,7 +48,7 @@ pub fn take() -> ~Scheduler { /// Check whether there is a thread-local Scheduler attached to the running thread pub fn exists() -> bool { unsafe { - match maybe_tls_key() { + match local_ptr::maybe_tls_key() { Some(key) => tls::get(key).is_not_null(), None => false } @@ -89,7 +80,7 @@ pub fn borrow(f: &fn(&mut Scheduler)) { /// Because this leaves the Scheduler in thread-local storage it is possible /// For the Scheduler pointer to be aliased pub unsafe fn unsafe_borrow() -> *mut Scheduler { - let key = tls_key(); + let key = local_ptr::tls_key(); let mut void_sched: *mut c_void = tls::get(key); rtassert!(void_sched.is_not_null()); { @@ -106,43 +97,6 @@ pub unsafe fn unsafe_borrow_io() -> *mut IoFactoryObject { return io; } -fn tls_key() -> tls::Key { - match maybe_tls_key() { - Some(key) => key, - None => abort!("runtime tls key not initialized") - } -} - -fn maybe_tls_key() -> Option { - unsafe { - let key: *mut c_void = rust_get_rt_tls_key(); - let key: &mut tls::Key = cast::transmute(key); - let key = *key; - // Check that the key has been initialized. - - // NB: This is a little racy because, while the key is - // initalized under a mutex and it's assumed to be initalized - // in the Scheduler ctor by any thread that needs to use it, - // we are not accessing the key under a mutex. Threads that - // are not using the new Scheduler but still *want to check* - // whether they are running under a new Scheduler may see a 0 - // value here that is in the process of being initialized in - // another thread. I think this is fine since the only action - // they could take if it was initialized would be to check the - // thread-local value and see that it's not set. - if key != -1 { - return Some(key); - } else { - return None; - } - } -} - -extern { - #[fast_ffi] - fn rust_get_rt_tls_key() -> *mut c_void; -} - #[test] fn thread_local_scheduler_smoke_test() { let scheduler = ~UvEventLoop::new_scheduler(); diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index 37ac6ad3365..bda44b4c67f 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -85,10 +85,6 @@ pub mod uv; /// or task-local storage. pub mod local; -// FIXME #5248: The import in `sched` doesn't resolve unless this is pub! -/// Bindings to pthread/windows thread-local storage. -pub mod thread_local_storage; - /// A parallel work-stealing deque. mod work_queue; @@ -126,6 +122,15 @@ pub mod tube; /// Simple reimplementation of core::comm pub mod comm; +// FIXME #5248 shouldn't be pub +/// The runtime needs to be able to put a pointer into thread-local storage. +pub mod local_ptr; + +// FIXME #5248: The import in `sched` doesn't resolve unless this is pub! +/// Bindings to pthread/windows thread-local storage. +pub mod thread_local_storage; + + /// Set up a default runtime configuration, given compiler-supplied arguments. /// /// This is invoked by the `start` _language item_ (unstable::lang) to diff --git a/src/libcore/rt/sched.rs b/src/libcore/rt/sched.rs index 0cdc4e9602b..8352993278c 100644 --- a/src/libcore/rt/sched.rs +++ b/src/libcore/rt/sched.rs @@ -11,13 +11,14 @@ use option::*; use sys; use cast::transmute; +use cell::Cell; use super::work_queue::WorkQueue; use super::stack::{StackPool, StackSegment}; use super::rtio::{EventLoop, EventLoopObject}; use super::context::Context; use super::task::Task; -use cell::Cell; +use rt::local_ptr; // A more convenient name for external callers, e.g. `local_sched::take()` pub mod local_sched; @@ -64,8 +65,8 @@ pub impl Scheduler { fn new(event_loop: ~EventLoopObject) -> Scheduler { - // Lazily initialize the scheduler TLS key - local_sched::init_tls_key(); + // Lazily initialize the runtime TLS key + local_ptr::init_tls_key(); Scheduler { event_loop: event_loop,