// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_THREADING_THREAD_LOCAL_INTERNAL_H_ #define BASE_THREADING_THREAD_LOCAL_INTERNAL_H_ #if DCHECK_IS_ON() #include #include #include #include "base/macros.h" #include "base/threading/thread_local_storage.h" namespace base { namespace internal { // A version of ThreadLocalOwnedPointer which verifies that it's only destroyed // when no threads, other than the one it is destroyed on, have remaining state // set in it. A ThreadLocalOwnedPointer instance being destroyed too early would // result in leaks per unregistering the TLS slot (and thus the DeleteTlsPtr // hook). template class CheckedThreadLocalOwnedPointer { public: CheckedThreadLocalOwnedPointer() = default; ~CheckedThreadLocalOwnedPointer() { Set(nullptr); DCHECK_EQ(num_assigned_threads_.load(std::memory_order_relaxed), 0) << "Memory leak: Must join all threads or release all associated " "thread-local slots before ~ThreadLocalOwnedPointer"; } T* Get() const { PtrTracker* const ptr_tracker = static_cast(slot_.Get()); return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr; } void Set(std::unique_ptr ptr) { delete static_cast(slot_.Get()); if (ptr) slot_.Set(new PtrTracker(this, std::move(ptr))); else slot_.Set(nullptr); } private: struct PtrTracker { public: PtrTracker(CheckedThreadLocalOwnedPointer* outer, std::unique_ptr ptr) : outer_(outer), ptr_(std::move(ptr)) { outer_->num_assigned_threads_.fetch_add(1, std::memory_order_relaxed); } ~PtrTracker() { outer_->num_assigned_threads_.fetch_sub(1, std::memory_order_relaxed); } CheckedThreadLocalOwnedPointer* const outer_; const std::unique_ptr ptr_; }; static void DeleteTlsPtr(void* ptr) { delete static_cast(ptr); } ThreadLocalStorage::Slot slot_{&DeleteTlsPtr}; std::atomic_int num_assigned_threads_{0}; DISALLOW_COPY_AND_ASSIGN(CheckedThreadLocalOwnedPointer); }; } // namespace internal } // namespace base #endif // DCHECK_IS_ON() #endif // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_