thread_local_internal.h 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. #if DCHECK_IS_ON()
  7. #include <atomic>
  8. #include <memory>
  9. #include <ostream>
  10. #include "base/macros.h"
  11. #include "base/threading/thread_local_storage.h"
  12. namespace base {
  13. namespace internal {
  14. // A version of ThreadLocalOwnedPointer which verifies that it's only destroyed
  15. // when no threads, other than the one it is destroyed on, have remaining state
  16. // set in it. A ThreadLocalOwnedPointer instance being destroyed too early would
  17. // result in leaks per unregistering the TLS slot (and thus the DeleteTlsPtr
  18. // hook).
  19. template <typename T>
  20. class CheckedThreadLocalOwnedPointer {
  21. public:
  22. CheckedThreadLocalOwnedPointer() = default;
  23. ~CheckedThreadLocalOwnedPointer() {
  24. Set(nullptr);
  25. DCHECK_EQ(num_assigned_threads_.load(std::memory_order_relaxed), 0)
  26. << "Memory leak: Must join all threads or release all associated "
  27. "thread-local slots before ~ThreadLocalOwnedPointer";
  28. }
  29. T* Get() const {
  30. PtrTracker* const ptr_tracker = static_cast<PtrTracker*>(slot_.Get());
  31. return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr;
  32. }
  33. void Set(std::unique_ptr<T> ptr) {
  34. delete static_cast<PtrTracker*>(slot_.Get());
  35. if (ptr)
  36. slot_.Set(new PtrTracker(this, std::move(ptr)));
  37. else
  38. slot_.Set(nullptr);
  39. }
  40. private:
  41. struct PtrTracker {
  42. public:
  43. PtrTracker(CheckedThreadLocalOwnedPointer<T>* outer, std::unique_ptr<T> ptr)
  44. : outer_(outer), ptr_(std::move(ptr)) {
  45. outer_->num_assigned_threads_.fetch_add(1, std::memory_order_relaxed);
  46. }
  47. ~PtrTracker() {
  48. outer_->num_assigned_threads_.fetch_sub(1, std::memory_order_relaxed);
  49. }
  50. CheckedThreadLocalOwnedPointer<T>* const outer_;
  51. const std::unique_ptr<T> ptr_;
  52. };
  53. static void DeleteTlsPtr(void* ptr) { delete static_cast<PtrTracker*>(ptr); }
  54. ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
  55. std::atomic_int num_assigned_threads_{0};
  56. DISALLOW_COPY_AND_ASSIGN(CheckedThreadLocalOwnedPointer<T>);
  57. };
  58. } // namespace internal
  59. } // namespace base
  60. #endif // DCHECK_IS_ON()
  61. #endif // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_