72 lines
2.5 KiB
C++
72 lines
2.5 KiB
C++
// 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_
|