X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=folly%2FThreadLocal.h;h=b47742072a65a9c837872edf602b8fe4989b9137;hb=6c76acfc86177dd2570bf80411baa47dd2b74c72;hp=4ecc757ad440dc983c6842a010e905395d31bdcd;hpb=22afce906d7e98d95f8c45c3301072d9fd891d41;p=folly.git diff --git a/folly/ThreadLocal.h b/folly/ThreadLocal.h index 4ecc757a..b4774207 100644 --- a/folly/ThreadLocal.h +++ b/folly/ThreadLocal.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,14 +34,14 @@ * @author Spencer Ahrens (sahrens) */ -#ifndef FOLLY_THREADLOCAL_H_ -#define FOLLY_THREADLOCAL_H_ +#pragma once -#include "folly/Portability.h" +#include +#include +#include #include -#include "folly/Likely.h" #include - +#include namespace folly { enum class TLPDestructionMode { @@ -50,7 +50,7 @@ enum class TLPDestructionMode { }; } // namespace -#include "folly/detail/ThreadLocalDetail.h" +#include namespace folly { @@ -59,7 +59,13 @@ template class ThreadLocalPtr; template class ThreadLocal { public: - ThreadLocal() { } + constexpr ThreadLocal() : constructor_([]() { + return new T(); + }) {} + + explicit ThreadLocal(std::function constructor) : + constructor_(constructor) { + } T* get() const { T* ptr = tlp_.get(); @@ -98,12 +104,13 @@ class ThreadLocal { ThreadLocal& operator=(const ThreadLocal&) = delete; T* makeTlp() const { - T* ptr = new T(); + auto ptr = constructor_(); tlp_.reset(ptr); return ptr; } mutable ThreadLocalPtr tlp_; + std::function constructor_; }; /* @@ -128,23 +135,25 @@ class ThreadLocal { * NOTE: Apple platforms don't support the same semantics for __thread that * Linux does (and it's only supported at all on i386). For these, use * pthread_setspecific()/pthread_getspecific() for the per-thread - * storage. + * storage. Windows (MSVC and GCC) does support the same semantics + * with __declspec(thread) */ template class ThreadLocalPtr { + private: + typedef threadlocal_detail::StaticMeta StaticMeta; public: - ThreadLocalPtr() : id_(threadlocal_detail::StaticMeta::create()) { } + constexpr ThreadLocalPtr() : id_() {} - ThreadLocalPtr(ThreadLocalPtr&& other) : id_(other.id_) { - other.id_ = 0; + ThreadLocalPtr(ThreadLocalPtr&& other) noexcept : + id_(std::move(other.id_)) { } ThreadLocalPtr& operator=(ThreadLocalPtr&& other) { assert(this != &other); destroy(); - id_ = other.id_; - other.id_ = 0; + id_ = std::move(other.id_); return *this; } @@ -153,7 +162,8 @@ class ThreadLocalPtr { } T* get() const { - return static_cast(threadlocal_detail::StaticMeta::get(id_).ptr); + threadlocal_detail::ElementWrapper& w = StaticMeta::instance().get(&id_); + return static_cast(w.ptr); } T* operator->() const { @@ -164,34 +174,72 @@ class ThreadLocalPtr { return *get(); } + T* release() { + threadlocal_detail::ElementWrapper& w = StaticMeta::instance().get(&id_); + + return static_cast(w.release()); + } + void reset(T* newPtr = nullptr) { - threadlocal_detail::ElementWrapper& w = - threadlocal_detail::StaticMeta::get(id_); - if (w.ptr != newPtr) { - w.dispose(TLPDestructionMode::THIS_THREAD); - w.set(newPtr); - } + auto guard = makeGuard([&] { delete newPtr; }); + threadlocal_detail::ElementWrapper& w = StaticMeta::instance().get(&id_); + + w.dispose(TLPDestructionMode::THIS_THREAD); + guard.dismiss(); + w.set(newPtr); } explicit operator bool() const { return get() != nullptr; } + /** + * reset() that transfers ownership from a smart pointer + */ + template < + typename SourceT, + typename Deleter, + typename = typename std::enable_if< + std::is_convertible::value>::type> + void reset(std::unique_ptr source) { + auto deleter = [delegate = source.get_deleter()]( + T * ptr, TLPDestructionMode) { + delegate(ptr); + }; + reset(source.release(), deleter); + } + + /** + * reset() that transfers ownership from a smart pointer with the default + * deleter + */ + template < + typename SourceT, + typename = typename std::enable_if< + std::is_convertible::value>::type> + void reset(std::unique_ptr source) { + reset(source.release()); + } + /** * reset() with a custom deleter: * deleter(T* ptr, TLPDestructionMode mode) * "mode" is ALL_THREADS if we're destructing this ThreadLocalPtr (and thus * deleting pointers for all threads), and THIS_THREAD if we're only deleting - * the member for one thread (because of thread exit or reset()) + * the member for one thread (because of thread exit or reset()). + * Invoking the deleter must not throw. */ template - void reset(T* newPtr, Deleter deleter) { - threadlocal_detail::ElementWrapper& w = - threadlocal_detail::StaticMeta::get(id_); - if (w.ptr != newPtr) { - w.dispose(TLPDestructionMode::THIS_THREAD); - w.set(newPtr, deleter); - } + void reset(T* newPtr, const Deleter& deleter) { + auto guard = makeGuard([&] { + if (newPtr) { + deleter(newPtr, TLPDestructionMode::THIS_THREAD); + } + }); + threadlocal_detail::ElementWrapper& w = StaticMeta::instance().get(&id_); + w.dispose(TLPDestructionMode::THIS_THREAD); + guard.dismiss(); + w.set(newPtr, deleter); } // Holds a global lock for iteration through all thread local child objects. @@ -200,9 +248,9 @@ class ThreadLocalPtr { class Accessor { friend class ThreadLocalPtr; - threadlocal_detail::StaticMeta& meta_; + threadlocal_detail::StaticMetaBase& meta_; std::mutex* lock_; - int id_; + uint32_t id_; public: class Iterator; @@ -215,7 +263,7 @@ class ThreadLocalPtr { boost::bidirectional_traversal_tag> { // traversal friend class Accessor; friend class boost::iterator_core_access; - const Accessor* const accessor_; + const Accessor* accessor_; threadlocal_detail::ThreadEntry* e_; void increment() { @@ -301,7 +349,7 @@ class ThreadLocalPtr { } private: - explicit Accessor(int id) + explicit Accessor(uint32_t id) : meta_(threadlocal_detail::StaticMeta::instance()), lock_(&meta_.lock_) { lock_->lock(); @@ -322,23 +370,19 @@ class ThreadLocalPtr { Accessor accessAllThreads() const { static_assert(!std::is_same::value, "Must use a unique Tag to use the accessAllThreads feature"); - return Accessor(id_); + return Accessor(id_.getOrAllocate(StaticMeta::instance())); } private: void destroy() { - if (id_) { - threadlocal_detail::StaticMeta::destroy(id_); - } + StaticMeta::instance().destroy(&id_); } // non-copyable ThreadLocalPtr(const ThreadLocalPtr&) = delete; ThreadLocalPtr& operator=(const ThreadLocalPtr&) = delete; - int id_; // every instantiation has a unique id + mutable typename StaticMeta::EntryID id_; }; } // namespace folly - -#endif /* FOLLY_THREADLOCAL_H_ */