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