BlockingUDPTransport wrap close() to break ref. loop

This commit is contained in:
Michael Davidsaver
2017-06-02 12:32:12 +02:00
parent 11cc395baf
commit 6fcfd60bd5
3 changed files with 26 additions and 1 deletions

View File

@@ -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;
}
}

View File

@@ -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,

View File

@@ -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));