diff --git a/include/upnp/upnp_context.h b/include/upnp/upnp_context.h index cabfbba0d8f143df5bb1294ca6042d551875bff5..3f24bca3b2ac85545cca65cc0413e5c19aa2dab5 100644 --- a/include/upnp/upnp_context.h +++ b/include/upnp/upnp_context.h @@ -107,6 +107,8 @@ public: UPnPContext(const std::shared_ptr<asio::io_context>& ctx, const std::shared_ptr<dht::log::Logger>& logger); ~UPnPContext(); + std::shared_ptr<asio::io_context> createIoContext(const std::shared_ptr<asio::io_context>& ctx, const std::shared_ptr<dht::log::Logger>& logger); + // Terminate the instance. void shutdown(); @@ -311,6 +313,9 @@ private: // Shutdown synchronization bool shutdownComplete_ {false}; + + // Thread + std::unique_ptr<std::thread> ioContextRunner_; }; } // namespace upnp diff --git a/src/upnp/upnp_context.cpp b/src/upnp/upnp_context.cpp index 335f70ba199d55fd14cc83fcc60ce82b0638efff..9d79f49520dd782f375895a87cc00a5eb6664b65 100644 --- a/src/upnp/upnp_context.cpp +++ b/src/upnp/upnp_context.cpp @@ -44,7 +44,7 @@ constexpr static uint16_t UPNP_UDP_PORT_MIN {20000}; constexpr static uint16_t UPNP_UDP_PORT_MAX {UPNP_UDP_PORT_MIN + 5000}; UPnPContext::UPnPContext(const std::shared_ptr<asio::io_context>& ioContext, const std::shared_ptr<dht::log::Logger>& logger) - : mappingListUpdateTimer_(*ioContext), ctx(ioContext), logger_(logger) + : ctx(createIoContext(ioContext, logger)), mappingListUpdateTimer_(*ioContext), logger_(logger) { if (logger_) logger_->debug("Creating UPnPContext instance [{}]", fmt::ptr(this)); @@ -55,6 +55,25 @@ UPnPContext::UPnPContext(const std::shared_ptr<asio::io_context>& ioContext, con ctx->post([this] { init(); }); } +std::shared_ptr<asio::io_context> +UPnPContext::createIoContext(const std::shared_ptr<asio::io_context>& ctx, const std::shared_ptr<dht::log::Logger>& logger) { + if (ctx) { + return ctx; + } else { + if (logger) logger->debug("UPnPContext: starting dedicated io_context thread"); + auto ioCtx = std::make_shared<asio::io_context>(); + ioContextRunner_ = std::make_unique<std::thread>([ioCtx, l=logger]() { + try { + auto work = asio::make_work_guard(*ioCtx); + ioCtx->run(); + } catch (const std::exception& ex) { + if (l) l->error("Unexpected io_context thread exception: {}", ex.what()); + } + }); + return ioCtx; + } +} + void UPnPContext::shutdown(std::condition_variable& cv) { @@ -75,6 +94,13 @@ UPnPContext::shutdown(std::condition_variable& cv) shutdownComplete_ = true; cv.notify_one(); } + + if (ioContextRunner_) { + if (logger_) logger_->debug("UPnPContext: stopping io_context thread"); + ctx->stop(); + ioContextRunner_->join(); + ioContextRunner_.reset(); + } } void