summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/base/threading/thread_local_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium/base/threading/thread_local_internal.h')
-rw-r--r--security/sandbox/chromium/base/threading/thread_local_internal.h80
1 files changed, 80 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/threading/thread_local_internal.h b/security/sandbox/chromium/base/threading/thread_local_internal.h
new file mode 100644
index 0000000000..6f7fdc9768
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local_internal.h
@@ -0,0 +1,80 @@
+// 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_