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