tls.rs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. //! Safe implementation of thread-local storage.
  2. //!
  3. //! This module provides lightweight abstractions for TLS similar to the ones provided by libstd.
  4. use core::{marker, mem};
  5. use sys;
  6. /// A thread-local container.
  7. pub struct Key<T: 'static> {
  8. /// The inner data.
  9. inner: T,
  10. }
  11. impl<T: 'static> Key<T> {
  12. /// Create a new `Key` wrapper.
  13. ///
  14. /// # Safety
  15. ///
  16. /// This is invariant-breaking (assumes thread-safety) and thus unsafe.
  17. pub const unsafe fn new(inner: T) -> Key<T> {
  18. Key { inner: inner }
  19. }
  20. /// Obtain a reference temporarily.
  21. ///
  22. /// Due to [the lack of thread lifetimes](https://github.com/rust-lang/rfcs/pull/1705#issuecomment-238015901), we use a closure to make sure no leakage happens.
  23. ///
  24. /// Having a reference newtype would be unsound, due to the ability to leak a reference to
  25. /// another thread.
  26. #[inline]
  27. pub fn with<F, R>(&'static self, f: F) -> R
  28. where F: FnOnce(&T) -> R {
  29. f(&self.inner)
  30. }
  31. /// Register a TLS destructor on the current thread.
  32. ///
  33. /// Note that this has to be registered for every thread, it is needed for.
  34. // TODO: Make this automatic on `Drop`.
  35. #[inline]
  36. pub fn register_thread_destructor(&'static self, dtor: extern fn(&T)) -> Result<(), ()> {
  37. sys::register_thread_destructor(&self.inner as *const T as *mut T, unsafe { mem::transmute(dtor) })
  38. }
  39. }
  40. unsafe impl<T> marker::Sync for Key<T> {}
  41. /// Declare a thread-local static variable.
  42. ///
  43. /// TLS works by copying the initial data on every new thread creation. This allows access to a
  44. /// variable, which is only available for the current thread, meaning that there is no need for
  45. /// syncronization.
  46. ///
  47. /// For this reason, in contrast to other `static`s in Rust, this need not thread-safety, which is
  48. /// what this macro "fixes".
  49. macro_rules! tls {
  50. (static $name:ident: $ty:ty = $val:expr;) => { tls! { #[] static $name: $ty = $val; } };
  51. (#[$($attr:meta),*] static $name:ident: $ty:ty = $val:expr;) => {
  52. $(#[$attr])*
  53. #[thread_local]
  54. static $name: tls::Key<$ty> = unsafe { tls::Key::new($val) };
  55. }
  56. }