thread_local_internal.h 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
  5. #define BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
  6. #include "base/dcheck_is_on.h"
  7. #if DCHECK_IS_ON()
  8. #include <atomic>
  9. #include <memory>
  10. #include <ostream>
  11. #include "base/check_op.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/threading/thread_local_storage.h"
  14. namespace base {
  15. namespace internal {
  16. // A version of ThreadLocalOwnedPointer which verifies that it's only destroyed
  17. // when no threads, other than the one it is destroyed on, have remaining state
  18. // set in it. A ThreadLocalOwnedPointer instance being destroyed too early would
  19. // result in leaks per unregistering the TLS slot (and thus the DeleteTlsPtr
  20. // hook).
  21. template <typename T>
  22. class CheckedThreadLocalOwnedPointer {
  23. public:
  24. CheckedThreadLocalOwnedPointer() = default;
  25. CheckedThreadLocalOwnedPointer<T>(const CheckedThreadLocalOwnedPointer<T>&) =
  26. delete;
  27. CheckedThreadLocalOwnedPointer<T>& operator=(
  28. const CheckedThreadLocalOwnedPointer<T>&) = delete;
  29. ~CheckedThreadLocalOwnedPointer() {
  30. Set(nullptr);
  31. DCHECK_EQ(num_assigned_threads_.load(std::memory_order_relaxed), 0)
  32. << "Memory leak: Must join all threads or release all associated "
  33. "thread-local slots before ~ThreadLocalOwnedPointer";
  34. }
  35. T* Get() const {
  36. PtrTracker* const ptr_tracker = static_cast<PtrTracker*>(slot_.Get());
  37. return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr;
  38. }
  39. std::unique_ptr<T> Set(std::unique_ptr<T> ptr) {
  40. std::unique_ptr<T> existing_ptr;
  41. auto existing_tracker = static_cast<PtrTracker*>(slot_.Get());
  42. if (existing_tracker) {
  43. existing_ptr = std::move(existing_tracker->ptr_);
  44. delete existing_tracker;
  45. }
  46. if (ptr)
  47. slot_.Set(new PtrTracker(this, std::move(ptr)));
  48. else
  49. slot_.Set(nullptr);
  50. return existing_ptr;
  51. }
  52. T& operator*() { return *Get(); }
  53. private:
  54. struct PtrTracker {
  55. public:
  56. PtrTracker(CheckedThreadLocalOwnedPointer<T>* outer, std::unique_ptr<T> ptr)
  57. : outer_(outer), ptr_(std::move(ptr)) {
  58. outer_->num_assigned_threads_.fetch_add(1, std::memory_order_relaxed);
  59. }
  60. ~PtrTracker() {
  61. outer_->num_assigned_threads_.fetch_sub(1, std::memory_order_relaxed);
  62. }
  63. const raw_ptr<CheckedThreadLocalOwnedPointer<T>> outer_;
  64. std::unique_ptr<T> ptr_;
  65. };
  66. static void DeleteTlsPtr(void* ptr) { delete static_cast<PtrTracker*>(ptr); }
  67. ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
  68. std::atomic_int num_assigned_threads_{0};
  69. };
  70. } // namespace internal
  71. } // namespace base
  72. #endif // DCHECK_IS_ON()
  73. #endif // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_