}
void StaticMetaBase::onThreadExit(void* ptr) {
+#ifdef FOLLY_TLD_USE_FOLLY_TLS
+ auto threadEntry = static_cast<ThreadEntry*>(ptr);
+#else
std::unique_ptr<ThreadEntry> threadEntry(static_cast<ThreadEntry*>(ptr));
+#endif
DCHECK_GT(threadEntry->elementsCapacity, 0);
auto& meta = *threadEntry->meta;
+
+ // Make sure this ThreadEntry is available if ThreadLocal A is accessed in
+ // ThreadLocal B destructor.
+ pthread_setspecific(meta.pthreadKey_, threadEntry);
+ SCOPE_EXIT {
+ pthread_setspecific(meta.pthreadKey_, nullptr);
+ };
+
{
std::lock_guard<std::mutex> g(meta.lock_);
- meta.erase(threadEntry.get());
+ meta.erase(&(*threadEntry));
// No need to hold the lock any longer; the ThreadEntry is private to this
// thread now that it's been removed from meta.
}
free(reallocated);
}
-ElementWrapper& StaticMetaBase::get(EntryID* ent) {
- ThreadEntry* threadEntry = (*threadEntry_)();
- uint32_t id = ent->getOrInvalid();
- // if id is invalid, it is equal to uint32_t's max value.
- // x <= max value is always true
- if (UNLIKELY(threadEntry->elementsCapacity <= id)) {
- reserve(ent);
- id = ent->getOrInvalid();
- assert(threadEntry->elementsCapacity > id);
- }
- return threadEntry->elements[id];
-}
-
FOLLY_STATIC_CTOR_PRIORITY_MAX
PthreadKeyUnregister PthreadKeyUnregister::instance_;
}}
// StaticMeta; you can specify multiple Tag types to break that lock.
template <class Tag>
struct StaticMeta : StaticMetaBase {
- StaticMeta() : StaticMetaBase(&StaticMeta::getThreadEntry) {
+ StaticMeta() : StaticMetaBase(&StaticMeta::getThreadEntrySlow) {
#if FOLLY_HAVE_PTHREAD_ATFORK
int ret = pthread_atfork(
/*prepare*/ &StaticMeta::preFork,
return *instance;
}
+ ElementWrapper& get(EntryID* ent) {
+ ThreadEntry* threadEntry = getThreadEntry();
+ uint32_t id = ent->getOrInvalid();
+ // if id is invalid, it is equal to uint32_t's max value.
+ // x <= max value is always true
+ if (UNLIKELY(threadEntry->elementsCapacity <= id)) {
+ reserve(ent);
+ id = ent->getOrInvalid();
+ assert(threadEntry->elementsCapacity > id);
+ }
+ return threadEntry->elements[id];
+ }
+
static ThreadEntry* getThreadEntrySlow() {
auto& meta = instance();
auto key = meta.pthreadKey_;
ThreadEntry* threadEntry =
static_cast<ThreadEntry*>(pthread_getspecific(key));
if (!threadEntry) {
+#ifdef FOLLY_TLD_USE_FOLLY_TLS
+ static FOLLY_TLS ThreadEntry threadEntrySingleton;
+ threadEntry = &threadEntrySingleton;
+#else
threadEntry = new ThreadEntry();
+#endif
threadEntry->meta = &meta;
int ret = pthread_setspecific(key, threadEntry);
checkPosixError(ret, "pthread_setspecific failed");
return threadEntry;
}
- static ThreadEntry* getThreadEntry() {
+ inline static ThreadEntry* getThreadEntry() {
#ifdef FOLLY_TLD_USE_FOLLY_TLS
static FOLLY_TLS ThreadEntry* threadEntryCache{nullptr};
if (UNLIKELY(threadEntryCache == nullptr)) {
- threadEntryCache = getThreadEntrySlow();
+ threadEntryCache = instance().threadEntry_();
}
return threadEntryCache;
#else
- return getThreadEntrySlow();
+ return instance().threadEntry_();
#endif
}