]> git.lizzy.rs Git - rust.git/blob - library/std/src/thread/local.rs
Auto merge of #75974 - SkiFire13:peekmut-opt-sift, r=LukasKalbertodt
[rust.git] / library / std / src / thread / local.rs
1 //! Thread local storage
2
3 #![unstable(feature = "thread_local_internals", issue = "none")]
4
5 #[cfg(all(test, not(target_os = "emscripten")))]
6 mod tests;
7
8 #[cfg(test)]
9 mod dynamic_tests;
10
11 use crate::error::Error;
12 use crate::fmt;
13
14 /// A thread local storage key which owns its contents.
15 ///
16 /// This key uses the fastest possible implementation available to it for the
17 /// target platform. It is instantiated with the [`thread_local!`] macro and the
18 /// primary method is the [`with`] method.
19 ///
20 /// The [`with`] method yields a reference to the contained value which cannot be
21 /// sent across threads or escape the given closure.
22 ///
23 /// # Initialization and Destruction
24 ///
25 /// Initialization is dynamically performed on the first call to [`with`]
26 /// within a thread, and values that implement [`Drop`] get destructed when a
27 /// thread exits. Some caveats apply, which are explained below.
28 ///
29 /// A `LocalKey`'s initializer cannot recursively depend on itself, and using
30 /// a `LocalKey` in this way will cause the initializer to infinitely recurse
31 /// on the first call to `with`.
32 ///
33 /// # Examples
34 ///
35 /// ```
36 /// use std::cell::RefCell;
37 /// use std::thread;
38 ///
39 /// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
40 ///
41 /// FOO.with(|f| {
42 ///     assert_eq!(*f.borrow(), 1);
43 ///     *f.borrow_mut() = 2;
44 /// });
45 ///
46 /// // each thread starts out with the initial value of 1
47 /// let t = thread::spawn(move|| {
48 ///     FOO.with(|f| {
49 ///         assert_eq!(*f.borrow(), 1);
50 ///         *f.borrow_mut() = 3;
51 ///     });
52 /// });
53 ///
54 /// // wait for the thread to complete and bail out on panic
55 /// t.join().unwrap();
56 ///
57 /// // we retain our original value of 2 despite the child thread
58 /// FOO.with(|f| {
59 ///     assert_eq!(*f.borrow(), 2);
60 /// });
61 /// ```
62 ///
63 /// # Platform-specific behavior
64 ///
65 /// Note that a "best effort" is made to ensure that destructors for types
66 /// stored in thread local storage are run, but not all platforms can guarantee
67 /// that destructors will be run for all types in thread local storage. For
68 /// example, there are a number of known caveats where destructors are not run:
69 ///
70 /// 1. On Unix systems when pthread-based TLS is being used, destructors will
71 ///    not be run for TLS values on the main thread when it exits. Note that the
72 ///    application will exit immediately after the main thread exits as well.
73 /// 2. On all platforms it's possible for TLS to re-initialize other TLS slots
74 ///    during destruction. Some platforms ensure that this cannot happen
75 ///    infinitely by preventing re-initialization of any slot that has been
76 ///    destroyed, but not all platforms have this guard. Those platforms that do
77 ///    not guard typically have a synthetic limit after which point no more
78 ///    destructors are run.
79 ///
80 /// [`with`]: LocalKey::with
81 #[stable(feature = "rust1", since = "1.0.0")]
82 pub struct LocalKey<T: 'static> {
83     // This outer `LocalKey<T>` type is what's going to be stored in statics,
84     // but actual data inside will sometimes be tagged with #[thread_local].
85     // It's not valid for a true static to reference a #[thread_local] static,
86     // so we get around that by exposing an accessor through a layer of function
87     // indirection (this thunk).
88     //
89     // Note that the thunk is itself unsafe because the returned lifetime of the
90     // slot where data lives, `'static`, is not actually valid. The lifetime
91     // here is actually slightly shorter than the currently running thread!
92     //
93     // Although this is an extra layer of indirection, it should in theory be
94     // trivially devirtualizable by LLVM because the value of `inner` never
95     // changes and the constant should be readonly within a crate. This mainly
96     // only runs into problems when TLS statics are exported across crates.
97     inner: unsafe fn() -> Option<&'static T>,
98 }
99
100 #[stable(feature = "std_debug", since = "1.16.0")]
101 impl<T: 'static> fmt::Debug for LocalKey<T> {
102     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103         f.pad("LocalKey { .. }")
104     }
105 }
106
107 /// Declare a new thread local storage key of type [`std::thread::LocalKey`].
108 ///
109 /// # Syntax
110 ///
111 /// The macro wraps any number of static declarations and makes them thread local.
112 /// Publicity and attributes for each static are allowed. Example:
113 ///
114 /// ```
115 /// use std::cell::RefCell;
116 /// thread_local! {
117 ///     pub static FOO: RefCell<u32> = RefCell::new(1);
118 ///
119 ///     #[allow(unused)]
120 ///     static BAR: RefCell<f32> = RefCell::new(1.0);
121 /// }
122 /// # fn main() {}
123 /// ```
124 ///
125 /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
126 /// information.
127 ///
128 /// [`std::thread::LocalKey`]: crate::thread::LocalKey
129 #[macro_export]
130 #[stable(feature = "rust1", since = "1.0.0")]
131 #[allow_internal_unstable(thread_local_internals)]
132 macro_rules! thread_local {
133     // empty (base case for the recursion)
134     () => {};
135
136     // process multiple declarations
137     ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
138         $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
139         $crate::thread_local!($($rest)*);
140     );
141
142     // handle a single declaration
143     ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
144         $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
145     );
146 }
147
148 #[doc(hidden)]
149 #[unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
150 #[macro_export]
151 #[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)]
152 #[allow_internal_unsafe]
153 macro_rules! __thread_local_inner {
154     (@key $t:ty, $init:expr) => {
155         {
156             #[inline]
157             fn __init() -> $t { $init }
158
159             unsafe fn __getit() -> $crate::option::Option<&'static $t> {
160                 #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
161                 static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
162                     $crate::thread::__StaticLocalKeyInner::new();
163
164                 #[thread_local]
165                 #[cfg(all(
166                     target_thread_local,
167                     not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
168                 ))]
169                 static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
170                     $crate::thread::__FastLocalKeyInner::new();
171
172                 #[cfg(all(
173                     not(target_thread_local),
174                     not(all(target_arch = "wasm32", not(target_feature = "atomics"))),
175                 ))]
176                 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
177                     $crate::thread::__OsLocalKeyInner::new();
178
179                 // FIXME: remove the #[allow(...)] marker when macros don't
180                 // raise warning for missing/extraneous unsafe blocks anymore.
181                 // See https://github.com/rust-lang/rust/issues/74838.
182                 #[allow(unused_unsafe)]
183                 unsafe { __KEY.get(__init) }
184             }
185
186             unsafe {
187                 $crate::thread::LocalKey::new(__getit)
188             }
189         }
190     };
191     ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
192         $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
193             $crate::__thread_local_inner!(@key $t, $init);
194     }
195 }
196
197 /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
198 #[stable(feature = "thread_local_try_with", since = "1.26.0")]
199 #[derive(Clone, Copy, Eq, PartialEq)]
200 pub struct AccessError {
201     _private: (),
202 }
203
204 #[stable(feature = "thread_local_try_with", since = "1.26.0")]
205 impl fmt::Debug for AccessError {
206     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207         f.debug_struct("AccessError").finish()
208     }
209 }
210
211 #[stable(feature = "thread_local_try_with", since = "1.26.0")]
212 impl fmt::Display for AccessError {
213     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214         fmt::Display::fmt("already destroyed", f)
215     }
216 }
217
218 #[stable(feature = "thread_local_try_with", since = "1.26.0")]
219 impl Error for AccessError {}
220
221 impl<T: 'static> LocalKey<T> {
222     #[doc(hidden)]
223     #[unstable(
224         feature = "thread_local_internals",
225         reason = "recently added to create a key",
226         issue = "none"
227     )]
228     pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
229         LocalKey { inner }
230     }
231
232     /// Acquires a reference to the value in this TLS key.
233     ///
234     /// This will lazily initialize the value if this thread has not referenced
235     /// this key yet.
236     ///
237     /// # Panics
238     ///
239     /// This function will `panic!()` if the key currently has its
240     /// destructor running, and it **may** panic if the destructor has
241     /// previously been run for this thread.
242     #[stable(feature = "rust1", since = "1.0.0")]
243     pub fn with<F, R>(&'static self, f: F) -> R
244     where
245         F: FnOnce(&T) -> R,
246     {
247         self.try_with(f).expect(
248             "cannot access a Thread Local Storage value \
249              during or after destruction",
250         )
251     }
252
253     /// Acquires a reference to the value in this TLS key.
254     ///
255     /// This will lazily initialize the value if this thread has not referenced
256     /// this key yet. If the key has been destroyed (which may happen if this is called
257     /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html).
258     ///
259     /// # Panics
260     ///
261     /// This function will still `panic!()` if the key is uninitialized and the
262     /// key's initializer panics.
263     #[stable(feature = "thread_local_try_with", since = "1.26.0")]
264     #[inline]
265     pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
266     where
267         F: FnOnce(&T) -> R,
268     {
269         unsafe {
270             let thread_local = (self.inner)().ok_or(AccessError { _private: () })?;
271             Ok(f(thread_local))
272         }
273     }
274 }
275
276 mod lazy {
277     use crate::cell::UnsafeCell;
278     use crate::hint;
279     use crate::mem;
280
281     pub struct LazyKeyInner<T> {
282         inner: UnsafeCell<Option<T>>,
283     }
284
285     impl<T> LazyKeyInner<T> {
286         pub const fn new() -> LazyKeyInner<T> {
287             LazyKeyInner { inner: UnsafeCell::new(None) }
288         }
289
290         pub unsafe fn get(&self) -> Option<&'static T> {
291             (*self.inner.get()).as_ref()
292         }
293
294         pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T {
295             // Execute the initialization up front, *then* move it into our slot,
296             // just in case initialization fails.
297             let value = init();
298             let ptr = self.inner.get();
299
300             // note that this can in theory just be `*ptr = Some(value)`, but due to
301             // the compiler will currently codegen that pattern with something like:
302             //
303             //      ptr::drop_in_place(ptr)
304             //      ptr::write(ptr, Some(value))
305             //
306             // Due to this pattern it's possible for the destructor of the value in
307             // `ptr` (e.g., if this is being recursively initialized) to re-access
308             // TLS, in which case there will be a `&` and `&mut` pointer to the same
309             // value (an aliasing violation). To avoid setting the "I'm running a
310             // destructor" flag we just use `mem::replace` which should sequence the
311             // operations a little differently and make this safe to call.
312             let _ = mem::replace(&mut *ptr, Some(value));
313
314             // After storing `Some` we want to get a reference to the contents of
315             // what we just stored. While we could use `unwrap` here and it should
316             // always work it empirically doesn't seem to always get optimized away,
317             // which means that using something like `try_with` can pull in
318             // panicking code and cause a large size bloat.
319             match *ptr {
320                 Some(ref x) => x,
321                 None => hint::unreachable_unchecked(),
322             }
323         }
324
325         #[allow(unused)]
326         pub unsafe fn take(&mut self) -> Option<T> {
327             (*self.inner.get()).take()
328         }
329     }
330 }
331
332 /// On some platforms like wasm32 there's no threads, so no need to generate
333 /// thread locals and we can instead just use plain statics!
334 #[doc(hidden)]
335 #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
336 pub mod statik {
337     use super::lazy::LazyKeyInner;
338     use crate::fmt;
339
340     pub struct Key<T> {
341         inner: LazyKeyInner<T>,
342     }
343
344     unsafe impl<T> Sync for Key<T> {}
345
346     impl<T> fmt::Debug for Key<T> {
347         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348             f.pad("Key { .. }")
349         }
350     }
351
352     impl<T> Key<T> {
353         pub const fn new() -> Key<T> {
354             Key { inner: LazyKeyInner::new() }
355         }
356
357         pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> {
358             let value = match self.inner.get() {
359                 Some(ref value) => value,
360                 None => self.inner.initialize(init),
361             };
362             Some(value)
363         }
364     }
365 }
366
367 #[doc(hidden)]
368 #[cfg(target_thread_local)]
369 pub mod fast {
370     use super::lazy::LazyKeyInner;
371     use crate::cell::Cell;
372     use crate::fmt;
373     use crate::mem;
374     use crate::sys::thread_local_dtor::register_dtor;
375
376     #[derive(Copy, Clone)]
377     enum DtorState {
378         Unregistered,
379         Registered,
380         RunningOrHasRun,
381     }
382
383     // This data structure has been carefully constructed so that the fast path
384     // only contains one branch on x86. That optimization is necessary to avoid
385     // duplicated tls lookups on OSX.
386     //
387     // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
388     pub struct Key<T> {
389         // If `LazyKeyInner::get` returns `None`, that indicates either:
390         //   * The value has never been initialized
391         //   * The value is being recursively initialized
392         //   * The value has already been destroyed or is being destroyed
393         // To determine which kind of `None`, check `dtor_state`.
394         //
395         // This is very optimizer friendly for the fast path - initialized but
396         // not yet dropped.
397         inner: LazyKeyInner<T>,
398
399         // Metadata to keep track of the state of the destructor. Remember that
400         // this variable is thread-local, not global.
401         dtor_state: Cell<DtorState>,
402     }
403
404     impl<T> fmt::Debug for Key<T> {
405         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406             f.pad("Key { .. }")
407         }
408     }
409
410     impl<T> Key<T> {
411         pub const fn new() -> Key<T> {
412             Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
413         }
414
415         pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
416             match self.inner.get() {
417                 Some(val) => Some(val),
418                 None => self.try_initialize(init),
419             }
420         }
421
422         // `try_initialize` is only called once per fast thread local variable,
423         // except in corner cases where thread_local dtors reference other
424         // thread_local's, or it is being recursively initialized.
425         //
426         // Macos: Inlining this function can cause two `tlv_get_addr` calls to
427         // be performed for every call to `Key::get`.
428         // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
429         #[inline(never)]
430         unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
431             if !mem::needs_drop::<T>() || self.try_register_dtor() {
432                 Some(self.inner.initialize(init))
433             } else {
434                 None
435             }
436         }
437
438         // `try_register_dtor` is only called once per fast thread local
439         // variable, except in corner cases where thread_local dtors reference
440         // other thread_local's, or it is being recursively initialized.
441         unsafe fn try_register_dtor(&self) -> bool {
442             match self.dtor_state.get() {
443                 DtorState::Unregistered => {
444                     // dtor registration happens before initialization.
445                     register_dtor(self as *const _ as *mut u8, destroy_value::<T>);
446                     self.dtor_state.set(DtorState::Registered);
447                     true
448                 }
449                 DtorState::Registered => {
450                     // recursively initialized
451                     true
452                 }
453                 DtorState::RunningOrHasRun => false,
454             }
455         }
456     }
457
458     unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
459         let ptr = ptr as *mut Key<T>;
460
461         // Right before we run the user destructor be sure to set the
462         // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
463         // causes future calls to `get` to run `try_initialize_drop` again,
464         // which will now fail, and return `None`.
465         let value = (*ptr).inner.take();
466         (*ptr).dtor_state.set(DtorState::RunningOrHasRun);
467         drop(value);
468     }
469 }
470
471 #[doc(hidden)]
472 pub mod os {
473     use super::lazy::LazyKeyInner;
474     use crate::cell::Cell;
475     use crate::fmt;
476     use crate::marker;
477     use crate::ptr;
478     use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
479
480     pub struct Key<T> {
481         // OS-TLS key that we'll use to key off.
482         os: OsStaticKey,
483         marker: marker::PhantomData<Cell<T>>,
484     }
485
486     impl<T> fmt::Debug for Key<T> {
487         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
488             f.pad("Key { .. }")
489         }
490     }
491
492     unsafe impl<T> Sync for Key<T> {}
493
494     struct Value<T: 'static> {
495         inner: LazyKeyInner<T>,
496         key: &'static Key<T>,
497     }
498
499     impl<T: 'static> Key<T> {
500         pub const fn new() -> Key<T> {
501             Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
502         }
503
504         pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> {
505             let ptr = self.os.get() as *mut Value<T>;
506             if ptr as usize > 1 {
507                 if let Some(ref value) = (*ptr).inner.get() {
508                     return Some(value);
509                 }
510             }
511             self.try_initialize(init)
512         }
513
514         // `try_initialize` is only called once per os thread local variable,
515         // except in corner cases where thread_local dtors reference other
516         // thread_local's, or it is being recursively initialized.
517         unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> {
518             let ptr = self.os.get() as *mut Value<T>;
519             if ptr as usize == 1 {
520                 // destructor is running
521                 return None;
522             }
523
524             let ptr = if ptr.is_null() {
525                 // If the lookup returned null, we haven't initialized our own
526                 // local copy, so do that now.
527                 let ptr: Box<Value<T>> = box Value { inner: LazyKeyInner::new(), key: self };
528                 let ptr = Box::into_raw(ptr);
529                 self.os.set(ptr as *mut u8);
530                 ptr
531             } else {
532                 // recursive initialization
533                 ptr
534             };
535
536             Some((*ptr).inner.initialize(init))
537         }
538     }
539
540     unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
541         // The OS TLS ensures that this key contains a NULL value when this
542         // destructor starts to run. We set it back to a sentinel value of 1 to
543         // ensure that any future calls to `get` for this thread will return
544         // `None`.
545         //
546         // Note that to prevent an infinite loop we reset it back to null right
547         // before we return from the destructor ourselves.
548         let ptr = Box::from_raw(ptr as *mut Value<T>);
549         let key = ptr.key;
550         key.os.set(1 as *mut u8);
551         drop(ptr);
552         key.os.set(ptr::null_mut());
553     }
554 }