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")]
46 // macro hygiene sure would be nice, wouldn't it?
49 pub use super::imp
::KeyInner
;
50 pub use sys_common
::thread_local
::INIT
as OS_INIT
;
53 /// Type representing a thread local storage key corresponding to a reference
54 /// to the type parameter `T`.
56 /// Keys are statically allocated and can contain a reference to an instance of
57 /// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
58 /// and `with`, both of which currently use closures to control the scope of
60 #[unstable(feature = "scoped_tls",
61 reason
= "scoped TLS has yet to have wide enough use to fully consider \
62 stabilizing its interface")]
63 pub struct ScopedKey
<T
> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
65 /// Declare a new scoped thread local storage key.
67 /// This macro declares a `static` item on which methods are used to get and
68 /// set the value stored within.
70 /// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more
73 #[allow_internal_unstable]
74 #[cfg(not(no_elf_tls))]
75 macro_rules
! scoped_thread_local
{
76 (static $name
:ident
: $t
:ty
) => (
77 __scoped_thread_local_inner
!(static $name
: $t
);
79 (pub static $name
:ident
: $t
:ty
) => (
80 __scoped_thread_local_inner
!(pub static $name
: $t
);
86 #[allow_internal_unstable]
87 macro_rules
! __scoped_thread_local_inner
{
88 (static $name
:ident
: $t
:ty
) => (
89 #[cfg_attr(not(any(windows,
90 target_os
= "android",
92 target_os
= "openbsd",
93 target_arch
= "aarch64")),
95 static $name
: ::std
::thread
::ScopedKey
<$t
> =
96 __scoped_thread_local_inner
!($t
);
98 (pub static $name
:ident
: $t
:ty
) => (
99 #[cfg_attr(not(any(windows,
100 target_os
= "android",
102 target_os
= "openbsd",
103 target_arch
= "aarch64")),
105 pub static $name
: ::std
::thread
::ScopedKey
<$t
> =
106 __scoped_thread_local_inner
!($t
);
109 use std
::thread
::ScopedKey
as __Key
;
111 #[cfg(not(any(windows,
112 target_os
= "android",
114 target_os
= "openbsd",
115 target_arch
= "aarch64")))]
116 const _INIT
: __Key
<$t
> = __Key
{
117 inner
: ::std
::thread
::__scoped
::KeyInner
{
118 inner
: ::std
::cell
::UnsafeCell { value: 0 as *mut _ }
,
123 target_os
= "android",
125 target_os
= "openbsd",
126 target_arch
= "aarch64"))]
127 const _INIT
: __Key
<$t
> = __Key
{
128 inner
: ::std
::thread
::__scoped
::KeyInner
{
129 inner
: ::std
::thread
::__scoped
::OS_INIT
,
130 marker
: ::std
::marker
::PhantomData
::<::std
::cell
::Cell
<$t
>>,
139 #[allow_internal_unstable]
141 macro_rules
! scoped_thread_local
{
142 (static $name
:ident
: $t
:ty
) => (
143 static $name
: ::std
::thread
::ScopedKey
<$t
> =
144 ::std
::thread
::ScopedKey
::new();
146 (pub static $name
:ident
: $t
:ty
) => (
147 pub static $name
: ::std
::thread
::ScopedKey
<$t
> =
148 ::std
::thread
::ScopedKey
::new();
152 #[unstable(feature = "scoped_tls",
153 reason
= "scoped TLS has yet to have wide enough use to fully consider \
154 stabilizing its interface")]
155 impl<T
> ScopedKey
<T
> {
156 /// Inserts a value into this scoped thread local storage slot for a
157 /// duration of a closure.
159 /// While `cb` is running, the value `t` will be returned by `get` unless
160 /// this function is called recursively inside of `cb`.
162 /// Upon return, this function will restore the previous value, if any
168 /// # #![feature(scoped_tls)]
169 /// scoped_thread_local!(static FOO: u32);
171 /// FOO.set(&100, || {
172 /// let val = FOO.with(|v| *v);
173 /// assert_eq!(val, 100);
175 /// // set can be called recursively
176 /// FOO.set(&101, || {
180 /// // Recursive calls restore the previous value.
181 /// let val = FOO.with(|v| *v);
182 /// assert_eq!(val, 100);
185 pub fn set
<R
, F
>(&'
static self, t
: &T
, cb
: F
) -> R
where
188 struct Reset
<'a
, T
: 'a
> {
189 key
: &'a __impl
::KeyInner
<T
>,
192 impl<'a
, T
> Drop
for Reset
<'a
, T
> {
194 unsafe { self.key.set(self.val) }
199 let prev
= self.inner
.get();
200 self.inner
.set(t
as *const T
as *mut T
);
204 let _reset
= Reset { key: &self.inner, val: prev }
;
208 /// Gets a value out of this scoped variable.
210 /// This function takes a closure which receives the value of this
215 /// This function will panic if `set` has not previously been called.
220 /// # #![feature(scoped_tls)]
221 /// scoped_thread_local!(static FOO: u32);
223 /// FOO.with(|slot| {
224 /// // work with `slot`
227 pub fn with
<R
, F
>(&'
static self, cb
: F
) -> R
where
231 let ptr
= self.inner
.get();
232 assert
!(!ptr
.is_null(), "cannot access a scoped thread local \
233 variable without calling `set` first");
238 /// Test whether this TLS key has been `set` for the current thread.
239 pub fn is_set(&'
static self) -> bool
{
240 unsafe { !self.inner.get().is_null() }
244 #[cfg(not(any(windows,
245 target_os
= "android",
247 target_os
= "openbsd",
248 target_arch
= "aarch64",
251 use std
::cell
::UnsafeCell
;
254 pub struct KeyInner
<T
> { pub inner: UnsafeCell<*mut T> }
256 unsafe impl<T
> ::marker
::Sync
for KeyInner
<T
> { }
259 impl<T
> KeyInner
<T
> {
261 pub unsafe fn set(&self, ptr
: *mut T
) { *self.inner.get() = ptr; }
263 pub unsafe fn get(&self) -> *mut T { *self.inner.get() }
268 target_os
= "android",
270 target_os
= "openbsd",
271 target_arch
= "aarch64",
276 use sys_common
::thread_local
::StaticKey
as OsStaticKey
;
279 pub struct KeyInner
<T
> {
280 pub inner
: OsStaticKey
,
281 pub marker
: marker
::PhantomData
<Cell
<T
>>,
284 unsafe impl<T
> ::marker
::Sync
for KeyInner
<T
> { }
287 impl<T
> KeyInner
<T
> {
289 pub unsafe fn set(&self, ptr
: *mut T
) { self.inner.set(ptr as *mut _) }
291 pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ }
301 scoped_thread_local
!(static FOO
: u32);
305 scoped_thread_local
!(static BAR
: u32);
307 assert
!(!BAR
.is_set());
309 assert
!(BAR
.is_set());
311 assert_eq
!(*slot
, 1);
314 assert
!(!BAR
.is_set());
319 scoped_thread_local
!(static BAR
: Cell
<u32>);
321 BAR
.set(&Cell
::new(1), || {
323 assert_eq
!(slot
.get(), 1);
329 fn scope_item_allowed() {
330 assert
!(!FOO
.is_set());
332 assert
!(FOO
.is_set());
334 assert_eq
!(*slot
, 1);
337 assert
!(!FOO
.is_set());