1 //! Safe implementation of thread-local storage. 2 //! 3 //! This module provides lightweight abstractions for TLS similar to the ones provided by libstd. 4 5 use core::{marker, mem}; 6 7 use shim::thread_destructor; 8 9 /// A thread-local container. 10 pub struct Key<T: 'static> { 11 /// The inner data. 12 inner: T, 13 } 14 15 impl<T: 'static> Key<T> { 16 /// Create a new `Key` wrapper. 17 /// 18 /// # Safety 19 /// 20 /// This is invariant-breaking (assumes thread-safety) and thus unsafe. 21 pub const unsafe fn new(inner: T) -> Key<T> { 22 Key { inner: inner } 23 } 24 25 /// Obtain a reference temporarily. 26 /// 27 /// Due to [the lack of thread lifetimes](https://github.com/rust-lang/rfcs/pull/1705#issuecomment-238015901), we use a closure to make sure no leakage happens. 28 /// 29 /// Having a reference newtype would be unsound, due to the ability to leak a reference to 30 /// another thread. 31 #[inline] 32 pub fn with<F, R>(&'static self, f: F) -> R 33 where F: FnOnce(&T) -> R { 34 // Logging. 35 log!(INTERNAL, "Accessing TLS variable."); 36 37 f(&self.inner) 38 } 39 40 /// Register a TLS destructor on the current thread. 41 /// 42 /// Note that this has to be registered for every thread, it is needed for. 43 // TODO: Make this automatic on `Drop`. 44 #[inline] 45 pub fn register_thread_destructor(&'static self, dtor: extern fn(&T)) { 46 // Logging. 47 log!(INTERNAL, "Registering thread destructor."); 48 49 // This is safe due to sharing memory layout. 50 thread_destructor::register(&self.inner as *const T as *const u8 as *mut u8, 51 unsafe { mem::transmute(dtor) }); 52 } 53 } 54 55 unsafe impl<T> marker::Sync for Key<T> {} 56 57 /// Declare a thread-local static variable. 58 /// 59 /// TLS works by copying the initial data on every new thread creation. This allows access to a 60 /// variable, which is only available for the current thread, meaning that there is no need for 61 /// syncronization. 62 /// 63 /// For this reason, in contrast to other `static`s in Rust, this need not thread-safety, which is 64 /// what this macro "fixes". 65 macro_rules! tls { 66 (static $name:ident: $ty:ty = $val:expr;) => { tls! { #[] static $name: $ty = $val; } }; 67 (#[$($attr:meta),*] static $name:ident: $ty:ty = $val:expr;) => { 68 $(#[$attr])* 69 #[thread_local] 70 static $name: tls::Key<$ty> = unsafe { tls::Key::new($val) }; 71 } 72 } 73