tls.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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 shim::thread_destructor;
  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. // Logging.
  30. log!(INTERNAL, "Accessing TLS variable.");
  31. f(&self.inner)
  32. }
  33. /// Register a TLS destructor on the current thread.
  34. ///
  35. /// Note that this has to be registered for every thread, it is needed for.
  36. // TODO: Make this automatic on `Drop`.
  37. #[inline]
  38. pub fn register_thread_destructor(&'static self, dtor: extern fn(&T)) {
  39. // Logging.
  40. log!(INTERNAL, "Registering thread destructor.");
  41. thread_destructor::register(&self.inner as *const T as *const u8 as *mut u8, unsafe {
  42. // LAST AUDIT: 2016-08-21 (Ticki).
  43. // This is safe due to sharing memory layout.
  44. mem::transmute(dtor)
  45. });
  46. }
  47. }
  48. unsafe impl<T> marker::Sync for Key<T> {}
  49. /// Declare a thread-local static variable.
  50. ///
  51. /// TLS works by copying the initial data on every new thread creation. This allows access to a
  52. /// variable, which is only available for the current thread, meaning that there is no need for
  53. /// syncronization.
  54. ///
  55. /// For this reason, in contrast to other `static`s in Rust, this need not thread-safety, which is
  56. /// what this macro "fixes".
  57. macro_rules! tls {
  58. (static $name:ident: $ty:ty = $val:expr;) => { tls! { #[] static $name: $ty = $val; } };
  59. (#[$($attr:meta),*] static $name:ident: $ty:ty = $val:expr;) => {
  60. $(#[$attr])*
  61. #[thread_local]
  62. static $name: tls::Key<$ty> = unsafe {
  63. // LAST AUDIT: 2016-08-21 (Ticki).
  64. // This is secure due to being stored in a thread-local variable and thus being bounded
  65. // by the current thread.
  66. tls::Key::new($val)
  67. };
  68. }
  69. }