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