1 // Copyright 2014-2015 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 #![unstable(feature = "thread_local_internals")]
19 // Sure wish we had macro hygiene, no?
22 pub use super::imp
::Key
as KeyInner
;
23 pub use super::imp
::destroy_value
;
24 pub use sys_common
::thread_local
::INIT_INNER
as OS_INIT_INNER
;
25 pub use sys_common
::thread_local
::StaticKey
as OsStaticKey
;
28 /// A thread local storage key which owns its contents.
30 /// This key uses the fastest possible implementation available to it for the
31 /// target platform. It is instantiated with the `thread_local!` macro and the
32 /// primary method is the `with` method.
34 /// The `with` method yields a reference to the contained value which cannot be
35 /// sent across threads or escape the given closure.
37 /// # Initialization and Destruction
39 /// Initialization is dynamically performed on the first call to `with()`
40 /// within a thread, and values support destructors which will be run when a
46 /// use std::cell::RefCell;
49 /// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
52 /// assert_eq!(*f.borrow(), 1);
53 /// *f.borrow_mut() = 2;
56 /// // each thread starts out with the initial value of 1
57 /// thread::spawn(move|| {
59 /// assert_eq!(*f.borrow(), 1);
60 /// *f.borrow_mut() = 3;
64 /// // we retain our original value of 2 despite the child thread
66 /// assert_eq!(*f.borrow(), 2);
69 #[stable(feature = "rust1", since = "1.0.0")]
70 pub struct LocalKey
<T
> {
71 // The key itself may be tagged with #[thread_local], and this `Key` is
72 // stored as a `static`, and it's not valid for a static to reference the
73 // address of another thread_local static. For this reason we kinda wonkily
74 // work around this by generating a shim function which will give us the
75 // address of the inner TLS key at runtime.
77 // This is trivially devirtualizable by LLVM because we never store anything
78 // to this field and rustc can declare the `static` as constant as well.
80 pub inner
: fn() -> &'
static __impl
::KeyInner
<UnsafeCell
<Option
<T
>>>,
82 // initialization routine to invoke to create a value
87 /// Declare a new thread local storage key of type `std::thread::LocalKey`.
89 /// See [LocalKey documentation](thread/struct.LocalKey.html) for more information.
91 #[stable(feature = "rust1", since = "1.0.0")]
92 #[allow_internal_unstable]
93 macro_rules
! thread_local
{
94 (static $name
:ident
: $t
:ty
= $init
:expr
) => (
95 static $name
: ::std
::thread
::LocalKey
<$t
> = {
96 use std
::cell
::UnsafeCell
as __UnsafeCell
;
97 use std
::thread
::__local
::KeyInner
as __KeyInner
;
98 use std
::option
::Option
as __Option
;
99 use std
::option
::Option
::None
as __None
;
101 __thread_local_inner
!(static __KEY
: __UnsafeCell
<__Option
<$t
>> = {
102 __UnsafeCell { value: __None }
104 fn __init() -> $t { $init }
105 fn __getit() -> &'
static __KeyInner
<__UnsafeCell
<__Option
<$t
>>> {
108 ::std
::thread
::LocalKey { inner: __getit, init: __init }
111 (pub static $name
:ident
: $t
:ty
= $init
:expr
) => (
112 pub static $name
: ::std
::thread
::LocalKey
<$t
> = {
113 use std
::cell
::UnsafeCell
as __UnsafeCell
;
114 use std
::thread
::__local
::KeyInner
as __KeyInner
;
115 use std
::option
::Option
as __Option
;
116 use std
::option
::Option
::None
as __None
;
118 __thread_local_inner
!(static __KEY
: __UnsafeCell
<__Option
<$t
>> = {
119 __UnsafeCell { value: __None }
121 fn __init() -> $t { $init }
122 fn __getit() -> &'
static __KeyInner
<__UnsafeCell
<__Option
<$t
>>> {
125 ::std
::thread
::LocalKey { inner: __getit, init: __init }
132 // When cross compiling, rustc will load plugins and macros from the *host*
133 // platform before search for macros from the target platform. This is primarily
134 // done to detect, for example, plugins. Ideally the macro below would be
135 // defined once per module below, but unfortunately this means we have the
136 // following situation:
138 // 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
139 // will inject #[thread_local] statics.
140 // 2. We then try to compile a program for arm-linux-androideabi
141 // 3. The compiler has a host of linux and a target of android, so it loads
142 // macros from the *linux* libstd.
143 // 4. The macro generates a #[thread_local] field, but the android libstd does
144 // not use #[thread_local]
145 // 5. Compile error about structs with wrong fields.
147 // To get around this, we're forced to inject the #[cfg] logic into the macro
152 #[allow_internal_unstable]
153 #[cfg(not(no_elf_tls))]
154 macro_rules
! __thread_local_inner
{
155 (static $name
:ident
: $t
:ty
= $init
:expr
) => (
156 #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
157 not(target_arch
= "aarch64")),
159 static $name
: ::std
::thread
::__local
::KeyInner
<$t
> =
160 __thread_local_inner
!($init
, $t
);
162 (pub static $name
:ident
: $t
:ty
= $init
:expr
) => (
163 #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
164 not(target_arch
= "aarch64")),
166 pub static $name
: ::std
::thread
::__local
::KeyInner
<$t
> =
167 __thread_local_inner
!($init
, $t
);
169 ($init
:expr
, $t
:ty
) => ({
170 #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
171 const _INIT
: ::std
::thread
::__local
::KeyInner
<$t
> = {
172 ::std
::thread
::__local
::KeyInner
{
173 inner
: ::std
::cell
::UnsafeCell { value: $init }
,
174 dtor_registered
: ::std
::cell
::UnsafeCell { value: false }
,
175 dtor_running
: ::std
::cell
::UnsafeCell { value: false }
,
179 #[allow(trivial_casts)]
180 #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
181 const _INIT
: ::std
::thread
::__local
::KeyInner
<$t
> = {
182 ::std
::thread
::__local
::KeyInner
{
183 inner
: ::std
::cell
::UnsafeCell { value: $init }
,
184 os
: ::std
::thread
::__local
::OsStaticKey
{
185 inner
: ::std
::thread
::__local
::OS_INIT_INNER
,
186 dtor
: ::std
::option
::Option
::Some(
187 ::std
::thread
::__local
::destroy_value
::<$t
>
199 #[allow_internal_unstable]
201 macro_rules
! __thread_local_inner
{
202 (static $name
:ident
: $t
:ty
= $init
:expr
) => (
203 static $name
: ::std
::thread
::__local
::KeyInner
<$t
> =
204 __thread_local_inner
!($init
, $t
);
206 (pub static $name
:ident
: $t
:ty
= $init
:expr
) => (
207 pub static $name
: ::std
::thread
::__local
::KeyInner
<$t
> =
208 __thread_local_inner
!($init
, $t
);
210 ($init
:expr
, $t
:ty
) => ({
211 #[allow(trivial_casts)]
212 const _INIT
: ::std
::thread
::__local
::KeyInner
<$t
> = {
213 ::std
::thread
::__local
::KeyInner
{
214 inner
: ::std
::cell
::UnsafeCell { value: $init }
,
215 os
: ::std
::thread
::__local
::OsStaticKey
{
216 inner
: ::std
::thread
::__local
::OS_INIT_INNER
,
217 dtor
: ::std
::option
::Option
::Some(
218 ::std
::thread
::__local
::destroy_value
::<$t
>
228 /// Indicator of the state of a thread local storage key.
229 #[unstable(feature = "std_misc",
230 reason
= "state querying was recently added")]
231 #[derive(Eq, PartialEq, Copy, Clone)]
232 pub enum LocalKeyState
{
233 /// All keys are in this state whenever a thread starts. Keys will
234 /// transition to the `Valid` state once the first call to `with` happens
235 /// and the initialization expression succeeds.
237 /// Keys in the `Uninitialized` state will yield a reference to the closure
238 /// passed to `with` so long as the initialization routine does not panic.
241 /// Once a key has been accessed successfully, it will enter the `Valid`
242 /// state. Keys in the `Valid` state will remain so until the thread exits,
243 /// at which point the destructor will be run and the key will enter the
244 /// `Destroyed` state.
246 /// Keys in the `Valid` state will be guaranteed to yield a reference to the
247 /// closure passed to `with`.
250 /// When a thread exits, the destructors for keys will be run (if
251 /// necessary). While a destructor is running, and possibly after a
252 /// destructor has run, a key is in the `Destroyed` state.
254 /// Keys in the `Destroyed` states will trigger a panic when accessed via
259 impl<T
: '
static> LocalKey
<T
> {
260 /// Acquires a reference to the value in this TLS key.
262 /// This will lazily initialize the value if this thread has not referenced
267 /// This function will `panic!()` if the key currently has its
268 /// destructor running, and it **may** panic if the destructor has
269 /// previously been run for this thread.
270 #[stable(feature = "rust1", since = "1.0.0")]
271 pub fn with
<F
, R
>(&'
static self, f
: F
) -> R
272 where F
: FnOnce(&T
) -> R
{
273 let slot
= (self.inner
)();
275 let slot
= slot
.get().expect("cannot access a TLS value during or \
276 after it is destroyed");
277 f(match *slot
.get() {
278 Some(ref inner
) => inner
,
279 None
=> self.init(slot
),
284 unsafe fn init(&self, slot
: &UnsafeCell
<Option
<T
>>) -> &T
{
285 // Execute the initialization up front, *then* move it into our slot,
286 // just in case initialization fails.
287 let value
= (self.init
)();
288 let ptr
= slot
.get();
290 (*ptr
).as_ref().unwrap()
293 /// Query the current state of this key.
295 /// A key is initially in the `Uninitialized` state whenever a thread
296 /// starts. It will remain in this state up until the first call to `with`
297 /// within a thread has run the initialization expression successfully.
299 /// Once the initialization expression succeeds, the key transitions to the
300 /// `Valid` state which will guarantee that future calls to `with` will
301 /// succeed within the thread.
303 /// When a thread exits, each key will be destroyed in turn, and as keys are
304 /// destroyed they will enter the `Destroyed` state just before the
305 /// destructor starts to run. Keys may remain in the `Destroyed` state after
306 /// destruction has completed. Keys without destructors (e.g. with types
307 /// that are `Copy`), may never enter the `Destroyed` state.
309 /// Keys in the `Uninitialized` can be accessed so long as the
310 /// initialization does not panic. Keys in the `Valid` state are guaranteed
311 /// to be able to be accessed. Keys in the `Destroyed` state will panic on
312 /// any call to `with`.
313 #[unstable(feature = "std_misc",
314 reason
= "state querying was recently added")]
315 pub fn state(&'
static self) -> LocalKeyState
{
317 match (self.inner
)().get() {
320 Some(..) => LocalKeyState
::Valid
,
321 None
=> LocalKeyState
::Uninitialized
,
324 None
=> LocalKeyState
::Destroyed
,
330 #[cfg(all(any(target_os = "macos", target_os = "linux"),
331 not(target_arch
= "aarch64"),
337 use cell
::UnsafeCell
;
342 // Place the inner bits in an `UnsafeCell` to currently get around the
343 // "only Sync statics" restriction. This allows any type to be placed in
346 // Note that all access requires `T: 'static` so it can't be a type with
347 // any borrowed pointers still.
348 pub inner
: UnsafeCell
<T
>,
350 // Metadata to keep track of the state of the destructor. Remember that
351 // these variables are thread-local, not global.
352 pub dtor_registered
: UnsafeCell
<bool
>, // should be Cell
353 pub dtor_running
: UnsafeCell
<bool
>, // should be Cell
356 unsafe impl<T
> ::marker
::Sync
for Key
<T
> { }
359 pub unsafe fn get(&'
static self) -> Option
<&'
static T
> {
360 if intrinsics
::needs_drop
::<T
>() && *self.dtor_running
.get() {
363 self.register_dtor();
364 Some(&*self.inner
.get())
367 unsafe fn register_dtor(&self) {
368 if !intrinsics
::needs_drop
::<T
>() || *self.dtor_registered
.get() {
372 register_dtor(self as *const _
as *mut u8,
374 *self.dtor_registered
.get() = true;
378 // Since what appears to be glibc 2.18 this symbol has been shipped which
379 // GCC and clang both use to invoke destructors in thread_local globals, so
380 // let's do the same!
382 // Note, however, that we run on lots older linuxes, as well as cross
383 // compiling from a newer linux to an older linux, so we also have a
384 // fallback implementation to use as well.
386 // Due to rust-lang/rust#18804, make sure this is not generic!
387 #[cfg(target_os = "linux")]
388 unsafe fn register_dtor(t
: *mut u8, dtor
: unsafe extern fn(*mut u8)) {
392 use sys_common
::thread_local
as os
;
395 #[linkage = "extern_weak"]
396 static __dso_handle
: *mut u8;
397 #[linkage = "extern_weak"]
398 static __cxa_thread_atexit_impl
: *const ();
400 if !__cxa_thread_atexit_impl
.is_null() {
401 type F
= unsafe extern fn(dtor
: unsafe extern fn(*mut u8),
403 dso_handle
: *mut u8) -> libc
::c_int
;
404 mem
::transmute
::<*const (), F
>(__cxa_thread_atexit_impl
)
405 (dtor
, t
, &__dso_handle
as *const _
as *mut _
);
409 // The fallback implementation uses a vanilla OS-based TLS key to track
410 // the list of destructors that need to be run for this thread. The key
411 // then has its own destructor which runs all the other destructors.
413 // The destructor for DTORS is a little special in that it has a `while`
414 // loop to continuously drain the list of registered destructors. It
415 // *should* be the case that this loop always terminates because we
416 // provide the guarantee that a TLS key cannot be set after it is
417 // flagged for destruction.
418 static DTORS
: os
::StaticKey
= os
::StaticKey
{
419 inner
: os
::INIT_INNER
,
420 dtor
: Some(run_dtors
as unsafe extern "C" fn(*mut u8)),
422 type List
= Vec
<(*mut u8, unsafe extern fn(*mut u8))>;
423 if DTORS
.get().is_null() {
424 let v
: Box
<List
> = box Vec
::new();
425 DTORS
.set(boxed
::into_raw(v
) as *mut u8);
427 let list
: &mut List
= &mut *(DTORS
.get() as *mut List
);
428 list
.push((t
, dtor
));
430 unsafe extern fn run_dtors(mut ptr
: *mut u8) {
431 while !ptr
.is_null() {
432 let list
: Box
<List
> = Box
::from_raw(ptr
as *mut List
);
433 for &(ptr
, dtor
) in &*list
{
437 DTORS
.set(ptr
::null_mut());
442 // OSX's analog of the above linux function is this _tlv_atexit function.
443 // The disassembly of thread_local globals in C++ (at least produced by
444 // clang) will have this show up in the output.
445 #[cfg(target_os = "macos")]
446 unsafe fn register_dtor(t
: *mut u8, dtor
: unsafe extern fn(*mut u8)) {
448 fn _tlv_atexit(dtor
: unsafe extern fn(*mut u8),
451 _tlv_atexit(dtor
, t
);
454 pub unsafe extern fn destroy_value
<T
>(ptr
: *mut u8) {
455 let ptr
= ptr
as *mut Key
<T
>;
456 // Right before we run the user destructor be sure to flag the
457 // destructor as running for this thread so calls to `get` will return
459 *(*ptr
).dtor_running
.get() = true;
460 ptr
::read((*ptr
).inner
.get());
464 #[cfg(any(not(any(target_os = "macos", target_os = "linux")),
465 target_arch
= "aarch64",
472 use cell
::UnsafeCell
;
475 use sys_common
::thread_local
::StaticKey
as OsStaticKey
;
478 // Statically allocated initialization expression, using an `UnsafeCell`
479 // for the same reasons as above.
480 pub inner
: UnsafeCell
<T
>,
482 // OS-TLS key that we'll use to key off.
486 unsafe impl<T
> ::marker
::Sync
for Key
<T
> { }
488 struct Value
<T
: '
static> {
489 key
: &'
static Key
<T
>,
494 pub unsafe fn get(&'
static self) -> Option
<&'
static T
> {
495 self.ptr().map(|p
| &*p
)
498 unsafe fn ptr(&'
static self) -> Option
<*mut T
> {
499 let ptr
= self.os
.get() as *mut Value
<T
>;
501 if ptr
as usize == 1 {
504 return Some(&mut (*ptr
).value
as *mut T
);
507 // If the lookup returned null, we haven't initialized our own local
508 // copy, so do that now.
510 // Also note that this transmute_copy should be ok because the value
511 // `inner` is already validated to be a valid `static` value, so we
512 // should be able to freely copy the bits.
513 let ptr
: Box
<Value
<T
>> = box Value
{
515 value
: mem
::transmute_copy(&self.inner
),
517 let ptr
= boxed
::into_raw(ptr
);
518 self.os
.set(ptr
as *mut u8);
519 Some(&mut (*ptr
).value
as *mut T
)
523 pub unsafe extern fn destroy_value
<T
: '
static>(ptr
: *mut u8) {
524 // The OS TLS ensures that this key contains a NULL value when this
525 // destructor starts to run. We set it back to a sentinel value of 1 to
526 // ensure that any future calls to `get` for this thread will return
529 // Note that to prevent an infinite loop we reset it back to null right
530 // before we return from the destructor ourselves.
531 let ptr
= Box
::from_raw(ptr
as *mut Value
<T
>);
533 key
.os
.set(1 as *mut u8);
535 key
.os
.set(ptr
::null_mut());
543 use sync
::mpsc
::{channel, Sender}
;
544 use cell
::UnsafeCell
;
545 use super::LocalKeyState
;
548 struct Foo(Sender
<()>);
552 let Foo(ref s
) = *self;
559 thread_local
!(static FOO
: UnsafeCell
<i32> = UnsafeCell { value: 1 }
);
561 FOO
.with(|f
| unsafe {
562 assert_eq
!(*f
.get(), 1);
565 let (tx
, rx
) = channel();
566 let _t
= thread
::spawn(move|| {
567 FOO
.with(|f
| unsafe {
568 assert_eq
!(*f
.get(), 1);
570 tx
.send(()).unwrap();
574 FOO
.with(|f
| unsafe {
575 assert_eq
!(*f
.get(), 2);
584 assert
!(FOO
.state() == LocalKeyState
::Destroyed
);
588 assert
!(FOO
.state() == LocalKeyState
::Uninitialized
);
591 thread_local
!(static FOO
: Foo
= foo());
594 assert
!(FOO
.state() == LocalKeyState
::Uninitialized
);
596 assert
!(FOO
.state() == LocalKeyState
::Valid
);
598 assert
!(FOO
.state() == LocalKeyState
::Valid
);
599 }).join().ok().unwrap();
604 thread_local
!(static FOO
: UnsafeCell
<Option
<Foo
>> = UnsafeCell
{
608 let (tx
, rx
) = channel();
609 let _t
= thread
::spawn(move|| unsafe {
610 let mut tx
= Some(tx
);
612 *f
.get() = Some(Foo(tx
.take().unwrap()));
622 thread_local
!(static K1
: UnsafeCell
<Option
<S1
>> = UnsafeCell
{
625 thread_local
!(static K2
: UnsafeCell
<Option
<S2
>> = UnsafeCell
{
628 static mut HITS
: u32 = 0;
634 if K2
.state() == LocalKeyState
::Destroyed
{
638 K2
.with(|s
| *s
.get() = Some(S2
));
650 assert
!(K1
.state() != LocalKeyState
::Destroyed
);
652 K1
.with(|s
| *s
.get() = Some(S1
));
657 thread
::spawn(move|| {
659 }).join().ok().unwrap();
663 fn self_referential() {
665 thread_local
!(static K1
: UnsafeCell
<Option
<S1
>> = UnsafeCell
{
671 assert
!(K1
.state() == LocalKeyState
::Destroyed
);
675 thread
::spawn(move|| unsafe {
676 K1
.with(|s
| *s
.get() = Some(S1
));
677 }).join().ok().unwrap();
681 fn dtors_in_dtors_in_dtors() {
682 struct S1(Sender
<()>);
683 thread_local
!(static K1
: UnsafeCell
<Option
<S1
>> = UnsafeCell
{
686 thread_local
!(static K2
: UnsafeCell
<Option
<Foo
>> = UnsafeCell
{
692 let S1(ref tx
) = *self;
694 if K2
.state() != LocalKeyState
::Destroyed
{
695 K2
.with(|s
| *s
.get() = Some(Foo(tx
.clone())));
701 let (tx
, rx
) = channel();
702 let _t
= thread
::spawn(move|| unsafe {
703 let mut tx
= Some(tx
);
704 K1
.with(|s
| *s
.get() = Some(S1(tx
.take().unwrap())));
715 use collections
::HashMap
;
719 fn square(i
: i32) -> i32 { i * i }
720 thread_local
!(static FOO
: i32 = square(3));
729 fn map() -> RefCell
<HashMap
<i32, i32>> {
730 let mut m
= HashMap
::new();
734 thread_local
!(static FOO
: RefCell
<HashMap
<i32, i32>> = map());
737 assert_eq
!(map
.borrow()[&1], 2);
743 thread_local
!(static FOO
: RefCell
<Vec
<u32>> = RefCell
::new(vec
![1, 2, 3]));
746 assert_eq
!(vec
.borrow().len(), 3);
747 vec
.borrow_mut().push(4);
748 assert_eq
!(vec
.borrow()[3], 4);