detail/Sleeper.h \
detail/SlowFingerprint.h \
detail/SpinLockImpl.h \
+ detail/StaticSingletonManager.h \
detail/Stats.h \
detail/ThreadLocalDetail.h \
detail/TurnSequencer.h \
futures/QueuedImmediateExecutor.cpp \
futures/ThreadWheelTimekeeper.cpp \
detail/Futex.cpp \
+ detail/StaticSingletonManager.cpp \
detail/ThreadLocalDetail.cpp \
GroupVarint.cpp \
GroupVarintTables.cpp \
namespace detail {
-// This implementation should always live in .cpp file.
-StaticSingletonManager& StaticSingletonManager::instance() {
- static StaticSingletonManager* instance = new StaticSingletonManager();
- return *instance;
-}
-
constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
}
#include <folly/Demangle.h>
#include <folly/Executor.h>
#include <folly/experimental/ReadMostlySharedPtr.h>
+#include <folly/detail/StaticSingletonManager.h>
#include <algorithm>
#include <atomic>
namespace detail {
-// This internal-use-only class is used to create all leaked Meyers singletons.
-// It guarantees that only one instance of every such singleton will ever be
-// created, even when requested from different compilation units linked
-// dynamically.
-class StaticSingletonManager {
- public:
- static StaticSingletonManager& instance();
-
- template <typename T, typename Tag, typename F>
- inline T* create(F&& creator) {
- auto& entry = [&]() mutable -> Entry<T>& {
- std::lock_guard<std::mutex> lg(mutex_);
-
- auto& id = typeid(TypePair<T, Tag>);
- auto& entryPtr = reinterpret_cast<Entry<T>*&>(map_[id]);
- if (!entryPtr) {
- entryPtr = new Entry<T>();
- }
- return *entryPtr;
- }();
-
- std::lock_guard<std::mutex> lg(entry.mutex);
-
- if (!entry.ptr) {
- entry.ptr = creator();
- }
- return entry.ptr;
- }
-
- private:
- template <typename A, typename B>
- class TypePair {};
-
- StaticSingletonManager() {}
-
- template <typename T>
- struct Entry {
- T* ptr{nullptr};
- std::mutex mutex;
- };
-
- std::unordered_map<std::type_index, intptr_t> map_;
- std::mutex mutex_;
-};
-
-template <typename T, typename Tag, typename F>
-inline T* createGlobal(F&& creator) {
- return StaticSingletonManager::instance().create<T, Tag>(
- std::forward<F>(creator));
-}
-
-template <typename T, typename Tag>
-inline T* createGlobal() {
- return createGlobal<T, Tag>([]() { return new T(); });
-}
-
struct DefaultTag {};
// A TypeDescriptor is the unique handle for a given singleton. It is
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <folly/detail/StaticSingletonManager.h>
+
+namespace folly {
+namespace detail {
+
+// This implementation should always live in .cpp file.
+StaticSingletonManager& StaticSingletonManager::instance() {
+ static StaticSingletonManager* instance = new StaticSingletonManager();
+ return *instance;
+}
+}
+}
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <typeindex>
+#include <unordered_map>
+
+namespace folly {
+namespace detail {
+
+// This internal-use-only class is used to create all leaked Meyers singletons.
+// It guarantees that only one instance of every such singleton will ever be
+// created, even when requested from different compilation units linked
+// dynamically.
+class StaticSingletonManager {
+ public:
+ static StaticSingletonManager& instance();
+
+ template <typename T, typename Tag, typename F>
+ inline T* create(F&& creator) {
+ auto& entry = [&]() mutable -> Entry<T>& {
+ std::lock_guard<std::mutex> lg(mutex_);
+
+ auto& id = typeid(TypePair<T, Tag>);
+ auto& entryPtr = map_[id];
+ if (!entryPtr) {
+ entryPtr = new Entry<T>();
+ }
+ assert(dynamic_cast<Entry<T>*>(entryPtr) != nullptr);
+ return *static_cast<Entry<T>*>(entryPtr);
+ }();
+
+ std::lock_guard<std::mutex> lg(entry.mutex);
+
+ if (!entry.ptr) {
+ entry.ptr = creator();
+ }
+ return entry.ptr;
+ }
+
+ private:
+ template <typename A, typename B>
+ class TypePair {};
+
+ StaticSingletonManager() {}
+
+ struct EntryIf {
+ virtual ~EntryIf() {}
+ };
+
+ template <typename T>
+ struct Entry : public EntryIf {
+ T* ptr{nullptr};
+ std::mutex mutex;
+ };
+
+ std::unordered_map<std::type_index, EntryIf*> map_;
+ std::mutex mutex_;
+};
+
+template <typename T, typename Tag, typename F>
+inline T* createGlobal(F&& creator) {
+ return StaticSingletonManager::instance().create<T, Tag>(
+ std::forward<F>(creator));
+}
+
+template <typename T, typename Tag>
+inline T* createGlobal() {
+ return createGlobal<T, Tag>([]() { return new T(); });
+}
+}
+}
#include <folly/Malloc.h>
#include <folly/MicroSpinLock.h>
+#include <folly/detail/StaticSingletonManager.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.
* (under the lock).
*/
struct ThreadEntry {
- ElementWrapper* elements;
- size_t elementsCapacity;
- ThreadEntry* next;
- ThreadEntry* prev;
+ ElementWrapper* elements{nullptr};
+ size_t elementsCapacity{0};
+ ThreadEntry* next{nullptr};
+ ThreadEntry* prev{nullptr};
};
constexpr uint32_t kEntryIDInvalid = std::numeric_limits<uint32_t>::max();
static StaticMeta<Tag>& instance() {
// Leak it on exit, there's only one per process and we don't have to
// worry about synchronization with exiting threads.
- static bool constructed = (inst_ = new StaticMeta<Tag>());
- (void)constructed; // suppress unused warning
- return *inst_;
+ static auto instance = detail::createGlobal<StaticMeta<Tag>, void>();
+ return *instance;
}
uint32_t nextId_;
t->next = t->prev = t;
}
-#ifdef FOLLY_TLD_USE_FOLLY_TLS
- static FOLLY_TLS ThreadEntry threadEntry_;
-#endif
- static StaticMeta<Tag>* inst_;
-
StaticMeta() : nextId_(1) {
head_.next = head_.prev = &head_;
int ret = pthread_key_create(&pthreadKey_, &onThreadExit);
LOG(FATAL) << "StaticMeta lives forever!";
}
- static ThreadEntry* getThreadEntry() {
-#ifdef FOLLY_TLD_USE_FOLLY_TLS
- return &threadEntry_;
-#else
+ static ThreadEntry* getThreadEntrySlow() {
auto key = instance().pthreadKey_;
ThreadEntry* threadEntry =
static_cast<ThreadEntry*>(pthread_getspecific(key));
checkPosixError(ret, "pthread_setspecific failed");
}
return threadEntry;
+ }
+
+ static ThreadEntry* getThreadEntry() {
+#ifdef FOLLY_TLD_USE_FOLLY_TLS
+ static FOLLY_TLS ThreadEntry* threadEntryCache{nullptr};
+ if (UNLIKELY(threadEntryCache == nullptr)) {
+ threadEntryCache = getThreadEntrySlow();
+ }
+ return threadEntryCache;
+#else
+ return getThreadEntrySlow();
#endif
}
instance().lock_.lock(); // Make sure it's created
}
- static void onForkParent(void) {
- inst_->lock_.unlock();
- }
+ static void onForkParent(void) { instance().lock_.unlock(); }
static void onForkChild(void) {
// only the current thread survives
- inst_->head_.next = inst_->head_.prev = &inst_->head_;
+ instance().head_.next = instance().head_.prev = &instance().head_;
ThreadEntry* threadEntry = getThreadEntry();
// If this thread was in the list before the fork, add it back.
if (threadEntry->elementsCapacity != 0) {
- inst_->push_back(threadEntry);
+ instance().push_back(threadEntry);
}
- inst_->lock_.unlock();
+ instance().lock_.unlock();
}
static void onThreadExit(void* ptr) {
auto& meta = instance();
-#ifdef FOLLY_TLD_USE_FOLLY_TLS
- ThreadEntry* threadEntry = getThreadEntry();
- DCHECK_EQ(ptr, &meta);
- DCHECK_GT(threadEntry->elementsCapacity, 0);
-#else
// pthread sets the thread-specific value corresponding
// to meta.pthreadKey_ to NULL before calling onThreadExit.
// We need to set it back to ptr to enable the correct behaviour
// of the subsequent calls of getThreadEntry
// (which may happen in user-provided custom deleters)
pthread_setspecific(meta.pthreadKey_, ptr);
- ThreadEntry* threadEntry = static_cast<ThreadEntry*>(ptr);
-#endif
+
+ ThreadEntry* threadEntry = getThreadEntry();
+ DCHECK_GT(threadEntry->elementsCapacity, 0);
+
{
std::lock_guard<std::mutex> g(meta.lock_);
meta.erase(threadEntry);
threadEntry->elements = nullptr;
pthread_setspecific(meta.pthreadKey_, nullptr);
-#ifndef FOLLY_TLD_USE_FOLLY_TLS
- // Allocated in getThreadEntry() when not using folly TLS; free it
delete threadEntry;
-#endif
}
static uint32_t allocate(EntryID* ent) {
}
free(reallocated);
-
-#ifdef FOLLY_TLD_USE_FOLLY_TLS
- if (prevCapacity == 0) {
- pthread_setspecific(meta.pthreadKey_, &meta);
- }
-#endif
}
static ElementWrapper& get(EntryID* ent) {
}
};
-#ifdef FOLLY_TLD_USE_FOLLY_TLS
-template <class Tag>
-FOLLY_TLS ThreadEntry StaticMeta<Tag>::threadEntry_ = {nullptr, 0,
- nullptr, nullptr};
-#endif
-template <class Tag> StaticMeta<Tag>* StaticMeta<Tag>::inst_ = nullptr;
-
} // namespace threadlocal_detail
} // namespace folly