81 lines
2.3 KiB
C
81 lines
2.3 KiB
C
|
// 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 <atomic>
|
||
|
#include <memory>
|
||
|
|
||
|
#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 <typename T>
|
||
|
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<PtrTracker*>(slot_.Get());
|
||
|
return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr;
|
||
|
}
|
||
|
|
||
|
void Set(std::unique_ptr<T> ptr) {
|
||
|
delete static_cast<PtrTracker*>(slot_.Get());
|
||
|
if (ptr)
|
||
|
slot_.Set(new PtrTracker(this, std::move(ptr)));
|
||
|
else
|
||
|
slot_.Set(nullptr);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
struct PtrTracker {
|
||
|
public:
|
||
|
PtrTracker(CheckedThreadLocalOwnedPointer<T>* outer, std::unique_ptr<T> 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<T>* const outer_;
|
||
|
const std::unique_ptr<T> ptr_;
|
||
|
};
|
||
|
|
||
|
static void DeleteTlsPtr(void* ptr) { delete static_cast<PtrTracker*>(ptr); }
|
||
|
|
||
|
ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
|
||
|
|
||
|
std::atomic_int num_assigned_threads_{0};
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(CheckedThreadLocalOwnedPointer<T>);
|
||
|
};
|
||
|
|
||
|
} // namespace internal
|
||
|
} // namespace base
|
||
|
|
||
|
#endif // DCHECK_IS_ON()
|
||
|
|
||
|
#endif // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
|