]> git.lizzy.rs Git - rust.git/blob - src/libstd/thread/local.rs
Auto merge of #24865 - bluss:range-size, r=alexcrichton
[rust.git] / src / libstd / thread / local.rs
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.
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 #![unstable(feature = "thread_local_internals")]
14
15 use prelude::v1::*;
16
17 use cell::UnsafeCell;
18
19 // Sure wish we had macro hygiene, no?
20 #[doc(hidden)]
21 pub mod __impl {
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;
26 }
27
28 /// A thread local storage key which owns its contents.
29 ///
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.
33 ///
34 /// The `with` method yields a reference to the contained value which cannot be
35 /// sent across tasks or escape the given closure.
36 ///
37 /// # Initialization and Destruction
38 ///
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
41 /// thread exits.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use std::cell::RefCell;
47 /// use std::thread;
48 ///
49 /// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
50 ///
51 /// FOO.with(|f| {
52 ///     assert_eq!(*f.borrow(), 1);
53 ///     *f.borrow_mut() = 2;
54 /// });
55 ///
56 /// // each thread starts out with the initial value of 1
57 /// thread::spawn(move|| {
58 ///     FOO.with(|f| {
59 ///         assert_eq!(*f.borrow(), 1);
60 ///         *f.borrow_mut() = 3;
61 ///     });
62 /// });
63 ///
64 /// // we retain our original value of 2 despite the child thread
65 /// FOO.with(|f| {
66 ///     assert_eq!(*f.borrow(), 2);
67 /// });
68 /// ```
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.
76     //
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.
79     #[doc(hidden)]
80     pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
81
82     // initialization routine to invoke to create a value
83     #[doc(hidden)]
84     pub init: fn() -> T,
85 }
86
87 /// Declare a new thread local storage key of type `std::thread::LocalKey`.
88 #[macro_export]
89 #[stable(feature = "rust1", since = "1.0.0")]
90 #[allow_internal_unstable]
91 macro_rules! thread_local {
92     (static $name:ident: $t:ty = $init:expr) => (
93         static $name: ::std::thread::LocalKey<$t> = {
94             use std::cell::UnsafeCell as __UnsafeCell;
95             use std::thread::__local::KeyInner as __KeyInner;
96             use std::option::Option as __Option;
97             use std::option::Option::None as __None;
98
99             __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
100                 __UnsafeCell { value: __None }
101             });
102             fn __init() -> $t { $init }
103             fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
104                 &__KEY
105             }
106             ::std::thread::LocalKey { inner: __getit, init: __init }
107         };
108     );
109     (pub static $name:ident: $t:ty = $init:expr) => (
110         pub static $name: ::std::thread::LocalKey<$t> = {
111             use std::cell::UnsafeCell as __UnsafeCell;
112             use std::thread::__local::KeyInner as __KeyInner;
113             use std::option::Option as __Option;
114             use std::option::Option::None as __None;
115
116             __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
117                 __UnsafeCell { value: __None }
118             });
119             fn __init() -> $t { $init }
120             fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
121                 &__KEY
122             }
123             ::std::thread::LocalKey { inner: __getit, init: __init }
124         };
125     );
126 }
127
128 // Macro pain #4586:
129 //
130 // When cross compiling, rustc will load plugins and macros from the *host*
131 // platform before search for macros from the target platform. This is primarily
132 // done to detect, for example, plugins. Ideally the macro below would be
133 // defined once per module below, but unfortunately this means we have the
134 // following situation:
135 //
136 // 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
137 //    will inject #[thread_local] statics.
138 // 2. We then try to compile a program for arm-linux-androideabi
139 // 3. The compiler has a host of linux and a target of android, so it loads
140 //    macros from the *linux* libstd.
141 // 4. The macro generates a #[thread_local] field, but the android libstd does
142 //    not use #[thread_local]
143 // 5. Compile error about structs with wrong fields.
144 //
145 // To get around this, we're forced to inject the #[cfg] logic into the macro
146 // itself. Woohoo.
147
148 #[macro_export]
149 #[doc(hidden)]
150 #[allow_internal_unstable]
151 macro_rules! __thread_local_inner {
152     (static $name:ident: $t:ty = $init:expr) => (
153         #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
154                        not(target_arch = "aarch64")),
155                    thread_local)]
156         static $name: ::std::thread::__local::KeyInner<$t> =
157             __thread_local_inner!($init, $t);
158     );
159     (pub static $name:ident: $t:ty = $init:expr) => (
160         #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
161                        not(target_arch = "aarch64")),
162                    thread_local)]
163         pub static $name: ::std::thread::__local::KeyInner<$t> =
164             __thread_local_inner!($init, $t);
165     );
166     ($init:expr, $t:ty) => ({
167         #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
168         const _INIT: ::std::thread::__local::KeyInner<$t> = {
169             ::std::thread::__local::KeyInner {
170                 inner: ::std::cell::UnsafeCell { value: $init },
171                 dtor_registered: ::std::cell::UnsafeCell { value: false },
172                 dtor_running: ::std::cell::UnsafeCell { value: false },
173             }
174         };
175
176         #[allow(trivial_casts)]
177         #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
178         const _INIT: ::std::thread::__local::KeyInner<$t> = {
179             ::std::thread::__local::KeyInner {
180                 inner: ::std::cell::UnsafeCell { value: $init },
181                 os: ::std::thread::__local::OsStaticKey {
182                     inner: ::std::thread::__local::OS_INIT_INNER,
183                     dtor: ::std::option::Option::Some(
184                         ::std::thread::__local::destroy_value::<$t>
185                     ),
186                 },
187             }
188         };
189
190         _INIT
191     });
192 }
193
194 /// Indicator of the state of a thread local storage key.
195 #[unstable(feature = "std_misc",
196            reason = "state querying was recently added")]
197 #[derive(Eq, PartialEq, Copy, Clone)]
198 pub enum LocalKeyState {
199     /// All keys are in this state whenever a thread starts. Keys will
200     /// transition to the `Valid` state once the first call to `with` happens
201     /// and the initialization expression succeeds.
202     ///
203     /// Keys in the `Uninitialized` state will yield a reference to the closure
204     /// passed to `with` so long as the initialization routine does not panic.
205     Uninitialized,
206
207     /// Once a key has been accessed successfully, it will enter the `Valid`
208     /// state. Keys in the `Valid` state will remain so until the thread exits,
209     /// at which point the destructor will be run and the key will enter the
210     /// `Destroyed` state.
211     ///
212     /// Keys in the `Valid` state will be guaranteed to yield a reference to the
213     /// closure passed to `with`.
214     Valid,
215
216     /// When a thread exits, the destructors for keys will be run (if
217     /// necessary). While a destructor is running, and possibly after a
218     /// destructor has run, a key is in the `Destroyed` state.
219     ///
220     /// Keys in the `Destroyed` states will trigger a panic when accessed via
221     /// `with`.
222     Destroyed,
223 }
224
225 impl<T: 'static> LocalKey<T> {
226     /// Acquires a reference to the value in this TLS key.
227     ///
228     /// This will lazily initialize the value if this thread has not referenced
229     /// this key yet.
230     ///
231     /// # Panics
232     ///
233     /// This function will `panic!()` if the key currently has its
234     /// destructor running, and it **may** panic if the destructor has
235     /// previously been run for this thread.
236     #[stable(feature = "rust1", since = "1.0.0")]
237     pub fn with<F, R>(&'static self, f: F) -> R
238                       where F: FnOnce(&T) -> R {
239         let slot = (self.inner)();
240         unsafe {
241             let slot = slot.get().expect("cannot access a TLS value during or \
242                                           after it is destroyed");
243             f(match *slot.get() {
244                 Some(ref inner) => inner,
245                 None => self.init(slot),
246             })
247         }
248     }
249
250     unsafe fn init(&self, slot: &UnsafeCell<Option<T>>) -> &T {
251         // Execute the initialization up front, *then* move it into our slot,
252         // just in case initialization fails.
253         let value = (self.init)();
254         let ptr = slot.get();
255         *ptr = Some(value);
256         (*ptr).as_ref().unwrap()
257     }
258
259     /// Query the current state of this key.
260     ///
261     /// A key is initially in the `Uninitialized` state whenever a thread
262     /// starts. It will remain in this state up until the first call to `with`
263     /// within a thread has run the initialization expression successfully.
264     ///
265     /// Once the initialization expression succeeds, the key transitions to the
266     /// `Valid` state which will guarantee that future calls to `with` will
267     /// succeed within the thread.
268     ///
269     /// When a thread exits, each key will be destroyed in turn, and as keys are
270     /// destroyed they will enter the `Destroyed` state just before the
271     /// destructor starts to run. Keys may remain in the `Destroyed` state after
272     /// destruction has completed. Keys without destructors (e.g. with types
273     /// that are `Copy`), may never enter the `Destroyed` state.
274     ///
275     /// Keys in the `Uninitialized` can be accessed so long as the
276     /// initialization does not panic. Keys in the `Valid` state are guaranteed
277     /// to be able to be accessed. Keys in the `Destroyed` state will panic on
278     /// any call to `with`.
279     #[unstable(feature = "std_misc",
280                reason = "state querying was recently added")]
281     pub fn state(&'static self) -> LocalKeyState {
282         unsafe {
283             match (self.inner)().get() {
284                 Some(cell) => {
285                     match *cell.get() {
286                         Some(..) => LocalKeyState::Valid,
287                         None => LocalKeyState::Uninitialized,
288                     }
289                 }
290                 None => LocalKeyState::Destroyed,
291             }
292         }
293     }
294 }
295
296 #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
297 #[doc(hidden)]
298 mod imp {
299     use prelude::v1::*;
300
301     use cell::UnsafeCell;
302     use intrinsics;
303     use ptr;
304
305     pub struct Key<T> {
306         // Place the inner bits in an `UnsafeCell` to currently get around the
307         // "only Sync statics" restriction. This allows any type to be placed in
308         // the cell.
309         //
310         // Note that all access requires `T: 'static` so it can't be a type with
311         // any borrowed pointers still.
312         pub inner: UnsafeCell<T>,
313
314         // Metadata to keep track of the state of the destructor. Remember that
315         // these variables are thread-local, not global.
316         pub dtor_registered: UnsafeCell<bool>, // should be Cell
317         pub dtor_running: UnsafeCell<bool>, // should be Cell
318     }
319
320     unsafe impl<T> ::marker::Sync for Key<T> { }
321
322     impl<T> Key<T> {
323         pub unsafe fn get(&'static self) -> Option<&'static T> {
324             if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
325                 return None
326             }
327             self.register_dtor();
328             Some(&*self.inner.get())
329         }
330
331         unsafe fn register_dtor(&self) {
332             if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
333                 return
334             }
335
336             register_dtor(self as *const _ as *mut u8,
337                           destroy_value::<T>);
338             *self.dtor_registered.get() = true;
339         }
340     }
341
342     // Since what appears to be glibc 2.18 this symbol has been shipped which
343     // GCC and clang both use to invoke destructors in thread_local globals, so
344     // let's do the same!
345     //
346     // Note, however, that we run on lots older linuxes, as well as cross
347     // compiling from a newer linux to an older linux, so we also have a
348     // fallback implementation to use as well.
349     //
350     // Due to rust-lang/rust#18804, make sure this is not generic!
351     #[cfg(target_os = "linux")]
352     unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
353         use boxed;
354         use mem;
355         use libc;
356         use sys_common::thread_local as os;
357
358         extern {
359             #[linkage = "extern_weak"]
360             static __dso_handle: *mut u8;
361             #[linkage = "extern_weak"]
362             static __cxa_thread_atexit_impl: *const ();
363         }
364         if !__cxa_thread_atexit_impl.is_null() {
365             type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
366                                       arg: *mut u8,
367                                       dso_handle: *mut u8) -> libc::c_int;
368             mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
369             (dtor, t, &__dso_handle as *const _ as *mut _);
370             return
371         }
372
373         // The fallback implementation uses a vanilla OS-based TLS key to track
374         // the list of destructors that need to be run for this thread. The key
375         // then has its own destructor which runs all the other destructors.
376         //
377         // The destructor for DTORS is a little special in that it has a `while`
378         // loop to continuously drain the list of registered destructors. It
379         // *should* be the case that this loop always terminates because we
380         // provide the guarantee that a TLS key cannot be set after it is
381         // flagged for destruction.
382         static DTORS: os::StaticKey = os::StaticKey {
383             inner: os::INIT_INNER,
384             dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)),
385         };
386         type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
387         if DTORS.get().is_null() {
388             let v: Box<List> = box Vec::new();
389             DTORS.set(boxed::into_raw(v) as *mut u8);
390         }
391         let list: &mut List = &mut *(DTORS.get() as *mut List);
392         list.push((t, dtor));
393
394         unsafe extern fn run_dtors(mut ptr: *mut u8) {
395             while !ptr.is_null() {
396                 let list: Box<List> = Box::from_raw(ptr as *mut List);
397                 for &(ptr, dtor) in &*list {
398                     dtor(ptr);
399                 }
400                 ptr = DTORS.get();
401                 DTORS.set(ptr::null_mut());
402             }
403         }
404     }
405
406     // OSX's analog of the above linux function is this _tlv_atexit function.
407     // The disassembly of thread_local globals in C++ (at least produced by
408     // clang) will have this show up in the output.
409     #[cfg(target_os = "macos")]
410     unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
411         extern {
412             fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
413                            arg: *mut u8);
414         }
415         _tlv_atexit(dtor, t);
416     }
417
418     pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
419         let ptr = ptr as *mut Key<T>;
420         // Right before we run the user destructor be sure to flag the
421         // destructor as running for this thread so calls to `get` will return
422         // `None`.
423         *(*ptr).dtor_running.get() = true;
424         ptr::read((*ptr).inner.get());
425     }
426 }
427
428 #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
429 #[doc(hidden)]
430 mod imp {
431     use prelude::v1::*;
432
433     use alloc::boxed;
434     use cell::UnsafeCell;
435     use mem;
436     use ptr;
437     use sys_common::thread_local::StaticKey as OsStaticKey;
438
439     pub struct Key<T> {
440         // Statically allocated initialization expression, using an `UnsafeCell`
441         // for the same reasons as above.
442         pub inner: UnsafeCell<T>,
443
444         // OS-TLS key that we'll use to key off.
445         pub os: OsStaticKey,
446     }
447
448     unsafe impl<T> ::marker::Sync for Key<T> { }
449
450     struct Value<T: 'static> {
451         key: &'static Key<T>,
452         value: T,
453     }
454
455     impl<T> Key<T> {
456         pub unsafe fn get(&'static self) -> Option<&'static T> {
457             self.ptr().map(|p| &*p)
458         }
459
460         unsafe fn ptr(&'static self) -> Option<*mut T> {
461             let ptr = self.os.get() as *mut Value<T>;
462             if !ptr.is_null() {
463                 if ptr as usize == 1 {
464                     return None
465                 }
466                 return Some(&mut (*ptr).value as *mut T);
467             }
468
469             // If the lookup returned null, we haven't initialized our own local
470             // copy, so do that now.
471             //
472             // Also note that this transmute_copy should be ok because the value
473             // `inner` is already validated to be a valid `static` value, so we
474             // should be able to freely copy the bits.
475             let ptr: Box<Value<T>> = box Value {
476                 key: self,
477                 value: mem::transmute_copy(&self.inner),
478             };
479             let ptr = boxed::into_raw(ptr);
480             self.os.set(ptr as *mut u8);
481             Some(&mut (*ptr).value as *mut T)
482         }
483     }
484
485     pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
486         // The OS TLS ensures that this key contains a NULL value when this
487         // destructor starts to run. We set it back to a sentinel value of 1 to
488         // ensure that any future calls to `get` for this thread will return
489         // `None`.
490         //
491         // Note that to prevent an infinite loop we reset it back to null right
492         // before we return from the destructor ourselves.
493         let ptr = Box::from_raw(ptr as *mut Value<T>);
494         let key = ptr.key;
495         key.os.set(1 as *mut u8);
496         drop(ptr);
497         key.os.set(ptr::null_mut());
498     }
499 }
500
501 #[cfg(test)]
502 mod tests {
503     use prelude::v1::*;
504
505     use sync::mpsc::{channel, Sender};
506     use cell::UnsafeCell;
507     use super::LocalKeyState;
508     use thread;
509
510     struct Foo(Sender<()>);
511
512     impl Drop for Foo {
513         fn drop(&mut self) {
514             let Foo(ref s) = *self;
515             s.send(()).unwrap();
516         }
517     }
518
519     #[test]
520     fn smoke_no_dtor() {
521         thread_local!(static FOO: UnsafeCell<i32> = UnsafeCell { value: 1 });
522
523         FOO.with(|f| unsafe {
524             assert_eq!(*f.get(), 1);
525             *f.get() = 2;
526         });
527         let (tx, rx) = channel();
528         let _t = thread::spawn(move|| {
529             FOO.with(|f| unsafe {
530                 assert_eq!(*f.get(), 1);
531             });
532             tx.send(()).unwrap();
533         });
534         rx.recv().unwrap();
535
536         FOO.with(|f| unsafe {
537             assert_eq!(*f.get(), 2);
538         });
539     }
540
541     #[test]
542     fn states() {
543         struct Foo;
544         impl Drop for Foo {
545             fn drop(&mut self) {
546                 assert!(FOO.state() == LocalKeyState::Destroyed);
547             }
548         }
549         fn foo() -> Foo {
550             assert!(FOO.state() == LocalKeyState::Uninitialized);
551             Foo
552         }
553         thread_local!(static FOO: Foo = foo());
554
555         thread::spawn(|| {
556             assert!(FOO.state() == LocalKeyState::Uninitialized);
557             FOO.with(|_| {
558                 assert!(FOO.state() == LocalKeyState::Valid);
559             });
560             assert!(FOO.state() == LocalKeyState::Valid);
561         }).join().ok().unwrap();
562     }
563
564     #[test]
565     fn smoke_dtor() {
566         thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
567             value: None
568         });
569
570         let (tx, rx) = channel();
571         let _t = thread::spawn(move|| unsafe {
572             let mut tx = Some(tx);
573             FOO.with(|f| {
574                 *f.get() = Some(Foo(tx.take().unwrap()));
575             });
576         });
577         rx.recv().unwrap();
578     }
579
580     #[test]
581     fn circular() {
582         struct S1;
583         struct S2;
584         thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
585             value: None
586         });
587         thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
588             value: None
589         });
590         static mut HITS: u32 = 0;
591
592         impl Drop for S1 {
593             fn drop(&mut self) {
594                 unsafe {
595                     HITS += 1;
596                     if K2.state() == LocalKeyState::Destroyed {
597                         assert_eq!(HITS, 3);
598                     } else {
599                         if HITS == 1 {
600                             K2.with(|s| *s.get() = Some(S2));
601                         } else {
602                             assert_eq!(HITS, 3);
603                         }
604                     }
605                 }
606             }
607         }
608         impl Drop for S2 {
609             fn drop(&mut self) {
610                 unsafe {
611                     HITS += 1;
612                     assert!(K1.state() != LocalKeyState::Destroyed);
613                     assert_eq!(HITS, 2);
614                     K1.with(|s| *s.get() = Some(S1));
615                 }
616             }
617         }
618
619         thread::spawn(move|| {
620             drop(S1);
621         }).join().ok().unwrap();
622     }
623
624     #[test]
625     fn self_referential() {
626         struct S1;
627         thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
628             value: None
629         });
630
631         impl Drop for S1 {
632             fn drop(&mut self) {
633                 assert!(K1.state() == LocalKeyState::Destroyed);
634             }
635         }
636
637         thread::spawn(move|| unsafe {
638             K1.with(|s| *s.get() = Some(S1));
639         }).join().ok().unwrap();
640     }
641
642     #[test]
643     fn dtors_in_dtors_in_dtors() {
644         struct S1(Sender<()>);
645         thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
646             value: None
647         });
648         thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell {
649             value: None
650         });
651
652         impl Drop for S1 {
653             fn drop(&mut self) {
654                 let S1(ref tx) = *self;
655                 unsafe {
656                     if K2.state() != LocalKeyState::Destroyed {
657                         K2.with(|s| *s.get() = Some(Foo(tx.clone())));
658                     }
659                 }
660             }
661         }
662
663         let (tx, rx) = channel();
664         let _t = thread::spawn(move|| unsafe {
665             let mut tx = Some(tx);
666             K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
667         });
668         rx.recv().unwrap();
669     }
670 }
671
672 #[cfg(test)]
673 mod dynamic_tests {
674     use prelude::v1::*;
675
676     use cell::RefCell;
677     use collections::HashMap;
678
679     #[test]
680     fn smoke() {
681         fn square(i: i32) -> i32 { i * i }
682         thread_local!(static FOO: i32 = square(3));
683
684         FOO.with(|f| {
685             assert_eq!(*f, 9);
686         });
687     }
688
689     #[test]
690     fn hashmap() {
691         fn map() -> RefCell<HashMap<i32, i32>> {
692             let mut m = HashMap::new();
693             m.insert(1, 2);
694             RefCell::new(m)
695         }
696         thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
697
698         FOO.with(|map| {
699             assert_eq!(map.borrow()[&1], 2);
700         });
701     }
702
703     #[test]
704     fn refcell_vec() {
705         thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
706
707         FOO.with(|vec| {
708             assert_eq!(vec.borrow().len(), 3);
709             vec.borrow_mut().push(4);
710             assert_eq!(vec.borrow()[3], 4);
711         });
712     }
713 }