3535//! `Cell` or `RefCell` types.
3636
3737#![ macro_escape]
38- #![ experimental ]
38+ #![ stable ]
3939
4040use prelude:: * ;
4141
4242use cell:: UnsafeCell ;
4343
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 ;
49-
5044pub mod scoped;
5145
46+ // Sure wish we had macro hygiene, no?
47+ #[ doc( hidden) ]
48+ pub mod __impl {
49+ pub use super :: imp:: Key as KeyInner ;
50+ pub use super :: imp:: destroy_value;
51+ pub use sys_common:: thread_local:: INIT_INNER as OS_INIT_INNER ;
52+ pub use sys_common:: thread_local:: StaticKey as OsStaticKey ;
53+ }
54+
5255/// A thread local storage key which owns its contents.
5356///
5457/// This key uses the fastest possible implementation available to it for the
@@ -90,6 +93,7 @@ pub mod scoped;
9093/// assert_eq!(*f.borrow(), 2);
9194/// });
9295/// ```
96+ #[ stable]
9397pub struct Key < T > {
9498 // The key itself may be tagged with #[thread_local], and this `Key` is
9599 // stored as a `static`, and it's not valid for a static to reference the
@@ -100,7 +104,7 @@ pub struct Key<T> {
100104 // This is trivially devirtualizable by LLVM because we never store anything
101105 // to this field and rustc can declare the `static` as constant as well.
102106 #[ doc( hidden) ]
103- pub inner : fn ( ) -> & ' static KeyInner < UnsafeCell < Option < T > > > ,
107+ pub inner : fn ( ) -> & ' static __impl :: KeyInner < UnsafeCell < Option < T > > > ,
104108
105109 // initialization routine to invoke to create a value
106110 #[ doc( hidden) ]
@@ -109,12 +113,12 @@ pub struct Key<T> {
109113
110114/// Declare a new thread local storage key of type `std::thread_local::Key`.
111115#[ macro_export]
112- #[ doc ( hidden ) ]
116+ #[ stable ]
113117macro_rules! thread_local {
114118 ( static $name: ident: $t: ty = $init: expr) => (
115119 static $name: :: std:: thread_local:: Key <$t> = {
116120 use std:: cell:: UnsafeCell as __UnsafeCell;
117- use std:: thread_local:: KeyInner as __KeyInner;
121+ use std:: thread_local:: __impl :: KeyInner as __KeyInner;
118122 use std:: option:: Option as __Option;
119123 use std:: option:: Option :: None as __None;
120124
@@ -131,7 +135,7 @@ macro_rules! thread_local {
131135 ( pub static $name: ident: $t: ty = $init: expr) => (
132136 pub static $name: :: std:: thread_local:: Key <$t> = {
133137 use std:: cell:: UnsafeCell as __UnsafeCell;
134- use std:: thread_local:: KeyInner as __KeyInner;
138+ use std:: thread_local:: __impl :: KeyInner as __KeyInner;
135139 use std:: option:: Option as __Option;
136140 use std:: option:: Option :: None as __None;
137141
@@ -168,46 +172,77 @@ macro_rules! thread_local {
168172// itself. Woohoo.
169173
170174#[ macro_export]
175+ #[ doc( hidden) ]
171176macro_rules! __thread_local_inner {
172177 ( static $name: ident: $t: ty = $init: expr) => (
173178 #[ cfg_attr( any( target_os = "macos" , target_os = "linux" ) , thread_local) ]
174- static $name: :: std:: thread_local:: KeyInner <$t> =
179+ static $name: :: std:: thread_local:: __impl :: KeyInner <$t> =
175180 __thread_local_inner!( $init, $t) ;
176181 ) ;
177182 ( pub static $name: ident: $t: ty = $init: expr) => (
178183 #[ cfg_attr( any( target_os = "macos" , target_os = "linux" ) , thread_local) ]
179- pub static $name: :: std:: thread_local:: KeyInner <$t> =
184+ pub static $name: :: std:: thread_local:: __impl :: KeyInner <$t> =
180185 __thread_local_inner!( $init, $t) ;
181186 ) ;
182187 ( $init: expr, $t: ty) => ( {
183188 #[ cfg( any( target_os = "macos" , target_os = "linux" ) ) ]
184- const INIT : :: std:: thread_local:: KeyInner <$t> = {
185- :: std:: thread_local:: KeyInner {
189+ const _INIT : :: std:: thread_local:: __impl :: KeyInner <$t> = {
190+ :: std:: thread_local:: __impl :: KeyInner {
186191 inner: :: std:: cell:: UnsafeCell { value: $init } ,
187192 dtor_registered: :: std:: cell:: UnsafeCell { value: false } ,
188193 dtor_running: :: std:: cell:: UnsafeCell { value: false } ,
189194 }
190195 } ;
191196
192197 #[ cfg( all( not( any( target_os = "macos" , target_os = "linux" ) ) ) ) ]
193- const INIT : :: std:: thread_local:: KeyInner <$t> = {
198+ const _INIT : :: std:: thread_local:: __impl :: KeyInner <$t> = {
194199 unsafe extern fn __destroy( ptr: * mut u8 ) {
195- :: std:: thread_local:: destroy_value:: <$t>( ptr) ;
200+ :: std:: thread_local:: __impl :: destroy_value:: <$t>( ptr) ;
196201 }
197202
198- :: std:: thread_local:: KeyInner {
203+ :: std:: thread_local:: __impl :: KeyInner {
199204 inner: :: std:: cell:: UnsafeCell { value: $init } ,
200- os: :: std:: thread_local:: OsStaticKey {
201- inner: :: std:: thread_local:: OS_INIT_INNER ,
205+ os: :: std:: thread_local:: __impl :: OsStaticKey {
206+ inner: :: std:: thread_local:: __impl :: OS_INIT_INNER ,
202207 dtor: :: std:: option:: Option :: Some ( __destroy as unsafe extern fn ( * mut u8 ) ) ,
203208 } ,
204209 }
205210 } ;
206211
207- INIT
212+ _INIT
208213 } ) ;
209214}
210215
216+ /// Indicator of the state of a thread local storage key.
217+ #[ unstable = "state querying was recently added" ]
218+ #[ deriving( Eq , PartialEq , Copy ) ]
219+ pub enum State {
220+ /// All keys are in this state whenever a thread starts. Keys will
221+ /// transition to the `Valid` state once the first call to `with` happens
222+ /// and the initialization expression succeeds.
223+ ///
224+ /// Keys in the `Uninitialized` state will yield a reference to the closure
225+ /// passed to `with` so long as the initialization routine does not panic.
226+ Uninitialized ,
227+
228+ /// Once a key has been accessed successfully, it will enter the `Valid`
229+ /// state. Keys in the `Valid` state will remain so until the thread exits,
230+ /// at which point the destructor will be run and the key will enter the
231+ /// `Destroyed` state.
232+ ///
233+ /// Keys in the `Valid` state will be guaranteed to yield a reference to the
234+ /// closure passed to `with`.
235+ Valid ,
236+
237+ /// When a thread exits, the destructors for keys will be run (if
238+ /// necessary). While a destructor is running, and possibly after a
239+ /// destructor has run, a key is in the `Destroyed` state.
240+ ///
241+ /// Keys in the `Destroyed` states will trigger a panic when accessed via
242+ /// `with`.
243+ Destroyed ,
244+ }
245+
211246impl < T : ' static > Key < T > {
212247 /// Acquire a reference to the value in this TLS key.
213248 ///
@@ -219,6 +254,7 @@ impl<T: 'static> Key<T> {
219254 /// This function will `panic!()` if the key currently has its
220255 /// destructor running, and it **may** panic if the destructor has
221256 /// previously been run for this thread.
257+ #[ stable]
222258 pub fn with < F , R > ( & ' static self , f : F ) -> R
223259 where F : FnOnce ( & T ) -> R {
224260 let slot = ( self . inner ) ( ) ;
@@ -233,17 +269,52 @@ impl<T: 'static> Key<T> {
233269 }
234270
235271 unsafe fn init ( & self , slot : & UnsafeCell < Option < T > > ) -> & T {
236- * slot. get ( ) = Some ( ( self . init ) ( ) ) ;
237- ( * slot. get ( ) ) . as_ref ( ) . unwrap ( )
272+ // Execute the initialization up front, *then* move it into our slot,
273+ // just in case initialization fails.
274+ let value = ( self . init ) ( ) ;
275+ let ptr = slot. get ( ) ;
276+ * ptr = Some ( value) ;
277+ ( * ptr) . as_ref ( ) . unwrap ( )
238278 }
239279
240- /// Test this TLS key to determine whether its value has been destroyed for
241- /// the current thread or not.
280+ /// Query the current state of this key.
281+ ///
282+ /// A key is initially in the `Uninitialized` state whenever a thread
283+ /// starts. It will remain in this state up until the first call to `with`
284+ /// within a thread has run the initialization expression successfully.
285+ ///
286+ /// Once the initialization expression succeeds, the key transitions to the
287+ /// `Valid` state which will guarantee that future calls to `with` will
288+ /// succeed within the thread.
242289 ///
243- /// This will not initialize the key if it is not already initialized.
244- pub fn destroyed ( & ' static self ) -> bool {
245- unsafe { ( self . inner ) ( ) . get ( ) . is_none ( ) }
290+ /// When a thread exits, each key will be destroyed in turn, and as keys are
291+ /// destroyed they will enter the `Destroyed` state just before the
292+ /// destructor starts to run. Keys may remain in the `Destroyed` state after
293+ /// destruction has completed. Keys without destructors (e.g. with types
294+ /// that are `Copy`), may never enter the `Destroyed` state.
295+ ///
296+ /// Keys in the `Uninitialized` can be accessed so long as the
297+ /// initialization does not panic. Keys in the `Valid` state are guaranteed
298+ /// to be able to be accessed. Keys in the `Destroyed` state will panic on
299+ /// any call to `with`.
300+ #[ unstable = "state querying was recently added" ]
301+ pub fn state ( & ' static self ) -> State {
302+ unsafe {
303+ match ( self . inner ) ( ) . get ( ) {
304+ Some ( cell) => {
305+ match * cell. get ( ) {
306+ Some ( ..) => State :: Valid ,
307+ None => State :: Uninitialized ,
308+ }
309+ }
310+ None => State :: Destroyed ,
311+ }
312+ }
246313 }
314+
315+ /// Deprecated
316+ #[ deprecated = "function renamed to state() and returns more info" ]
317+ pub fn destroyed ( & ' static self ) -> bool { self . state ( ) == State :: Destroyed }
247318}
248319
249320#[ cfg( any( target_os = "macos" , target_os = "linux" ) ) ]
@@ -456,6 +527,7 @@ mod tests {
456527 use prelude:: * ;
457528
458529 use cell:: UnsafeCell ;
530+ use super :: State ;
459531 use thread:: Thread ;
460532
461533 struct Foo ( Sender < ( ) > ) ;
@@ -489,6 +561,29 @@ mod tests {
489561 } ) ;
490562 }
491563
564+ #[ test]
565+ fn states ( ) {
566+ struct Foo ;
567+ impl Drop for Foo {
568+ fn drop ( & mut self ) {
569+ assert ! ( FOO . state( ) == State :: Destroyed ) ;
570+ }
571+ }
572+ fn foo ( ) -> Foo {
573+ assert ! ( FOO . state( ) == State :: Uninitialized ) ;
574+ Foo
575+ }
576+ thread_local ! ( static FOO : Foo = foo( ) ) ;
577+
578+ Thread :: spawn ( || {
579+ assert ! ( FOO . state( ) == State :: Uninitialized ) ;
580+ FOO . with ( |_| {
581+ assert ! ( FOO . state( ) == State :: Valid ) ;
582+ } ) ;
583+ assert ! ( FOO . state( ) == State :: Valid ) ;
584+ } ) . join ( ) . ok ( ) . unwrap ( ) ;
585+ }
586+
492587 #[ test]
493588 fn smoke_dtor ( ) {
494589 thread_local ! ( static FOO : UnsafeCell <Option <Foo >> = UnsafeCell {
@@ -521,7 +616,7 @@ mod tests {
521616 fn drop ( & mut self ) {
522617 unsafe {
523618 HITS += 1 ;
524- if K2 . destroyed ( ) {
619+ if K2 . state ( ) == State :: Destroyed {
525620 assert_eq ! ( HITS , 3 ) ;
526621 } else {
527622 if HITS == 1 {
@@ -537,7 +632,7 @@ mod tests {
537632 fn drop ( & mut self ) {
538633 unsafe {
539634 HITS += 1 ;
540- assert ! ( ! K1 . destroyed ( ) ) ;
635+ assert ! ( K1 . state ( ) != State :: Destroyed ) ;
541636 assert_eq ! ( HITS , 2 ) ;
542637 K1 . with ( |s| * s. get ( ) = Some ( S1 ) ) ;
543638 }
@@ -558,7 +653,7 @@ mod tests {
558653
559654 impl Drop for S1 {
560655 fn drop ( & mut self ) {
561- assert ! ( K1 . destroyed ( ) ) ;
656+ assert ! ( K1 . state ( ) == State :: Destroyed ) ;
562657 }
563658 }
564659
@@ -581,7 +676,7 @@ mod tests {
581676 fn drop ( & mut self ) {
582677 let S1 ( ref tx) = * self ;
583678 unsafe {
584- if ! K2 . destroyed ( ) {
679+ if K2 . state ( ) != State :: Destroyed {
585680 K2 . with ( |s| * s. get ( ) = Some ( Foo ( tx. clone ( ) ) ) ) ;
586681 }
587682 }
0 commit comments