]> git.lizzy.rs Git - rust.git/blob - src/libstd/thread_local/mod.rs
std: Add a new top-level thread_local module
[rust.git] / src / libstd / thread_local / mod.rs
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.
4 //
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.
10
11 //! Thread local storage
12 //!
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.
17 //!
18 //! At a high level, this module provides two variants of storage:
19 //!
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.
24 //!
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
28 //!   into this key.
29 //!
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.
36
37 #![macro_escape]
38 #![experimental]
39
40 use prelude::*;
41
42 use cell::UnsafeCell;
43
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
50 pub mod scoped;
51
52 /// A thread local storage key which owns its contents.
53 ///
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.
57 ///
58 /// The `with` method yields a reference to the contained value which cannot be
59 /// sent across tasks or escape the given closure.
60 ///
61 /// # Initialization and Destruction
62 ///
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
65 /// thread exits.
66 ///
67 /// # Example
68 ///
69 /// ```
70 /// use std::cell::RefCell;
71 ///
72 /// thread_local!(static FOO: RefCell<uint> = RefCell::new(1));
73 ///
74 /// FOO.with(|f| {
75 ///     assert_eq!(*f.borrow(), 1);
76 ///     *f.borrow_mut() = 2;
77 /// });
78 ///
79 /// // each thread starts out with the initial value of 1
80 /// spawn(proc() {
81 ///     FOO.with(|f| {
82 ///         assert_eq!(*f.borrow(), 1);
83 ///         *f.borrow_mut() = 3;
84 ///     });
85 /// });
86 ///
87 /// // we retain our original value of 2 despite the child thread
88 /// FOO.with(|f| {
89 ///     assert_eq!(*f.borrow(), 2);
90 /// });
91 /// ```
92 pub struct Key<T> {
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.
98     //
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.
101     #[doc(hidden)]
102     pub inner: fn() -> &'static KeyInner<UnsafeCell<Option<T>>>,
103
104     // initialization routine to invoke to create a value
105     #[doc(hidden)]
106     pub init: fn() -> T,
107 }
108
109 /// Declare a new thread local storage key of type `std::thread_local::Key`.
110 #[macro_export]
111 #[doc(hidden)]
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;
119
120             __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
121                 __UnsafeCell { value: __None }
122             })
123             fn __init() -> $t { $init }
124             fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
125                 &__KEY
126             }
127             ::std::thread_local::Key { inner: __getit, init: __init }
128         };
129     );
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;
136
137             __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
138                 __UnsafeCell { value: __None }
139             })
140             fn __init() -> $t { $init }
141             fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
142                 &__KEY
143             }
144             ::std::thread_local::Key { inner: __getit, init: __init }
145         };
146     );
147 )
148
149 // Macro pain #4586:
150 //
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:
156 //
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.
165 //
166 // To get around this, we're forced to inject the #[cfg] logic into the macro
167 // itself. Woohoo.
168
169 #[macro_export]
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);
175     );
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);
180     );
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,
189             }
190         };
191
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);
196             }
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),
202                 },
203             }
204         };
205
206         INIT
207     });
208 )
209
210 impl<T: 'static> Key<T> {
211     /// Acquire a reference to the value in this TLS key.
212     ///
213     /// This will lazily initialize the value if this thread has not referenced
214     /// this key yet.
215     ///
216     /// # Panics
217     ///
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)();
223         unsafe {
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)());
228             }
229             f((*slot.get()).as_ref().unwrap())
230         }
231     }
232
233     /// Test this TLS key to determine whether its value has been destroyed for
234     /// the current thread or not.
235     ///
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() }
239     }
240 }
241
242 #[cfg(any(target_os = "macos", target_os = "linux"))]
243 mod imp {
244     use prelude::*;
245
246     use cell::UnsafeCell;
247     use intrinsics;
248     use kinds::marker;
249     use ptr;
250
251     #[doc(hidden)]
252     pub struct Key<T> {
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
255         // the cell.
256         //
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>,
260
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
265
266         // These shouldn't be copied around.
267         pub marker: marker::NoCopy,
268     }
269
270     #[doc(hidden)]
271     impl<T> Key<T> {
272         pub unsafe fn get(&'static self) -> Option<&'static T> {
273             if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
274                 return None
275             }
276             self.register_dtor();
277             Some(&*self.inner.get())
278         }
279
280         unsafe fn register_dtor(&self) {
281             if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
282                 return
283             }
284
285             register_dtor(self as *const _ as *mut u8,
286                           destroy_value::<T>);
287             *self.dtor_registered.get() = true;
288         }
289     }
290
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!
294     //
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.
298     //
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)) {
302         use mem;
303         use libc;
304         use sys_common::thread_local as os;
305
306         extern {
307             static __dso_handle: *mut u8;
308             #[linkage = "extern_weak"]
309             static __cxa_thread_atexit_impl: *const ();
310         }
311         if !__cxa_thread_atexit_impl.is_null() {
312             type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
313                                       arg: *mut u8,
314                                       dso_handle: *mut u8) -> libc::c_int;
315             mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
316             (dtor, t, __dso_handle);
317             return
318         }
319
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.
323         //
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),
332         };
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));
337         }
338         let list: &mut List = &mut *(DTORS.get() as *mut List);
339         list.push((t, dtor));
340
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() {
345                     dtor(ptr);
346                 }
347                 ptr = DTORS.get();
348                 DTORS.set(0 as *mut _);
349             }
350         }
351     }
352
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)) {
358         extern {
359             fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
360                            arg: *mut u8);
361         }
362         _tlv_atexit(dtor, t);
363     }
364
365     #[doc(hidden)]
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
370         // `None`.
371         *(*ptr).dtor_running.get() = true;
372         ptr::read((*ptr).inner.get() as *const T);
373     }
374 }
375
376 #[cfg(not(any(target_os = "macos", target_os = "linux")))]
377 mod imp {
378     use prelude::*;
379
380     use cell::UnsafeCell;
381     use mem;
382     use sys_common::thread_local::StaticKey as OsStaticKey;
383
384     #[doc(hidden)]
385     pub struct Key<T> {
386         // Statically allocated initialization expression, using an `UnsafeCell`
387         // for the same reasons as above.
388         pub inner: UnsafeCell<T>,
389
390         // OS-TLS key that we'll use to key off.
391         pub os: OsStaticKey,
392     }
393
394     struct Value<T: 'static> {
395         key: &'static Key<T>,
396         value: T,
397     }
398
399     #[doc(hidden)]
400     impl<T> Key<T> {
401         pub unsafe fn get(&'static self) -> Option<&'static T> {
402             self.ptr().map(|p| &*p)
403         }
404
405         unsafe fn ptr(&'static self) -> Option<*mut T> {
406             let ptr = self.os.get() as *mut Value<T>;
407             if !ptr.is_null() {
408                 if ptr as uint == 1 {
409                     return None
410                 }
411                 return Some(&mut (*ptr).value as *mut T);
412             }
413
414             // If the lookup returned null, we haven't initialized our own local
415             // copy, so do that now.
416             //
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 {
421                 key: self,
422                 value: mem::transmute_copy(&self.inner),
423             };
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)
427         }
428     }
429
430     #[doc(hidden)]
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
435         // `None`.
436         //
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);
440         let key = ptr.key;
441         key.os.set(1 as *mut u8);
442         drop(ptr);
443         key.os.set(0 as *mut u8);
444     }
445 }
446
447 #[cfg(test)]
448 mod tests {
449     use prelude::*;
450
451     use cell::UnsafeCell;
452     use rustrt::thread::Thread;
453
454     struct Foo(Sender<()>);
455
456     impl Drop for Foo {
457         fn drop(&mut self) {
458             let Foo(ref s) = *self;
459             s.send(());
460         }
461     }
462
463     #[test]
464     fn smoke_no_dtor() {
465         thread_local!(static FOO: UnsafeCell<int> = UnsafeCell { value: 1 })
466
467         FOO.with(|f| unsafe {
468             assert_eq!(*f.get(), 1);
469             *f.get() = 2;
470         });
471         let (tx, rx) = channel();
472         spawn(proc() {
473             FOO.with(|f| unsafe {
474                 assert_eq!(*f.get(), 1);
475             });
476             tx.send(());
477         });
478         rx.recv();
479
480         FOO.with(|f| unsafe {
481             assert_eq!(*f.get(), 2);
482         });
483     }
484
485     #[test]
486     fn smoke_dtor() {
487         thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
488             value: None
489         })
490
491         let (tx, rx) = channel();
492         spawn(proc() unsafe {
493             let mut tx = Some(tx);
494             FOO.with(|f| {
495                 *f.get() = Some(Foo(tx.take().unwrap()));
496             });
497         });
498         rx.recv();
499     }
500
501     #[test]
502     fn circular() {
503         struct S1;
504         struct S2;
505         thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
506             value: None
507         })
508         thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
509             value: None
510         })
511         static mut HITS: uint = 0;
512
513         impl Drop for S1 {
514             fn drop(&mut self) {
515                 unsafe {
516                     HITS += 1;
517                     if K2.destroyed() {
518                         assert_eq!(HITS, 3);
519                     } else {
520                         if HITS == 1 {
521                             K2.with(|s| *s.get() = Some(S2));
522                         } else {
523                             assert_eq!(HITS, 3);
524                         }
525                     }
526                 }
527             }
528         }
529         impl Drop for S2 {
530             fn drop(&mut self) {
531                 unsafe {
532                     HITS += 1;
533                     assert!(!K1.destroyed());
534                     assert_eq!(HITS, 2);
535                     K1.with(|s| *s.get() = Some(S1));
536                 }
537             }
538         }
539
540         Thread::start(proc() {
541             drop(S1);
542         }).join();
543     }
544
545     #[test]
546     fn self_referential() {
547         struct S1;
548         thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
549             value: None
550         })
551
552         impl Drop for S1 {
553             fn drop(&mut self) {
554                 assert!(K1.destroyed());
555             }
556         }
557
558         Thread::start(proc() unsafe {
559             K1.with(|s| *s.get() = Some(S1));
560         }).join();
561     }
562
563     #[test]
564     fn dtors_in_dtors_in_dtors() {
565         struct S1(Sender<()>);
566         thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
567             value: None
568         })
569         thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell {
570             value: None
571         })
572
573         impl Drop for S1 {
574             fn drop(&mut self) {
575                 let S1(ref tx) = *self;
576                 unsafe {
577                     if !K2.destroyed() {
578                         K2.with(|s| *s.get() = Some(Foo(tx.clone())));
579                     }
580                 }
581             }
582         }
583
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())));
588         });
589         rx.recv();
590     }
591 }
592
593 #[cfg(test)]
594 mod dynamic_tests {
595     use prelude::*;
596
597     use cell::RefCell;
598     use collections::HashMap;
599
600     #[test]
601     fn smoke() {
602         fn square(i: int) -> int { i * i }
603         thread_local!(static FOO: int = square(3))
604
605         FOO.with(|f| {
606             assert_eq!(*f, 9);
607         });
608     }
609
610     #[test]
611     fn hashmap() {
612         fn map() -> RefCell<HashMap<int, int>> {
613             let mut m = HashMap::new();
614             m.insert(1, 2);
615             RefCell::new(m)
616         }
617         thread_local!(static FOO: RefCell<HashMap<int, int>> = map())
618
619         FOO.with(|map| {
620             assert_eq!(map.borrow()[1], 2);
621         });
622     }
623
624     #[test]
625     fn refcell_vec() {
626         thread_local!(static FOO: RefCell<Vec<uint>> = RefCell::new(vec![1, 2, 3]))
627
628         FOO.with(|vec| {
629             assert_eq!(vec.borrow().len(), 3);
630             vec.borrow_mut().push(4);
631             assert_eq!(vec.borrow()[3], 4);
632         });
633     }
634 }