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 //! Scoped thread-local storage
13 //! This module provides the ability to generate *scoped* thread-local
14 //! variables. In this sense, scoped indicates that thread local storage
15 //! actually stores a reference to a value, and this reference is only placed
16 //! in storage for a scoped amount of time.
18 //! There are no restrictions on what types can be placed into a scoped
19 //! variable, but all scoped variables are initialized to the equivalent of
20 //! null. Scoped thread local storage is useful when a value is present for a known
21 //! period of time and it is not required to relinquish ownership of the
27 //! # #![feature(scoped_tls)]
28 //! scoped_thread_local!(static FOO: u32);
30 //! // Initially each scoped slot is empty.
31 //! assert!(!FOO.is_set());
33 //! // When inserting a value, the value is only in place for the duration
34 //! // of the closure specified.
37 //! assert_eq!(*slot, 1);
42 #![unstable(feature = "thread_local_internals")]
47 pub use self::imp
::KeyInner
as __KeyInner
;
49 /// Type representing a thread local storage key corresponding to a reference
50 /// to the type parameter `T`.
52 /// Keys are statically allocated and can contain a reference to an instance of
53 /// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
54 /// and `with`, both of which currently use closures to control the scope of
56 #[unstable(feature = "scoped_tls",
57 reason
= "scoped TLS has yet to have wide enough use to fully consider \
58 stabilizing its interface")]
59 pub struct ScopedKey
<T
> { inner: fn() -> &'static imp::KeyInner<T> }
61 /// Declare a new scoped thread local storage key.
63 /// This macro declares a `static` item on which methods are used to get and
64 /// set the value stored within.
66 /// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more
69 #[allow_internal_unstable]
70 macro_rules
! scoped_thread_local
{
71 (static $name
:ident
: $t
:ty
) => (
72 static $name
: ::std
::thread
::ScopedKey
<$t
> =
73 __scoped_thread_local_inner
!($t
);
75 (pub static $name
:ident
: $t
:ty
) => (
76 pub static $name
: ::std
::thread
::ScopedKey
<$t
> =
77 __scoped_thread_local_inner
!($t
);
82 #[unstable(feature = "thread_local_internals",
83 reason
= "should not be necessary")]
85 #[allow_internal_unstable]
87 macro_rules
! __scoped_thread_local_inner
{
89 static _KEY
: ::std
::thread
::__ScopedKeyInner
<$t
> =
90 ::std
::thread
::__ScopedKeyInner
::new();
91 fn _getit() -> &'
static ::std
::thread
::__ScopedKeyInner
<$t
> { &_KEY }
92 ::std
::thread
::ScopedKey
::new(_getit
)
97 #[unstable(feature = "thread_local_internals",
98 reason
= "should not be necessary")]
100 #[allow_internal_unstable]
101 #[cfg(not(no_elf_tls))]
102 macro_rules
! __scoped_thread_local_inner
{
104 #[cfg_attr(not(any(windows,
105 target_os
= "android",
107 target_os
= "openbsd",
108 target_arch
= "aarch64")),
110 static _KEY
: ::std
::thread
::__ScopedKeyInner
<$t
> =
111 ::std
::thread
::__ScopedKeyInner
::new();
112 fn _getit() -> &'
static ::std
::thread
::__ScopedKeyInner
<$t
> { &_KEY }
113 ::std
::thread
::ScopedKey
::new(_getit
)
117 #[unstable(feature = "scoped_tls",
118 reason
= "scoped TLS has yet to have wide enough use to fully consider \
119 stabilizing its interface")]
120 impl<T
> ScopedKey
<T
> {
122 pub const fn new(inner
: fn() -> &'
static imp
::KeyInner
<T
>) -> ScopedKey
<T
> {
123 ScopedKey { inner: inner }
126 /// Inserts a value into this scoped thread local storage slot for a
127 /// duration of a closure.
129 /// While `cb` is running, the value `t` will be returned by `get` unless
130 /// this function is called recursively inside of `cb`.
132 /// Upon return, this function will restore the previous value, if any
138 /// # #![feature(scoped_tls)]
139 /// scoped_thread_local!(static FOO: u32);
141 /// FOO.set(&100, || {
142 /// let val = FOO.with(|v| *v);
143 /// assert_eq!(val, 100);
145 /// // set can be called recursively
146 /// FOO.set(&101, || {
150 /// // Recursive calls restore the previous value.
151 /// let val = FOO.with(|v| *v);
152 /// assert_eq!(val, 100);
155 pub fn set
<R
, F
>(&'
static self, t
: &T
, cb
: F
) -> R
where
158 struct Reset
<'a
, T
: 'a
> {
159 key
: &'a imp
::KeyInner
<T
>,
162 impl<'a
, T
> Drop
for Reset
<'a
, T
> {
164 unsafe { self.key.set(self.val) }
168 let inner
= (self.inner
)();
170 let prev
= inner
.get();
171 inner
.set(t
as *const T
as *mut T
);
175 let _reset
= Reset { key: inner, val: prev }
;
179 /// Gets a value out of this scoped variable.
181 /// This function takes a closure which receives the value of this
186 /// This function will panic if `set` has not previously been called.
191 /// # #![feature(scoped_tls)]
192 /// scoped_thread_local!(static FOO: u32);
194 /// FOO.with(|slot| {
195 /// // work with `slot`
198 pub fn with
<R
, F
>(&'
static self, cb
: F
) -> R
where
202 let ptr
= (self.inner
)().get();
203 assert
!(!ptr
.is_null(), "cannot access a scoped thread local \
204 variable without calling `set` first");
209 /// Test whether this TLS key has been `set` for the current thread.
210 pub fn is_set(&'
static self) -> bool
{
211 unsafe { !(self.inner)().get().is_null() }
215 #[cfg(not(any(windows,
216 target_os
= "android",
218 target_os
= "openbsd",
219 target_arch
= "aarch64",
225 pub struct KeyInner
<T
> { inner: Cell<*mut T> }
227 unsafe impl<T
> ::marker
::Sync
for KeyInner
<T
> { }
229 impl<T
> KeyInner
<T
> {
230 pub const fn new() -> KeyInner
<T
> {
231 KeyInner { inner: Cell::new(0 as *mut _) }
233 pub unsafe fn set(&self, ptr
: *mut T
) { self.inner.set(ptr); }
234 pub unsafe fn get(&self) -> *mut T { self.inner.get() }
239 target_os
= "android",
241 target_os
= "openbsd",
242 target_arch
= "aarch64",
250 use sys_common
::thread_local
::StaticKey
as OsStaticKey
;
252 pub struct KeyInner
<T
> {
253 pub inner
: OsStaticKey
,
254 pub marker
: marker
::PhantomData
<Cell
<T
>>,
257 unsafe impl<T
> marker
::Sync
for KeyInner
<T
> { }
259 impl<T
> KeyInner
<T
> {
260 pub const fn new() -> KeyInner
<T
> {
262 inner
: OsStaticKey
::new(None
),
263 marker
: marker
::PhantomData
266 pub unsafe fn set(&self, ptr
: *mut T
) { self.inner.set(ptr as *mut _) }
267 pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ }
277 scoped_thread_local
!(static FOO
: u32);
281 scoped_thread_local
!(static BAR
: u32);
283 assert
!(!BAR
.is_set());
285 assert
!(BAR
.is_set());
287 assert_eq
!(*slot
, 1);
290 assert
!(!BAR
.is_set());
295 scoped_thread_local
!(static BAR
: Cell
<u32>);
297 BAR
.set(&Cell
::new(1), || {
299 assert_eq
!(slot
.get(), 1);
305 fn scope_item_allowed() {
306 assert
!(!FOO
.is_set());
308 assert
!(FOO
.is_set());
310 assert_eq
!(*slot
, 1);
313 assert
!(!FOO
.is_set());