Commit 64484582 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

assume thread_local in StaticMeta

Reviewed By: Orvid

Differential Revision: D27671636

fbshipit-source-id: 82cab152ecb606235ee66c026ecafecfe52a88a5
parent 94d0da77
...@@ -76,37 +76,37 @@ StaticMetaBase::StaticMetaBase(ThreadEntry* (*threadEntry)(), bool strict) ...@@ -76,37 +76,37 @@ StaticMetaBase::StaticMetaBase(ThreadEntry* (*threadEntry)(), bool strict)
} }
ThreadEntryList* StaticMetaBase::getThreadEntryList() { ThreadEntryList* StaticMetaBase::getThreadEntryList() {
#ifdef FOLLY_TLD_USE_FOLLY_TLS if (kUseThreadLocal) {
static thread_local ThreadEntryList threadEntryListSingleton; static thread_local ThreadEntryList threadEntryListSingleton;
return &threadEntryListSingleton; return &threadEntryListSingleton;
#else } else {
class PthreadKey { class PthreadKey {
public: public:
PthreadKey() { PthreadKey() {
int ret = pthread_key_create(&pthreadKey_, nullptr); int ret = pthread_key_create(&pthreadKey_, nullptr);
checkPosixError(ret, "pthread_key_create failed"); checkPosixError(ret, "pthread_key_create failed");
PthreadKeyUnregister::registerKey(pthreadKey_); PthreadKeyUnregister::registerKey(pthreadKey_);
} }
FOLLY_ALWAYS_INLINE pthread_key_t get() const { return pthreadKey_; } FOLLY_ALWAYS_INLINE pthread_key_t get() const { return pthreadKey_; }
private: private:
pthread_key_t pthreadKey_; pthread_key_t pthreadKey_;
}; };
auto& instance = detail::createGlobal<PthreadKey, void>(); auto& instance = detail::createGlobal<PthreadKey, void>();
ThreadEntryList* threadEntryList = ThreadEntryList* threadEntryList =
static_cast<ThreadEntryList*>(pthread_getspecific(instance.get())); static_cast<ThreadEntryList*>(pthread_getspecific(instance.get()));
if (UNLIKELY(!threadEntryList)) { if (UNLIKELY(!threadEntryList)) {
threadEntryList = new ThreadEntryList(); threadEntryList = new ThreadEntryList();
int ret = pthread_setspecific(instance.get(), threadEntryList); int ret = pthread_setspecific(instance.get(), threadEntryList);
checkPosixError(ret, "pthread_setspecific failed"); checkPosixError(ret, "pthread_setspecific failed");
} }
return threadEntryList; return threadEntryList;
#endif }
} }
bool StaticMetaBase::dying() { bool StaticMetaBase::dying() {
...@@ -207,14 +207,14 @@ void StaticMetaBase::onThreadExit(void* ptr) { ...@@ -207,14 +207,14 @@ void StaticMetaBase::onThreadExit(void* ptr) {
tmp->setElementsCapacity(0); tmp->setElementsCapacity(0);
} }
#ifndef FOLLY_TLD_USE_FOLLY_TLS if (!kUseThreadLocal) {
delete tmp; delete tmp;
#endif }
} }
#ifndef FOLLY_TLD_USE_FOLLY_TLS if (!kUseThreadLocal) {
delete threadEntryList; delete threadEntryList;
#endif }
} }
uint32_t StaticMetaBase::elementsCapacity() const { uint32_t StaticMetaBase::elementsCapacity() const {
......
...@@ -41,18 +41,6 @@ ...@@ -41,18 +41,6 @@
#include <folly/synchronization/MicroSpinLock.h> #include <folly/synchronization/MicroSpinLock.h>
#include <folly/system/ThreadId.h> #include <folly/system/ThreadId.h>
// In general, emutls cleanup is not guaranteed to play nice with the way
// StaticMeta mixes direct pthread calls and the use of __thread. This has
// caused problems on multiple platforms so don't use __thread there.
//
// XXX: Ideally we would instead determine if emutls is in use at runtime as it
// is possible to configure glibc on Linux to use emutls regardless.
#if !FOLLY_MOBILE && !defined(__APPLE__) && !defined(_MSC_VER)
#define FOLLY_TLD_USE_FOLLY_TLS 1
#else
#undef FOLLY_TLD_USE_FOLLY_TLS
#endif
namespace folly { namespace folly {
enum class TLPDestructionMode { THIS_THREAD, ALL_THREADS }; enum class TLPDestructionMode { THIS_THREAD, ALL_THREADS };
...@@ -299,6 +287,14 @@ class PthreadKeyUnregister { ...@@ -299,6 +287,14 @@ class PthreadKeyUnregister {
}; };
struct StaticMetaBase { struct StaticMetaBase {
// In general, emutls cleanup is not guaranteed to play nice with the way
// StaticMeta mixes direct pthread calls and the use of __thread. This has
// caused problems on multiple platforms so don't use __thread there.
//
// XXX: Ideally we would instead determine if emutls is in use at runtime as
// it is possible to configure glibc on Linux to use emutls regardless.
static constexpr bool kUseThreadLocal = !kIsMobile && !kIsApple && !kMscVer;
// Represents an ID of a thread local object. Initially set to the maximum // Represents an ID of a thread local object. Initially set to the maximum
// uint. This representation allows us to avoid a branch in accessing TLS data // uint. This representation allows us to avoid a branch in accessing TLS data
// (because if you test capacity > id if id = maxint then the test will always // (because if you test capacity > id if id = maxint then the test will always
...@@ -415,13 +411,15 @@ struct FOLLY_EXPORT StaticMeta final : StaticMetaBase { ...@@ -415,13 +411,15 @@ struct FOLLY_EXPORT StaticMeta final : StaticMetaBase {
// Eliminate as many branches and as much extra code as possible in the // Eliminate as many branches and as much extra code as possible in the
// cached fast path, leaving only one branch here and one indirection below. // cached fast path, leaving only one branch here and one indirection below.
uint32_t id = ent->getOrInvalid(); uint32_t id = ent->getOrInvalid();
#ifdef FOLLY_TLD_USE_FOLLY_TLS
static thread_local ThreadEntry* threadEntry{}; static thread_local ThreadEntry* threadEntryTL{};
static thread_local size_t capacity{}; ThreadEntry* threadEntryNonTL{};
#else auto& threadEntry = kUseThreadLocal ? threadEntryTL : threadEntryNonTL;
ThreadEntry* threadEntry{};
size_t capacity{}; static thread_local size_t capacityTL{};
#endif size_t capacityNonTL{};
auto& capacity = kUseThreadLocal ? capacityTL : capacityNonTL;
if (FOLLY_UNLIKELY(capacity <= id)) { if (FOLLY_UNLIKELY(capacity <= id)) {
getSlowReserveAndCache(ent, id, threadEntry, capacity); getSlowReserveAndCache(ent, id, threadEntry, capacity);
} }
...@@ -447,12 +445,12 @@ struct FOLLY_EXPORT StaticMeta final : StaticMetaBase { ...@@ -447,12 +445,12 @@ struct FOLLY_EXPORT StaticMeta final : StaticMetaBase {
static_cast<ThreadEntry*>(pthread_getspecific(key)); static_cast<ThreadEntry*>(pthread_getspecific(key));
if (!threadEntry) { if (!threadEntry) {
ThreadEntryList* threadEntryList = StaticMeta::getThreadEntryList(); ThreadEntryList* threadEntryList = StaticMeta::getThreadEntryList();
#ifdef FOLLY_TLD_USE_FOLLY_TLS if (kUseThreadLocal) {
static thread_local ThreadEntry threadEntrySingleton; static thread_local ThreadEntry threadEntrySingleton;
threadEntry = &threadEntrySingleton; threadEntry = &threadEntrySingleton;
#else } else {
threadEntry = new ThreadEntry(); threadEntry = new ThreadEntry();
#endif }
// if the ThreadEntry already exists // if the ThreadEntry already exists
// but pthread_getspecific returns NULL // but pthread_getspecific returns NULL
// do not add the same entry twice to the list // do not add the same entry twice to the list
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment