tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

thread_local_internal.h (2782B)


      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 
     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 
     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 
     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:
     72    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 
     77    ~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 
     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_