From 9cb5d5f13059ecc61c45bd042971ef29fa33fe9a Mon Sep 17 00:00:00 2001 From: sha512sum Date: Sun, 7 Apr 2024 13:59:07 +0000 Subject: [PATCH] Parallel initialisation components --- include/cserver/engine/components.hpp | 135 ++++++++++++++++++++------ 1 file changed, 105 insertions(+), 30 deletions(-) diff --git a/include/cserver/engine/components.hpp b/include/cserver/engine/components.hpp index 9bc3c9a..fa97e00 100644 --- a/include/cserver/engine/components.hpp +++ b/include/cserver/engine/components.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -63,38 +64,105 @@ struct ConstexprConfig { }; }; -template +namespace impl { + +template +inline constexpr auto GetInitFlagFor(auto&... args) -> InitFlag& { + static InitFlag flag{args...}; + return flag; +}; + +template +inline constexpr auto TransformDependencyGraphToInited(auto&&... args) { + return [&](std::index_sequence) { + return utempl::Tuple{[&](utempl::Wrapper){ + return [&](std::index_sequence){ + return std::array{&GetInitFlagFor(args...)...}; + }(std::make_index_sequence()); + }(utempl::Wrapper(Tuple)>{})...}; + }(std::make_index_sequence>()); +}; + +struct AsyncConditionVariable { + inline AsyncConditionVariable(boost::asio::io_context& ioContext) : + mtx{}, + deadlineTimer(ioContext), + flag{} {}; + template > + inline auto AsyncWait(Token&& token = {}) -> Task<> { + return boost::asio::async_initiate< + Token, + void(void)>([this](Handler&& handler) -> void { + std::unique_lock lc(this->mtx); + if(this->flag) { + return handler(); + }; + this->deadlineTimer.async_wait([h = std::make_unique(std::forward(handler))](const boost::system::error_code&){ + return (*h)(); + }); + }, token); + }; + inline auto Wait() -> void { + this->deadlineTimer.wait(); + }; + inline auto NotifyOne() { + std::unique_lock lc(this->mtx); + this->deadlineTimer.cancel_one(); + }; + inline auto NotifyAll() { + std::unique_lock lc(this->mtx); + this->flag = true; + this->deadlineTimer.cancel(); + }; + std::mutex mtx; + boost::asio::deadline_timer deadlineTimer; + bool flag; +}; + +template +inline constexpr auto InitComponents(T& ccontext) -> void { + static auto& context = ccontext; + static auto& ioContext = context.template FindComponent().ioContext; + static utempl::Tuple inited = TransformDependencyGraphToInited(ioContext); + [](std::index_sequence){ + (boost::asio::co_spawn(ioContext, [](utempl::Wrapper) -> cserver::Task<> { + auto& dependencies = Get(inited); + for(auto* flag : dependencies) { + co_await flag->AsyncWait(); + }; + Get(context.storage).emplace(utempl::Wrapper(T::kNames)>{}, context); + auto& componentInitFlag = GetInitFlagFor(ioContext); + componentInitFlag.NotifyAll(); + if constexpr(requires{Get(context.storage)->Run();}) { + Get(context.storage)->Run(); + }; + }(utempl::Wrapper{}), boost::asio::detached), ...); + }(std::make_index_sequence>()); + +}; + +} // namespace impl + +template struct ServiceContext { + static constexpr auto kNames = names; static constexpr auto kConfig = config; static constexpr auto kList = utempl::TypeList{}; static constexpr auto kThreadsCount = config.template Get<"threads">(); - engine::basic::TaskProcessor taskProcessor; - utempl::Tuple storage; + engine::basic::TaskProcessor taskProcessor; + utempl::Tuple...> storage; inline constexpr ServiceContext() : - taskProcessor{utempl::Wrapper{}, *this}, - storage{ - [&](std::index_sequence) -> utempl::Tuple { - return {[&](utempl::Wrapper) { - return [&] -> std::remove_cvref_t(storage))> { - return {utempl::Wrapper(names)>{}, *this}; - }; - }(utempl::Wrapper{})...}; - }(std::index_sequence_for()) - } {}; + taskProcessor{utempl::Wrapper{}, *this} + ,storage{} { + }; inline constexpr auto Run() { this->taskProcessor.Run(); - [&](std::index_sequence) { - ([](auto& component){ - if constexpr(requires{component.Run();}) { - component.Run(); - }; - }(Get(this->storage)), ...); - }(std::index_sequence_for()); + impl::InitComponents(*this); }; template inline constexpr auto FindComponent() -> auto& { constexpr auto I = utempl::Find(names, name); - return Get(this->storage); + return *Get(this->storage); }; template <> inline constexpr auto FindComponent() -> auto& { @@ -103,7 +171,7 @@ struct ServiceContext { template inline constexpr auto FindComponent() -> T& { constexpr auto I = utempl::Find>(utempl::kTypeList); - return Get(this->storage); + return *Get(this->storage); }; }; @@ -170,8 +238,8 @@ struct DependencyInfoInjector { private: template static consteval auto FindComponentTypeImpl(ComponentConfig...) { - if constexpr(name == kBasicTaskProcessorName) { - return [] -> engine::basic::TaskProcessor()> {}(); + if constexpr(static_cast(name) == kBasicTaskProcessorName) { + return [] -> engine::basic::TaskProcessor() - 1> {}(); } else { constexpr auto I = utempl::Find(utempl::Tuple{std::string_view{names}...}, std::string_view{name}); return [] -> decltype(utempl::Get(utempl::TypeList{})) {}(); @@ -232,7 +300,7 @@ public: }; } else { constexpr auto name = Magic(loopholes::Getter{}>{}); - if constexpr(name == kBasicTaskProcessorName) { + if constexpr(static_cast(name) == kBasicTaskProcessorName) { return utempl::Tuple{names...}; } else { return utempl::Tuple{names..., name}; @@ -366,7 +434,7 @@ struct ServiceContextBuilder { template static consteval auto FindComponent() { if constexpr(name == kBasicTaskProcessorName) { - return [] -> engine::basic::TaskProcessor()> {}(); + return [] -> engine::basic::TaskProcessor() - 1> {}(); } else { return [] (const ServiceContextBuilder...>&) @@ -392,6 +460,15 @@ struct ServiceContextBuilder { }(ComponentConfigs{}...); }; + static consteval auto GetIndexDependencyGraph() { + return [] + (DependencyGraph...>){ + return utempl::Tuple{Unpack(Dependencies, [](auto... dependencies) -> std::array { + return {Find(utempl::Tuple{Names...}, dependencies)...}; + })...}; + }(GetDependencyGraph()); + }; + static consteval auto Sort() { constexpr auto sorted = TopologicalSort(GetDependencyGraph()); return [&](std::index_sequence){ @@ -403,16 +480,14 @@ struct ServiceContextBuilder { static constexpr auto GetServiceContext() { return [] (utempl::TypeList...>) { - return ServiceContext{}; + return ServiceContext{}; }(utempl::TypeList{}); }; static constexpr auto Run() -> void { static auto context = GetServiceContext(); context.Run(); - for(;;) { - std::this_thread::sleep_for(std::chrono::minutes(1)); - }; + context.template FindComponent().ioContext.run(); }; }; } // namespace cserver