From b8e5139f87c3d86c2855bf87783e65f1fbe7cdaf Mon Sep 17 00:00:00 2001 From: afrind Date: Mon, 1 Jun 2026 18:03:35 -0400 Subject: [PATCH] relay: make stop() idempotent and keep context_ alive during teardown Guard stop() with a stopped_ flag instead of context_ presence, and stop resetting context_. terminateClientSession can run after stop() returns, from handleClientSession coroutines still draining on the evb/IO threads, so context_ must outlive stop(). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/MoqxPicoRelayServer.cpp | 6 ++++-- src/MoqxPicoRelayServer.h | 1 + src/MoqxRelayServer.cpp | 7 ++++--- src/MoqxRelayServer.h | 1 + 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/MoqxPicoRelayServer.cpp b/src/MoqxPicoRelayServer.cpp index 62aed595..4f8a171d 100644 --- a/src/MoqxPicoRelayServer.cpp +++ b/src/MoqxPicoRelayServer.cpp @@ -93,12 +93,14 @@ MoqxPicoRelayServer::~MoqxPicoRelayServer() { } void MoqxPicoRelayServer::stop() { - if (!context_) { + if (stopped_) { return; } + stopped_ = true; + // Keep context_ alive: terminateClientSession can run after stop() returns, + // from handleClientSession coroutines still draining on the evb. context_->stop(); evb_->runImmediatelyOrRunInEventBaseThreadAndWait([this] { MoQPicoQuicEventBaseServer::stop(); }); - context_.reset(); } void MoqxPicoRelayServer::setStatsRegistry(std::shared_ptr registry) { diff --git a/src/MoqxPicoRelayServer.h b/src/MoqxPicoRelayServer.h index cda2fbf4..e35fc882 100644 --- a/src/MoqxPicoRelayServer.h +++ b/src/MoqxPicoRelayServer.h @@ -64,6 +64,7 @@ class MoqxPicoRelayServer : public moxygen::MoQPicoQuicEventBaseServer { config::ListenerConfig listenerCfg_; std::shared_ptr context_; folly::EventBase* evb_; + bool stopped_{false}; }; } // namespace openmoq::moqx diff --git a/src/MoqxRelayServer.cpp b/src/MoqxRelayServer.cpp index aedc4047..1bd3a84d 100644 --- a/src/MoqxRelayServer.cpp +++ b/src/MoqxRelayServer.cpp @@ -143,12 +143,13 @@ MoqxRelayServer::~MoqxRelayServer() { } void MoqxRelayServer::stop() { - if (!context_) { + if (stopped_) { return; } - // QuicServer::shutdown drives terminateClientSession, which uses context_. + stopped_ = true; + // Keep context_ alive: terminateClientSession can run after stop() returns, + // from handleClientSession coroutines still draining on IO threads. MoQServer::stop(); - context_.reset(); } void MoqxRelayServer::setStatsRegistry(std::shared_ptr registry) { diff --git a/src/MoqxRelayServer.h b/src/MoqxRelayServer.h index 0dd0fb5d..f99524c4 100644 --- a/src/MoqxRelayServer.h +++ b/src/MoqxRelayServer.h @@ -57,6 +57,7 @@ class MoqxRelayServer : public moxygen::MoQServer { config::ListenerConfig listenerCfg_; std::shared_ptr context_; folly::IOThreadPoolExecutor* ioExecutor_; + bool stopped_{false}; }; } // namespace openmoq::moqx