SharedMutex.h \
Singleton.h \
Singleton-inl.h \
+ SingletonThreadLocal.h \
SmallLocks.h \
small_vector.h \
SocketAddress.h \
}
void SingletonVault::registrationComplete() {
- RequestContext::saveContext();
std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
RWSpinLock::WriteHolder wh(&stateMutex_);
}
void SingletonVault::scheduleDestroyInstances() {
- RequestContext::saveContext();
-
class SingletonVaultDestructor {
public:
~SingletonVaultDestructor() {
#include <folly/RWSpinLock.h>
#include <folly/Demangle.h>
#include <folly/Executor.h>
-#include <folly/io/async/Request.h>
#include <folly/experimental/ReadMostlySharedPtr.h>
#include <algorithm>
}
};
+template <typename T, typename Tag = detail::DefaultTag>
+class LeakySingleton {
+ public:
+ using CreateFunc = std::function<T*()>;
+
+ LeakySingleton() : LeakySingleton([] { return new T(); }) {}
+
+ explicit LeakySingleton(CreateFunc createFunc) {
+ auto& entry = entryInstance();
+ if (entry.state != State::NotRegistered) {
+ LOG(FATAL) << "Double registration of singletons of the same "
+ << "underlying type; check for multiple definitions "
+ << "of type folly::LeakySingleton<" + entry.type_.name() + ">";
+ }
+ entry.createFunc = createFunc;
+ entry.state = State::Dead;
+ }
+
+ static T& get() { return instance(); }
+
+ private:
+ enum class State { NotRegistered, Dead, Living };
+
+ struct Entry {
+ Entry() {}
+ Entry(const Entry&) = delete;
+ Entry& operator=(const Entry&) = delete;
+
+ std::atomic<State> state{State::NotRegistered};
+ T* ptr{nullptr};
+ CreateFunc createFunc;
+ std::mutex mutex;
+ detail::TypeDescriptor type_{typeid(T), typeid(Tag)};
+ };
+
+ static Entry& entryInstance() {
+ static auto entry = new Entry();
+ return *entry;
+ }
+
+ static T& instance() {
+ auto& entry = entryInstance();
+ if (UNLIKELY(entry.state != State::Living)) {
+ createInstance();
+ }
+
+ return *entry.ptr;
+ }
+
+ static void createInstance() {
+ auto& entry = entryInstance();
+
+ std::lock_guard<std::mutex> lg(entry.mutex);
+ if (entry.state == State::Living) {
+ return;
+ }
+
+ if (entry.state == State::NotRegistered) {
+ auto ptr = SingletonVault::stackTraceGetter().load();
+ LOG(FATAL) << "Creating instance for unregistered singleton: "
+ << entry.type_.name() << "\n"
+ << "Stacktrace:"
+ << "\n" << (ptr ? (*ptr)() : "(not available)");
+ }
+
+ entry.ptr = entry.createFunc();
+ entry.state = State::Living;
+ }
+};
}
#include <folly/Singleton-inl.h>
--- /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 <folly/ThreadLocal.h>
+#include <folly/Singleton.h>
+
+namespace folly {
+
+template <typename T, typename Tag = detail::DefaultTag>
+class SingletonThreadLocal {
+ public:
+ using CreateFunc = std::function<T*(void)>;
+
+ SingletonThreadLocal() : SingletonThreadLocal([]() { return new T(); }) {}
+
+ explicit SingletonThreadLocal(CreateFunc createFunc)
+ : singleton_([createFunc = std::move(createFunc)]() mutable {
+ return new ThreadLocalT([createFunc =
+ std::move(createFunc)]() mutable {
+ return new Wrapper(std::unique_ptr<T>(createFunc()));
+ });
+ }) {}
+
+ static T& get() {
+#ifdef FOLLY_TLS
+ *localPtr() = nullptr;
+ if (UNLIKELY(*localPtr() == nullptr)) {
+ *localPtr() = &(**SingletonT::get());
+ }
+
+ return **localPtr();
+#else
+ return **SingletonT::get();
+#endif
+ }
+
+ private:
+#ifdef FOLLY_TLS
+ static T** localPtr() {
+ static FOLLY_TLS T* localPtr = nullptr;
+ return &localPtr;
+ }
+#endif
+
+ class Wrapper {
+ public:
+ explicit Wrapper(std::unique_ptr<T> t) : t_(std::move(t)) {}
+
+ ~Wrapper() {
+#ifdef FOLLY_TLS
+ *localPtr() = nullptr;
+#endif
+ }
+
+ T& operator*() { return *t_; }
+
+ private:
+ std::unique_ptr<T> t_;
+ };
+
+ using ThreadLocalT = ThreadLocal<Wrapper>;
+ using SingletonT = LeakySingleton<ThreadLocalT, Tag>;
+
+ SingletonT singleton_;
+};
+}
#include <glog/logging.h>
#include <folly/ThreadLocal.h>
#include <folly/RWSpinLock.h>
+#include <folly/SingletonThreadLocal.h>
namespace folly {
}
private:
- // Used to solve static destruction ordering issue. Any static object
- // that uses RequestContext must call this function in its constructor.
- //
- // See below link for more details.
- // http://stackoverflow.com/questions/335369/
- // finding-c-static-initialization-order-problems#335746
- static std::shared_ptr<RequestContext> &getStaticContext() {
- static folly::ThreadLocal<std::shared_ptr<RequestContext> > context;
- return *context;
+ static std::shared_ptr<RequestContext>& getStaticContext() {
+ using SingletonT = SingletonThreadLocal<std::shared_ptr<RequestContext>>;
+ static SingletonT singleton;
+ return singleton.get();
}
folly::RWSpinLock lock;