From 0de17036f4a61770a42541f71fed9dee3a94ca76 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 22 Sep 2022 08:51:20 -0700 Subject: [PATCH] add Context::close() --- src/client.cpp | 19 +++++++++++++++++++ src/clientconn.cpp | 3 +++ src/clientdiscover.cpp | 3 +++ src/clientimpl.h | 8 +++++++- src/pvxs/client.h | 11 +++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/client.cpp b/src/client.cpp index c6d4771..f32ea7b 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -312,6 +312,9 @@ std::shared_ptr Channel::build(const std::shared_ptr& cont const std::string& name, const std::string& server) { + if(context->state!=ContextImpl::Running) + throw std::logic_error("Context close()d"); + SockAddr forceServer; decltype (context->chanByName)::key_type namekey(name, server); @@ -381,6 +384,14 @@ const Config& Context::config() const return pvt->impl->effective; } +void Context::close() +{ + if(!pvt) + throw std::logic_error("NULL Context"); + + pvt->impl->close(); +} + void Context::hurryUp() { if(!pvt) @@ -584,6 +595,8 @@ ContextImpl::ContextImpl(const Config& conf, const evbase& tcp_loop) log_err_printf(setup, "Error enabling beacon clean timer on\n%s", ""); if(event_add(cacheCleaner.get(), &channelCacheCleanInterval)) log_err_printf(setup, "Error enabling channel cache clean timer on\n%s", ""); + + state = Running; } ContextImpl::~ContextImpl() {} @@ -609,8 +622,14 @@ void ContextImpl::startNS() void ContextImpl::close() { + log_debug_printf(setup, "context %p close\n", this); + // terminate all active connections tcp_loop.call([this]() { + if(state == Stopped) + return; + state = Stopped; + (void)event_del(searchTimer.get()); (void)event_del(searchRx4.get()); (void)event_del(searchRx6.get()); diff --git a/src/clientconn.cpp b/src/clientconn.cpp index 05567c9..52d9bed 100644 --- a/src/clientconn.cpp +++ b/src/clientconn.cpp @@ -46,6 +46,9 @@ Connection::~Connection() std::shared_ptr Connection::build(const std::shared_ptr& context, const SockAddr& serv, bool reconn) { + if(context->state!=ContextImpl::Running) + throw std::logic_error("Context close()d"); + std::shared_ptr ret; auto it = context->connByAddr.find(serv); if(it==context->connByAddr.end() || !(ret = it->second.lock())) { diff --git a/src/clientdiscover.cpp b/src/clientdiscover.cpp index f677ea1..c128dac 100644 --- a/src/clientdiscover.cpp +++ b/src/clientdiscover.cpp @@ -82,6 +82,9 @@ std::shared_ptr DiscoverBuilder::exec() context->tcp_loop.dispatch([op, context, ping]() { + if(context->state!=ContextImpl::Running) + throw std::logic_error("Context close()d"); + bool first = context->discoverers.empty(); context->discoverers[op.get()] = op; diff --git a/src/clientimpl.h b/src/clientimpl.h index 9839288..485b303 100644 --- a/src/clientimpl.h +++ b/src/clientimpl.h @@ -239,6 +239,12 @@ struct ContextImpl : public std::enable_shared_from_this SockAttach attach; IfaceMap& ifmap; + enum state_t { + Init, + Running, + Stopped, + } state = Init; + // "const" after ctor Config effective; @@ -334,7 +340,7 @@ struct Context::Pvt { private: evbase loop; public: - std::shared_ptr impl; + const std::shared_ptr impl; INST_COUNTER(ClientPvt); diff --git a/src/pvxs/client.h b/src/pvxs/client.h index 685a3f8..ee67e47 100644 --- a/src/pvxs/client.h +++ b/src/pvxs/client.h @@ -309,6 +309,17 @@ public: //! effective config of running client const Config& config() const; + /** Force close the client. + * + * ~Context() will close() automatically. So an explicit call is optional. + * + * Aborts/interrupts all in progress network operations. + * Blocks until any in-progress callbacks have completed. + * + * @since UNRELEASED + */ + void close(); + /** Request the present value of a PV * * Simple blocking