From 6fcfd60bd50092e2263dd00c1cb1cbce68c0f7fd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 2 Jun 2017 12:32:12 +0200 Subject: [PATCH] BlockingUDPTransport wrap close() to break ref. loop --- src/remote/blockingUDPConnector.cpp | 21 ++++++++++++++++++++- src/remote/pv/blockingUDP.h | 5 +++++ src/server/serverContext.cpp | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/remote/blockingUDPConnector.cpp b/src/remote/blockingUDPConnector.cpp index 44a447c..818c082 100644 --- a/src/remote/blockingUDPConnector.cpp +++ b/src/remote/blockingUDPConnector.cpp @@ -16,6 +16,22 @@ using namespace std; using namespace epics::pvData; +namespace { +struct closer { + epics::pvAccess::Transport::shared_pointer P; + closer(const epics::pvAccess::Transport::shared_pointer& P) :P(P) {} + void operator()(epics::pvAccess::Transport*) { + try{ + P->close(); + }catch(...){ + P.reset(); + throw; + } + P.reset(); + } +}; +} + namespace epics { namespace pvAccess { @@ -72,7 +88,10 @@ Transport::shared_pointer BlockingUDPConnector::connect(TransportClient::shared_ BlockingUDPTransport::shared_pointer transport(new BlockingUDPTransport(_serverFlag, responseHandler, socket, bindAddress, transportRevision)); - return Transport::shared_pointer(transport); + // the worker thread holds a strong ref, which is released by transport->close() + Transport::shared_pointer ret(transport.get(), closer(transport)); + + return ret; } } diff --git a/src/remote/pv/blockingUDP.h b/src/remote/pv/blockingUDP.h index ba3d79a..dbbd310 100644 --- a/src/remote/pv/blockingUDP.h +++ b/src/remote/pv/blockingUDP.h @@ -35,6 +35,8 @@ namespace epics { namespace pvAccess { +class BlockingUDPConnector; + enum InetAddressType { inetAddressType_all, inetAddressType_unicast, inetAddressType_broadcast_multicast }; class BlockingUDPTransport : public epics::pvData::NoDefaultMethods, @@ -46,10 +48,13 @@ class BlockingUDPTransport : public epics::pvData::NoDefaultMethods, public: POINTER_DEFINITIONS(BlockingUDPTransport); +private: + friend class BlockingUDPConnector; BlockingUDPTransport(bool serverFlag, ResponseHandler::shared_pointer const & responseHandler, SOCKET channel, osiSockAddr &bindAddress, short remoteTransportRevision); +public: static shared_pointer create(bool serverFlag, ResponseHandler::shared_pointer const & responseHandler, diff --git a/src/server/serverContext.cpp b/src/server/serverContext.cpp index 5c49cd3..9b128ce 100644 --- a/src/server/serverContext.cpp +++ b/src/server/serverContext.cpp @@ -263,6 +263,7 @@ void ServerContextImpl::initialize() _timer.reset(new Timer("pvAccess-server timer", lowerPriority)); ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); + // we create reference cycles here which are broken by our shutdown() method, _responseHandler.reset(new ServerResponseHandler(thisServerContext)); _acceptor.reset(new BlockingTCPAcceptor(thisServerContext, _responseHandler, _ifaceAddr, _receiveBufferSize));