1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Thread local storage
13 //! This module provides an implementation of thread local storage for Rust
14 //! programs. Thread local storage is a method of storing data into a global
15 //! variable which each thread in the program will have its own copy of.
16 //! Threads do not share this data, so accesses do not need to be synchronized.
18 //! At a high level, this module provides two variants of storage:
20 //! * Owning thread local storage. This is a type of thread local key which
21 //! owns the value that it contains, and will destroy the value when the
22 //! thread exits. This variant is created with the `thread_local!` macro and
23 //! can contain any value which is `'static` (no borrowed pointers.
25 //! * Scoped thread local storage. This type of key is used to store a reference
26 //! to a value into local storage temporarily for the scope of a function
27 //! call. There are no restrictions on what types of values can be placed
30 //! Both forms of thread local storage provide an accessor function, `with`,
31 //! which will yield a shared reference to the value to the specified
32 //! closure. Thread local keys only allow shared access to values as there is no
33 //! way to guarantee uniqueness if a mutable borrow was allowed. Most values
34 //! will want to make use of some form of **interior mutability** through the
35 //! `Cell` or `RefCell` types.
44 // Sure wish we had macro hygiene, no?
45 #[doc(hidden)] pub use self::imp::Key as KeyInner;
46 #[doc(hidden)] pub use self::imp::destroy_value;
47 #[doc(hidden)] pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER;
48 #[doc(hidden)] pub use sys_common::thread_local::StaticKey as OsStaticKey;
52 /// A thread local storage key which owns its contents.
54 /// This key uses the fastest possible implementation available to it for the
55 /// target platform. It is instantiated with the `thread_local!` macro and the
56 /// primary method is the `with` method.
58 /// The `with` method yields a reference to the contained value which cannot be
59 /// sent across tasks or escape the given closure.
61 /// # Initialization and Destruction
63 /// Initialization is dynamically performed on the first call to `with()`
64 /// within a thread, and values support destructors which will be run when a
70 /// use std::cell::RefCell;
72 /// thread_local!(static FOO: RefCell<uint> = RefCell::new(1));
75 /// assert_eq!(*f.borrow(), 1);
76 /// *f.borrow_mut() = 2;
79 /// // each thread starts out with the initial value of 1
82 /// assert_eq!(*f.borrow(), 1);
83 /// *f.borrow_mut() = 3;
87 /// // we retain our original value of 2 despite the child thread
89 /// assert_eq!(*f.borrow(), 2);
93 // The key itself may be tagged with #[thread_local], and this `Key` is
94 // stored as a `static`, and it's not valid for a static to reference the
95 // address of another thread_local static. For this reason we kinda wonkily
96 // work around this by generating a shim function which will give us the
97 // address of the inner TLS key at runtime.
99 // This is trivially devirtualizable by LLVM because we never store anything
100 // to this field and rustc can declare the `static` as constant as well.
102 pub inner: fn() -> &'static KeyInner<UnsafeCell<Option<T>>>,
104 // initialization routine to invoke to create a value
109 /// Declare a new thread local storage key of type `std::thread_local::Key`.
112 macro_rules! thread_local(
113 (static $name:ident: $t:ty = $init:expr) => (
114 static $name: ::std::thread_local::Key<$t> = {
115 use std::cell::UnsafeCell as __UnsafeCell;
116 use std::thread_local::KeyInner as __KeyInner;
117 use std::option::Option as __Option;
118 use std::option::None as __None;
120 __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
121 __UnsafeCell { value: __None }
123 fn __init() -> $t { $init }
124 fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
127 ::std::thread_local::Key { inner: __getit, init: __init }
130 (pub static $name:ident: $t:ty = $init:expr) => (
131 pub static $name: ::std::thread_local::Key<$t> = {
132 use std::cell::UnsafeCell as __UnsafeCell;
133 use std::thread_local::KeyInner as __KeyInner;
134 use std::option::Option as __Option;
135 use std::option::None as __None;
137 __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
138 __UnsafeCell { value: __None }
140 fn __init() -> $t { $init }
141 fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
144 ::std::thread_local::Key { inner: __getit, init: __init }
151 // When cross compiling, rustc will load plugins and macros from the *host*
152 // platform before search for macros from the target platform. This is primarily
153 // done to detect, for example, plugins. Ideally the macro below would be
154 // defined once per module below, but unfortunately this means we have the
155 // following situation:
157 // 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
158 // will inject #[thread_local] statics.
159 // 2. We then try to compile a program for arm-linux-androideabi
160 // 3. The compiler has a host of linux and a target of android, so it loads
161 // macros from the *linux* libstd.
162 // 4. The macro generates a #[thread_local] field, but the android libstd does
163 // not use #[thread_local]
164 // 5. Compile error about structs with wrong fields.
166 // To get around this, we're forced to inject the #[cfg] logic into the macro
170 macro_rules! __thread_local_inner(
171 (static $name:ident: $t:ty = $init:expr) => (
172 #[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)]
173 static $name: ::std::thread_local::KeyInner<$t> =
174 __thread_local_inner!($init, $t);
176 (pub static $name:ident: $t:ty = $init:expr) => (
177 #[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)]
178 pub static $name: ::std::thread_local::KeyInner<$t> =
179 __thread_local_inner!($init, $t);
181 ($init:expr, $t:ty) => ({
182 #[cfg(any(target_os = "macos", target_os = "linux"))]
183 const INIT: ::std::thread_local::KeyInner<$t> = {
184 ::std::thread_local::KeyInner {
185 inner: ::std::cell::UnsafeCell { value: $init },
186 dtor_registered: ::std::cell::UnsafeCell { value: false },
187 dtor_running: ::std::cell::UnsafeCell { value: false },
188 marker: ::std::kinds::marker::NoCopy,
192 #[cfg(not(any(target_os = "macos", target_os = "linux")))]
193 const INIT: ::std::thread_local::KeyInner<$t> = {
194 unsafe extern fn __destroy(ptr: *mut u8) {
195 ::std::thread_local::destroy_value::<$t>(ptr);
197 ::std::thread_local::KeyInner {
198 inner: ::std::cell::UnsafeCell { value: $init },
199 os: ::std::thread_local::OsStaticKey {
200 inner: ::std::thread_local::OS_INIT_INNER,
201 dtor: ::std::option::Some(__destroy),
210 impl<T: 'static> Key<T> {
211 /// Acquire a reference to the value in this TLS key.
213 /// This will lazily initialize the value if this thread has not referenced
218 /// This function will `panic!()` if the key currently has its
219 /// destructor running, and it **may** panic if the destructor has
220 /// previously been run for this thread.
221 pub fn with<R>(&'static self, f: |&T| -> R) -> R {
222 let slot = (self.inner)();
224 let slot = slot.get().expect("cannot access a TLS value during or \
225 after it is destroyed");
226 if (*slot.get()).is_none() {
227 *slot.get() = Some((self.init)());
229 f((*slot.get()).as_ref().unwrap())
233 /// Test this TLS key to determine whether its value has been destroyed for
234 /// the current thread or not.
236 /// This will not initialize the key if it is not already initialized.
237 pub fn destroyed(&'static self) -> bool {
238 unsafe { (self.inner)().get().is_none() }
242 #[cfg(any(target_os = "macos", target_os = "linux"))]
246 use cell::UnsafeCell;
253 // Place the inner bits in an `UnsafeCell` to currently get around the
254 // "only Sync statics" restriction. This allows any type to be placed in
257 // Note that all access requires `T: 'static` so it can't be a type with
258 // any borrowed pointers still.
259 pub inner: UnsafeCell<T>,
261 // Metadata to keep track of the state of the destructor. Remember that
262 // these variables are thread-local, not global.
263 pub dtor_registered: UnsafeCell<bool>, // should be Cell
264 pub dtor_running: UnsafeCell<bool>, // should be Cell
266 // These shouldn't be copied around.
267 pub marker: marker::NoCopy,
272 pub unsafe fn get(&'static self) -> Option<&'static T> {
273 if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
276 self.register_dtor();
277 Some(&*self.inner.get())
280 unsafe fn register_dtor(&self) {
281 if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
285 register_dtor(self as *const _ as *mut u8,
287 *self.dtor_registered.get() = true;
291 // Since what appears to be glibc 2.18 this symbol has been shipped which
292 // GCC and clang both use to invoke destructors in thread_local globals, so
293 // let's do the same!
295 // Note, however, that we run on lots older linuxes, as well as cross
296 // compiling from a newer linux to an older linux, so we also have a
297 // fallback implementation to use as well.
299 // Due to rust-lang/rust#18804, make sure this is not generic!
300 #[cfg(target_os = "linux")]
301 unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
304 use sys_common::thread_local as os;
307 static __dso_handle: *mut u8;
308 #[linkage = "extern_weak"]
309 static __cxa_thread_atexit_impl: *const ();
311 if !__cxa_thread_atexit_impl.is_null() {
312 type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
314 dso_handle: *mut u8) -> libc::c_int;
315 mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
316 (dtor, t, __dso_handle);
320 // The fallback implementation uses a vanilla OS-based TLS key to track
321 // the list of destructors that need to be run for this thread. The key
322 // then has its own destructor which runs all the other destructors.
324 // The destructor for DTORS is a little special in that it has a `while`
325 // loop to continuously drain the list of registered destructors. It
326 // *should* be the case that this loop always terminates because we
327 // provide the guarantee that a TLS key cannot be set after it is
328 // flagged for destruction.
329 static DTORS: os::StaticKey = os::StaticKey {
330 inner: os::INIT_INNER,
331 dtor: Some(run_dtors),
333 type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
334 if DTORS.get().is_null() {
335 let v: Box<List> = box Vec::new();
336 DTORS.set(mem::transmute(v));
338 let list: &mut List = &mut *(DTORS.get() as *mut List);
339 list.push((t, dtor));
341 unsafe extern fn run_dtors(mut ptr: *mut u8) {
342 while !ptr.is_null() {
343 let list: Box<List> = mem::transmute(ptr);
344 for &(ptr, dtor) in list.iter() {
348 DTORS.set(0 as *mut _);
353 // OSX's analog of the above linux function is this _tlv_atexit function.
354 // The disassembly of thread_local globals in C++ (at least produced by
355 // clang) will have this show up in the output.
356 #[cfg(target_os = "macos")]
357 unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
359 fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
362 _tlv_atexit(dtor, t);
366 pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
367 let ptr = ptr as *mut Key<T>;
368 // Right before we run the user destructor be sure to flag the
369 // destructor as running for this thread so calls to `get` will return
371 *(*ptr).dtor_running.get() = true;
372 ptr::read((*ptr).inner.get() as *const T);
376 #[cfg(not(any(target_os = "macos", target_os = "linux")))]
380 use cell::UnsafeCell;
382 use sys_common::thread_local::StaticKey as OsStaticKey;
386 // Statically allocated initialization expression, using an `UnsafeCell`
387 // for the same reasons as above.
388 pub inner: UnsafeCell<T>,
390 // OS-TLS key that we'll use to key off.
394 struct Value<T: 'static> {
395 key: &'static Key<T>,
401 pub unsafe fn get(&'static self) -> Option<&'static T> {
402 self.ptr().map(|p| &*p)
405 unsafe fn ptr(&'static self) -> Option<*mut T> {
406 let ptr = self.os.get() as *mut Value<T>;
408 if ptr as uint == 1 {
411 return Some(&mut (*ptr).value as *mut T);
414 // If the lookup returned null, we haven't initialized our own local
415 // copy, so do that now.
417 // Also note that this transmute_copy should be ok because the value
418 // `inner` is already validated to be a valid `static` value, so we
419 // should be able to freely copy the bits.
420 let ptr: Box<Value<T>> = box Value {
422 value: mem::transmute_copy(&self.inner),
424 let ptr: *mut Value<T> = mem::transmute(ptr);
425 self.os.set(ptr as *mut u8);
426 Some(&mut (*ptr).value as *mut T)
431 pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
432 // The OS TLS ensures that this key contains a NULL value when this
433 // destructor starts to run. We set it back to a sentinel value of 1 to
434 // ensure that any future calls to `get` for this thread will return
437 // Note that to prevent an infinite loop we reset it back to null right
438 // before we return from the destructor ourselves.
439 let ptr: Box<Value<T>> = mem::transmute(ptr);
441 key.os.set(1 as *mut u8);
443 key.os.set(0 as *mut u8);
451 use cell::UnsafeCell;
452 use rustrt::thread::Thread;
454 struct Foo(Sender<()>);
458 let Foo(ref s) = *self;
465 thread_local!(static FOO: UnsafeCell<int> = UnsafeCell { value: 1 })
467 FOO.with(|f| unsafe {
468 assert_eq!(*f.get(), 1);
471 let (tx, rx) = channel();
473 FOO.with(|f| unsafe {
474 assert_eq!(*f.get(), 1);
480 FOO.with(|f| unsafe {
481 assert_eq!(*f.get(), 2);
487 thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
491 let (tx, rx) = channel();
492 spawn(proc() unsafe {
493 let mut tx = Some(tx);
495 *f.get() = Some(Foo(tx.take().unwrap()));
505 thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
508 thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
511 static mut HITS: uint = 0;
521 K2.with(|s| *s.get() = Some(S2));
533 assert!(!K1.destroyed());
535 K1.with(|s| *s.get() = Some(S1));
540 Thread::start(proc() {
546 fn self_referential() {
548 thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
554 assert!(K1.destroyed());
558 Thread::start(proc() unsafe {
559 K1.with(|s| *s.get() = Some(S1));
564 fn dtors_in_dtors_in_dtors() {
565 struct S1(Sender<()>);
566 thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
569 thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell {
575 let S1(ref tx) = *self;
578 K2.with(|s| *s.get() = Some(Foo(tx.clone())));
584 let (tx, rx) = channel();
585 spawn(proc() unsafe {
586 let mut tx = Some(tx);
587 K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
598 use collections::HashMap;
602 fn square(i: int) -> int { i * i }
603 thread_local!(static FOO: int = square(3))
612 fn map() -> RefCell<HashMap<int, int>> {
613 let mut m = HashMap::new();
617 thread_local!(static FOO: RefCell<HashMap<int, int>> = map())
620 assert_eq!(map.borrow()[1], 2);
626 thread_local!(static FOO: RefCell<Vec<uint>> = RefCell::new(vec![1, 2, 3]))
629 assert_eq!(vec.borrow().len(), 3);
630 vec.borrow_mut().push(4);
631 assert_eq!(vec.borrow()[3], 4);