| // Copyright 2011 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // WARNING: Thread local storage is a bit tricky to get right. Please make sure |
| // that this is really the proper solution for what you're trying to achieve. |
| // Don't prematurely optimize, most likely you can just use a Lock. |
| |
| #ifndef BASE_THREADING_THREAD_LOCAL_H_ |
| #define BASE_THREADING_THREAD_LOCAL_H_ |
| |
| #include <memory> |
| |
| #include "base/dcheck_is_on.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/threading/thread_local_internal.h" |
| #include "base/threading/thread_local_storage.h" |
| |
| namespace base { |
| |
| // `thread_local` is only allowed for trivially-destructible types (see |
| // //styleguide/c++/c++.md#thread_local-variables). This class provides |
| // thread-scoped management of non-trivially-destructible types. Pointers handed |
| // to it are owned and automatically deleted during their associated thread's |
| // exit phase (or when replaced if Set() is invoked multiple times on the same |
| // thread). |
| // |
| // The ThreadLocalOwnedPointer instance itself can only be destroyed when no |
| // threads, other than the one it is destroyed on, have remaining state set in |
| // it. Typically this means that ThreadLocalOwnedPointer instances are held in |
| // static storage or at the very least only recycled in the single-threaded |
| // phase between tests in the same process. |
| #if DCHECK_IS_ON() |
| template <typename T> |
| using ThreadLocalOwnedPointer = internal::CheckedThreadLocalOwnedPointer<T>; |
| #else // DCHECK_IS_ON() |
| template <typename T> |
| class ThreadLocalOwnedPointer { |
| public: |
| ThreadLocalOwnedPointer() = default; |
| |
| ThreadLocalOwnedPointer(const ThreadLocalOwnedPointer&) = delete; |
| ThreadLocalOwnedPointer& operator=(const ThreadLocalOwnedPointer&) = delete; |
| |
| ~ThreadLocalOwnedPointer() { |
| // Assume that this thread is the only one with potential state left. This |
| // is verified in ~CheckedThreadLocalOwnedPointer(). |
| Set(nullptr); |
| } |
| |
| T* Get() const { return static_cast<T*>(slot_.Get()); } |
| |
| // Sets a new value, returns the old. |
| std::unique_ptr<T> Set(std::unique_ptr<T> ptr) { |
| auto existing = WrapUnique(Get()); |
| slot_.Set(const_cast<void*>(static_cast<const void*>(ptr.release()))); |
| return existing; |
| } |
| |
| T& operator*() { return *Get(); } |
| |
| private: |
| static void DeleteTlsPtr(void* ptr) { delete static_cast<T*>(ptr); } |
| |
| ThreadLocalStorage::Slot slot_{&DeleteTlsPtr}; |
| }; |
| #endif // DCHECK_IS_ON() |
| |
| } // namespace base |
| |
| #endif // BASE_THREADING_THREAD_LOCAL_H_ |