From c36ba5264d211339c67246240e3ff9715d953683 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Thu, 12 May 2011 12:47:55 +0200 Subject: [PATCH] port from pvAccessCPP-md --- README | 3 +- configure/RELEASE | 4 +- pvAccessApp/Makefile | 18 +- pvAccessApp/ca/caConstants.h | 4 +- pvAccessApp/ca/clientFactory.cpp | 15 +- pvAccessApp/ca/clientFactory.h | 4 +- pvAccessApp/client/pvAccess.h | 213 +- pvAccessApp/factory/ChannelAccessFactory.cpp | 20 +- pvAccessApp/factory/CreateRequestFactory.cpp | 428 ++- .../remote/abstractResponseHandler.cpp | 4 +- pvAccessApp/remote/beaconEmitter.cpp | 157 - pvAccessApp/remote/beaconHandler.cpp | 43 +- pvAccessApp/remote/beaconHandler.h | 8 +- .../remote/beaconServerStatusProvider.h | 52 - .../remote/blockingClientTCPTransport.cpp | 96 +- .../remote/blockingServerTCPTransport.cpp | 30 +- pvAccessApp/remote/blockingTCP.h | 183 +- pvAccessApp/remote/blockingTCPAcceptor.cpp | 113 +- pvAccessApp/remote/blockingTCPConnector.cpp | 126 +- pvAccessApp/remote/blockingTCPTransport.cpp | 258 +- pvAccessApp/remote/blockingUDP.h | 35 +- pvAccessApp/remote/blockingUDPConnector.cpp | 15 +- pvAccessApp/remote/blockingUDPTransport.cpp | 57 +- pvAccessApp/remote/channelSearchManager.cpp | 94 +- pvAccessApp/remote/channelSearchManager.h | 23 +- pvAccessApp/remote/remote.h | 286 +- .../remoteClient/clientContextImpl.cpp | 2583 +++++++++-------- pvAccessApp/remoteClient/clientContextImpl.h | 45 +- pvAccessApp/server/baseChannelRequester.cpp | 37 +- pvAccessApp/server/baseChannelRequester.h | 25 +- pvAccessApp/server/beaconEmitter.cpp | 146 + .../{remote => server}/beaconEmitter.h | 89 +- .../beaconServerStatusProvider.cpp | 27 +- .../server/beaconServerStatusProvider.h | 65 + .../server/referencedTransportSender.cpp | 37 - .../server/referencedTransportSender.h | 29 - pvAccessApp/server/responseHandlers.cpp | 874 +++--- pvAccessApp/server/responseHandlers.h | 530 ++-- pvAccessApp/server/serverChannelImpl.cpp | 37 +- pvAccessApp/server/serverChannelImpl.h | 29 +- pvAccessApp/server/serverContext.cpp | 137 +- pvAccessApp/server/serverContext.h | 89 +- pvAccessApp/utils/arrayFIFO.h | 376 --- pvAccessApp/utils/configuration.h | 4 + pvAccessApp/utils/growingCircularBuffer.h | 281 -- pvAccessApp/utils/introspectionRegistry.cpp | 58 +- pvAccessApp/utils/introspectionRegistry.h | 5 +- pvAccessApp/utils/namedLockPattern.cpp | 7 - pvAccessApp/utils/namedLockPattern.h | 17 +- pvAccessApp/utils/transportRegistry.cpp | 156 +- pvAccessApp/utils/transportRegistry.h | 52 +- testApp/Makefile | 2 +- testApp/client/MockClientImpl.cpp | 2 +- testApp/client/testCreateRequest.cpp | 267 +- testApp/remote/Makefile | 4 +- testApp/remote/testBlockingTCPClnt.cpp | 61 +- testApp/remote/testBlockingTCPSrv.cpp | 44 +- testApp/remote/testBlockingUDPClnt.cpp | 44 +- testApp/remote/testBlockingUDPSrv.cpp | 39 +- testApp/remote/testChannelSearchManager.cpp | 564 +--- testApp/remote/testRemoteClientImpl.cpp | 227 +- testApp/remote/testServer.cpp | 522 ++-- testApp/remote/testServerContext.cpp | 73 +- testApp/utils/Makefile | 8 - testApp/utils/arrayFIFOTest.cpp | 271 -- testApp/utils/growingCircularBufferTest.cpp | 89 - testApp/utils/introspectionRegistryTest.cpp | 50 +- testApp/utils/transportRegistryTest.cpp | 83 +- 68 files changed, 4762 insertions(+), 5612 deletions(-) delete mode 100644 pvAccessApp/remote/beaconEmitter.cpp delete mode 100644 pvAccessApp/remote/beaconServerStatusProvider.h create mode 100644 pvAccessApp/server/beaconEmitter.cpp rename pvAccessApp/{remote => server}/beaconEmitter.h (59%) rename pvAccessApp/{remote => server}/beaconServerStatusProvider.cpp (53%) create mode 100644 pvAccessApp/server/beaconServerStatusProvider.h delete mode 100644 pvAccessApp/server/referencedTransportSender.cpp delete mode 100644 pvAccessApp/server/referencedTransportSender.h delete mode 100644 pvAccessApp/utils/arrayFIFO.h delete mode 100644 pvAccessApp/utils/growingCircularBuffer.h delete mode 100644 pvAccessApp/utils/namedLockPattern.cpp delete mode 100644 testApp/utils/arrayFIFOTest.cpp delete mode 100644 testApp/utils/growingCircularBufferTest.cpp diff --git a/README b/README index a6d7456..33c3be4 100644 --- a/README +++ b/README @@ -1,5 +1,6 @@ Define +EPICS_BASE PVDATA_HOME -env. variable that points to pvDataCPP installation directory (includes and libraries). +variables that points to EPICS base and pvDataCPP installation directory (includes and libraries) in configure/RELEASE. diff --git a/configure/RELEASE b/configure/RELEASE index 39ba077..07381c3 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -26,8 +26,8 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top # EPICS_BASE usually appears last so other apps can override stuff: -PVDATA=/home/mrk/hg/pvDataCPP -EPICS_BASE=/home/install/epics/base +PVDATA=/Users/msekoranja/tmp/pvDataCPP +EPICS_BASE=/opt/epics/base #PVDATA=/home/mrk/hg/pvDataCPP #EPICS_BASE=/home/install/epics/base diff --git a/pvAccessApp/Makefile b/pvAccessApp/Makefile index 03d6aa7..bdf2203 100644 --- a/pvAccessApp/Makefile +++ b/pvAccessApp/Makefile @@ -15,8 +15,6 @@ LIBSRCS += clientFactory.cpp SRC_DIRS += $(PVACCESS)/utils INC += hexDump.h INC += wildcharMatcher.h -INC += arrayFIFO.h -INC += growingCircularBuffer.h INC += inetAddressUtil.h INC += logger.h INC += introspectionRegistry.h @@ -30,10 +28,8 @@ LIBSRCS += inetAddressUtil.cpp LIBSRCS += logger.cpp LIBSRCS += introspectionRegistry.cpp LIBSRCS += transportRegistry.cpp -LIBSRCS += namedLockPattern.cpp -LIBSRCS += referenceCountingLock.cpp LIBSRCS += configuration.cpp - +LIBSRCS += referenceCountingLock.cpp SRC_DIRS += $(PVACCESS)/client INC += pvAccess.h @@ -44,12 +40,14 @@ INC += serverContext.h INC += responseHandlers.h INC += serverChannelImpl.h INC += baseChannelRequester.h -INC += referencedTransportSender.h +INC += beaconEmitter.h +INC += beaconServerStatusProvider.h LIBSRCS += responseHandlers.cpp LIBSRCS += serverContext.cpp LIBSRCS += serverChannelImpl.cpp LIBSRCS += baseChannelRequester.cpp -LIBSRCS += referencedTransportSender.h +LIBSRCS += beaconEmitter.cpp +LIBSRCS += beaconServerStatusProvider.cpp SRC_DIRS += $(PVACCESS)/factory LIBSRCS += ChannelAccessFactory.cpp @@ -59,23 +57,19 @@ LIBSRCS += CreateRequestFactory.cpp SRC_DIRS += $(PVACCESS)/remote INC += remote.h INC += blockingUDP.h -INC += beaconEmitter.h -INC += beaconServerStatusProvider.h INC += beaconHandler.h INC += blockingTCP.h INC += channelSearchManager.h LIBSRCS += blockingUDPTransport.cpp LIBSRCS += blockingUDPConnector.cpp -LIBSRCS += beaconEmitter.cpp -LIBSRCS += beaconServerStatusProvider.cpp LIBSRCS += beaconHandler.cpp LIBSRCS += blockingTCPTransport.cpp LIBSRCS += blockingClientTCPTransport.cpp LIBSRCS += blockingTCPConnector.cpp LIBSRCS += blockingServerTCPTransport.cpp -LIBSRCS += blockingTCPAcceptor.cpp LIBSRCS += channelSearchManager.cpp LIBSRCS += abstractResponseHandler.cpp +LIBSRCS += blockingTCPAcceptor.cpp SRC_DIRS += $(PVACCESS)/remoteClient diff --git a/pvAccessApp/ca/caConstants.h b/pvAccessApp/ca/caConstants.h index 1dea910..ccd409a 100644 --- a/pvAccessApp/ca/caConstants.h +++ b/pvAccessApp/ca/caConstants.h @@ -74,10 +74,10 @@ namespace epics { const int16 INVALID_DATA_TYPE = (int16)0xFFFF; /** Invalid IOID. */ - const int32 CAJ_INVALID_IOID = 0; + const int32 INVALID_IOID = 0; /** Default CA provider name. */ - const String CAJ_DEFAULT_PROVIDER = "local"; + const String PVACCESS_DEFAULT_PROVIDER = "local"; } } diff --git a/pvAccessApp/ca/clientFactory.cpp b/pvAccessApp/ca/clientFactory.cpp index 4e0bb4f..1070191 100644 --- a/pvAccessApp/ca/clientFactory.cpp +++ b/pvAccessApp/ca/clientFactory.cpp @@ -8,18 +8,19 @@ using namespace epics::pvData; using namespace epics::pvAccess; Mutex ClientFactory::m_mutex; -ClientContextImpl* ClientFactory::m_context = 0; +ClientContextImpl::shared_pointer ClientFactory::m_context; void ClientFactory::start() { Lock guard(m_mutex); - if (m_context) return; + if (m_context.get()) return; try { m_context = createClientContextImpl(); m_context->initialize(); - registerChannelProvider(m_context->getProvider()); + ChannelProvider::shared_pointer provider = m_context->getProvider(); + registerChannelProvider(provider); } catch (std::exception &e) { errlogSevPrintf(errlogMajor, "Unhandled exception caught at %s:%d: %s", __FILE__, __LINE__, e.what()); } catch (...) { @@ -31,7 +32,11 @@ void ClientFactory::stop() { Lock guard(m_mutex); - unregisterChannelProvider(m_context->getProvider()); + if (!m_context.get()) return; + + ChannelProvider::shared_pointer provider = m_context->getProvider(); + unregisterChannelProvider(provider); + m_context->dispose(); - m_context = 0; + m_context.reset(); } diff --git a/pvAccessApp/ca/clientFactory.h b/pvAccessApp/ca/clientFactory.h index 93d61bb..fbbc114 100644 --- a/pvAccessApp/ca/clientFactory.h +++ b/pvAccessApp/ca/clientFactory.h @@ -14,9 +14,9 @@ class ClientFactory { private: static epics::pvData::Mutex m_mutex; - static ClientContextImpl* m_context; + static ClientContextImpl::shared_pointer m_context; }; }} -#endif /* CLIENTFACTORY_H */ \ No newline at end of file +#endif /* CLIENTFACTORY_H */ diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index f4fac58..3b3ae4a 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -30,11 +30,20 @@ namespace epics { namespace pvAccess { class Channel; class ChannelProvider; +#define POINTER_DEFINITIONS(clazz) \ + typedef std::tr1::shared_ptr shared_pointer; \ + typedef std::tr1::shared_ptr const_shared_pointer; \ + typedef std::tr1::weak_ptr weak_pointer; \ + typedef std::tr1::weak_ptr const_weak_pointer; + + /** * Base interface for all channel requests. * @author mse */ class ChannelRequest : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { + public: + POINTER_DEFINITIONS(ChannelRequest); }; /** @@ -45,6 +54,7 @@ namespace epics { namespace pvAccess { */ class ChannelArray : public ChannelRequest{ public: + POINTER_DEFINITIONS(ChannelArray); /** * put to the remote array. @@ -78,6 +88,7 @@ namespace epics { namespace pvAccess { */ class ChannelArrayRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelArrayRequester); /** * The client and server have both completed the createChannelArray request. @@ -85,25 +96,28 @@ namespace epics { namespace pvAccess { * @param channelArray The channelArray interface or null if the request failed. * @param pvArray The PVArray that holds the data. */ - virtual void channelArrayConnect(const epics::pvData::Status &status,ChannelArray *channelArray,epics::pvData::PVArray *pvArray) = 0; + virtual void channelArrayConnect( + const epics::pvData::Status& status, + ChannelArray::shared_pointer& channelArray, + epics::pvData::PVArray::shared_pointer& pvArray) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void putArrayDone(const epics::pvData::Status &status) = 0; + virtual void putArrayDone(const epics::pvData::Status& status) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void getArrayDone(const epics::pvData::Status &status) = 0; + virtual void getArrayDone(const epics::pvData::Status& status) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void setLengthDone(const epics::pvData::Status &status) = 0; + virtual void setLengthDone(const epics::pvData::Status& status) = 0; }; @@ -113,7 +127,9 @@ namespace epics { namespace pvAccess { */ class ChannelFind : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: - virtual ChannelProvider* getChannelProvider() = 0; + POINTER_DEFINITIONS(ChannelFind); + + virtual std::tr1::shared_ptr getChannelProvider() = 0; virtual void cancelChannelFind() = 0; }; @@ -123,11 +139,12 @@ namespace epics { namespace pvAccess { */ class ChannelFindRequester { public: + POINTER_DEFINITIONS(ChannelFindRequester); /** * @param status Completion status. */ - virtual void channelFindResult(const epics::pvData::Status &status,ChannelFind *channelFind,bool wasFound) = 0; + virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind::shared_pointer& channelFind,bool wasFound) = 0; }; @@ -138,6 +155,7 @@ namespace epics { namespace pvAccess { */ class ChannelGet : public ChannelRequest { public: + POINTER_DEFINITIONS(ChannelGet); /** * Get data from the channel. @@ -156,6 +174,7 @@ namespace epics { namespace pvAccess { */ class ChannelGetRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelGetRequester); /** * The client and server have both completed the createChannelGet request. @@ -164,14 +183,14 @@ namespace epics { namespace pvAccess { * @param pvStructure The PVStructure that holds the data. * @param bitSet The bitSet for that shows what data has changed. */ - virtual void channelGetConnect(const epics::pvData::Status &status,ChannelGet *channelGet, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) = 0; + virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet::shared_pointer& channelGet, + epics::pvData::PVStructure::shared_pointer& pvStructure,epics::pvData::BitSet::shared_pointer& bitSet) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void getDone(const epics::pvData::Status &status) = 0; + virtual void getDone(const epics::pvData::Status& status) = 0; }; @@ -182,6 +201,7 @@ namespace epics { namespace pvAccess { */ class ChannelProcess : public ChannelRequest { public: + POINTER_DEFINITIONS(ChannelProcess); /** * Issue a process request. @@ -200,6 +220,7 @@ namespace epics { namespace pvAccess { */ class ChannelProcessRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelProcessRequester); /** * The client and server have both completed the createChannelProcess request. @@ -207,13 +228,13 @@ namespace epics { namespace pvAccess { * @param channelProcess The channelProcess interface or null if the client could not become * the record processor. */ - virtual void channelProcessConnect(const epics::pvData::Status &status,ChannelProcess *channelProcess) = 0; + virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess::shared_pointer& channelProcess) = 0; /** * The process request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void processDone(const epics::pvData::Status &status) = 0; + virtual void processDone(const epics::pvData::Status& status) = 0; }; @@ -224,6 +245,7 @@ namespace epics { namespace pvAccess { */ class ChannelPut : public ChannelRequest { public: + POINTER_DEFINITIONS(ChannelPut); /** * Put data to a channel. @@ -247,6 +269,7 @@ namespace epics { namespace pvAccess { */ class ChannelPutRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelPutRequester); /** * The client and server have both processed the createChannelPut request. @@ -255,20 +278,20 @@ namespace epics { namespace pvAccess { * @param pvStructure The PVStructure that holds the data. * @param bitSet The bitSet for that shows what data has changed. */ - virtual void channelPutConnect(const epics::pvData::Status &status,ChannelPut *channelPut, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) = 0; + virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut::shared_pointer& channelPut, + epics::pvData::PVStructure::shared_pointer& pvStructure,epics::pvData::BitSet::shared_pointer& bitSet) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void putDone(const epics::pvData::Status &status) = 0; + virtual void putDone(const epics::pvData::Status& status) = 0; /** * The get request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void getDone(const epics::pvData::Status &status) = 0; + virtual void getDone(const epics::pvData::Status& status) = 0; }; @@ -280,6 +303,7 @@ namespace epics { namespace pvAccess { */ class ChannelPutGet : public ChannelRequest { public: + POINTER_DEFINITIONS(ChannelPutGet); /** * Issue a put/get request. If process was requested when the ChannelPutGet was created this is a put, process, get. @@ -309,6 +333,7 @@ namespace epics { namespace pvAccess { class ChannelPutGetRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelPutGetRequester); /** * The client and server have both completed the createChannelPutGet request. @@ -317,25 +342,25 @@ namespace epics { namespace pvAccess { * @param pvPutStructure The PVStructure that holds the putData. * @param pvGetStructure The PVStructure that holds the getData. */ - virtual void channelPutGetConnect(const epics::pvData::Status &status,ChannelPutGet *channelPutGet, - epics::pvData::PVStructure *pvPutStructure,epics::pvData::PVStructure *pvGetStructure) = 0; + virtual void channelPutGetConnect(const epics::pvData::Status& status,ChannelPutGet::shared_pointer& channelPutGet, + epics::pvData::PVStructure::shared_pointer& pvPutStructure,epics::pvData::PVStructure::shared_pointer& pvGetStructure) = 0; /** * The putGet request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void putGetDone(const epics::pvData::Status &status) = 0; + virtual void putGetDone(const epics::pvData::Status& status) = 0; /** * The getPut request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void getPutDone(const epics::pvData::Status &status) = 0; + virtual void getPutDone(const epics::pvData::Status& status) = 0; /** * The getGet request is done. This is always called with no locks held. * @param status Completion status. */ - virtual void getGetDone(const epics::pvData::Status &status) = 0; + virtual void getGetDone(const epics::pvData::Status& status) = 0; }; @@ -346,6 +371,7 @@ namespace epics { namespace pvAccess { */ class ChannelRPC : public ChannelRequest { public: + POINTER_DEFINITIONS(ChannelRPC); /** * Issue an RPC request to the channel. @@ -363,6 +389,7 @@ namespace epics { namespace pvAccess { */ class ChannelRPCRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelRPCRequester); /** * The client and server have both completed the createChannelGet request. @@ -371,15 +398,15 @@ namespace epics { namespace pvAccess { * @param pvArgument The argument structure for an RPC request. * @param bitSet The bitSet for argument changes. */ - virtual void channelRPCConnect(const epics::pvData::Status &status,ChannelRPC *channelRPC, - epics::pvData::PVStructure *pvArgument,epics::pvData::BitSet *bitSet) = 0; + virtual void channelRPCConnect(const epics::pvData::Status& status,ChannelRPC::shared_pointer& channelRPC, + epics::pvData::PVStructure::shared_pointer& pvArgument,epics::pvData::BitSet::shared_pointer& bitSet) = 0; /** * The request is done. This is always called with no locks held. * @param status Completion status. * @param pvResponse The response data for the RPC request. */ - virtual void requestDone(const epics::pvData::Status &status,epics::pvData::PVStructure *pvResponse) = 0; + virtual void requestDone(const epics::pvData::Status& status,epics::pvData::PVStructure::shared_pointer& pvResponse) = 0; }; @@ -390,13 +417,15 @@ namespace epics { namespace pvAccess { */ class GetFieldRequester : virtual public epics::pvData::Requester { public: + POINTER_DEFINITIONS(GetFieldRequester); /** * The client and server have both completed the getStructure request. * @param status Completion status. * @param field The Structure for the request. */ - virtual void getDone(const epics::pvData::Status &status,epics::pvData::FieldConstPtr field) = 0; + // TODO naming convention + virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr& field) = 0; }; @@ -413,6 +442,7 @@ namespace epics { namespace pvAccess { public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: + POINTER_DEFINITIONS(Channel); /** * Channel connection status. @@ -427,7 +457,8 @@ namespace epics { namespace pvAccess { * Get the the channel provider of this channel. * @return The channel provider. */ - virtual ChannelProvider* getProvider() = 0; + virtual std::tr1::shared_ptr getProvider() = 0; +// virtual ChannelProvider::shared_pointer getProvider() = 0; /** * Returns the channel's remote address, e.g. "/192.168.1.101:5064" or "#C0 S1". @@ -451,7 +482,8 @@ namespace epics { namespace pvAccess { * Get the channel epics::pvData::Requester. * @return The epics::pvData::Requester. */ - virtual ChannelRequester* getChannelRequester() = 0; +// virtual ChannelRequester::shared_pointer getChannelRequester() = 0; + virtual std::tr1::shared_ptr getChannelRequester() = 0; /** * Is the channel connected? @@ -467,7 +499,7 @@ namespace epics { namespace pvAccess { * @param subField The name of the subField. * If this is null or an empty epics::pvData::String the returned Field is for the entire record. */ - virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) = 0; + virtual void getField(GetFieldRequester::shared_pointer& requester,epics::pvData::String subField) = 0; /** * Get the access rights for a field of a PVStructure created via a call to createPVStructure. @@ -475,7 +507,7 @@ namespace epics { namespace pvAccess { * @param pvField The field for which access rights is desired. * @return The access rights. */ - virtual AccessRights getAccessRights(epics::pvData::PVField *pvField) = 0; + virtual AccessRights getAccessRights(epics::pvData::PVField::shared_pointer& pvField) = 0; /** * Create a ChannelProcess. @@ -486,9 +518,9 @@ namespace epics { namespace pvAccess { * @param pvRequest Additional options (e.g. triggering). * @return ChannelProcess instance. */ - virtual ChannelProcess* createChannelProcess( - ChannelProcessRequester *channelProcessRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual ChannelProcess::shared_pointer createChannelProcess( + ChannelProcessRequester::shared_pointer& channelProcessRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Create a ChannelGet. @@ -500,9 +532,9 @@ namespace epics { namespace pvAccess { * This has the same form as a pvRequest to PVCopyFactory.create. * @return ChannelGet instance. */ - virtual ChannelGet* createChannelGet( - ChannelGetRequester *channelGetRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual ChannelGet::shared_pointer createChannelGet( + ChannelGetRequester::shared_pointer& channelGetRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Create a ChannelPut. @@ -514,9 +546,9 @@ namespace epics { namespace pvAccess { * This has the same form as a pvRequest to PVCopyFactory.create. * @return ChannelPut instance. */ - virtual ChannelPut* createChannelPut( - ChannelPutRequester *channelPutRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual ChannelPut::shared_pointer createChannelPut( + ChannelPutRequester::shared_pointer& channelPutRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Create a ChannelPutGet. @@ -528,9 +560,9 @@ namespace epics { namespace pvAccess { * This has the same form as a pvRequest to PVCopyFactory.create. * @return ChannelPutGet instance. */ - virtual ChannelPutGet* createChannelPutGet( - ChannelPutGetRequester *channelPutGetRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual ChannelPutGet::shared_pointer createChannelPutGet( + ChannelPutGetRequester::shared_pointer& channelPutGetRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Create a ChannelRPC (Remote Procedure Call). @@ -538,8 +570,9 @@ namespace epics { namespace pvAccess { * @param pvRequest Request options. * @return ChannelRPC instance. */ - virtual ChannelRPC* createChannelRPC(ChannelRPCRequester *channelRPCRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual ChannelRPC::shared_pointer createChannelRPC( + ChannelRPCRequester::shared_pointer& channelRPCRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Create a Monitor. @@ -548,9 +581,9 @@ namespace epics { namespace pvAccess { * This has the same form as a pvRequest to PVCopyFactory.create. * @return Monitor instance. */ - virtual epics::pvData::Monitor* createMonitor( - epics::pvData::MonitorRequester *monitorRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual epics::pvData::Monitor::shared_pointer createMonitor( + epics::pvData::MonitorRequester::shared_pointer& monitorRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Create a ChannelArray. @@ -558,9 +591,9 @@ namespace epics { namespace pvAccess { * @param pvRequest Additional options (e.g. triggering). * @return ChannelArray instance. */ - virtual ChannelArray* createChannelArray( - ChannelArrayRequester *channelArrayRequester, - epics::pvData::PVStructure *pvRequest) = 0; + virtual ChannelArray::shared_pointer createChannelArray( + ChannelArrayRequester::shared_pointer& channelArrayRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) = 0; /** * Prints detailed information about the context to the standard output stream. @@ -582,49 +615,23 @@ namespace epics { namespace pvAccess { */ class ChannelRequester : public virtual epics::pvData::Requester { public: + POINTER_DEFINITIONS(ChannelRequester); /** * A channel has been created. This may be called multiple times if there are multiple providers. * @param status Completion status. * @param channel The channel. */ - virtual void channelCreated(const epics::pvData::Status &status, Channel *channel) = 0; + virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer& channel) = 0; /** * A channel connection state change has occurred. * @param c The channel. * @param connectionState The new connection state. */ - virtual void channelStateChange(Channel *c, Channel::ConnectionState connectionState) = 0; + virtual void channelStateChange(Channel::shared_pointer& channel, Channel::ConnectionState connectionState) = 0; }; - /** - * Interface for locating channel providers. - * @author mrk - * - */ - class ChannelAccess : private epics::pvData::NoDefaultMethods { - public: - virtual ~ChannelAccess() {}; - - /** - * Get the provider with the specified name. - * @param providerName The name of the provider. - * @return The interface for the provider or null if the provider is not known. - */ - virtual ChannelProvider* getProvider(epics::pvData::String providerName) = 0; - - /** - * Get a array of the names of all the known providers. - * @return The names. Be sure to delete vector instance. - */ - virtual std::vector* getProviderNames() = 0; - }; - - extern ChannelAccess * getChannelAccess(); - extern void registerChannelProvider(ChannelProvider *channelProvider); - extern void unregisterChannelProvider(ChannelProvider *channelProvider); - /** * Interface implemented by code that can provide access to the record * to which a channel connects. @@ -633,6 +640,7 @@ namespace epics { namespace pvAccess { */ class ChannelProvider : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: + POINTER_DEFINITIONS(ChannelProvider); /** Minimal priority. */ static const short PRIORITY_MIN = 0; @@ -659,7 +667,8 @@ namespace epics { namespace pvAccess { * @param channelFindRequester The epics::pvData::Requester. * @return An interface for the find. */ - virtual ChannelFind* channelFind(epics::pvData::String channelName,ChannelFindRequester *channelFindRequester) = 0; + virtual ChannelFind::shared_pointer channelFind(epics::pvData::String channelName, + ChannelFindRequester::shared_pointer& channelFindRequester) = 0; /** * Create a channel. @@ -668,7 +677,8 @@ namespace epics { namespace pvAccess { * @param priority channel priority, must be PRIORITY_MIN <= priority <= PRIORITY_MAX. * @return Channel instance. If channel does not exist null is returned and channelRequester notified. */ - virtual Channel* createChannel(epics::pvData::String channelName,ChannelRequester *channelRequester,short priority = PRIORITY_DEFAULT) = 0; + virtual Channel::shared_pointer createChannel(epics::pvData::String channelName,ChannelRequester::shared_pointer& channelRequester, + short priority = PRIORITY_DEFAULT) = 0; /** * Create a channel. @@ -678,9 +688,41 @@ namespace epics { namespace pvAccess { * @param address address (or list of addresses) where to look for a channel. Implementation independed epics::pvData::String. * @return Channel instance. If channel does not exist null is returned and channelRequester notified. */ - virtual Channel* createChannel(epics::pvData::String channelName,ChannelRequester *channelRequester,short priority,epics::pvData::String address) = 0; + virtual Channel::shared_pointer createChannel(epics::pvData::String channelName,ChannelRequester::shared_pointer& channelRequester, + short priority, epics::pvData::String address) = 0; }; + /** + * Interface for locating channel providers. + * @author mrk + * + */ + class ChannelAccess : private epics::pvData::NoDefaultMethods { + public: + POINTER_DEFINITIONS(ChannelAccess); + + typedef std::vector stringVector_t; + + virtual ~ChannelAccess() {}; + + /** + * Get the provider with the specified name. + * @param providerName The name of the provider. + * @return The interface for the provider or null if the provider is not known. + */ + virtual ChannelProvider::shared_pointer getProvider(epics::pvData::String providerName) = 0; + + /** + * Get a array of the names of all the known providers. + * @return The names. Be sure to delete vector instance. + */ + virtual std::auto_ptr getProviderNames() = 0; + }; + + extern ChannelAccess::shared_pointer getChannelAccess(); + extern void registerChannelProvider(ChannelProvider::shared_pointer& channelProvider); + extern void unregisterChannelProvider(ChannelProvider::shared_pointer& channelProvider); + /** * The class representing a CA Client Context. @@ -688,12 +730,13 @@ namespace epics { namespace pvAccess { */ class ClientContext : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: + POINTER_DEFINITIONS(ClientContext); /** * Get context implementation version. * @return version of the context implementation. */ - virtual Version* getVersion() = 0; + virtual Version& getVersion() = 0; /** * Initialize client context. This method is called immediately after instance construction (call of constructor). @@ -704,7 +747,7 @@ namespace epics { namespace pvAccess { * Get channel provider implementation. * @return the channel provider. */ - virtual ChannelProvider* getProvider() = 0; + virtual ChannelProvider::shared_pointer getProvider() = 0; /** * Prints detailed information about the context to the standard output stream. @@ -732,6 +775,8 @@ namespace epics { namespace pvAccess { */ class CreateRequest : private epics::pvData::NoDefaultMethods { public: + POINTER_DEFINITIONS(CreateRequest); + virtual ~CreateRequest() {}; /** @@ -741,10 +786,10 @@ namespace epics { namespace pvAccess { * @param requester The requester; * @return The request structure if an invalid request was given. */ - virtual epics::pvData::PVStructure* createRequest(String request, epics::pvData::Requester* requester) = 0; + virtual epics::pvData::PVStructure::shared_pointer createRequest(String request) = 0; }; - extern CreateRequest * getCreateRequest(); + extern CreateRequest::shared_pointer getCreateRequest(); }} diff --git a/pvAccessApp/factory/ChannelAccessFactory.cpp b/pvAccessApp/factory/ChannelAccessFactory.cpp index aef54f3..b8158ae 100644 --- a/pvAccessApp/factory/ChannelAccessFactory.cpp +++ b/pvAccessApp/factory/ChannelAccessFactory.cpp @@ -12,25 +12,25 @@ using namespace epics::pvData; namespace epics { namespace pvAccess { -static ChannelAccess* channelAccess = 0; +static ChannelAccess::shared_pointer channelAccess; static Mutex channelProviderMutex; -typedef std::map ChannelProviderMap; +typedef std::map ChannelProviderMap; static ChannelProviderMap channelProviders; class ChannelAccessImpl : public ChannelAccess { public: - ChannelProvider* getProvider(String providerName) { + ChannelProvider::shared_pointer getProvider(String providerName) { Lock guard(channelProviderMutex); return channelProviders[providerName]; } - std::vector* getProviderNames() { + std::auto_ptr getProviderNames() { Lock guard(channelProviderMutex); - std::vector* providers = new std::vector(); + std::auto_ptr providers(new stringVector_t()); for (ChannelProviderMap::const_iterator i = channelProviders.begin(); i != channelProviders.end(); i++) providers->push_back(i->first); @@ -39,22 +39,22 @@ class ChannelAccessImpl : public ChannelAccess { } }; -ChannelAccess * getChannelAccess() { +ChannelAccess::shared_pointer getChannelAccess() { static Mutex mutex; Lock guard(mutex); - if(channelAccess==0){ - channelAccess = new ChannelAccessImpl(); + if(channelAccess.get()==0){ + channelAccess.reset(new ChannelAccessImpl()); } return channelAccess; } -void registerChannelProvider(ChannelProvider *channelProvider) { +void registerChannelProvider(ChannelProvider::shared_pointer& channelProvider) { Lock guard(channelProviderMutex); channelProviders[channelProvider->getProviderName()] = channelProvider; } -void unregisterChannelProvider(ChannelProvider *channelProvider) { +void unregisterChannelProvider(ChannelProvider::shared_pointer& channelProvider) { Lock guard(channelProviderMutex); channelProviders.erase(channelProvider->getProviderName()); } diff --git a/pvAccessApp/factory/CreateRequestFactory.cpp b/pvAccessApp/factory/CreateRequestFactory.cpp index c063549..bfcbe84 100644 --- a/pvAccessApp/factory/CreateRequestFactory.cpp +++ b/pvAccessApp/factory/CreateRequestFactory.cpp @@ -12,254 +12,210 @@ using namespace epics::pvData; + namespace epics { namespace pvAccess { class CreateRequestImpl : public CreateRequest { - private: - - static void trim(std::string& str) - { - std::string::size_type pos = str.find_last_not_of(' '); - if(pos != std::string::npos) { - str.erase(pos + 1); - pos = str.find_first_not_of(' '); - if(pos != std::string::npos) str.erase(0, pos); - } - else str.erase(str.begin(), str.end()); - } - - static int findMatchingBrace(std::string& request, int index, int numOpen) { - size_t openBrace = request.find('{', index+1); - size_t closeBrace = request.find('}', index+1); - if(openBrace == std::string::npos && closeBrace == std::string::npos) return std::string::npos; - if (openBrace != std::string::npos) { - if(openBraceopenBrace)) { - //find matching brace - size_t closeBrace = findMatchingBrace(request,openBrace+1,1); - if(closeBrace==std::string::npos) { - requester->message(request + "mismatched { }", errorMessage); - return false; - } - String fieldName = request.substr(0,openBrace); - PVStructure* pvStructure = getPVDataCreate()->createPVStructure(pvParent, fieldName, 0); - createFieldRequest(pvStructure,request.substr(openBrace+1,closeBrace-openBrace-1),false,requester); - // error check? - pvParent->appendPVField(pvStructure); - if(request.length()>closeBrace+1) { - if(request.at(closeBrace+1) != ',') { - requester->message(request + "misssing , after }", errorMessage); - return false; - } - if(!createFieldRequest(pvParent,request.substr(closeBrace+2),false,requester)) return false; - } - return true; - } - if(openBracket==std::string::npos && fieldListOK) { - PVString* pvStringField = static_cast(getPVDataCreate()->createPVScalar(pvParent, "fieldList", pvString)); - pvStringField->put(request); - pvParent->appendPVField(pvStringField); - return true; - } - if(openBracket!=std::string::npos && (comma==std::string::npos || comma>openBracket)) { - size_t closeBracket = request.find(']'); - if(closeBracket==std::string::npos) { - requester->message(request + "option does not have matching []", errorMessage); - return false; - } - if(!createLeafFieldRequest(pvParent,request.substr(0, closeBracket+1),requester)) return false; - size_t commaLoc = request.rfind(','); - if(commaLoc!=std::string::npos && commaLoc>closeBracket) { - int nextComma = request.find(',', closeBracket); - if(!createFieldRequest(pvParent,request.substr(nextComma+1),false,requester)) return false; - } - return true; - } - if(comma!=std::string::npos) { - if(!createLeafFieldRequest(pvParent,request.substr(0, comma),requester)) return false; - return createFieldRequest(pvParent,request.substr(comma+1),false,requester); - } - return createLeafFieldRequest(pvParent,request,requester); - } - - static bool createLeafFieldRequest(PVStructure* pvParent,String request,Requester* requester) { - size_t openBracket = request.find('['); - String fullName = request; - if(openBracket != std::string::npos) fullName = request.substr(0,openBracket); - size_t indLast = fullName.rfind('.'); - String fieldName = fullName; - if(indLast>1 && indLast != std::string::npos) fieldName = fullName.substr(indLast+1); - PVStructure* pvStructure = getPVDataCreate()->createPVStructure(pvParent, fieldName, 0); - PVStructure* pvLeaf = getPVDataCreate()->createPVStructure(pvStructure,"leaf", 0); - PVString* pvStringField = static_cast(getPVDataCreate()->createPVScalar(pvLeaf, "source", pvString)); - pvStringField->put(fullName); - pvLeaf->appendPVField(pvStringField); - if(openBracket != std::string::npos) { - size_t closeBracket = request.find(']'); - if(closeBracket==std::string::npos) { - delete pvLeaf; - delete pvStructure; - requester->message("option does not have matching []", errorMessage); - return false; - } - if(!createRequestOptions(pvLeaf,request.substr(openBracket+1, closeBracket-openBracket-1),requester)) - { - delete pvLeaf; - delete pvStructure; - return false; - } - } - pvStructure->appendPVField(pvLeaf); - pvParent->appendPVField(pvStructure); - return true; - } - - static bool createRequestOptions(PVStructure* pvParent,std::string request,Requester* requester) { - trim(request); - if(request.length()<=1) return true; - - std::string token; - std::istringstream iss(request); - while (getline(iss, token, ',')) - { - size_t equalsPos = token.find('='); - size_t equalsRPos = token.rfind('='); - if (equalsPos != equalsRPos) - { - requester->message("illegal option", errorMessage); - return false; - } - - if (equalsPos != std::string::npos) - { - PVString* pvStringField = static_cast(getPVDataCreate()->createPVScalar(pvParent, token.substr(0, equalsPos), pvString)); - pvStringField->put(token.substr(equalsPos+1)); - pvParent->appendPVField(pvStringField); - } - } - return true; - } - - public: - - virtual PVStructure* createRequest(String request, Requester* requester) - { - static String emptyString; - if (!request.empty()) trim(request); - if (request.empty()) - { - return getPVDataCreate()->createPVStructure(0, emptyString, 0); - } +private: - size_t offsetRecord = request.find("record["); - size_t offsetField = request.find("field("); - size_t offsetPutField = request.find("putField("); - size_t offsetGetField = request.find("getField("); + static void trim(std::string& str) + { + std::string::size_type pos = str.find_last_not_of(' '); + if(pos != std::string::npos) { + str.erase(pos + 1); + pos = str.find_first_not_of(' '); + if(pos != std::string::npos) str.erase(0, pos); + } + else str.erase(str.begin(), str.end()); + } - PVStructure* pvStructure = getPVDataCreate()->createPVStructure(0, emptyString, 0); + static size_t findMatchingBrace(std::string& request, int index, int numOpen) { + size_t openBrace = request.find('{', index+1); + size_t closeBrace = request.find('}', index+1); + if(openBrace == std::string::npos && closeBrace == std::string::npos) return std::string::npos; + if (openBrace != std::string::npos) { + if(openBraceopenBrace)) { + //find matching brace + size_t closeBrace = findMatchingBrace(request,openBrace+1,1); + if(closeBrace==std::string::npos) { + THROW_BASE_EXCEPTION("mismatched { }"); + } + String fieldName = request.substr(0,openBrace); + std::auto_ptr pvStructure(getPVDataCreate()->createPVStructure(pvParent, fieldName, 0)); + createFieldRequest(pvStructure.get(),request.substr(openBrace+1,closeBrace-openBrace-1),false); + pvParent->appendPVField(pvStructure.release()); + if(request.length()>closeBrace+1) { + if(request.at(closeBrace+1) != ',') { + THROW_BASE_EXCEPTION("misssing , after }"); + } + createFieldRequest(pvParent,request.substr(closeBrace+2),false); + } + return; + } + if(openBracket==std::string::npos && fieldListOK) { + std::auto_ptr pvStringField(static_cast(getPVDataCreate()->createPVScalar(pvParent, "fieldList", pvString))); + pvStringField->put(request); + pvParent->appendPVField(pvStringField.release()); + return; + } + if(openBracket!=std::string::npos && (comma==std::string::npos || comma>openBracket)) { + size_t closeBracket = request.find(']'); + if(closeBracket==std::string::npos) { + THROW_BASE_EXCEPTION("option does not have matching []"); + } + createLeafFieldRequest(pvParent,request.substr(0, closeBracket+1)); + size_t commaLoc = request.rfind(','); + if(commaLoc!=std::string::npos && commaLoc>closeBracket) { + int nextComma = request.find(',', closeBracket); + createFieldRequest(pvParent,request.substr(nextComma+1),false); + } + return; + } + if(comma!=std::string::npos) { + createLeafFieldRequest(pvParent,request.substr(0, comma)); + createFieldRequest(pvParent,request.substr(comma+1),false); + return; + } + createLeafFieldRequest(pvParent,request); + } + + static void createLeafFieldRequest(PVStructure* pvParent,String request) { + size_t openBracket = request.find('['); + String fullName = request; + if(openBracket != std::string::npos) fullName = request.substr(0,openBracket); + size_t indLast = fullName.rfind('.'); + String fieldName = fullName; + if(indLast>1 && indLast != std::string::npos) fieldName = fullName.substr(indLast+1); + std::auto_ptr pvStructure(getPVDataCreate()->createPVStructure(pvParent, fieldName, 0)); + std::auto_ptr pvLeaf(getPVDataCreate()->createPVStructure(pvStructure.get(),"leaf", 0)); + std::auto_ptr pvStringField(static_cast(getPVDataCreate()->createPVScalar(pvLeaf.get(), "source", pvString))); + pvStringField->put(fullName); + pvLeaf->appendPVField(pvStringField.release()); + if(openBracket != std::string::npos) { + size_t closeBracket = request.find(']'); + if(closeBracket==std::string::npos) { + THROW_BASE_EXCEPTION("option does not have matching []"); + } + createRequestOptions(pvLeaf.get(),request.substr(openBracket+1, closeBracket-openBracket-1)); + } + pvStructure->appendPVField(pvLeaf.release()); + pvParent->appendPVField(pvStructure.release()); + } + + static void createRequestOptions(PVStructure* pvParent,std::string request) { + trim(request); + if(request.length()<=1) return; + + std::string token; + std::istringstream iss(request); + while (getline(iss, token, ',')) + { + size_t equalsPos = token.find('='); + size_t equalsRPos = token.rfind('='); + if (equalsPos != equalsRPos) + { + THROW_BASE_EXCEPTION("illegal option"); + } + + if (equalsPos != std::string::npos) + { + std::auto_ptr pvStringField(static_cast(getPVDataCreate()->createPVScalar(pvParent, token.substr(0, equalsPos), pvString))); + pvStringField->put(token.substr(equalsPos+1)); + pvParent->appendPVField(pvStringField.release()); + } + } + } + +public: + + virtual PVStructure::shared_pointer createRequest(String request) + { + static String emptyString; + if (!request.empty()) trim(request); + if (request.empty()) + { + PVStructure::shared_pointer pvStructure(getPVDataCreate()->createPVStructure(0, emptyString, 0)); + return pvStructure; + } + + size_t offsetRecord = request.find("record["); + size_t offsetField = request.find("field("); + size_t offsetPutField = request.find("putField("); + size_t offsetGetField = request.find("getField("); + + PVStructure::shared_pointer pvStructure(getPVDataCreate()->createPVStructure(0, emptyString, 0)); + + if (offsetRecord != std::string::npos) { + size_t offsetBegin = request.find('[', offsetRecord); + size_t offsetEnd = request.find(']', offsetBegin); + if(offsetEnd == std::string::npos) { + THROW_BASE_EXCEPTION("record[ does not have matching ]"); + } + std::auto_ptr pvStruct(getPVDataCreate()->createPVStructure(pvStructure.get(), "record", 0)); + createRequestOptions(pvStruct.get(),request.substr(offsetBegin+1, offsetEnd-offsetBegin-1)); + pvStructure->appendPVField(pvStruct.release()); + } + if (offsetField != std::string::npos) { + size_t offsetBegin = request.find('(', offsetField); + size_t offsetEnd = request.find(')', offsetBegin); + if(offsetEnd == std::string::npos) { + THROW_BASE_EXCEPTION("field( does not have matching )"); + } + std::auto_ptr pvStruct(getPVDataCreate()->createPVStructure(pvStructure.get(), "field", 0)); + createFieldRequest(pvStruct.get(),request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true); + pvStructure->appendPVField(pvStruct.release()); + } + if (offsetPutField != std::string::npos) { + size_t offsetBegin = request.find('(', offsetPutField); + size_t offsetEnd = request.find(')', offsetBegin); + if(offsetEnd == std::string::npos) { + THROW_BASE_EXCEPTION("putField( does not have matching )"); + } + std::auto_ptr pvStruct(getPVDataCreate()->createPVStructure(pvStructure.get(), "putField", 0)); + createFieldRequest(pvStruct.get(),request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true); + pvStructure->appendPVField(pvStruct.release()); + } + if (offsetGetField != std::string::npos) { + size_t offsetBegin = request.find('(', offsetGetField); + size_t offsetEnd = request.find(')', offsetBegin); + if(offsetEnd == std::string::npos) { + THROW_BASE_EXCEPTION("getField( does not have matching )"); + } + std::auto_ptr pvStruct(getPVDataCreate()->createPVStructure(pvStructure.get(), "getField", 0)); + createFieldRequest(pvStruct.get(),request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true); + pvStructure->appendPVField(pvStruct.release()); + } + if (pvStructure.get()->getStructure()->getNumberFields()==0) { + createFieldRequest(pvStructure.get(),request,true); + } + return pvStructure; + } - if (offsetRecord != std::string::npos) { - size_t offsetBegin = request.find('[', offsetRecord); - size_t offsetEnd = request.find(']', offsetBegin); - if(offsetEnd == std::string::npos) { - delete pvStructure; - requester->message("record[ does not have matching ]", errorMessage); - return 0; - } - PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "record", 0); - if(!createRequestOptions(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),requester)) - { - delete pvStruct; - delete pvStructure; - return 0; - } - pvStructure->appendPVField(pvStruct); - } - if (offsetField != std::string::npos) { - size_t offsetBegin = request.find('(', offsetField); - size_t offsetEnd = request.find(')', offsetBegin); - if(offsetEnd == std::string::npos) { - delete pvStructure; - requester->message("field( does not have matching )", errorMessage); - return 0; - } - PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "field", 0); - if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester)) - { - delete pvStruct; - delete pvStructure; - return 0; - } - pvStructure->appendPVField(pvStruct); - } - if (offsetPutField != std::string::npos) { - size_t offsetBegin = request.find('(', offsetPutField); - size_t offsetEnd = request.find(')', offsetBegin); - if(offsetEnd == std::string::npos) { - delete pvStructure; - requester->message("putField( does not have matching )", errorMessage); - return 0; - } - PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "putField", 0); - if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester)) - { - delete pvStruct; - delete pvStructure; - return 0; - } - pvStructure->appendPVField(pvStruct); - } - if (offsetGetField != std::string::npos) { - size_t offsetBegin = request.find('(', offsetGetField); - size_t offsetEnd = request.find(')', offsetBegin); - if(offsetEnd == std::string::npos) { - delete pvStructure; - requester->message("getField( does not have matching )", errorMessage); - return 0; - } - PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "getField", 0); - if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester)) - { - delete pvStruct; - delete pvStructure; - return 0; - } - pvStructure->appendPVField(pvStruct); - } - if (pvStructure->getStructure()->getNumberFields()==0) { - if(!createFieldRequest(pvStructure,request,true,requester)) - { - delete pvStructure; - return 0; - } - } - return pvStructure; - } - }; -static CreateRequest* createRequest = 0; +CreateRequest::shared_pointer createRequest; -CreateRequest * getCreateRequest() { +CreateRequest::shared_pointer getCreateRequest() { static Mutex mutex; Lock guard(mutex); - if(createRequest==0){ - createRequest = new CreateRequestImpl(); + if(createRequest.get()==0){ + createRequest.reset(new CreateRequestImpl()); } return createRequest; } diff --git a/pvAccessApp/remote/abstractResponseHandler.cpp b/pvAccessApp/remote/abstractResponseHandler.cpp index 2d5f0b3..4b3702e 100644 --- a/pvAccessApp/remote/abstractResponseHandler.cpp +++ b/pvAccessApp/remote/abstractResponseHandler.cpp @@ -6,7 +6,7 @@ */ #include "remote.h" -#include "hexDump.h" +#include #include @@ -23,7 +23,7 @@ namespace epics { namespace pvAccess { void AbstractResponseHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { if(_debug) { char ipAddrStr[48]; diff --git a/pvAccessApp/remote/beaconEmitter.cpp b/pvAccessApp/remote/beaconEmitter.cpp deleted file mode 100644 index bcd6469..0000000 --- a/pvAccessApp/remote/beaconEmitter.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * beaconEmitter.cpp - */ - -#include "beaconEmitter.h" - -using namespace std; - -namespace epics { namespace pvAccess { - -const float BeaconEmitter::EPICS_CA_MIN_BEACON_PERIOD = 1.0; -const float BeaconEmitter::EPICS_CA_MIN_BEACON_COUNT_LIMIT = 3.0; - -BeaconEmitter::BeaconEmitter(Transport* transport, ServerContextImpl* context): _transport(transport) -{ - if(transport == NULL || context == NULL) - { - THROW_BASE_EXCEPTION("null transport or context"); - } - - _timer = context->getTimer(); - _beaconSequenceID = 0; - _serverAddress = context->getServerInetAddress(); - _serverPort = context->getServerPort(); - _serverStatusProvider = context->getBeaconServerStatusProvider(); - _fastBeaconPeriod = std::max(context->getBeaconPeriod(), EPICS_CA_MIN_BEACON_PERIOD); - _slowBeaconPeriod = std::max(180.0, _fastBeaconPeriod); // TODO configurable - _beaconCountLimit = (int16)std::max(10.0f, EPICS_CA_MIN_BEACON_COUNT_LIMIT); // TODO configurable - _startupTime = new TimeStamp(); - _startupTime->getCurrent(); - _timerNode = new TimerNode(*this); -} - -BeaconEmitter::BeaconEmitter(Transport* transport,const osiSockAddr* serverAddress): _transport(transport) -{ - if(transport == NULL) - { - THROW_BASE_EXCEPTION("null transport"); - } - - _timer = new Timer("pvAccess-server timer", lowPriority); - - _beaconSequenceID = 0; - _serverAddress = serverAddress; - _serverPort = serverAddress->ia.sin_port; - _serverStatusProvider = NULL;//new BeaconServerStatusProvider(); - _fastBeaconPeriod = EPICS_CA_MIN_BEACON_PERIOD; - _slowBeaconPeriod = 180.0; - _beaconCountLimit = 10; - _startupTime = new TimeStamp(); - _startupTime->getCurrent(); - _timerNode = new TimerNode(*this); -} - -BeaconEmitter::~BeaconEmitter() -{ - if(_serverStatusProvider) delete _serverStatusProvider; - if(_timerNode) delete _timerNode; - if(_startupTime) delete _startupTime; -} - -void BeaconEmitter::lock() -{ - //noop -} - -void BeaconEmitter::unlock() -{ - //noop -} - -void BeaconEmitter::acquire() -{ - //noop -} - -void BeaconEmitter::release() -{ - //noop -} - -void BeaconEmitter::send(ByteBuffer* buffer, TransportSendControl* control) -{ - // get server status - PVFieldPtr serverStatus = NULL; - if(_serverStatusProvider != NULL) - { - try - { - serverStatus = _serverStatusProvider->getServerStatusData(); - } - catch (...) { - // we have to proctect internal code from external implementation... - errlogSevPrintf(errlogMinor, "BeaconServerStatusProvider implementation thrown an exception."); - } - } - - // send beacon - control->startMessage((int8)0, (sizeof(int16)+2*sizeof(int32)+128+sizeof(int16))/sizeof(int8)); - - buffer->putShort(_beaconSequenceID); - buffer->putLong((int64)_startupTime->getSecondsPastEpoch()); - buffer->putInt((int32)_startupTime->getNanoSeconds()); - - // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 - encodeAsIPv6Address(buffer, _serverAddress); - buffer->putShort((int16)_serverPort); - - if (serverStatus != NULL) - { - // introspection interface + data - IntrospectionRegistry::serializeFull(serverStatus->getField(), buffer, control); - serverStatus->serialize(buffer, control); - } - else - { - IntrospectionRegistry::serializeFull(NULL, buffer, control); - } - control->flush(true); - - // increment beacon sequence ID - _beaconSequenceID++; - - reschedule(); -} - -void BeaconEmitter::timerStopped() -{ - //noop -} - -void BeaconEmitter::destroy() -{ - _timerNode->cancel(); -} - -void BeaconEmitter::start() -{ - _timer->scheduleAfterDelay(*_timerNode, 0.0); -} - -void BeaconEmitter::reschedule() -{ - const double period = (_beaconSequenceID >= _beaconCountLimit) ? _slowBeaconPeriod : _fastBeaconPeriod; - if (period > 0) - { - _timer->scheduleAfterDelay(*_timerNode, period); - } -} - -void BeaconEmitter::callback() -{ - _transport->enqueueSendRequest(this); -} - -}} - diff --git a/pvAccessApp/remote/beaconHandler.cpp b/pvAccessApp/remote/beaconHandler.cpp index b7a1803..c82f173 100644 --- a/pvAccessApp/remote/beaconHandler.cpp +++ b/pvAccessApp/remote/beaconHandler.cpp @@ -3,6 +3,7 @@ */ #include "beaconHandler.h" +#include "transportRegistry.h" using namespace std; using namespace epics::pvData; @@ -10,9 +11,9 @@ using namespace epics::pvAccess; namespace epics { namespace pvAccess { -BeaconHandler::BeaconHandler(ClientContextImpl* context, +BeaconHandler::BeaconHandler(Context::shared_pointer context, const osiSockAddr* responseFrom) - :_context(context) + :_context(Context::weak_pointer(context)) ,_responseFrom(*responseFrom) ,_mutex() ,_serverStartupTime(0) @@ -54,7 +55,7 @@ bool BeaconHandler::updateBeacon(int8 remoteTransportRevision, TimeStamp* timest _serverStartupTime = *startupTime; // new server up.. - _context->beaconAnomalyNotify(); + _context.lock()->beaconAnomalyNotify(); // notify corresponding transport(s) beaconArrivalNotify(); @@ -65,7 +66,7 @@ bool BeaconHandler::updateBeacon(int8 remoteTransportRevision, TimeStamp* timest bool networkChange = !(_serverStartupTime == *startupTime); if (networkChange) { - _context->beaconAnomalyNotify(); + _context.lock()->beaconAnomalyNotify(); } else { @@ -77,38 +78,34 @@ bool BeaconHandler::updateBeacon(int8 remoteTransportRevision, TimeStamp* timest void BeaconHandler::beaconArrivalNotify() { - int32 size = 0; - //TODO TCP name must be get from somewhere not hardcoded - Transport** transports = _context->getTransportRegistry()->get("TCP", &_responseFrom, size); - if (transports == NULL) - { + auto_ptr transports = + _context.lock()->getTransportRegistry()->get("TCP", &_responseFrom); + if (!transports.get()) return; - } // notify all - for (int i = 0; i < size; i++) + for (TransportRegistry::transportVector_t::iterator iter = transports->begin(); + iter != transports->end(); + iter++) { - transports[i]->aliveNotification(); + (*iter)->aliveNotification(); } - delete[] transports; } void BeaconHandler::changedTransport() { - int32 size = 0; - //TODO TCP name must be get from somewhere not hardcoded - Transport** transports = _context->getTransportRegistry()->get("TCP", &_responseFrom, size); - if (transports == NULL) - { + auto_ptr transports = + _context.lock()->getTransportRegistry()->get("TCP", &_responseFrom); + if (!transports.get()) return; - } - + // notify all - for (int i = 0; i < size; i++) + for (TransportRegistry::transportVector_t::iterator iter = transports->begin(); + iter != transports->end(); + iter++) { - transports[i]->changedTransport(); + (*iter)->changedTransport(); } - delete[] transports; } }} diff --git a/pvAccessApp/remote/beaconHandler.h b/pvAccessApp/remote/beaconHandler.h index 88664d6..8fdb2f4 100644 --- a/pvAccessApp/remote/beaconHandler.h +++ b/pvAccessApp/remote/beaconHandler.h @@ -7,7 +7,6 @@ #include "remote.h" #include -#include "clientContextImpl.h" #include #include @@ -21,12 +20,15 @@ namespace epics { namespace pvAccess { class BeaconHandler { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + /** * Constructor. * @param transport transport to be used to send beacons. * @param context CA context. */ - BeaconHandler(ClientContextImpl* context, const osiSockAddr* responseFrom); + BeaconHandler(Context::shared_pointer context, const osiSockAddr* responseFrom); /** * Test Constructor (for testing) * @param transport transport to be used to send beacons. @@ -52,7 +54,7 @@ namespace epics { namespace pvAccess { /** * Context instance. */ - ClientContextImpl* _context; + Context::weak_pointer _context; /** * Remote address. */ diff --git a/pvAccessApp/remote/beaconServerStatusProvider.h b/pvAccessApp/remote/beaconServerStatusProvider.h deleted file mode 100644 index 5b65494..0000000 --- a/pvAccessApp/remote/beaconServerStatusProvider.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * beaconServerStatusProvider.h - */ - -#ifndef BEACONSERVERSTATUSPROVIDER_H -#define BEACONSERVERSTATUSPROVIDER_H - -#include "pvData.h" - -using namespace epics::pvData; - -namespace epics { namespace pvAccess { - - class ServerContext; - /** - * BeaconServerStatusProvider - */ - class BeaconServerStatusProvider - { - public: - /** - * Constructor. - * @param context CA context. - */ - BeaconServerStatusProvider(ServerContext* context); - /** - * Test Constructor (without context) - */ - BeaconServerStatusProvider(); - /** - * Destructor. - */ - virtual ~BeaconServerStatusProvider(); - /** - * Gets server status data. - */ - PVFieldPtr getServerStatusData(); - private: - /** - * Initialize - */ - void initialize(); - - - private: - PVStructurePtr _status; - ServerContext* _context; - }; - -}} - -#endif /* INTROSPECTIONREGISTRY_H */ diff --git a/pvAccessApp/remote/blockingClientTCPTransport.cpp b/pvAccessApp/remote/blockingClientTCPTransport.cpp index 9fa6ae4..dce6d81 100644 --- a/pvAccessApp/remote/blockingClientTCPTransport.cpp +++ b/pvAccessApp/remote/blockingClientTCPTransport.cpp @@ -21,7 +21,7 @@ #include #include -using std::set; +using namespace std; using namespace epics::pvData; namespace epics { @@ -31,16 +31,18 @@ namespace epics { catch (std::exception &e) { errlogSevPrintf(errlogMajor, "Unhandled exception caught from code at %s:%d: %s", __FILE__, __LINE__, e.what()); } \ catch (...) { errlogSevPrintf(errlogMajor, "Unhandled exception caught from code at %s:%d.", __FILE__, __LINE__); } - BlockingClientTCPTransport::BlockingClientTCPTransport( - Context* context, SOCKET channel, - ResponseHandler* responseHandler, int receiveBufferSize, - TransportClient* client, short remoteTransportRevision, + BlockingClientTCPTransport::BlockingClientTCPTransport( + Context::shared_pointer& context, SOCKET channel, + auto_ptr& responseHandler, int receiveBufferSize, + TransportClient::shared_pointer client, short remoteTransportRevision, float beaconInterval, int16 priority) : - BlockingTCPTransport(context, channel, responseHandler, - receiveBufferSize, priority), _introspectionRegistry( - new IntrospectionRegistry(false)), _connectionTimeout(beaconInterval - *1000), _unresponsiveTransport(false), _timerNode( - new TimerNode(*this)), _verifyOrEcho(true) { + BlockingTCPTransport(context, channel, responseHandler, receiveBufferSize, priority), + _introspectionRegistry(false), + _connectionTimeout(beaconInterval*1000), + _unresponsiveTransport(false), + _timerNode(*this), + _verifyOrEcho(true) + { // _autoDelete = false; // initialize owners list, send queue @@ -52,16 +54,13 @@ namespace epics { // setup connection timeout timer (watchdog) epicsTimeGetCurrent(&_aliveTimestamp); - context->getTimer()->schedulePeriodic(*_timerNode, beaconInterval, - beaconInterval); + context->getTimer()->schedulePeriodic(_timerNode, beaconInterval, beaconInterval); - start(); + //start(); } BlockingClientTCPTransport::~BlockingClientTCPTransport() { - delete _introspectionRegistry; - delete _timerNode; } void BlockingClientTCPTransport::callback() { @@ -79,7 +78,8 @@ namespace epics { // use some k (3/4) to handle "jitter" else if(diff>=((3*_connectionTimeout)/4)) { // send echo - enqueueSendRequest(this); + TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast(shared_from_this()); + enqueueSendRequest(transportSender); } } @@ -88,17 +88,18 @@ namespace epics { if(!_unresponsiveTransport) { _unresponsiveTransport = true; - set::iterator it = _owners.begin(); + TransportClientMap_t::iterator it = _owners.begin(); for(; it!=_owners.end(); it++) { - TransportClient* client = *it; - client->acquire(); - EXCEPTION_GUARD(client->transportUnresponsive()); - client->release(); + TransportClient::shared_pointer client = it->second.lock(); + if (client) + { + EXCEPTION_GUARD(client->transportUnresponsive()); + } } } } - bool BlockingClientTCPTransport::acquire(TransportClient* client) { + bool BlockingClientTCPTransport::acquire(TransportClient::shared_pointer& client) { Lock lock(_mutex); if(_closed) return false; @@ -108,7 +109,8 @@ namespace epics { Lock lock2(_ownersMutex); // TODO double check? if(_closed) return false; - _owners.insert(client); + //_owners.insert(TransportClient::weak_pointer(client)); + _owners[client->getID()] = TransportClient::weak_pointer(client); return true; } @@ -116,7 +118,7 @@ namespace epics { void BlockingClientTCPTransport::internalClose(bool forced) { BlockingTCPTransport::internalClose(forced); - _timerNode->cancel(); + _timerNode.cancel(); closedNotifyClients(); } @@ -137,12 +139,13 @@ namespace epics { "Transport to %s still has %d client(s) active and closing...", ipAddrStr, refs); - set::iterator it = _owners.begin(); + TransportClientMap_t::iterator it = _owners.begin(); for(; it!=_owners.end(); it++) { - TransportClient* client = *it; - client->acquire(); - EXCEPTION_GUARD(client->transportClosed()); - client->release(); + TransportClient::shared_pointer client = it->second.lock(); + if (client) + { + EXCEPTION_GUARD(client->transportClosed()); + } } } @@ -150,7 +153,8 @@ namespace epics { _owners.clear(); } - void BlockingClientTCPTransport::release(TransportClient* client) { + //void BlockingClientTCPTransport::release(TransportClient::shared_pointer& client) { + void BlockingClientTCPTransport::release(pvAccessID clientID) { Lock lock(_mutex); if(_closed) return; @@ -160,9 +164,10 @@ namespace epics { errlogSevPrintf(errlogInfo, "Releasing transport to %s.", ipAddrStr); Lock lock2(_ownersMutex); - _owners.erase(client); - - // not used anymore + _owners.erase(clientID); + //_owners.erase(TransportClient::weak_pointer(client)); + + // not used anymore, close it // TODO consider delayed destruction (can improve performance!!!) if(_owners.size()==0) close(false); } @@ -178,26 +183,29 @@ namespace epics { if(_unresponsiveTransport) { _unresponsiveTransport = false; - set::iterator it = _owners.begin(); + Transport::shared_pointer thisSharedPtr = shared_from_this(); + TransportClientMap_t::iterator it = _owners.begin(); for(; it!=_owners.end(); it++) { - TransportClient* client = *it; - client->acquire(); - EXCEPTION_GUARD(client->transportResponsive(this)); - client->release(); + TransportClient::shared_pointer client = it->second.lock(); + if (client) + { + EXCEPTION_GUARD(client->transportResponsive(thisSharedPtr)); + } } } } void BlockingClientTCPTransport::changedTransport() { - _introspectionRegistry->reset(); + _introspectionRegistry.reset(); Lock lock(_ownersMutex); - set::iterator it = _owners.begin(); + TransportClientMap_t::iterator it = _owners.begin(); for(; it!=_owners.end(); it++) { - TransportClient* client = *it; - client->acquire(); - EXCEPTION_GUARD(client->transportChanged()); - client->release(); + TransportClient::shared_pointer client = it->second.lock(); + if (client) + { + EXCEPTION_GUARD(client->transportChanged()); + } } } diff --git a/pvAccessApp/remote/blockingServerTCPTransport.cpp b/pvAccessApp/remote/blockingServerTCPTransport.cpp index aabac00..0ad20f3 100644 --- a/pvAccessApp/remote/blockingServerTCPTransport.cpp +++ b/pvAccessApp/remote/blockingServerTCPTransport.cpp @@ -20,27 +20,26 @@ #include using namespace epics::pvData; -using std::map; +using namespace std; namespace epics { namespace pvAccess { BlockingServerTCPTransport::BlockingServerTCPTransport( - Context* context, SOCKET channel, - ResponseHandler* responseHandler, int receiveBufferSize) : - BlockingTCPTransport(context, channel, responseHandler, - receiveBufferSize, CA_DEFAULT_PRIORITY), - _introspectionRegistry(new IntrospectionRegistry(true)), - _lastChannelSID(0) { + Context::shared_pointer& context, SOCKET channel, + auto_ptr& responseHandler, int receiveBufferSize) : + BlockingTCPTransport(context, channel, responseHandler, receiveBufferSize, CA_DEFAULT_PRIORITY), + _introspectionRegistry(true), + _lastChannelSID(0) + { // NOTE: priority not yet known, default priority is used to register/unregister // TODO implement priorities in Reactor... not that user will // change it.. still getPriority() must return "registered" priority! - start(); + //start(); } BlockingServerTCPTransport::~BlockingServerTCPTransport() { - delete _introspectionRegistry; } void BlockingServerTCPTransport::destroyAllChannels() { @@ -53,9 +52,9 @@ namespace epics { errlogSevPrintf( errlogInfo, "Transport to %s still has %u channel(s) active and closing...", - ipAddrStr, _channels.size()); + ipAddrStr, (unsigned int)_channels.size()); - map::iterator it = _channels.begin(); + map::iterator it = _channels.begin(); for(; it!=_channels.end(); it++) it->second->destroy(); @@ -76,8 +75,7 @@ namespace epics { return sid; } - void BlockingServerTCPTransport::registerChannel(pvAccessID sid, - ServerChannel* channel) { + void BlockingServerTCPTransport::registerChannel(pvAccessID sid, ServerChannel::shared_pointer& channel) { Lock lock(_channelsMutex); _channels[sid] = channel; } @@ -87,13 +85,13 @@ namespace epics { _channels.erase(sid); } - ServerChannel* BlockingServerTCPTransport::getChannel(pvAccessID sid) { + ServerChannel::shared_pointer BlockingServerTCPTransport::getChannel(pvAccessID sid) { Lock lock(_channelsMutex); - map::iterator it = _channels.find(sid); + map::iterator it = _channels.find(sid); if(it!=_channels.end()) return it->second; - return NULL; + return ServerChannel::shared_pointer(); } int BlockingServerTCPTransport::getChannelCount() { diff --git a/pvAccessApp/remote/blockingTCP.h b/pvAccessApp/remote/blockingTCP.h index cfe328b..104f826 100644 --- a/pvAccessApp/remote/blockingTCP.h +++ b/pvAccessApp/remote/blockingTCP.h @@ -11,7 +11,6 @@ /* pvAccess */ #include "caConstants.h" #include "remote.h" -#include "growingCircularBuffer.h" #include "transportRegistry.h" #include "introspectionRegistry.h" #include "namedLockPattern.h" @@ -33,11 +32,12 @@ /* standard */ #include #include +#include namespace epics { namespace pvAccess { - class MonitorSender; + //class MonitorSender; enum ReceiveStage { READ_FROM_SOCKET, PROCESS_HEADER, PROCESS_PAYLOAD, NONE @@ -47,13 +47,17 @@ namespace epics { IMMEDIATE, DELAYED, USER_CONTROLED }; - class BlockingTCPTransport : public Transport, - public TransportSendControl { - public: - BlockingTCPTransport(Context* context, SOCKET channel, - ResponseHandler* responseHandler, int receiveBufferSize, + class BlockingTCPTransport : + public Transport, + public TransportSendControl, + public std::tr1::enable_shared_from_this + { + protected: + BlockingTCPTransport(Context::shared_pointer& context, SOCKET channel, + std::auto_ptr& responseHandler, int receiveBufferSize, int16 priority); + public: virtual bool isClosed() { Lock guard(_mutex); return _closed; @@ -63,16 +67,12 @@ namespace epics { _remoteTransportRevision = minorRevision; } - virtual void setRemoteTransportReceiveBufferSize( - int remoteTransportReceiveBufferSize) { - _remoteTransportReceiveBufferSize - = remoteTransportReceiveBufferSize; + virtual void setRemoteTransportReceiveBufferSize(int remoteTransportReceiveBufferSize) { + _remoteTransportReceiveBufferSize = remoteTransportReceiveBufferSize; } - virtual void setRemoteTransportSocketReceiveBufferSize( - int socketReceiveBufferSize) { - _remoteTransportSocketReceiveBufferSize - = socketReceiveBufferSize; + virtual void setRemoteTransportSocketReceiveBufferSize(int socketReceiveBufferSize) { + _remoteTransportSocketReceiveBufferSize = socketReceiveBufferSize; } virtual const String getType() const { @@ -117,6 +117,7 @@ namespace epics { virtual void verified() { Lock lock(_verifiedMutex); _verified = true; + _verifiedEvent.signal(); } virtual void setRecipient(const osiSockAddr& sendTo) { @@ -162,9 +163,9 @@ namespace epics { */ void start(); - virtual void enqueueSendRequest(TransportSender* sender); + virtual void enqueueSendRequest(TransportSender::shared_pointer& sender); - void enqueueMonitorSendRequest(TransportSender* sender); + //void enqueueMonitorSendRequest(TransportSender::shared_pointer& sender); protected: @@ -222,7 +223,7 @@ namespace epics { /** * CAS response handler. */ - ResponseHandler* _responseHandler; + std::auto_ptr _responseHandler; /** * Send buffer size. @@ -247,9 +248,10 @@ namespace epics { epicsThreadId _sendThreadId; - MonitorSender* _monitorSender; + // TODO + //MonitorSender* _monitorSender; - Context* _context; + Context::shared_pointer _context; bool _autoDelete; @@ -279,11 +281,11 @@ namespace epics { // and its reference is only valid when called from send thread // initialized at construction time - GrowingCircularBuffer* _sendQueue; + std::deque _sendQueue; epics::pvData::Mutex _sendQueueMutex; // initialized at construction time - GrowingCircularBuffer* _monitorSendQueue; + std::deque _monitorSendQueue; epics::pvData::Mutex _monitorMutex; /** @@ -371,6 +373,8 @@ namespace epics { Event _sendQueueEvent; + Event _verifiedEvent; + @@ -419,43 +423,63 @@ namespace epics { * Free all send buffers (return them to the cached buffer allocator). */ void freeSendBuffers(); - - TransportSender* extractFromSendQueue(); }; + class BlockingClientTCPTransport : public BlockingTCPTransport, public TransportSender, public epics::pvData::TimerCallback, public ReferenceCountingTransport { public: - BlockingClientTCPTransport(Context* context, SOCKET channel, - ResponseHandler* responseHandler, int receiveBufferSize, - TransportClient* client, short remoteTransportRevision, + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + private: + BlockingClientTCPTransport(Context::shared_pointer& context, SOCKET channel, + std::auto_ptr& responseHandler, int receiveBufferSize, + TransportClient::shared_pointer client, short remoteTransportRevision, float beaconInterval, int16 priority); + public: + static BlockingClientTCPTransport::shared_pointer create(Context::shared_pointer& context, SOCKET channel, + std::auto_ptr& responseHandler, int receiveBufferSize, + TransportClient::shared_pointer client, short remoteTransportRevision, + float beaconInterval, int16 priority) + { + BlockingClientTCPTransport::shared_pointer thisPointer( + new BlockingClientTCPTransport(context, channel, responseHandler, receiveBufferSize, + client, remoteTransportRevision, beaconInterval, priority) + ); + thisPointer->start(); + return thisPointer; + } + + virtual ~BlockingClientTCPTransport(); + virtual void timerStopped() { // noop } virtual void callback(); + virtual IntrospectionRegistry* getIntrospectionRegistry() { + return &_introspectionRegistry; + } + /** * Acquires transport. * @param client client (channel) acquiring the transport * @return true if transport was granted, false otherwise. */ - virtual bool acquire(TransportClient* client); - - virtual IntrospectionRegistry* getIntrospectionRegistry() { - return _introspectionRegistry; - } + virtual bool acquire(TransportClient::shared_pointer& client); /** * Releases transport. * @param client client (channel) releasing the transport */ - virtual void release(TransportClient* client); + virtual void release(pvAccessID clientId); + //virtual void release(TransportClient::shared_pointer& client); /** * Alive notification. @@ -493,18 +517,18 @@ namespace epics { /** * Introspection registry. */ - IntrospectionRegistry* _introspectionRegistry; + IntrospectionRegistry _introspectionRegistry; virtual void internalClose(bool force); - virtual ~BlockingClientTCPTransport(); - private: /** * Owners (users) of the transport. */ - std::set _owners; + // TODO consider using TR1 hash map + typedef std::map TransportClientMap_t; + TransportClientMap_t _owners; /** * Connection timeout (no-traffic) flag. @@ -519,7 +543,7 @@ namespace epics { /** * Timer task node. */ - TimerNode* _timerNode; + TimerNode _timerNode; /** * Timestamp of last "live" event on this transport. @@ -531,6 +555,9 @@ namespace epics { bool _verifyOrEcho; + /** + * Unresponsive transport notify. + */ void unresponsiveTransport(); /** @@ -551,13 +578,13 @@ namespace epics { */ class BlockingTCPConnector : public Connector { public: - BlockingTCPConnector(Context* context, int receiveBufferSize, + BlockingTCPConnector(Context::shared_pointer& context, int receiveBufferSize, float beaconInterval); virtual ~BlockingTCPConnector(); - virtual Transport* connect(TransportClient* client, - ResponseHandler* responseHandler, osiSockAddr& address, + virtual Transport::shared_pointer connect(TransportClient::shared_pointer& client, + std::auto_ptr& responseHandler, osiSockAddr& address, short transportRevision, int16 priority); private: /** @@ -568,13 +595,12 @@ namespace epics { /** * Context instance. */ - Context* _context; + Context::weak_pointer _context; /** * named lock */ - NamedLockPattern - * _namedLocker; + NamedLockPattern _namedLocker; /** * Receive buffer size. @@ -601,11 +627,25 @@ namespace epics { public ChannelHostingTransport, public TransportSender { public: - BlockingServerTCPTransport(Context* context, SOCKET channel, - ResponseHandler* responseHandler, int receiveBufferSize); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + private: + BlockingServerTCPTransport(Context::shared_pointer& context, SOCKET channel, + std::auto_ptr& responseHandler, int receiveBufferSize); + public: + static BlockingServerTCPTransport::shared_pointer create(Context::shared_pointer& context, SOCKET channel, + std::auto_ptr& responseHandler, int receiveBufferSize) + { + BlockingServerTCPTransport::shared_pointer thisPointer( + new BlockingServerTCPTransport(context, channel, responseHandler, receiveBufferSize) + ); + thisPointer->start(); + return thisPointer; + } + virtual IntrospectionRegistry* getIntrospectionRegistry() { - return _introspectionRegistry; + return &_introspectionRegistry; } /** @@ -627,7 +667,7 @@ namespace epics { * @param sid preallocated channel SID. * @param channel channel to register. */ - virtual void registerChannel(pvAccessID sid, ServerChannel* channel); + virtual void registerChannel(pvAccessID sid, ServerChannel::shared_pointer& channel); /** * Unregister a new channel (and deallocates its handle). @@ -640,7 +680,7 @@ namespace epics { * @param sid channel SID * @return channel with given SID, NULL otherwise */ - virtual ServerChannel* getChannel(pvAccessID sid); + virtual ServerChannel::shared_pointer getChannel(pvAccessID sid); /** * Get channel count. @@ -648,8 +688,8 @@ namespace epics { */ virtual int getChannelCount(); - virtual epics::pvData::PVField* getSecurityToken() { - return NULL; + virtual epics::pvData::PVField::shared_pointer getSecurityToken() { + return epics::pvData::PVField::shared_pointer(); } virtual void lock() { @@ -672,7 +712,8 @@ namespace epics { * Verify transport. Server side is self-verified. */ void verify() { - enqueueSendRequest(this); + TransportSender::shared_pointer transportSender = std::tr1::dynamic_pointer_cast(shared_from_this()); + enqueueSendRequest(transportSender); verified(); } @@ -699,16 +740,16 @@ namespace epics { virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); + virtual ~BlockingServerTCPTransport(); + protected: /** * Introspection registry. */ - IntrospectionRegistry* _introspectionRegistry; + IntrospectionRegistry _introspectionRegistry; virtual void internalClose(bool force); - virtual ~BlockingServerTCPTransport(); - private: /** * Last SID cache. @@ -718,7 +759,7 @@ namespace epics { /** * Channel table (SID -> channel mapping). */ - std::map _channels; + std::map _channels; Mutex _channelsMutex; @@ -727,7 +768,18 @@ namespace epics { */ void destroyAllChannels(); }; + + class ResponseHandlerFactory + { + public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + virtual ~ResponseHandlerFactory() {}; + virtual std::auto_ptr createResponseHandler() = 0; + }; + /** * Channel Access Server TCP acceptor. * @author Matej Sekoranja @@ -735,6 +787,8 @@ namespace epics { */ class BlockingTCPAcceptor { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; /** * @param context @@ -742,8 +796,9 @@ namespace epics { * @param receiveBufferSize * @throws CAException */ - BlockingTCPAcceptor(Context* context, int port, - int receiveBufferSize); + BlockingTCPAcceptor(Context::shared_pointer& context, + ResponseHandlerFactory::shared_pointer& responseHandlerFactory, + int port, int receiveBufferSize); virtual ~BlockingTCPAcceptor(); @@ -753,7 +808,7 @@ namespace epics { * Bind socket address. * @return bind socket address, null if not binded. */ - osiSockAddr* getBindAddress() { + const osiSockAddr* getBindAddress() { return &_bindAddress; } @@ -766,7 +821,12 @@ namespace epics { /** * Context instance. */ - Context* _context; + Context::shared_pointer _context; + + /** + * ResponseHandler factory. + */ + ResponseHandlerFactory::shared_pointer _responseHandlerFactory; /** * Bind server socket address. @@ -802,8 +862,7 @@ namespace epics { * Validate connection by sending a validation message request. * @return true on success. */ - bool validateConnection(BlockingServerTCPTransport* transport, - const char* address); + bool validateConnection(BlockingServerTCPTransport::shared_pointer& transport, const char* address); static void handleEventsRunner(void* param); }; diff --git a/pvAccessApp/remote/blockingTCPAcceptor.cpp b/pvAccessApp/remote/blockingTCPAcceptor.cpp index a41626c..6cd27ab 100644 --- a/pvAccessApp/remote/blockingTCPAcceptor.cpp +++ b/pvAccessApp/remote/blockingTCPAcceptor.cpp @@ -1,15 +1,10 @@ /* * blockingTCPAcceptor.cpp - * - * Created on: Jan 4, 2011 - * Author: Miha Vitorovic */ /* pvAccess */ -#include "blockingTCP.h" -#include "remote.h" -#include "serverContext.h" -#include "responseHandlers.h" +#include +#include /* pvData */ #include @@ -27,11 +22,19 @@ using std::ostringstream; namespace epics { namespace pvAccess { - BlockingTCPAcceptor::BlockingTCPAcceptor(Context* context, int port, + BlockingTCPAcceptor::BlockingTCPAcceptor( + Context::shared_pointer& context, + ResponseHandlerFactory::shared_pointer& responseHandlerFactory, + int port, int receiveBufferSize) : - _context(context), _bindAddress(), _serverSocketChannel( - INVALID_SOCKET), _receiveBufferSize(receiveBufferSize), - _destroyed(false), _threadId(NULL) { + _context(context), + _responseHandlerFactory(responseHandlerFactory), + _bindAddress(), + _serverSocketChannel(INVALID_SOCKET), + _receiveBufferSize(receiveBufferSize), + _destroyed(false), + _threadId(0) + { initialize(port); } @@ -52,14 +55,11 @@ namespace epics { int tryCount = 0; while(tryCount<2) { - errlogSevPrintf(errlogInfo, "Creating acceptor to %s.", - ipAddrStr); + errlogSevPrintf(errlogInfo, "Creating acceptor to %s.", ipAddrStr); - _serverSocketChannel = epicsSocketCreate(AF_INET, SOCK_STREAM, - IPPROTO_TCP); + _serverSocketChannel = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(_serverSocketChannel==INVALID_SOCKET) { - epicsSocketConvertErrnoToString(strBuffer, - sizeof(strBuffer)); + epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); ostringstream temp; temp<<"Socket create error: "< responseHandler = _responseHandlerFactory->createResponseHandler(); + BlockingServerTCPTransport::shared_pointer transport = + BlockingServerTCPTransport::create( _context, newClient, - new ServerResponseHandler( - dynamic_cast (_context)), + responseHandler, _receiveBufferSize); // validate connection @@ -223,8 +204,7 @@ namespace epics { return; } - errlogSevPrintf(errlogInfo, "Serving to CA client: %s", - ipAddrStr); + errlogSevPrintf(errlogInfo, "Serving to CA client: %s", ipAddrStr); }// accept succeeded else @@ -232,8 +212,7 @@ namespace epics { } // while } - bool BlockingTCPAcceptor::validateConnection( - BlockingServerTCPTransport* transport, const char* address) { + bool BlockingTCPAcceptor::validateConnection(BlockingServerTCPTransport::shared_pointer& transport, const char* address) { try { transport->verify(); return true; @@ -254,10 +233,8 @@ namespace epics { if(_serverSocketChannel!=INVALID_SOCKET) { char ipAddrStr[48]; - ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, - sizeof(ipAddrStr)); - errlogSevPrintf(errlogInfo, - "Stopped accepting connections at %s.", ipAddrStr); + ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr)); + errlogSevPrintf(errlogInfo, "Stopped accepting connections at %s.", ipAddrStr); epicsSocketDestroy(_serverSocketChannel); } diff --git a/pvAccessApp/remote/blockingTCPConnector.cpp b/pvAccessApp/remote/blockingTCPConnector.cpp index 54a9f06..9129ce1 100644 --- a/pvAccessApp/remote/blockingTCPConnector.cpp +++ b/pvAccessApp/remote/blockingTCPConnector.cpp @@ -20,105 +20,102 @@ namespace epics { namespace pvAccess { - BlockingTCPConnector::BlockingTCPConnector(Context* context, - int receiveBufferSize, float beaconInterval) : - _context(context), _namedLocker(new NamedLockPattern< - const osiSockAddr*, comp_osiSockAddrPtr> ()), - _receiveBufferSize(receiveBufferSize), _beaconInterval( - beaconInterval) { + BlockingTCPConnector::BlockingTCPConnector( + Context::shared_pointer& context, + int receiveBufferSize, + float beaconInterval) : + _context(context), + _namedLocker(), + _receiveBufferSize(receiveBufferSize), + _beaconInterval(beaconInterval) + { } BlockingTCPConnector::~BlockingTCPConnector() { - delete _namedLocker; } SOCKET BlockingTCPConnector::tryConnect(osiSockAddr& address, int tries) { - for(int tryCount = 0; tryCount0) epicsThreadSleep(0.1); + + char strBuffer[64]; + ipAddrToDottedIP(&address.ia, strBuffer, sizeof(strBuffer)); - char strBuffer[64]; - ipAddrToDottedIP(&address.ia, strBuffer, sizeof(strBuffer)); + for(int tryCount = 0; tryCount& responseHandler, osiSockAddr& address, short transportRevision, int16 priority) { SOCKET socket = INVALID_SOCKET; char ipAddrStr[64]; ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr)); + + Context::shared_pointer context = _context.lock(); // first try to check cache w/o named lock... - BlockingClientTCPTransport - * transport = - (BlockingClientTCPTransport*)(_context->getTransportRegistry()->get( - "TCP", &address, priority)); - if(transport!=NULL) { + Transport::shared_pointer tt = context->getTransportRegistry()->get("TCP", &address, priority); + BlockingClientTCPTransport::shared_pointer transport = std::tr1::static_pointer_cast(tt); + if(transport.get()) { errlogSevPrintf(errlogInfo, "Reusing existing connection to CA server: %s", ipAddrStr); - if(transport->acquire(client)) return transport; + if (transport->acquire(client)) + return transport; } - bool lockAcquired = _namedLocker->acquireSynchronizationObject( - &address, LOCK_TIMEOUT); + bool lockAcquired = _namedLocker.acquireSynchronizationObject(&address, LOCK_TIMEOUT); if(lockAcquired) { try { // ... transport created during waiting in lock - transport - = (BlockingClientTCPTransport*)(_context->getTransportRegistry()->get( - "TCP", &address, priority)); - if(transport!=NULL) { + tt = context->getTransportRegistry()->get("TCP", &address, priority); + transport = std::tr1::static_pointer_cast(tt); + if(transport.get()) { errlogSevPrintf(errlogInfo, - "Reusing existing connection to CA server: %s", - ipAddrStr); - if(transport->acquire(client)) return transport; + "Reusing existing connection to CA server: %s", + ipAddrStr); + if (transport->acquire(client)) + return transport; } - - errlogSevPrintf(errlogInfo, "Connecting to CA server: %s", - ipAddrStr); + + errlogSevPrintf(errlogInfo, "Connecting to CA server: %s", ipAddrStr); socket = tryConnect(address, 3); + // verify if(socket==INVALID_SOCKET) { errlogSevPrintf(errlogMajor, "Connection to CA server %s failed.", ipAddrStr); ostringstream temp; - temp<<"Failed to verify TCP connection to '"<waitUntilVerified(3.0)) { @@ -150,25 +144,31 @@ namespace epics { "Connection to CA server %s failed to be validated, closing it.", ipAddrStr); ostringstream temp; - temp<<"Failed to verify TCP connection to '"<close(true); else if(socket!=INVALID_SOCKET) epicsSocketDestroy(socket); - _namedLocker->releaseSynchronizationObject(&address); + _namedLocker.releaseSynchronizationObject(&address); + throw; + } catch(...) { + if(transport.get()) + transport->close(true); + else if(socket!=INVALID_SOCKET) epicsSocketDestroy(socket); + _namedLocker.releaseSynchronizationObject(&address); throw; } - _namedLocker->releaseSynchronizationObject(&address); } else { ostringstream temp; diff --git a/pvAccessApp/remote/blockingTCPTransport.cpp b/pvAccessApp/remote/blockingTCPTransport.cpp index bd29841..52da8b4 100644 --- a/pvAccessApp/remote/blockingTCPTransport.cpp +++ b/pvAccessApp/remote/blockingTCPTransport.cpp @@ -6,9 +6,9 @@ */ #include "blockingTCP.h" -#include "inetAddressUtil.h" -#include "growingCircularBuffer.h" -#include "caConstants.h" +#include +#include +#include /* pvData */ #include @@ -37,6 +37,7 @@ using std::ostringstream; namespace epics { namespace pvAccess { + /* class MonitorSender : public TransportSender, public NoDefaultMethods { public: MonitorSender(Mutex* monitorMutex, GrowingCircularBuffer< @@ -67,49 +68,67 @@ namespace epics { Mutex* _monitorMutex; GrowingCircularBuffer* _monitorSendQueue; }; + */ - BlockingTCPTransport::BlockingTCPTransport(Context* context, - SOCKET channel, ResponseHandler* responseHandler, + PVDATA_REFCOUNT_MONITOR_DEFINE(blockingTCPTransport); + + BlockingTCPTransport::BlockingTCPTransport(Context::shared_pointer& context, + SOCKET channel, auto_ptr& responseHandler, int receiveBufferSize, int16 priority) : - _closed(false), _channel(channel), + _channel(channel), + _priority(priority), + _responseHandler(responseHandler), + _markerPeriodBytes(MARKER_PERIOD), + _flushStrategy(DELAYED), + _rcvThreadId(0), + _sendThreadId(0), + //_monitorSender(new MonitorSender(&_monitorMutex,_monitorSendQueue)), + _context(context), + _autoDelete(true), _remoteTransportRevision(0), _remoteTransportReceiveBufferSize(MAX_TCP_RECV), _remoteTransportSocketReceiveBufferSize(MAX_TCP_RECV), - _priority(priority), _responseHandler(responseHandler), - _totalBytesReceived(0), _totalBytesSent(0), - _markerToSend(0), _verified(false), _remoteBufferFreeSpace( - LONG_LONG_MAX), _autoDelete(true), - _markerPeriodBytes(MARKER_PERIOD), _nextMarkerPosition( - _markerPeriodBytes), _sendPending(false), - _lastMessageStartPosition(0), _stage(READ_FROM_SOCKET), - _lastSegmentedMessageType(0), _lastSegmentedMessageCommand( - 0), _storedPayloadSize(0), _storedPosition(0), - _storedLimit(0), _magicAndVersion(0), _packetType(0), - _command(0), _payloadSize(0), _flushRequested(false), - _sendBufferSentPosition(0), _flushStrategy(DELAYED), - _sendQueue( - new GrowingCircularBuffer (100)), - _rcvThreadId(NULL), _sendThreadId(NULL), _monitorSendQueue( - new GrowingCircularBuffer (100)), - _monitorSender(new MonitorSender(&_monitorMutex, - _monitorSendQueue)), _context(context), - _sendThreadExited(false) { + _sendQueue(), + //_monitorSendQueue(), + _nextMarkerPosition(_markerPeriodBytes), + _sendPending(false), + _lastMessageStartPosition(0), + _lastSegmentedMessageType(0), + _lastSegmentedMessageCommand(0), + _flushRequested(false), + _sendBufferSentPosition(0), + _storedPayloadSize(0), + _storedPosition(0), + _storedLimit(0), + _magicAndVersion(0), + _packetType(0), + _command(0), + _payloadSize(0), + _stage(READ_FROM_SOCKET), + _totalBytesReceived(0), + _closed(false), + _sendThreadExited(false), + _verified(false), + _markerToSend(0), + _totalBytesSent(0), + _remoteBufferFreeSpace(LONG_LONG_MAX) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(blockingTCPTransport); - _socketBuffer = new ByteBuffer(max(MAX_TCP_RECV - +MAX_ENSURE_DATA_BUFFER_SIZE, receiveBufferSize), EPICS_ENDIAN_BIG); + // TODO minor tweak: deque size is not preallocated... + + _socketBuffer = new ByteBuffer(max(MAX_TCP_RECV+MAX_ENSURE_DATA_BUFFER_SIZE, receiveBufferSize), EPICS_ENDIAN_BIG); _socketBuffer->setPosition(_socketBuffer->getLimit()); _startPosition = _socketBuffer->getPosition(); // allocate buffer _sendBuffer = new ByteBuffer(_socketBuffer->getSize(), EPICS_ENDIAN_BIG); - _maxPayloadSize = _sendBuffer->getSize()-2*CA_MESSAGE_HEADER_SIZE; // one for header, one for flow control + _maxPayloadSize = _sendBuffer->getSize() - 2*CA_MESSAGE_HEADER_SIZE; // one for header, one for flow control // get send buffer size - socklen_t intLen = sizeof(int); - int retval = getsockopt(_channel, SOL_SOCKET, SO_SNDBUF, - &_socketSendBufferSize, &intLen); + int retval = getsockopt(_channel, SOL_SOCKET, SO_SNDBUF, &_socketSendBufferSize, &intLen); if(retval<0) { _socketSendBufferSize = MAX_TCP_RECV; errlogSevPrintf(errlogMinor, @@ -121,74 +140,64 @@ namespace epics { retval = getpeername(_channel, &(_socketAddress.sa), &saSize); if(retval<0) { errlogSevPrintf(errlogMajor, - "Error fetching socket remote address: %s", strerror( - errno)); + "Error fetching socket remote address: %s", + strerror(errno)); } // prepare buffer clearAndReleaseBuffer(); - - // add to registry - _context->acquire(); - _context->getTransportRegistry()->put(this); } BlockingTCPTransport::~BlockingTCPTransport() { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(blockingTCPTransport); + close(true); - TransportSender* sender; - while ((sender = _monitorSendQueue->extract())) - sender->release(); - delete _monitorSendQueue; - - while ((sender = _sendQueue->extract())) - sender->release(); - delete _sendQueue; - - delete _monitorSender; - - delete _socketBuffer; delete _sendBuffer; - - delete _responseHandler; - - _context->release(); } + // TODO consider epics::pvData::Thread void BlockingTCPTransport::start() { - // TODO consuder epics::pvData::Thread - - String threadName = "TCP-receive "+inetAddressToString( - _socketAddress); + // TODO this was in constructor + // add to registry + Transport::shared_pointer thisSharedPtr = shared_from_this(); + _context->getTransportRegistry()->put(thisSharedPtr); - errlogSevPrintf(errlogInfo, "Starting thread: %s", - threadName.c_str()); + + String socketAddressString = inetAddressToString(_socketAddress); + + // + // start receive thread + // + + String threadName = "TCP-receive " + socketAddressString; + errlogSevPrintf(errlogInfo, "Starting thread: %s", threadName.c_str()); _rcvThreadId = epicsThreadCreate(threadName.c_str(), - epicsThreadPriorityMedium, epicsThreadGetStackSize( - epicsThreadStackMedium), + epicsThreadPriorityMedium, + epicsThreadGetStackSize(epicsThreadStackMedium), BlockingTCPTransport::rcvThreadRunner, this); - threadName = "TCP-send "+inetAddressToString(_socketAddress); + // + // start send thread + // - errlogSevPrintf(errlogInfo, "Starting thread: %s", - threadName.c_str()); + threadName = "TCP-send " + socketAddressString; + errlogSevPrintf(errlogInfo, "Starting thread: %s",threadName.c_str()); _sendThreadId = epicsThreadCreate(threadName.c_str(), - epicsThreadPriorityMedium, epicsThreadGetStackSize( - epicsThreadStackMedium), + epicsThreadPriorityMedium, + epicsThreadGetStackSize(epicsThreadStackMedium), BlockingTCPTransport::sendThreadRunner, this); - } void BlockingTCPTransport::clearAndReleaseBuffer() { // NOTE: take care that nextMarkerPosition is set right // fix position to be correct when buffer is cleared // do not include pre-buffered flow control message; not 100% correct, but OK - _nextMarkerPosition -= _sendBuffer->getPosition() - -CA_MESSAGE_HEADER_SIZE; + _nextMarkerPosition -= _sendBuffer->getPosition() - CA_MESSAGE_HEADER_SIZE; _sendQueueMutex.lock(); _flushRequested = false; @@ -214,7 +223,8 @@ namespace epics { _closed = true; // remove from registry - _context->getTransportRegistry()->remove(this); + Transport::shared_pointer thisSharedPtr = shared_from_this(); + _context->getTransportRegistry()->remove(thisSharedPtr); // clean resources internalClose(force); @@ -239,33 +249,17 @@ namespace epics { int sockBufSize; socklen_t intLen = sizeof(int); - int retval = getsockopt(_channel, SOL_SOCKET, SO_RCVBUF, - &sockBufSize, &intLen); - if(retval<0) errlogSevPrintf(errlogMajor, - "Socket getsockopt SO_RCVBUF error: %s", strerror(errno)); + int retval = getsockopt(_channel, SOL_SOCKET, SO_RCVBUF,&sockBufSize, &intLen); + if(retval<0) + errlogSevPrintf(errlogMajor, + "Socket getsockopt SO_RCVBUF error: %s", + strerror(errno)); return sockBufSize; } - // TODO reimplement using Event bool BlockingTCPTransport::waitUntilVerified(double timeout) { - double internalTimeout = timeout; - bool internalVerified = false; - - _verifiedMutex.lock(); - internalVerified = _verified; - _verifiedMutex.unlock(); - - while(!internalVerified&&internalTimeout>0) { - epicsThreadSleep(min(0.1, internalTimeout)); - internalTimeout -= 0.1; - - _verifiedMutex.lock(); - internalVerified = _verified; - _verifiedMutex.unlock(); - } - - return internalVerified; + return _verifiedEvent.wait(timeout); } void BlockingTCPTransport::flush(bool lastMessageCompleted) { @@ -291,15 +285,14 @@ namespace epics { _lastSegmentedMessageCommand, 0); } - void BlockingTCPTransport::startMessage(int8 command, - int ensureCapacity) { + void BlockingTCPTransport::startMessage(int8 command, int ensureCapacity) { _lastMessageStartPosition = -1; ensureBuffer(CA_MESSAGE_HEADER_SIZE+ensureCapacity); _lastMessageStartPosition = _sendBuffer->getPosition(); _sendBuffer->putShort(CA_MAGIC_AND_VERSION); _sendBuffer->putByte(_lastSegmentedMessageType); // data - _sendBuffer->putByte(command); // command - _sendBuffer->putInt(0); // temporary zero payload + _sendBuffer->putByte(command); // command + _sendBuffer->putInt(0); // temporary zero payload } @@ -586,16 +579,14 @@ namespace epics { _socketBuffer->setLimit(min(_storedPosition+_storedPayloadSize, _storedLimit)); try { // handle response + Transport::shared_pointer thisPointer = shared_from_this(); _responseHandler->handleResponse(&_socketAddress, - this, version, _command, _payloadSize, + thisPointer, version, _command, _payloadSize, _socketBuffer); } catch(...) { //noop // TODO print? } - /* - * Java finally start - */ _socketBuffer->setLimit(_storedLimit); int newPosition = _storedPosition+_storedPayloadSize; if(newPosition>_storedLimit) { @@ -606,9 +597,6 @@ namespace epics { } _socketBuffer->setPosition(newPosition); // TODO discard all possible segments?!!! - /* - * Java finally end - */ _stage = PROCESS_HEADER; @@ -757,27 +745,25 @@ namespace epics { return true; } - TransportSender* BlockingTCPTransport::extractFromSendQueue() { - TransportSender* retval; - - _sendQueueMutex.lock(); - retval = _sendQueue->extract(); - _sendQueueMutex.unlock(); - - return retval; - } - void BlockingTCPTransport::processSendQueue() { // TODO sync _closed while(!_closed) { - TransportSender* sender; - sender = extractFromSendQueue(); + _sendQueueMutex.lock(); + // TODO optimize + TransportSender::shared_pointer sender; + if (!_sendQueue.empty()) + { + sender = _sendQueue.front(); + _sendQueue.pop_front(); + } + _sendQueueMutex.unlock(); + // wait for new message - while(sender==NULL&&!_flushRequested&&!_closed) { + while(sender.get()==0&&!_flushRequested&&!_closed) { if(_flushStrategy==DELAYED) { if(_delay>0) epicsThreadSleep(_delay); - if(_sendQueue->size()==0) { + if(_sendQueue.empty()) { // if (hasMonitors || sendBuffer.position() > CAConstants.CA_MESSAGE_HEADER_SIZE) if(_sendBuffer->getPosition()>CA_MESSAGE_HEADER_SIZE) _flushRequested = true; @@ -787,7 +773,16 @@ namespace epics { } else _sendQueueEvent.wait(); - sender = extractFromSendQueue(); + + _sendQueueMutex.lock(); + if (!_sendQueue.empty()) + { + sender = _sendQueue.front(); + _sendQueue.pop_front(); + } + else + sender.reset(); + _sendQueueMutex.unlock(); } // always do flush from this thread @@ -802,7 +797,7 @@ namespace epics { flush(); } - if(sender!=NULL) { + if(sender.get()) { sender->lock(); try { _lastMessageStartPosition = _sendBuffer->getPosition(); @@ -820,7 +815,6 @@ namespace epics { _sendBuffer->setPosition(_lastMessageStartPosition); } sender->unlock(); - sender->release(); } // if(sender!=NULL) } // while(!_closed) } @@ -843,6 +837,7 @@ namespace epics { void BlockingTCPTransport::rcvThreadRunner(void* param) { BlockingTCPTransport* obj = (BlockingTCPTransport*)param; + Transport::shared_pointer ptr = obj->shared_from_this(); // hold reference try{ obj->processReadCached(false, NONE, CA_MESSAGE_HEADER_SIZE, false); @@ -850,6 +845,7 @@ try{ printf("rcvThreadRunnner exception\n"); } + /* if(obj->_autoDelete) { while(true) { @@ -863,12 +859,16 @@ printf("rcvThreadRunnner exception\n"); } delete obj; } + */ } void BlockingTCPTransport::sendThreadRunner(void* param) { BlockingTCPTransport* obj = (BlockingTCPTransport*)param; + Transport::shared_pointer ptr = obj->shared_from_this(); // hold reference try { obj->processSendQueue(); +} catch (std::exception& ex) { + printf("sendThreadRunnner exception %s\n", ex.what()); } catch (...) { printf("sendThreadRunnner exception\n"); } @@ -881,21 +881,21 @@ printf("sendThreadRunnner exception\n"); obj->_mutex.unlock(); } - void BlockingTCPTransport::enqueueSendRequest(TransportSender* sender) { + void BlockingTCPTransport::enqueueSendRequest(TransportSender::shared_pointer& sender) { Lock lock(_sendQueueMutex); if(_closed) return; - sender->acquire(); - _sendQueue->insert(sender); + _sendQueue.push_back(sender); _sendQueueEvent.signal(); } - void BlockingTCPTransport::enqueueMonitorSendRequest(TransportSender* sender) { + /* + void BlockingTCPTransport::enqueueMonitorSendRequest(TransportSender::shared_pointer sender) { Lock lock(_monitorMutex); if(_closed) return; - sender->acquire(); - _monitorSendQueue->insert(sender); - if(_monitorSendQueue->size()==1) enqueueSendRequest(_monitorSender); + _monitorSendQueue.insert(sender); + if(_monitorSendQueue.size()==1) enqueueSendRequest(_monitorSender); } + void MonitorSender::send(ByteBuffer* buffer, TransportSendControl* control) { control->startMessage(19, 0); @@ -911,13 +911,13 @@ printf("sendThreadRunnner exception\n"); if(sender==NULL) { control->ensureBuffer(sizeof(int32)); - buffer->putInt(CAJ_INVALID_IOID); + buffer->putInt(INVALID_IOID); break; } sender->send(buffer, control); sender->release(); } } - +*/ } } diff --git a/pvAccessApp/remote/blockingUDP.h b/pvAccessApp/remote/blockingUDP.h index 3173576..189d5bd 100644 --- a/pvAccessApp/remote/blockingUDP.h +++ b/pvAccessApp/remote/blockingUDP.h @@ -29,11 +29,27 @@ namespace epics { class BlockingUDPTransport : public epics::pvData::NoDefaultMethods, public Transport, - public TransportSendControl { + public TransportSendControl, + public std::tr1::enable_shared_from_this + { public: - BlockingUDPTransport(ResponseHandler* responseHandler, + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + private: + BlockingUDPTransport(std::auto_ptr& responseHandler, + SOCKET channel, osiSockAddr& bindAddress, + short remoteTransportRevision); + public: + static BlockingUDPTransport::shared_pointer create(std::auto_ptr& responseHandler, SOCKET channel, osiSockAddr& bindAddress, - short remoteTransportRevision); + short remoteTransportRevision) + { + BlockingUDPTransport::shared_pointer thisPointer( + new BlockingUDPTransport(responseHandler, channel, bindAddress, remoteTransportRevision) + ); + return thisPointer; + } virtual ~BlockingUDPTransport(); @@ -43,6 +59,7 @@ namespace epics { } virtual const osiSockAddr* getRemoteAddress() const { + // always connected return &_bindAddress; } @@ -90,7 +107,7 @@ namespace epics { // noop } - virtual void enqueueSendRequest(TransportSender* sender); + virtual void enqueueSendRequest(TransportSender::shared_pointer& sender); void start(); @@ -190,14 +207,14 @@ namespace epics { /** * Response handler. */ - ResponseHandler* _responseHandler; + std::auto_ptr _responseHandler; virtual void processRead(); + private: static void threadRunner(void* param); - bool processBuffer(osiSockAddr& fromAddress, - epics::pvData::ByteBuffer* receiveBuffer); + bool processBuffer(Transport::shared_pointer& transport, osiSockAddr& fromAddress, epics::pvData::ByteBuffer* receiveBuffer); void close(bool forced, bool waitForThreadToComplete); @@ -276,8 +293,8 @@ namespace epics { /** * NOTE: transport client is ignored for broadcast (UDP). */ - virtual Transport* connect(TransportClient* client, - ResponseHandler* responseHandler, osiSockAddr& bindAddress, + virtual Transport::shared_pointer connect(TransportClient::shared_pointer& client, + std::auto_ptr& responseHandler, osiSockAddr& bindAddress, short transportRevision, int16 priority); private: diff --git a/pvAccessApp/remote/blockingUDPConnector.cpp b/pvAccessApp/remote/blockingUDPConnector.cpp index 629df10..722b301 100644 --- a/pvAccessApp/remote/blockingUDPConnector.cpp +++ b/pvAccessApp/remote/blockingUDPConnector.cpp @@ -17,11 +17,13 @@ #include #include +using namespace std; + namespace epics { namespace pvAccess { - Transport* BlockingUDPConnector::connect(TransportClient* client, - ResponseHandler* responseHandler, osiSockAddr& bindAddress, + Transport::shared_pointer BlockingUDPConnector::connect(TransportClient::shared_pointer& client, + auto_ptr& responseHandler, osiSockAddr& bindAddress, short transportRevision, int16 priority) { errlogSevPrintf(errlogInfo, "Creating datagram socket to: %s", @@ -32,7 +34,7 @@ namespace epics { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); errlogSevPrintf(errlogMajor, "Error creating socket: %s", errStr); - return 0; + return Transport::shared_pointer(); } int optval = _broadcast ? 1 : 0; @@ -41,7 +43,7 @@ namespace epics { { errlogSevPrintf(errlogMajor, "Error setting SO_BROADCAST: %s", strerror(errno)); epicsSocketDestroy (socket); - return 0; + return Transport::shared_pointer(); } // set SO_REUSEADDR or SO_REUSEPORT, OS dependant @@ -52,11 +54,12 @@ namespace epics { if(retval<0) { errlogSevPrintf(errlogMajor, "Error binding socket: %s", strerror(errno)); epicsSocketDestroy (socket); - return 0; + return Transport::shared_pointer(); } // sockets are blocking by default - return new BlockingUDPTransport(responseHandler, socket, bindAddress, transportRevision); + Transport::shared_pointer transport = BlockingUDPTransport::create(responseHandler, socket, bindAddress, transportRevision); + return transport; } } diff --git a/pvAccessApp/remote/blockingUDPTransport.cpp b/pvAccessApp/remote/blockingUDPTransport.cpp index 1889580..a3f375a 100644 --- a/pvAccessApp/remote/blockingUDPTransport.cpp +++ b/pvAccessApp/remote/blockingUDPTransport.cpp @@ -7,12 +7,13 @@ /* pvAccess */ #include "blockingUDP.h" -#include "caConstants.h" -#include "inetAddressUtil.h" +#include +#include /* pvData */ #include #include +#include /* EPICSv3 */ #include @@ -26,13 +27,16 @@ #include #include +using namespace epics::pvData; +using namespace std; + namespace epics { namespace pvAccess { - using namespace epics::pvData; + PVDATA_REFCOUNT_MONITOR_DEFINE(blockingUDPTransport); BlockingUDPTransport::BlockingUDPTransport( - ResponseHandler* responseHandler, SOCKET channel, + auto_ptr& responseHandler, SOCKET channel, osiSockAddr& bindAddress, short remoteTransportRevision) : _closed(false), @@ -47,9 +51,12 @@ namespace epics { _lastMessageStartPosition(0), _threadId(0) { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(blockingUDPTransport); } BlockingUDPTransport::~BlockingUDPTransport() { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(blockingUDPTransport); + close(true); // close the socket and stop the thread. if (_sendAddresses) delete _sendAddresses; @@ -57,12 +64,11 @@ namespace epics { delete _receiveBuffer; delete _sendBuffer; - delete _responseHandler; } void BlockingUDPTransport::start() { - String threadName = "UDP-receive "+inetAddressToString(_bindAddress); + String threadName = "UDP-receive "+inetAddressToString(_bindAddress); errlogSevPrintf(errlogInfo, "Starting thread: %s",threadName.c_str()); _threadId = epicsThreadCreate(threadName.c_str(), @@ -93,7 +99,7 @@ namespace epics { _shutdownEvent.wait(); } - void BlockingUDPTransport::enqueueSendRequest(TransportSender* sender) { + void BlockingUDPTransport::enqueueSendRequest(TransportSender::shared_pointer& sender) { Lock lock(_sendMutex); _sendToEnabled = false; @@ -132,11 +138,13 @@ namespace epics { char _readBuffer[MAX_UDP_RECV]; osiSockAddr fromAddress; + Transport::shared_pointer thisTransport = shared_from_this(); try { bool closed; - while(!_closed) { + while(!_closed) + { _mutex.lock(); closed = _closed; @@ -161,10 +169,12 @@ namespace epics { if(_ignoredAddresses!=0) { for(size_t i = 0; i <_ignoredAddresses->size(); i++) - if(_ignoredAddresses->at(i).ia.sin_addr.s_addr - ==fromAddress.ia.sin_addr.s_addr) { - ignore = true; - break; + { + if(_ignoredAddresses->at(i).ia.sin_addr.s_addr==fromAddress.ia.sin_addr.s_addr) + { + ignore = true; + break; + } } } @@ -172,20 +182,19 @@ namespace epics { // TODO do not copy.... wrap the buffer!!! _receiveBuffer->put(_readBuffer, 0, bytesRead <_receiveBuffer->getRemaining() ? - bytesRead : - _receiveBuffer->getRemaining() + bytesRead : _receiveBuffer->getRemaining() ); _receiveBuffer->flip(); - processBuffer(fromAddress, _receiveBuffer); + processBuffer(thisTransport, fromAddress, _receiveBuffer); } } else { // 0 == socket remotely closed // log a 'recvfrom' error - if(!_closed && bytesRead==-1) errlogSevPrintf(errlogMajor, - "Socket recv error: %s", strerror(errno)); + if(!_closed && bytesRead==-1) + errlogSevPrintf(errlogMajor, "Socket recv error: %s", strerror(errno)); close(true, false); break; @@ -204,8 +213,7 @@ namespace epics { _shutdownEvent.signal(); } - bool BlockingUDPTransport::processBuffer(osiSockAddr& fromAddress, - ByteBuffer* receiveBuffer) { + bool BlockingUDPTransport::processBuffer(Transport::shared_pointer& thisTransport, osiSockAddr& fromAddress, ByteBuffer* receiveBuffer) { // handle response(s) while(receiveBuffer->getRemaining()>=CA_MESSAGE_HEADER_SIZE) { @@ -225,14 +233,13 @@ namespace epics { // command ID and paylaod int8 command = receiveBuffer->getByte(); int payloadSize = receiveBuffer->getInt(); - int nextRequestPosition = receiveBuffer->getPosition() - +payloadSize; + int nextRequestPosition = receiveBuffer->getPosition() + payloadSize; // payload size check if(nextRequestPosition>receiveBuffer->getLimit()) return false; // handle - _responseHandler->handleResponse(&fromAddress, this, + _responseHandler->handleResponse(&fromAddress, thisTransport, (int8)(magicAndVersion&0xFF), command, payloadSize, _receiveBuffer); @@ -244,8 +251,7 @@ namespace epics { return true; } - bool BlockingUDPTransport::send(ByteBuffer* buffer, - const osiSockAddr& address) { + bool BlockingUDPTransport::send(ByteBuffer* buffer, const osiSockAddr& address) { buffer->flip(); int retval = sendto(_channel, buffer->getArray(), @@ -268,8 +274,7 @@ namespace epics { buffer->getLimit(), 0, &(_sendAddresses->at(i).sa), sizeof(sockaddr)); { - if(retval<0) errlogSevPrintf(errlogMajor, - "Socket sendto error: %s", strerror(errno)); + if(retval<0) errlogSevPrintf(errlogMajor, "Socket sendto error: %s", strerror(errno)); return false; } } diff --git a/pvAccessApp/remote/channelSearchManager.cpp b/pvAccessApp/remote/channelSearchManager.cpp index 4545756..1f2c4ba 100644 --- a/pvAccessApp/remote/channelSearchManager.cpp +++ b/pvAccessApp/remote/channelSearchManager.cpp @@ -21,19 +21,19 @@ void BaseSearchInstance::initializeSearchInstance() void BaseSearchInstance::unsetListOwnership() { Lock guard(_mutex); - if (_owner != NULL) this->release(); + //if (_owner != NULL) this->release(); _owner = NULL; } -void BaseSearchInstance::addAndSetListOwnership(ArrayFIFO* newOwner, Mutex* ownerMutex, int32 index) +void BaseSearchInstance::addAndSetListOwnership(SearchInstance::List* newOwner, Mutex* ownerMutex, int32 index) { if(ownerMutex == NULL) THROW_BASE_EXCEPTION("Null owner mutex"); _ownerMutex = ownerMutex; Lock ownerGuard(*_ownerMutex); Lock guard(_mutex); - newOwner->push(this); - if (_owner == NULL) this->acquire(); // new owner + newOwner->push_back(this); + //if (_owner == NULL) this->acquire(); // new owner _owner = newOwner; _ownerIndex = index; } @@ -47,8 +47,14 @@ void BaseSearchInstance::removeAndUnsetListOwnership() Lock guard(_mutex); if(_owner != NULL) { - this->release(); - _owner->remove(this); + //this->release(); + // TODO !!! + for (SearchInstance::List::iterator iter = _owner->begin(); iter != _owner->end(); iter++) + if (*iter == this) + { + _owner->erase(iter); + break; + } _owner = NULL; } } @@ -65,10 +71,12 @@ bool BaseSearchInstance::generateSearchRequestMessage(ByteBuffer* requestMessage int16 dataCount = requestMessage->getShort(DATA_COUNT_POSITION); dataCount++; + /* if(dataCount >= MAX_SEARCH_BATCH_COUNT) { return false; } + */ const String name = getSearchInstanceName(); // not nice... @@ -100,8 +108,8 @@ SearchTimer::SearchTimer(ChannelSearchManager* _chanSearchManager, int32 timerIn _timerIndex(timerIndex), _allowBoost(allowBoost), _allowSlowdown(allowSlowdown), - _requestPendingChannels(new ArrayFIFO), - _responsePendingChannels(new ArrayFIFO), + _requestPendingChannels(new SearchInstance::List()), + _responsePendingChannels(new SearchInstance::List()), _timerNode(new TimerNode(*this)), _canceled(false), _timeAtResponseCheck(0) @@ -141,7 +149,7 @@ void SearchTimer::installChannel(SearchInstance* channel) if(_canceled) return; Lock pendingChannelGuard(_requestPendingChannelsMutex); - bool startImmediately = _requestPendingChannels->isEmpty(); + bool startImmediately = _requestPendingChannels->empty(); channel->addAndSetListOwnership(_requestPendingChannels, &_requestPendingChannelsMutex, _timerIndex); // start searching @@ -163,9 +171,11 @@ void SearchTimer::installChannel(SearchInstance* channel) void SearchTimer::moveChannels(SearchTimer* destination) { // do not sync this, not necessary and might cause deadlock - SearchInstance* channel; - while((channel = _responsePendingChannels->pop()) != NULL) + while(!_responsePendingChannels->empty()) { + SearchInstance* channel = _responsePendingChannels->front(); + _responsePendingChannels->pop_front(); + { Lock guard(_volMutex); if(_searchAttempts > 0) @@ -178,9 +188,12 @@ void SearchTimer::moveChannels(SearchTimer* destination) // bulk move Lock guard(_requestPendingChannelsMutex); - while (!_requestPendingChannels->isEmpty()) + while (!_requestPendingChannels->empty()) { - destination->installChannel(_requestPendingChannels->pop()); + SearchInstance* channel = _requestPendingChannels->front(); + _requestPendingChannels->pop_front(); + + destination->installChannel(channel); } } @@ -206,19 +219,19 @@ void SearchTimer::callback() if(_allowBoost && searchRespones > 0) { Lock guard(_requestPendingChannelsMutex); - while(!_requestPendingChannels->isEmpty()) + while(!_requestPendingChannels->empty()) { - SearchInstance* channel = _requestPendingChannels->peek(); + SearchInstance* channel = _requestPendingChannels->front(); // boost needed check //final int boostIndex = searchRespones >= searchAttempts * SUCCESS_RATE ? Math.min(Math.max(0, timerIndex - 1), beaconAnomalyTimerIndex) : beaconAnomalyTimerIndex; const int boostIndex = _chanSearchManager->_beaconAnomalyTimerIndex; if(channel->getOwnerIndex() > boostIndex) { - _requestPendingChannels->pop(); - channel->acquire(); + _requestPendingChannels->pop_front(); + //channel->acquire(); channel->unsetListOwnership(); _chanSearchManager->boostSearching(channel, boostIndex); - channel->release(); + //channel->release(); } } } @@ -234,14 +247,17 @@ void SearchTimer::callback() _timeAtResponseCheck = now; // notify about timeout (move it to other timer) - while((channel = _responsePendingChannels->pop()) != NULL) + while(!_responsePendingChannels->empty()) { + channel = _responsePendingChannels->front(); + _responsePendingChannels->pop_front(); + if(_allowSlowdown) { - channel->acquire(); + //channel->acquire(); channel->unsetListOwnership(); _chanSearchManager->searchResponseTimeout(channel, _timerIndex); - channel->release(); + //channel->release(); } else { @@ -306,11 +322,17 @@ void SearchTimer::callback() { Lock guard(_requestPendingChannelsMutex); - channel = _requestPendingChannels->pop(); + if (_requestPendingChannels->empty()) + channel = 0; + else { + channel = _requestPendingChannels->front(); + _requestPendingChannels->pop_front(); + } + } while (!canceled && channel != NULL) { - channel->acquire(); + //channel->acquire(); channel->unsetListOwnership(); bool requestSent = true; @@ -345,7 +367,7 @@ void SearchTimer::callback() } } - channel->release(); + //channel->release(); // limit if(triesInFrame == 0 && !allowNewFrame) break; @@ -357,7 +379,12 @@ void SearchTimer::callback() { Lock guard(_requestPendingChannelsMutex); - channel = _requestPendingChannels->pop(); + if (_requestPendingChannels->empty()) + channel = 0; + else { + channel = _requestPendingChannels->front(); + _requestPendingChannels->pop_front(); + } } } @@ -380,7 +407,7 @@ void SearchTimer::callback() Lock guard(_requestPendingChannelsMutex); if(!canceled && !_timerNode->isScheduled()) { - bool someWorkToDo = (!_requestPendingChannels->isEmpty() || !_responsePendingChannels->isEmpty()); + bool someWorkToDo = (!_requestPendingChannels->empty() || !_responsePendingChannels->empty()); if(someWorkToDo) { _chanSearchManager->_context->getTimer()->scheduleAfterDelay(*_timerNode, period()/1000.0); @@ -546,7 +573,7 @@ void ChannelSearchManager::searchResponse(int32 cid, int32 seqNo, int8 minorRevi { si = _channelsIter->second; _channels.erase(_channelsIter); - si->acquire(); + //si->acquire(); si->removeAndUnsetListOwnership(); // report success @@ -557,17 +584,17 @@ void ChannelSearchManager::searchResponse(int32 cid, int32 seqNo, int8 minorRevi // then notify SearchInstance si->searchResponse(minorRevision, serverAddress); - si->release(); + //si->release(); } else { // minor hack to enable duplicate reports - si = dynamic_cast(_context->getChannel(cid)); + si = dynamic_cast(_context->getChannel(cid).get()); // TODO if(si != NULL) { - si->acquire(); // TODO not thread/destruction safe + //si->acquire(); // TODO not thread/destruction safe si->searchResponse(minorRevision, serverAddress); - si->release(); + //si->release(); } return; } @@ -611,7 +638,10 @@ void ChannelSearchManager::flushSendBuffer() TimeStamp now; now.getCurrent(); _timeAtLastSend = now.getMilliseconds(); - ((BlockingUDPTransport*)_context->getSearchTransport())->send(_sendBuffer); + + Transport::shared_pointer tt = _context->getSearchTransport(); + BlockingUDPTransport::shared_pointer ut = std::tr1::static_pointer_cast(tt); + ut->send(_sendBuffer); // TODO initializeSendBuffer(); } diff --git a/pvAccessApp/remote/channelSearchManager.h b/pvAccessApp/remote/channelSearchManager.h index 3973c4f..64024f4 100644 --- a/pvAccessApp/remote/channelSearchManager.h +++ b/pvAccessApp/remote/channelSearchManager.h @@ -7,7 +7,6 @@ #include "remote.h" #include "pvAccess.h" -#include "arrayFIFO.h" #include "caConstants.h" #include "blockingUDP.h" @@ -20,6 +19,8 @@ #include #include +#include + using namespace epics::pvData; namespace epics { namespace pvAccess { @@ -29,8 +30,11 @@ namespace epics { namespace pvAccess { /** * SearchInstance. */ -class SearchInstance : public ReferenceCountingInstance { +class SearchInstance { public: + + typedef std::deque List; + /** * Destructor */ @@ -61,7 +65,7 @@ public: * * @throws BaseException if the ownerMutex is NULL. */ - virtual void addAndSetListOwnership(ArrayFIFO* newOwner, Mutex* ownerMutex, int32 index) = 0; + virtual void addAndSetListOwnership(List* newOwner, Mutex* ownerMutex, int32 index) = 0; /** * Removes this search instance from the owner list and also removes the list as the owner of this * search instance. @@ -97,7 +101,7 @@ public: virtual pvAccessID getSearchInstanceID() = 0; virtual String getSearchInstanceName() = 0; virtual void unsetListOwnership(); - virtual void addAndSetListOwnership(ArrayFIFO* newOwner, Mutex* ownerMutex, int32 index); + virtual void addAndSetListOwnership(List* newOwner, Mutex* ownerMutex, int32 index); virtual void removeAndUnsetListOwnership(); virtual int32 getOwnerIndex(); /** @@ -107,7 +111,7 @@ public: virtual bool generateSearchRequestMessage(ByteBuffer* requestMessage, TransportSendControl* control); private: Mutex _mutex; - ArrayFIFO* _owner; + List* _owner; Mutex* _ownerMutex; int32 _ownerIndex; @@ -211,11 +215,13 @@ private: /** * Ordered (as inserted) list of channels with search request pending. */ - ArrayFIFO* _requestPendingChannels; + // TODO replace with stl::deque + SearchInstance::List* _requestPendingChannels; /** * Ordered (as inserted) list of channels with search request pending. */ - ArrayFIFO* _responsePendingChannels; + // TODO replace with stl::deque + SearchInstance::List* _responsePendingChannels; /** * Timer node. * (sync on requestPendingChannels) @@ -266,6 +272,9 @@ public: class ChannelSearchManager { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + /** * Constructor. * @param context diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index 89ba5f5..7dcf850 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -8,10 +8,9 @@ #ifndef REMOTE_H_ #define REMOTE_H_ -#include "caConstants.h" -#include "transportRegistry.h" +#include +#include #include "introspectionRegistry.h" -#include "configuration.h" #include #include @@ -19,6 +18,8 @@ #include #include +#include + #include #include @@ -27,10 +28,6 @@ namespace epics { class TransportRegistry; - enum ProtocolType { - TCP, UDP, SSL - }; - enum QoS { /** * Default behavior. @@ -72,51 +69,57 @@ namespace epics { typedef int32 pvAccessID; - enum MessageCommands { - CMD_BEACON = 0, CMD_CONNECTION_VALIDATION = 1, CMD_ECHO = 2, - CMD_SEARCH = 3, CMD_SEARCH_RESPONSE = 4, - CMD_INTROSPECTION_SEARCH = 5, CMD_CREATE_CHANNEL = 7, - CMD_DESTROY_CHANNEL = 8, CMD_GET = 10, CMD_PUT = 11, - CMD_PUT_GET = 12, CMD_MONITOR = 13, CMD_ARRAY = 14, - CMD_CANCEL_REQUEST = 15, CMD_PROCESS = 16, CMD_GET_FIELD = 17, - CMD_MESSAGE = 18, CMD_MULTIPLE_DATA = 19, CMD_RPC = 20, + enum MessageCommands { + CMD_BEACON = 0, + CMD_CONNECTION_VALIDATION = 1, + CMD_ECHO = 2, + CMD_SEARCH = 3, + CMD_SEARCH_RESPONSE = 4, + CMD_INTROSPECTION_SEARCH = 5, + CMD_INTROSPECTION_SEARCH_RESPONSE = 6, + CMD_CREATE_CHANNEL = 7, + CMD_DESTROY_CHANNEL = 8, + CMD_RESERVED0 = 9, + CMD_GET = 10, + CMD_PUT = 11, + CMD_PUT_GET = 12, + CMD_MONITOR = 13, + CMD_ARRAY = 14, + CMD_CANCEL_REQUEST = 15, + CMD_PROCESS = 16, + CMD_GET_FIELD = 17, + CMD_MESSAGE = 18, + CMD_MULTIPLE_DATA = 19, + CMD_RPC = 20 }; /** * Interface defining transport send control. - * @author Matej Sekoranja */ class TransportSendControl : public epics::pvData::SerializableControl { public: - virtual ~TransportSendControl() { - } + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + virtual ~TransportSendControl() {} - virtual void startMessage(int8 command, int ensureCapacity) =0; - virtual void endMessage() =0; + virtual void startMessage(int8 command, int ensureCapacity) = 0; + virtual void endMessage() = 0; - virtual void flush(bool lastMessageCompleted) =0; + virtual void flush(bool lastMessageCompleted) = 0; - virtual void setRecipient(const osiSockAddr& sendTo) =0; + virtual void setRecipient(const osiSockAddr& sendTo) = 0; }; - /** - * Reference counting instance. - */ - class ReferenceCountingInstance { - public: - virtual void acquire() =0; - virtual void release() =0; - }; - /** * Interface defining transport sender (instance sending data over transport). - * @author Matej Sekoranja - * @version $Id: TransportSender.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ - class TransportSender : virtual public ReferenceCountingInstance { + class TransportSender { public: - virtual ~TransportSender() { - } + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + virtual ~TransportSender() {} /** * Called by transport. @@ -126,40 +129,33 @@ namespace epics { * of this method. * NOTE: these limitations allows efficient implementation. */ - virtual void send(epics::pvData::ByteBuffer* buffer, - TransportSendControl* control) =0; + virtual void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) = 0; - virtual void lock() =0; - virtual void unlock() =0; + virtual void lock() = 0; + virtual void unlock() = 0; }; /** * Interface defining transport (connection). - * @author Matej Sekoranja - * @version $Id: Transport.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class Transport : public epics::pvData::DeserializableControl { public: - virtual ~Transport() { - } + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + virtual ~Transport() {} /** * Get remote address. - * @return remote address. + * @return remote address, can be null. */ - virtual const osiSockAddr* getRemoteAddress() const =0; + virtual const osiSockAddr* getRemoteAddress() const = 0; /** * Get protocol type (tcp, udp, ssl, etc.). * @return protocol type. */ - virtual const String getType() const =0; - - /** - * Get context transport is living in. - * @return context transport is living in. - */ - //public Context getContext(); + virtual const String getType() const = 0; /** * Transport protocol major revision. @@ -181,84 +177,82 @@ namespace epics { * Get receive buffer size. * @return receive buffer size. */ - virtual int getReceiveBufferSize() const =0; + virtual int getReceiveBufferSize() const = 0; /** * Get socket receive buffer size. * @return socket receive buffer size. */ - virtual int getSocketReceiveBufferSize() const =0; + virtual int getSocketReceiveBufferSize() const = 0; /** * Transport priority. * @return protocol priority. */ - virtual int16 getPriority() const =0; + virtual int16 getPriority() const = 0; /** * Set remote transport protocol minor revision. * @param minor protocol minor revision. */ - virtual void setRemoteMinorRevision(int8 minor) =0; + virtual void setRemoteMinorRevision(int8 minor) = 0; /** * Set remote transport receive buffer size. * @param receiveBufferSize receive buffer size. */ - virtual void setRemoteTransportReceiveBufferSize( - int receiveBufferSize) =0; + virtual void setRemoteTransportReceiveBufferSize(int receiveBufferSize) = 0; /** * Set remote transport socket receive buffer size. * @param socketReceiveBufferSize remote socket receive buffer size. */ - virtual void setRemoteTransportSocketReceiveBufferSize( - int socketReceiveBufferSize) =0; + virtual void setRemoteTransportSocketReceiveBufferSize(int socketReceiveBufferSize) = 0; /** * Notification transport that is still alive. */ - virtual void aliveNotification() =0; + virtual void aliveNotification() = 0; /** * Notification that transport has changed. */ - virtual void changedTransport() =0; + virtual void changedTransport() = 0; /** * Get introspection registry for transport. - * @return IntrospectionRegistry instance. + * @return IntrospectionRegistry instance, can be null. */ - virtual IntrospectionRegistry* getIntrospectionRegistry() =0; + virtual IntrospectionRegistry* getIntrospectionRegistry() = 0; /** * Close transport. * @param force flag indicating force-full (e.g. remote disconnect) close. */ - virtual void close(bool force) =0; + virtual void close(bool force) = 0; /** * Check connection status. * @return true if connected. */ - virtual bool isClosed() =0; + virtual bool isClosed() = 0; /** * Get transport verification status. * @return verification flag. */ - virtual bool isVerified() =0; + virtual bool isVerified() = 0; /** * Notify transport that it is has been verified. */ - virtual void verified() =0; + virtual void verified() = 0; /** * Enqueue send request. * @param sender */ - virtual void enqueueSendRequest(TransportSender* sender) =0; + virtual void enqueueSendRequest(TransportSender::shared_pointer& sender) = 0; }; @@ -267,37 +261,39 @@ namespace epics { /** * Not public IF, used by Transports, etc. */ - class Context : public ReferenceCountingInstance { + class Context { public: - virtual ~Context() { - } - /** - * Get timer. - * @return timer. - */ - virtual Timer* getTimer() = 0; + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + typedef std::tr1::weak_ptr weak_pointer; + typedef std::tr1::weak_ptr const_weak_pointer; - /** - * Get transport (virtual circuit) registry. - * @return transport (virtual circuit) registry. - */ - virtual TransportRegistry* getTransportRegistry() = 0; + virtual ~Context() {} - virtual Channel* getChannel(pvAccessID id) = 0; + virtual std::tr1::shared_ptr getChannel(pvAccessID id) = 0; + + virtual Transport::shared_pointer getSearchTransport() = 0; - virtual Transport* getSearchTransport() = 0; - - virtual Configuration* getConfiguration() = 0; + virtual Timer::shared_pointer getTimer() = 0; + + //virtual TransportRegistry::shared_pointer getTransportRegistry() = 0; + virtual std::tr1::shared_ptr getTransportRegistry() = 0; + + virtual Configuration::shared_pointer getConfiguration() = 0; + + virtual void beaconAnomalyNotify() = 0; + }; /** * Interface defining response handler. - * @author Matej Sekoranja - * @version $Id: ResponseHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class ResponseHandler { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + virtual ~ResponseHandler() {} /** @@ -311,15 +307,13 @@ namespace epics { * Code must not manipulate buffer. */ virtual void - handleResponse(osiSockAddr* responseFrom, Transport* transport, + handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, - epics::pvData::ByteBuffer* payloadBuffer) =0; + epics::pvData::ByteBuffer* payloadBuffer) = 0; }; /** * Base (abstract) channel access response handler. - * @author Matej Sekoranja - * @version $Id: AbstractResponseHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class AbstractResponseHandler : public ResponseHandler { public: @@ -331,12 +325,11 @@ namespace epics { _debug(context->getConfiguration()->getPropertyAsBoolean("PVACCESS_DEBUG", false)) { } - virtual ~AbstractResponseHandler() { - } + virtual ~AbstractResponseHandler() {} - virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); + virtual void handleResponse(osiSockAddr* responseFrom, Transport::shared_pointer& transport, + int8 version, int8 command, int payloadSize, + epics::pvData::ByteBuffer* payloadBuffer); protected: /** @@ -352,47 +345,50 @@ namespace epics { /** * Client (user) of the transport. - * @author Matej Sekoranja - * @version $Id: TransportClient.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ - class TransportClient : public ReferenceCountingInstance { + class TransportClient { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + typedef std::tr1::weak_ptr weak_pointer; + typedef std::tr1::weak_ptr const_weak_pointer; + virtual ~TransportClient() { } + + // ID used to allow fast/efficient lookup + virtual pvAccessID getID() = 0; /** * Notification of unresponsive transport (e.g. no heartbeat detected) . */ - virtual void transportUnresponsive() =0; + virtual void transportUnresponsive() = 0; /** * Notification of responsive transport (e.g. heartbeat detected again), * called to discard transportUnresponsive notification. * @param transport responsive transport. */ - virtual void transportResponsive(Transport* transport) =0; + virtual void transportResponsive(Transport::shared_pointer& transport) = 0; /** * Notification of network change (server restarted). */ - virtual void transportChanged() =0; + virtual void transportChanged() = 0; /** * Notification of forcefully closed transport. */ - virtual void transportClosed() =0; + virtual void transportClosed() = 0; }; /** * Interface defining socket connector (Connector-Transport pattern). - * @author Matej Sekoranja - * @version $Id: Connector.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class Connector { public: - virtual ~Connector() { - } + virtual ~Connector() {} /** * Connect. @@ -402,18 +398,15 @@ namespace epics { * @param[in] transportRevision transport revision to be used. * @param[in] priority process priority. * @return transport instance. - * @throws ConnectionException */ - virtual Transport* connect(TransportClient* client, - ResponseHandler* responseHandler, osiSockAddr& address, - short transportRevision, int16 priority) =0; + virtual Transport::shared_pointer connect(TransportClient::shared_pointer& client, + std::auto_ptr& responseHandler, osiSockAddr& address, + short transportRevision, int16 priority) = 0; }; /** * Interface defining reference counting transport IF. - * @author Matej Sekoranja - * @version $Id: ReferenceCountingTransport.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class ReferenceCountingTransport { public: @@ -425,103 +418,108 @@ namespace epics { * @param client client (channel) acquiring the transport * @return true if transport was granted, false otherwise. */ - virtual bool acquire(TransportClient* client) =0; + virtual bool acquire(TransportClient::shared_pointer& client) = 0; /** * Releases transport. * @param client client (channel) releasing the transport */ - virtual void release(TransportClient* client) =0; + virtual void release(pvAccessID clientId) = 0; + //virtual void release(TransportClient::shared_pointer& client) = 0; }; class ServerChannel { public: - virtual ~ServerChannel() { - } + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + virtual ~ServerChannel() {} /** * Get channel SID. * @return channel SID. */ - virtual pvAccessID getSID() =0; + virtual pvAccessID getSID() const = 0; /** * Destroy server channel. * This method MUST BE called if overriden. */ - virtual void destroy() =0; + virtual void destroy() = 0; }; /** - * Interface defining a transport that hosts channels. - * @author Matej Sekoranja - * @version $Id: ChannelHostingTransport.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ + * Interface defining a transport that hosts server channels. */ class ChannelHostingTransport { public: - virtual ~ChannelHostingTransport() { - } + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + virtual ~ChannelHostingTransport() {} /** * Get security token. * @return security token, can be null. */ - virtual epics::pvData::PVField* getSecurityToken() =0; + virtual epics::pvData::PVField::shared_pointer getSecurityToken() = 0; /** * Preallocate new channel SID. * @return new channel server id (SID). */ - virtual pvAccessID preallocateChannelSID() =0; + virtual pvAccessID preallocateChannelSID() = 0; /** * De-preallocate new channel SID. * @param sid preallocated channel SID. */ - virtual void depreallocateChannelSID(pvAccessID sid) =0; + virtual void depreallocateChannelSID(pvAccessID sid) = 0; /** * Register a new channel. * @param sid preallocated channel SID. * @param channel channel to register. */ - virtual void - registerChannel(pvAccessID sid, ServerChannel* channel) =0; + virtual void registerChannel(pvAccessID sid, ServerChannel::shared_pointer& channel) =0; /** * Unregister a new channel (and deallocates its handle). * @param sid SID */ - virtual void unregisterChannel(pvAccessID sid) =0; + virtual void unregisterChannel(pvAccessID sid) = 0; /** * Get channel by its SID. * @param sid channel SID * @return channel with given SID, null otherwise */ - virtual ServerChannel* getChannel(pvAccessID sid) =0; + virtual ServerChannel::shared_pointer getChannel(pvAccessID sid) = 0; /** * Get channel count. * @return channel count. */ - virtual int getChannelCount() =0; + virtual int getChannelCount() = 0; }; /** * A request that expects an response. * Responses identified by its I/O ID. - * This interface needs to be extended (to provide method called on response). - * @author Matej Sekoranja */ - class ResponseRequest : public ReferenceCountingInstance { + class ResponseRequest { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + typedef std::tr1::weak_ptr weak_pointer; + typedef std::tr1::weak_ptr const_weak_pointer; + virtual ~ResponseRequest() {} /** * Get I/O ID. * @return ioid */ - virtual pvAccessID getIOID() = 0; + virtual pvAccessID getIOID() const = 0; /** * Timeout notification. @@ -543,7 +541,7 @@ namespace epics { * Get request requester. * @return request requester. */ - virtual epics::pvData::Requester* getRequester() = 0; + virtual std::tr1::shared_ptr getRequester() = 0; }; /** @@ -552,6 +550,9 @@ namespace epics { */ class DataResponse : public ResponseRequest { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + virtual ~DataResponse() {} /** @@ -560,7 +561,7 @@ namespace epics { * @param version * @param payloadBuffer */ - virtual void response(Transport* transport, int8 version, ByteBuffer* payloadBuffer) = 0; + virtual void response(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer) = 0; }; @@ -573,6 +574,9 @@ namespace epics { */ class SubscriptionRequest /*: public ResponseRequest*/ { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + virtual ~SubscriptionRequest() {} /** @@ -584,7 +588,7 @@ namespace epics { * Rescubscribe (e.g. when server was restarted) * @param transport new transport to be used. */ - virtual void resubscribeSubscription(Transport* transport) = 0; + virtual void resubscribeSubscription(Transport::shared_pointer& transport) = 0; }; diff --git a/pvAccessApp/remoteClient/clientContextImpl.cpp b/pvAccessApp/remoteClient/clientContextImpl.cpp index 1834b0a..a930005 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.cpp +++ b/pvAccessApp/remoteClient/clientContextImpl.cpp @@ -28,6 +28,9 @@ #include #include +using std::tr1::dynamic_pointer_cast; +using std::tr1::static_pointer_cast; + using namespace epics::pvData; namespace epics { @@ -36,25 +39,37 @@ namespace epics { Status ChannelImpl::channelDestroyed = Status(Status::STATUSTYPE_WARNING, "channel destroyed"); Status ChannelImpl::channelDisconnected = Status(Status::STATUSTYPE_WARNING, "channel disconnected"); + String emptyString; // TODO consider std::unordered_map - typedef std::map IOIDResponseRequestMap; + typedef std::map IOIDResponseRequestMap; #define EXCEPTION_GUARD(code) try { code; } \ catch (std::exception &e) { errlogSevPrintf(errlogMajor, "Unhandled exception caught from client code at %s:%d: %s", __FILE__, __LINE__, e.what()); } \ catch (...) { errlogSevPrintf(errlogMajor, "Unhandled exception caught from client code at %s:%d.", __FILE__, __LINE__); } - class ResponseRequestGuard { - private: - ResponseRequest* m_rr; - public: - // no, don't be tempted to acquire here (must be done in getResponseRequest()) - ResponseRequestGuard(ResponseRequest* rr) : m_rr(rr) {}; - ~ResponseRequestGuard() { if (m_rr) m_rr->release(); }; - ResponseRequest* get() const { return m_rr; }; + struct delayed_destroyable_deleter + { + template void operator()(T * p) + { + try + { + // new owner, this also allows to use shared_from_this() in destroy() method + std::tr1::shared_ptr ptr(p); + ptr->destroy(); + } + catch(std::exception &ex) + { + printf("delayed_destroyable_deleter: unhandled exception: %s", ex.what()); + } + catch(...) + { + printf("delayed_destroyable_deleter: unhandled exception"); + } + } }; - + /** * Base channel request. * @author Matej Sekoranja @@ -63,15 +78,26 @@ namespace epics { public DataResponse, public SubscriptionRequest, public TransportSender, - public Destroyable { - protected: + public Destroyable, + public std::tr1::enable_shared_from_this + { + public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + static PVDataCreate* pvDataCreate; + + static Status notInitializedStatus; + static Status destroyedStatus; + static Status channelNotConnected; + static Status otherRequestPendingStatus; + static Status pvRequestNull; + + protected: - ChannelImpl* m_channel; - ClientContextImpl* m_context; + ChannelImpl::shared_pointer m_channel; - pvAccessID m_ioid; - - Requester* m_requester; + Requester::shared_pointer m_requester; bool m_destroyed; bool m_initialized; @@ -82,32 +108,31 @@ namespace epics { int32 m_pendingRequest; + pvAccessID m_ioid; + Mutex m_mutex; - int m_refCount; - - Status m_status; + // used to hold ownership until create is called (to support complete async usage) + ResponseRequest::shared_pointer m_thisPointer; virtual ~BaseRequestImpl() {}; - public: - - static PVDataCreate* pvDataCreate; - - static Status notInitializedStatus; - static Status destroyedStatus; - static Status channelNotConnected; - static Status otherRequestPendingStatus; - static Status pvRequestNull; - - BaseRequestImpl(ChannelImpl* channel, Requester* requester) : - m_channel(channel), m_context(channel->getContext()), - m_requester(requester), m_destroyed(false), m_initialized(false), - m_pendingRequest(NULL_REQUEST), m_refCount(1), m_status() + BaseRequestImpl(ChannelImpl::shared_pointer& channel, Requester::shared_pointer requester) : + m_channel(channel), + m_requester(requester), + m_destroyed(false), + m_initialized(false), + m_pendingRequest(NULL_REQUEST), + m_ioid(INVALID_IOID) { + } + + void activate() { // register response request - m_ioid = m_context->registerResponseRequest(this); - channel->registerResponseRequest(this); + // ResponseRequest::shared_pointer to this instance must already exist + m_thisPointer = shared_from_this(); + m_ioid = m_channel->getContext()->registerResponseRequest(m_thisPointer); + m_channel->registerResponseRequest(m_thisPointer); } bool startRequest(int32 qos) { @@ -130,23 +155,28 @@ namespace epics { Lock guard(m_mutex); return m_pendingRequest; } + + public: - Requester* getRequester() { + // used to send message to this request + Requester::shared_pointer getRequester() { return m_requester; } - pvAccessID getIOID() { + pvAccessID getIOID() const { return m_ioid; } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) = 0; - virtual void response(Transport* transport, int8 version, ByteBuffer* payloadBuffer) { + virtual void response(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer) { transport->ensureData(1); int8 qos = payloadBuffer->getByte(); - transport->getIntrospectionRegistry()->deserializeStatus(m_status, payloadBuffer, transport); + + Status m_status; + transport->getIntrospectionRegistry()->deserializeStatus(m_status, payloadBuffer, transport.get()); try { @@ -160,6 +190,10 @@ namespace epics { m_mutex.unlock(); } + // we are initialized now, release pointer + // this is safe since at least caller owns it + m_thisPointer.reset(); + initResponse(transport, version, payloadBuffer, qos, m_status); } else if (qos & QOS_DESTROY) @@ -197,8 +231,8 @@ namespace epics { } // unregister response request - m_context->unregisterResponseRequest(this); - m_channel->unregisterResponseRequest(this); + m_channel->getContext()->unregisterResponseRequest(m_ioid); + m_channel->unregisterResponseRequest(m_ioid); // destroy remote instance if (m_initialized) @@ -206,14 +240,16 @@ namespace epics { try { startRequest(PURE_DESTROY_REQUEST); - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (...) { // noop (do not complain if fails) } } - release(); + // in case this instance is destroyed uninitialized + m_thisPointer.reset(); } virtual void timeout() { @@ -244,9 +280,7 @@ namespace epics { return; else if (qos == PURE_DESTROY_REQUEST) { - control->startMessage((int8)15, 8); - // NOTE: reference to the channel that can be deleted - // however CHANNEL_DESTROY request to the server keeps it alive + control->startMessage((int8)CMD_CANCEL_REQUEST, 8); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); } @@ -257,31 +291,17 @@ namespace epics { // noop } - virtual void acquire() { - Lock guard(m_mutex); - m_refCount++; - } - - virtual void release() { - m_mutex.lock(); - m_refCount--; - m_mutex.unlock(); - if (m_refCount == 0) - delete this; - } - - }; - PVDataCreate* BaseRequestImpl::pvDataCreate = getPVDataCreate(); - - Status BaseRequestImpl::notInitializedStatus = Status(Status::STATUSTYPE_ERROR, "request not initialized"); - Status BaseRequestImpl::destroyedStatus = Status(Status::STATUSTYPE_ERROR, "request destroyed"); - Status BaseRequestImpl::channelNotConnected = Status(Status::STATUSTYPE_ERROR, "channel not connected"); - Status BaseRequestImpl::otherRequestPendingStatus = Status(Status::STATUSTYPE_ERROR, "other request pending"); - Status BaseRequestImpl::pvRequestNull = Status(Status::STATUSTYPE_ERROR, "pvRequest == 0"); + PVDataCreate* BaseRequestImpl::pvDataCreate = getPVDataCreate(); + + Status BaseRequestImpl::notInitializedStatus = Status(Status::STATUSTYPE_ERROR, "request not initialized"); + Status BaseRequestImpl::destroyedStatus = Status(Status::STATUSTYPE_ERROR, "request destroyed"); + Status BaseRequestImpl::channelNotConnected = Status(Status::STATUSTYPE_ERROR, "channel not connected"); + Status BaseRequestImpl::otherRequestPendingStatus = Status(Status::STATUSTYPE_ERROR, "other request pending"); + Status BaseRequestImpl::pvRequestNull = Status(Status::STATUSTYPE_ERROR, "pvRequest == 0"); @@ -291,37 +311,53 @@ namespace epics { PVDATA_REFCOUNT_MONITOR_DEFINE(channelProcess); - class ChannelProcessRequestImpl : public BaseRequestImpl, public ChannelProcess + class ChannelProcessRequestImpl : + public BaseRequestImpl, + public ChannelProcess { private: - ChannelProcessRequester* m_callback; - PVStructure* m_pvRequest; + ChannelProcessRequester::shared_pointer m_callback; + PVStructure::shared_pointer m_pvRequest; - private: - ~ChannelProcessRequestImpl() + ChannelProcessRequestImpl(ChannelImpl::shared_pointer& channel, ChannelProcessRequester::shared_pointer& callback, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(callback)), + m_callback(callback), + m_pvRequest(pvRequest) { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelProcess); - //if (m_pvRequest) delete m_pvRequest; + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelProcess); + } + + void activate() + { + BaseRequestImpl::activate(); + + // pvRequest can be null + + // TODO best-effort support + + try { + Transport::shared_pointer tp = m_channel->checkAndGetTransport(); + resubscribeSubscription(tp); + } catch (std::runtime_error &rte) { + ChannelProcess::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_callback->channelProcessConnect(channelNotConnected, thisPointer)); + } } public: - ChannelProcessRequestImpl(ChannelImpl* channel, ChannelProcessRequester* callback, PVStructure *pvRequest) : - BaseRequestImpl(channel, callback), - m_callback(callback), m_pvRequest(pvRequest) - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))) + static ChannelProcess::shared_pointer create(ChannelImpl::shared_pointer& channel, ChannelProcessRequester::shared_pointer& callback, PVStructure::shared_pointer& pvRequest) { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelProcess); - - // pvRequest can be null - - // TODO best-effort support - - // subscribe - try { - resubscribeSubscription(channel->checkAndGetTransport()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_callback->channelProcessConnect(channelNotConnected, 0)); - } + ChannelProcess::shared_pointer thisPointer( + new ChannelProcessRequestImpl(channel, callback, pvRequest), + delayed_destroyable_deleter() + ); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } + + ~ChannelProcessRequestImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelProcess); } virtual void send(ByteBuffer* buffer, TransportSendControl* control) { @@ -332,7 +368,7 @@ namespace epics { return; } - control->startMessage((int8)16, 9); + control->startMessage((int8)CMD_PROCESS, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); buffer->putByte((int8)m_pendingRequest); @@ -340,23 +376,24 @@ namespace epics { if (pendingRequest & QOS_INIT) { // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { EXCEPTION_GUARD(m_callback->processDone(status)); return true; } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { - EXCEPTION_GUARD(m_callback->channelProcessConnect(status, this)); + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + ChannelProcess::shared_pointer thisPtr = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_callback->channelProcessConnect(status, thisPtr)); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { EXCEPTION_GUARD(m_callback->processDone(status)); return true; } @@ -381,16 +418,18 @@ namespace epics { } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_callback->processDone(channelNotConnected)); } } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } virtual void destroy() @@ -407,50 +446,63 @@ namespace epics { PVDATA_REFCOUNT_MONITOR_DEFINE(channelGet); - class ChannelGetImpl : public BaseRequestImpl, public ChannelGet + class ChannelGetImpl : + public BaseRequestImpl, + public ChannelGet { private: - ChannelGetRequester* m_channelGetRequester; + ChannelGetRequester::shared_pointer m_channelGetRequester; - PVStructure* m_pvRequest; + PVStructure::shared_pointer m_pvRequest; - PVStructure* m_data; - BitSet* m_bitSet; + PVStructure::shared_pointer m_data; + BitSet::shared_pointer m_bitSet; - private: - ~ChannelGetImpl() + ChannelGetImpl(ChannelImpl::shared_pointer& channel, ChannelGetRequester::shared_pointer& channelGetRequester, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(channelGetRequester)), + m_channelGetRequester(channelGetRequester), m_pvRequest(pvRequest) { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelGet); - // synced by code calling this - if (m_data) delete m_data; - if (m_bitSet) delete m_bitSet; - //if (m_pvRequest) delete m_pvRequest; + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelGet); + } + + void activate() + { + BaseRequestImpl::activate(); + + if (m_pvRequest.get() == 0) + { + ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, thisPointer, nullPVStructure, nullBitSet)); + return; + } + + // TODO immediate get, i.e. get data with init message + // TODO one-time get, i.e. immediate get + lastRequest + + try { + Transport::shared_pointer transport = m_channel->checkAndGetTransport(); + resubscribeSubscription(transport); + } catch (std::runtime_error &rte) { + ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelNotConnected, thisPointer, nullPVStructure, nullBitSet)); + } } public: - ChannelGetImpl(ChannelImpl* channel, ChannelGetRequester* channelGetRequester, PVStructure *pvRequest) : - BaseRequestImpl(channel, channelGetRequester), - m_channelGetRequester(channelGetRequester), m_pvRequest(pvRequest), - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))), - m_data(0), m_bitSet(0) + static ChannelGet::shared_pointer create(ChannelImpl::shared_pointer& channel, ChannelGetRequester::shared_pointer& channelGetRequester, PVStructure::shared_pointer& pvRequest) { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelGet); - - if (pvRequest == 0) - { - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(pvRequestNull, 0, 0, 0)); - return; - } + ChannelGet::shared_pointer thisPointer(new ChannelGetImpl(channel, channelGetRequester, pvRequest), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } - // TODO immediate get, i.e. get data with init message - // TODO one-time get, i.e. immediate get + lastRequest - - // subscribe - try { - resubscribeSubscription(m_channel->checkAndGetTransport()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(channelNotConnected, 0, 0, 0)); - } + ~ChannelGetImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelGet); } virtual void send(ByteBuffer* buffer, TransportSendControl* control) { @@ -461,7 +513,7 @@ namespace epics { return; } - control->startMessage((int8)10, 9); + control->startMessage((int8)CMD_GET, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); buffer->putByte((int8)m_pendingRequest); @@ -469,36 +521,40 @@ namespace epics { if (pendingRequest & QOS_INIT) { // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { // data available if (qos & QOS_GET) return normalResponse(transport, version, payloadBuffer, qos, status); return true; } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, this, 0, 0)); + ChannelGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisPointer, nullPVStructure, nullBitSet)); return true; } // create data and its bitSet - m_data = transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport); - m_bitSet = new BitSet(m_data->getNumberFields()); + m_data.reset(transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get())); + m_bitSet.reset(new BitSet(m_data->getNumberFields())); // notify - EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, this, m_data, m_bitSet)); + ChannelGet::shared_pointer thisChannelGet = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_channelGetRequester->channelGetConnect(status, thisChannelGet, m_data, m_bitSet)); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { EXCEPTION_GUARD(m_channelGetRequester->getDone(status)); @@ -506,8 +562,8 @@ namespace epics { } // deserialize bitSet and data - m_bitSet->deserialize(payloadBuffer, transport); - m_data->deserialize(payloadBuffer, transport, m_bitSet); + m_bitSet->deserialize(payloadBuffer, transport.get()); + m_data->deserialize(payloadBuffer, transport.get(), m_bitSet.get()); EXCEPTION_GUARD(m_channelGetRequester->getDone(status)); return true; @@ -533,16 +589,18 @@ namespace epics { } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelGetRequester->getDone(channelNotConnected)); } } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } virtual void destroy() @@ -566,49 +624,60 @@ namespace epics { class ChannelPutImpl : public BaseRequestImpl, public ChannelPut { private: - ChannelPutRequester* m_channelPutRequester; + ChannelPutRequester::shared_pointer m_channelPutRequester; - PVStructure* m_pvRequest; + PVStructure::shared_pointer m_pvRequest; - PVStructure* m_data; - BitSet* m_bitSet; + PVStructure::shared_pointer m_data; + BitSet::shared_pointer m_bitSet; - private: - ~ChannelPutImpl() + ChannelPutImpl(ChannelImpl::shared_pointer& channel, ChannelPutRequester::shared_pointer& channelPutRequester, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(channelPutRequester)), + m_channelPutRequester(channelPutRequester), m_pvRequest(pvRequest) { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelPut); - // synced by code calling this - if (m_data) delete m_data; - if (m_bitSet) delete m_bitSet; - //if (m_pvRequest) delete m_pvRequest; + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelPut); + } + + void activate() + { + BaseRequestImpl::activate(); + + if (m_pvRequest.get() == 0) + { + ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, thisPointer, nullPVStructure, nullBitSet)); + return; + } + + // TODO low-overhead put + // TODO best-effort put + + try { + Transport::shared_pointer transport = m_channel->checkAndGetTransport(); + resubscribeSubscription(transport); + } catch (std::runtime_error &rte) { + ChannelPut::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelNotConnected, thisPointer, nullPVStructure, nullBitSet)); + } } public: - ChannelPutImpl(ChannelImpl* channel, ChannelPutRequester* channelPutRequester, PVStructure *pvRequest) : - BaseRequestImpl(channel, channelPutRequester), - m_channelPutRequester(channelPutRequester), m_pvRequest(pvRequest), - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))), - m_data(0), m_bitSet(0) + static ChannelPut::shared_pointer create(ChannelImpl::shared_pointer& channel, ChannelPutRequester::shared_pointer& channelPutRequester, PVStructure::shared_pointer& pvRequest) { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelPut); - - if (pvRequest == 0) - { - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(pvRequestNull, 0, 0, 0)); - return; - } - - // TODO low-overhead put - // TODO best-effort put - - // subscribe - try { - resubscribeSubscription(m_channel->checkAndGetTransport()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(channelNotConnected, 0, 0, 0)); - } + ChannelPut::shared_pointer thisPointer(new ChannelPutImpl(channel, channelPutRequester, pvRequest), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; } + ~ChannelPutImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelPut); + } + virtual void send(ByteBuffer* buffer, TransportSendControl* control) { int32 pendingRequest = getPendingRequest(); if (pendingRequest < 0) @@ -617,7 +686,7 @@ namespace epics { return; } - control->startMessage((int8)11, 9); + control->startMessage((int8)CMD_PUT, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); buffer->putByte((int8)m_pendingRequest); @@ -625,41 +694,45 @@ namespace epics { if (pendingRequest & QOS_INIT) { // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } else if (!(pendingRequest & QOS_GET)) { // put // serialize only what has been changed m_bitSet->serialize(buffer, control); - m_data->serialize(buffer, control, m_bitSet); + m_data->serialize(buffer, control, m_bitSet.get()); } stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { EXCEPTION_GUARD(m_channelPutRequester->putDone(status)); return true; } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, this, 0, 0)); + ChannelPut::shared_pointer nullChannelPut; + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, nullChannelPut, nullPVStructure, nullBitSet)); return true; } // create data and its bitSet - m_data = transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport); - m_bitSet = new BitSet(m_data->getNumberFields()); + m_data.reset(transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get())); + m_bitSet.reset(new BitSet(m_data->getNumberFields())); // notify - EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, this, m_data, m_bitSet)); + ChannelPut::shared_pointer thisChannelPut = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_channelPutRequester->channelPutConnect(status, thisChannelPut, m_data, m_bitSet)); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (qos & QOS_GET) { if (!status.isSuccess()) @@ -668,7 +741,7 @@ namespace epics { return true; } - m_data->deserialize(payloadBuffer, transport); + m_data->deserialize(payloadBuffer, transport.get()); EXCEPTION_GUARD(m_channelPutRequester->getDone(status)); return true; @@ -701,7 +774,8 @@ namespace epics { try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutRequester->getDone(channelNotConnected)); @@ -728,16 +802,18 @@ namespace epics { } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutRequester->putDone(channelNotConnected)); } } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } virtual void destroy() @@ -758,47 +834,55 @@ namespace epics { class ChannelPutGetImpl : public BaseRequestImpl, public ChannelPutGet { private: - ChannelPutGetRequester* m_channelPutGetRequester; + ChannelPutGetRequester::shared_pointer m_channelPutGetRequester; - PVStructure* m_pvRequest; + PVStructure::shared_pointer m_pvRequest; - PVStructure* m_putData; - PVStructure* m_getData; + PVStructure::shared_pointer m_putData; + PVStructure::shared_pointer m_getData; + + ChannelPutGetImpl(ChannelImpl::shared_pointer& channel, ChannelPutGetRequester::shared_pointer& channelPutGetRequester, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(channelPutGetRequester)), + m_channelPutGetRequester(channelPutGetRequester), m_pvRequest(pvRequest) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelPutGet); + } + + void activate() + { + BaseRequestImpl::activate(); + + if (m_pvRequest.get() == 0) + { + ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, thisPointer, nullPVStructure, nullPVStructure)); + return; + } + + try { + Transport::shared_pointer transport = m_channel->checkAndGetTransport(); + resubscribeSubscription(transport); + } catch (std::runtime_error &rte) { + ChannelPutGet::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelNotConnected, thisPointer, nullPVStructure, nullPVStructure)); + } + } + + public: + static ChannelPutGet::shared_pointer create(ChannelImpl::shared_pointer& channel, ChannelPutGetRequester::shared_pointer& channelPutGetRequester, PVStructure::shared_pointer& pvRequest) + { + ChannelPutGet::shared_pointer thisPointer(new ChannelPutGetImpl(channel, channelPutGetRequester, pvRequest), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } - private: ~ChannelPutGetImpl() { PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelPutGet); - // synced by code calling this - if (m_putData) delete m_putData; - if (m_getData) delete m_getData; - //if (m_pvRequest) delete m_pvRequest; } - public: - ChannelPutGetImpl(ChannelImpl* channel, ChannelPutGetRequester* channelPutGetRequester, PVStructure *pvRequest) : - BaseRequestImpl(channel, channelPutGetRequester), - m_channelPutGetRequester(channelPutGetRequester), m_pvRequest(pvRequest), - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))), - m_putData(0), m_getData(0) - { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelPutGet); - - if (pvRequest == 0) - { - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(pvRequestNull, 0, 0, 0)); - return; - } - - // subscribe - try { - resubscribeSubscription(m_channel->checkAndGetTransport()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(channelNotConnected, 0, 0, 0)); - } - } - - virtual void send(ByteBuffer* buffer, TransportSendControl* control) { int32 pendingRequest = getPendingRequest(); if (pendingRequest < 0) @@ -807,7 +891,7 @@ namespace epics { return; } - control->startMessage((int8)12, 9); + control->startMessage((int8)CMD_PUT_GET, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); if ((pendingRequest & QOS_INIT) == 0) @@ -818,7 +902,7 @@ namespace epics { buffer->putByte((int8)QOS_INIT); // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } else if (pendingRequest & (QOS_GET | QOS_GET_PUT)) { // noop @@ -831,30 +915,33 @@ namespace epics { stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { // data available // TODO we need a flag here... return normalResponse(transport, version, payloadBuffer, qos, status); } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, this, 0, 0)); + ChannelPutGet::shared_pointer nullChannelPutGet; + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, nullChannelPutGet, nullPVStructure, nullPVStructure)); return true; } IntrospectionRegistry* registry = transport->getIntrospectionRegistry(); - m_putData = registry->deserializeStructureAndCreatePVStructure(payloadBuffer, transport); - m_getData = registry->deserializeStructureAndCreatePVStructure(payloadBuffer, transport); + m_putData.reset(registry->deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get())); + m_getData.reset(registry->deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get())); // notify - EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, this, m_putData, m_getData)); + ChannelPutGet::shared_pointer thisChannelPutGet = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_channelPutGetRequester->channelPutGetConnect(status, thisChannelPutGet, m_putData, m_getData)); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (qos & QOS_GET) { if (!status.isSuccess()) @@ -864,7 +951,7 @@ namespace epics { } // deserialize get data - m_getData->deserialize(payloadBuffer, transport); + m_getData->deserialize(payloadBuffer, transport.get()); EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(status)); return true; @@ -878,7 +965,7 @@ namespace epics { } // deserialize put data - m_putData->deserialize(payloadBuffer, transport); + m_putData->deserialize(payloadBuffer, transport.get()); EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(status)); return true; @@ -892,7 +979,7 @@ namespace epics { } // deserialize data - m_getData->deserialize(payloadBuffer, transport); + m_getData->deserialize(payloadBuffer, transport.get()); EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(status)); return true; @@ -919,7 +1006,8 @@ namespace epics { } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutGetRequester->putGetDone(channelNotConnected)); @@ -945,7 +1033,8 @@ namespace epics { } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutGetRequester->getGetDone(channelNotConnected)); @@ -971,16 +1060,18 @@ namespace epics { } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelPutGetRequester->getPutDone(channelNotConnected)); } } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } virtual void destroy() @@ -1003,44 +1094,56 @@ namespace epics { class ChannelRPCImpl : public BaseRequestImpl, public ChannelRPC { private: - ChannelRPCRequester* m_channelRPCRequester; + ChannelRPCRequester::shared_pointer m_channelRPCRequester; - PVStructure* m_pvRequest; + PVStructure::shared_pointer m_pvRequest; - PVStructure* m_data; - BitSet* m_bitSet; + PVStructure::shared_pointer m_data; + BitSet::shared_pointer m_bitSet; - private: - ~ChannelRPCImpl() + ChannelRPCImpl(ChannelImpl::shared_pointer& channel, ChannelRPCRequester::shared_pointer& channelRPCRequester, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(channelRPCRequester)), + m_channelRPCRequester(channelRPCRequester), m_pvRequest(pvRequest) { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelRPC); - // synced by code calling this - if (m_data) delete m_data; - if (m_bitSet) delete m_bitSet; - //if (m_pvRequest) delete m_pvRequest; + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelRPC); + } + + void activate() + { + BaseRequestImpl::activate(); + + if (m_pvRequest.get() == 0) + { + ChannelRPC::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(pvRequestNull, thisPointer, nullPVStructure, nullBitSet)); + return; + } + + // subscribe + try { + Transport::shared_pointer transport = m_channel->checkAndGetTransport(); + resubscribeSubscription(transport); + } catch (std::runtime_error &rte) { + ChannelRPC::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(channelNotConnected, thisPointer, nullPVStructure, nullBitSet)); + } } public: - ChannelRPCImpl(ChannelImpl* channel, ChannelRPCRequester* channelRPCRequester, PVStructure *pvRequest) : - BaseRequestImpl(channel, channelRPCRequester), - m_channelRPCRequester(channelRPCRequester), m_pvRequest(pvRequest), - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))), - m_data(0), m_bitSet(0) + static ChannelRPC::shared_pointer create(ChannelImpl::shared_pointer& channel, ChannelRPCRequester::shared_pointer& channelRPCRequester, PVStructure::shared_pointer& pvRequest) { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelRPC); + ChannelRPC::shared_pointer thisPointer(new ChannelRPCImpl(channel, channelRPCRequester, pvRequest), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } - if (pvRequest == 0) - { - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(pvRequestNull, 0, 0, 0)); - return; - } - - // subscribe - try { - resubscribeSubscription(m_channel->checkAndGetTransport()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(channelNotConnected, 0, 0, 0)); - } + ~ChannelRPCImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelRPC); } virtual void send(ByteBuffer* buffer, TransportSendControl* control) { @@ -1051,7 +1154,7 @@ namespace epics { return; } - control->startMessage((int8)20, 9); + control->startMessage((int8)CMD_RPC, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); if ((m_pendingRequest & QOS_INIT) == 0) @@ -1062,50 +1165,54 @@ namespace epics { buffer->putByte((int8)QOS_INIT); // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } else { m_bitSet->serialize(buffer, control); - m_data->serialize(buffer, control, m_bitSet); + m_data->serialize(buffer, control, m_bitSet.get()); } stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { // data available // TODO we need a flag here... return normalResponse(transport, version, payloadBuffer, qos, status); } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, this, 0, 0)); + ChannelRPC::shared_pointer nullChannelRPC; + PVStructure::shared_pointer nullPVStructure; + BitSet::shared_pointer nullBitSet; + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, nullChannelRPC, nullPVStructure, nullBitSet)); return true; } // create data and its bitSet - m_data = transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport); - m_bitSet = new BitSet(m_data->getNumberFields()); + m_data.reset(transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get())); + m_bitSet.reset(new BitSet(m_data->getNumberFields())); // notify - EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, this, m_data, m_bitSet)); + ChannelRPC::shared_pointer thisChannelRPC = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_channelRPCRequester->channelRPCConnect(status, thisChannelRPC, m_data, m_bitSet)); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, 0)); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, nullPVStructure)); return true; } - PVStructure* response = transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport); + PVStructure::shared_pointer response(transport->getIntrospectionRegistry()->deserializeStructureAndCreatePVStructure(payloadBuffer, transport.get())); EXCEPTION_GUARD(m_channelRPCRequester->requestDone(status, response)); - delete response; return true; } @@ -1114,31 +1221,37 @@ namespace epics { { Lock guard(m_mutex); if (m_destroyed) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, 0)); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(destroyedStatus, nullPVStructure)); return; } if (!m_initialized) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, 0)); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(notInitializedStatus, nullPVStructure)); return; } } if (!startRequest(lastRequest ? QOS_DESTROY : QOS_DEFAULT)) { - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, 0)); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(otherRequestPendingStatus, nullPVStructure)); return; } try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); - EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, 0)); + PVStructure::shared_pointer nullPVStructure; + EXCEPTION_GUARD(m_channelRPCRequester->requestDone(channelNotConnected, nullPVStructure)); } } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } virtual void destroy() @@ -1160,11 +1273,11 @@ namespace epics { class ChannelArrayImpl : public BaseRequestImpl, public ChannelArray { private: - ChannelArrayRequester* m_channelArrayRequester; + ChannelArrayRequester::shared_pointer m_channelArrayRequester; - PVStructure* m_pvRequest; + PVStructure::shared_pointer m_pvRequest; - PVArray* m_data; + PVArray::shared_pointer m_data; int32 m_offset; int32 m_count; @@ -1172,36 +1285,48 @@ namespace epics { int32 m_length; int32 m_capacity; - private: - ~ChannelArrayImpl() + ChannelArrayImpl(ChannelImpl::shared_pointer& channel, ChannelArrayRequester::shared_pointer& channelArrayRequester, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(channelArrayRequester)), + m_channelArrayRequester(channelArrayRequester), m_pvRequest(pvRequest), + m_offset(0), m_count(0), m_length(-1), m_capacity(-1) { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelArray); - // synced by code calling this - if (m_data) delete m_data; - //if (m_pvRequest) delete m_pvRequest; + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelArray); + } + + void activate() + { + BaseRequestImpl::activate(); + + if (m_pvRequest.get() == 0) + { + ChannelArray::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVArray::shared_pointer nullPVArray; + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(pvRequestNull, thisPointer, nullPVArray)); + return; + } + + // subscribe + try { + Transport::shared_pointer transport = m_channel->checkAndGetTransport(); + resubscribeSubscription(transport); + } catch (std::runtime_error &rte) { + ChannelArray::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + PVArray::shared_pointer nullPVArray; + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(channelNotConnected, thisPointer, nullPVArray)); + } } public: - ChannelArrayImpl(ChannelImpl* channel, ChannelArrayRequester* channelArrayRequester, PVStructure *pvRequest) : - BaseRequestImpl(channel, channelArrayRequester), - m_channelArrayRequester(channelArrayRequester), m_pvRequest(pvRequest), - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))), - m_data(0), m_offset(0), m_count(0), m_length(-1), m_capacity(-1) + static ChannelArray::shared_pointer create(ChannelImpl::shared_pointer& channel, ChannelArrayRequester::shared_pointer& channelArrayRequester, PVStructure::shared_pointer& pvRequest) { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelArray); + ChannelArray::shared_pointer thisPointer(new ChannelArrayImpl(channel, channelArrayRequester, pvRequest), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } - if (pvRequest == 0) - { - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(pvRequestNull, 0, 0)); - return; - } - - // subscribe - try { - resubscribeSubscription(m_channel->checkAndGetTransport()); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(channelNotConnected, 0, 0)); - } + ~ChannelArrayImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelArray); } virtual void send(ByteBuffer* buffer, TransportSendControl* control) { @@ -1212,7 +1337,7 @@ namespace epics { return; } - control->startMessage((int8)14, 9); + control->startMessage((int8)CMD_ARRAY, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); buffer->putByte((int8)m_pendingRequest); @@ -1220,7 +1345,7 @@ namespace epics { if (pendingRequest & QOS_INIT) { // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } else if (pendingRequest & QOS_GET) { @@ -1242,30 +1367,33 @@ namespace epics { stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { // data available (get with destroy) if (qos & QOS_GET) return normalResponse(transport, version, payloadBuffer, qos, status); return true; } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, this, 0)); + ChannelArray::shared_pointer nullChannelArray; + PVArray::shared_pointer nullPVArray; + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, nullChannelArray, nullPVArray)); return true; } // create data and its bitSet - FieldConstPtr field = transport->getIntrospectionRegistry()->deserialize(payloadBuffer, transport); - m_data = dynamic_cast(getPVDataCreate()->createPVField(0, field)); + FieldConstPtr field = transport->getIntrospectionRegistry()->deserialize(payloadBuffer, transport.get()); + m_data.reset(dynamic_cast(getPVDataCreate()->createPVField(0, field))); // notify - EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, this, m_data)); + ChannelArray::shared_pointer thisChannelArray = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_channelArrayRequester->channelArrayConnect(status, thisChannelArray, m_data)); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (qos & QOS_GET) { if (!status.isSuccess()) @@ -1274,7 +1402,7 @@ namespace epics { return true; } - m_data->deserialize(payloadBuffer, transport); + m_data->deserialize(payloadBuffer, transport.get()); EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(status)); return true; @@ -1314,7 +1442,8 @@ namespace epics { try { m_offset = offset; m_count = count; - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelArrayRequester->getArrayDone(channelNotConnected)); @@ -1343,7 +1472,8 @@ namespace epics { try { m_offset = offset; m_count = count; - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelArrayRequester->putArrayDone(channelNotConnected)); @@ -1372,7 +1502,8 @@ namespace epics { try { m_length = length; m_capacity = capacity; - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); } catch (std::runtime_error &rte) { stopRequest(); EXCEPTION_GUARD(m_channelArrayRequester->setLengthDone(channelNotConnected)); @@ -1380,9 +1511,10 @@ namespace epics { } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } virtual void destroy() @@ -1402,50 +1534,73 @@ namespace epics { PVDATA_REFCOUNT_MONITOR_DEFINE(channelGetField); // NOTE: this instance is not returned as Request, so it must self-destruct - class ChannelGetFieldRequestImpl : public DataResponse, public TransportSender + class ChannelGetFieldRequestImpl : + public DataResponse, + public TransportSender, + public std::tr1::enable_shared_from_this { - private: - ChannelImpl* m_channel; - ClientContextImpl* m_context; - pvAccessID m_ioid; - GetFieldRequester* m_callback; - String m_subField; - Mutex m_mutex; - bool m_destroyed; - int m_refCount; + public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; private: + ChannelImpl::shared_pointer m_channel; + + GetFieldRequester::shared_pointer m_callback; + String m_subField; + + pvAccessID m_ioid; + + Mutex m_mutex; + bool m_destroyed; + + ResponseRequest::shared_pointer m_thisPointer; + + ChannelGetFieldRequestImpl(ChannelImpl::shared_pointer& channel, GetFieldRequester::shared_pointer& callback, String subField) : + m_channel(channel), + m_callback(callback), + m_subField(subField), + m_ioid(INVALID_IOID), + m_destroyed(false) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelGetField); + } + + void activate() + { + // register response request + m_thisPointer = shared_from_this(); + m_ioid = m_channel->getContext()->registerResponseRequest(m_thisPointer); + m_channel->registerResponseRequest(m_thisPointer); + + // enqueue send request + try { + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); + } catch (std::runtime_error &rte) { + FieldConstPtr nullField; + EXCEPTION_GUARD(m_callback->getDone(BaseRequestImpl::channelNotConnected, nullField)); + } + } + + public: + static ChannelGetFieldRequestImpl::shared_pointer create(ChannelImpl::shared_pointer& channel, GetFieldRequester::shared_pointer& callback, String subField) + { + ChannelGetFieldRequestImpl::shared_pointer thisPointer(new ChannelGetFieldRequestImpl(channel, callback, subField), delayed_destroyable_deleter()); + thisPointer->activate(); + return thisPointer; + } + ~ChannelGetFieldRequestImpl() { PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelGetField); } - - public: - ChannelGetFieldRequestImpl(ChannelImpl* channel, GetFieldRequester* callback, String subField) : - m_channel(channel), m_context(channel->getContext()), - m_callback(callback), m_subField(subField), - m_destroyed(false), m_refCount(1) - { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelGetField); - - // register response request - m_ioid = m_context->registerResponseRequest(this); - channel->registerResponseRequest(this); - - // enqueue send request - try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); - } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(callback->getDone(BaseRequestImpl::channelNotConnected, 0)); - } - } - - Requester* getRequester() { + Requester::shared_pointer getRequester() { return m_callback; } - pvAccessID getIOID() { + pvAccessID getIOID() const { return m_ioid; } @@ -1491,39 +1646,26 @@ namespace epics { } // unregister response request - m_context->unregisterResponseRequest(this); - m_channel->unregisterResponseRequest(this); - - release(); + m_channel->getContext()->unregisterResponseRequest(m_ioid); + m_channel->unregisterResponseRequest(m_ioid); + + m_thisPointer.reset(); } - virtual void acquire() { - Lock guard(m_mutex); - m_refCount++; - } - - virtual void release() { - m_mutex.lock(); - m_refCount--; - m_mutex.unlock(); - if (m_refCount == 0) - delete this; - } - - virtual void response(Transport* transport, int8 version, ByteBuffer* payloadBuffer) { + virtual void response(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer) { Status status; - transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport); + transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport.get()); if (status.isSuccess()) { // deserialize Field... - const Field* field = transport->getIntrospectionRegistry()->deserialize(payloadBuffer, transport); + FieldConstPtr field = transport->getIntrospectionRegistry()->deserialize(payloadBuffer, transport.get()); EXCEPTION_GUARD(m_callback->getDone(status, field)); - field->decReferenceCount(); } else { - EXCEPTION_GUARD(m_callback->getDone(status, 0)); + FieldConstPtr nullField; + EXCEPTION_GUARD(m_callback->getDone(status, nullField)); } cancel(); @@ -1545,21 +1687,25 @@ namespace epics { class MonitorStrategy : public Monitor { public: virtual ~MonitorStrategy() {}; - virtual void init(Structure* structure) = 0; - virtual void response(Transport* transport, ByteBuffer* payloadBuffer) = 0; + virtual void init(StructureConstPtr& structure) = 0; + virtual void response(Transport::shared_pointer& transport, ByteBuffer* payloadBuffer) = 0; }; - class MonitorStrategyNotify : public MonitorStrategy, public MonitorElement { + class MonitorStrategyNotify : + public MonitorStrategy, + public MonitorElement, + public std::tr1::enable_shared_from_this + { private: - MonitorRequester* m_callback; + MonitorRequester::shared_pointer m_callback; bool m_gotMonitor; Mutex m_mutex; public: - MonitorStrategyNotify(MonitorRequester* callback) : + MonitorStrategyNotify(MonitorRequester::shared_pointer& callback) : m_callback(callback), m_gotMonitor(false), m_mutex() { } @@ -1568,23 +1714,24 @@ namespace epics { { } - virtual void init(Structure* structure) { + virtual void init(StructureConstPtr& structure) { // noop } - virtual void response(Transport* transport, ByteBuffer* payloadBuffer) { + virtual void response(Transport::shared_pointer& transport, ByteBuffer* payloadBuffer) { Lock guard(m_mutex); m_gotMonitor = true; // no data, only notify - m_callback->monitorEvent(this); + Monitor::shared_pointer thisMonitor = shared_from_this(); + m_callback->monitorEvent(thisMonitor); } - virtual MonitorElement* poll() { + virtual MonitorElement::shared_pointer poll() { Lock guard(m_mutex); - return m_gotMonitor ? this : 0; + return m_gotMonitor ? static_pointer_cast(shared_from_this()) : MonitorElement::shared_pointer(); } - virtual void release(MonitorElement* monitorElement) { + virtual void release(MonitorElement::shared_pointer& monitorElement) { Lock guard(m_mutex); m_gotMonitor = false; } @@ -1603,77 +1750,75 @@ namespace epics { // ============ MonitorElement ============ - virtual PVStructure* getPVStructure() + virtual PVStructure::shared_pointer getPVStructure() { - return 0; + return PVStructure::shared_pointer(); } - virtual BitSet* getChangedBitSet() + virtual BitSet::shared_pointer getChangedBitSet() { - return 0; + return BitSet::shared_pointer(); } - virtual BitSet* getOverrunBitSet() + virtual BitSet::shared_pointer getOverrunBitSet() { - return 0; + return BitSet::shared_pointer(); } }; - class MonitorStrategyEntire : public MonitorStrategy, public MonitorElement { + class MonitorStrategyEntire : + public MonitorStrategy, + public MonitorElement, + public std::tr1::enable_shared_from_this + { private: - MonitorRequester* m_callback; + MonitorRequester::shared_pointer m_callback; bool m_gotMonitor; Mutex m_mutex; - PVStructure* m_monitorElementStructure; - BitSet* m_monitorElementChangeBitSet; - BitSet* m_monitorElementOverrunBitSet; + PVStructure::shared_pointer m_monitorElementStructure; + BitSet::shared_pointer m_monitorElementChangeBitSet; + BitSet::shared_pointer m_monitorElementOverrunBitSet; public: - MonitorStrategyEntire(MonitorRequester* callback) : - m_callback(callback), m_gotMonitor(false), m_mutex(), - m_monitorElementStructure(0), - m_monitorElementChangeBitSet(0), - m_monitorElementOverrunBitSet(0) + MonitorStrategyEntire(MonitorRequester::shared_pointer& callback) : + m_callback(callback), m_gotMonitor(false), m_mutex() { } virtual ~MonitorStrategyEntire() { - if (m_monitorElementStructure) delete m_monitorElementStructure; - if (m_monitorElementChangeBitSet) delete m_monitorElementChangeBitSet; - if (m_monitorElementOverrunBitSet) delete m_monitorElementOverrunBitSet; } - virtual void init(Structure* structure) { + virtual void init(StructureConstPtr& structure) { Lock guard(m_mutex); - structure->incReferenceCount(); - m_monitorElementStructure = getPVDataCreate()->createPVStructure(0, structure); + m_monitorElementStructure.reset(getPVDataCreate()->createPVStructure(0, structure)); int numberFields = m_monitorElementStructure->getNumberFields(); - m_monitorElementChangeBitSet = new BitSet(numberFields); - m_monitorElementOverrunBitSet = new BitSet(numberFields); + m_monitorElementChangeBitSet.reset(new BitSet(numberFields)); + m_monitorElementOverrunBitSet.reset(new BitSet(numberFields)); } - virtual void response(Transport* transport, ByteBuffer* payloadBuffer) { + virtual void response(Transport::shared_pointer& transport, ByteBuffer* payloadBuffer) { Lock guard(m_mutex); // simply deserialize and notify - m_monitorElementChangeBitSet->deserialize(payloadBuffer, transport); - m_monitorElementStructure->deserialize(payloadBuffer, transport, m_monitorElementChangeBitSet); - m_monitorElementOverrunBitSet->deserialize(payloadBuffer, transport); + m_monitorElementChangeBitSet->deserialize(payloadBuffer, transport.get()); + m_monitorElementStructure->deserialize(payloadBuffer, transport.get(), m_monitorElementChangeBitSet.get()); + m_monitorElementOverrunBitSet->deserialize(payloadBuffer, transport.get()); m_gotMonitor = true; - m_callback->monitorEvent(this); + Monitor::shared_pointer thisMonitor = shared_from_this(); + m_callback->monitorEvent(thisMonitor); } - virtual MonitorElement* poll() { + virtual MonitorElement::shared_pointer poll() { Lock guard(m_mutex); - return m_gotMonitor ? this : 0; + return m_gotMonitor ? static_pointer_cast(shared_from_this()) : MonitorElement::shared_pointer(); } - virtual void release(MonitorElement* monitorElement) { + virtual void release(MonitorElement::shared_pointer& monitorElement) { Lock guard(m_mutex); m_gotMonitor = false; } @@ -1694,123 +1839,117 @@ namespace epics { // ============ MonitorElement ============ - virtual PVStructure* getPVStructure() + virtual PVStructure::shared_pointer getPVStructure() { return m_monitorElementStructure; } - virtual BitSet* getChangedBitSet() + virtual BitSet::shared_pointer getChangedBitSet() { return m_monitorElementChangeBitSet; } - virtual BitSet* getOverrunBitSet() + virtual BitSet::shared_pointer getOverrunBitSet() { return m_monitorElementOverrunBitSet; } }; - class MonitorStrategySingle : public MonitorStrategy, public MonitorElement { + class MonitorStrategySingle : + public MonitorStrategy, + public MonitorElement, + public std::tr1::enable_shared_from_this + { private: - MonitorRequester* m_callback; + MonitorRequester::shared_pointer m_callback; bool m_gotMonitor; Mutex m_mutex; - PVStructure* m_monitorElementStructure; - BitSet* m_monitorElementChangeBitSet; - BitSet* m_monitorElementOverrunBitSet; + PVStructure::shared_pointer m_monitorElementStructure; + BitSet::shared_pointer m_monitorElementChangeBitSet; + BitSet::shared_pointer m_monitorElementOverrunBitSet; - BitSet* m_dataChangeBitSet; - BitSet* m_dataOverrunBitSet; + BitSet::shared_pointer m_dataChangeBitSet; + BitSet::shared_pointer m_dataOverrunBitSet; bool m_needToCompress; public: - MonitorStrategySingle(MonitorRequester* callback) : + MonitorStrategySingle(MonitorRequester::shared_pointer callback) : m_callback(callback), m_gotMonitor(false), m_mutex(), - m_monitorElementStructure(0), - m_monitorElementChangeBitSet(0), - m_monitorElementOverrunBitSet(0), - m_dataChangeBitSet(0), - m_dataOverrunBitSet(0), m_needToCompress(false) { } virtual ~MonitorStrategySingle() { - if (m_monitorElementStructure) delete m_monitorElementStructure; - if (m_monitorElementChangeBitSet) delete m_monitorElementChangeBitSet; - if (m_monitorElementOverrunBitSet) delete m_monitorElementOverrunBitSet; - - if (m_dataChangeBitSet) delete m_dataChangeBitSet; - if (m_dataOverrunBitSet) delete m_dataOverrunBitSet; } - virtual void init(Structure* structure) { + virtual void init(StructureConstPtr& structure) { Lock guard(m_mutex); - structure->incReferenceCount(); - m_monitorElementStructure = getPVDataCreate()->createPVStructure(0, structure); + m_monitorElementStructure.reset(getPVDataCreate()->createPVStructure(0, structure)); int numberFields = m_monitorElementStructure->getNumberFields(); - m_monitorElementChangeBitSet = new BitSet(numberFields); - m_monitorElementOverrunBitSet = new BitSet(numberFields); + m_monitorElementChangeBitSet.reset(new BitSet(numberFields)); + m_monitorElementOverrunBitSet.reset(new BitSet(numberFields)); - m_dataChangeBitSet = new BitSet(numberFields); - m_dataOverrunBitSet = new BitSet(numberFields); + m_dataChangeBitSet.reset(new BitSet(numberFields)); + m_dataOverrunBitSet.reset(new BitSet(numberFields)); } - virtual void response(Transport* transport, ByteBuffer* payloadBuffer) { + virtual void response(Transport::shared_pointer& transport, ByteBuffer* payloadBuffer) { Lock guard(m_mutex); if (!m_gotMonitor) { // simply deserialize and notify - m_monitorElementChangeBitSet->deserialize(payloadBuffer, transport); - m_monitorElementStructure->deserialize(payloadBuffer, transport, m_monitorElementChangeBitSet); - m_monitorElementOverrunBitSet->deserialize(payloadBuffer, transport); + m_monitorElementChangeBitSet->deserialize(payloadBuffer, transport.get()); + m_monitorElementStructure->deserialize(payloadBuffer, transport.get(), m_monitorElementChangeBitSet.get()); + m_monitorElementOverrunBitSet->deserialize(payloadBuffer, transport.get()); m_gotMonitor = true; - m_callback->monitorEvent(this); + Monitor::shared_pointer thisMonitor = shared_from_this(); + m_callback->monitorEvent(thisMonitor); } else { // deserialize first - m_dataChangeBitSet->deserialize(payloadBuffer, transport); - m_monitorElementStructure->deserialize(payloadBuffer, transport, m_dataChangeBitSet); - m_dataOverrunBitSet->deserialize(payloadBuffer, transport); + m_dataChangeBitSet->deserialize(payloadBuffer, transport.get()); + m_monitorElementStructure->deserialize(payloadBuffer, transport.get(), m_dataChangeBitSet.get()); + m_dataOverrunBitSet->deserialize(payloadBuffer, transport.get()); // OR local overrun // TODO should work only on uncompressed - m_monitorElementOverrunBitSet->or_and(*m_dataChangeBitSet, *m_monitorElementChangeBitSet); + m_monitorElementOverrunBitSet->or_and(*m_dataChangeBitSet.get(), *m_monitorElementChangeBitSet.get()); // OR new changes - *m_monitorElementChangeBitSet |= *m_dataChangeBitSet; + *m_monitorElementChangeBitSet |= *m_dataChangeBitSet.get(); // OR remote overrun - *m_monitorElementOverrunBitSet |= *m_dataOverrunBitSet; + *m_monitorElementOverrunBitSet |= *m_dataOverrunBitSet.get(); } } - virtual MonitorElement* poll() { + virtual MonitorElement::shared_pointer poll() { Lock guard(m_mutex); - if (!m_gotMonitor) return 0; + if (!m_gotMonitor) return MonitorElement::shared_pointer(); // compress if needed if (m_needToCompress) { - BitSetUtil::compress(m_monitorElementChangeBitSet, m_monitorElementStructure); - BitSetUtil::compress(m_monitorElementOverrunBitSet, m_monitorElementStructure); + BitSetUtil::compress(m_monitorElementChangeBitSet.get(), m_monitorElementStructure.get()); + BitSetUtil::compress(m_monitorElementOverrunBitSet.get(), m_monitorElementStructure.get()); m_needToCompress = false; } - return this; + MonitorElement::shared_pointer thisMonitorElement = shared_from_this(); + return thisMonitorElement; } - virtual void release(MonitorElement* monitorElement) { + virtual void release(MonitorElement::shared_pointer& monitorElement) { Lock guard(m_mutex); m_gotMonitor = false; } @@ -1835,17 +1974,17 @@ namespace epics { // ============ MonitorElement ============ - virtual PVStructure* getPVStructure() + virtual PVStructure::shared_pointer getPVStructure() { return m_monitorElementStructure; } - virtual BitSet* getChangedBitSet() + virtual BitSet::shared_pointer getChangedBitSet() { return m_monitorElementChangeBitSet; } - virtual BitSet* getOverrunBitSet() + virtual BitSet::shared_pointer getOverrunBitSet() { return m_monitorElementOverrunBitSet; } @@ -1856,47 +1995,41 @@ namespace epics { PVDATA_REFCOUNT_MONITOR_DEFINE(channelMonitor); - class ChannelMonitorImpl : public BaseRequestImpl, public Monitor + class ChannelMonitorImpl : + public BaseRequestImpl, + public Monitor { private: - MonitorRequester* m_monitorRequester; + MonitorRequester::shared_pointer m_monitorRequester; bool m_started; - PVStructure* m_pvRequest; + PVStructure::shared_pointer m_pvRequest; - MonitorStrategy* m_monitorStrategy; + auto_ptr m_monitorStrategy; - private: - ~ChannelMonitorImpl() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelMonitor); - - // synced by code calling this - //if (m_pvRequest) delete m_pvRequest; - - if (m_monitorStrategy) delete m_monitorStrategy; - } - - public: - ChannelMonitorImpl(ChannelImpl* channel, MonitorRequester* monitorRequester, PVStructure *pvRequest) : - BaseRequestImpl(channel, monitorRequester), + ChannelMonitorImpl(ChannelImpl::shared_pointer& channel, MonitorRequester::shared_pointer& monitorRequester, PVStructure::shared_pointer& pvRequest) : + BaseRequestImpl(channel, static_pointer_cast(monitorRequester)), m_monitorRequester(monitorRequester), - m_started(false), m_pvRequest(pvRequest), - //(dynamic_cast(getPVDataCreate()->createPVField(0, "", pvRequest))), - m_monitorStrategy(0) + m_started(false), + m_pvRequest(pvRequest) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channelMonitor); - - /* - if (pvRequest == 0) + } + + void activate() + { + BaseRequestImpl::activate(); + + if (m_pvRequest.get() == 0) { - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(pvRequestNull, 0, 0)); + Monitor::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + StructureConstPtr nullPVStructure; + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(pvRequestNull, thisPointer, nullPVStructure)); return; } - */ - + int queueSize = 2; - PVField* pvField = pvRequest->getSubField("record.queueSize"); + PVField* pvField = m_pvRequest->getSubField("record.queueSize"); if (pvField) { PVString* pvString = dynamic_cast(pvField); if (pvString) @@ -1904,35 +2037,53 @@ namespace epics { String value = pvString->get(); istringstream buffer(value); - + if ((buffer >> queueSize).fail()) { Status failedToConvert(Status::STATUSTYPE_ERROR, "queueSize type is not a valid integer"); - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(failedToConvert, 0, 0)); + Monitor::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + StructureConstPtr nullPVStructure; + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(failedToConvert, thisPointer, nullPVStructure)); return; } } } - + if (queueSize == -1) - m_monitorStrategy = new MonitorStrategyNotify(m_monitorRequester); + m_monitorStrategy.reset(new MonitorStrategyNotify(m_monitorRequester)); else if (queueSize == 0) // 0 means all (old v3 style), some sending optimization can be done (not to send bit-sets) - m_monitorStrategy = new MonitorStrategyEntire(m_monitorRequester); + m_monitorStrategy.reset(new MonitorStrategyEntire(m_monitorRequester)); else //if (queueSize == 1) - m_monitorStrategy = new MonitorStrategySingle(m_monitorRequester); - /* else - m_monitorStrategy = new MonitorStrategyQueue(queueSize); - */ - - + m_monitorStrategy.reset(new MonitorStrategySingle(m_monitorRequester)); + /* else + m_monitorStrategy.reset(new MonitorStrategyQueue(queueSize)); + */ + + // subscribe try { - resubscribeSubscription(m_channel->checkAndGetTransport()); + Transport::shared_pointer transport = m_channel->checkAndGetTransport(); + resubscribeSubscription(transport); } catch (std::runtime_error &rte) { - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(channelNotConnected, 0, 0)); + Monitor::shared_pointer thisPointer = dynamic_pointer_cast(shared_from_this()); + StructureConstPtr nullPVStructure; + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(channelNotConnected, thisPointer, nullPVStructure)); } } + public: + static Monitor::shared_pointer create(ChannelImpl::shared_pointer& channel, MonitorRequester::shared_pointer& monitorRequester, PVStructure::shared_pointer& pvRequest) + { + Monitor::shared_pointer thisPointer(new ChannelMonitorImpl(channel, monitorRequester, pvRequest), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } + + ~ChannelMonitorImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channelMonitor); + } + virtual void send(ByteBuffer* buffer, TransportSendControl* control) { int32 pendingRequest = getPendingRequest(); if (pendingRequest < 0) @@ -1941,7 +2092,7 @@ namespace epics { return; } - control->startMessage((int8)13, 9); + control->startMessage((int8)CMD_MONITOR, 9); buffer->putInt(m_channel->getServerChannelID()); buffer->putInt(m_ioid); buffer->putByte((int8)m_pendingRequest); @@ -1949,39 +2100,45 @@ namespace epics { if (pendingRequest & QOS_INIT) { // pvRequest - m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest); + m_channel->getTransport()->getIntrospectionRegistry()->serializePVRequest(buffer, control, m_pvRequest.get()); } stopRequest(); } - virtual bool destroyResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool destroyResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { // data available // TODO if (qos & QOS_GET) return normalResponse(transport, version, payloadBuffer, qos, status); } - virtual bool initResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool initResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (!status.isSuccess()) { - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, this, 0)); + Monitor::shared_pointer nullChannelMonitor; + StructureConstPtr nullPVStructure; + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, nullChannelMonitor, nullPVStructure)); return true; } - Structure* structure = const_cast(dynamic_cast(transport->getIntrospectionRegistry()->deserialize(payloadBuffer, transport))); + StructureConstPtr structure = + dynamic_pointer_cast( + transport->getIntrospectionRegistry()-> + deserialize(payloadBuffer, transport.get()) + ); m_monitorStrategy->init(structure); // notify - EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, this, structure)); - structure->decReferenceCount(); - + Monitor::shared_pointer thisChannelMonitor = dynamic_pointer_cast(shared_from_this()); + EXCEPTION_GUARD(m_monitorRequester->monitorConnect(status, thisChannelMonitor, structure)); + if (m_started) start(); return true; } - virtual bool normalResponse(Transport* transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { + virtual bool normalResponse(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer, int8 qos, const Status& status) { if (qos & QOS_GET) { // TODO not supported by IF yet... @@ -1993,20 +2150,21 @@ namespace epics { return true; } - virtual void resubscribeSubscription(Transport* transport) { + virtual void resubscribeSubscription(Transport::shared_pointer& transport) { startRequest(QOS_INIT); - transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + transport->enqueueSendRequest(thisSender); } // override, since we optimize status - virtual void response(Transport* transport, int8 version, ByteBuffer* payloadBuffer) { + virtual void response(Transport::shared_pointer& transport, int8 version, ByteBuffer* payloadBuffer) { transport->ensureData(1); int8 qos = payloadBuffer->getByte(); if (qos & QOS_INIT) { Status status; - transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport); + transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport.get()); if (status.isSuccess()) { m_mutex.lock(); @@ -2018,7 +2176,7 @@ namespace epics { else if (qos & QOS_DESTROY) { Status status; - transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport); + transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport.get()); m_mutex.lock(); m_initialized = false; @@ -2051,7 +2209,8 @@ namespace epics { try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); m_started = true; return Status::OK; } catch (std::runtime_error &rte) { @@ -2077,7 +2236,8 @@ namespace epics { try { - m_channel->checkAndGetTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_channel->checkAndGetTransport()->enqueueSendRequest(thisSender); m_started = false; return Status::OK; } catch (std::runtime_error &rte) { @@ -2092,12 +2252,12 @@ namespace epics { BaseRequestImpl::destroy(); } - virtual MonitorElement* poll() + virtual MonitorElement::shared_pointer poll() { return m_monitorStrategy->poll(); } - virtual void release(MonitorElement* monitorElement) + virtual void release(MonitorElement::shared_pointer& monitorElement) { m_monitorStrategy->release(monitorElement); } @@ -2106,32 +2266,21 @@ namespace epics { - /** - * @author Matej Sekoranja - * @version $Id: AbstractServerResponseHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ - */ class AbstractClientResponseHandler : public AbstractResponseHandler { protected: - ClientContextImpl* _context; + ClientContextImpl::weak_pointer _context; public: - /** - * @param context - * @param description - */ - AbstractClientResponseHandler(ClientContextImpl* context, String description) : - AbstractResponseHandler(context, description), _context(context) { + AbstractClientResponseHandler(ClientContextImpl::shared_pointer& context, String description) : + AbstractResponseHandler(context.get(), description), _context(ClientContextImpl::weak_pointer(context)) { } virtual ~AbstractClientResponseHandler() { } }; - class NoopResponse : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class NoopResponse : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - /** - * @param context - */ - NoopResponse(ClientContextImpl* context, String description) : + NoopResponse(ClientContextImpl::shared_pointer& context, String description) : AbstractClientResponseHandler(context, description) { } @@ -2141,12 +2290,9 @@ namespace epics { }; - class BadResponse : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class BadResponse : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - /** - * @param context - */ - BadResponse(ClientContextImpl* context) : + BadResponse(ClientContextImpl::shared_pointer& context) : AbstractClientResponseHandler(context, "Bad response") { } @@ -2155,7 +2301,7 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { char ipAddrStr[48]; @@ -2168,12 +2314,9 @@ namespace epics { }; - class DataResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class DataResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - /** - * @param context - */ - DataResponseHandler(ClientContextImpl* context) : + DataResponseHandler(ClientContextImpl::shared_pointer& context) : AbstractClientResponseHandler(context, "Data response") { } @@ -2182,26 +2325,27 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); transport->ensureData(4); - ResponseRequestGuard rr(_context->getResponseRequest(payloadBuffer->getInt())); + // TODO check and optimize? + ResponseRequest::shared_pointer rr = _context.lock()->getResponseRequest(payloadBuffer->getInt()); if (rr.get()) { - DataResponse* nrr = dynamic_cast(rr.get()); - if (nrr) + DataResponse::shared_pointer nrr = dynamic_pointer_cast(rr); + if (nrr.get()) nrr->response(transport, version, payloadBuffer); } } }; - class SearchResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class SearchResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - SearchResponseHandler(ClientContextImpl* context) : + SearchResponseHandler(ClientContextImpl::shared_pointer& context) : AbstractClientResponseHandler(context, "Search response") { } @@ -2210,7 +2354,7 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -2245,9 +2389,10 @@ namespace epics { serverAddress.ia.sin_addr = responseFrom->ia.sin_addr; serverAddress.ia.sin_port = htons(payloadBuffer->getShort()); - + // reads CIDs - ChannelSearchManager* csm = _context->getChannelSearchManager(); + // TODO optimize + std::tr1::shared_ptr csm = _context.lock()->getChannelSearchManager(); int16 count = payloadBuffer->getShort(); for (int i = 0; i < count; i++) { @@ -2261,9 +2406,9 @@ namespace epics { }; - class BeaconResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class BeaconResponseHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - BeaconResponseHandler(ClientContextImpl* context) : + BeaconResponseHandler(ClientContextImpl::shared_pointer& context) : AbstractClientResponseHandler(context, "Beacon") { } @@ -2272,7 +2417,7 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { // reception timestamp @@ -2309,29 +2454,35 @@ namespace epics { serverAddress.ia.sin_port = htons(payloadBuffer->getShort()); - BeaconHandler* beaconHandler = _context->getBeaconHandler(responseFrom); + // TODO optimize + ClientContextImpl::shared_pointer context = _context.lock(); + if (!context) + return; + + std::tr1::shared_ptr beaconHandler = context->getBeaconHandler(responseFrom); // currently we care only for servers used by this context - if (beaconHandler == NULL) + if (beaconHandler == 0) return; + // TODO smart pointers // extra data - PVFieldPtr data = NULL; - const FieldConstPtr field = IntrospectionRegistry::deserializeFull(payloadBuffer, transport); - if (field != NULL) + PVFieldPtr data = 0; + const FieldConstPtr field = IntrospectionRegistry::deserializeFull(payloadBuffer, transport.get()); + if (field != 0) { - data = getPVDataCreate()->createPVField(NULL, field); - data->deserialize(payloadBuffer, transport); + data = getPVDataCreate()->createPVField(0, field); + data->deserialize(payloadBuffer, transport.get()); } // notify beacon handler beaconHandler->beaconNotify(responseFrom, version, ×tamp, &startupTimestamp, sequentalID, data); - + if (data) delete data; } }; - class ClientConnectionValidationHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class ClientConnectionValidationHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - ClientConnectionValidationHandler(ClientContextImpl* context) : + ClientConnectionValidationHandler(ClientContextImpl::shared_pointer context) : AbstractClientResponseHandler(context, "Connection validation") { } @@ -2340,7 +2491,7 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -2350,17 +2501,18 @@ namespace epics { transport->setRemoteTransportSocketReceiveBufferSize(payloadBuffer->getInt()); transport->setRemoteMinorRevision(version); - TransportSender* sender = dynamic_cast(transport); - if (sender) + TransportSender::shared_pointer sender = dynamic_pointer_cast(transport); + if (sender.get()) { transport->enqueueSendRequest(sender); + } transport->verified(); } }; - class MessageHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class MessageHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - MessageHandler(ClientContextImpl* context) : + MessageHandler(ClientContextImpl::shared_pointer& context) : AbstractClientResponseHandler(context, "Message") { } @@ -2369,32 +2521,35 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); transport->ensureData(5); - ResponseRequestGuard rr(_context->getResponseRequest(payloadBuffer->getInt())); + // TODO optimize + ResponseRequest::shared_pointer rr = _context.lock()->getResponseRequest(payloadBuffer->getInt()); if (rr.get()) { - DataResponse* nrr = dynamic_cast(rr.get()); - Requester* requester; - if (nrr && (requester = nrr->getRequester())) + DataResponse::shared_pointer nrr = dynamic_pointer_cast(rr); + if (nrr.get()) { - MessageType type = (MessageType)payloadBuffer->getByte(); - String message = SerializeHelper::deserializeString(payloadBuffer, transport); - requester->message(message, type); + Requester::shared_pointer requester = nrr->getRequester(); + if (requester.get()) { + MessageType type = (MessageType)payloadBuffer->getByte(); + String message = SerializeHelper::deserializeString(payloadBuffer, transport.get()); + requester->message(message, type); + } } } } }; - class CreateChannelHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { + class CreateChannelHandler : public AbstractClientResponseHandler, private epics::pvData::NoDefaultMethods { public: - CreateChannelHandler(ClientContextImpl* context) : + CreateChannelHandler(ClientContextImpl::shared_pointer& context) : AbstractClientResponseHandler(context, "Create channel") { } @@ -2403,7 +2558,7 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer) { AbstractClientResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -2413,10 +2568,11 @@ namespace epics { pvAccessID sid = payloadBuffer->getInt(); Status status; - transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport); + transport->getIntrospectionRegistry()->deserializeStatus(status, payloadBuffer, transport.get()); - ChannelImpl* channel = static_cast(_context->getChannel(cid)); - if (channel) + // TODO optimize + ChannelImpl::shared_pointer channel = static_pointer_cast(_context.lock()->getChannel(cid)); + if (channel.get()) { // failed check if (!status.isSuccess()) { @@ -2443,82 +2599,54 @@ namespace epics { /** * Table of response handlers for each command ID. */ - ResponseHandler** m_handlerTable; - - /* - * Context instance is part of the response handler now - */ - //ClientContextImpl* m_context; + vector m_handlerTable; public: virtual ~ClientResponseHandler() { - delete m_handlerTable[ 0]; - delete m_handlerTable[ 1]; - delete m_handlerTable[ 2]; - delete m_handlerTable[ 3]; - delete m_handlerTable[ 4]; - delete m_handlerTable[ 5]; - delete m_handlerTable[ 6]; - delete m_handlerTable[ 7]; - delete m_handlerTable[ 8]; - delete m_handlerTable[ 9]; - delete m_handlerTable[18]; - - delete[] m_handlerTable; } /** * @param context */ - ClientResponseHandler(ClientContextImpl* context) { - ResponseHandler* badResponse = new BadResponse(context); - ResponseHandler* dataResponse = new DataResponseHandler(context); - - // TODO free!!! -#define HANDLER_COUNT 28 - m_handlerTable = new ResponseHandler*[HANDLER_COUNT]; - m_handlerTable[ 0] = new BeaconResponseHandler(context), /* 0 */ - m_handlerTable[ 1] = new ClientConnectionValidationHandler(context), /* 1 */ - m_handlerTable[ 2] = new NoopResponse(context, "Echo"), /* 2 */ - m_handlerTable[ 3] = new NoopResponse(context, "Search"), /* 3 */ - m_handlerTable[ 4] = new SearchResponseHandler(context), /* 4 */ - m_handlerTable[ 5] = new NoopResponse(context, "Introspection search"), /* 5 */ - m_handlerTable[ 6] = dataResponse; /* 6 - introspection search */ - m_handlerTable[ 7] = new CreateChannelHandler(context), /* 7 */ - m_handlerTable[ 8] = new NoopResponse(context, "Destroy channel"), /* 8 */ // TODO it might be useful to implement this... - m_handlerTable[ 9] = badResponse; /* 9 */ - m_handlerTable[10] = dataResponse; /* 10 - get response */ - m_handlerTable[11] = dataResponse; /* 11 - put response */ - m_handlerTable[12] = dataResponse; /* 12 - put-get response */ - m_handlerTable[13] = dataResponse; /* 13 - monitor response */ - m_handlerTable[14] = dataResponse; /* 14 - array response */ - m_handlerTable[15] = badResponse; /* 15 - cancel request */ - m_handlerTable[16] = dataResponse; /* 16 - process response */ - m_handlerTable[17] = dataResponse; /* 17 - get field response */ - m_handlerTable[18] = new MessageHandler(context), /* 18 - message to Requester */ - m_handlerTable[19] = badResponse; // TODO new MultipleDataResponseHandler(context), /* 19 - grouped monitors */ - m_handlerTable[20] = dataResponse; /* 20 - RPC response */ - m_handlerTable[21] = badResponse; /* 21 */ - m_handlerTable[22] = badResponse; /* 22 */ - m_handlerTable[23] = badResponse; /* 23 */ - m_handlerTable[24] = badResponse; /* 24 */ - m_handlerTable[25] = badResponse; /* 25 */ - m_handlerTable[26] = badResponse; /* 26 */ - m_handlerTable[27] = badResponse; /* 27 */ + ClientResponseHandler(ClientContextImpl::shared_pointer& context) { + ResponseHandler::shared_pointer badResponse(new BadResponse(context)); + ResponseHandler::shared_pointer dataResponse(new DataResponseHandler(context)); + + m_handlerTable.resize(CMD_RPC+1); + + m_handlerTable[CMD_BEACON].reset(new BeaconResponseHandler(context)); /* 0 */ + m_handlerTable[CMD_CONNECTION_VALIDATION].reset(new ClientConnectionValidationHandler(context)); /* 1 */ + m_handlerTable[CMD_ECHO].reset(new NoopResponse(context, "Echo")); /* 2 */ + m_handlerTable[CMD_SEARCH].reset(new NoopResponse(context, "Search")); /* 3 */ + m_handlerTable[CMD_SEARCH_RESPONSE].reset(new SearchResponseHandler(context)); /* 4 */ + m_handlerTable[CMD_INTROSPECTION_SEARCH].reset(new NoopResponse(context, "Introspection search")); /* 5 */ + m_handlerTable[CMD_INTROSPECTION_SEARCH_RESPONSE] = dataResponse; /* 6 - introspection search */ + m_handlerTable[CMD_CREATE_CHANNEL].reset(new CreateChannelHandler(context)); /* 7 */ + m_handlerTable[CMD_DESTROY_CHANNEL].reset(new NoopResponse(context, "Destroy channel")); /* 8 */ // TODO it might be useful to implement this... + m_handlerTable[CMD_RESERVED0] = badResponse; /* 9 */ + m_handlerTable[CMD_GET] = dataResponse; /* 10 - get response */ + m_handlerTable[CMD_PUT] = dataResponse; /* 11 - put response */ + m_handlerTable[CMD_PUT_GET] = dataResponse; /* 12 - put-get response */ + m_handlerTable[CMD_MONITOR] = dataResponse; /* 13 - monitor response */ + m_handlerTable[CMD_ARRAY] = dataResponse; /* 14 - array response */ + m_handlerTable[CMD_CANCEL_REQUEST] = badResponse; /* 15 - cancel request */ + m_handlerTable[CMD_PROCESS] = dataResponse; /* 16 - process response */ + m_handlerTable[CMD_GET_FIELD] = dataResponse; /* 17 - get field response */ + m_handlerTable[CMD_MESSAGE].reset(new MessageHandler(context)); /* 18 - message to Requester */ + m_handlerTable[CMD_MULTIPLE_DATA] = badResponse; // TODO new MultipleDataResponseHandler(context), /* 19 - grouped monitors */ + m_handlerTable[CMD_RPC] = dataResponse; /* 20 - RPC response */ } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { - if (command < 0 || command >= HANDLER_COUNT) + if (command < 0 || command >= (int8)m_handlerTable.size()) { - // TODO context.getLogger().fine("Invalid (or unsupported) command: " + command + "."); - std::cout << "Invalid (or unsupported) command: " << command << "." << std::endl; // TODO remove debug output char buf[100]; - sprintf(buf, "Invalid CA header %d its payload buffer", command); + sprintf(buf, "Invalid CA header %d, its payload", command); hexDump(buf, (const int8*)(payloadBuffer->getArray()), payloadBuffer->getPosition(), payloadSize); return; } @@ -2559,167 +2687,285 @@ namespace epics { PVDATA_REFCOUNT_MONITOR_DEFINE(remoteClientContext); - class InternalClientContextImpl : public ClientContextImpl + class InternalClientContextImpl : + public ClientContextImpl, + public std::tr1::enable_shared_from_this { + + class ChannelProviderImpl; +/* + class ChannelImplFind : public ChannelFind + { + public: + ChannelImplFind(ChannelProvider::shared_pointer provider) : m_provider(provider) + { + } + + virtual void destroy() + { + // one instance for all, do not delete at all + } + + virtual ChannelProvider::shared_pointer getChannelProvider() + { + return m_provider; + }; + + virtual void cancelChannelFind() + { + throw std::runtime_error("not supported"); + } + + private: + + // only to be destroyed by it + friend class ChannelProviderImpl; + virtual ~ChannelImplFind() {} + + ChannelProvider::shared_pointer m_provider; + }; +*/ + class ChannelProviderImpl : public ChannelProvider { + public: + + ChannelProviderImpl(ClientContextImpl* context) : + m_context(context) + { + } + + virtual epics::pvData::String getProviderName() + { + return "pvAccess"; + } + + virtual void destroy() + { + } + + virtual ChannelFind::shared_pointer channelFind( + epics::pvData::String channelName, + ChannelFindRequester::shared_pointer& channelFindRequester) + { + // TODO + m_context->checkChannelName(channelName); + + if (!channelFindRequester.get()) + throw std::runtime_error("null requester"); + + Status errorStatus(Status::STATUSTYPE_ERROR, "not implemented"); + ChannelFind::shared_pointer nullChannelFind; + EXCEPTION_GUARD(channelFindRequester->channelFindResult(errorStatus, nullChannelFind, false)); + return nullChannelFind; + } + + virtual Channel::shared_pointer createChannel( + epics::pvData::String channelName, + ChannelRequester::shared_pointer& channelRequester, + short priority) + { + return createChannel(channelName, channelRequester, priority, emptyString); + } + + virtual Channel::shared_pointer createChannel( + epics::pvData::String channelName, + ChannelRequester::shared_pointer& channelRequester, + short priority, + epics::pvData::String /*address*/) + { + // TODO support addressList + auto_ptr addresses; + Channel::shared_pointer channel = m_context->createChannelInternal(channelName, channelRequester, priority, addresses); + if (channel.get()) + channelRequester->channelCreated(Status::OK, channel); + return channel; + + // NOTE it's up to internal code to respond w/ error to requester and return 0 in case of errors + } + + ~ChannelProviderImpl() {}; + + private: + + ClientContextImpl* m_context; + }; + + + + + + /** * Implementation of CAJ JCA Channel. */ - class InternalChannelImpl : public ChannelImpl { + class InternalChannelImpl : + public ChannelImpl, + public std::tr1::enable_shared_from_this + { private: - + /** * Context. */ - ClientContextImpl* m_context; - + ClientContextImpl::shared_pointer m_context; + /** * Client channel ID. */ pvAccessID m_channelID; - + /** * Channel name. */ String m_name; - + /** * Channel requester. */ - ChannelRequester* m_requester; - + ChannelRequester::shared_pointer m_requester; + /** * Process priority. */ short m_priority; - + /** * List of fixed addresses, if name resolution will be used. */ - InetAddrVector* m_addresses; - + auto_ptr m_addresses; + /** * Connection status. */ ConnectionState m_connectionState; - + /** * List of all channel's pending requests (keys are subscription IDs). */ IOIDResponseRequestMap m_responseRequests; - + /** * Mutex for response requests. */ Mutex m_responseRequestsMutex; - + bool m_needSubscriptionUpdate; - + /** * Allow reconnection flag. */ bool m_allowCreation; - + /** * Reference counting. * NOTE: synced on m_channelMutex. */ int m_references; - + /* ****************** */ /* CA protocol fields */ /* ****************** */ - + /** * Server transport. */ - Transport* m_transport; - + Transport::shared_pointer m_transport; + /** * Server channel ID. */ pvAccessID m_serverChannelID; - + /** * Context sync. mutex. */ Mutex m_channelMutex; - + /** * Flag indicting what message to send. */ bool m_issueCreateMessage; - - private: - ~InternalChannelImpl() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(channel); - if (m_addresses) delete m_addresses; - m_context->release(); - } - - public: - + /** - * Constructor. - * @param context - * @param name - * @param listener - * @throws CAException - */ + * Constructor. + * @param context + * @param name + * @param listener + * @throws CAException + */ InternalChannelImpl( - ClientContextImpl* context, - pvAccessID channelID, - String name, - ChannelRequester* requester, - short priority, - InetAddrVector* addresses) : - m_context(context), - m_channelID(channelID), - m_name(name), - m_requester(requester), - m_priority(priority), - m_addresses(addresses), - m_connectionState(NEVER_CONNECTED), - m_needSubscriptionUpdate(false), - m_allowCreation(true), - m_references(1), - m_transport(0), - m_serverChannelID(0xFFFFFFFF), - m_issueCreateMessage(true) + ClientContextImpl::shared_pointer& context, + pvAccessID channelID, + String& name, + ChannelRequester::shared_pointer& requester, + short priority, + auto_ptr& addresses) : + m_context(context), + m_channelID(channelID), + m_name(name), + m_requester(requester), + m_priority(priority), + m_addresses(addresses), + m_connectionState(NEVER_CONNECTED), + m_needSubscriptionUpdate(false), + m_allowCreation(true), + m_serverChannelID(0xFFFFFFFF), + m_issueCreateMessage(true) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(channel); - + } + + void activate() + { initializeSearchInstance(); - + // register before issuing search request - m_context->acquire(); - m_context->registerChannel(this); - + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + m_context->registerChannel(thisPointer); + // connect connect(); } - + + public: + + static ChannelImpl::shared_pointer create(ClientContextImpl::shared_pointer context, + pvAccessID channelID, + String name, + ChannelRequester::shared_pointer requester, + short priority, + auto_ptr& addresses) + { + ChannelImpl::shared_pointer thisPointer(new InternalChannelImpl(context, channelID, name, requester, priority, addresses), delayed_destroyable_deleter()); + static_cast(thisPointer.get())->activate(); + return thisPointer; + } + + ~InternalChannelImpl() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(channel); + } + virtual void destroy() { - destroy(false); + destroy(false); }; - + virtual String getRequesterName() { return getChannelName(); }; - + virtual void message(String message,MessageType messageType) { std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - - virtual ChannelProvider* getProvider() + + virtual ChannelProvider::shared_pointer getProvider() { return m_context->getProvider(); } - + // NOTE: synchronization guarantees that transport is non-0 and state == CONNECTED. virtual epics::pvData::String getRemoteAddress() { @@ -2733,70 +2979,71 @@ namespace epics { return inetAddressToString(*m_transport->getRemoteAddress()); } } - + virtual epics::pvData::String getChannelName() { return m_name; } - - virtual ChannelRequester* getChannelRequester() + + virtual ChannelRequester::shared_pointer getChannelRequester() { return m_requester; } - + virtual ConnectionState getConnectionState() { Lock guard(m_channelMutex); return m_connectionState; } - + virtual bool isConnected() { return getConnectionState() == CONNECTED; } - - virtual AccessRights getAccessRights(epics::pvData::PVField *pvField) + + virtual AccessRights getAccessRights(std::tr1::shared_ptr&) { return readWrite; } + + virtual pvAccessID getID() { + return m_channelID; + } - /** - * Get client channel ID. - * @return client channel ID. - */ pvAccessID getChannelID() { return m_channelID; } - - virtual ClientContextImpl* getContext() { + + virtual ClientContextImpl::shared_pointer getContext() { return m_context; } - + virtual pvAccessID getSearchInstanceID() { return m_channelID; } - + virtual String getSearchInstanceName() { return m_name; } - + virtual pvAccessID getServerChannelID() { Lock guard(m_channelMutex); return m_serverChannelID; } - - virtual void registerResponseRequest(ResponseRequest* responseRequest) + + virtual void registerResponseRequest(ResponseRequest::shared_pointer& responseRequest) { Lock guard(m_responseRequestsMutex); - m_responseRequests[responseRequest->getIOID()] = responseRequest; + m_responseRequests[responseRequest->getIOID()] = ResponseRequest::weak_pointer(responseRequest); } - - virtual void unregisterResponseRequest(ResponseRequest* responseRequest) + + virtual void unregisterResponseRequest(pvAccessID ioid) { + if (ioid == INVALID_IOID) return; Lock guard(m_responseRequestsMutex); - m_responseRequests.erase(responseRequest->getIOID()); + m_responseRequests.erase(ioid); } - + void connect() { Lock guard(m_channelMutex); // if not destroyed... @@ -2805,7 +3052,7 @@ namespace epics { else if (m_connectionState != CONNECTED) initiateSearch(); } - + void disconnect() { Lock guard(m_channelMutex); // if not destroyed... @@ -2814,28 +3061,32 @@ namespace epics { else if (m_connectionState == CONNECTED) disconnect(false, true); } - + /** - * Create a channel, i.e. submit create channel request to the server. - * This method is called after search is complete. - * @param transport - */ - void createChannel(Transport* transport) + * Create a channel, i.e. submit create channel request to the server. + * This method is called after search is complete. + * @param transport + */ + void createChannel(Transport::shared_pointer& transport) { Lock guard(m_channelMutex); - + // do not allow duplicate creation to the same transport if (!m_allowCreation) return; m_allowCreation = false; - + // check existing transport - if (m_transport && m_transport != transport) + if (m_transport.get() && m_transport.get() != transport.get()) { disconnectPendingIO(false); - - ReferenceCountingTransport* rct = dynamic_cast(m_transport); - if (rct) rct->release(this); + + ReferenceCountingTransport* rct = dynamic_cast(m_transport.get()); + if (rct) + { + //TransportClient::shared_pointer thisPointer = shared_from_this(); + rct->release(getID()); + } } else if (m_transport == transport) { @@ -2843,51 +3094,52 @@ namespace epics { // this happens when server is slower (processing search requests) than client generating it return; } - + m_transport = transport; - m_transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_transport->enqueueSendRequest(thisSender); } - + virtual void cancel() { // noop } - + virtual void timeout() { createChannelFailed(); } - + /** - * Create channel failed. - */ + * Create channel failed. + */ virtual void createChannelFailed() { Lock guard(m_channelMutex); - + cancel(); // ... and search again initiateSearch(); } - + /** - * Called when channel created succeeded on the server. - * sid might not be valid, this depends on protocol revision. - * @param sid - */ + * Called when channel created succeeded on the server. + * sid might not be valid, this depends on protocol revision. + * @param sid + */ virtual void connectionCompleted(pvAccessID sid/*, rights*/) { Lock guard(m_channelMutex); - + bool allOK = false; try { // do this silently if (m_connectionState == DESTROYED) return; - + // store data m_serverChannelID = sid; //setAccessRights(rights); - + // user might create monitors in listeners, so this has to be done before this can happen // however, it would not be nice if events would come before connection event is fired // but this cannot happen since transport (TCP) is serving in this thread @@ -2899,167 +3151,141 @@ namespace epics { // noop // TODO at least log something?? } - + if (!allOK) { // end connection request cancel(); } } - + /** - * @param force force destruction regardless of reference count (not used now) - */ + * @param force force destruction regardless of reference count (not used now) + */ void destroy(bool force) { { - Lock guard(m_channelMutex); - if (m_connectionState == DESTROYED) - return; + Lock guard(m_channelMutex); + if (m_connectionState == DESTROYED) + return; //throw std::runtime_error("Channel already destroyed."); } // do destruction via context - m_context->destroyChannel(this, force); - + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + m_context->destroyChannel(thisPointer, force); } - // NOTE: this is used only to keep instance in memory - // it is not related to channel destroy; not a mechanism to - // allow channel sharing - void acquire() { - Lock guard(m_channelMutex); - m_references++; - } - - virtual void release() { - m_channelMutex.lock(); - m_references--; - m_channelMutex.unlock(); - if (m_references == 0) - { - if (m_transport) - { - // unresponsive state, do not forget to release transport - ReferenceCountingTransport* rct = dynamic_cast(m_transport); - if (rct) rct->release(this); - m_transport = 0; - } - - delete this; - } - } - /** - * Actual destroy method, to be called CAJContext. - * @param force force destruction regardless of reference count - * @throws CAException - * @throws std::runtime_error - * @throws IOException - */ + * Actual destroy method, to be called CAJContext. + * @param force force destruction regardless of reference count + * @throws CAException + * @throws std::runtime_error + * @throws IOException + */ void destroyChannel(bool force) { { Lock guard(m_channelMutex); - + if (m_connectionState == DESTROYED) throw std::runtime_error("Channel already destroyed."); - + // stop searching... m_context->getChannelSearchManager()->unregisterChannel(this); cancel(); - + disconnectPendingIO(true); - + if (m_connectionState == CONNECTED) { disconnect(false, true); - }/* - // transport is release on instance release + } else if (m_transport) { // unresponsive state, do not forget to release transport - ReferenceCountingTransport* rct = dynamic_cast(m_transport); - if (rct) rct->release(this); - m_transport = 0; - }*/ - + ReferenceCountingTransport* rct = dynamic_cast(m_transport.get()); + if (rct) { + //TransportClient::shared_pointer thisPointer = shared_from_this(); + rct->release(getID()); + } + m_transport.reset(); + } + + setConnectionState(DESTROYED); - + // unregister - m_context->unregisterChannel(this); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + m_context->unregisterChannel(thisPointer); } - - // can be delete this - release(); } - + /** - * Disconnected notification. - * @param initiateSearch flag to indicate if searching (connect) procedure should be initiated - * @param remoteDestroy issue channel destroy request. - */ + * Disconnected notification. + * @param initiateSearch flag to indicate if searching (connect) procedure should be initiated + * @param remoteDestroy issue channel destroy request. + */ void disconnect(bool initiateSearch, bool remoteDestroy) { Lock guard(m_channelMutex); - + if (m_connectionState != CONNECTED && !m_transport) return; - + if (!initiateSearch) { // stop searching... m_context->getChannelSearchManager()->unregisterChannel(this); cancel(); } setConnectionState(DISCONNECTED); - + disconnectPendingIO(false); - + // release transport if (m_transport) { if (remoteDestroy) { m_issueCreateMessage = false; - // NOTE: this is neccesary, this holds this channel instance reference - // and keeps it alive so that ResponseRequest reference to this instance - // is valid; otherwise ResponseRequests should acquire this instance - m_transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + m_transport->enqueueSendRequest(thisSender); } - /* - // will be release on this instance release - ReferenceCountingTransport* rct = dynamic_cast(m_transport); - if (rct) rct->release(this); - m_transport = 0; - */ - } + ReferenceCountingTransport* rct = dynamic_cast(m_transport.get()); + if (rct) { + //TransportClient::shared_pointer thisPointer = shared_from_this(); + rct->release(getID()); + } + m_transport.reset(); + } + if (initiateSearch) this->initiateSearch(); - + } - + /** - * Initiate search (connect) procedure. - */ + * Initiate search (connect) procedure. + */ void initiateSearch() { Lock guard(m_channelMutex); - + m_allowCreation = true; - - if (!m_addresses) + + if (!m_addresses.get()) m_context->getChannelSearchManager()->registerChannel(this); /* TODO - else - // TODO not only first - // TODO minor version - // TODO what to do if there is no channel, do not search in a loop!!! do this in other thread...! - searchResponse(CAConstants.CA_MINOR_PROTOCOL_REVISION, addresses[0]); - */ + else + // TODO not only first + // TODO minor version + // TODO what to do if there is no channel, do not search in a loop!!! do this in other thread...! + searchResponse(CAConstants.CA_MINOR_PROTOCOL_REVISION, addresses[0]); + */ } - + virtual void searchResponse(int8 minorRevision, osiSockAddr* serverAddress) { Lock guard(m_channelMutex); - Transport* transport = m_transport; - if (transport) + Transport::shared_pointer transport = m_transport; + if (transport.get()) { // multiple defined PV or reconnect request (same server address) if (!sockAddrAreIdentical(transport->getRemoteAddress(), serverAddress)) @@ -3069,100 +3295,102 @@ namespace epics { return; } } - - transport = m_context->getTransport(this, serverAddress, minorRevision, m_priority); - if (!transport) + + TransportClient::shared_pointer thisPointer = shared_from_this(); + transport = m_context->getTransport(thisPointer, serverAddress, minorRevision, m_priority); + if (!transport.get()) { createChannelFailed(); return; } - + // create channel createChannel(transport); } - + virtual void transportClosed() { disconnect(true, false); } - + virtual void transportChanged() { initiateSearch(); } - - virtual Transport* checkAndGetTransport() + + virtual Transport::shared_pointer checkAndGetTransport() { Lock guard(m_channelMutex); - // TODO C-fy + if (m_connectionState == DESTROYED) throw std::runtime_error("Channel destroyed."); else if (m_connectionState != CONNECTED) throw std::runtime_error("Channel not connected."); - return m_transport; // TODO transport can be 0 !!!!!!!!!! + return m_transport; } - - virtual Transport* getTransport() + + virtual Transport::shared_pointer getTransport() { Lock guard(m_channelMutex); return m_transport; } - - virtual void transportResponsive(Transport* transport) { + + virtual void transportResponsive(Transport::shared_pointer& transport) { Lock guard(m_channelMutex); if (m_connectionState == DISCONNECTED) { updateSubscriptions(); - + // reconnect using existing IDs, data connectionCompleted(m_serverChannelID/*, accessRights*/); } } - + void transportUnresponsive() { Lock guard(m_channelMutex); if (m_connectionState == CONNECTED) { // NOTE: 2 types of disconnected state - distinguish them setConnectionState(DISCONNECTED); - + // ... CA notifies also w/ no access rights callback, although access right are not changed } } - + /** - * Set connection state and if changed, notifies listeners. - * @param newState state to set. - */ + * Set connection state and if changed, notifies listeners. + * @param newState state to set. + */ void setConnectionState(ConnectionState connectionState) { Lock guard(m_channelMutex); if (m_connectionState != connectionState) { m_connectionState = connectionState; - + //bool connectionStatusToReport = (connectionState == CONNECTED); //if (connectionStatusToReport != lastReportedConnectionState) { //lastReportedConnectionState = connectionStatusToReport; // TODO via dispatcher ?!!! - EXCEPTION_GUARD(m_requester->channelStateChange(this, connectionState)); + Channel::shared_pointer thisPointer = shared_from_this(); + EXCEPTION_GUARD(m_requester->channelStateChange(thisPointer, connectionState)); } } } - + virtual void lock() { // noop } - - + + virtual void send(ByteBuffer* buffer, TransportSendControl* control) { m_channelMutex.lock(); bool issueCreateMessage = m_issueCreateMessage; m_channelMutex.unlock(); - + if (issueCreateMessage) { control->startMessage((int8)7, 2+4); - + // count buffer->putShort((int16)1); // array of CIDs and names @@ -3187,150 +3415,171 @@ namespace epics { control->flush(true); } } - + virtual void unlock() { // noop } - - + + /** - * Disconnects (destroys) all channels pending IO. - * @param destroy true if channel is being destroyed. - */ + * Disconnects (destroys) all channels pending IO. + * @param destroy true if channel is being destroyed. + */ void disconnectPendingIO(bool destroy) { Status* status = destroy ? &channelDestroyed : &channelDisconnected; - + Lock guard(m_responseRequestsMutex); - + m_needSubscriptionUpdate = true; - + int count = 0; - ResponseRequest* rrs[m_responseRequests.size()]; + ResponseRequest::weak_pointer rrs[m_responseRequests.size()]; for (IOIDResponseRequestMap::iterator iter = m_responseRequests.begin(); - iter != m_responseRequests.end(); - iter++) + iter != m_responseRequests.end(); + iter++) { rrs[count++] = iter->second; } + ResponseRequest::shared_pointer ptr; for (int i = 0; i< count; i++) { - EXCEPTION_GUARD(rrs[i]->reportStatus(*status)); + if(ptr = rrs[i].lock()) + { + EXCEPTION_GUARD(ptr->reportStatus(*status)); + } } } - + /** - * Resubscribe subscriptions. - */ + * Resubscribe subscriptions. + */ // TODO to be called from non-transport thread !!!!!! void resubscribeSubscriptions() { Lock guard(m_responseRequestsMutex); - - Transport* transport = getTransport(); - + + Transport::shared_pointer transport = getTransport(); + // NOTE: elements cannot be removed within rrs->updateSubscription callbacks for (IOIDResponseRequestMap::iterator iter = m_responseRequests.begin(); - iter != m_responseRequests.end(); - iter++) + iter != m_responseRequests.end(); + iter++) { - SubscriptionRequest* rrs = dynamic_cast(iter->second); - if (rrs) - EXCEPTION_GUARD(rrs->resubscribeSubscription(transport)); + ResponseRequest::shared_pointer ptr = iter->second.lock(); + if (ptr) + { + SubscriptionRequest::shared_pointer rrs = dynamic_pointer_cast(ptr); + if (rrs) + EXCEPTION_GUARD(rrs->resubscribeSubscription(transport)); + } } } - + /** - * Update subscriptions. - */ + * Update subscriptions. + */ // TODO to be called from non-transport thread !!!!!! void updateSubscriptions() { Lock guard(m_responseRequestsMutex); - + if (m_needSubscriptionUpdate) m_needSubscriptionUpdate = false; else return; // noop - + // NOTE: elements cannot be removed within rrs->updateSubscription callbacks for (IOIDResponseRequestMap::iterator iter = m_responseRequests.begin(); - iter != m_responseRequests.end(); - iter++) + iter != m_responseRequests.end(); + iter++) { - SubscriptionRequest* rrs = dynamic_cast(iter->second); - if (rrs) - EXCEPTION_GUARD(rrs->updateSubscription()); + ResponseRequest::shared_pointer ptr = iter->second.lock(); + if (ptr) + { + SubscriptionRequest::shared_pointer rrs = dynamic_pointer_cast(ptr); + if (rrs) + EXCEPTION_GUARD(rrs->updateSubscription()); + } } } - - virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) + + virtual void getField(GetFieldRequester::shared_pointer& requester,epics::pvData::String subField) { - new ChannelGetFieldRequestImpl(this, requester, subField); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + ChannelGetFieldRequestImpl::create(thisPointer, requester, subField); } - - virtual ChannelProcess* createChannelProcess( - ChannelProcessRequester *channelProcessRequester, - epics::pvData::PVStructure *pvRequest) + + virtual ChannelProcess::shared_pointer createChannelProcess( + ChannelProcessRequester::shared_pointer& channelProcessRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelProcessRequestImpl(this, channelProcessRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelProcessRequestImpl::create(thisPointer, channelProcessRequester, pvRequest); } - - virtual ChannelGet* createChannelGet( - ChannelGetRequester *channelGetRequester, - epics::pvData::PVStructure *pvRequest) + + virtual ChannelGet::shared_pointer createChannelGet( + ChannelGetRequester::shared_pointer& channelGetRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelGetImpl(this, channelGetRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelGetImpl::create(thisPointer, channelGetRequester, pvRequest); } - - virtual ChannelPut* createChannelPut( - ChannelPutRequester *channelPutRequester, - epics::pvData::PVStructure *pvRequest) + + virtual ChannelPut::shared_pointer createChannelPut( + ChannelPutRequester::shared_pointer& channelPutRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelPutImpl(this, channelPutRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelPutImpl::create(thisPointer, channelPutRequester, pvRequest); } - - virtual ChannelPutGet* createChannelPutGet( - ChannelPutGetRequester *channelPutGetRequester, - epics::pvData::PVStructure *pvRequest) + + virtual ChannelPutGet::shared_pointer createChannelPutGet( + ChannelPutGetRequester::shared_pointer& channelPutGetRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelPutGetImpl(this, channelPutGetRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelPutGetImpl::create(thisPointer, channelPutGetRequester, pvRequest); } - - virtual ChannelRPC* createChannelRPC(ChannelRPCRequester *channelRPCRequester, - epics::pvData::PVStructure *pvRequest) + + virtual ChannelRPC::shared_pointer createChannelRPC( + ChannelRPCRequester::shared_pointer& channelRPCRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelRPCImpl(this, channelRPCRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelRPCImpl::create(thisPointer, channelRPCRequester, pvRequest); } - - virtual epics::pvData::Monitor* createMonitor( - epics::pvData::MonitorRequester *monitorRequester, - epics::pvData::PVStructure *pvRequest) + + virtual epics::pvData::Monitor::shared_pointer createMonitor( + epics::pvData::MonitorRequester::shared_pointer& monitorRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelMonitorImpl(this, monitorRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelMonitorImpl::create(thisPointer, monitorRequester, pvRequest); } - - virtual ChannelArray* createChannelArray( - ChannelArrayRequester *channelArrayRequester, - epics::pvData::PVStructure *pvRequest) + + virtual ChannelArray::shared_pointer createChannelArray( + ChannelArrayRequester::shared_pointer& channelArrayRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new ChannelArrayImpl(this, channelArrayRequester, pvRequest); + ChannelImpl::shared_pointer thisPointer = shared_from_this(); + return ChannelArrayImpl::create(thisPointer, channelArrayRequester, pvRequest); } - - - + + + virtual void printInfo() { String info; printInfo(&info); std::cout << info.c_str() << std::endl; } - + virtual void printInfo(epics::pvData::StringBuilder out) { //Lock lock(m_channelMutex); //std::ostringstream ostr; //static String emptyString; - + out->append( "CHANNEL : "); out->append(m_name); out->append("\nSTATE : "); out->append(ConnectionStateNames[m_connectionState]); if (m_connectionState == CONNECTED) @@ -3341,118 +3590,36 @@ namespace epics { out->append("\n"); } }; + + + + + - - class ChannelProviderImpl; - - class ChannelImplFind : public ChannelFind - { - public: - ChannelImplFind(ChannelProvider* provider) : m_provider(provider) - { - } - - virtual void destroy() - { - // one instance for all, do not delete at all - } - - virtual ChannelProvider* getChannelProvider() - { - return m_provider; - }; - - virtual void cancelChannelFind() - { - throw std::runtime_error("not supported"); - } - - private: - - // only to be destroyed by it - friend class ChannelProviderImpl; - virtual ~ChannelImplFind() {} - - ChannelProvider* m_provider; - }; - - class ChannelProviderImpl : public ChannelProvider { - public: - - ChannelProviderImpl(ClientContextImpl* context) : - m_context(context) { - } - - virtual epics::pvData::String getProviderName() - { - return "pvAccess"; - } - - virtual void destroy() - { - delete this; - } - - virtual ChannelFind* channelFind( - epics::pvData::String channelName, - ChannelFindRequester *channelFindRequester) - { - m_context->checkChannelName(channelName); - - if (!channelFindRequester) - throw std::runtime_error("0 requester"); - - Status errorStatus(Status::STATUSTYPE_ERROR, "not implemented", 0); - channelFindRequester->channelFindResult(errorStatus, 0, false); - return 0; - } - - virtual Channel* createChannel( - epics::pvData::String channelName, - ChannelRequester *channelRequester, - short priority) - { - return createChannel(channelName, channelRequester, priority, emptyString); - } - - virtual Channel* createChannel( - epics::pvData::String channelName, - ChannelRequester *channelRequester, - short priority, - epics::pvData::String address) - { - // TODO support addressList - Channel* channel = m_context->createChannelInternal(channelName, channelRequester, priority, 0); - if (channel) - channelRequester->channelCreated(Status::OK, channel); - return channel; - - // NOTE it's up to internal code to respond w/ error to requester and return 0 in case of errors - } - - private: - ~ChannelProviderImpl() {}; - - /* TODO static*/ String emptyString; - ClientContextImpl* m_context; - }; - - public: + private: + InternalClientContextImpl() : m_addressList(""), m_autoAddressList(true), m_connectionTimeout(30.0f), m_beaconPeriod(15.0f), - m_broadcastPort(CA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), m_timer(0), - m_broadcastTransport(0), m_searchTransport(0), m_connector(0), m_transportRegistry(0), - m_namedLocker(0), m_lastCID(0), m_lastIOID(0), m_channelSearchManager(0), - m_version(new Version("CA Client", "cpp", 1, 0, 0, 0)), - m_provider(new ChannelProviderImpl(this)), - m_contextState(CONTEXT_NOT_INITIALIZED), m_configuration(new SystemConfigurationImpl()), - m_refCount(1) + m_broadcastPort(CA_BROADCAST_PORT), m_receiveBufferSize(MAX_TCP_RECV), + m_namedLocker(), m_lastCID(0), m_lastIOID(0), + m_version("CA Client", "cpp", 1, 0, 0, 0), + m_contextState(CONTEXT_NOT_INITIALIZED), + m_configuration(new SystemConfigurationImpl()) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(remoteClientContext); + m_provider.reset(new ChannelProviderImpl(this)); loadConfiguration(); } - virtual Configuration* getConfiguration() { + public: + + static InternalClientContextImpl::shared_pointer create() + { + InternalClientContextImpl::shared_pointer thisPointer(new InternalClientContextImpl(), delayed_destroyable_deleter()); + return thisPointer; + } + + virtual Configuration::shared_pointer getConfiguration() { /* TODO final ConfigurationProvider configurationProvider = ConfigurationFactory.getProvider(); @@ -3464,30 +3631,30 @@ TODO return m_configuration; } - virtual Version* getVersion() { + virtual Version& getVersion() { return m_version; } - virtual ChannelProvider* getProvider() { - Lock lock(m_contextMutex); + virtual ChannelProvider::shared_pointer getProvider() { + //Lock lock(m_contextMutex); return m_provider; } - virtual Timer* getTimer() + virtual Timer::shared_pointer getTimer() { - Lock lock(m_contextMutex); + //Lock lock(m_contextMutex); return m_timer; } - virtual TransportRegistry* getTransportRegistry() + virtual TransportRegistry::shared_pointer getTransportRegistry() { - Lock lock(m_contextMutex); + //Lock lock(m_contextMutex); return m_transportRegistry; } - virtual BlockingUDPTransport* getSearchTransport() + virtual Transport::shared_pointer getSearchTransport() { - Lock lock(m_contextMutex); + //Lock lock(m_contextMutex); return m_searchTransport; } @@ -3516,7 +3683,7 @@ TODO static String emptyString; out->append( "CLASS : ::epics::pvAccess::ClientContextImpl"); - out->append("\nVERSION : "); out->append(m_version->getVersionString()); + out->append("\nVERSION : "); out->append(m_version.getVersionString()); out->append("\nADDR_LIST : "); ostr << m_addressList; out->append(ostr.str()); ostr.str(emptyString); out->append("\nAUTO_ADDR_LIST : "); out->append(m_autoAddressList ? "true" : "false"); out->append("\nCONNECTION_TIMEOUT : "); ostr << m_connectionTimeout; out->append(ostr.str()); ostr.str(emptyString); @@ -3547,10 +3714,7 @@ TODO Lock guard(m_contextMutex); if (m_contextState == CONTEXT_DESTROYED) - { - m_contextMutex.unlock(); - throw std::runtime_error("Context already destroyed."); - } + return; // go into destroyed state ASAP m_contextState = CONTEXT_DESTROYED; @@ -3561,51 +3725,19 @@ TODO virtual void dispose() { - // TODO try catch - destroy(); + try { + destroy(); + } catch (std::exception& ex) { printf("dispose(): %s\n", ex.what()); // tODO remove + } catch (...) { /* TODO log with low level */ } } - virtual void acquire() { - Lock guard(m_contextMutex); - m_refCount++; - } - - virtual void release() { - m_contextMutex.lock(); - m_refCount--; - m_contextMutex.unlock(); - if (m_refCount == 0) - delete this; - } - - private: ~InternalClientContextImpl() { PVDATA_REFCOUNT_MONITOR_DESTRUCT(remoteClientContext); - - // stop searching - if (m_channelSearchManager) - delete m_channelSearchManager; //->destroy(); - - // stop timer - if (m_timer) - delete m_timer; - - // TODO destroy !!! - if (m_broadcastTransport) - delete m_broadcastTransport; //->destroy(true); - if (m_searchTransport) - delete m_searchTransport; //->destroy(true); - - if (m_namedLocker) delete m_namedLocker; - if (m_transportRegistry) delete m_transportRegistry; - if (m_connector) delete m_connector; - if (m_configuration) delete m_configuration; - - m_provider->destroy(); - delete m_version; }; + private: + void loadConfiguration() { m_addressList = m_configuration->getPropertyAsString("EPICS4_CA_ADDR_LIST", m_addressList); m_autoAddressList = m_configuration->getPropertyAsBoolean("EPICS4_CA_AUTO_ADDR_LIST", m_autoAddressList); @@ -3617,17 +3749,17 @@ TODO void internalInitialize() { - m_timer = new Timer("pvAccess-client timer", lowPriority); - m_connector = new BlockingTCPConnector(this, m_receiveBufferSize, m_beaconPeriod); - m_transportRegistry = new TransportRegistry(); - m_namedLocker = new NamedLockPattern(); + m_timer.reset(new Timer("pvAccess-client timer", lowPriority)); + Context::shared_pointer thisPointer = shared_from_this(); + m_connector.reset(new BlockingTCPConnector(thisPointer, m_receiveBufferSize, m_beaconPeriod)); + m_transportRegistry.reset(new TransportRegistry()); // setup UDP transport initializeUDPTransport(); // TODO what if initialization failed!!! // setup search manager - m_channelSearchManager = new ChannelSearchManager(this); + m_channelSearchManager.reset(new ChannelSearchManager(thisPointer.get())); } /** @@ -3661,13 +3793,18 @@ TODO listenLocalAddress.ia.sin_family = AF_INET; listenLocalAddress.ia.sin_port = htons(m_broadcastPort); listenLocalAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); + + ClientContextImpl::shared_pointer thisPointer = shared_from_this(); + TransportClient::shared_pointer nullTransportClient; + + auto_ptr clientResponseHandler(new ClientResponseHandler(thisPointer)); auto_ptr broadcastConnector(new BlockingUDPConnector(true, true)); - m_broadcastTransport = (BlockingUDPTransport*)broadcastConnector->connect( - 0, new ClientResponseHandler(this), + m_broadcastTransport = static_pointer_cast(broadcastConnector->connect( + nullTransportClient, clientResponseHandler, listenLocalAddress, CA_MINOR_PROTOCOL_REVISION, - CA_DEFAULT_PRIORITY); - if (!m_broadcastTransport) + CA_DEFAULT_PRIORITY)); + if (!m_broadcastTransport.get()) return false; m_broadcastTransport->setBroadcastAddresses(broadcastAddresses.get()); @@ -3677,12 +3814,13 @@ TODO undefinedAddress.ia.sin_port = htons(0); undefinedAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); + clientResponseHandler.reset(new ClientResponseHandler(thisPointer)); auto_ptr searchConnector(new BlockingUDPConnector(false, true)); - m_searchTransport = (BlockingUDPTransport*)searchConnector->connect( - 0, new ClientResponseHandler(this), + m_searchTransport = static_pointer_cast(searchConnector->connect( + nullTransportClient, clientResponseHandler, undefinedAddress, CA_MINOR_PROTOCOL_REVISION, - CA_DEFAULT_PRIORITY); - if (!m_searchTransport) + CA_DEFAULT_PRIORITY)); + if (!m_searchTransport.get()) return false; m_searchTransport->setBroadcastAddresses(broadcastAddresses.get()); @@ -3702,14 +3840,16 @@ TODO // this will also close all CA transports destroyAllChannels(); - release(); + // stop UDPs + m_searchTransport->close(true); + m_broadcastTransport->close(true); } void destroyAllChannels() { Lock guard(m_cidMapMutex); int count = 0; - ChannelImpl* channels[m_channelsByCID.size()]; + ChannelImpl::weak_pointer channels[m_channelsByCID.size()]; for (CIDChannelMap::iterator iter = m_channelsByCID.begin(); iter != m_channelsByCID.end(); iter++) @@ -3717,9 +3857,14 @@ TODO channels[count++] = iter->second; } - for (int i = 0; i< count; i++) + ChannelImpl::shared_pointer ptr; + for (int i = 0; i < count; i++) { - EXCEPTION_GUARD(channels[i]->destroy()); + ptr = channels[i].lock(); + if (ptr) + { + EXCEPTION_GUARD(ptr->destroy()); + } } } @@ -3749,17 +3894,17 @@ TODO * Register channel. * @param channel */ - void registerChannel(ChannelImpl* channel) + void registerChannel(ChannelImpl::shared_pointer& channel) { Lock guard(m_cidMapMutex); - m_channelsByCID[channel->getChannelID()] = channel; + m_channelsByCID[channel->getChannelID()] = ChannelImpl::weak_pointer(channel); } /** * Unregister channel. * @param channel */ - void unregisterChannel(ChannelImpl* channel) + void unregisterChannel(ChannelImpl::shared_pointer& channel) { Lock guard(m_cidMapMutex); m_channelsByCID.erase(channel->getChannelID()); @@ -3770,11 +3915,11 @@ TODO * @param channelID CID. * @return channel with given CID, 0 if non-existent. */ - ChannelImpl* getChannel(pvAccessID channelID) + Channel::shared_pointer getChannel(pvAccessID channelID) { Lock guard(m_cidMapMutex); CIDChannelMap::iterator it = m_channelsByCID.find(channelID); - return (it == m_channelsByCID.end() ? 0 : it->second); + return (it == m_channelsByCID.end() ? Channel::shared_pointer() : static_pointer_cast(it->second.lock())); } /** @@ -3788,7 +3933,7 @@ TODO // search first free (theoretically possible loop of death) while (m_channelsByCID.find(++m_lastCID) != m_channelsByCID.end()); // reserve CID - m_channelsByCID[m_lastCID] = 0; + m_channelsByCID[m_lastCID].reset(); return m_lastCID; } @@ -3807,14 +3952,12 @@ TODO * @param ioid I/O ID. * @return request response with given I/O ID. */ - ResponseRequest* getResponseRequest(pvAccessID ioid) + ResponseRequest::shared_pointer getResponseRequest(pvAccessID ioid) { Lock guard(m_ioidMapMutex); IOIDResponseRequestMap::iterator it = m_pendingResponseRequests.find(ioid); - if (it == m_pendingResponseRequests.end()) return 0; - ResponseRequest* rr = it->second; - rr->acquire(); - return rr; + if (it == m_pendingResponseRequests.end()) return ResponseRequest::shared_pointer(); + return it->second.lock(); } /** @@ -3822,11 +3965,11 @@ TODO * @param request request to register. * @return request ID (IOID). */ - pvAccessID registerResponseRequest(ResponseRequest* request) + pvAccessID registerResponseRequest(ResponseRequest::shared_pointer& request) { Lock guard(m_ioidMapMutex); pvAccessID ioid = generateIOID(); - m_pendingResponseRequests[ioid] = request; + m_pendingResponseRequests[ioid] = ResponseRequest::weak_pointer(request); return ioid; } @@ -3835,14 +3978,16 @@ TODO * @param request * @return removed object, can be 0 */ - ResponseRequest* unregisterResponseRequest(ResponseRequest* request) + ResponseRequest::shared_pointer unregisterResponseRequest(pvAccessID ioid) { - Lock guard(m_ioidMapMutex); - IOIDResponseRequestMap::iterator it = m_pendingResponseRequests.find(request->getIOID()); - if (it == m_pendingResponseRequests.end()) - return 0; + if (ioid == INVALID_IOID) return ResponseRequest::shared_pointer(); - ResponseRequest* retVal = it->second; + Lock guard(m_ioidMapMutex); + IOIDResponseRequestMap::iterator it = m_pendingResponseRequests.find(ioid); + if (it == m_pendingResponseRequests.end()) + return ResponseRequest::shared_pointer(); + + ResponseRequest::shared_pointer retVal = it->second.lock(); m_pendingResponseRequests.erase(it); return retVal; } @@ -3855,11 +4000,13 @@ TODO { Lock guard(m_ioidMapMutex); - // search first free (theoretically possible loop of death) - while (m_pendingResponseRequests.find(++m_lastIOID) != m_pendingResponseRequests.end()); + do { + while (m_pendingResponseRequests.find(++m_lastIOID) != m_pendingResponseRequests.end()); + } while (m_lastIOID == INVALID_IOID); + // reserve IOID - m_pendingResponseRequests[m_lastIOID] = 0; + m_pendingResponseRequests[m_lastIOID].reset(); return m_lastIOID; } @@ -3877,15 +4024,14 @@ TODO * @param responseFrom remote source address of received beacon. * @return beacon handler for particular server. */ - BeaconHandler* getBeaconHandler(osiSockAddr* responseFrom) + BeaconHandler::shared_pointer getBeaconHandler(osiSockAddr* responseFrom) { - // TODO delete handlers Lock guard(m_beaconMapMutex); AddressBeaconHandlerMap::iterator it = m_beaconHandlers.find(*responseFrom); - BeaconHandler* handler; + BeaconHandler::shared_pointer handler; if (it == m_beaconHandlers.end()) { - handler = new BeaconHandler(this, responseFrom); + handler.reset(new BeaconHandler(shared_from_this(), responseFrom)); m_beaconHandlers[*responseFrom] = handler; } else @@ -3899,17 +4045,19 @@ TODO * @param priority process priority. * @return transport for given address */ - Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) + Transport::shared_pointer getTransport(TransportClient::shared_pointer& client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) { try { - return m_connector->connect(client, new ClientResponseHandler(this), *serverAddress, minorRevision, priority); + ClientContextImpl::shared_pointer thisPointer = shared_from_this(); + auto_ptr handler(new ClientResponseHandler(thisPointer)); + return m_connector->connect(client, handler, *serverAddress, minorRevision, priority); } catch (...) { // TODO log //printf("failed to get transport\n"); - return 0; + return Transport::shared_pointer(); } } @@ -3918,8 +4066,8 @@ TODO */ // TODO no minor version with the addresses // TODO what if there is an channel with the same name, but on different host! - ChannelImpl* createChannelInternal(String name, ChannelRequester* requester, short priority, - InetAddrVector* addresses) { // TODO addresses + ChannelImpl::shared_pointer createChannelInternal(String name, ChannelRequester::shared_pointer& requester, short priority, + auto_ptr& addresses) { // TODO addresses checkState(); checkChannelName(name); @@ -3936,11 +4084,12 @@ TODO try { pvAccessID cid = generateCID(); - return new InternalChannelImpl(this, cid, name, requester, priority, addresses); + ClientContextImpl::shared_pointer thisPointer = shared_from_this(); + return InternalChannelImpl::create(thisPointer, cid, name, requester, priority, addresses); } catch(...) { // TODO - return 0; + return ChannelImpl::shared_pointer(); } // TODO namedLocker.releaseSynchronizationObject(name); } @@ -3958,7 +4107,7 @@ TODO * @throws CAException * @throws std::runtime_error */ - void destroyChannel(ChannelImpl* channel, bool force) { + void destroyChannel(ChannelImpl::shared_pointer& channel, bool force) { String name = channel->getChannelName(); bool lockAcquired = true; //namedLocker->acquireSynchronizationObject(name, LOCK_TIMEOUT); @@ -3984,7 +4133,7 @@ TODO * Get channel search manager. * @return channel search manager. */ - ChannelSearchManager* getChannelSearchManager() { + ChannelSearchManager::shared_pointer getChannelSearchManager() { return m_channelSearchManager; } @@ -4025,33 +4174,33 @@ TODO /** * Timer. */ - Timer* m_timer; + Timer::shared_pointer m_timer; /** * Broadcast transport needed to listen for broadcasts. */ - BlockingUDPTransport* m_broadcastTransport; + BlockingUDPTransport::shared_pointer m_broadcastTransport; /** * UDP transport needed for channel searches. */ - BlockingUDPTransport* m_searchTransport; + BlockingUDPTransport::shared_pointer m_searchTransport; /** * CA connector (creates CA virtual circuit). */ - BlockingTCPConnector* m_connector; + auto_ptr m_connector; /** * CA transport (virtual circuit) registry. * This registry contains all active transports - connections to CA servers. */ - TransportRegistry* m_transportRegistry; + TransportRegistry::shared_pointer m_transportRegistry; /** * Context instance. */ - NamedLockPattern* m_namedLocker; + NamedLockPattern m_namedLocker; /** * Context instance. @@ -4062,7 +4211,7 @@ TODO * Map of channels (keys are CIDs). */ // TODO consider std::unordered_map - typedef std::map CIDChannelMap; + typedef std::map CIDChannelMap; CIDChannelMap m_channelsByCID; /** @@ -4078,8 +4227,6 @@ TODO /** * Map of pending response requests (keys are IOID). */ - // TODO consider std::unordered_map - typedef std::map IOIDResponseRequestMap; IOIDResponseRequestMap m_pendingResponseRequests; /** @@ -4096,13 +4243,13 @@ TODO * Channel search manager. * Manages UDP search requests. */ - ChannelSearchManager* m_channelSearchManager; + ChannelSearchManager::shared_pointer m_channelSearchManager; /** * Beacon handler map. */ // TODO consider std::unordered_map - typedef std::map AddressBeaconHandlerMap; + typedef std::map AddressBeaconHandlerMap; AddressBeaconHandlerMap m_beaconHandlers; /** @@ -4113,12 +4260,12 @@ TODO /** * Version. */ - Version* m_version; + Version m_version; /** * Provider implementation. */ - ChannelProviderImpl* m_provider; + ChannelProviderImpl::shared_pointer m_provider; /** * Context state. @@ -4132,14 +4279,16 @@ TODO friend class ChannelProviderImpl; - Configuration* m_configuration; + Configuration::shared_pointer m_configuration; int m_refCount; }; - ClientContextImpl* createClientContextImpl() + ClientContextImpl::shared_pointer createClientContextImpl() { - return new InternalClientContextImpl(); + ClientContextImpl::shared_pointer ptr = InternalClientContextImpl::create(); + return ptr; } }}; + diff --git a/pvAccessApp/remoteClient/clientContextImpl.h b/pvAccessApp/remoteClient/clientContextImpl.h index b62be12..c64f941 100644 --- a/pvAccessApp/remoteClient/clientContextImpl.h +++ b/pvAccessApp/remoteClient/clientContextImpl.h @@ -10,8 +10,11 @@ #include #include +#include #include +class ChannelSearchManager; + namespace epics { namespace pvAccess { @@ -25,17 +28,22 @@ namespace epics { public BaseSearchInstance { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + typedef std::tr1::weak_ptr weak_pointer; + typedef std::tr1::weak_ptr const_weak_pointer; + virtual pvAccessID getChannelID() = 0; virtual void destroyChannel(bool force) = 0; virtual void connectionCompleted(pvAccessID sid/*, rights*/) = 0; virtual void createChannelFailed() = 0; - virtual ClientContextImpl* getContext() = 0; + virtual std::tr1::shared_ptr getContext() = 0; virtual pvAccessID getServerChannelID() = 0; - virtual void registerResponseRequest(ResponseRequest* responseRequest) = 0; - virtual void unregisterResponseRequest(ResponseRequest* responseRequest) = 0; - virtual Transport* checkAndGetTransport() = 0; - virtual Transport* getTransport() = 0; + virtual void registerResponseRequest(ResponseRequest::shared_pointer& responseRequest) = 0; + virtual void unregisterResponseRequest(pvAccessID ioid) = 0; + virtual Transport::shared_pointer checkAndGetTransport() = 0; + virtual Transport::shared_pointer getTransport() = 0; static Status channelDestroyed; static Status channelDisconnected; @@ -45,29 +53,34 @@ namespace epics { class ClientContextImpl : public ClientContext, public Context { public: - virtual ChannelSearchManager* getChannelSearchManager() = 0; + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + typedef std::tr1::weak_ptr weak_pointer; + typedef std::tr1::weak_ptr const_weak_pointer; + + virtual ChannelSearchManager::shared_pointer getChannelSearchManager() = 0; virtual void checkChannelName(String& name) = 0; - virtual void registerChannel(ChannelImpl* channel) = 0; - virtual void unregisterChannel(ChannelImpl* channel) = 0; + virtual void registerChannel(ChannelImpl::shared_pointer& channel) = 0; + virtual void unregisterChannel(ChannelImpl::shared_pointer& channel) = 0; - virtual void destroyChannel(ChannelImpl* channel, bool force) = 0; - virtual ChannelImpl* createChannelInternal(String name, ChannelRequester* requester, short priority, InetAddrVector* addresses) = 0; + virtual void destroyChannel(ChannelImpl::shared_pointer& channel, bool force) = 0; + virtual ChannelImpl::shared_pointer createChannelInternal(String name, ChannelRequester::shared_pointer& requester, short priority, std::auto_ptr& addresses) = 0; - virtual ResponseRequest* getResponseRequest(pvAccessID ioid) = 0; - virtual pvAccessID registerResponseRequest(ResponseRequest* request) = 0; - virtual ResponseRequest* unregisterResponseRequest(ResponseRequest* request) = 0; + virtual ResponseRequest::shared_pointer getResponseRequest(pvAccessID ioid) = 0; + virtual pvAccessID registerResponseRequest(ResponseRequest::shared_pointer& request) = 0; + virtual ResponseRequest::shared_pointer unregisterResponseRequest(pvAccessID ioid) = 0; - virtual Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) = 0; + virtual Transport::shared_pointer getTransport(TransportClient::shared_pointer& client, osiSockAddr* serverAddress, int16 minorRevision, int16 priority) = 0; virtual void beaconAnomalyNotify() = 0; - virtual BeaconHandler* getBeaconHandler(osiSockAddr* responseFrom) = 0; + virtual std::tr1::shared_ptr getBeaconHandler(osiSockAddr* responseFrom) = 0; }; - extern ClientContextImpl* createClientContextImpl(); + extern ClientContextImpl::shared_pointer createClientContextImpl(); } } diff --git a/pvAccessApp/server/baseChannelRequester.cpp b/pvAccessApp/server/baseChannelRequester.cpp index 665844f..a675799 100644 --- a/pvAccessApp/server/baseChannelRequester.cpp +++ b/pvAccessApp/server/baseChannelRequester.cpp @@ -18,7 +18,11 @@ const Status BaseChannelRequester::otherRequestPendingStatus = Status(Status::ST const int32 BaseChannelRequester::NULL_REQUEST = -1; -BaseChannelRequester::BaseChannelRequester(ServerContextImpl* context, ServerChannelImpl* channel,const pvAccessID ioid, Transport* transport) : +BaseChannelRequester::BaseChannelRequester( + ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, + Transport::shared_pointer& transport) : _ioid(ioid), _transport(transport), _channel(channel), @@ -63,14 +67,16 @@ void BaseChannelRequester::message(const String message, const epics::pvData::Me BaseChannelRequester::message(_transport, _ioid, message, messageType); } -void BaseChannelRequester::message(Transport* transport, const pvAccessID ioid, const String message, const MessageType messageType) +void BaseChannelRequester::message(Transport::shared_pointer& transport, const pvAccessID ioid, const String message, const MessageType messageType) { - transport->enqueueSendRequest(new BaseChannelRequesterMessageTransportSender(ioid, message, messageType)); + TransportSender::shared_pointer sender(new BaseChannelRequesterMessageTransportSender(ioid, message, messageType)); + transport->enqueueSendRequest(sender); } -void BaseChannelRequester::sendFailureMessage(const int8 command, Transport* transport, const pvAccessID ioid, const int8 qos, const Status status) +void BaseChannelRequester::sendFailureMessage(const int8 command, Transport::shared_pointer& transport, const pvAccessID ioid, const int8 qos, const Status status) { - transport->enqueueSendRequest(new BaseChannelRequesterFailureMessageTransportSender(command, transport, ioid, qos, status)); + TransportSender::shared_pointer sender(new BaseChannelRequesterFailureMessageTransportSender(command, transport, ioid, qos, status)); + transport->enqueueSendRequest(sender); } BaseChannelRequesterMessageTransportSender::BaseChannelRequesterMessageTransportSender(const pvAccessID ioid, const String message,const epics::pvData::MessageType messageType): @@ -98,18 +104,8 @@ void BaseChannelRequesterMessageTransportSender::unlock() // noop } -void BaseChannelRequesterMessageTransportSender::release() -{ - delete this; -} - -void BaseChannelRequesterMessageTransportSender::acquire() -{ - // noop -} - BaseChannelRequesterFailureMessageTransportSender::BaseChannelRequesterFailureMessageTransportSender(const int8 command, - Transport* transport, const pvAccessID ioid, const int8 qos, const Status status) : + Transport::shared_pointer& transport, const pvAccessID ioid, const int8 qos, const Status& status) : _command(command), _ioid(ioid), _qos(qos), @@ -136,15 +132,6 @@ void BaseChannelRequesterFailureMessageTransportSender::unlock() // noop } -void BaseChannelRequesterFailureMessageTransportSender::release() -{ - delete this; -} - -void BaseChannelRequesterFailureMessageTransportSender::acquire() -{ - // noop -} } } diff --git a/pvAccessApp/server/baseChannelRequester.h b/pvAccessApp/server/baseChannelRequester.h index f7a9799..29f4882 100644 --- a/pvAccessApp/server/baseChannelRequester.h +++ b/pvAccessApp/server/baseChannelRequester.h @@ -17,16 +17,17 @@ namespace pvAccess { class BaseChannelRequester : virtual public epics::pvData::Requester, public epics::pvData::Destroyable { public: - BaseChannelRequester(ServerContextImpl* context, ServerChannelImpl* channel,const pvAccessID ioid, Transport* transport); - ~BaseChannelRequester() {}; + BaseChannelRequester(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport); + virtual ~BaseChannelRequester() {}; - boolean startRequest(int32 qos); + bool startRequest(int32 qos); void stopRequest(); int32 getPendingRequest(); String getRequesterName(); void message(const String message, const epics::pvData::MessageType messageType); - static void message(Transport* transport, const pvAccessID ioid, const String message, const epics::pvData::MessageType messageType); - static void sendFailureMessage(const int8 command, Transport* transport, const pvAccessID ioid, const int8 qos, const Status status); + static void message(Transport::shared_pointer& transport, const pvAccessID ioid, const String message, const epics::pvData::MessageType messageType); + static void sendFailureMessage(const int8 command, Transport::shared_pointer& transport, const pvAccessID ioid, const int8 qos, const Status status); static const Status okStatus; static const Status badCIDStatus; @@ -37,11 +38,11 @@ public: static const Status otherRequestPendingStatus; protected: const pvAccessID _ioid; - Transport* _transport; - ServerChannelImpl* _channel; + Transport::shared_pointer _transport; + ServerChannelImpl::shared_pointer _channel; epics::pvData::Mutex _mutex; private: - ServerContextImpl* _context; + ServerContextImpl::shared_pointer _context; static const int32 NULL_REQUEST; int32 _pendingRequest; }; @@ -53,8 +54,6 @@ public: void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); void lock(); void unlock(); - void release(); - void acquire(); private: const pvAccessID _ioid; const String _message; @@ -64,19 +63,17 @@ private: class BaseChannelRequesterFailureMessageTransportSender : public TransportSender { public: - BaseChannelRequesterFailureMessageTransportSender(const int8 command, Transport* transport, const pvAccessID ioid, const int8 qos, const Status status); + BaseChannelRequesterFailureMessageTransportSender(const int8 command, Transport::shared_pointer& transport, const pvAccessID ioid, const int8 qos, const Status& status); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); void lock(); void unlock(); - void release(); - void acquire(); private: const int8 _command; const pvAccessID _ioid; const int8 _qos; const Status _status; - Transport* _transport; + Transport::shared_pointer _transport; }; } diff --git a/pvAccessApp/server/beaconEmitter.cpp b/pvAccessApp/server/beaconEmitter.cpp new file mode 100644 index 0000000..bdc3b0d --- /dev/null +++ b/pvAccessApp/server/beaconEmitter.cpp @@ -0,0 +1,146 @@ +/* + * beaconEmitter.cpp + */ + +#include "beaconEmitter.h" + +#include + +#include +#include + +#include + +using namespace std; + +namespace epics { namespace pvAccess { + +const float BeaconEmitter::EPICS_CA_MIN_BEACON_PERIOD = 1.0; +const float BeaconEmitter::EPICS_CA_MIN_BEACON_COUNT_LIMIT = 3.0; + +//BeaconEmitter::BeaconEmitter(Transport::shared_pointer& transport, ServerContextImpl::shared_pointer& context) : +BeaconEmitter::BeaconEmitter(Transport::shared_pointer& transport, std::tr1::shared_ptr& context) : + _transport(transport), + _beaconSequenceID(0), + _startupTime(), + _fastBeaconPeriod(std::max(context->getBeaconPeriod(), EPICS_CA_MIN_BEACON_PERIOD)), + _slowBeaconPeriod(std::max(180.0, _fastBeaconPeriod)), // TODO configurable + _beaconCountLimit((int16)std::max(10.0f, EPICS_CA_MIN_BEACON_COUNT_LIMIT)), // TODO configurable + _serverAddress(*(context->getServerInetAddress())), + _serverPort(context->getServerPort()), + _serverStatusProvider(context->getBeaconServerStatusProvider()), + _timer(context->getTimer()), + _timerNode(*this) +{ + _startupTime.getCurrent(); +} + +BeaconEmitter::BeaconEmitter(Transport::shared_pointer& transport, const osiSockAddr& serverAddress) : + _transport(transport), + _beaconSequenceID(0), + _startupTime(), + _fastBeaconPeriod(EPICS_CA_MIN_BEACON_PERIOD), + _slowBeaconPeriod(180.0), + _beaconCountLimit(10), + _serverAddress(serverAddress), + _serverPort(serverAddress.ia.sin_port), + _serverStatusProvider(), + _timer(new Timer("pvAccess-server timer", lowPriority)), + _timerNode(*this) +{ + _startupTime.getCurrent(); +} + +BeaconEmitter::~BeaconEmitter() +{ + destroy(); +} + +void BeaconEmitter::lock() +{ + //noop +} + +void BeaconEmitter::unlock() +{ + //noop +} + +void BeaconEmitter::send(ByteBuffer* buffer, TransportSendControl* control) +{ + // get server status + PVField::shared_pointer serverStatus; + if(_serverStatusProvider.get()) + { + try + { + serverStatus = _serverStatusProvider->getServerStatusData(); + } + catch (...) { + // we have to proctect internal code from external implementation... + errlogSevPrintf(errlogMinor, "BeaconServerStatusProvider implementation thrown an exception."); + } + } + + // send beacon + control->startMessage((int8)0, (sizeof(int16)+2*sizeof(int32)+128+sizeof(int16))/sizeof(int8)); + + buffer->putShort(_beaconSequenceID); + buffer->putLong((int64)_startupTime.getSecondsPastEpoch()); + buffer->putInt((int32)_startupTime.getNanoSeconds()); + + // NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0 + encodeAsIPv6Address(buffer, &_serverAddress); + buffer->putShort((int16)_serverPort); + + if (serverStatus) + { + // introspection interface + data + IntrospectionRegistry::serializeFull(serverStatus->getField(), buffer, control); + serverStatus->serialize(buffer, control); + } + else + { + IntrospectionRegistry::serializeFull(FieldConstPtr(), buffer, control); + } + control->flush(true); + + // increment beacon sequence ID + _beaconSequenceID++; + + reschedule(); +} + +void BeaconEmitter::timerStopped() +{ + //noop +} + +void BeaconEmitter::destroy() +{ + _timerNode.cancel(); +} + +void BeaconEmitter::start() +{ + _timer->scheduleAfterDelay(_timerNode, 0.0); +} + +void BeaconEmitter::reschedule() +{ + const double period = (_beaconSequenceID >= _beaconCountLimit) ? _slowBeaconPeriod : _fastBeaconPeriod; + if (period > 0) + { + _timer->scheduleAfterDelay(_timerNode, period); + } +} + +void BeaconEmitter::callback() +{ + // requires this instance has already a valid pointer to this + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); +} + +}} + diff --git a/pvAccessApp/remote/beaconEmitter.h b/pvAccessApp/server/beaconEmitter.h similarity index 59% rename from pvAccessApp/remote/beaconEmitter.h rename to pvAccessApp/server/beaconEmitter.h index 423a10e..bb8c864 100644 --- a/pvAccessApp/remote/beaconEmitter.h +++ b/pvAccessApp/server/beaconEmitter.h @@ -5,83 +5,76 @@ #ifndef BEACONEMITTER_H #define BEACONEMITTER_H -#include "timer.h" -#include "remote.h" -#include "beaconServerStatusProvider.h" -#include "inetAddressUtil.h" -#include "introspectionRegistry.h" -#include "serverContext.h" - - +#include #include +#include + #include -#include -#include -#include - -using namespace epics::pvData; +#include +//#include +#include namespace epics { namespace pvAccess { - class ServerContextImpl; + class ServerContextImpl; /** * BeaconEmitter * * @author gjansa */ - class BeaconEmitter: public TransportSender, public TimerCallback + class BeaconEmitter: + public TransportSender, + public epics::pvData::TimerCallback, + public std::tr1::enable_shared_from_this { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + /** * Constructor. * @param transport transport to be used to send beacons. * @param context CA context. */ - BeaconEmitter(Transport* transport, ServerContextImpl* context); - /** +// BeaconEmitter(Transport::shared_pointer& transport, ServerContextImpl::shared_pointer& context); + BeaconEmitter(Transport::shared_pointer& transport, std::tr1::shared_ptr& context); + + /** * Test Constructor (ohne context) * @param transport transport to be used to send beacons. */ - BeaconEmitter(Transport* transport,const osiSockAddr* serverAddress); + BeaconEmitter(Transport::shared_pointer& transport, const osiSockAddr& serverAddress); + virtual ~BeaconEmitter(); - /* - * @see TransportSender#lock() - */ void lock(); - /* - * @see TransportSender#unlock() - */ void unlock(); - void acquire(); - void release(); - void send(ByteBuffer* buffer, TransportSendControl* control); - /** - * noop - */ + void timerStopped(); - /** - * noop - */ - void destroy(); + /** * Start emitting. */ void start(); - /** + + /** * Reschedule timer. */ void reschedule(); - /** + + /** * Timer callback. */ void callback(); - private: + void destroy(); + + private: + /** * Minimal (initial) CA beacon period (in seconds). */ @@ -92,15 +85,10 @@ namespace epics { namespace pvAccess { */ static const float EPICS_CA_MIN_BEACON_COUNT_LIMIT; - /** - * Timer. - */ - Timer* _timer; - /** * Transport. */ - Transport* _transport; + Transport::shared_pointer _transport; /** * Beacon sequence ID. @@ -110,7 +98,7 @@ namespace epics { namespace pvAccess { /** * Startup timestamp (when clients detect a change, they will consider server restarted). */ - TimeStamp* _startupTime; + epics::pvData::TimeStamp _startupTime; /** * Fast (at startup) beacon period (in sec). @@ -130,7 +118,7 @@ namespace epics { namespace pvAccess { /** * Server address. */ - const osiSockAddr* _serverAddress; + const osiSockAddr _serverAddress; /** * Server port. @@ -140,14 +128,19 @@ namespace epics { namespace pvAccess { /** * Server status provider implementation (optional). */ - BeaconServerStatusProvider* _serverStatusProvider; + BeaconServerStatusProvider::shared_pointer _serverStatusProvider; + + /** + * Timer. + */ + Timer::shared_pointer _timer; /** * Timer task node. */ - TimerNode* _timerNode; + epics::pvData::TimerNode _timerNode; }; }} -#endif /* INTROSPECTIONREGISTRY_H */ +#endif /* BEACONEMITTER_H */ diff --git a/pvAccessApp/remote/beaconServerStatusProvider.cpp b/pvAccessApp/server/beaconServerStatusProvider.cpp similarity index 53% rename from pvAccessApp/remote/beaconServerStatusProvider.cpp rename to pvAccessApp/server/beaconServerStatusProvider.cpp index 28fc9ed..be30f46 100644 --- a/pvAccessApp/remote/beaconServerStatusProvider.cpp +++ b/pvAccessApp/server/beaconServerStatusProvider.cpp @@ -3,30 +3,23 @@ */ #include "beaconServerStatusProvider.h" +#include + +using namespace epics::pvData; namespace epics { namespace pvAccess { -BeaconServerStatusProvider::BeaconServerStatusProvider( ServerContext* context): _context(context) -{ - if(context == NULL) - { - THROW_BASE_EXCEPTION("null context"); - } - initialize(); -} - -BeaconServerStatusProvider::BeaconServerStatusProvider() +DefaultBeaconServerStatusProvider::DefaultBeaconServerStatusProvider(ServerContext::shared_pointer& context): _context(context) { initialize(); } -BeaconServerStatusProvider::~BeaconServerStatusProvider() +DefaultBeaconServerStatusProvider::~DefaultBeaconServerStatusProvider() { } -void BeaconServerStatusProvider::initialize() +void DefaultBeaconServerStatusProvider::initialize() { - PVDataCreate* pvDataCreate = getPVDataCreate(); FieldCreate* fieldCreate = getFieldCreate(); FieldConstPtrArray fields = new FieldConstPtr[6]; // TODO hierarchy can be used... @@ -37,13 +30,13 @@ void BeaconServerStatusProvider::initialize() fields[4] = fieldCreate->createScalar("deadlocks",pvInt); fields[5] = fieldCreate->createScalar("averageSystemLoad",pvDouble); - _status = pvDataCreate->createPVStructure(NULL,"status",6,fields); + _status.reset(getPVDataCreate()->createPVStructure(0,"status",6,fields)); } -PVFieldPtr BeaconServerStatusProvider::getServerStatusData() +PVField::shared_pointer DefaultBeaconServerStatusProvider::getServerStatusData() { - //TODO implement - return static_cast(_status); + //TODO implement (fill data) + return _status; } }} diff --git a/pvAccessApp/server/beaconServerStatusProvider.h b/pvAccessApp/server/beaconServerStatusProvider.h new file mode 100644 index 0000000..1e6c6d6 --- /dev/null +++ b/pvAccessApp/server/beaconServerStatusProvider.h @@ -0,0 +1,65 @@ +/* + * beaconServerStatusProvider.h + */ + +#ifndef BEACONSERVERSTATUSPROVIDER_H +#define BEACONSERVERSTATUSPROVIDER_H + +#include +//#include +#include + +namespace epics { namespace pvAccess { + + class ServerContext; + + /** + * BeaconServerStatusProvider + */ + class BeaconServerStatusProvider + { + public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + /** + * Gets server status data. + */ + virtual epics::pvData::PVField::shared_pointer getServerStatusData() = 0; + }; + + /** + * DefaultBeaconServerStatusProvider + */ + class DefaultBeaconServerStatusProvider : public BeaconServerStatusProvider + { + public: + /** + * Constructor. + * @param context CA context. + */ +// DefaultBeaconServerStatusProvider(ServerContext::shared_pointer& context); + DefaultBeaconServerStatusProvider(std::tr1::shared_ptr& context); + /** + * Destructor. + */ + virtual ~DefaultBeaconServerStatusProvider(); + + virtual epics::pvData::PVField::shared_pointer getServerStatusData(); + + private: + /** + * Initialize + */ + void initialize(); + + + private: + epics::pvData::PVStructure::shared_pointer _status; + std::tr1::shared_ptr _context; + //ServerContext::shared_pointer _context; + }; + +}} + +#endif /* BEACONSERVERSTATUSPROVIDER_H */ diff --git a/pvAccessApp/server/referencedTransportSender.cpp b/pvAccessApp/server/referencedTransportSender.cpp deleted file mode 100644 index cc240c4..0000000 --- a/pvAccessApp/server/referencedTransportSender.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * referencedTransportSender.cpp - */ - -#include "referencedTransportSender.h" - -using namespace epics::pvData; - -namespace epics { namespace pvAccess { - -ReferencedTransportSender::ReferencedTransportSender() : - _refCount(1) -{} - -ReferencedTransportSender::~ReferencedTransportSender() -{ -} - -void ReferencedTransportSender::release() -{ - _refMutex.lock(); - _refCount--; - _refMutex.unlock(); - if (_refCount == 0) - { - delete this; - } -} - -void ReferencedTransportSender::acquire() -{ - Lock guard(_refMutex); - _refCount++; -} - -} -} diff --git a/pvAccessApp/server/referencedTransportSender.h b/pvAccessApp/server/referencedTransportSender.h deleted file mode 100644 index 5d764b0..0000000 --- a/pvAccessApp/server/referencedTransportSender.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * referencedTransportSender.h - */ - -#ifndef REFERENCEDTRANSPORTSENDER_H_ -#define REFERENCEDTRANSPORTSENDER_H_ - -#include "remote.h" - -namespace epics { -namespace pvAccess { - -class ReferencedTransportSender : public TransportSender -{ -public: - ReferencedTransportSender(); - virtual ~ReferencedTransportSender(); - void release(); - void acquire(); -private: - epics::pvData::Mutex _refMutex; - int32 _refCount; -}; - -} -} - - -#endif /* REFERENCEDTRANSPORTSENDER_H_ */ diff --git a/pvAccessApp/server/responseHandlers.cpp b/pvAccessApp/server/responseHandlers.cpp index f38a7c8..737572a 100644 --- a/pvAccessApp/server/responseHandlers.cpp +++ b/pvAccessApp/server/responseHandlers.cpp @@ -1,13 +1,10 @@ /* * responseHandlers.cpp - * - * Created on: Jan 4, 2011 - * Author: Miha Vitorovic */ #include "responseHandlers.h" -#include "remote.h" -#include "hexDump.h" +#include +#include #include @@ -19,14 +16,18 @@ using std::ostringstream; using std::hex; +using std::tr1::dynamic_pointer_cast; +using std::tr1::static_pointer_cast; + using namespace epics::pvData; namespace epics { namespace pvAccess { void ServerBadResponse::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -39,68 +40,45 @@ void ServerBadResponse::handleResponse(osiSockAddr* responseFrom, } -ServerResponseHandler::ServerResponseHandler(ServerContextImpl* context) { - // TODO replace with auto_ptr and vector - _badResponse = new ServerBadResponse(context); - - _handlerTable = new ResponseHandler*[HANDLER_TABLE_LENGTH]; - _handlerTable[0] = new ServerNoopResponse(context, "Beacon"); - _handlerTable[1] = new ServerConnectionValidationHandler(context); - _handlerTable[2] = new ServerEchoHandler(context); - _handlerTable[3] = new ServerSearchHandler(context); - _handlerTable[4] = _badResponse; - _handlerTable[5] = new ServerIntrospectionSearchHandler(context); - _handlerTable[6] = _badResponse; - _handlerTable[7] = new ServerCreateChannelHandler(context); - _handlerTable[8] = new ServerDestroyChannelHandler(context); - _handlerTable[9] = _badResponse; - _handlerTable[10] = new ServerGetHandler(context); - _handlerTable[11] = new ServerPutHandler(context); - _handlerTable[12] = new ServerPutGetHandler(context); - _handlerTable[13] = new ServerMonitorHandler(context); - _handlerTable[14] = new ServerArrayHandler(context); - _handlerTable[15] = new ServerCancelRequestHandler(context); - _handlerTable[16] = new ServerProcessHandler(context); - _handlerTable[17] = new ServerGetFieldHandler(context); - _handlerTable[18] = _badResponse; - _handlerTable[19] = _badResponse; - _handlerTable[20] = new ServerRPCHandler(context); - _handlerTable[21] = _badResponse; - _handlerTable[22] = _badResponse; - _handlerTable[23] = _badResponse; - _handlerTable[24] = _badResponse; - _handlerTable[25] = _badResponse; - _handlerTable[26] = _badResponse; - _handlerTable[27] = _badResponse; -} - -ServerResponseHandler::~ServerResponseHandler() { - delete _badResponse; - delete _handlerTable[0]; - delete _handlerTable[1]; - delete _handlerTable[2]; - delete _handlerTable[3]; - delete _handlerTable[5]; - delete _handlerTable[7]; - delete _handlerTable[8]; - delete _handlerTable[10]; - delete _handlerTable[11]; - delete _handlerTable[12]; - delete _handlerTable[13]; - delete _handlerTable[14]; - delete _handlerTable[15]; - delete _handlerTable[16]; - delete _handlerTable[17]; - delete _handlerTable[20]; - delete[] _handlerTable; +ServerResponseHandler::ServerResponseHandler(ServerContextImpl::shared_pointer& context) +{ + ResponseHandler::shared_pointer badResponse(new ServerBadResponse(context)); + + m_handlerTable.resize(CMD_RPC+1); + + m_handlerTable[CMD_BEACON].reset(new ServerNoopResponse(context, "Beacon")); /* 0 */ + m_handlerTable[CMD_CONNECTION_VALIDATION].reset(new ServerConnectionValidationHandler(context)); /* 1 */ + m_handlerTable[CMD_ECHO].reset(new ServerEchoHandler(context)); /* 2 */ + m_handlerTable[CMD_SEARCH].reset(new ServerSearchHandler(context)); /* 3 */ + m_handlerTable[CMD_SEARCH_RESPONSE] = badResponse; + m_handlerTable[CMD_INTROSPECTION_SEARCH].reset(new ServerIntrospectionSearchHandler(context)); /* 5 */ + m_handlerTable[CMD_INTROSPECTION_SEARCH_RESPONSE] = badResponse; /* 6 - introspection search */ + m_handlerTable[CMD_CREATE_CHANNEL].reset(new ServerCreateChannelHandler(context)); /* 7 */ + m_handlerTable[CMD_DESTROY_CHANNEL].reset(new ServerDestroyChannelHandler(context)); /* 8 */ + m_handlerTable[CMD_RESERVED0] = badResponse; /* 9 */ + + m_handlerTable[CMD_GET].reset(new ServerGetHandler(context)); /* 10 - get response */ + m_handlerTable[CMD_PUT].reset(new ServerPutHandler(context)); /* 11 - put response */ + m_handlerTable[CMD_PUT_GET].reset(new ServerPutGetHandler(context)); /* 12 - put-get response */ + m_handlerTable[CMD_MONITOR].reset(new ServerMonitorHandler(context)); /* 13 - monitor response */ + m_handlerTable[CMD_ARRAY].reset(new ServerArrayHandler(context)); /* 14 - array response */ + m_handlerTable[CMD_CANCEL_REQUEST].reset(new ServerCancelRequestHandler(context)); /* 15 - cancel request */ + m_handlerTable[CMD_PROCESS].reset(new ServerProcessHandler(context)); /* 16 - process response */ + m_handlerTable[CMD_GET_FIELD].reset(new ServerGetFieldHandler(context)); /* 17 - get field response */ + m_handlerTable[CMD_MESSAGE] = badResponse; /* 18 - message to Requester */ + m_handlerTable[CMD_MULTIPLE_DATA] = badResponse; /* 19 - grouped monitors */ + m_handlerTable[CMD_RPC].reset(new ServerRPCHandler(context)); /* 20 - RPC response */ } void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { - if(command<0||command>=HANDLER_TABLE_LENGTH) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ + if(command<0||command>=(int8)m_handlerTable.size()) + { errlogSevPrintf(errlogMinor, "Invalid (or unsupported) command: %x.", (0xFF&command)); + // TODO remove debug output ostringstream name; name<<"Invalid CA header "<handleResponse(responseFrom, transport, + m_handlerTable[command]->handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); } void ServerConnectionValidationHandler::handleResponse( - osiSockAddr* responseFrom, Transport* transport, int8 version, + osiSockAddr* responseFrom, Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, - ByteBuffer* payloadBuffer) { + ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -134,22 +113,21 @@ void ServerConnectionValidationHandler::handleResponse( } void ServerEchoHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); - EchoTransportSender* echoReply = new EchoTransportSender(responseFrom); - - // send back + // send back + TransportSender::shared_pointer echoReply(new EchoTransportSender(responseFrom)); transport->enqueueSendRequest(echoReply); - - echoReply->release(); } void ServerIntrospectionSearchHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -158,21 +136,19 @@ void ServerIntrospectionSearchHandler::handleResponse(osiSockAddr* responseFrom, /****************************************************************************************/ -ServerSearchHandler::ServerSearchHandler(ServerContextImpl* context) : - AbstractServerResponseHandler(context, "Search request") - { - _provider = context->getChannelProvider(); - _objectPool = new ServerChannelFindRequesterImplObjectPool(context); - } +ServerSearchHandler::ServerSearchHandler(ServerContextImpl::shared_pointer& context) : + AbstractServerResponseHandler(context, "Search request"), _provider(context->getChannelProvider()) +{ +} ServerSearchHandler::~ServerSearchHandler() { - if(_objectPool) delete _objectPool; } void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -186,17 +162,21 @@ void ServerSearchHandler::handleResponse(osiSockAddr* responseFrom, { transport->ensureData(sizeof(int32)/sizeof(int8)); const int32 cid = payloadBuffer->getInt(); - const String name = SerializeHelper::deserializeString(payloadBuffer, transport); + const String name = SerializeHelper::deserializeString(payloadBuffer, transport.get()); // no name check here... - _provider->channelFind(name, _objectPool->get()->set(searchSequenceId, cid, responseFrom, responseRequired)); + // TODO object pool!!! + ServerChannelFindRequesterImpl* pr = new ServerChannelFindRequesterImpl(_context); + pr->set(searchSequenceId, cid, responseFrom, responseRequired); + ChannelFindRequester::shared_pointer spr(pr); + + _provider->channelFind(name, spr); } } -ServerChannelFindRequesterImpl::ServerChannelFindRequesterImpl(ServerContextImpl* context, ServerChannelFindRequesterImplObjectPool* objectPool) : +ServerChannelFindRequesterImpl::ServerChannelFindRequesterImpl(ServerContextImpl::shared_pointer& context) : _sendTo(NULL), - _context(context), - _objectPool(objectPool) + _context(context) {} void ServerChannelFindRequesterImpl::clear() @@ -215,14 +195,15 @@ ServerChannelFindRequesterImpl* ServerChannelFindRequesterImpl::set(int32 search return this; } -void ServerChannelFindRequesterImpl::channelFindResult(const Status& status, ChannelFind* channelFind, bool wasFound) +void ServerChannelFindRequesterImpl::channelFindResult(const Status& status, ChannelFind::shared_pointer& channelFind, bool wasFound) { // TODO status Lock guard(_mutex); if (wasFound || _responseRequired) { _wasFound = wasFound; - _context->getBroadcastTransport()->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _context->getBroadcastTransport()->enqueueSendRequest(thisSender); } } @@ -252,52 +233,13 @@ void ServerChannelFindRequesterImpl::send(ByteBuffer* buffer, TransportSendContr buffer->putInt(_cid); control->setRecipient(*_sendTo); - - // return this object to the pool - _objectPool->put(this); -} - -ServerChannelFindRequesterImplObjectPool::ServerChannelFindRequesterImplObjectPool(ServerContextImpl* context) : - _context(context) -{} - -ServerChannelFindRequesterImplObjectPool::~ServerChannelFindRequesterImplObjectPool() -{ - for(std::vector::iterator iter = _elements.begin(); - iter != _elements.end(); iter++) - { - delete *iter; - } - _elements.erase(_elements.begin(), _elements.end()); -} - -ServerChannelFindRequesterImpl* ServerChannelFindRequesterImplObjectPool::get() -{ - Lock guard(_mutex); - const int32 count = _elements.size(); - if (count == 0) - { - return new ServerChannelFindRequesterImpl(_context, this); - } - else - { - ServerChannelFindRequesterImpl* channelFindRequesterImpl = _elements.back(); - _elements.pop_back(); - return channelFindRequesterImpl; - } -} - -void ServerChannelFindRequesterImplObjectPool::put(ServerChannelFindRequesterImpl* element) -{ - Lock guard(_mutex); - element->clear(); - _elements.push_back(element); } /****************************************************************************************/ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); @@ -310,7 +252,7 @@ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom, } const pvAccessID cid = payloadBuffer->getInt(); - String channelName = SerializeHelper::deserializeString(payloadBuffer, transport); + String channelName = SerializeHelper::deserializeString(payloadBuffer, transport.get()); if (channelName.size() == 0) { @@ -329,35 +271,44 @@ void ServerCreateChannelHandler::handleResponse(osiSockAddr* responseFrom, return; } - // TODO memory leak... - ChannelRequester* cr = new ServerChannelRequesterImpl(transport, channelName, cid); - _provider->createChannel(channelName, cr, transport->getPriority()); + ServerChannelRequesterImpl::create(_provider, transport, channelName, cid); } -void ServerCreateChannelHandler::disconnect(Transport* transport) +void ServerCreateChannelHandler::disconnect(Transport::shared_pointer& transport) { transport->close(true); } -ServerChannelRequesterImpl::ServerChannelRequesterImpl(Transport* transport, const String channelName, const pvAccessID cid) : - _transport(transport), - _channelName(channelName), - _cid(cid), - _status(), - _channel(NULL) +ServerChannelRequesterImpl::ServerChannelRequesterImpl(Transport::shared_pointer& transport, + const String channelName, const pvAccessID cid) : + _transport(transport), + _channelName(channelName), + _cid(cid), + _status(), + _channel() { - } -void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel* channel) +ChannelRequester::shared_pointer ServerChannelRequesterImpl::create( + ChannelProvider::shared_pointer& provider, Transport::shared_pointer& transport, + const String channelName, const pvAccessID cid) +{ + ChannelRequester::shared_pointer cr(new ServerChannelRequesterImpl(transport, channelName, cid)); + // TODO exception guard and report error back + provider->createChannel(channelName, cr, transport->getPriority()); + return cr; +} + +void ServerChannelRequesterImpl::channelCreated(const Status& status, Channel::shared_pointer& channel) { Lock guard(_mutex); _status = status; _channel = channel; - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } -void ServerChannelRequesterImpl::channelStateChange(Channel* c, const Channel::ConnectionState isConnected) +void ServerChannelRequesterImpl::channelStateChange(Channel::shared_pointer& c, const Channel::ConnectionState isConnected) { //noop } @@ -386,27 +337,30 @@ void ServerChannelRequesterImpl::unlock() void ServerChannelRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { - Channel* channel; + Channel::shared_pointer channel; Status status; { Lock guard(_mutex); channel = _channel; status = _status; + + // TODO + _channel.reset(); } // error response - if (channel == NULL) + if (channel.get() == NULL) { createChannelFailedResponse(buffer, control, status); } // OK else { - ServerChannelImpl* serverChannel = NULL; + ServerChannel::shared_pointer serverChannel; try { // NOTE: we do not explicitly check if transport OK - ChannelHostingTransport* casTransport = dynamic_cast(_transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(_transport); // // create a new channel instance @@ -414,7 +368,8 @@ void ServerChannelRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* pvAccessID sid = casTransport->preallocateChannelSID(); try { - serverChannel = new ServerChannelImpl(channel, _cid, sid, casTransport->getSecurityToken()); + epics::pvData::PVField::shared_pointer securityToken = casTransport->getSecurityToken(); + serverChannel.reset(new ServerChannelImpl(channel, _cid, sid, securityToken)); // ack allocation and register casTransport->registerChannel(sid, serverChannel); @@ -435,19 +390,13 @@ void ServerChannelRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* { errlogSevPrintf(errlogMinor, "Exception caught when creating channel: %s", _channelName.c_str()); createChannelFailedResponse(buffer, control, Status(Status::STATUSTYPE_FATAL, "failed to create channel", e.what())); - if (serverChannel != NULL) - { - serverChannel->destroy(); - } + // TODO make sure that serverChannel gets destroyed } catch (...) { errlogSevPrintf(errlogMinor, "Exception caught when creating channel: %s", _channelName.c_str()); createChannelFailedResponse(buffer, control, Status(Status::STATUSTYPE_FATAL, "failed to create channel")); - if (serverChannel != NULL) - { - serverChannel->destroy(); - } + // TODO make sure that serverChannel gets destroyed } } } @@ -464,13 +413,14 @@ void ServerChannelRequesterImpl::createChannelFailedResponse(ByteBuffer* buffer, /****************************************************************************************/ void ServerDestroyChannelHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)); @@ -478,8 +428,8 @@ void ServerDestroyChannelHandler::handleResponse(osiSockAddr* responseFrom, const pvAccessID cid = payloadBuffer->getInt(); // get channel by SID - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); - if (channel == NULL) + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); + if (channel.get() == NULL) { if (!transport->isClosed()) { @@ -497,21 +447,21 @@ void ServerDestroyChannelHandler::handleResponse(osiSockAddr* responseFrom, casTransport->unregisterChannel(sid); // send response back - ServerDestroyChannelHandlerTransportSender* sr = new ServerDestroyChannelHandlerTransportSender(cid, sid); + TransportSender::shared_pointer sr(new ServerDestroyChannelHandlerTransportSender(cid, sid)); transport->enqueueSendRequest(sr); - sr->release(); } /****************************************************************************************/ void ServerGetHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, - int payloadSize, ByteBuffer* payloadBuffer) { + Transport::shared_pointer& transport, int8 version, int8 command, + int payloadSize, ByteBuffer* payloadBuffer) +{ AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -520,8 +470,8 @@ void ServerGetHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); - if (channel == NULL) + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); + if (channel.get() == NULL) { BaseChannelRequester::sendFailureMessage((int8)10, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; @@ -531,28 +481,25 @@ void ServerGetHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructurePtr pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerChannelGetRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerChannelGetRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { const bool lastRequest = (QOS_DESTROY & qosCode) != 0; - ServerChannelGetRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerChannelGetRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)10, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_GET, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } if (!request->startRequest(qosCode)) { - BaseChannelRequester::sendFailureMessage((int8)10, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_GET, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); return; } @@ -566,27 +513,39 @@ void ServerGetHandler::handleResponse(osiSockAddr* responseFrom, } \ catch (std::exception &e) { \ Status status(Status::STATUSTYPE_FATAL, e.what()); \ - BaseChannelRequester::sendFailureMessage((int8)cmd, transport, ioid, (int8)QOS_INIT, status); \ + BaseChannelRequester::sendFailureMessage((int8)cmd, _transport, _ioid, (int8)QOS_INIT, status); \ destroy(); \ } \ catch (...) { \ Status status(Status::STATUSTYPE_FATAL, "unknown exception caught"); \ - BaseChannelRequester::sendFailureMessage((int8)cmd, transport, ioid, (int8)QOS_INIT, status); \ + BaseChannelRequester::sendFailureMessage((int8)cmd, _transport, _ioid, (int8)QOS_INIT, status); \ destroy(); \ } -ServerChannelGetRequesterImpl::ServerChannelGetRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport, - PVStructurePtr pvRequest) : - BaseChannelRequester(context, channel, ioid, transport), _channelGet(0), _bitSet(0), _pvStructure(0) +ServerChannelGetRequesterImpl::ServerChannelGetRequesterImpl(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, Transport::shared_pointer& transport) : + BaseChannelRequester(context, channel, ioid, transport), _channelGet(), _bitSet(), _pvStructure() { - startRequest(QOS_INIT); - channel->registerRequest(ioid, this); - INIT_EXCEPTION_GUARD(10, _channelGet = channel->getChannel()->createChannelGet(this, pvRequest)); } -void ServerChannelGetRequesterImpl::channelGetConnect(const Status& status, ChannelGet* channelGet, PVStructurePtr pvStructure, - BitSet* bitSet) +ChannelGetRequester::shared_pointer ServerChannelGetRequesterImpl::create(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, Transport::shared_pointer& transport, +PVStructure::shared_pointer& pvRequest) +{ + ChannelGetRequester::shared_pointer thisPointer(new ServerChannelGetRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerChannelGetRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + ChannelGetRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_GET, _channelGet = _channel->getChannel()->createChannelGet(thisPointer, pvRequest)); +} + +void ServerChannelGetRequesterImpl::channelGetConnect(const Status& status, ChannelGet::shared_pointer& channelGet, PVStructure::shared_pointer& pvStructure, BitSet::shared_pointer& bitSet) { { Lock guard(_mutex); @@ -595,7 +554,8 @@ void ServerChannelGetRequesterImpl::channelGetConnect(const Status& status, Chan _status = status; _channelGet = channelGet; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -610,7 +570,8 @@ void ServerChannelGetRequesterImpl::getDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelGetRequesterImpl::destroy() @@ -623,10 +584,9 @@ void ServerChannelGetRequesterImpl::destroy() _channelGet->destroy(); } } - release(); } -ChannelGet* ServerChannelGetRequesterImpl::getChannelGet() +ChannelGet::shared_pointer ServerChannelGetRequesterImpl::getChannelGet() { return _channelGet; } @@ -659,13 +619,13 @@ void ServerChannelGetRequesterImpl::send(ByteBuffer* buffer, TransportSendContro if (request & QOS_INIT) { Lock guard(_mutex); - introspectionRegistry->serialize(_pvStructure != NULL ? _pvStructure->getField() : NULL, buffer, control); + introspectionRegistry->serialize(_pvStructure != NULL ? _pvStructure->getField() : FieldConstPtr(), buffer, control); } else { _bitSet->serialize(buffer, control); - _pvStructure->serialize(buffer, control, _bitSet); + _pvStructure->serialize(buffer, control, _bitSet.get()); } } @@ -679,14 +639,14 @@ void ServerChannelGetRequesterImpl::send(ByteBuffer* buffer, TransportSendContro } /****************************************************************************************/ void ServerPutHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -695,10 +655,10 @@ void ServerPutHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { - BaseChannelRequester::sendFailureMessage((int8)11, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PUT, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; } @@ -706,29 +666,26 @@ void ServerPutHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructure* pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerChannelPutRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerChannelPutRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { const bool lastRequest = (QOS_DESTROY & qosCode) != 0; const bool get = (QOS_GET & qosCode) != 0; - ServerChannelPutRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerChannelPutRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)11, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PUT, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } if (!request->startRequest(qosCode)) { - BaseChannelRequester::sendFailureMessage((int8)11, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PUT, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); return; } @@ -740,24 +697,38 @@ void ServerPutHandler::handleResponse(osiSockAddr* responseFrom, else { // deserialize bitSet and do a put - BitSet* putBitSet = request->getBitSet(); - putBitSet->deserialize(payloadBuffer, transport); - request->getPVStructure()->deserialize(payloadBuffer, transport, putBitSet); + BitSet::shared_pointer putBitSet = request->getBitSet(); + putBitSet->deserialize(payloadBuffer, transport.get()); + request->getPVStructure()->deserialize(payloadBuffer, transport.get(), putBitSet.get()); request->getChannelPut()->put(lastRequest); } } } -ServerChannelPutRequesterImpl::ServerChannelPutRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, - const pvAccessID ioid, Transport* transport,PVStructure* pvRequest): - BaseChannelRequester(context, channel, ioid, transport), _channelPut(0), _bitSet(0), _pvStructure(0) +ServerChannelPutRequesterImpl::ServerChannelPutRequesterImpl(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport): + BaseChannelRequester(context, channel, ioid, transport), _channelPut(), _bitSet(), _pvStructure() { - startRequest(QOS_INIT); - channel->registerRequest(ioid, static_cast(this)); - INIT_EXCEPTION_GUARD(11, _channelPut = channel->getChannel()->createChannelPut(this, pvRequest)); } -void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, ChannelPut* channelPut, PVStructure* pvStructure, BitSet* bitSet) +ChannelPutRequester::shared_pointer ServerChannelPutRequesterImpl::create(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport, PVStructure::shared_pointer& pvRequest) +{ + ChannelPutRequester::shared_pointer thisPointer(new ServerChannelPutRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerChannelPutRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + ChannelPutRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_PUT, _channelPut = _channel->getChannel()->createChannelPut(thisPointer, pvRequest)); +} + +void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, ChannelPut::shared_pointer& channelPut, PVStructure::shared_pointer& pvStructure, BitSet::shared_pointer& bitSet) { { Lock guard(_mutex); @@ -767,7 +738,8 @@ void ServerChannelPutRequesterImpl::channelPutConnect(const Status& status, Chan _channelPut = channelPut; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -782,7 +754,8 @@ void ServerChannelPutRequesterImpl::putDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelPutRequesterImpl::getDone(const Status& status) @@ -791,7 +764,8 @@ void ServerChannelPutRequesterImpl::getDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelPutRequesterImpl::lock() @@ -814,24 +788,23 @@ void ServerChannelPutRequesterImpl::destroy() _channelPut->destroy(); } } - release(); } -ChannelPut* ServerChannelPutRequesterImpl::getChannelPut() +ChannelPut::shared_pointer ServerChannelPutRequesterImpl::getChannelPut() { - Lock guard(_mutex); + //Lock guard(_mutex); return _channelPut; } -BitSet* ServerChannelPutRequesterImpl::getBitSet() +BitSet::shared_pointer ServerChannelPutRequesterImpl::getBitSet() { - Lock guard(_mutex); + //Lock guard(_mutex); return _bitSet; } -PVStructure* ServerChannelPutRequesterImpl::getPVStructure() +PVStructure::shared_pointer ServerChannelPutRequesterImpl::getPVStructure() { - Lock guard(_mutex); + //Lock guard(_mutex); return _pvStructure; } @@ -839,7 +812,7 @@ void ServerChannelPutRequesterImpl::send(ByteBuffer* buffer, TransportSendContro { const int32 request = getPendingRequest(); - control->startMessage((int32)11, sizeof(int32)/sizeof(int8) + 1); + control->startMessage((int32)CMD_PUT, sizeof(int32)/sizeof(int8) + 1); buffer->putInt(_ioid); buffer->putByte((int8)request); IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry(); @@ -853,7 +826,7 @@ void ServerChannelPutRequesterImpl::send(ByteBuffer* buffer, TransportSendContro if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - introspectionRegistry->serialize(_pvStructure != NULL ? _pvStructure->getField() : NULL, buffer, control); + introspectionRegistry->serialize(_pvStructure != NULL ? _pvStructure->getField() : FieldConstPtr(), buffer, control); } else if ((QOS_GET & request) != 0) { @@ -872,13 +845,13 @@ void ServerChannelPutRequesterImpl::send(ByteBuffer* buffer, TransportSendContro /****************************************************************************************/ void ServerPutGetHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -887,10 +860,10 @@ void ServerPutGetHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { - BaseChannelRequester::sendFailureMessage((int8)12, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PUT_GET, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; } @@ -898,13 +871,10 @@ void ServerPutGetHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructure* pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerChannelPutGetRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerChannelPutGetRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { @@ -912,16 +882,16 @@ void ServerPutGetHandler::handleResponse(osiSockAddr* responseFrom, const bool getGet = (QOS_GET & qosCode) != 0; const bool getPut = (QOS_GET_PUT & qosCode) != 0; - ServerChannelPutGetRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerChannelPutGetRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)12, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PUT_GET, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } if (!request->startRequest(qosCode)) { - BaseChannelRequester::sendFailureMessage((int8)12, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PUT_GET, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); return; } @@ -936,23 +906,37 @@ void ServerPutGetHandler::handleResponse(osiSockAddr* responseFrom, else { // deserialize bitSet and do a put - request->getPVPutStructure()->deserialize(payloadBuffer, transport); + request->getPVPutStructure()->deserialize(payloadBuffer, transport.get()); request->getChannelPutGet()->putGet(lastRequest); } } } -ServerChannelPutGetRequesterImpl::ServerChannelPutGetRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, - const pvAccessID ioid, Transport* transport,PVStructure* pvRequest): - BaseChannelRequester(context, channel, ioid, transport), _channelPutGet(0), _pvPutStructure(0), _pvGetStructure(0) +ServerChannelPutGetRequesterImpl::ServerChannelPutGetRequesterImpl(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport): + BaseChannelRequester(context, channel, ioid, transport), _channelPutGet(), _pvPutStructure(), _pvGetStructure() { - startRequest(QOS_INIT); - channel->registerRequest(ioid, static_cast(this)); - INIT_EXCEPTION_GUARD(12, _channelPutGet = channel->getChannel()->createChannelPutGet(this, pvRequest)); } -void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status, ChannelPutGet* channelPutGet, - PVStructure* pvPutStructure, PVStructure* pvGetStructure) +ChannelPutGetRequester::shared_pointer ServerChannelPutGetRequesterImpl::create(ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport,PVStructure::shared_pointer& pvRequest) +{ + ChannelPutGetRequester::shared_pointer thisPointer(new ServerChannelPutGetRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerChannelPutGetRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + ChannelPutGetRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_PUT_GET, _channelPutGet = _channel->getChannel()->createChannelPutGet(thisPointer, pvRequest)); +} + +void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status, ChannelPutGet::shared_pointer& channelPutGet, + PVStructure::shared_pointer& pvPutStructure, PVStructure::shared_pointer& pvGetStructure) { { Lock guard(_mutex); @@ -962,7 +946,8 @@ void ServerChannelPutGetRequesterImpl::channelPutGetConnect(const Status& status _channelPutGet = channelPutGet; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -977,7 +962,8 @@ void ServerChannelPutGetRequesterImpl::getGetDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelPutGetRequesterImpl::getPutDone(const Status& status) @@ -986,7 +972,8 @@ void ServerChannelPutGetRequesterImpl::getPutDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status) @@ -995,7 +982,8 @@ void ServerChannelPutGetRequesterImpl::putGetDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelPutGetRequesterImpl::lock() @@ -1018,18 +1006,17 @@ void ServerChannelPutGetRequesterImpl::destroy() _channelPutGet->destroy(); } } - release(); } -ChannelPutGet* ServerChannelPutGetRequesterImpl::getChannelPutGet() +ChannelPutGet::shared_pointer ServerChannelPutGetRequesterImpl::getChannelPutGet() { - Lock guard(_mutex); + //Lock guard(_mutex); return _channelPutGet; } -PVStructure* ServerChannelPutGetRequesterImpl::getPVPutStructure() +PVStructure::shared_pointer ServerChannelPutGetRequesterImpl::getPVPutStructure() { - Lock guard(_mutex); + //Lock guard(_mutex); return _pvPutStructure; } @@ -1051,8 +1038,8 @@ void ServerChannelPutGetRequesterImpl::send(ByteBuffer* buffer, TransportSendCon if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - introspectionRegistry->serialize(_pvPutStructure != NULL ? _pvPutStructure->getField() : NULL, buffer, control); - introspectionRegistry->serialize(_pvGetStructure != NULL ? _pvGetStructure->getField() : NULL, buffer, control); + introspectionRegistry->serialize(_pvPutStructure != NULL ? _pvPutStructure->getField() : FieldConstPtr(), buffer, control); + introspectionRegistry->serialize(_pvGetStructure != NULL ? _pvGetStructure->getField() : FieldConstPtr(), buffer, control); } else if ((QOS_GET & request) != 0) { @@ -1080,13 +1067,13 @@ void ServerChannelPutGetRequesterImpl::send(ByteBuffer* buffer, TransportSendCon /****************************************************************************************/ void ServerMonitorHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -1095,10 +1082,10 @@ void ServerMonitorHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { - BaseChannelRequester::sendFailureMessage((int8)12, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_MONITOR, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; } @@ -1106,13 +1093,10 @@ void ServerMonitorHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructure* pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerMonitorRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerMonitorRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { @@ -1120,10 +1104,10 @@ void ServerMonitorHandler::handleResponse(osiSockAddr* responseFrom, const bool get = (QOS_GET & qosCode) != 0; const bool process = (QOS_PROCESS & qosCode) != 0; - ServerMonitorRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerMonitorRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)13, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_MONITOR, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } @@ -1153,16 +1137,32 @@ void ServerMonitorHandler::handleResponse(osiSockAddr* responseFrom, } } -ServerMonitorRequesterImpl::ServerMonitorRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, - const pvAccessID ioid, Transport* transport,PVStructure* pvRequest): - BaseChannelRequester(context, channel, ioid, transport), _monitor(0), _channelMonitor(0), _structure(0) +ServerMonitorRequesterImpl::ServerMonitorRequesterImpl( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport): + BaseChannelRequester(context, channel, ioid, transport), _monitor(), _channelMonitor(), _structure() { - startRequest(QOS_INIT); - channel->registerRequest(ioid, static_cast(this)); - INIT_EXCEPTION_GUARD(13, _channelMonitor = channel->getChannel()->createMonitor(this, pvRequest)); } -void ServerMonitorRequesterImpl::monitorConnect(const Status& status, Monitor* monitor, StructureConstPtr structure) +MonitorRequester::shared_pointer ServerMonitorRequesterImpl::create( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport,PVStructure::shared_pointer& pvRequest) +{ + MonitorRequester::shared_pointer thisPointer(new ServerMonitorRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerMonitorRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + MonitorRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_MONITOR, _channelMonitor = _channel->getChannel()->createMonitor(thisPointer, pvRequest)); +} + +void ServerMonitorRequesterImpl::monitorConnect(const Status& status, Monitor::shared_pointer& monitor, epics::pvData::StructureConstPtr& structure) { { Lock guard(_mutex); @@ -1171,7 +1171,8 @@ void ServerMonitorRequesterImpl::monitorConnect(const Status& status, Monitor* m _structure = structure; _monitor = monitor; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -1180,12 +1181,12 @@ void ServerMonitorRequesterImpl::monitorConnect(const Status& status, Monitor* m } } -void ServerMonitorRequesterImpl::unlisten(Monitor* monitor) +void ServerMonitorRequesterImpl::unlisten(Monitor::shared_pointer& monitor) { //TODO } -void ServerMonitorRequesterImpl::monitorEvent(Monitor* monitor) +void ServerMonitorRequesterImpl::monitorEvent(Monitor::shared_pointer& monitor) { // TODO !!! if queueSize==0, monitor.poll() has to be called and returned NOW (since there is no cache) //sendEvent(transport); @@ -1199,7 +1200,8 @@ void ServerMonitorRequesterImpl::monitorEvent(Monitor* monitor) }*/ // TODO // multiple ((BlockingServerTCPTransport)transport).enqueueMonitorSendRequest(this); - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerMonitorRequesterImpl::lock() @@ -1222,12 +1224,11 @@ void ServerMonitorRequesterImpl::destroy() _channelMonitor->destroy(); } } - release(); } -Monitor* ServerMonitorRequesterImpl::getChannelMonitor() +Monitor::shared_pointer ServerMonitorRequesterImpl::getChannelMonitor() { - Lock guard(_mutex); + //Lock guard(_mutex); return _channelMonitor; } @@ -1237,7 +1238,7 @@ void ServerMonitorRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* if ((QOS_INIT & request) != 0) { - control->startMessage((int32)13, sizeof(int32)/sizeof(int8) + 1); + control->startMessage((int32)CMD_MONITOR, sizeof(int32)/sizeof(int8) + 1); buffer->putInt(_ioid); buffer->putByte((int8)request); @@ -1256,20 +1257,20 @@ void ServerMonitorRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* } else { - Monitor* monitor = _monitor; - MonitorElement* element = monitor->poll(); + Monitor::shared_pointer monitor = _monitor; + MonitorElement::shared_pointer element = monitor->poll(); if (element != NULL) { - control->startMessage((int8)13, sizeof(int32)/sizeof(int8) + 1); + control->startMessage((int8)CMD_MONITOR, sizeof(int32)/sizeof(int8) + 1); buffer->putInt(_ioid); buffer->putByte((int8)request); // changedBitSet and data, if not notify only (i.e. queueSize == -1) - BitSet* changedBitSet = element->getChangedBitSet(); + BitSet::shared_pointer changedBitSet = element->getChangedBitSet(); if (changedBitSet != NULL) { changedBitSet->serialize(buffer, control); - element->getPVStructure()->serialize(buffer, control, changedBitSet); + element->getPVStructure()->serialize(buffer, control, changedBitSet.get()); // overrunBitset element->getOverrunBitSet()->serialize(buffer, control); @@ -1282,13 +1283,13 @@ void ServerMonitorRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* /****************************************************************************************/ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -1297,10 +1298,10 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { - BaseChannelRequester::sendFailureMessage((int8)12, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_ARRAY, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; } @@ -1308,13 +1309,10 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructure* pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerChannelArrayRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerChannelArrayRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { @@ -1322,54 +1320,69 @@ void ServerArrayHandler::handleResponse(osiSockAddr* responseFrom, const bool get = (QOS_GET & qosCode) != 0; const bool setLength = (QOS_GET_PUT & qosCode) != 0; - ServerChannelArrayRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerChannelArrayRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)14, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_ARRAY, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } if (!request->startRequest(qosCode)) { - BaseChannelRequester::sendFailureMessage((int8)14, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_ARRAY, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); return; } if (get) { - const int32 offset = SerializeHelper::readSize(payloadBuffer, transport); - const int32 count = SerializeHelper::readSize(payloadBuffer, transport); + const int32 offset = SerializeHelper::readSize(payloadBuffer, transport.get()); + const int32 count = SerializeHelper::readSize(payloadBuffer, transport.get()); request->getChannelArray()->getArray(lastRequest, offset, count); } else if (setLength) { - const int32 length = SerializeHelper::readSize(payloadBuffer, transport); - const int32 capacity = SerializeHelper::readSize(payloadBuffer, transport); + const int32 length = SerializeHelper::readSize(payloadBuffer, transport.get()); + const int32 capacity = SerializeHelper::readSize(payloadBuffer, transport.get()); request->getChannelArray()->setLength(lastRequest, length, capacity); } else { // deserialize data to put - const int32 offset = SerializeHelper::readSize(payloadBuffer, transport); - PVArray* array = request->getPVArray(); - array->deserialize(payloadBuffer, transport); + const int32 offset = SerializeHelper::readSize(payloadBuffer, transport.get()); + PVArray::shared_pointer array = request->getPVArray(); + array->deserialize(payloadBuffer, transport.get()); request->getChannelArray()->putArray(lastRequest, offset, array->getLength()); } } } -ServerChannelArrayRequesterImpl::ServerChannelArrayRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, - const pvAccessID ioid, Transport* transport,PVStructure* pvRequest): - BaseChannelRequester(context, channel, ioid, transport), _channelArray(0), _pvArray(0) +ServerChannelArrayRequesterImpl::ServerChannelArrayRequesterImpl( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport): + BaseChannelRequester(context, channel, ioid, transport), _channelArray(), _pvArray() { - - startRequest(QOS_INIT); - channel->registerRequest(ioid, static_cast(this)); - INIT_EXCEPTION_GUARD(14, _channelArray = channel->getChannel()->createChannelArray(this, pvRequest)); } -void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, ChannelArray* channelArray, PVArray* pvArray) +ChannelArrayRequester::shared_pointer ServerChannelArrayRequesterImpl::create( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport,PVStructure::shared_pointer& pvRequest) +{ + ChannelArrayRequester::shared_pointer thisPointer(new ServerChannelArrayRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerChannelArrayRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + ChannelArrayRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_ARRAY, _channelArray = _channel->getChannel()->createChannelArray(thisPointer, pvRequest)); +} + +void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, ChannelArray::shared_pointer& channelArray, PVArray::shared_pointer& pvArray) { { Lock guard(_mutex); @@ -1377,8 +1390,8 @@ void ServerChannelArrayRequesterImpl::channelArrayConnect(const Status& status, _pvArray = pvArray; _channelArray = channelArray; } - - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -1393,7 +1406,8 @@ void ServerChannelArrayRequesterImpl::getArrayDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelArrayRequesterImpl::putArrayDone(const Status& status) @@ -1402,7 +1416,8 @@ void ServerChannelArrayRequesterImpl::putArrayDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelArrayRequesterImpl::setLengthDone(const Status& status) @@ -1411,7 +1426,8 @@ void ServerChannelArrayRequesterImpl::setLengthDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelArrayRequesterImpl::lock() @@ -1434,18 +1450,17 @@ void ServerChannelArrayRequesterImpl::destroy() _channelArray->destroy(); } } - release(); } -ChannelArray* ServerChannelArrayRequesterImpl::getChannelArray() +ChannelArray::shared_pointer ServerChannelArrayRequesterImpl::getChannelArray() { - Lock guard(_mutex); + //Lock guard(_mutex); return _channelArray; } -PVArray* ServerChannelArrayRequesterImpl::getPVArray() +PVArray::shared_pointer ServerChannelArrayRequesterImpl::getPVArray() { - Lock guard(_mutex); + //Lock guard(_mutex); return _pvArray; } @@ -1453,7 +1468,7 @@ void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendCont { const int32 request = getPendingRequest(); - control->startMessage((int32)14, sizeof(int32)/sizeof(int8) + 1); + control->startMessage((int32)CMD_ARRAY, sizeof(int32)/sizeof(int8) + 1); buffer->putInt(_ioid); buffer->putByte((int8)request); IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry(); @@ -1472,7 +1487,7 @@ void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendCont else if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - introspectionRegistry->serialize(_pvArray != NULL ? _pvArray->getField() : NULL, buffer, control); + introspectionRegistry->serialize(_pvArray != NULL ? _pvArray->getField() : FieldConstPtr(), buffer, control); } } @@ -1485,26 +1500,26 @@ void ServerChannelArrayRequesterImpl::send(ByteBuffer* buffer, TransportSendCont /****************************************************************************************/ void ServerCancelRequestHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); const pvAccessID ioid = payloadBuffer->getInt(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { failureResponse(transport, ioid, BaseChannelRequester::badCIDStatus); return; } - Destroyable* request = channel->getRequest(ioid); + Destroyable::shared_pointer request = channel->getRequest(ioid); if (request == NULL) { failureResponse(transport, ioid, BaseChannelRequester::badIOIDStatus); @@ -1518,20 +1533,20 @@ void ServerCancelRequestHandler::handleResponse(osiSockAddr* responseFrom, channel->unregisterRequest(ioid); } -void ServerCancelRequestHandler::failureResponse(Transport* transport, pvAccessID ioid, const Status& errorStatus) +void ServerCancelRequestHandler::failureResponse(Transport::shared_pointer& transport, pvAccessID ioid, const Status& errorStatus) { BaseChannelRequester::message(transport, ioid, errorStatus.getMessage(), warningMessage); } /****************************************************************************************/ void ServerProcessHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -1540,10 +1555,10 @@ void ServerProcessHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { - BaseChannelRequester::sendFailureMessage((int8)16, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PROCESS, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; } @@ -1551,28 +1566,25 @@ void ServerProcessHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructure* pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerChannelProcessRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerChannelProcessRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { const bool lastRequest = (QOS_DESTROY & qosCode) != 0; - ServerChannelProcessRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerChannelProcessRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)16, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PROCESS, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } if (!request->startRequest(qosCode)) { - BaseChannelRequester::sendFailureMessage((int8)16, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_PROCESS, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); return; } @@ -1580,23 +1592,40 @@ void ServerProcessHandler::handleResponse(osiSockAddr* responseFrom, } } -ServerChannelProcessRequesterImpl::ServerChannelProcessRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, - const pvAccessID ioid, Transport* transport,PVStructure* pvRequest): BaseChannelRequester(context, channel, ioid, transport), - _channelProcess(0) +ServerChannelProcessRequesterImpl::ServerChannelProcessRequesterImpl( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport): + BaseChannelRequester(context, channel, ioid, transport), _channelProcess() { - startRequest(QOS_INIT); - channel->registerRequest(ioid, static_cast(this)); - INIT_EXCEPTION_GUARD(16, _channelProcess = channel->getChannel()->createChannelProcess(this, pvRequest)); } -void ServerChannelProcessRequesterImpl::channelProcessConnect(const Status& status, ChannelProcess* channelProcess) +ChannelProcessRequester::shared_pointer ServerChannelProcessRequesterImpl::create( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport,PVStructure::shared_pointer& pvRequest) +{ + ChannelProcessRequester::shared_pointer thisPointer(new ServerChannelProcessRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerChannelProcessRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + ChannelProcessRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_PROCESS, _channelProcess = _channel->getChannel()->createChannelProcess(thisPointer, pvRequest)); +} + +void ServerChannelProcessRequesterImpl::channelProcessConnect(const Status& status, ChannelProcess::shared_pointer& channelProcess) { { Lock guard(_mutex); _status = status; _channelProcess = channelProcess; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -1611,7 +1640,8 @@ void ServerChannelProcessRequesterImpl::processDone(const Status& status) Lock guard(_mutex); _status = status; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelProcessRequesterImpl::lock() @@ -1634,12 +1664,11 @@ void ServerChannelProcessRequesterImpl::destroy() _channelProcess->destroy(); } } - release(); } -ChannelProcess* ServerChannelProcessRequesterImpl::getChannelProcess() +ChannelProcess::shared_pointer ServerChannelProcessRequesterImpl::getChannelProcess() { - Lock guard(_mutex); + //Lock guard(_mutex); return _channelProcess; } @@ -1647,7 +1676,7 @@ void ServerChannelProcessRequesterImpl::send(ByteBuffer* buffer, TransportSendCo { const int32 request = getPendingRequest(); - control->startMessage((int32)16, sizeof(int32)/sizeof(int8) + 1); + control->startMessage((int32)CMD_PROCESS, sizeof(int32)/sizeof(int8) + 1); buffer->putInt(_ioid); buffer->putByte((int8)request); IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry(); @@ -1668,50 +1697,55 @@ void ServerChannelProcessRequesterImpl::send(ByteBuffer* buffer, TransportSendCo /****************************************************************************************/ void ServerGetFieldHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)); const pvAccessID sid = payloadBuffer->getInt(); const pvAccessID ioid = payloadBuffer->getInt(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { getFieldFailureResponse(transport, ioid, BaseChannelRequester::badCIDStatus); return; } - String subField = SerializeHelper::deserializeString(payloadBuffer, transport); + String subField = SerializeHelper::deserializeString(payloadBuffer, transport.get()); // issue request - channel->getChannel()->getField(new ServerGetFieldRequesterImpl(_context, channel, ioid, transport), subField); + GetFieldRequester::shared_pointer gfr(new ServerGetFieldRequesterImpl(_context, channel, ioid, transport)); + // TODO exception check + channel->getChannel()->getField(gfr, subField); } -void ServerGetFieldHandler::getFieldFailureResponse(Transport* transport, const pvAccessID ioid, const Status& errorStatus) +void ServerGetFieldHandler::getFieldFailureResponse(Transport::shared_pointer& transport, const pvAccessID ioid, const Status& errorStatus) { - transport->enqueueSendRequest(new ServerGetFieldHandlerTransportSender(ioid,errorStatus,transport)); + TransportSender::shared_pointer sender(new ServerGetFieldHandlerTransportSender(ioid,errorStatus,transport)); + transport->enqueueSendRequest(sender); } -ServerGetFieldRequesterImpl::ServerGetFieldRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport) : - BaseChannelRequester(context, channel, ioid, transport), _field(0) +ServerGetFieldRequesterImpl::ServerGetFieldRequesterImpl( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport) : + BaseChannelRequester(context, channel, ioid, transport), _field() { } -void ServerGetFieldRequesterImpl::getDone(const Status& status, FieldConstPtr field) +void ServerGetFieldRequesterImpl::getDone(const Status& status, FieldConstPtr& field) { { Lock guard(_mutex); _status = status; _field = field; } - _transport->enqueueSendRequest(this); - release(); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerGetFieldRequesterImpl::lock() @@ -1726,12 +1760,11 @@ void ServerGetFieldRequesterImpl::unlock() void ServerGetFieldRequesterImpl::destroy() { - release(); } void ServerGetFieldRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* control) { - control->startMessage((int8)17, sizeof(int32)/sizeof(int8)); + control->startMessage((int8)CMD_GET_FIELD, sizeof(int32)/sizeof(int8)); buffer->putInt(_ioid); IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry(); { @@ -1743,13 +1776,13 @@ void ServerGetFieldRequesterImpl::send(ByteBuffer* buffer, TransportSendControl* /****************************************************************************************/ void ServerRPCHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { AbstractServerResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer); // NOTE: we do not explicitly check if transport is OK - ChannelHostingTransport* casTransport = dynamic_cast(transport); + ChannelHostingTransport::shared_pointer casTransport = dynamic_pointer_cast(transport); transport->ensureData(2*sizeof(int32)/sizeof(int8)+1); const pvAccessID sid = payloadBuffer->getInt(); @@ -1758,10 +1791,10 @@ void ServerRPCHandler::handleResponse(osiSockAddr* responseFrom, // mode const int8 qosCode = payloadBuffer->getByte(); - ServerChannelImpl* channel = static_cast(casTransport->getChannel(sid)); + ServerChannelImpl::shared_pointer channel = static_pointer_cast(casTransport->getChannel(sid)); if (channel == NULL) { - BaseChannelRequester::sendFailureMessage((int8)16, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_RPC, transport, ioid, qosCode, BaseChannelRequester::badCIDStatus); return; } @@ -1769,50 +1802,64 @@ void ServerRPCHandler::handleResponse(osiSockAddr* responseFrom, if (init) { // pvRequest - //TODO who is responsible to delete this pvRequest?? - PVStructure* pvRequest = transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport); + PVStructure::shared_pointer pvRequest(transport->getIntrospectionRegistry()->deserializePVRequest(payloadBuffer, transport.get())); // create... - new ServerChannelRPCRequesterImpl(_context, channel, ioid, transport, pvRequest); - - delete pvRequest; + ServerChannelRPCRequesterImpl::create(_context, channel, ioid, transport, pvRequest); } else { const bool lastRequest = (QOS_DESTROY & qosCode) != 0; - ServerChannelRPCRequesterImpl* request = static_cast(channel->getRequest(ioid)); + ServerChannelRPCRequesterImpl::shared_pointer request = static_pointer_cast(channel->getRequest(ioid)); if (request == NULL) { - BaseChannelRequester::sendFailureMessage((int8)20, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_RPC, transport, ioid, qosCode, BaseChannelRequester::badIOIDStatus); return; } if (!request->startRequest(qosCode)) { - BaseChannelRequester::sendFailureMessage((int8)20, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); + BaseChannelRequester::sendFailureMessage((int8)CMD_RPC, transport, ioid, qosCode, BaseChannelRequester::otherRequestPendingStatus); return; } // deserialize put data - BitSet* changedBitSet = request->getAgrumentsBitSet(); - changedBitSet->deserialize(payloadBuffer, transport); - request->getPvArguments()->deserialize(payloadBuffer, transport, changedBitSet); + BitSet::shared_pointer changedBitSet = request->getAgrumentsBitSet(); + changedBitSet->deserialize(payloadBuffer, transport.get()); + request->getPvArguments()->deserialize(payloadBuffer, transport.get(), changedBitSet.get()); request->getChannelRPC()->request(lastRequest); } } -ServerChannelRPCRequesterImpl::ServerChannelRPCRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, - const pvAccessID ioid, Transport* transport,PVStructure* pvRequest): -BaseChannelRequester(context, channel, ioid, transport), _channelRPC(0), _pvArguments(0), _pvResponse(0), _argumentsBitSet(0) +ServerChannelRPCRequesterImpl::ServerChannelRPCRequesterImpl( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport): + BaseChannelRequester(context, channel, ioid, transport), + _channelRPC(), _pvArguments(), _pvResponse(), _argumentsBitSet() { - startRequest(QOS_INIT); - channel->registerRequest(ioid, static_cast(this)); - INIT_EXCEPTION_GUARD(20, _channelRPC = channel->getChannel()->createChannelRPC(this, pvRequest)); } -void ServerChannelRPCRequesterImpl::channelRPCConnect(const Status& status, ChannelRPC* channelRPC, PVStructure* arguments, BitSet* bitSet) +ChannelRPCRequester::shared_pointer ServerChannelRPCRequesterImpl::create( + ServerContextImpl::shared_pointer& context, ServerChannelImpl::shared_pointer& channel, + const pvAccessID ioid, Transport::shared_pointer& transport, PVStructure::shared_pointer& pvRequest) +{ + ChannelRPCRequester::shared_pointer thisPointer(new ServerChannelRPCRequesterImpl(context, channel, ioid, transport)); + static_cast(thisPointer.get())->activate(pvRequest); + return thisPointer; +} + +void ServerChannelRPCRequesterImpl::activate(PVStructure::shared_pointer& pvRequest) +{ + startRequest(QOS_INIT); + ChannelRPCRequester::shared_pointer thisPointer = shared_from_this(); + Destroyable::shared_pointer thisDestroyable = shared_from_this(); + _channel->registerRequest(_ioid, thisDestroyable); + INIT_EXCEPTION_GUARD(CMD_RPC, _channelRPC = _channel->getChannel()->createChannelRPC(thisPointer, pvRequest)); +} + +void ServerChannelRPCRequesterImpl::channelRPCConnect(const Status& status, ChannelRPC::shared_pointer& channelRPC, PVStructure::shared_pointer& arguments, BitSet::shared_pointer& bitSet) { { Lock guard(_mutex); @@ -1821,7 +1868,8 @@ void ServerChannelRPCRequesterImpl::channelRPCConnect(const Status& status, Chan _status = status; _channelRPC = channelRPC; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); // self-destruction if (!status.isSuccess()) @@ -1830,14 +1878,15 @@ void ServerChannelRPCRequesterImpl::channelRPCConnect(const Status& status, Chan } } -void ServerChannelRPCRequesterImpl::requestDone(const Status& status, PVStructure* pvResponse) +void ServerChannelRPCRequesterImpl::requestDone(const Status& status, PVStructure::shared_pointer& pvResponse) { { Lock guard(_mutex); _status = status; _pvResponse = pvResponse; } - _transport->enqueueSendRequest(this); + TransportSender::shared_pointer thisSender = shared_from_this(); + _transport->enqueueSendRequest(thisSender); } void ServerChannelRPCRequesterImpl::lock() @@ -1860,24 +1909,23 @@ void ServerChannelRPCRequesterImpl::destroy() _channelRPC->destroy(); } } - release(); } -ChannelRPC* ServerChannelRPCRequesterImpl::getChannelRPC() +ChannelRPC::shared_pointer ServerChannelRPCRequesterImpl::getChannelRPC() { - Lock guard(_mutex); + //Lock guard(_mutex); return _channelRPC; } -PVStructure* ServerChannelRPCRequesterImpl::getPvArguments() +PVStructure::shared_pointer ServerChannelRPCRequesterImpl::getPvArguments() { - Lock guard(_mutex); + //Lock guard(_mutex); return _pvArguments; } -BitSet* ServerChannelRPCRequesterImpl::getAgrumentsBitSet() +BitSet::shared_pointer ServerChannelRPCRequesterImpl::getAgrumentsBitSet() { - Lock guard(_mutex); + //Lock guard(_mutex); return _argumentsBitSet; } @@ -1885,7 +1933,7 @@ void ServerChannelRPCRequesterImpl::send(ByteBuffer* buffer, TransportSendContro { const int32 request = getPendingRequest(); - control->startMessage((int32)20, sizeof(int32)/sizeof(int8) + 1); + control->startMessage((int32)CMD_RPC, sizeof(int32)/sizeof(int8) + 1); buffer->putInt(_ioid); buffer->putByte((int8)request); IntrospectionRegistry* introspectionRegistry = _transport->getIntrospectionRegistry(); @@ -1899,11 +1947,11 @@ void ServerChannelRPCRequesterImpl::send(ByteBuffer* buffer, TransportSendContro if ((QOS_INIT & request) != 0) { Lock guard(_mutex); - introspectionRegistry->serialize(_pvArguments != NULL ? _pvArguments->getField() : NULL, buffer, control); + introspectionRegistry->serialize(_pvArguments != NULL ? _pvArguments->getField() : FieldConstPtr(), buffer, control); } else { - introspectionRegistry->serializeStructure(buffer, control, _pvResponse); + introspectionRegistry->serializeStructure(buffer, control, _pvResponse.get()); } } diff --git a/pvAccessApp/server/responseHandlers.h b/pvAccessApp/server/responseHandlers.h index 9fb86f3..0bcacfe 100644 --- a/pvAccessApp/server/responseHandlers.h +++ b/pvAccessApp/server/responseHandlers.h @@ -1,36 +1,26 @@ /* * responseHandlers.h - * - * Created on: Jan 5, 2011 - * Author: user */ #ifndef RESPONSEHANDLERS_H_ #define RESPONSEHANDLERS_H_ #include "serverContext.h" -#include "remote.h" +#include #include "serverChannelImpl.h" #include "baseChannelRequester.h" -#include "referencedTransportSender.h" namespace epics { namespace pvAccess { /** - * @author Matej Sekoranja - * @version $Id: AbstractServerResponseHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class AbstractServerResponseHandler : public AbstractResponseHandler { protected: - ServerContextImpl* _context; + ServerContextImpl::shared_pointer _context; public: - /** - * @param context - * @param description - */ - AbstractServerResponseHandler(ServerContextImpl* context, String description) : - AbstractResponseHandler(context, description), _context(context) { + AbstractServerResponseHandler(ServerContextImpl::shared_pointer& context, String description) : + AbstractResponseHandler(context.get(), description), _context(context) { } virtual ~AbstractServerResponseHandler() { @@ -39,15 +29,10 @@ namespace epics { /** * Bad request handler. - * @author Matej Sekoranja - * @version $Id: BadResponse.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class ServerBadResponse : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerBadResponse(ServerContextImpl* context) : + ServerBadResponse(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Bad request") { } @@ -55,97 +40,78 @@ namespace epics { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; /** * CAS request handler - main handler which dispatches requests to appropriate handlers. - * @author Matej Sekoranja - * @version $Id: ServerResponseHandler.java,v 1.1 2010/05/03 14:45:48 mrkraimer Exp $ */ class ServerResponseHandler : public ResponseHandler { public: - ServerResponseHandler(ServerContextImpl* context); + ServerResponseHandler(ServerContextImpl::shared_pointer& context); - virtual ~ServerResponseHandler(); + virtual ~ServerResponseHandler() { + } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: - static const int HANDLER_TABLE_LENGTH = 28; - /** - * Bad response handlers. - */ - ServerBadResponse *_badResponse; /** * Table of response handlers for each command ID. */ - ResponseHandler** _handlerTable; + vector m_handlerTable; }; /** * Connection validation message handler. - * @author Matej Sekoranja - * @version $Id: ConnectionValidationHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class ServerConnectionValidationHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerConnectionValidationHandler(ServerContextImpl* context) : + ServerConnectionValidationHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Connection validation") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; /** * NOOP response. - * @author Matej Sekoranja - * @version $Id: NoopResponse.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class ServerNoopResponse : public AbstractServerResponseHandler { public: - /** - * @param context - * @param description - */ - ServerNoopResponse(ServerContextImpl* context, String description) : + ServerNoopResponse(ServerContextImpl::shared_pointer& context, String description) : AbstractServerResponseHandler(context, description) { } }; /** * Echo request handler. - * @author Matej Sekoranja - * @version $Id: EchoHandler.java,v 1.1 2010/05/03 14:45:39 mrkraimer Exp $ */ class ServerEchoHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerEchoHandler(ServerContextImpl* context) : + ServerEchoHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Echo request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class EchoTransportSender : public ReferencedTransportSender { + class EchoTransportSender : public TransportSender { public: EchoTransportSender(osiSockAddr* echoFrom) { memcpy(&_echoFrom, echoFrom, sizeof(osiSockAddr)); } + virtual ~EchoTransportSender() { + } + virtual void send(ByteBuffer* buffer, TransportSendControl* control) { control->startMessage(CMD_ECHO, 0); control->setRecipient(_echoFrom); @@ -160,9 +126,6 @@ namespace epics { private: osiSockAddr _echoFrom; - - virtual ~EchoTransportSender() { - } }; /** @@ -171,15 +134,12 @@ namespace epics { class ServerIntrospectionSearchHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerIntrospectionSearchHandler(ServerContextImpl* context) : + ServerIntrospectionSearchHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Search request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; @@ -187,33 +147,32 @@ namespace epics { /** * Search channel request handler. */ - class ServerChannelFindRequesterImplObjectPool; + // TODO object pool!!! class ServerSearchHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerSearchHandler(ServerContextImpl* context); - ~ServerSearchHandler(); + ServerSearchHandler(ServerContextImpl::shared_pointer& context); + virtual ~ServerSearchHandler(); virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: - ChannelProvider* _provider; - ServerChannelFindRequesterImplObjectPool* _objectPool; + ChannelProvider::shared_pointer _provider; }; - class ServerChannelFindRequesterImpl: public ChannelFindRequester, public ReferencedTransportSender + class ServerChannelFindRequesterImpl: + public ChannelFindRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelFindRequesterImpl(ServerContextImpl* context, ServerChannelFindRequesterImplObjectPool* objectPool); + ServerChannelFindRequesterImpl(ServerContextImpl::shared_pointer& context); void clear(); ServerChannelFindRequesterImpl* set(int32 searchSequenceId, int32 cid, osiSockAddr* sendTo, boolean responseRequired); - void channelFindResult(const epics::pvData::Status& status, ChannelFind* channelFind, boolean wasFound); + void channelFindResult(const epics::pvData::Status& status, ChannelFind::shared_pointer& channelFind, boolean wasFound); void lock(); void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); @@ -223,24 +182,10 @@ namespace epics { osiSockAddr* _sendTo; boolean _responseRequired; boolean _wasFound; - ServerContextImpl* _context; - epics::pvData::Mutex _mutex; - ServerChannelFindRequesterImplObjectPool* _objectPool; - }; - - class ServerChannelFindRequesterImplObjectPool - { - public: - ServerChannelFindRequesterImplObjectPool(ServerContextImpl* context); - ~ServerChannelFindRequesterImplObjectPool(); - ServerChannelFindRequesterImpl* get(); - void put(ServerChannelFindRequesterImpl* element); - - private: - std::vector _elements; - ServerContextImpl* _context; + ServerContextImpl::shared_pointer _context; epics::pvData::Mutex _mutex; }; + /****************************************************************************************/ /** * Create channel request handler. @@ -248,43 +193,45 @@ namespace epics { class ServerCreateChannelHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerCreateChannelHandler(ServerContextImpl* context) : + ServerCreateChannelHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Create channel request") { _provider = context->getChannelProvider(); } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: - /** - * Disconnect. - */ - void disconnect(Transport* transport); - ChannelProvider* _provider; + void disconnect(Transport::shared_pointer& transport); + ChannelProvider::shared_pointer _provider; }; - class ServerChannelRequesterImpl : public ChannelRequester, public ReferencedTransportSender + class ServerChannelRequesterImpl : + public ChannelRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelRequesterImpl(Transport* transport, const String channelName, const pvAccessID cid); - void channelCreated(const epics::pvData::Status& status, Channel* channel); - void channelStateChange(Channel* c, const Channel::ConnectionState isConnected); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelRequesterImpl(Transport::shared_pointer& transport, const String channelName, const pvAccessID cid); + public: + static ChannelRequester::shared_pointer create(ChannelProvider::shared_pointer& provider, Transport::shared_pointer& transport, const String channelName, const pvAccessID cid); + void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer& channel); + void channelStateChange(Channel::shared_pointer& c, const Channel::ConnectionState isConnected); String getRequesterName(); void message(const String message, const epics::pvData::MessageType messageType); void lock(); void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: - Transport* _transport; + Transport::shared_pointer _transport; const String _channelName; const pvAccessID _cid; epics::pvData::Status _status; - Channel* _channel; + Channel::shared_pointer _channel; epics::pvData::Mutex _mutex; void createChannelFailedResponse(epics::pvData::ByteBuffer* buffer, TransportSendControl* control, const epics::pvData::Status& status); }; @@ -296,28 +243,24 @@ namespace epics { class ServerDestroyChannelHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerDestroyChannelHandler(ServerContextImpl* context) : + ServerDestroyChannelHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Destroy channel request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerDestroyChannelHandlerTransportSender : public ReferencedTransportSender + class ServerDestroyChannelHandlerTransportSender : public TransportSender { public: ServerDestroyChannelHandlerTransportSender(pvAccessID cid, pvAccessID sid): _cid(cid), _sid(sid) { - } void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { - control->startMessage((int8)8, 2*sizeof(int32)/sizeof(int8)); + control->startMessage((int8)CMD_DESTROY_CHANNEL, 2*sizeof(int32)/sizeof(int8)); buffer->putInt(_sid); buffer->putInt(_cid); } @@ -342,38 +285,48 @@ namespace epics { class ServerGetHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerGetHandler(ServerContextImpl* context) : + ServerGetHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Get request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerChannelGetRequesterImpl : public BaseChannelRequester, public ChannelGetRequester, public ReferencedTransportSender + class ServerChannelGetRequesterImpl : + public BaseChannelRequester, + public ChannelGetRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelGetRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport, - epics::pvData::PVStructurePtr pvRequest); - void channelGetConnect(const epics::pvData::Status& status, ChannelGet* channelGet, epics::pvData::PVStructurePtr pvStructure, - epics::pvData::BitSet* bitSet); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelGetRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static ChannelGetRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport, + epics::pvData::PVStructure::shared_pointer& pvRequest); + void channelGetConnect(const epics::pvData::Status& status, ChannelGet::shared_pointer& channelGet, + epics::pvData::PVStructure::shared_pointer& pvStructure, epics::pvData::BitSet::shared_pointer& bitSet); void getDone(const epics::pvData::Status& status); void destroy(); - /** - * @return the channelGet - */ - ChannelGet* getChannelGet(); + + ChannelGet::shared_pointer getChannelGet(); + void lock(); void unlock(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: - ChannelGet* _channelGet; - epics::pvData::BitSet* _bitSet; - epics::pvData::PVStructurePtr _pvStructure; + ChannelGet::shared_pointer _channelGet; + epics::pvData::BitSet::shared_pointer _bitSet; + epics::pvData::PVStructure::shared_pointer _pvStructure; epics::pvData::Status _status; }; @@ -385,45 +338,49 @@ namespace epics { class ServerPutHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerPutHandler(ServerContextImpl* context) : + ServerPutHandler(ServerContextImpl::shared_pointer context) : AbstractServerResponseHandler(context, "Put request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerChannelPutRequesterImpl : public BaseChannelRequester, public ChannelPutRequester, public ReferencedTransportSender + class ServerChannelPutRequesterImpl : + public BaseChannelRequester, + public ChannelPutRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelPutRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport,epics::pvData::PVStructure* pvRequest); - void channelPutConnect(const epics::pvData::Status& status, ChannelPut* channelPut, epics::pvData::PVStructure* pvStructure, epics::pvData::BitSet* bitSet); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelPutRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static ChannelPutRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport,epics::pvData::PVStructure::shared_pointer& pvRequest); + + void channelPutConnect(const epics::pvData::Status& status, ChannelPut::shared_pointer& channelPut, epics::pvData::PVStructure::shared_pointer& pvStructure, epics::pvData::BitSet::shared_pointer& bitSet); void putDone(const epics::pvData::Status& status); void getDone(const epics::pvData::Status& status); void lock(); void unlock(); void destroy(); - /** - * @return the channelPut - */ - ChannelPut* getChannelPut(); - /** - * @return the bitSet - */ - BitSet* getBitSet(); - /** - * @return the pvStructure - */ - PVStructure* getPVStructure(); + + ChannelPut::shared_pointer getChannelPut(); + BitSet::shared_pointer getBitSet(); + PVStructure::shared_pointer getPVStructure(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: - ChannelPut* _channelPut; - epics::pvData::BitSet* _bitSet; - epics::pvData::PVStructure* _pvStructure; + ChannelPut::shared_pointer _channelPut; + epics::pvData::BitSet::shared_pointer _bitSet; + epics::pvData::PVStructure::shared_pointer _pvStructure; epics::pvData::Status _status; }; @@ -434,42 +391,49 @@ namespace epics { class ServerPutGetHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerPutGetHandler(ServerContextImpl* context) : + ServerPutGetHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Put-get request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerChannelPutGetRequesterImpl : public BaseChannelRequester, public ChannelPutGetRequester, public ReferencedTransportSender + class ServerChannelPutGetRequesterImpl : + public BaseChannelRequester, + public ChannelPutGetRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelPutGetRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport,epics::pvData::PVStructure* pvRequest); - void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet* channelPutGet, epics::pvData::PVStructure* pvPutStructure, epics::pvData::PVStructure* pvGetStructure); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelPutGetRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static ChannelPutGetRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport,epics::pvData::PVStructure::shared_pointer& pvRequest); + + void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet::shared_pointer& channelPutGet, epics::pvData::PVStructure::shared_pointer& pvPutStructure, epics::pvData::PVStructure::shared_pointer& pvGetStructure); void getGetDone(const epics::pvData::Status& status); void getPutDone(const epics::pvData::Status& status); void putGetDone(const epics::pvData::Status& status); void lock(); void unlock(); void destroy(); - /** - * @return the channelPutGet - */ - ChannelPutGet* getChannelPutGet(); - /** - * @return the pvPutStructure - */ - PVStructure* getPVPutStructure(); + + ChannelPutGet::shared_pointer getChannelPutGet(); + PVStructure::shared_pointer getPVPutStructure(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: - ChannelPutGet* _channelPutGet; - epics::pvData::PVStructure* _pvPutStructure; - epics::pvData::PVStructure* _pvGetStructure; + ChannelPutGet::shared_pointer _channelPutGet; + epics::pvData::PVStructure::shared_pointer _pvPutStructure; + epics::pvData::PVStructure::shared_pointer _pvGetStructure; epics::pvData::Status _status; }; @@ -481,38 +445,48 @@ namespace epics { class ServerMonitorHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerMonitorHandler(ServerContextImpl* context) : + ServerMonitorHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Monitor request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerMonitorRequesterImpl : public BaseChannelRequester, public MonitorRequester, public ReferencedTransportSender + class ServerMonitorRequesterImpl : + public BaseChannelRequester, + public MonitorRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerMonitorRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport,epics::pvData::PVStructure* pvRequest); - void monitorConnect(const epics::pvData::Status& status, epics::pvData::Monitor* monitor, epics::pvData::StructureConstPtr structure); - void unlisten(epics::pvData::Monitor* monitor); - void monitorEvent(epics::pvData::Monitor* monitor); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerMonitorRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static MonitorRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport,epics::pvData::PVStructure::shared_pointer& pvRequest); + + void monitorConnect(const epics::pvData::Status& status, epics::pvData::Monitor::shared_pointer& monitor, epics::pvData::StructureConstPtr& structure); + void unlisten(epics::pvData::Monitor::shared_pointer& monitor); + void monitorEvent(epics::pvData::Monitor::shared_pointer& monitor); void lock(); void unlock(); void destroy(); - /** - * @return the channelMonitor - */ - epics::pvData::Monitor* getChannelMonitor(); + + epics::pvData::Monitor::shared_pointer getChannelMonitor(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: - epics::pvData::Monitor* _monitor; - epics::pvData::Monitor* _channelMonitor; - epics::pvData::StructureConstPtr _structure; + epics::pvData::Monitor::shared_pointer _monitor; + epics::pvData::Monitor::shared_pointer _channelMonitor; + epics::pvData::StructureConstPtr _structure; epics::pvData::Status _status; }; @@ -524,41 +498,50 @@ namespace epics { class ServerArrayHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerArrayHandler(ServerContextImpl* context) : + ServerArrayHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Array request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerChannelArrayRequesterImpl : public BaseChannelRequester, public ChannelArrayRequester, public ReferencedTransportSender + class ServerChannelArrayRequesterImpl : + public BaseChannelRequester, + public ChannelArrayRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelArrayRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport,epics::pvData::PVStructure* pvRequest); - void channelArrayConnect(const epics::pvData::Status& status, ChannelArray* channelArray, epics::pvData::PVArray* pvArray); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelArrayRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static ChannelArrayRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport,epics::pvData::PVStructure::shared_pointer& pvRequest); + + void channelArrayConnect(const epics::pvData::Status& status, ChannelArray::shared_pointer& channelArray, epics::pvData::PVArray::shared_pointer& pvArray); void getArrayDone(const epics::pvData::Status& status); void putArrayDone(const epics::pvData::Status& status); void setLengthDone(const epics::pvData::Status& status); void lock(); void unlock(); void destroy(); - /** - * @return the channelArray - */ - ChannelArray* getChannelArray(); - /** - * @return the pvArray - */ - epics::pvData::PVArray* getPVArray(); + + ChannelArray::shared_pointer getChannelArray(); + + epics::pvData::PVArray::shared_pointer getPVArray(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); + private: - ChannelArray* _channelArray; - epics::pvData::PVArray* _pvArray; + ChannelArray::shared_pointer _channelArray; + epics::pvData::PVArray::shared_pointer _pvArray; epics::pvData::Status _status; }; @@ -569,23 +552,16 @@ namespace epics { class ServerCancelRequestHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerCancelRequestHandler(ServerContextImpl* context) : + ServerCancelRequestHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Cancel request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: - /** - * @param transport - * @param ioid - * @param errorStatus - */ - void failureResponse(Transport* transport, pvAccessID ioid, const epics::pvData::Status& errorStatus); + + void failureResponse(Transport::shared_pointer& transport, pvAccessID ioid, const epics::pvData::Status& errorStatus); }; @@ -596,34 +572,45 @@ namespace epics { class ServerProcessHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerProcessHandler(ServerContextImpl* context) : + ServerProcessHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Process request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerChannelProcessRequesterImpl : public BaseChannelRequester, public ChannelProcessRequester, public ReferencedTransportSender + class ServerChannelProcessRequesterImpl : + public BaseChannelRequester, + public ChannelProcessRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelProcessRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport,epics::pvData::PVStructure* pvRequest); - void channelProcessConnect(const epics::pvData::Status& status, ChannelProcess* channelProcess); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelProcessRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static ChannelProcessRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport, epics::pvData::PVStructure::shared_pointer& pvRequest); + + void channelProcessConnect(const epics::pvData::Status& status, ChannelProcess::shared_pointer& channelProcess); void processDone(const epics::pvData::Status& status); void lock(); void unlock(); void destroy(); - /** - * @return the channelProcess - */ - ChannelProcess* getChannelProcess(); + + ChannelProcess::shared_pointer getChannelProcess(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); + private: - ChannelProcess* _channelProcess; + ChannelProcess::shared_pointer _channelProcess; epics::pvData::Status _status; }; @@ -634,25 +621,32 @@ namespace epics { class ServerGetFieldHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerGetFieldHandler(ServerContextImpl* context) : + ServerGetFieldHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "Get field request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); private: - void getFieldFailureResponse(Transport* transport, const pvAccessID ioid, const epics::pvData::Status& errorStatus); + void getFieldFailureResponse(Transport::shared_pointer& transport, const pvAccessID ioid, const epics::pvData::Status& errorStatus); }; - class ServerGetFieldRequesterImpl : public BaseChannelRequester, public GetFieldRequester, public ReferencedTransportSender + class ServerGetFieldRequesterImpl : + public BaseChannelRequester, + public GetFieldRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerGetFieldRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport); - void getDone(const epics::pvData::Status& status, epics::pvData::FieldConstPtr field); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + ServerGetFieldRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + + void getDone(const epics::pvData::Status& status, epics::pvData::FieldConstPtr& field); void lock(); void unlock(); void destroy(); @@ -662,16 +656,16 @@ namespace epics { epics::pvData::FieldConstPtr _field; }; - class ServerGetFieldHandlerTransportSender : public ReferencedTransportSender + class ServerGetFieldHandlerTransportSender : public TransportSender { public: - ServerGetFieldHandlerTransportSender(const pvAccessID ioid,const epics::pvData::Status& status, Transport* transport): + ServerGetFieldHandlerTransportSender(const pvAccessID ioid,const epics::pvData::Status& status, Transport::shared_pointer& transport): _ioid(ioid), _status(status), _transport(transport) { } void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control) { - control->startMessage((int8)17, sizeof(int32)/sizeof(int8)); + control->startMessage((int8)CMD_GET_FIELD, sizeof(int32)/sizeof(int8)); buffer->putInt(_ioid); _transport->getIntrospectionRegistry()->serializeStatus(buffer, control, _status); } @@ -686,8 +680,8 @@ namespace epics { private: const pvAccessID _ioid; - const epics::pvData::Status& _status; - Transport* _transport; + const epics::pvData::Status _status; + Transport::shared_pointer& _transport; }; @@ -699,45 +693,57 @@ namespace epics { class ServerRPCHandler : public AbstractServerResponseHandler { public: - /** - * @param context - */ - ServerRPCHandler(ServerContextImpl* context) : + ServerRPCHandler(ServerContextImpl::shared_pointer& context) : AbstractServerResponseHandler(context, "RPC request") { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, epics::pvData::ByteBuffer* payloadBuffer); }; - class ServerChannelRPCRequesterImpl : public BaseChannelRequester, public ChannelRPCRequester, public ReferencedTransportSender + class ServerChannelRPCRequesterImpl : + public BaseChannelRequester, + public ChannelRPCRequester, + public TransportSender, + public std::tr1::enable_shared_from_this { public: - ServerChannelRPCRequesterImpl(ServerContextImpl* context, ServerChannelImpl* channel, const pvAccessID ioid, Transport* transport,epics::pvData::PVStructure* pvRequest); - void channelRPCConnect(const epics::pvData::Status& status, ChannelRPC* channelRPC, epics::pvData::PVStructure* arguments, epics::pvData::BitSet* bitSet); - void requestDone(const epics::pvData::Status& status, epics::pvData::PVStructure* pvResponse); + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + protected: + ServerChannelRPCRequesterImpl(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport); + void activate(epics::pvData::PVStructure::shared_pointer& pvRequest); + public: + static ChannelRPCRequester::shared_pointer create(ServerContextImpl::shared_pointer& context, + ServerChannelImpl::shared_pointer& channel, const pvAccessID ioid, + Transport::shared_pointer& transport,epics::pvData::PVStructure::shared_pointer& pvRequest); + + void channelRPCConnect(const epics::pvData::Status& status, ChannelRPC::shared_pointer& channelRPC, epics::pvData::PVStructure::shared_pointer& arguments, epics::pvData::BitSet::shared_pointer& bitSet); + void requestDone(const epics::pvData::Status& status, epics::pvData::PVStructure::shared_pointer& pvResponse); void lock(); void unlock(); void destroy(); /** * @return the channelRPC */ - ChannelRPC* getChannelRPC(); + ChannelRPC::shared_pointer getChannelRPC(); /** * @return the pvArguments */ - PVStructure* getPvArguments(); + PVStructure::shared_pointer getPvArguments(); /** * @return the agrumentsBitSet */ - BitSet* getAgrumentsBitSet(); + BitSet::shared_pointer getAgrumentsBitSet(); void send(epics::pvData::ByteBuffer* buffer, TransportSendControl* control); private: - ChannelRPC* _channelRPC; - epics::pvData::PVStructure* _pvArguments; - epics::pvData::PVStructure* _pvResponse; - epics::pvData::BitSet* _argumentsBitSet; + ChannelRPC::shared_pointer _channelRPC; + epics::pvData::PVStructure::shared_pointer _pvArguments; + epics::pvData::PVStructure::shared_pointer _pvResponse; + epics::pvData::BitSet::shared_pointer _argumentsBitSet; epics::pvData::Status _status; }; } diff --git a/pvAccessApp/server/serverChannelImpl.cpp b/pvAccessApp/server/serverChannelImpl.cpp index 96b9d51..3d524f5 100644 --- a/pvAccessApp/server/serverChannelImpl.cpp +++ b/pvAccessApp/server/serverChannelImpl.cpp @@ -4,36 +4,33 @@ #include "serverChannelImpl.h" -// TODO remove -#include "responseHandlers.h" - +using namespace epics::pvData; namespace epics { namespace pvAccess { -ServerChannelImpl::ServerChannelImpl(Channel* channel, pvAccessID cid, - pvAccessID sid, epics::pvData::PVField* securityToken): +ServerChannelImpl::ServerChannelImpl(Channel::shared_pointer& channel, pvAccessID cid, pvAccessID sid, epics::pvData::PVField::shared_pointer& securityToken): _channel(channel), _cid(cid), _sid(cid), _destroyed(false) { - if (channel == NULL) + if (!channel.get()) { - THROW_BASE_EXCEPTION("non null local channel required"); + THROW_BASE_EXCEPTION("non-null channel required"); } } -Channel* ServerChannelImpl::getChannel() +Channel::shared_pointer ServerChannelImpl::getChannel() { return _channel; } -pvAccessID ServerChannelImpl::getCID() +pvAccessID ServerChannelImpl::getCID() const { return _cid; } -pvAccessID ServerChannelImpl::getSID() +pvAccessID ServerChannelImpl::getSID() const { return _sid; } @@ -44,13 +41,8 @@ int16 ServerChannelImpl::getAccessRights() return 0; } -void ServerChannelImpl::registerRequest(const pvAccessID id, Destroyable* request) +void ServerChannelImpl::registerRequest(const pvAccessID id, Destroyable::shared_pointer& request) { - if (request == NULL) - { - THROW_BASE_EXCEPTION("request == null"); - } - Lock guard(_mutex); _requests[id] = request; } @@ -65,19 +57,18 @@ void ServerChannelImpl::unregisterRequest(const pvAccessID id) } } -Destroyable* ServerChannelImpl::getRequest(const pvAccessID id) +Destroyable::shared_pointer ServerChannelImpl::getRequest(const pvAccessID id) { _iter = _requests.find(id); if(_iter != _requests.end()) { return _iter->second; } - return NULL; + return Destroyable::shared_pointer(); } void ServerChannelImpl::destroy() { - { Lock guard(_mutex); if (_destroyed) return; @@ -86,13 +77,9 @@ void ServerChannelImpl::destroy() // destroy all requests destroyAllRequests(); - // now thats ugly!!! - (static_cast(_channel->getChannelRequester()))->release(); - // TODO make impl that does shares channels (and does ref counting)!!! - // try catch? + // ... and the channel + // TODO try catch _channel->destroy(); - } - delete this; } void ServerChannelImpl::printInfo() diff --git a/pvAccessApp/server/serverChannelImpl.h b/pvAccessApp/server/serverChannelImpl.h index eff18c5..ed956e5 100644 --- a/pvAccessApp/server/serverChannelImpl.h +++ b/pvAccessApp/server/serverChannelImpl.h @@ -5,17 +5,19 @@ #ifndef SERVERCHANNEL_H_ #define SERVERCHANNEL_H_ -#include "remote.h" -#include "clientContextImpl.h" +#include +#include #include namespace epics { namespace pvAccess { -class ServerChannelImpl : public ServerChannel +class ServerChannelImpl : public ServerChannel { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; /** * Create server channel for given process variable. * @param channel local channel. @@ -23,29 +25,29 @@ public: * @param sid channel SID. * @param securityToken security token. */ - ServerChannelImpl(Channel* channel, pvAccessID cid, pvAccessID sid, epics::pvData::PVField* securityToken); + ServerChannelImpl(Channel::shared_pointer& channel, pvAccessID cid, pvAccessID sid, epics::pvData::PVField::shared_pointer& securityToken); /* * Destructor. */ - ~ServerChannelImpl() {}; + virtual ~ServerChannelImpl() {}; /** * Get local channel. * @return local channel. */ - Channel* getChannel(); + Channel::shared_pointer getChannel(); /** * Get channel CID. * @return channel CID. */ - pvAccessID getCID(); + pvAccessID getCID() const; /** * Get channel SID. * @return channel SID. */ - pvAccessID getSID(); + pvAccessID getSID() const; /** * Get access rights (bit-mask encoded). @@ -59,7 +61,7 @@ public: * @param id request ID. * @param request request to be registered. */ - void registerRequest(pvAccessID id, epics::pvData::Destroyable* request); + void registerRequest(pvAccessID id, epics::pvData::Destroyable::shared_pointer& request); /** * Unregister request. @@ -72,7 +74,7 @@ public: * @param id request ID. * @return request with given ID, null if there is no request with such ID. */ - epics::pvData::Destroyable* getRequest(pvAccessID id); + epics::pvData::Destroyable::shared_pointer getRequest(pvAccessID id); /** * Destroy server channel. @@ -94,7 +96,7 @@ private: /** * Local channel. */ - Channel* _channel; + Channel::shared_pointer _channel; /** * Channel CID. @@ -109,12 +111,13 @@ private: /** * Requests. */ - std::map _requests; + std::map _requests; /** * Requests iterator. */ - std::map::iterator _iter; + // TODO remove + std::map::iterator _iter; /** * Destroy state. diff --git a/pvAccessApp/server/serverContext.cpp b/pvAccessApp/server/serverContext.cpp index 4f906a8..ffa7107 100644 --- a/pvAccessApp/server/serverContext.cpp +++ b/pvAccessApp/server/serverContext.cpp @@ -5,6 +5,9 @@ #include "serverContext.h" #include "responseHandlers.h" +using std::tr1::dynamic_pointer_cast; +using std::tr1::static_pointer_cast; + namespace epics { namespace pvAccess { const char* ServerContextImpl::StateNames[] = { "NOT_INITIALIZED", "INITIALIZED", "RUNNING", "SHUTDOWN", "DESTROYED"}; @@ -28,28 +31,29 @@ ServerContextImpl::ServerContextImpl(): _broadcastPort(CA_BROADCAST_PORT), _serverPort(CA_SERVER_PORT), _receiveBufferSize(MAX_TCP_RECV), - _timer(NULL), - _broadcastTransport(NULL), - _beaconEmitter(NULL), - _acceptor(NULL), - _transportRegistry(NULL), - _channelAccess(NULL), - _channelProviderName(CAJ_DEFAULT_PROVIDER), - _channelProvider(NULL), - _beaconServerStatusProvider(NULL) + _timer(), + _broadcastTransport(), + _beaconEmitter(), + _acceptor(), + _transportRegistry(), + _channelAccess(), + _channelProviderName(PVACCESS_DEFAULT_PROVIDER), + _channelProvider(), + _beaconServerStatusProvider() { initializeLogger(); loadConfiguration(); } +ServerContextImpl::shared_pointer ServerContextImpl::create() +{ + ServerContextImpl::shared_pointer thisPointer(new ServerContextImpl()); + return thisPointer; +} + ServerContextImpl::~ServerContextImpl() { - if(_beaconEmitter) delete _beaconEmitter; - if(_broadcastTransport) delete _broadcastTransport; - if(_acceptor) delete _acceptor; - if(_transportRegistry) delete _transportRegistry; - if(_timer) delete _timer; } const Version& ServerContextImpl::getVersion() @@ -62,15 +66,23 @@ void ServerContextImpl::initializeLogger() //createFileLogger("serverContextImpl.log"); } -Configuration* ServerContextImpl::getConfiguration() + struct noop_deleter + { + template void operator()(T * p) + { + } + }; + +Configuration::shared_pointer ServerContextImpl::getConfiguration() { - ConfigurationProvider* configurationProvider = ConfigurationFactory::getProvider(); + ConfigurationProvider* configurationProvider = ConfigurationFactory::getProvider(); Configuration* config = configurationProvider->getConfiguration("pvAccess-server"); if (config == NULL) { config = configurationProvider->getConfiguration("system"); } - return config; + return Configuration::shared_pointer(config, noop_deleter()); + // TODO cache !!! } /** @@ -78,7 +90,7 @@ Configuration* ServerContextImpl::getConfiguration() */ void ServerContextImpl::loadConfiguration() { - Configuration* config = getConfiguration(); + Configuration::shared_pointer config = getConfiguration(); _beaconAddressList = config->getPropertyAsString("EPICS4_CA_ADDR_LIST", _beaconAddressList); _beaconAddressList = config->getPropertyAsString("EPICS4_CAS_BEACON_ADDR_LIST", _beaconAddressList); @@ -102,7 +114,7 @@ void ServerContextImpl::loadConfiguration() _channelProviderName = config->getPropertyAsString("EPICS4_CAS_PROVIDER_NAME", _channelProviderName); } -void ServerContextImpl::initialize(ChannelAccess* channelAccess) +void ServerContextImpl::initialize(ChannelAccess::shared_pointer& channelAccess) { Lock guard(_mutex); if (channelAccess == NULL) @@ -133,19 +145,28 @@ void ServerContextImpl::initialize(ChannelAccess* channelAccess) _state = INITIALIZED; } +std::auto_ptr ServerContextImpl::createResponseHandler() +{ + ServerContextImpl::shared_pointer thisContext = shared_from_this(); + return std::auto_ptr(new ServerResponseHandler(thisContext)); +} + void ServerContextImpl::internalInitialize() { - //TODO should be allocated on stack - _timer = new Timer("pvAccess-server timer",lowerPriority); - _transportRegistry = new TransportRegistry(); + _timer.reset(new Timer("pvAccess-server timer",lowerPriority)); + _transportRegistry.reset(new TransportRegistry()); // setup broadcast UDP transport initializeBroadcastTransport(); - _acceptor = new BlockingTCPAcceptor(this, _serverPort, _receiveBufferSize); + Context::shared_pointer thisContext = shared_from_this(); + ResponseHandlerFactory::shared_pointer thisFactory = shared_from_this(); + _acceptor.reset(new BlockingTCPAcceptor(thisContext, thisFactory, _serverPort, _receiveBufferSize)); _serverPort = ntohs(_acceptor->getBindAddress()->ia.sin_port); - _beaconEmitter = new BeaconEmitter(_broadcastTransport, this); + ServerContextImpl::shared_pointer thisServerContext = shared_from_this(); + Transport::shared_pointer transport = _broadcastTransport; + _beaconEmitter.reset(new BeaconEmitter(transport, thisServerContext)); } void ServerContextImpl::initializeBroadcastTransport() @@ -168,11 +189,14 @@ void ServerContextImpl::initializeBroadcastTransport() auto_ptr broadcastAddresses(getBroadcastAddresses(socket,_broadcastPort)); epicsSocketDestroy(socket); + TransportClient::shared_pointer nullTransportClient; + auto_ptr broadcastConnector(new BlockingUDPConnector(true, true)); - _broadcastTransport = static_cast(broadcastConnector->connect( - NULL, new ServerResponseHandler(this), - listenLocalAddress, CA_MINOR_PROTOCOL_REVISION, - CA_DEFAULT_PRIORITY)); + auto_ptr responseHandler = createResponseHandler(); + _broadcastTransport = static_pointer_cast(broadcastConnector->connect( + nullTransportClient, responseHandler, + listenLocalAddress, CA_MINOR_PROTOCOL_REVISION, + CA_DEFAULT_PRIORITY)); _broadcastTransport->setBroadcastAddresses(broadcastAddresses.get()); // set ignore address list @@ -299,18 +323,21 @@ void ServerContextImpl::internalDestroy() if (_broadcastTransport != NULL) { _broadcastTransport->close(true); + _broadcastTransport.reset(); } // stop accepting connections if (_acceptor != NULL) { _acceptor->destroy(); + _acceptor.reset(); } // stop emitting beacons if (_beaconEmitter != NULL) { _beaconEmitter->destroy(); + _beaconEmitter.reset(); } // this will also destroy all channels @@ -326,20 +353,19 @@ void ServerContextImpl::destroyAllTransports() return; } - int32 size; - Transport** transports = _transportRegistry->toArray(size); - + std::auto_ptr transports = _transportRegistry->toArray(); + if (transports.get() == 0) + return; + + int size = (int)transports->size(); if (size == 0) - { - delete[] transports; return; - } errlogSevPrintf(errlogInfo, "Server context still has %d transport(s) active and closing...", size); for (int i = 0; i < size; i++) { - Transport* transport = transports[i]; + Transport::shared_pointer transport = (*transports)[i]; try { transport->close(true); @@ -356,7 +382,9 @@ void ServerContextImpl::destroyAllTransports() } } - delete[] transports; + // now clear all (release) + _transportRegistry->clear(); + } void ServerContextImpl::printInfo() @@ -391,7 +419,7 @@ void ServerContextImpl::dispose() } } -void ServerContextImpl::setBeaconServerStatusProvider(BeaconServerStatusProvider* beaconServerStatusProvider) +void ServerContextImpl::setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer& beaconServerStatusProvider) { _beaconServerStatusProvider = beaconServerStatusProvider; } @@ -448,7 +476,7 @@ std::string ServerContextImpl::getIgnoreAddressList() return _ignoreAddressList; } -BeaconServerStatusProvider* ServerContextImpl::getBeaconServerStatusProvider() +BeaconServerStatusProvider::shared_pointer ServerContextImpl::getBeaconServerStatusProvider() { return _beaconServerStatusProvider; } @@ -457,17 +485,17 @@ osiSockAddr* ServerContextImpl::getServerInetAddress() { if(_acceptor != NULL) { - return _acceptor->getBindAddress(); + return const_cast(_acceptor->getBindAddress()); } return NULL; } -BlockingUDPTransport* ServerContextImpl::getBroadcastTransport() +BlockingUDPTransport::shared_pointer ServerContextImpl::getBroadcastTransport() { return _broadcastTransport; } -ChannelAccess* ServerContextImpl::getChannelAccess() +ChannelAccess::shared_pointer ServerContextImpl::getChannelAccess() { return _channelAccess; } @@ -484,41 +512,38 @@ void ServerContextImpl::setChannelProviderName(std::string channelProviderName) _channelProviderName = channelProviderName; } -ChannelProvider* ServerContextImpl::getChannelProvider() +ChannelProvider::shared_pointer ServerContextImpl::getChannelProvider() { return _channelProvider; } -Timer* ServerContextImpl::getTimer() +Timer::shared_pointer ServerContextImpl::getTimer() { return _timer; } -TransportRegistry* ServerContextImpl::getTransportRegistry() +TransportRegistry::shared_pointer ServerContextImpl::getTransportRegistry() { return _transportRegistry; } -Channel* ServerContextImpl::getChannel(pvAccessID id) +Channel::shared_pointer ServerContextImpl::getChannel(pvAccessID id) { - //TODO - return NULL; + //TODO, not used + return Channel::shared_pointer(); } -Transport* ServerContextImpl::getSearchTransport() +Transport::shared_pointer ServerContextImpl::getSearchTransport() { - //TODO - return NULL; + //TODO, not used + return Transport::shared_pointer(); } -void ServerContextImpl::acquire() +void ServerContextImpl::beaconAnomalyNotify() { - // TODO -} -void ServerContextImpl::release() -{ - // TODO + // noop } + } } diff --git a/pvAccessApp/server/serverContext.h b/pvAccessApp/server/serverContext.h index 162e5c9..ff79dc5 100644 --- a/pvAccessApp/server/serverContext.h +++ b/pvAccessApp/server/serverContext.h @@ -5,16 +5,15 @@ #ifndef SERVERCONTEXT_H_ #define SERVERCONTEXT_H_ -#include "remote.h" -#include "beaconServerStatusProvider.h" -#include "caConstants.h" -#include "version.h" -#include "pvAccess.h" -#include "logger.h" -#include "blockingUDP.h" -#include "blockingTCP.h" +#include +#include +#include +#include +#include +#include +#include #include "beaconEmitter.h" -#include "logger.h" +#include #include @@ -24,10 +23,13 @@ namespace pvAccess { /** * The class representing a CA Server context. */ -class ServerContext +class ServerContext { public: - /** + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + /** * Destructor */ virtual ~ServerContext() {}; @@ -41,7 +43,7 @@ public: * Set ChannelAccess implementation and initialize server. * @param channelAccess implementation of channel access to be served. */ - virtual void initialize(ChannelAccess* channelAccess) = 0; + virtual void initialize(ChannelAccess::shared_pointer& channelAccess) = 0; /** * Run server (process events). @@ -89,38 +91,46 @@ public: * Set beacon server status provider. * @param beaconServerStatusProvider BeaconServerStatusProvider implementation to set. */ - virtual void setBeaconServerStatusProvider(BeaconServerStatusProvider* beaconServerStatusProvider) = 0; + virtual void setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer& beaconServerStatusProvider) = 0; }; -class BeaconEmitter; - -class ServerContextImpl : public ServerContext, public Context +class ServerContextImpl : + public ServerContext, + public Context, + public ResponseHandlerFactory, + public std::tr1::enable_shared_from_this { public: - /** - * Constructor. - */ + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; +protected: ServerContextImpl(); +public: + static ServerContextImpl::shared_pointer create(); + virtual ~ServerContextImpl(); //**************** derived from ServerContext ****************// const Version& getVersion(); - void initialize(ChannelAccess* channelAccess); + void initialize(ChannelAccess::shared_pointer& channelAccess); void run(int32 seconds); void shutdown(); void destroy(); void printInfo(); void printInfo(ostream& str); void dispose(); - void setBeaconServerStatusProvider(BeaconServerStatusProvider* beaconServerStatusProvider); + void setBeaconServerStatusProvider(BeaconServerStatusProvider::shared_pointer& beaconServerStatusProvider); //**************** derived from Context ****************// - Timer* getTimer(); - Channel* getChannel(pvAccessID id); - Transport* getSearchTransport(); - Configuration* getConfiguration(); - TransportRegistry* getTransportRegistry(); + Timer::shared_pointer getTimer(); + Channel::shared_pointer getChannel(pvAccessID id); + Transport::shared_pointer getSearchTransport(); + Configuration::shared_pointer getConfiguration(); + TransportRegistry::shared_pointer getTransportRegistry(); + + std::auto_ptr createResponseHandler(); + void beaconAnomalyNotify(); /** * Version. @@ -226,7 +236,7 @@ public: * Get registered beacon server status provider. * @return registered beacon server status provider. */ - BeaconServerStatusProvider* getBeaconServerStatusProvider(); + BeaconServerStatusProvider::shared_pointer getBeaconServerStatusProvider(); /** * Get server newtwork (IP) address. @@ -238,13 +248,13 @@ public: * Broadcast transport. * @return broadcast transport. */ - BlockingUDPTransport* getBroadcastTransport(); + BlockingUDPTransport::shared_pointer getBroadcastTransport(); /** * Get channel access implementation. * @return channel access implementation. */ - ChannelAccess* getChannelAccess(); + ChannelAccess::shared_pointer getChannelAccess(); /** * Get channel provider name. @@ -262,10 +272,7 @@ public: * Get channel provider. * @return channel provider. */ - ChannelProvider* getChannelProvider(); - - void release(); - void acquire(); + ChannelProvider::shared_pointer getChannelProvider(); private: /** @@ -333,33 +340,33 @@ private: /** * Timer. */ - epics::pvData::Timer* _timer; + epics::pvData::Timer::shared_pointer _timer; /** * Broadcast transport needed for channel searches. */ - BlockingUDPTransport* _broadcastTransport; + BlockingUDPTransport::shared_pointer _broadcastTransport; /** * Beacon emitter. */ - BeaconEmitter* _beaconEmitter; + BeaconEmitter::shared_pointer _beaconEmitter; /** * CAS acceptor (accepts CA virtual circuit). */ - BlockingTCPAcceptor* _acceptor; + BlockingTCPAcceptor::shared_pointer _acceptor; /** * CA transport (virtual circuit) registry. * This registry contains all active transports - connections to CA servers. */ - TransportRegistry* _transportRegistry; + TransportRegistry::shared_pointer _transportRegistry; /** * Channel access. */ - ChannelAccess* _channelAccess; + ChannelAccess::shared_pointer _channelAccess; /** * Channel provider name. @@ -369,7 +376,7 @@ private: /** * Channel provider. */ - ChannelProvider* _channelProvider; + ChannelProvider::shared_pointer _channelProvider; /** * Run mutex. @@ -384,7 +391,7 @@ private: /** * Beacon server status provider interface (optional). */ - BeaconServerStatusProvider* _beaconServerStatusProvider; + BeaconServerStatusProvider::shared_pointer _beaconServerStatusProvider; /** * Initialize logger. diff --git a/pvAccessApp/utils/arrayFIFO.h b/pvAccessApp/utils/arrayFIFO.h deleted file mode 100644 index c515c11..0000000 --- a/pvAccessApp/utils/arrayFIFO.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * arrayFIFO.h - * - * Created on: Nov 8, 2010 - * Author: Miha Vitorovic - */ - -#ifndef ARRAYFIFO_H_ -#define ARRAYFIFO_H_ - -#ifdef ARRAY_FIFO_DEBUG -#include -#endif - -#include -#include -#include - -namespace epics { - namespace pvAccess { - - template - class ArrayFIFO { - public: - /** - * Constructs an empty array deque with an initial capacity - * sufficient to hold the specified number of elements. Array FIFO - * is designed to hold objects allocated on the heap. - * - * @param[in] numElements lower bound on initial capacity of the - * deque. Default value is 16 elements. - */ - ArrayFIFO(size_t numElements = 16); - ~ArrayFIFO(); - - /** - * Inserts the specified element at the front of this deque. - * - * @param[in] e the element to add. - */ - void addFirst(const T e); - - /** - * Inserts the specified element at the end of this deque. - * @param[in] e the element to add - */ - void addLast(const T e); - - T pollFirst(); - T pollLast(); - T peekFirst(); - T peekLast(); - - /** - * Pushes an element onto the stack represented by this deque. In other - * words, inserts the element at the front of this deque. - * - * @param[in] e the element to push - */ - void push(const T e); - - /** - * Pops an element from the stack represented by this deque. In other - * words, removes and returns the first element of this deque. - * - * @return the element at the front of this deque (which is the top - * of the stack represented by this deque), null if no element available. - */ - T pop(); - - /** - * Looks at the object at the top of this stack without removing it - * from the stack. - * @return the object at the top of this stack (the last item - * of the Vector object). - */ - T peek(); - - /** - * Returns the number of elements in this deque. - * @return the number of elements in this deque - */ - size_t size(); - - /** - * Returns true if this deque contains no elements. - * - * @return true if this deque contains no elements - */ - bool isEmpty(); - - /** - * Removes all of the elements from this deque. - * The deque will be empty after this call returns. - * - * @param freeElements tells the methods to automatically free - * the memory of all the elments in the FIFO. Default is {@code true} - */ - void clear(); - - /** - * Removes the first occurrence of the specified element in this - * deque (when traversing the deque from head to tail). - * If the deque does not contain the element, it is unchanged. - * More formally, removes the first element e such that - * o.equals(e) (if such an element exists). - * Returns true if this deque contained the specified element - * (or equivalently, if this deque changed as a result of the call). - * - * @param o element to be removed from this deque, if present - * @return true if the deque contained the specified element - */ - bool remove(const T e); - -#ifdef ARRAY_FIFO_DEBUG - void debugState() { - //size_t mask = _size-1; - std::cout<<"h:"<<_head<<",t:"<<_tail<<",c:"<<_size; - std::cout<<",s:"<This method is called delete rather than remove to emphasize - * that its semantics differ from those of {@link List#remove(int)}. - * - * @return true if elements moved backwards - */ - bool del(const size_t i); - - }; - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * g++ requires template definition inside a header file. - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - template - int ArrayFIFO::MIN_INITIAL_CAPACITY = 8; - - template - void ArrayFIFO::arraycopy(T* src, size_t srcPos, T* dest, - size_t destPos, size_t length) { - if(srcPos=0; i--) - dest[destPos+i] = src[srcPos+i]; - else - for(size_t i = 0; i - void ArrayFIFO::allocateElements(size_t numElements) { - _size = MIN_INITIAL_CAPACITY; - // Find the best power of two to hold elements. - // Tests "<=" because arrays aren't kept full. - if(numElements>=_size) { - _size = numElements; - _size |= (_size>>1); - _size |= (_size>>2); - _size |= (_size>>4); - _size |= (_size>>8); - _size |= (_size>>16); - _size++; - } - _elements = new T[_size]; - } - - template - void ArrayFIFO::doubleCapacity() { - size_t p = _head; - size_t n = _size; - size_t r = n-p; // number of elements to the right of p - size_t newCapacity = n<<1; - T* a = new T[newCapacity]; - arraycopy(_elements, p, a, 0, r); - arraycopy(_elements, 0, a, r, p); - delete[] _elements; - _elements = a; - _size = newCapacity; - _head = 0; - _tail = n; - - } - - template - ArrayFIFO::ArrayFIFO(size_t numElements) : - _head(0), _tail(0), _mutex() { - allocateElements(numElements); - } - - template - ArrayFIFO::~ArrayFIFO() { - delete[] _elements; - } - - template - void ArrayFIFO::addFirst(const T e) { - epics::pvData::Lock lock(_mutex); - - _elements[_head = (_head-1)&(_size-1)] = e; - if(_head==_tail) doubleCapacity(); - } - - template - void ArrayFIFO::addLast(const T e) { - epics::pvData::Lock lock(_mutex); - - _elements[_tail] = e; - if((_tail = (_tail+1)&(_size-1))==_head) doubleCapacity(); - } - - template - T ArrayFIFO::pollFirst() { - epics::pvData::Lock lock(_mutex); - - if(isEmpty()) return 0; - - T result = _elements[_head]; // Element is null if deque empty - _head = (_head+1)&(_size-1); - return result; - } - - template - T ArrayFIFO::pollLast() { - epics::pvData::Lock lock(_mutex); - - if(isEmpty()) return 0; - - _tail = (_tail-1)&(_size-1); - return _elements[_tail]; - } - - template - T ArrayFIFO::peekFirst() { - epics::pvData::Lock lock(_mutex); - - if(isEmpty()) return 0; - - return _elements[_head]; - } - - template - T ArrayFIFO::peekLast() { - epics::pvData::Lock lock(_mutex); - - if(isEmpty()) return 0; - - return _elements[(_tail-1)&(_size-1)]; - } - - template - void ArrayFIFO::push(const T e) { - addLast(e); - } - - template - T ArrayFIFO::pop() { - return pollLast(); - } - - template - T ArrayFIFO::peek() { - return peekFirst(); - } - - template - size_t ArrayFIFO::size() { - epics::pvData::Lock lock(_mutex); - - return (_tail-_head)&(_size-1); - } - - template - bool ArrayFIFO::isEmpty() { - epics::pvData::Lock lock(_mutex); - - return _head==_tail; - } - - template - void ArrayFIFO::clear() { - epics::pvData::Lock lock(_mutex); - - _head = _tail = 0; - } - - template - bool ArrayFIFO::del(const size_t i) { - // i is absolute index in the array - size_t mask = _size-1; - size_t h = _head; - size_t t = _tail; - size_t front = (i-h)&mask; - size_t back = (t-i)&mask; - - // Invariant: head <= i < tail mod circularity - assert(front<((t-h)&mask)); // concurrency problem detected - - // Optimize for least element motion - if(front0) _elements[0] = _elements[mask]; - arraycopy(_elements, h, _elements, h+1, mask-h); - } - _head = (h+1)&mask; - - return false; - } - else { - if(i - bool ArrayFIFO::remove(const T e) { - epics::pvData::Lock lock(_mutex); - - if(isEmpty()) return false; // nothing to do - - size_t mask = _size-1; - size_t i = _head; - while(i!=_tail) { - if(e==_elements[i]) { - del(i); - return true; - } - i = (i+1)&mask; - } - return false; - } - - } -} - -#endif /* ARRAYFIFO_H_ */ diff --git a/pvAccessApp/utils/configuration.h b/pvAccessApp/utils/configuration.h index 74a4363..dcf6454 100644 --- a/pvAccessApp/utils/configuration.h +++ b/pvAccessApp/utils/configuration.h @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -72,6 +73,9 @@ private: class Configuration : private epics::pvData::NoDefaultMethods { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + /* * Destructor. */ diff --git a/pvAccessApp/utils/growingCircularBuffer.h b/pvAccessApp/utils/growingCircularBuffer.h deleted file mode 100644 index cf58111..0000000 --- a/pvAccessApp/utils/growingCircularBuffer.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * growingCircularBuffer.h - * - * Created on: Nov 11, 2010 - * Author: Miha Vitorovic - */ - -#ifndef GROWINGCIRCULARBUFFER_H_ -#define GROWINGCIRCULARBUFFER_H_ - -// TODO remove exception throwing !!! - -#include - -namespace epics { - namespace pvAccess { - - /** - * Implementation of circular FIFO unbouded buffer. - * Instance is not thread safe. - * @author Miha Vitorovic - */ - template - class GrowingCircularBuffer { - public: - - /** - * Create a GrowingCircularBuffer with the given capacity. - **/ - GrowingCircularBuffer(size_t capacity = 16) : - _elements(new T[capacity]), _takePointer(0), _putPointer(0), - _count(0), _size(capacity) { - } - - ~GrowingCircularBuffer() { - delete[] _elements; - } - - /** - * Get number of elements in the buffer. - * @return number of elements in the buffer. - */ - inline size_t size() { - return _count; - } - - /** - * Get current buffer capacity. - * @return buffer current capacity. - */ - inline size_t capacity() { - return _size; - } - - /** - * Insert a new element in to the buffer. - * If buffer full the buffer is doubled. - * - * @param x element to insert. - * @return true if first element. - */ - bool insert(const T x); - - /** - * Extract the oldest element from the buffer. - * @return the oldest element from the buffer. - */ - T extract(); - - private: - /** - * Array (circular buffer) of elements. - */ - T* _elements; - - /** - * Take (read) pointer. - */ - size_t _takePointer; - - /** - * Put (write) pointer. - */ - size_t _putPointer; - - /** - * Number of elements in the buffer. - */ - size_t _count; - - size_t _size; - - void arraycopy(T* src, size_t srcPos, T* dest, size_t destPos, - size_t length); - }; - - template - void GrowingCircularBuffer::arraycopy(T* src, size_t srcPos, - T* dest, size_t destPos, size_t length) { - if(srcPos=0; i--) - dest[destPos+i] = src[srcPos+i]; - else - for(size_t i = 0; i - bool GrowingCircularBuffer::insert(const T x) { - if(_count==_size) { - // we are full, grow by factor 2 - T* newElements = new T[_size*2]; - - // invariant: _takePointer < _size - size_t split = _size-_takePointer; - if(split>0) arraycopy(_elements, _takePointer, newElements, 0, - split); - if(_takePointer!=0) arraycopy(_elements, 0, newElements, split, - _putPointer); - - _takePointer = 0; - _putPointer = _size; - _size *= 2; - delete[] _elements; - _elements = newElements; - } - _count++; - - _elements[_putPointer] = x; - if(++_putPointer>=_size) _putPointer = 0; - return _count==1; - } - - template - T GrowingCircularBuffer::extract() { - if(_count==0) THROW_BASE_EXCEPTION("Buffer empty."); - - _count--; - T old = _elements[_takePointer]; - if(++_takePointer>=_size) _takePointer = 0; - return old; - } - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Template specialization for pointers. - * Implementation of circular FIFO unbouded buffer. - * Instance is not thread safe. - * @author Miha Vitorovic - */ - template - class GrowingCircularBuffer { - public: - - /** - * Create a GrowingCircularBuffer with the given capacity. - **/ - GrowingCircularBuffer(size_t capacity = 16) : - _elements(new T*[capacity]), _takePointer(0), _putPointer(0), - _count(0), _size(capacity) { - } - - ~GrowingCircularBuffer() { - delete[] _elements; - } - - /** - * Get number of elements in the buffer. - * @return number of elements in the buffer. - */ - inline size_t size() { - return _count; - } - - /** - * Get current buffer capacity. - * @return buffer current capacity. - */ - inline size_t capacity() { - return _size; - } - - /** - * Insert a new element in to the buffer. - * If buffer full the buffer is doubled. - * - * @param x element to insert. - * @return true if first element. - */ - bool insert(const T* x); - - /** - * Extract the oldest element from the buffer. - * @return the oldest element from the buffer. - */ - T* extract(); - - private: - /** - * Array (circular buffer) of elements. - */ - T** _elements; - - /** - * Take (read) pointer. - */ - size_t _takePointer; - - /** - * Put (write) pointer. - */ - size_t _putPointer; - - /** - * Number of elements in the buffer. - */ - size_t _count; - - size_t _size; - - void arraycopy(T** src, size_t srcPos, T** dest, size_t destPos, - size_t length); - }; - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * g++ requires template definition inside a header file. - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - template - void GrowingCircularBuffer::arraycopy(T** src, size_t srcPos, - T** dest, size_t destPos, size_t length) { - if(srcPos=0; i--) - dest[destPos+i] = src[srcPos+i]; - else - for(size_t i = 0; i - bool GrowingCircularBuffer::insert(const T* x) { - if(_count==_size) { - // we are full, grow by factor 2 - T** newElements = new T*[_size*2]; - - // invariant: _takePointer < _size - size_t split = _size-_takePointer; - if(split>0) arraycopy(_elements, _takePointer, newElements, 0, - split); - if(_takePointer!=0) arraycopy(_elements, 0, newElements, split, - _putPointer); - - _takePointer = 0; - _putPointer = _size; - _size *= 2; - delete[] _elements; - _elements = newElements; - } - _count++; - - _elements[_putPointer] = const_cast(x); - if(++_putPointer>=_size) _putPointer = 0; - return _count==1; - } - - template - T* GrowingCircularBuffer::extract() { - if(_count==0) return NULL; - - _count--; - T* old = _elements[_takePointer]; - if(++_takePointer>=_size) _takePointer = 0; - return old; - } - - } -} -#endif /* GROWINGCIRCULARBUFFER_H_ */ diff --git a/pvAccessApp/utils/introspectionRegistry.cpp b/pvAccessApp/utils/introspectionRegistry.cpp index 18f5567..b401114 100644 --- a/pvAccessApp/utils/introspectionRegistry.cpp +++ b/pvAccessApp/utils/introspectionRegistry.cpp @@ -3,6 +3,9 @@ */ #include "introspectionRegistry.h" +#include + +using std::tr1::static_pointer_cast; namespace epics { namespace pvAccess { @@ -12,7 +15,7 @@ const int8 IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE = (int8)-3; PVDataCreate* IntrospectionRegistry::_pvDataCreate = 0; FieldCreate* IntrospectionRegistry::_fieldCreate = 0; -IntrospectionRegistry::IntrospectionRegistry(bool serverSide) : _mutex() +IntrospectionRegistry::IntrospectionRegistry(bool serverSide) { // TODO not optimal _pvDataCreate = getPVDataCreate(); @@ -31,11 +34,7 @@ void IntrospectionRegistry::reset() { Lock guard(_mutex); _outgoingIdPointer = _direction; - //decrement references - for(_registryRIter = _registry.rbegin(); _registryRIter != _registry.rend(); _registryRIter++) - { - _registryRIter->second->decReferenceCount(); - } + _registry.clear(); } @@ -45,7 +44,7 @@ FieldConstPtr IntrospectionRegistry::getIntrospectionInterface(const short id) _registryIter = _registry.find(id); if(_registryIter == _registry.end()) { - return NULL; + return FieldConstPtr(); } return _registryIter->second; } @@ -53,14 +52,11 @@ FieldConstPtr IntrospectionRegistry::getIntrospectionInterface(const short id) void IntrospectionRegistry::registerIntrospectionInterface(const short id,FieldConstPtr field) { Lock guard(_mutex); - //first decrement reference on old value + _registryIter = _registry.find(id); - if(_registryIter != _registry.end()) - { - _registryIter->second->decReferenceCount(); - } + _registry[id] = field; - field->incReferenceCount(); + } short IntrospectionRegistry::registerIntrospectionInterface(FieldConstPtr field, bool& existing) @@ -84,13 +80,9 @@ short IntrospectionRegistry::registerIntrospectionInterface(FieldConstPtr field, //first decrement reference on old value _registryIter = _registry.find(key); - if(_registryIter != _registry.end()) - { - _registryIter->second->decReferenceCount(); - } _registry[key] = field; - field->incReferenceCount(); + } return key; } @@ -104,7 +96,7 @@ void IntrospectionRegistry::printKeysAndValues(string name) buffer.clear(); cout << "\t" << "Key: "<< _registryIter->first << endl; cout << "\t" << "Value: " << _registryIter->second << endl; - _registryIter->second->dumpReferenceCount(&buffer,0); + cout << "\t" << "References: " << buffer.c_str() << endl; buffer.clear(); _registryIter->second->toString(&buffer); @@ -127,7 +119,7 @@ bool IntrospectionRegistry::registryContainsValue(FieldConstPtr field, short& ke void IntrospectionRegistry::serialize(FieldConstPtr field, ByteBuffer* buffer, SerializableControl* control) { - serialize(field, NULL, buffer, control, this); + serialize(field, StructureConstPtr(), buffer, control, this); } FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, DeserializableControl* control) @@ -137,7 +129,7 @@ FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, Deserializa void IntrospectionRegistry::serializeFull(FieldConstPtr field, ByteBuffer* buffer, SerializableControl* control) { - serialize(field, NULL, buffer, control, NULL); + serialize(field, StructureConstPtr(), buffer, control, NULL); } FieldConstPtr IntrospectionRegistry::deserializeFull(ByteBuffer* buffer, DeserializableControl* control) @@ -181,7 +173,7 @@ void IntrospectionRegistry::serialize(FieldConstPtr field, StructureConstPtr par { case epics::pvData::scalar: { - ScalarConstPtr scalar = static_cast(field); + ScalarConstPtr scalar = static_pointer_cast(field); control->ensureBuffer(1); buffer->putByte((int8)(epics::pvData::scalar << 4 | scalar->getScalarType())); SerializeHelper::serializeString(field->getFieldName(), buffer, control); @@ -189,7 +181,7 @@ void IntrospectionRegistry::serialize(FieldConstPtr field, StructureConstPtr par } case epics::pvData::scalarArray: { - ScalarArrayConstPtr array = static_cast(field); + ScalarArrayConstPtr array = static_pointer_cast(field); control->ensureBuffer(1); buffer->putByte((int8)(epics::pvData::scalarArray << 4 | array->getElementType())); SerializeHelper::serializeString(field->getFieldName(), buffer, control); @@ -197,7 +189,7 @@ void IntrospectionRegistry::serialize(FieldConstPtr field, StructureConstPtr par } case epics::pvData::structure: { - StructureConstPtr structure = static_cast(field); + StructureConstPtr structure = static_pointer_cast(field); control->ensureBuffer(1); buffer->putByte((int8)(epics::pvData::structure << 4)); serializeStructureField(buffer, control, registry, structure); @@ -205,12 +197,12 @@ void IntrospectionRegistry::serialize(FieldConstPtr field, StructureConstPtr par } case epics::pvData::structureArray: { - StructureArrayConstPtr structureArray = static_cast(field); + StructureArrayConstPtr structureArray = static_pointer_cast(field); control->ensureBuffer(1); buffer->putByte((int8)(epics::pvData::structureArray << 4)); SerializeHelper::serializeString(field->getFieldName(), buffer, control); // we also need to serialize structure field... - const Structure* structureElement = structureArray->getStructure(); + StructureConstPtr structureElement = structureArray->getStructure(); serializeStructureField(buffer, control, registry, structureElement); break; } @@ -236,13 +228,13 @@ FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, Deserializa const int8 typeCode = buffer->getByte(); if(typeCode == IntrospectionRegistry::NULL_TYPE_CODE) { - return NULL; + return FieldConstPtr(); } else if(typeCode == IntrospectionRegistry::ONLY_ID_TYPE_CODE) { control->ensureData(sizeof(int16)/sizeof(int8)); FieldConstPtr field = registry->getIntrospectionInterface(buffer->getShort()); - field->incReferenceCount(); // we inc, so that deserialize always returns a field with +1 ref. count (as when created) + return field; } @@ -286,7 +278,7 @@ FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, Deserializa default: { // TODO log - return NULL; + return FieldConstPtr(); } } } @@ -313,7 +305,7 @@ void IntrospectionRegistry::serializeStructure(ByteBuffer* buffer, SerializableC { if (pvStructure == NULL) { - serialize(NULL, buffer, control); + serialize(StructureConstPtr(), buffer, control); } else { @@ -328,7 +320,8 @@ PVStructurePtr IntrospectionRegistry::deserializeStructure(ByteBuffer* buffer, D FieldConstPtr structureField = deserialize(buffer, control); if (structureField != NULL) { - pvStructure = _pvDataCreate->createPVStructure(NULL, static_cast(structureField)); + pvStructure = _pvDataCreate->createPVStructure(NULL, + static_pointer_cast(structureField)); pvStructure->deserialize(buffer, control); } return pvStructure; @@ -353,7 +346,8 @@ PVStructurePtr IntrospectionRegistry::deserializeStructureAndCreatePVStructure(B { return NULL; } - PVStructurePtr retVal = _pvDataCreate->createPVStructure(NULL,static_cast(field)); + PVStructurePtr retVal = _pvDataCreate->createPVStructure(NULL, + static_pointer_cast(field)); return retVal; } diff --git a/pvAccessApp/utils/introspectionRegistry.h b/pvAccessApp/utils/introspectionRegistry.h index afb8235..4d3b44c 100644 --- a/pvAccessApp/utils/introspectionRegistry.h +++ b/pvAccessApp/utils/introspectionRegistry.h @@ -26,7 +26,7 @@ using namespace std; namespace epics { namespace pvAccess { -typedef std::map registryMap_t; +typedef std::map registryMap_t; /** @@ -34,10 +34,11 @@ typedef std::map registryMap_t; * Registry is used to cache introspection interfaces to minimize network traffic. * @author gjansa */ - class IntrospectionRegistry { + class IntrospectionRegistry : public NoDefaultMethods { public: IntrospectionRegistry(bool serverSide); virtual ~IntrospectionRegistry(); + void printKeysAndValues(string name); /** * Resets registry, i.e. must be done when transport is changed (server restarted). diff --git a/pvAccessApp/utils/namedLockPattern.cpp b/pvAccessApp/utils/namedLockPattern.cpp deleted file mode 100644 index 538d502..0000000 --- a/pvAccessApp/utils/namedLockPattern.cpp +++ /dev/null @@ -1,7 +0,0 @@ -/* - * namedLockPattern.cpp - */ - -#include "namedLockPattern.h" - -//NOTE NamedLockPattern is template so implementation is in header file diff --git a/pvAccessApp/utils/namedLockPattern.h b/pvAccessApp/utils/namedLockPattern.h index 6bed798..36f75c0 100644 --- a/pvAccessApp/utils/namedLockPattern.h +++ b/pvAccessApp/utils/namedLockPattern.h @@ -13,7 +13,10 @@ #include "referenceCountingLock.h" +// TODO implement using smart pointers + namespace epics { namespace pvAccess { + /** * NamedLockPattern */ @@ -41,12 +44,12 @@ public: * @return true if acquired, false othwerwise. * NOTE: currently this routine always returns true. Look above for explanation. */ - bool acquireSynchronizationObject(const Key name, const epics::pvData::int64 msec); + bool acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec); /** * Release synchronization lock for named object. * @param name name of the object whose lock to release. */ - void releaseSynchronizationObject(const Key name); + void releaseSynchronizationObject(const Key& name); private: epics::pvData::Mutex _mutex; std::map _namedLocks; @@ -58,11 +61,11 @@ private: * @param release set to false if there is no need to call release * on synchronization lock. */ - void releaseSynchronizationObject(const Key name,const bool release); + void releaseSynchronizationObject(const Key& name,const bool release); }; template -bool NamedLockPattern::acquireSynchronizationObject(const Key name, const epics::pvData::int64 msec) +bool NamedLockPattern::acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec) { ReferenceCountingLock* lock; { //due to guard @@ -96,13 +99,13 @@ bool NamedLockPattern::acquireSynchronizationObject(const Key name, } template -void NamedLockPattern::releaseSynchronizationObject(const Key name) +void NamedLockPattern::releaseSynchronizationObject(const Key& name) { releaseSynchronizationObject(name, true); } template -void NamedLockPattern::releaseSynchronizationObject(const Key name,const bool release) +void NamedLockPattern::releaseSynchronizationObject(const Key& name,const bool release) { epics::pvData::Lock guard(_mutex); ReferenceCountingLock* lock; @@ -134,7 +137,7 @@ class NamedLock : private epics::pvData::NoDefaultMethods { public: NamedLock(NamedLockPattern* namedLockPattern): _namedLockPattern(namedLockPattern) {} - bool acquireSynchronizationObject(const Key name, const epics::pvData::int64 msec) {_name = name; return _namedLockPattern->acquireSynchronizationObject(name,msec);} + bool acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec) {_name = name; return _namedLockPattern->acquireSynchronizationObject(name,msec);} ~NamedLock(){_namedLockPattern->releaseSynchronizationObject(_name);} private: Key _name; diff --git a/pvAccessApp/utils/transportRegistry.cpp b/pvAccessApp/utils/transportRegistry.cpp index 12858d6..ad0c82a 100644 --- a/pvAccessApp/utils/transportRegistry.cpp +++ b/pvAccessApp/utils/transportRegistry.cpp @@ -9,100 +9,97 @@ using namespace std; namespace epics { namespace pvAccess { -TransportRegistry::TransportRegistry(): _mutex() +TransportRegistry::TransportRegistry(): _transports(), _transportCount(0), _mutex() { } TransportRegistry::~TransportRegistry() { - clear(); } -void TransportRegistry::put(Transport* transport) +void TransportRegistry::put(Transport::shared_pointer& transport) { Lock guard(_mutex); //const String type = transport.getType(); const int16 priority = transport->getPriority(); const osiSockAddr* address = transport->getRemoteAddress(); - _transportsIter = _transports.find(address); - prioritiesMap_t* priorities; - if(_transportsIter == _transports.end()) + transportsMap_t::iterator transportsIter = _transports.find(address); + prioritiesMapSharedPtr_t priorities; + if(transportsIter == _transports.end()) { - priorities = new prioritiesMap_t(); + priorities.reset(new prioritiesMap_t()); _transports[address] = priorities; + _transportCount++; } else { - priorities = _transportsIter->second; - } - (*priorities)[priority] = transport; - _allTransports.push_back(transport); -} - -Transport* TransportRegistry::get(const String type, const osiSockAddr* address, const int16 priority) -{ - Lock guard(_mutex); - _transportsIter = _transports.find(address); - if(_transportsIter != _transports.end()) - { - prioritiesMap_t* priorities = _transportsIter->second; - _prioritiesIter = priorities->find(priority); - if(_prioritiesIter != priorities->end()) + priorities = transportsIter->second; + prioritiesMap_t::iterator prioritiesIter = priorities->find(priority); + if(prioritiesIter == priorities->end()) //only increase transportCount if not replacing { - return _prioritiesIter->second; + _transportCount++; } } - return NULL; + (*priorities)[priority] = transport; } -Transport** TransportRegistry::get(const String type, const osiSockAddr* address, int32& size) +Transport::shared_pointer TransportRegistry::get(String type, const osiSockAddr* address, const int16 priority) { Lock guard(_mutex); - _transportsIter = _transports.find(address); - if(_transportsIter != _transports.end()) + transportsMap_t::iterator transportsIter = _transports.find(address); + if(transportsIter != _transports.end()) { - prioritiesMap_t* priorities = _transportsIter->second; - size = priorities->size(); - Transport** transportArray = new Transport*[size]; - int i = 0; - for(_prioritiesIter = priorities->begin(); _prioritiesIter != priorities->end(); _prioritiesIter++, i++) + prioritiesMapSharedPtr_t priorities = transportsIter->second; + prioritiesMap_t::iterator prioritiesIter = priorities->find(priority); + if(prioritiesIter != priorities->end()) { - transportArray[i] = _prioritiesIter->second; + return prioritiesIter->second; + } + } + return Transport::shared_pointer(); +} + +auto_ptr TransportRegistry::get(String type, const osiSockAddr* address) +{ + Lock guard(_mutex); + transportsMap_t::iterator transportsIter = _transports.find(address); + if(transportsIter != _transports.end()) + { + prioritiesMapSharedPtr_t priorities = transportsIter->second; + auto_ptr transportArray(new transportVector_t(priorities->size())); + int32 i = 0; + for(prioritiesMap_t::iterator prioritiesIter = priorities->begin(); + prioritiesIter != priorities->end(); + prioritiesIter++, i++) + { + transportArray->at(i) = prioritiesIter->second; } return transportArray; } - return NULL; + return auto_ptr(); } -Transport* TransportRegistry::remove(Transport* transport) +Transport::shared_pointer TransportRegistry::remove(Transport::shared_pointer& transport) { Lock guard(_mutex); const int16 priority = transport->getPriority(); const osiSockAddr* address = transport->getRemoteAddress(); - Transport* retTransport = NULL; - _transportsIter = _transports.find(address); - if(_transportsIter != _transports.end()) + Transport::shared_pointer retTransport; + transportsMap_t::iterator transportsIter = _transports.find(address); + if(transportsIter != _transports.end()) { - prioritiesMap_t* priorities = _transportsIter->second; - _prioritiesIter = priorities->find(priority); - if(_prioritiesIter != priorities->end()) + prioritiesMapSharedPtr_t priorities = transportsIter->second; + prioritiesMap_t::iterator prioritiesIter = priorities->find(priority); + if(prioritiesIter != priorities->end()) { - for(_allTransportsIter = _allTransports.begin(); _allTransportsIter != _allTransports.end(); _allTransportsIter++) - { - if(_prioritiesIter->second == *_allTransportsIter) - { - retTransport = _prioritiesIter->second; - _allTransports.erase(_allTransportsIter); - break; - } - } - priorities->erase(_prioritiesIter); + retTransport = prioritiesIter->second; + priorities->erase(prioritiesIter); + _transportCount--; if(priorities->size() == 0) { - _transports.erase(_transportsIter); - delete priorities; + _transports.erase(transportsIter); } } } @@ -112,51 +109,44 @@ Transport* TransportRegistry::remove(Transport* transport) void TransportRegistry::clear() { Lock guard(_mutex); - for(_transportsIter = _transports.begin(); _transportsIter != _transports.end(); _transportsIter++) - { - delete _transportsIter->second; - } - _transports.clear(); - _allTransports.clear(); + _transportCount = 0; } int TransportRegistry::numberOfActiveTransports() { Lock guard(_mutex); - return (int32)_allTransports.size(); + return _transportCount; } -Transport** TransportRegistry::toArray(const String type, int32& size) +auto_ptr TransportRegistry::toArray(String type) { // TODO support type - Lock guard(_mutex); - size = _allTransports.size(); - Transport** transportArray = new Transport*[size]; - int i = 0; - for(_allTransportsIter = _allTransports.begin(); _allTransportsIter != _allTransports.end(); _allTransportsIter++, i++) - { - transportArray[i] = *_allTransportsIter; - } - return transportArray; + return toArray(); } -Transport** TransportRegistry::toArray(int32& size) +auto_ptr TransportRegistry::toArray() { Lock guard(_mutex); - size = _allTransports.size(); + if (_transportCount == 0) + return auto_ptr(0); + + auto_ptr transportArray(new transportVector_t(_transportCount)); - if(size == 0) - { - return NULL; - } - - Transport** transportArray = new Transport*[size]; - int i = 0; - for(_allTransportsIter = _allTransports.begin(); _allTransportsIter != _allTransports.end(); _allTransportsIter++, i++) - { - transportArray[i] = *_allTransportsIter; - } + int32 i = 0; + for (transportsMap_t::iterator transportsIter = _transports.begin(); + transportsIter != _transports.end(); + transportsIter++) + { + prioritiesMapSharedPtr_t priorities = transportsIter->second; + for (prioritiesMap_t::iterator prioritiesIter = priorities->begin(); + prioritiesIter != priorities->end(); + prioritiesIter++, i++) + { + transportArray->at(i) = prioritiesIter->second; + } + } + return transportArray; } diff --git a/pvAccessApp/utils/transportRegistry.h b/pvAccessApp/utils/transportRegistry.h index fdc7e41..65bd287 100644 --- a/pvAccessApp/utils/transportRegistry.h +++ b/pvAccessApp/utils/transportRegistry.h @@ -16,38 +16,40 @@ #include #include #include "inetAddressUtil.h" +#include namespace epics { namespace pvAccess { -class Transport; -//TODO if unordered map is used instead of map we can use sockAddrAreIdentical routine from osiSock.h +class TransportRegistry { +public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; -typedef std::map prioritiesMap_t; -typedef std::map transportsMap_t; -typedef std::vector allTransports_t; + typedef std::vector transportVector_t; - class TransportRegistry { - public: - TransportRegistry(); - virtual ~TransportRegistry(); + TransportRegistry(); + virtual ~TransportRegistry(); - void put(Transport* transport); - Transport* get(const epics::pvData::String type, const osiSockAddr* address, const epics::pvData::int16 priority); - Transport** get(const epics::pvData::String type, const osiSockAddr* address, epics::pvData::int32& size); - Transport* remove(Transport* transport); - void clear(); - epics::pvData::int32 numberOfActiveTransports(); - Transport** toArray(const epics::pvData::String type, epics::pvData::int32& size); - Transport** toArray(epics::pvData::int32& size); + void put(Transport::shared_pointer& transport); + Transport::shared_pointer get(epics::pvData::String type, const osiSockAddr* address, const epics::pvData::int16 priority); + std::auto_ptr get(epics::pvData::String type, const osiSockAddr* address); + Transport::shared_pointer remove(Transport::shared_pointer& transport); + void clear(); + epics::pvData::int32 numberOfActiveTransports(); + std::auto_ptr toArray(epics::pvData::String type); + std::auto_ptr toArray(); - private: - transportsMap_t _transports; - transportsMap_t::iterator _transportsIter; - prioritiesMap_t::iterator _prioritiesIter; - allTransports_t _allTransports; - allTransports_t::iterator _allTransportsIter; - epics::pvData::Mutex _mutex; - }; +private: + //TODO if unordered map is used instead of map we can use sockAddrAreIdentical routine from osiSock.h + // NOTE: pointers are used to osiSockAddr (to save memory), since it guaranteed that their reference is valid as long as Transport + typedef std::map prioritiesMap_t; + typedef std::tr1::shared_ptr prioritiesMapSharedPtr_t; + typedef std::map transportsMap_t; + + transportsMap_t _transports; + int32 _transportCount; + epics::pvData::Mutex _mutex; +}; }} diff --git a/testApp/Makefile b/testApp/Makefile index 0b70107..eebf51c 100644 --- a/testApp/Makefile +++ b/testApp/Makefile @@ -1,6 +1,6 @@ TOP = .. include $(TOP)/configure/CONFIG DIRS += utils -DIRS += client +#DIRS += client DIRS += remote include $(TOP)/configure/RULES_DIRS diff --git a/testApp/client/MockClientImpl.cpp b/testApp/client/MockClientImpl.cpp index b1abf3f..d684702 100644 --- a/testApp/client/MockClientImpl.cpp +++ b/testApp/client/MockClientImpl.cpp @@ -294,7 +294,7 @@ class MockMonitor : public Monitor, public MonitorElement m_changedBitSet->set(0); // TODO pvRequest - m_monitorRequester->monitorConnect(Status::OK, this, const_cast(m_pvStructure->getStructure())); + m_monitorRequester->monitorConnect(Status::OK, this, m_pvStructure->getStructure()); } virtual Status start() diff --git a/testApp/client/testCreateRequest.cpp b/testApp/client/testCreateRequest.cpp index f5ff388..43c9ef4 100644 --- a/testApp/client/testCreateRequest.cpp +++ b/testApp/client/testCreateRequest.cpp @@ -16,145 +16,174 @@ using namespace epics::pvData; using namespace epics::pvAccess; - -class RequesterImpl : public Requester { - public: - - virtual String getRequesterName() - { - return "RequesterImpl"; - }; - - virtual void message(String message,MessageType messageType) - { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; - } -}; - - void testCreateRequest() { - printf("testCreateRequest... "); + printf("testCreateRequest... "); - RequesterImpl requester; - String out; + String out; String request = ""; - PVStructure* pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + std::tr1::shared_ptr pvRequest(getCreateRequest()->createRequest(request)); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = "alarm,timeStamp,power.value"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + request = "alarm,timeStamp,power.value"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = "record[process=true]field(alarm,timeStamp,power.value)"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; - - request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{power.value,power.alarm})"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + request = "record[process=true]field(alarm,timeStamp,power.value)"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value)"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{power.value,power.alarm})"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = String("record[process=true,xxx=yyy]") - + "putField(power.value)" - + "getField(alarm,timeStamp,power{power.value,power.alarm}," - + "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm})"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value)"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = String("record[process=true,xxx=yyy]") - + "putField(power.value)" - + "getField(alarm,timeStamp,power{power.value,power.alarm}," - + "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm}," - + "ps0{" - + "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm}," - + "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}}," - + "ps1{" - + "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm}," - + "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}" - + "})"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + request = String("record[process=true,xxx=yyy]") + + "putField(power.value)" + + "getField(alarm,timeStamp,power{power.value,power.alarm}," + + "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm})"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = "a{b{c{d}}}"; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest); - out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - delete pvRequest; + request = String("record[process=true,xxx=yyy]") + + "putField(power.value)" + + "getField(alarm,timeStamp,power{power.value,power.alarm}," + + "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm}," + + "ps0{" + + "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm}," + + "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}}," + + "ps1{" + + "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm}," + + "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}" + + "})"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); - - request = String("record[process=true,xxx=yyy]") - + "putField(power.value)" - + "getField(alarm,timeStamp,power{power.value,power.alarm}," - + "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm}," - + "ps0{" - + "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm}," - + "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}}," - + "ps1{" - + "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm}," - + "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}" - + ")"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); + request = "a{b{c{d}}}"; + pvRequest = getCreateRequest()->createRequest(request); + assert(pvRequest); + out.clear(); pvRequest->toString(&out); std::cout << out << std::endl; - request = "record[process=true,power.value"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); - - request = "field(power.value"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); - - request = "putField(power.value"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); + request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl; + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } - request = "getField(power.value"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); + request = String("record[process=true,xxx=yyy]") + + "putField(power.value)" + + "getField(alarm,timeStamp,power{power.value,power.alarm}," + + "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm}," + + "ps0{" + + "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm}," + + "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}}," + + "ps1{" + + "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm}," + + "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}" + + ")"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl; + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } - request = "record[process=true=power.value]"; - std::cout << std::endl << "Error Expected for next call!!" << std::endl; - pvRequest = getCreateRequest()->createRequest(request,&requester); - assert(pvRequest==0); - printf("PASSED\n"); + request = "record[process=true,power.value"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl; + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } + + + request = "field(power.value"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl; + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } + + + request = "putField(power.value"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl; + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } + + + request = "getField(power.value"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl;\ + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } + + + request = "record[process=true=power.value]"; + std::cout << std::endl << "Error Expected for next call!!" << std::endl; + try + { + pvRequest = getCreateRequest()->createRequest(request); + assert(false); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } + + printf("PASSED\n"); } int main(int argc,char *argv[]) { - testCreateRequest(); + testCreateRequest(); - std::cout << "-----------------------------------------------------------------------" << std::endl; - epicsExitCallAtExits(); - CDRMonitor::get().show(stdout); - return 0; + std::cout << "-----------------------------------------------------------------------" << std::endl; + epicsExitCallAtExits(); + CDRMonitor::get().show(stdout); + return 0; } diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 6bc794e..7e2f161 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -14,11 +14,11 @@ PROD_HOST += testRemoteClientImpl testRemoteClientImpl_SRCS += testRemoteClientImpl.cpp testRemoteClientImpl_LIBS += pvData pvAccess Com -PROD_HOST += testBeaconEmitter +#PROD_HOST += testBeaconEmitter testBeaconEmitter_SRCS += testBeaconEmitter.cpp testBeaconEmitter_LIBS += pvData pvAccess Com -PROD_HOST += testBeaconHandler +#PROD_HOST += testBeaconHandler testBeaconHandler_SRCS += testBeaconHandler.cpp testBeaconHandler_LIBS += pvData pvAccess Com diff --git a/testApp/remote/testBlockingTCPClnt.cpp b/testApp/remote/testBlockingTCPClnt.cpp index d899557..8e85204 100644 --- a/testApp/remote/testBlockingTCPClnt.cpp +++ b/testApp/remote/testBlockingTCPClnt.cpp @@ -21,6 +21,8 @@ #include #include +using std::tr1::static_pointer_cast; + using namespace epics::pvAccess; using namespace epics::pvData; @@ -28,48 +30,49 @@ using std::cout; using std::endl; using std::sscanf; + class ContextImpl : public Context { public: ContextImpl() : - _tr(new TransportRegistry()), _timer(new Timer("server thread", - lowPriority)), _conf(new SystemConfigurationImpl()) { - } + _tr(new TransportRegistry()), _timer(new Timer("server thread", + lowPriority)), _conf(new SystemConfigurationImpl()) + {} + virtual ~ContextImpl() { - delete _tr; - delete _timer; } - virtual Timer* getTimer() { + virtual Timer::shared_pointer getTimer() { return _timer; } - virtual TransportRegistry* getTransportRegistry() { + virtual std::tr1::shared_ptr getTransportRegistry() { return _tr; } - virtual Channel* getChannel(epics::pvAccess::pvAccessID) { - return 0; + virtual std::tr1::shared_ptr getChannel(epics::pvAccess::pvAccessID) { + return std::tr1::shared_ptr(); } - virtual Transport* getSearchTransport() { - return 0; + virtual Transport::shared_pointer getSearchTransport() { + return Transport::shared_pointer(); } - virtual Configuration* getConfiguration() { + virtual Configuration::shared_pointer getConfiguration() { return _conf; } virtual void acquire() {} virtual void release() {} + virtual void beaconAnomalyNotify() {} private: - TransportRegistry* _tr; - Timer* _timer; - Configuration* _conf; + std::tr1::shared_ptr _tr; + Timer::shared_pointer _timer; + Configuration::shared_pointer _conf; }; class DummyResponseHandler : public ResponseHandler { public: - DummyResponseHandler(Context* ctx) : + DummyResponseHandler() : ResponseHandler() { } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, int payloadSize, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { if(command==CMD_CONNECTION_VALIDATION) transport->verified(); @@ -85,7 +88,7 @@ public: virtual void transportUnresponsive() { errlogSevPrintf(errlogInfo, "unresponsive"); } - virtual void transportResponsive(Transport* transport) { + virtual void transportResponsive(Transport::shared_pointer& transport) { errlogSevPrintf(errlogInfo, "responsive"); } virtual void transportChanged() { @@ -96,6 +99,7 @@ public: } virtual void acquire() {}; virtual void release() {}; + virtual pvAccessID getID() {return 0;}; }; class DummyTransportSender : public TransportSender { @@ -129,32 +133,31 @@ private: }; void testBlockingTCPSender() { - ContextImpl ctx; - BlockingTCPConnector connector(&ctx, 1024, 1.0); + Context::shared_pointer ctx(new ContextImpl()); + BlockingTCPConnector connector(ctx, 1024, 1.0); - DummyTransportClient dtc; - DummyTransportSender dts; - DummyResponseHandler drh(&ctx); + TransportClient::shared_pointer dtc(new DummyTransportClient()); + TransportSender::shared_pointer dts(new DummyTransportSender()); + std::auto_ptr drh(new DummyResponseHandler()); osiSockAddr srvAddr; //srvAddr.ia.sin_family = AF_INET; - if(aToIPAddr("192.168.71.132", CA_SERVER_PORT, &srvAddr.ia)<0) { + if(aToIPAddr("localhost", CA_SERVER_PORT, &srvAddr.ia)<0) { cout<<"error in aToIPAddr(...)"<isClosed()) - transport->enqueueSendRequest(&dts); + transport->enqueueSendRequest(dts); else break; sleep(1); @@ -163,7 +166,7 @@ void testBlockingTCPSender() { cout< getTransportRegistry() { return _tr; } + Channel::shared_pointer getChannel(epics::pvAccess::pvAccessID) { return Channel::shared_pointer(); } + Transport::shared_pointer getSearchTransport() { return Transport::shared_pointer(); } + Configuration::shared_pointer getConfiguration() { return _conf; } virtual void acquire() {} virtual void release() {} private: - TransportRegistry* _tr; - Timer* _timer; - Configuration* _conf; + std::tr1::shared_ptr _tr; + Timer::shared_pointer _timer; + Configuration::shared_pointer _conf; }; -void testServerConnections() { - ContextImpl ctx; +class DummyResponseHandler : public ResponseHandler { +public: + virtual void handleResponse(osiSockAddr* responseFrom, + Transport::shared_pointer& transport, int8 version, int8 command, int payloadSize, + ByteBuffer* payloadBuffer) { + cout << "DummyResponseHandler::handleResponse" << endl; + } +}; - BlockingTCPAcceptor* srv = new BlockingTCPAcceptor(&ctx, CA_SERVER_PORT, - 1024); +class DummyResponseHandlerFactory : public ResponseHandlerFactory + { + public: + std::auto_ptr createResponseHandler() {return std::auto_ptr(new DummyResponseHandler());}; + }; + + +void testServerConnections() { + Context::shared_pointer ctx(new ContextImpl()); + ResponseHandlerFactory::shared_pointer rhf(new DummyResponseHandlerFactory()); + + BlockingTCPAcceptor* srv = new BlockingTCPAcceptor(ctx, rhf, CA_SERVER_PORT, 1024); cout<<"Press any key to stop the server..."; cin.peek(); diff --git a/testApp/remote/testBlockingUDPClnt.cpp b/testApp/remote/testBlockingUDPClnt.cpp index 2178970..e17f7ba 100644 --- a/testApp/remote/testBlockingUDPClnt.cpp +++ b/testApp/remote/testBlockingUDPClnt.cpp @@ -21,6 +21,7 @@ using namespace epics::pvAccess; using namespace epics::pvData; +using std::tr1::static_pointer_cast; using std::cout; using std::endl; @@ -30,28 +31,28 @@ static osiSockAddr sendTo; class ContextImpl : public Context { public: - ContextImpl() - {} + ContextImpl() {} virtual ~ContextImpl() { } - virtual Timer* getTimer() { - return 0; + virtual Timer::shared_pointer getTimer() { + return Timer::shared_pointer(); } - virtual TransportRegistry* getTransportRegistry() { - return 0; + virtual std::tr1::shared_ptr getTransportRegistry() { + return std::tr1::shared_ptr(); } - virtual Channel* getChannel(epics::pvAccess::pvAccessID) { - return 0; + virtual std::tr1::shared_ptr getChannel(epics::pvAccess::pvAccessID) { + return std::tr1::shared_ptr(); } - virtual Transport* getSearchTransport() { - return 0; + virtual Transport::shared_pointer getSearchTransport() { + return Transport::shared_pointer(); } - virtual Configuration* getConfiguration() { - return 0; + virtual Configuration::shared_pointer getConfiguration() { + return Configuration::shared_pointer(); } virtual void acquire() {} virtual void release() {} + virtual void beaconAnomalyNotify() {} }; class DummyResponseHandler : public ResponseHandler { @@ -62,13 +63,16 @@ public: virtual ~DummyResponseHandler() {} virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, int payloadSize, + Transport::shared_pointer&, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { } }; class DummyTransportSender : public TransportSender { public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_pointer; + DummyTransportSender() { for(int i = 0; i<20; i++) data[i] = (char)(i+1); @@ -102,8 +106,9 @@ void testBlockingUDPSender() { BlockingUDPConnector connector(false, true); ContextImpl ctx; - DummyTransportSender dts; - DummyResponseHandler drh(&ctx); + + auto_ptr drh(new DummyResponseHandler(&ctx)); + TransportSender::shared_pointer dts(new DummyTransportSender()); osiSockAddr bindAddr; @@ -111,7 +116,8 @@ void testBlockingUDPSender() { bindAddr.ia.sin_port = htons(65001); bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); - Transport* transport = connector.connect(NULL, &drh, bindAddr, 1, 50); + TransportClient::shared_pointer nullPointer; + Transport::shared_pointer transport(connector.connect(nullPointer, drh, bindAddr, 1, 50)); // SRV_IP defined at the top of the this file if(aToIPAddr(SRV_IP, 65000, &sendTo.ia)<0) { @@ -121,14 +127,12 @@ void testBlockingUDPSender() { cout<<"Sending 10 packets..."<enqueueSendRequest(&dts); + transport->enqueueSendRequest(dts); sleep(1); } - - delete transport; - } int main(int argc, char *argv[]) { diff --git a/testApp/remote/testBlockingUDPSrv.cpp b/testApp/remote/testBlockingUDPSrv.cpp index c043e0e..805f15e 100644 --- a/testApp/remote/testBlockingUDPSrv.cpp +++ b/testApp/remote/testBlockingUDPSrv.cpp @@ -20,6 +20,7 @@ using std::cout; using std::endl; using std::hex; using std::dec; +using std::tr1::static_pointer_cast; class ContextImpl : public Context { public: @@ -27,23 +28,24 @@ public: virtual ~ContextImpl() { } - virtual Timer* getTimer() { - return 0; + virtual Timer::shared_pointer getTimer() { + return Timer::shared_pointer(); } - virtual TransportRegistry* getTransportRegistry() { - return 0; + virtual std::tr1::shared_ptr getTransportRegistry() { + return std::tr1::shared_ptr(); } - virtual Channel* getChannel(epics::pvAccess::pvAccessID) { - return 0; + virtual std::tr1::shared_ptr getChannel(epics::pvAccess::pvAccessID) { + return std::tr1::shared_ptr(); } - virtual Transport* getSearchTransport() { - return 0; + virtual Transport::shared_pointer getSearchTransport() { + return Transport::shared_pointer(); } - virtual Configuration* getConfiguration() { - return 0; + virtual Configuration::shared_pointer getConfiguration() { + return Configuration::shared_pointer(); } virtual void acquire() {} virtual void release() {} + virtual void beaconAnomalyNotify() {} }; class DummyResponseHandler : public ResponseHandler { @@ -59,14 +61,14 @@ public: } virtual void handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, int payloadSize, + Transport::shared_pointer&, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer); private: int packets; }; void DummyResponseHandler::handleResponse(osiSockAddr* responseFrom, - Transport* transport, int8 version, int8 command, int payloadSize, + Transport::shared_pointer&, int8 version, int8 command, int payloadSize, ByteBuffer* payloadBuffer) { std::ostringstream os; @@ -100,7 +102,8 @@ void testBlockingUDPConnector() { BlockingUDPConnector connector(false, true); ContextImpl ctx; - DummyResponseHandler drh(&ctx); + DummyResponseHandler* drh = new DummyResponseHandler(&ctx); + auto_ptr rh(static_cast(drh)); osiSockAddr bindAddr; @@ -108,17 +111,17 @@ void testBlockingUDPConnector() { bindAddr.ia.sin_port = htons(65000); bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); - Transport* transport = connector.connect(NULL, &drh, bindAddr, 1, 50); + TransportClient::shared_pointer nullPointer; + Transport::shared_pointer transport(connector.connect(nullPointer,rh, bindAddr, 1, 50)); - ((BlockingUDPTransport*)transport)->start(); + static_pointer_cast(transport)->start(); cout<<"Waiting for 10 packets..."<getPackets()<10) { sleep(1); } - - delete transport; } int main(int argc, char *argv[]) { diff --git a/testApp/remote/testChannelSearchManager.cpp b/testApp/remote/testChannelSearchManager.cpp index 074166f..650d4ea 100644 --- a/testApp/remote/testChannelSearchManager.cpp +++ b/testApp/remote/testChannelSearchManager.cpp @@ -9,346 +9,103 @@ using namespace epics::pvData; using namespace epics::pvAccess; //TODO this will be deleted - class ChannelImpl; - - class ContextImpl : public Context - - { - - private: - - Timer* _timer; - - public: - - - - ContextImpl() - - { - - _timer = new Timer("krneki",lowPriority); - - } - - - - virtual Version* getVersion() { - - return NULL; - - } - - - - virtual ChannelProvider* getProvider() { - - return NULL; - - } - - - - Timer* getTimer() - - { - - return _timer; - - } - - - - virtual void initialize() { - - - - } - - - - virtual void printInfo() { - - - - } - - - - virtual void printInfo(epics::pvData::StringBuilder out) { - - - - } - - - - virtual void destroy() - - { - - - - } - - - - virtual void dispose() - - { - - - - } - - - - BlockingUDPTransport* getSearchTransport() - - { - - return NULL; - - } - - - - /** - - * Searches for a channel with given channel ID. - - * @param channelID CID. - - * @return channel with given CID, if non-existent. - - */ - - Channel* getChannel(pvAccessID channelID) - - { - - return NULL; - - } - - Configuration* getConfiguration() {return NULL;} - - TransportRegistry* getTransportRegistry() {return NULL;} - - ~ContextImpl() { delete _timer;}; - - private: - - - - - - void loadConfiguration() { - - - - } - - - - void internalInitialize() { - - - - - - } - - - - void initializeUDPTransport() { - - - - } - - - - void internalDestroy() { - - - - } - - - - void destroyAllChannels() { - - - - } - - - - /** - - * Check channel name. - - */ - - void checkChannelName(String& name) { - - - - } - - - - /** - - * Check context state and tries to establish necessary state. - - */ - - void checkState() { - - - - } - - - - - - - - /** - - * Generate Client channel ID (CID). - - * @return Client channel ID (CID). - - */ - - pvAccessID generateCID() - - { - - return 0; - - } - - - - /** - - * Free generated channel ID (CID). - - */ - - void freeCID(int cid) - - { - - - - } - - - - - - /** - - * Get, or create if necessary, transport of given server address. - - * @param serverAddress required transport address - - * @param priority process priority. - - * @return transport for given address - - */ - - Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int minorRevision, int priority) - - { - - - - return NULL; - - } - - - - /** - - * Internal create channel. - - */ - - // TODO no minor version with the addresses - - // TODO what if there is an channel with the same name, but on different host! - - Channel* createChannelInternal(String name, ChannelRequester* requester, short priority, - - InetAddrVector* addresses) { - - return NULL; - - } - - - - /** - - * Destroy channel. - - * @param channel - - * @param force - - * @throws CAException - - * @throws IllegalStateException - - */ - - void destroyChannel(ChannelImpl* channel, bool force) { - - - - - - } - - - - /** - - * Get channel search manager. - - * @return channel search manager. - - */ - - ChannelSearchManager* getChannelSearchManager() { - - return NULL; - - } - - virtual void acquire() {} - virtual void release() {} - - }; +class ChannelImpl; + +class ContextImpl : public Context +{ +public: + ContextImpl(): _timer(new Timer("krneki",lowPriority)) + { + + } + virtual Version* getVersion() + { + return NULL; + } + virtual ChannelProvider* getProvider() + { + return NULL; + } + Timer::shared_pointer getTimer() + { + return _timer; + } + virtual void initialize() + { + } + virtual void printInfo() + { + } + virtual void printInfo(epics::pvData::StringBuilder out) + { + } + virtual void destroy() + { + } + virtual void dispose() + { + } + Transport::shared_pointer getSearchTransport() + { + return Transport::shared_pointer(); + } + std::tr1::shared_ptr getChannel(pvAccessID channelID) + { + return std::tr1::shared_ptr(); + } + Configuration::shared_pointer getConfiguration() + { + return Configuration::shared_pointer(); + } + std::tr1::shared_ptr getTransportRegistry() + { + return std::tr1::shared_ptr(); + } + void beaconAnomalyNotify() {}; +private: + Timer::shared_pointer _timer; + void loadConfiguration() { } + void internalInitialize() { } + void initializeUDPTransport() { } + void internalDestroy() { } + void destroyAllChannels() { } + void checkChannelName(String& name) {} + void checkState() { } + pvAccessID generateCID() + { + return 0; + } + void freeCID(int cid) + { + } + Transport* getTransport(TransportClient* client, osiSockAddr* serverAddress, int minorRevision, int priority) + { + return NULL; + } + Channel* createChannelInternal(String name, ChannelRequester* requester, short priority, + InetAddrVector* addresses) + { + return NULL; + } + void destroyChannel(ChannelImpl* channel, bool force) { + } + ChannelSearchManager* getChannelSearchManager() { + return NULL; + } + + virtual void acquire() {} + virtual void release() {} +}; class TestSearcInstance : public BaseSearchInstance { public: TestSearcInstance(string channelName, pvAccessID channelID): _channelID(channelID), _channelName(channelName) {} pvAccessID getSearchInstanceID() { return _channelID;}; - string getSearchInstanceName() {return _channelName;}; + string getSearchInstanceName() {return _channelName;}; void searchResponse(int8 minorRevision, osiSockAddr* serverAddress) {}; - void acquire() {}; - void release() {}; + void acquire() {}; + void release() {}; private: pvAccessID _channelID; string _channelName; @@ -360,90 +117,91 @@ ChannelSearchManager* manager = new ChannelSearchManager(static_cast(c TestSearcInstance** chanArray = new TestSearcInstance*[max_channels]; void* testWorker1(void* p) -{ - for(int i = 0; i < 1000; i++) - { - for(int j = 0; j < max_channels/2; j++) - { - manager->unregisterChannel(chanArray[j]); - usleep(100); - manager->registerChannel(chanArray[j]); - } - } + { + for(int i = 0; i < 1000; i++) + { + for(int j = 0; j < max_channels/2; j++) + { + manager->unregisterChannel(chanArray[j]); + usleep(100); + manager->registerChannel(chanArray[j]); + } + } - return NULL; -} + return NULL; + } void* testWorker2(void* p) -{ - for(int i = 0; i < 1000; i++) - { - for(int j = max_channels/2; j < max_channels; j++) - { - manager->unregisterChannel(chanArray[j]); - usleep(100); - manager->registerChannel(chanArray[j]); - manager->beaconAnomalyNotify(); - } - } + { + for(int i = 0; i < 1000; i++) + { + for(int j = max_channels/2; j < max_channels; j++) + { + manager->unregisterChannel(chanArray[j]); + usleep(100); + manager->registerChannel(chanArray[j]); + manager->beaconAnomalyNotify(); + } + } - return NULL; -} + return NULL; + } int main(int argc,char *argv[]) { - pthread_t _worker1Id; - pthread_t _worker2Id; + pthread_t _worker1Id; + pthread_t _worker2Id; - ostringstream obuffer; - for(int i = 0; i < max_channels; i++) - { - obuffer.clear(); - obuffer.str(""); - obuffer << i; - string name = "chan" + obuffer.str(); - chanArray[i] = new TestSearcInstance(name.c_str(), i); - manager->registerChannel(chanArray[i]); - } + ostringstream obuffer; + for(int i = 0; i < max_channels; i++) + { + obuffer.clear(); + obuffer.str(""); + obuffer << i; + string name = "chan" + obuffer.str(); + chanArray[i] = new TestSearcInstance(name.c_str(), i); + manager->registerChannel(chanArray[i]); + } - //create two threads - int32 retval = pthread_create(&_worker1Id, NULL, testWorker1, NULL); - if(retval != 0) - { - assert(true); - } + //create two threads + int32 retval = pthread_create(&_worker1Id, NULL, testWorker1, NULL); + if(retval != 0) + { + assert(true); + } - retval = pthread_create(&_worker2Id, NULL, testWorker2, NULL); - if(retval != 0) - { - assert(true); - } + retval = pthread_create(&_worker2Id, NULL, testWorker2, NULL); + if(retval != 0) + { + assert(true); + } - retval = pthread_join(_worker1Id, NULL); - if(retval != 0) - { - assert(true); - } + retval = pthread_join(_worker1Id, NULL); + if(retval != 0) + { + assert(true); + } - retval = pthread_join(_worker2Id, NULL); - if(retval != 0) - { - assert(true); - } + retval = pthread_join(_worker2Id, NULL); + if(retval != 0) + { + assert(true); + } - manager->cancel(); + manager->cancel(); - context->destroy(); - epicsExitCallAtExits(); - CDRMonitor::get().show(stdout); - for(int i = 0; i < max_channels; i++) - { - if(chanArray[i]) delete chanArray[i]; - } - if(chanArray) delete [] chanArray; - if(manager) delete manager; - if(context) delete context; - return(0); + context->destroy(); + epicsExitCallAtExits(); + CDRMonitor::get().show(stdout); + + for(int i = 0; i < max_channels; i++) + { + if(chanArray[i]) delete chanArray[i]; + } + if(chanArray) delete [] chanArray; + if(manager) delete manager; + if(context) delete context; + return(0); } diff --git a/testApp/remote/testRemoteClientImpl.cpp b/testApp/remote/testRemoteClientImpl.cpp index 206822f..604ad5f 100644 --- a/testApp/remote/testRemoteClientImpl.cpp +++ b/testApp/remote/testRemoteClientImpl.cpp @@ -16,7 +16,7 @@ using namespace epics::pvAccess; class ChannelFindRequesterImpl : public ChannelFindRequester { - virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind *channelFind,bool wasFound) + virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind::shared_pointer& channelFind,bool wasFound) { std::cout << "[ChannelFindRequesterImpl] channelFindResult(" << status.toString() << ", ..., " << wasFound << ")" << std::endl; @@ -35,13 +35,13 @@ class ChannelRequesterImpl : public ChannelRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelCreated(const epics::pvData::Status& status, Channel *channel) + virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer& channel) { std::cout << "channelCreated(" << status.toString() << ", " << (channel ? channel->getChannelName() : "(0)") << ")" << std::endl; } - virtual void channelStateChange(Channel *c, Channel::ConnectionState connectionState) + virtual void channelStateChange(Channel::shared_pointer& c, Channel::ConnectionState connectionState) { std::cout << "channelStateChange(" << c->getChannelName() << ", " << Channel::ConnectionStateNames[connectionState] << ")" << std::endl; } @@ -59,7 +59,7 @@ class GetFieldRequesterImpl : public GetFieldRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr field) + virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr& field) { std::cout << "getDone(" << status.toString() << ", "; if (status.isSuccess() && field) @@ -76,15 +76,14 @@ class GetFieldRequesterImpl : public GetFieldRequester class ChannelGetRequesterImpl : public ChannelGetRequester { - Mutex m_mutex; - ChannelGet *m_channelGet; - epics::pvData::PVStructure *m_pvStructure; - epics::pvData::BitSet *m_bitSet; + private: + + //ChannelGet::shared_pointer m_channelGet; + epics::pvData::PVStructure::shared_pointer m_pvStructure; + epics::pvData::BitSet::shared_pointer m_bitSet; public: - ChannelGetRequesterImpl() : m_channelGet(0), m_pvStructure(0), m_bitSet(0) {} - virtual String getRequesterName() { return "ChannelGetRequesterImpl"; @@ -95,8 +94,8 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet *channelGet, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet::shared_pointer& channelGet, + epics::pvData::PVStructure::shared_pointer& pvStructure,epics::pvData::BitSet::shared_pointer& bitSet) { std::cout << "channelGetConnect(" << status.toString() << ")" << std::endl; if (status.isSuccess()) @@ -106,17 +105,15 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cout << st << std::endl; } - m_mutex.lock(); - m_channelGet = channelGet; + //m_channelGet = channelGet; m_pvStructure = pvStructure; m_bitSet = bitSet; - m_mutex.unlock(); } virtual void getDone(const epics::pvData::Status& status) { std::cout << "getDone(" << status.toString() << ")" << std::endl; - Lock guard(m_mutex); + if (status.isSuccess()) { String str; @@ -129,10 +126,14 @@ class ChannelGetRequesterImpl : public ChannelGetRequester class ChannelPutRequesterImpl : public ChannelPutRequester { - ChannelPut *m_channelPut; - epics::pvData::PVStructure *m_pvStructure; - epics::pvData::BitSet *m_bitSet; + private: + + //ChannelPut::shared_pointer m_channelPut; + epics::pvData::PVStructure::shared_pointer m_pvStructure; + epics::pvData::BitSet::shared_pointer m_bitSet; + public: + virtual String getRequesterName() { return "ChannelPutRequesterImpl"; @@ -143,13 +144,12 @@ class ChannelPutRequesterImpl : public ChannelPutRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut *channelPut, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut::shared_pointer& channelPut, + epics::pvData::PVStructure::shared_pointer& pvStructure,epics::pvData::BitSet::shared_pointer& bitSet) { std::cout << "channelPutConnect(" << status.toString() << ")" << std::endl; - // TODO sync - m_channelPut = channelPut; + //m_channelPut = channelPut; m_pvStructure = pvStructure; m_bitSet = bitSet; } @@ -182,15 +182,13 @@ class ChannelPutRequesterImpl : public ChannelPutRequester class ChannelPutGetRequesterImpl : public ChannelPutGetRequester { - public: - - ChannelPutGetRequesterImpl() : m_channelPutGet(0), m_putData(0), m_getData(0) {}; - private: - ChannelPutGet *m_channelPutGet; - epics::pvData::PVStructure *m_putData; - epics::pvData::PVStructure *m_getData; + //ChannelPutGet::shared_pointer m_channelPutGet; + epics::pvData::PVStructure::shared_pointer m_putData; + epics::pvData::PVStructure::shared_pointer m_getData; + + public: virtual String getRequesterName() { @@ -202,12 +200,12 @@ class ChannelPutGetRequesterImpl : public ChannelPutGetRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelPutGetConnect(const epics::pvData::Status& status,ChannelPutGet *channelPutGet, - epics::pvData::PVStructure *putData,epics::pvData::PVStructure *getData) + virtual void channelPutGetConnect(const epics::pvData::Status& status, ChannelPutGet::shared_pointer& channelPutGet, + epics::pvData::PVStructure::shared_pointer& putData,epics::pvData::PVStructure::shared_pointer& getData) { std::cout << "channelGetPutConnect(" << status.toString() << ")" << std::endl; - // TODO sync - m_channelPutGet = channelPutGet; + + //m_channelPutGet = channelPutGet; m_putData = putData; m_getData = getData; @@ -268,9 +266,9 @@ class ChannelPutGetRequesterImpl : public ChannelPutGetRequester class ChannelRPCRequesterImpl : public ChannelRPCRequester { - ChannelRPC *m_channelRPC; - epics::pvData::PVStructure *m_pvStructure; - epics::pvData::BitSet *m_bitSet; + //ChannelRPC::shared_pointer m_channelRPC; + epics::pvData::PVStructure::shared_pointer m_pvStructure; + epics::pvData::BitSet::shared_pointer m_bitSet; virtual String getRequesterName() { @@ -282,8 +280,8 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelRPCConnect(const epics::pvData::Status& status,ChannelRPC *channelRPC, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + virtual void channelRPCConnect(const epics::pvData::Status& status,ChannelRPC::shared_pointer& channelRPC, + epics::pvData::PVStructure::shared_pointer& pvStructure,epics::pvData::BitSet::shared_pointer& bitSet) { std::cout << "channelRPCConnect(" << status.toString() << ")" << std::endl; if (status.isSuccess()) @@ -293,13 +291,12 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester std::cout << st << std::endl; } - // TODO sync - m_channelRPC = channelRPC; + //m_channelRPC = channelRPC; m_pvStructure = pvStructure; m_bitSet = bitSet; } - virtual void requestDone(const epics::pvData::Status& status,epics::pvData::PVStructure *pvResponse) + virtual void requestDone(const epics::pvData::Status& status,epics::pvData::PVStructure::shared_pointer& pvResponse) { std::cout << "requestDone(" << status.toString() << ")" << std::endl; if (status.isSuccess()) @@ -314,15 +311,13 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester class ChannelArrayRequesterImpl : public ChannelArrayRequester { - public: - - ChannelArrayRequesterImpl() : m_channelArray(0), m_pvArray(0) {}; - private: - ChannelArray *m_channelArray; - epics::pvData::PVArray *m_pvArray; + //ChannelArray::shared_pointer m_channelArray; + epics::pvData::PVArray::shared_pointer m_pvArray; + public: + virtual String getRequesterName() { return "ChannelArrayRequesterImpl"; @@ -333,8 +328,8 @@ class ChannelArrayRequesterImpl : public ChannelArrayRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelArrayConnect(const epics::pvData::Status& status,ChannelArray *channelArray, - epics::pvData::PVArray *pvArray) + virtual void channelArrayConnect(const epics::pvData::Status& status,ChannelArray::shared_pointer& channelArray, + epics::pvData::PVArray::shared_pointer& pvArray) { std::cout << "channelArrayConnect(" << status.toString() << ")" << std::endl; if (status.isSuccess()) @@ -344,8 +339,7 @@ class ChannelArrayRequesterImpl : public ChannelArrayRequester std::cout << st << std::endl; } - // TODO sync - m_channelArray = channelArray; + //m_channelArray = channelArray; m_pvArray = pvArray; } @@ -384,7 +378,7 @@ class MonitorRequesterImpl : public MonitorRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void monitorConnect(const epics::pvData::Status& status, Monitor* monitor, StructureConstPtr structure) + virtual void monitorConnect(const epics::pvData::Status& status, Monitor::shared_pointer& monitor, StructureConstPtr& structure) { std::cout << "monitorConnect(" << status.toString() << ")" << std::endl; if (status.isSuccess() && structure) @@ -395,11 +389,11 @@ class MonitorRequesterImpl : public MonitorRequester } } - virtual void monitorEvent(Monitor* monitor) + virtual void monitorEvent(Monitor::shared_pointer& monitor) { std::cout << "monitorEvent" << std::endl; - MonitorElement* element = monitor->poll(); + MonitorElement::shared_pointer element = monitor->poll(); String str("changed/overrun "); element->getChangedBitSet()->toString(&str); @@ -412,7 +406,7 @@ class MonitorRequesterImpl : public MonitorRequester monitor->release(element); } - virtual void unlisten(Monitor* monitor) + virtual void unlisten(Monitor::shared_pointer& monitor) { std::cout << "unlisten" << std::endl; } @@ -421,7 +415,7 @@ class MonitorRequesterImpl : public MonitorRequester class ChannelProcessRequesterImpl : public ChannelProcessRequester { - ChannelProcess *m_channelProcess; + //ChannelProcess::shared_pointer& m_channelProcess; virtual String getRequesterName() { @@ -433,12 +427,11 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess *channelProcess) + virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess::shared_pointer& channelProcess) { std::cout << "channelProcessConnect(" << status.toString() << ")" << std::endl; - // TODO sync - m_channelProcess = channelProcess; + //m_channelProcess = channelProcess; } virtual void processDone(const epics::pvData::Status& status) @@ -451,8 +444,10 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester int main(int argc,char *argv[]) { + for (int i = 0; i < 10; i++) { + { /* - ClientContextImpl* context = createClientContextImpl(); + ClientContextImpl::shared_pointer context = createClientContextImpl(); context->printInfo(); context->initialize(); @@ -460,63 +455,65 @@ int main(int argc,char *argv[]) epicsThreadSleep ( 1.0 ); - ChannelProvider* provider = context->getProvider(); + ChannelProvider::shared_pointer provider = context->getProvider(); */ ClientFactory::start(); - ChannelProvider* provider = getChannelAccess()->getProvider("pvAccess"); + ChannelProvider::shared_pointer provider = getChannelAccess()->getProvider("pvAccess"); -/* - ChannelFindRequesterImpl findRequester; - ChannelFind* channelFind = provider->channelFind("something", &findRequester); + ChannelFindRequester::shared_pointer findRequester(new ChannelFindRequesterImpl()); + ChannelFind::shared_pointer channelFind = provider->channelFind("something", findRequester); epicsThreadSleep ( 1.0 ); - channelFind->destroy(); -*/ - ChannelRequesterImpl channelRequester; - Channel* channel = provider->createChannel("structureArrayTest", &channelRequester); + //channelFind->destroy(); + ChannelRequester::shared_pointer channelRequester(new ChannelRequesterImpl()); + Channel::shared_pointer channel = provider->createChannel("structureArrayTest", channelRequester); epicsThreadSleep ( 1.0 ); - channel->printInfo(); - - PVStructure* pvRequest; - - GetFieldRequesterImpl getFieldRequesterImpl; - channel->getField(&getFieldRequesterImpl, ""); + + { + GetFieldRequester::shared_pointer getFieldRequesterImpl(new GetFieldRequesterImpl()); + channel->getField(getFieldRequesterImpl, ""); epicsThreadSleep ( 1.0 ); - - ChannelProcessRequesterImpl channelProcessRequester; - ChannelProcess* channelProcess = channel->createChannelProcess(&channelProcessRequester, 0); + } + + { + ChannelProcessRequester::shared_pointer channelProcessRequester(new ChannelProcessRequesterImpl()); + PVStructure::shared_pointer pvRequest; + ChannelProcess::shared_pointer channelProcess = channel->createChannelProcess(channelProcessRequester, pvRequest); epicsThreadSleep ( 1.0 ); channelProcess->process(false); epicsThreadSleep ( 1.0 ); channelProcess->destroy(); epicsThreadSleep ( 1.0 ); - - ChannelGetRequesterImpl channelGetRequesterImpl; - pvRequest = getCreateRequest()->createRequest("field()",&channelGetRequesterImpl); - ChannelGet* channelGet = channel->createChannelGet(&channelGetRequesterImpl, pvRequest); + } + + { + ChannelGetRequester::shared_pointer channelGetRequesterImpl(new ChannelGetRequesterImpl()); + PVStructure::shared_pointer pvRequest = getCreateRequest()->createRequest("field()"); + ChannelGet::shared_pointer channelGet = channel->createChannelGet(channelGetRequesterImpl, pvRequest); epicsThreadSleep ( 3.0 ); channelGet->get(false); epicsThreadSleep ( 3.0 ); - channelGet->destroy(); - delete pvRequest; - - ChannelPutRequesterImpl channelPutRequesterImpl; - pvRequest = getCreateRequest()->createRequest("field(value,timeStamp)",&channelPutRequesterImpl); - ChannelPut* channelPut = channel->createChannelPut(&channelPutRequesterImpl, pvRequest); + } + + { + ChannelPutRequester::shared_pointer channelPutRequesterImpl(new ChannelPutRequesterImpl()); + PVStructure::shared_pointer pvRequest = getCreateRequest()->createRequest("field(value,timeStamp)"); + ChannelPut::shared_pointer channelPut = channel->createChannelPut(channelPutRequesterImpl, pvRequest); epicsThreadSleep ( 1.0 ); channelPut->get(); epicsThreadSleep ( 1.0 ); channelPut->put(false); epicsThreadSleep ( 1.0 ); channelPut->destroy(); - delete pvRequest; + } - ChannelPutGetRequesterImpl channelPutGetRequesterImpl; - pvRequest = getCreateRequest()->createRequest("putField(value,timeStamp)getField(timeStamp)",&channelPutGetRequesterImpl); - ChannelPutGet* channelPutGet = channel->createChannelPutGet(&channelPutGetRequesterImpl, pvRequest); + { + ChannelPutGetRequester::shared_pointer channelPutGetRequesterImpl(new ChannelPutGetRequesterImpl()); + PVStructure::shared_pointer pvRequest = getCreateRequest()->createRequest("putField(value,timeStamp)getField(timeStamp)"); + ChannelPutGet::shared_pointer channelPutGet = channel->createChannelPutGet(channelPutGetRequesterImpl, pvRequest); epicsThreadSleep ( 1.0 ); channelPutGet->getGet(); epicsThreadSleep ( 1.0 ); @@ -525,26 +522,26 @@ int main(int argc,char *argv[]) channelPutGet->putGet(false); epicsThreadSleep ( 1.0 ); channelPutGet->destroy(); - delete pvRequest; + } - - ChannelRPCRequesterImpl channelRPCRequesterImpl; - pvRequest = getCreateRequest()->createRequest("record[]field(arguments)",&channelRPCRequesterImpl); - ChannelRPC* channelRPC = channel->createChannelRPC(&channelRPCRequesterImpl, pvRequest); + { + ChannelRPCRequester::shared_pointer channelRPCRequesterImpl(new ChannelRPCRequesterImpl()); + PVStructure::shared_pointer pvRequest = getCreateRequest()->createRequest("record[]field(arguments)"); + ChannelRPC::shared_pointer channelRPC = channel->createChannelRPC(channelRPCRequesterImpl, pvRequest); epicsThreadSleep ( 1.0 ); channelRPC->request(false); epicsThreadSleep ( 1.0 ); channelRPC->destroy(); - delete pvRequest; - - ChannelArrayRequesterImpl channelArrayRequesterImpl; - //pvRequest = getCreateRequest()->createRequest("value",&channelArrayRequesterImpl); - pvRequest = getPVDataCreate()->createPVStructure(0, "", 0); - PVString* pvFieldName = (PVString*)getPVDataCreate()->createPVScalar(pvRequest, "field", pvString); + } + + { + ChannelArrayRequester::shared_pointer channelArrayRequesterImpl(new ChannelArrayRequesterImpl()); + PVStructure::shared_pointer pvRequest(getPVDataCreate()->createPVStructure(0, "", 0)); + PVString* pvFieldName = (PVString*)getPVDataCreate()->createPVScalar(pvRequest.get(), "field", pvString); pvFieldName->put("value"); pvRequest->appendPVField(pvFieldName); - ChannelArray* channelArray = channel->createChannelArray(&channelArrayRequesterImpl, pvRequest); + ChannelArray::shared_pointer channelArray = channel->createChannelArray(channelArrayRequesterImpl, pvRequest); epicsThreadSleep ( 1.0 ); channelArray->getArray(false,0,-1); epicsThreadSleep ( 1.0 ); @@ -553,11 +550,12 @@ int main(int argc,char *argv[]) channelArray->setLength(false,3,4); epicsThreadSleep ( 1.0 ); channelArray->destroy(); - delete pvRequest; + } - MonitorRequesterImpl monitorRequesterImpl; - pvRequest = getCreateRequest()->createRequest("field()",&monitorRequesterImpl); - Monitor* monitor = channel->createMonitor(&monitorRequesterImpl, pvRequest); + { + MonitorRequester::shared_pointer monitorRequesterImpl(new MonitorRequesterImpl()); + PVStructure::shared_pointer pvRequest = getCreateRequest()->createRequest("field()"); + Monitor::shared_pointer monitor = channel->createMonitor(monitorRequesterImpl, pvRequest); epicsThreadSleep( 1.0 ); @@ -571,23 +569,26 @@ int main(int argc,char *argv[]) monitor->destroy(); - delete pvRequest; - + } + epicsThreadSleep ( 3.0 ); printf("Destroying channel... \n"); channel->destroy(); printf("done.\n"); epicsThreadSleep ( 3.0 ); - + + } + ClientFactory::stop(); + /* printf("Destroying context... \n"); context->destroy(); printf("done.\n"); */ - epicsThreadSleep ( 1.0 ); + epicsThreadSleep ( 1.0 ); } std::cout << "-----------------------------------------------------------------------" << std::endl; epicsExitCallAtExits(); CDRMonitor::get().show(stdout); diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 6a407ac..db2aed0 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -11,36 +11,33 @@ using namespace epics::pvAccess; using namespace epics::pvData; using namespace std; - +using std::tr1::static_pointer_cast; PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelProcess); -class MockChannelProcess : public ChannelProcess +class MockChannelProcess : + public ChannelProcess, + public std::tr1::enable_shared_from_this { private: - ChannelProcessRequester* m_channelProcessRequester; - PVStructure* m_pvStructure; + ChannelProcessRequester::shared_pointer m_channelProcessRequester; + PVStructure::shared_pointer m_pvStructure; PVScalar* m_valueField; - private: - ~MockChannelProcess() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelProcess); - } - - public: - MockChannelProcess(ChannelProcessRequester* channelProcessRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + protected: + MockChannelProcess(ChannelProcessRequester::shared_pointer& channelProcessRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : m_channelProcessRequester(channelProcessRequester), m_pvStructure(pvStructure) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelProcess); +// TODO wrong + ChannelProcess::shared_pointer thisPtr = static_pointer_cast(shared_from_this()); PVField* field = pvStructure->getSubField(String("value")); if (field == 0) { Status noValueFieldStatus(Status::STATUSTYPE_ERROR, "no 'value' field"); - m_channelProcessRequester->channelProcessConnect(noValueFieldStatus, this); - + m_channelProcessRequester->channelProcessConnect(noValueFieldStatus, thisPtr); // NOTE client must destroy this instance... // do not access any fields and return ASAP return; @@ -49,19 +46,32 @@ class MockChannelProcess : public ChannelProcess if (field->getField()->getType() != scalar) { Status notAScalarStatus(Status::STATUSTYPE_ERROR, "'value' field not scalar type"); - m_channelProcessRequester->channelProcessConnect(notAScalarStatus, this); - + m_channelProcessRequester->channelProcessConnect(notAScalarStatus, thisPtr); // NOTE client must destroy this instance…. // do not access any fields and return ASAP return; } m_valueField = static_cast(field); + } + + public: + static ChannelProcess::shared_pointer create(ChannelProcessRequester::shared_pointer& channelProcessRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) + { + ChannelProcess::shared_pointer thisPtr(new MockChannelProcess(channelProcessRequester, pvStructure, pvRequest)); // TODO pvRequest - m_channelProcessRequester->channelProcessConnect(Status::OK, this); + channelProcessRequester->channelProcessConnect(Status::OK, thisPtr); + + return thisPtr; } + virtual ~MockChannelProcess() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelProcess); + } + + virtual void process(bool lastRequest) { switch (m_valueField->getScalar()->getScalarType()) @@ -143,7 +153,7 @@ class MockChannelProcess : public ChannelProcess virtual void destroy() { - delete this; + } }; @@ -158,26 +168,32 @@ PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelGet); class MockChannelGet : public ChannelGet { private: - ChannelGetRequester* m_channelGetRequester; - PVStructure* m_pvStructure; - BitSet* m_bitSet; + ChannelGetRequester::shared_pointer m_channelGetRequester; + PVStructure::shared_pointer m_pvStructure; + BitSet::shared_pointer m_bitSet; bool m_first; - private: - ~MockChannelGet() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelGet); - } - - public: - MockChannelGet(ChannelGetRequester* channelGetRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + protected: + MockChannelGet(ChannelGetRequester::shared_pointer& channelGetRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : m_channelGetRequester(channelGetRequester), m_pvStructure(pvStructure), m_bitSet(new BitSet(pvStructure->getNumberFields())), m_first(true) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelGet); + } + public: + static ChannelGet::shared_pointer create(ChannelGetRequester::shared_pointer& channelGetRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) + { + ChannelGet::shared_pointer thisPtr(new MockChannelGet(channelGetRequester, pvStructure, pvRequest)); // TODO pvRequest - m_channelGetRequester->channelGetConnect(Status::OK, this, m_pvStructure, m_bitSet); + channelGetRequester->channelGetConnect(Status::OK, thisPtr, pvStructure, static_cast(thisPtr.get())->m_bitSet); + + return thisPtr; + } + + virtual ~MockChannelGet() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelGet); } virtual void get(bool lastRequest) @@ -195,8 +211,6 @@ class MockChannelGet : public ChannelGet virtual void destroy() { - delete m_bitSet; - delete this; } }; @@ -204,36 +218,39 @@ class MockChannelGet : public ChannelGet - - - - PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelPut); class MockChannelPut : public ChannelPut { private: - ChannelPutRequester* m_channelPutRequester; - PVStructure* m_pvStructure; - BitSet* m_bitSet; + ChannelPutRequester::shared_pointer m_channelPutRequester; + PVStructure::shared_pointer m_pvStructure; + BitSet::shared_pointer m_bitSet; - private: - ~MockChannelPut() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelPut); - } - - public: - MockChannelPut(ChannelPutRequester* channelPutRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + protected: + MockChannelPut(ChannelPutRequester::shared_pointer& channelPutRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : m_channelPutRequester(channelPutRequester), m_pvStructure(pvStructure), m_bitSet(new BitSet(pvStructure->getNumberFields())) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelPut); - - // TODO pvRequest - m_channelPutRequester->channelPutConnect(Status::OK, this, m_pvStructure, m_bitSet); } + public: + static ChannelPut::shared_pointer create(ChannelPutRequester::shared_pointer& channelPutRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) + { + ChannelPut::shared_pointer thisPtr(new MockChannelPut(channelPutRequester, pvStructure, pvRequest)); + // TODO pvRequest + channelPutRequester->channelPutConnect(Status::OK, thisPtr, pvStructure, static_cast(thisPtr.get())->m_bitSet); + + return thisPtr; + } + + virtual ~MockChannelPut() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelPut); + } + + virtual void put(bool lastRequest) { m_channelPutRequester->putDone(Status::OK); @@ -248,8 +265,6 @@ class MockChannelPut : public ChannelPut virtual void destroy() { - delete m_bitSet; - delete this; } }; @@ -257,31 +272,34 @@ class MockChannelPut : public ChannelPut - - - PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelPutGet); class MockChannelPutGet : public ChannelPutGet { private: - ChannelPutGetRequester* m_channelPutGetRequester; - PVStructure* m_pvStructure; + ChannelPutGetRequester::shared_pointer m_channelPutGetRequester; + PVStructure::shared_pointer m_pvStructure; - private: - ~MockChannelPutGet() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelPutGet); - } - - public: - MockChannelPutGet(ChannelPutGetRequester* channelPutGetRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + protected: + MockChannelPutGet(ChannelPutGetRequester::shared_pointer& channelPutGetRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : m_channelPutGetRequester(channelPutGetRequester), m_pvStructure(pvStructure) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelPutGet); + } + public: + static ChannelPutGet::shared_pointer create(ChannelPutGetRequester::shared_pointer& channelPutGetRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) + { + ChannelPutGet::shared_pointer thisPtr(new MockChannelPutGet(channelPutGetRequester, pvStructure, pvRequest)); // TODO pvRequest - m_channelPutGetRequester->channelPutGetConnect(Status::OK, this, m_pvStructure, m_pvStructure); + channelPutGetRequester->channelPutGetConnect(Status::OK, thisPtr, pvStructure, pvStructure); + + return thisPtr; + } + + virtual ~MockChannelPutGet() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelPutGet); } virtual void putGet(bool lastRequest) @@ -303,7 +321,6 @@ class MockChannelPutGet : public ChannelPutGet virtual void destroy() { - delete this; } }; @@ -318,25 +335,30 @@ PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelRPC); class MockChannelRPC : public ChannelRPC { private: - ChannelRPCRequester* m_channelRPCRequester; - PVStructure* m_pvStructure; - BitSet* m_bitSet; + ChannelRPCRequester::shared_pointer m_channelRPCRequester; + PVStructure::shared_pointer m_pvStructure; + BitSet::shared_pointer m_bitSet; - private: - ~MockChannelRPC() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelRPC); - } - - public: - MockChannelRPC(ChannelRPCRequester* channelRPCRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + protected: + MockChannelRPC(ChannelRPCRequester::shared_pointer& channelRPCRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : m_channelRPCRequester(channelRPCRequester), m_pvStructure(pvStructure), m_bitSet(new BitSet(pvStructure->getNumberFields())) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelRPC); + } + public: + static ChannelRPC::shared_pointer create(ChannelRPCRequester::shared_pointer& channelRPCRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) + { + ChannelRPC::shared_pointer thisPtr(new MockChannelRPC(channelRPCRequester, pvStructure, pvRequest)); // TODO pvRequest - m_channelRPCRequester->channelRPCConnect(Status::OK, this, m_pvStructure, m_bitSet); + channelRPCRequester->channelRPCConnect(Status::OK, thisPtr, pvStructure, static_cast(thisPtr.get())->m_bitSet); + return thisPtr; + } + + virtual ~MockChannelRPC() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelRPC); } virtual void request(bool lastRequest) @@ -348,8 +370,6 @@ class MockChannelRPC : public ChannelRPC virtual void destroy() { - delete m_bitSet; - delete this; } }; @@ -368,25 +388,31 @@ PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelArray); class MockChannelArray : public ChannelArray { private: - ChannelArrayRequester* m_channelArrayRequester; - PVArray* m_pvArray; + ChannelArrayRequester::shared_pointer m_channelArrayRequester; + PVArray::shared_pointer m_pvArray; - private: - ~MockChannelArray() + protected: + MockChannelArray(ChannelArrayRequester::shared_pointer& channelArrayRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : + m_channelArrayRequester(channelArrayRequester), + m_pvArray(getPVDataCreate()->createPVScalarArray(0, "", pvDouble)) { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelArray); + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelArray); } public: - MockChannelArray(ChannelArrayRequester* channelArrayRequester, PVStructure *pvStructure, PVStructure *pvRequest) : - m_channelArrayRequester(channelArrayRequester) + static ChannelArray::shared_pointer create(ChannelArrayRequester::shared_pointer& channelArrayRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) { - PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelArray); - - m_pvArray = getPVDataCreate()->createPVScalarArray(0, "", pvDouble); + ChannelArray::shared_pointer thisPtr(new MockChannelArray(channelArrayRequester, pvStructure, pvRequest)); // TODO pvRequest - m_channelArrayRequester->channelArrayConnect(Status::OK, this, m_pvArray); + channelArrayRequester->channelArrayConnect(Status::OK, thisPtr, static_cast(thisPtr.get())->m_pvArray); + + return thisPtr; + } + + virtual ~MockChannelArray() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelArray); } virtual void putArray(bool lastRequest, int offset, int count) @@ -415,8 +441,6 @@ class MockChannelArray : public ChannelArray virtual void destroy() { - delete m_pvArray; - delete this; } }; @@ -428,25 +452,19 @@ class MockChannelArray : public ChannelArray PVDATA_REFCOUNT_MONITOR_DEFINE(mockMonitor); -class MockMonitor : public Monitor, public MonitorElement +class MockMonitor : public Monitor, public MonitorElement, public std::tr1::enable_shared_from_this { private: - MonitorRequester* m_monitorRequester; - PVStructure* m_pvStructure; - BitSet* m_changedBitSet; - BitSet* m_overrunBitSet; + MonitorRequester::shared_pointer m_monitorRequester; + PVStructure::shared_pointer m_pvStructure; + BitSet::shared_pointer m_changedBitSet; + BitSet::shared_pointer m_overrunBitSet; bool m_first; Mutex m_lock; int m_count; - private: - ~MockMonitor() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockMonitor); - } - - public: - MockMonitor(MonitorRequester* monitorRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + protected: + MockMonitor(MonitorRequester::shared_pointer& monitorRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) : m_monitorRequester(monitorRequester), m_pvStructure(pvStructure), m_changedBitSet(new BitSet(pvStructure->getNumberFields())), m_overrunBitSet(new BitSet(pvStructure->getNumberFields())), @@ -457,15 +475,30 @@ class MockMonitor : public Monitor, public MonitorElement PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockMonitor); m_changedBitSet->set(0); + } + + public: + static Monitor::shared_pointer create(MonitorRequester::shared_pointer& monitorRequester, PVStructure::shared_pointer& pvStructure, PVStructure::shared_pointer& pvRequest) + { + Monitor::shared_pointer thisPtr(new MockMonitor(monitorRequester, pvStructure, pvRequest)); // TODO pvRequest - m_monitorRequester->monitorConnect(Status::OK, this, const_cast(m_pvStructure->getStructure())); + StructureConstPtr structurePtr = static_cast(thisPtr.get())->m_pvStructure->getStructure(); + monitorRequester->monitorConnect(Status::OK, thisPtr, structurePtr); + + return thisPtr; + } + + virtual ~MockMonitor() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockMonitor); } virtual Status start() { // first monitor - m_monitorRequester->monitorEvent(this); + Monitor::shared_pointer thisPtr = shared_from_this(); + m_monitorRequester->monitorEvent(thisPtr); return Status::OK; } @@ -475,21 +508,22 @@ class MockMonitor : public Monitor, public MonitorElement return Status::OK; } - virtual MonitorElement* poll() + virtual MonitorElement::shared_pointer poll() { Lock xx(m_lock); if (m_count) { - return 0; + return MonitorElement::shared_pointer(); } else { m_count++; - return this; + MonitorElement::shared_pointer thisPtr = shared_from_this(); + return thisPtr; } } - virtual void release(MonitorElement* monitorElement) + virtual void release(MonitorElement::shared_pointer& monitorElement) { Lock xx(m_lock); if (m_count) @@ -499,25 +533,21 @@ class MockMonitor : public Monitor, public MonitorElement virtual void destroy() { stop(); - - delete m_overrunBitSet; - delete m_changedBitSet; - delete this; } // ============ MonitorElement ============ - virtual PVStructure* getPVStructure() + virtual PVStructure::shared_pointer getPVStructure() { return m_pvStructure; } - virtual BitSet* getChangedBitSet() + virtual BitSet::shared_pointer getChangedBitSet() { return m_changedBitSet; } - virtual BitSet* getOverrunBitSet() + virtual BitSet::shared_pointer getOverrunBitSet() { return m_overrunBitSet; } @@ -526,35 +556,28 @@ class MockMonitor : public Monitor, public MonitorElement }; - PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannel); class MockChannel : public Channel { private: - ChannelProvider* m_provider; - ChannelRequester* m_requester; + ChannelProvider::shared_pointer m_provider; + ChannelRequester::shared_pointer m_requester; String m_name; String m_remoteAddress; + PVStructure::shared_pointer m_pvStructure; - PVStructure* m_pvStructure; - - private: - ~MockChannel() - { - PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannel); - } - - public: + protected: MockChannel( - ChannelProvider* provider, - ChannelRequester* requester, + ChannelProvider::shared_pointer provider, + ChannelRequester::shared_pointer requester, String name, String remoteAddress) : m_provider(provider), m_requester(requester), m_name(name), - m_remoteAddress(remoteAddress) + m_remoteAddress(remoteAddress), + m_pvStructure() { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannel); @@ -562,20 +585,34 @@ class MockChannel : public Channel { ScalarType stype = pvDouble; String allProperties("alarm,timeStamp,display,control,valueAlarm"); - m_pvStructure = getStandardPVField()->scalar( - 0,name,stype,allProperties); + m_pvStructure.reset(getStandardPVField()->scalar(0,name,stype,allProperties)); PVDouble *pvField = m_pvStructure->getDoubleField(String("value")); pvField->put(1.123); + } + + public: + static Channel::shared_pointer create( + ChannelProvider::shared_pointer provider, + ChannelRequester::shared_pointer requester, + String name, + String remoteAddress) + { + Channel::shared_pointer channelPtr(new MockChannel(provider, requester, name, remoteAddress)); // already connected, report state - m_requester->channelStateChange(this, CONNECTED); + requester->channelStateChange(channelPtr, CONNECTED); + + return channelPtr; + } + + virtual ~MockChannel() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannel); } virtual void destroy() { - delete m_pvStructure; - delete this; }; virtual String getRequesterName() @@ -588,7 +625,7 @@ class MockChannel : public Channel { std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual ChannelProvider* getProvider() + virtual ChannelProvider::shared_pointer getProvider() { return m_provider; } @@ -603,7 +640,7 @@ class MockChannel : public Channel { return m_name; } - virtual ChannelRequester* getChannelRequester() + virtual std::tr1::shared_ptr getChannelRequester() { return m_requester; } @@ -618,17 +655,17 @@ class MockChannel : public Channel { return getConnectionState() == CONNECTED; } - virtual AccessRights getAccessRights(epics::pvData::PVField *pvField) + virtual AccessRights getAccessRights(epics::pvData::PVField::shared_pointer& pvField) { return readWrite; } - virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) + virtual void getField(GetFieldRequester::shared_pointer& requester,epics::pvData::String subField) { PVFieldPtr pvField; if(subField == "") { - pvField = m_pvStructure; + pvField = m_pvStructure.get(); } else { @@ -638,59 +675,61 @@ class MockChannel : public Channel { if(pvField == NULL) { string errMsg = "field '" + subField + "' not found"; + FieldConstPtr nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, errMsg); - requester->getDone(errorStatus,NULL); + requester->getDone(errorStatus,nullPtr); return; } - requester->getDone(Status::OK,pvField->getField()); + FieldConstPtr fieldPtr = pvField->getField(); + requester->getDone(Status::OK, fieldPtr); } - virtual ChannelProcess* createChannelProcess( - ChannelProcessRequester *channelProcessRequester, - epics::pvData::PVStructure *pvRequest) + virtual ChannelProcess::shared_pointer createChannelProcess( + ChannelProcessRequester::shared_pointer& channelProcessRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockChannelProcess(channelProcessRequester, m_pvStructure, pvRequest); + return MockChannelProcess::create(channelProcessRequester, m_pvStructure, pvRequest); } - virtual ChannelGet* createChannelGet( - ChannelGetRequester *channelGetRequester, - epics::pvData::PVStructure *pvRequest) + virtual ChannelGet::shared_pointer createChannelGet( + ChannelGetRequester::shared_pointer& channelGetRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockChannelGet(channelGetRequester, m_pvStructure, pvRequest); + return MockChannelGet::create(channelGetRequester, m_pvStructure, pvRequest); } - virtual ChannelPut* createChannelPut( - ChannelPutRequester *channelPutRequester, - epics::pvData::PVStructure *pvRequest) + virtual ChannelPut::shared_pointer createChannelPut( + ChannelPutRequester::shared_pointer& channelPutRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockChannelPut(channelPutRequester, m_pvStructure, pvRequest); + return MockChannelPut::create(channelPutRequester, m_pvStructure, pvRequest); } - virtual ChannelPutGet* createChannelPutGet( - ChannelPutGetRequester *channelPutGetRequester, - epics::pvData::PVStructure *pvRequest) + virtual ChannelPutGet::shared_pointer createChannelPutGet( + ChannelPutGetRequester::shared_pointer& channelPutGetRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockChannelPutGet(channelPutGetRequester, m_pvStructure, pvRequest); + return MockChannelPutGet::create(channelPutGetRequester, m_pvStructure, pvRequest); } - virtual ChannelRPC* createChannelRPC(ChannelRPCRequester *channelRPCRequester, - epics::pvData::PVStructure *pvRequest) + virtual ChannelRPC::shared_pointer createChannelRPC(ChannelRPCRequester::shared_pointer& channelRPCRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockChannelRPC(channelRPCRequester, m_pvStructure, pvRequest); + return MockChannelRPC::create(channelRPCRequester, m_pvStructure, pvRequest); } - virtual epics::pvData::Monitor* createMonitor( - epics::pvData::MonitorRequester *monitorRequester, - epics::pvData::PVStructure *pvRequest) + virtual epics::pvData::Monitor::shared_pointer createMonitor( + epics::pvData::MonitorRequester::shared_pointer& monitorRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockMonitor(monitorRequester, m_pvStructure, pvRequest); + return MockMonitor::create(monitorRequester, m_pvStructure, pvRequest); } - virtual ChannelArray* createChannelArray( - ChannelArrayRequester *channelArrayRequester, - epics::pvData::PVStructure *pvRequest) + virtual ChannelArray::shared_pointer createChannelArray( + ChannelArrayRequester::shared_pointer& channelArrayRequester, + epics::pvData::PVStructure::shared_pointer& pvRequest) { - return new MockChannelArray(channelArrayRequester, m_pvStructure, pvRequest); + return MockChannelArray::create(channelArrayRequester, m_pvStructure, pvRequest); } virtual void printInfo() { @@ -720,18 +759,23 @@ class MockServerChannelProvider; class MockChannelFind : public ChannelFind { public: - MockChannelFind(ChannelProvider* provider) : m_provider(provider) + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + + MockChannelFind(ChannelProvider::shared_pointer &provider) : m_provider(provider) { } + virtual ~MockChannelFind() {} + virtual void destroy() { // one instance for all, do not delete at all } - virtual ChannelProvider* getChannelProvider() + virtual ChannelProvider::shared_pointer getChannelProvider() { - return m_provider; + return m_provider.lock(); }; virtual void cancelChannelFind() @@ -740,22 +784,26 @@ class MockChannelFind : public ChannelFind } private: - - // only to be destroyed by it - friend class MockServerChannelProvider; - virtual ~MockChannelFind() {} - - ChannelProvider* m_provider; + ChannelProvider::weak_pointer m_provider; }; -class MockServerChannelProvider : public ChannelProvider { +class MockServerChannelProvider : public ChannelProvider, + public std::tr1::enable_shared_from_this +{ public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; - MockServerChannelProvider() : m_mockChannelFind(new MockChannelFind(this)) { + MockServerChannelProvider() : m_mockChannelFind() + { } - ~MockServerChannelProvider() {}; + void initialize() + { + ChannelProvider::shared_pointer chProviderPtr = shared_from_this(); + m_mockChannelFind.reset(new MockChannelFind(chProviderPtr)); + } virtual epics::pvData::String getProviderName() { @@ -764,56 +812,55 @@ class MockServerChannelProvider : public ChannelProvider { virtual void destroy() { - delete m_mockChannelFind; - delete this; } - virtual ChannelFind* channelFind( + virtual ChannelFind::shared_pointer channelFind( epics::pvData::String channelName, - ChannelFindRequester *channelFindRequester) + ChannelFindRequester::shared_pointer& channelFindRequester) { + // channel always exists channelFindRequester->channelFindResult(Status::OK, m_mockChannelFind, true); return m_mockChannelFind; } - virtual Channel* createChannel( + virtual Channel::shared_pointer createChannel( epics::pvData::String channelName, - ChannelRequester *channelRequester, + ChannelRequester::shared_pointer& channelRequester, short priority) { return createChannel(channelName, channelRequester, priority, "local"); } - virtual Channel* createChannel( + virtual Channel::shared_pointer createChannel( epics::pvData::String channelName, - ChannelRequester *channelRequester, + ChannelRequester::shared_pointer& channelRequester, short priority, epics::pvData::String address) { if (address == "local") { - Channel* channel = new MockChannel(this, channelRequester, channelName, address); + ChannelProvider::shared_pointer chProviderPtr = shared_from_this(); + Channel::shared_pointer channel = MockChannel::create(chProviderPtr, channelRequester, channelName, address); channelRequester->channelCreated(Status::OK, channel); return channel; } else { + Channel::shared_pointer nullPtr; Status errorStatus(Status::STATUSTYPE_ERROR, "only local supported"); - channelRequester->channelCreated(errorStatus, 0); - return 0; + channelRequester->channelCreated(errorStatus, nullPtr); + return nullPtr; } } private: - - MockChannelFind* m_mockChannelFind; - + ChannelFind::shared_pointer m_mockChannelFind; }; class ChannelFindRequesterImpl : public ChannelFindRequester { - virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind *channelFind,bool wasFound) + virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind::shared_pointer &channelFind,bool wasFound) { std::cout << "[ChannelFindRequesterImpl] channelFindResult(" << status.toString() << ", ..., " << wasFound << ")" << std::endl; @@ -832,15 +879,15 @@ class ChannelRequesterImpl : public ChannelRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelCreated(const epics::pvData::Status& status, Channel *channel) + virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer &channel) { std::cout << "channelCreated(" << status.toString() << ", " << (channel ? channel->getChannelName() : "(null)") << ")" << std::endl; } - virtual void channelStateChange(Channel *c, Channel::ConnectionState connectionState) + virtual void channelStateChange(Channel::shared_pointer &channel, Channel::ConnectionState connectionState) { - std::cout << "channelStateChange(" << c->getChannelName() << ", " << Channel::ConnectionStateNames[connectionState] << ")" << std::endl; + std::cout << "channelStateChange(" << channel->getChannelName() << ", " << Channel::ConnectionStateNames[connectionState] << ")" << std::endl; } }; @@ -873,9 +920,9 @@ class GetFieldRequesterImpl : public GetFieldRequester class ChannelGetRequesterImpl : public ChannelGetRequester { - ChannelGet *m_channelGet; - epics::pvData::PVStructure *m_pvStructure; - epics::pvData::BitSet *m_bitSet; + //TODO weak ChannelGet::shared_pointer m_channelGet; + epics::pvData::PVStructure::shared_pointer m_pvStructure; + epics::pvData::BitSet::shared_pointer m_bitSet; virtual String getRequesterName() { @@ -887,13 +934,12 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet *channelGet, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + virtual void channelGetConnect(const epics::pvData::Status& status, ChannelGet::shared_pointer& channelGet, + epics::pvData::PVStructure::shared_pointer& pvStructure, epics::pvData::BitSet::shared_pointer& bitSet) { std::cout << "channelGetConnect(" << status.toString() << ")" << std::endl; - // TODO sync - m_channelGet = channelGet; + //m_channelGet = channelGet; m_pvStructure = pvStructure; m_bitSet = bitSet; } @@ -910,9 +956,9 @@ class ChannelGetRequesterImpl : public ChannelGetRequester class ChannelPutRequesterImpl : public ChannelPutRequester { - ChannelPut *m_channelPut; - epics::pvData::PVStructure *m_pvStructure; - epics::pvData::BitSet *m_bitSet; + //TODO weak ChannelPut::shared_pointer m_channelPut; + epics::pvData::PVStructure::shared_pointer m_pvStructure; + epics::pvData::BitSet::shared_pointer m_bitSet; virtual String getRequesterName() { @@ -924,13 +970,12 @@ class ChannelPutRequesterImpl : public ChannelPutRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut *channelPut, - epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut::shared_pointer& channelPut, + epics::pvData::PVStructure::shared_pointer& pvStructure, epics::pvData::BitSet::shared_pointer& bitSet) { std::cout << "channelPutConnect(" << status.toString() << ")" << std::endl; - // TODO sync - m_channelPut = channelPut; + //m_channelPut = channelPut; m_pvStructure = pvStructure; m_bitSet = bitSet; } @@ -968,7 +1013,7 @@ class MonitorRequesterImpl : public MonitorRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void monitorConnect(const Status& status, Monitor* monitor, Structure* structure) + virtual void monitorConnect(const Status& status, Monitor::shared_pointer& monitor, StructureConstPtr& structure) { std::cout << "monitorConnect(" << status.toString() << ")" << std::endl; if (structure) @@ -979,11 +1024,11 @@ class MonitorRequesterImpl : public MonitorRequester } } - virtual void monitorEvent(Monitor* monitor) + virtual void monitorEvent(Monitor::shared_pointer& monitor) { std::cout << "monitorEvent" << std::endl; - MonitorElement* element = monitor->poll(); + MonitorElement::shared_pointer element = monitor->poll(); String str("changed/overrun "); element->getChangedBitSet()->toString(&str); @@ -996,7 +1041,7 @@ class MonitorRequesterImpl : public MonitorRequester monitor->release(element); } - virtual void unlisten(Monitor* monitor) + virtual void unlisten(Monitor::shared_pointer& monitor) { std::cout << "unlisten" << std::endl; } @@ -1005,7 +1050,7 @@ class MonitorRequesterImpl : public MonitorRequester class ChannelProcessRequesterImpl : public ChannelProcessRequester { - ChannelProcess *m_channelProcess; + //TODO weak ChannelProcess::shared_pointer m_channelProcess; virtual String getRequesterName() { @@ -1017,12 +1062,11 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; } - virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess *channelProcess) + virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess::shared_pointer& channelProcess) { std::cout << "channelProcessConnect(" << status.toString() << ")" << std::endl; - // TODO sync - m_channelProcess = channelProcess; + //m_channelProcess = channelProcess; } virtual void processDone(const epics::pvData::Status& status) @@ -1035,21 +1079,25 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester void testServer() { - ChannelAccess* channelAccess = getChannelAccess(); - MockServerChannelProvider* channelProvider = new MockServerChannelProvider(); - registerChannelProvider(static_cast(channelProvider)); + + MockServerChannelProvider::shared_pointer channelProvider(new MockServerChannelProvider()); + channelProvider->initialize(); + + ChannelProvider::shared_pointer ptr = channelProvider; + registerChannelProvider(ptr); - ServerContextImpl ctx; - ctx.initialize(channelAccess); + ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); + ChannelAccess::shared_pointer channelAccess = getChannelAccess(); + ctx->initialize(channelAccess); - ctx.printInfo(); + ctx->printInfo(); - ctx.run(100); + ctx->run(10); - ctx.destroy(); + ctx->destroy(); + + unregisterChannelProvider(ptr); - unregisterChannelProvider(static_cast(channelProvider)); - delete channelProvider; } int main(int argc, char *argv[]) @@ -1058,6 +1106,8 @@ int main(int argc, char *argv[]) cout << "Done" << endl; + epicsThreadSleep ( 1.0 ); + std::cout << "-----------------------------------------------------------------------" << std::endl; epicsExitCallAtExits(); CDRMonitor::get().show(stdout); return (0); diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index 49fbcda..36e95ee 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -10,18 +10,81 @@ using namespace epics::pvAccess; using namespace epics::pvData; using namespace std; +class TestChannelProvider : public ChannelProvider +{ +public: + + epics::pvData::String getProviderName() { return "local"; }; + + + ChannelFind::shared_pointer channelFind(epics::pvData::String channelName, + ChannelFindRequester::shared_pointer& channelFindRequester) + { + ChannelFind::shared_pointer nullCF; + channelFindRequester->channelFindResult(Status::OK, nullCF, false); + return nullCF; + } + + Channel::shared_pointer createChannel( + epics::pvData::String channelName, + ChannelRequester::shared_pointer& channelRequester, + short priority = PRIORITY_DEFAULT) + { + return createChannel(channelName, channelRequester, priority, ""); + } + + Channel::shared_pointer createChannel( + epics::pvData::String channelName, + ChannelRequester::shared_pointer& channelRequester, + short priority, epics::pvData::String address) + { + Channel::shared_pointer nullC; + channelRequester->channelCreated(Status::OK, nullC); + return nullC; + } + + void destroy() + { + } +}; + + +class TestChannelAccess : public ChannelAccess { +public: + + virtual ~TestChannelAccess() {}; + + ChannelProvider::shared_pointer getProvider(epics::pvData::String providerName) + { + if (providerName == "local") + { + return ChannelProvider::shared_pointer(new TestChannelProvider()); + } + else + return ChannelProvider::shared_pointer(); + } + + std::auto_ptr getProviderNames() + { + std::auto_ptr pn(new stringVector_t()); + pn->push_back("local"); + return pn; + } +}; + void testServerContext() { - ServerContextImpl ctx; + ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); - ctx.initialize(NULL); + ChannelAccess::shared_pointer ca(new TestChannelAccess()); + ctx->initialize(ca); - ctx.printInfo(); + ctx->printInfo(); - ctx.run(1); + ctx->run(1); - ctx.destroy(); + ctx->destroy(); } int main(int argc, char *argv[]) diff --git a/testApp/utils/Makefile b/testApp/utils/Makefile index e3ecbf7..28fe01b 100644 --- a/testApp/utils/Makefile +++ b/testApp/utils/Makefile @@ -10,14 +10,6 @@ PROD_HOST += wildcharMatcherTest wildcharMatcherTest_SRCS += wildcharMatcherTest.cpp wildcharMatcherTest_LIBS += pvAccess pvData Com -PROD_HOST += arrayFIFOTest -arrayFIFOTest_SRCS += arrayFIFOTest.cpp -arrayFIFOTest_LIBS += pvAccess pvData Com - -PROD_HOST += growingCircularBufferTest -growingCircularBufferTest_SRCS += growingCircularBufferTest.cpp -growingCircularBufferTest_LIBS += pvAccess pvData Com - PROD_HOST += inetAddressUtilsTest inetAddressUtilsTest_SRCS += inetAddressUtilsTest.cpp inetAddressUtilsTest_LIBS += pvAccess pvData Com diff --git a/testApp/utils/arrayFIFOTest.cpp b/testApp/utils/arrayFIFOTest.cpp deleted file mode 100644 index 966d2c1..0000000 --- a/testApp/utils/arrayFIFOTest.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* - * arrayFIFOTest.cpp - * - * Created on: Nov 9, 2010 - * Author: Miha Vitorovic - */ - -#define ARRAY_FIFO_DEBUG 1 -#include "arrayFIFO.h" - -#include -#include - -using namespace epics::pvAccess; -using std::cout; -using std::endl; - -void testSimpleType() { - cout<<"\nTests for simple type template."< fifoInt; - - assert(fifoInt.size()==0); - assert(fifoInt.isEmpty()); - - cout<<"Testing clear."< fifoInt; - - assert(fifoInt.size()==0); - assert(fifoInt.isEmpty()); - - cout<<"Testing clear."< - -#include -#include - -using namespace epics::pvAccess; -using std::cout; -using std::endl; - -const size_t CAPACITY = 10; - -void testSimpleType() { - GrowingCircularBuffer cb(CAPACITY); - - cout<<"Testing circular buffer simple type."< cb(CAPACITY); - int testVals[] = {0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20}; - - cout<<"Testing circular buffer pointer type."< #include #include +#include + +using std::tr1::static_pointer_cast; namespace epics { namespace pvAccess { @@ -139,45 +142,45 @@ void testRegistryPutGet() registry->registerIntrospectionInterface(id,structureArrayIn); id = 0; - ScalarConstPtr scalarOut = static_cast(registry->getIntrospectionInterface(id)); + ScalarConstPtr scalarOut = static_pointer_cast(registry->getIntrospectionInterface(id)); assert(scalarIn == scalarOut); id++; - ScalarArrayConstPtr scalarArrayOut = static_cast(registry->getIntrospectionInterface(id)); + ScalarArrayConstPtr scalarArrayOut = static_pointer_cast(registry->getIntrospectionInterface(id)); assert(scalarArrayIn == scalarArrayOut); id++; - StructureConstPtr structureOut = static_cast(registry->getIntrospectionInterface(id)); + StructureConstPtr structureOut = static_pointer_cast(registry->getIntrospectionInterface(id)); assert(structureIn == structureOut); id++; - StructureArrayConstPtr structureArrayOut = static_cast(registry->getIntrospectionInterface(id)); + StructureArrayConstPtr structureArrayOut = static_pointer_cast(registry->getIntrospectionInterface(id)); assert(structureArrayIn == structureArrayOut); bool existing; - id = registry->registerIntrospectionInterface(static_cast(scalarIn),existing); + id = registry->registerIntrospectionInterface(static_pointer_cast(scalarIn),existing); assert(existing == true); assert(id == 0); - id = registry->registerIntrospectionInterface(static_cast(scalarArrayIn),existing); + id = registry->registerIntrospectionInterface(static_pointer_cast(scalarArrayIn),existing); assert(existing == true); assert(id == 1); - id = registry->registerIntrospectionInterface(static_cast(structureIn),existing); + id = registry->registerIntrospectionInterface(static_pointer_cast(structureIn),existing); assert(existing == true); assert(id == 2); - id = registry->registerIntrospectionInterface(static_cast(structureArrayIn),existing); + id = registry->registerIntrospectionInterface(static_pointer_cast(structureArrayIn),existing); assert(existing == true); assert(id == 3); //should exist ScalarConstPtr scalarInNew = getScalar("field1"); - id = registry->registerIntrospectionInterface(static_cast(scalarInNew),existing); + id = registry->registerIntrospectionInterface(static_pointer_cast(scalarInNew),existing); assert(existing == true); assert(id == 0); - scalarOut = static_cast(registry->getIntrospectionInterface(id)); + scalarOut = static_pointer_cast(registry->getIntrospectionInterface(id)); assert(scalarIn == scalarOut); } @@ -186,7 +189,7 @@ void testRegistryReset() registry->reset(); short id = 0; - assert(static_cast(registry->getIntrospectionInterface(id)) == 0); + assert(static_pointer_cast(registry->getIntrospectionInterface(id)) == 0); } void serialize(FieldConstPtr field, IntrospectionRegistry* registry) @@ -214,6 +217,7 @@ FieldConstPtr deserialize(IntrospectionRegistry* registry) void checkTypeCode(int8 typeCodeIn) { int8 typeCode = buffer->getByte(); + printf("%d == %d\n", typeCode, typeCodeIn); assert(typeCode == typeCodeIn); buffer->rewind(); } @@ -275,7 +279,7 @@ void testSerialize() j++; ss << j; name2 = "field" + ss.str(); - testSerializeCommon(static_cast(getScalar(name1)),static_cast(getScalar(name2))); + testSerializeCommon(static_pointer_cast(getScalar(name1)),static_pointer_cast(getScalar(name2))); name1.clear(); name2.clear(); @@ -286,7 +290,7 @@ void testSerialize() j++; ss << j; name2 = "fieldArray" + ss.str(); - testSerializeCommon(static_cast(getScalarArray(name1)),static_cast(getScalarArray(name2))); + testSerializeCommon(static_pointer_cast(getScalarArray(name1)),static_pointer_cast(getScalarArray(name2))); name1.clear(); name2.clear(); @@ -297,7 +301,7 @@ void testSerialize() j++; ss << j; name2 = "structure" + ss.str(); - testSerializeCommon(static_cast(getStructure(name1)),static_cast(getStructure(name2))); + testSerializeCommon(static_pointer_cast(getStructure(name1)),static_pointer_cast(getStructure(name2))); name1.clear(); name2.clear(); @@ -312,7 +316,7 @@ void testSerialize() ss << j; name3 = "structure" + ss.str(); name4 = "structureArray" + ss.str(); - testSerializeCommon(static_cast(getStructureArray(name1,name2)),static_cast(getStructureArray(name3,name4))); + testSerializeCommon(static_pointer_cast(getStructureArray(name1,name2)),static_pointer_cast(getStructureArray(name3,name4))); } //serverRegistry->printKeysAndValues("server"); @@ -323,9 +327,9 @@ void testSerializeFull() { buffer->clear(); ScalarConstPtr scalarIn = getScalar("field1"); - IntrospectionRegistry::serializeFull(static_cast(scalarIn),buffer,flusher); + IntrospectionRegistry::serializeFull(static_pointer_cast(scalarIn),buffer,flusher); buffer->flip(); - ScalarConstPtr scalarOut = static_cast(IntrospectionRegistry::deserializeFull(buffer,control)); + ScalarConstPtr scalarOut = static_pointer_cast(IntrospectionRegistry::deserializeFull(buffer,control)); PVField *pvField = pvDataCreate->createPVField(0,scalarOut); pvFieldArray.push_back(pvField); assert(scalarIn->getFieldName() == scalarOut->getFieldName()); @@ -333,9 +337,9 @@ void testSerializeFull() buffer->clear(); ScalarArrayConstPtr scalarArrayIn = getScalarArray("fieldArray1"); - IntrospectionRegistry::serializeFull(static_cast(scalarArrayIn),buffer,flusher); + IntrospectionRegistry::serializeFull(static_pointer_cast(scalarArrayIn),buffer,flusher); buffer->flip(); - ScalarArrayConstPtr scalarArrayOut = static_cast(IntrospectionRegistry::deserializeFull(buffer,control)); + ScalarArrayConstPtr scalarArrayOut = static_pointer_cast(IntrospectionRegistry::deserializeFull(buffer,control)); pvField = pvDataCreate->createPVField(0,scalarArrayOut); pvFieldArray.push_back(pvField); assert(scalarArrayIn->getFieldName() == scalarArrayOut->getFieldName()); @@ -343,9 +347,9 @@ void testSerializeFull() buffer->clear(); StructureConstPtr structureIn = getStructure("struct1"); - IntrospectionRegistry::serializeFull(static_cast(structureIn),buffer,flusher); + IntrospectionRegistry::serializeFull(static_pointer_cast(structureIn),buffer,flusher); buffer->flip(); - StructureConstPtr structureOut = static_cast(IntrospectionRegistry::deserializeFull(buffer,control)); + StructureConstPtr structureOut = static_pointer_cast(IntrospectionRegistry::deserializeFull(buffer,control)); pvField = pvDataCreate->createPVField(0,structureOut); pvFieldArray.push_back(pvField); assert(structureIn->getFieldName() == structureOut->getFieldName()); @@ -353,9 +357,9 @@ void testSerializeFull() buffer->clear(); StructureArrayConstPtr structureArrayIn = getStructureArray("struct1","structArray1"); - IntrospectionRegistry::serializeFull(static_cast(structureArrayIn),buffer,flusher); + IntrospectionRegistry::serializeFull(static_pointer_cast(structureArrayIn),buffer,flusher); buffer->flip(); - StructureArrayConstPtr structureArrayOut = static_cast(IntrospectionRegistry::deserializeFull(buffer,control)); + StructureArrayConstPtr structureArrayOut = static_pointer_cast(IntrospectionRegistry::deserializeFull(buffer,control)); pvField = pvDataCreate->createPVField(0,structureArrayOut); pvFieldArray.push_back(pvField); assert(structureArrayIn->getFieldName() == structureArrayOut->getFieldName()); diff --git a/testApp/utils/transportRegistryTest.cpp b/testApp/utils/transportRegistryTest.cpp index 406b63f..d92fbc9 100644 --- a/testApp/utils/transportRegistryTest.cpp +++ b/testApp/utils/transportRegistryTest.cpp @@ -12,12 +12,16 @@ #include #include + namespace epics { namespace pvAccess { class TestTransport : public Transport{ public: + typedef std::tr1::shared_ptr shared_pointer; + typedef std::tr1::shared_ptr const_shared_pointer; + TestTransport(string type, int16 priority, osiSockAddr* address): _type(type), _priority(priority), _address(address) {/*cout << "Transport::Transport" << endl;*/}; ~TestTransport(){/*cout << "Transport::~Transport" << endl;*/}; virtual const string getType() const {return _type;}; @@ -39,7 +43,7 @@ namespace epics { virtual bool isClosed() {return false;}; virtual bool isVerified() {return false;}; virtual void verified(){}; - virtual void enqueueSendRequest(TransportSender* sender){}; + virtual void enqueueSendRequest(TransportSender::shared_pointer& sender){}; virtual void ensureData(int) {}; virtual IntrospectionRegistry* getIntrospectionRegistry() {return NULL;}; private: @@ -57,68 +61,77 @@ using namespace std; static TransportRegistry* registry; static const int16 address_max = 10; static const int16 priority_max = 100; +typedef std::vector osiSockAddrVector_t; int main(int argc, char *argv[]) { registry = new TransportRegistry(); - int32 size; - TestTransport** transportArrayOut; - TestTransport** transportArrayIn = new TestTransport*[address_max * priority_max]; - osiSockAddr** addrArray = new osiSockAddr*[address_max]; + auto_ptr transportArrayOut; + std::vector transportArrayIn (address_max * priority_max); + osiSockAddrVector_t addrArray (address_max); //address for(int32 i = 0; i < address_max; i++) { osiSockAddr* addr = new osiSockAddr; - addrArray[i] = addr; addr->ia.sin_addr.s_addr = i; addr->ia.sin_port = i; addr->ia.sin_family = AF_INET; + addrArray.at(i) = addr; //priority for(int16 j = 0; j < priority_max; j++) { - TestTransport* transportIn = new TestTransport("tcp", j, addr); - transportArrayIn[i * priority_max + j] = transportIn; - registry->put(static_cast(transportIn)); + Transport::shared_pointer testTransportIn(new TestTransport("tcp", j, addr)); + transportArrayIn.at(i * priority_max + j) = testTransportIn; + registry->put(testTransportIn); - TestTransport* transportOut = static_cast(registry->get("tcp",addr,(const int16)j)); - assert(transportIn == transportOut); + Transport::shared_pointer testTransportOut(registry->get("tcp",addr,(const int16)j)); + assert(testTransportIn.get() == testTransportOut.get()); } - - transportArrayOut = reinterpret_cast(registry->get("tcp",addr,size)); - assert(size == priority_max); + transportArrayOut = registry->get("tcp",addr); + assert((int16)transportArrayOut->size() == priority_max); for(int32 k = 0; k < priority_max; k++) { - assert(transportArrayIn[i * priority_max + k] == transportArrayOut[k]); + assert(transportArrayIn.at(i * priority_max + k).get() == transportArrayOut->at(k).get()); } - - delete[] transportArrayOut; } + //add one transport which has same addr and priority as last one and check that the size does not increase + osiSockAddr* addr = new osiSockAddr; + addr->ia.sin_addr.s_addr = address_max - 1; + addr->ia.sin_port = address_max - 1; + addr->ia.sin_family = AF_INET; + Transport::shared_pointer testTransportIn(new TestTransport("tcp", priority_max - 1, addr)); + registry->put(testTransportIn); + Transport::shared_pointer testTransportOut(registry->get("tcp",addr,(const int16)priority_max - 1)); + assert(testTransportIn.get() == testTransportOut.get()); + delete addr; + //put back the old one + registry->put(transportArrayIn.at((address_max - 1) * priority_max + priority_max - 1)); + assert(registry->numberOfActiveTransports() == (address_max * priority_max)); - transportArrayOut = reinterpret_cast(registry->toArray("tcp",size)); - assert(size == (address_max * priority_max)); + transportArrayOut = registry->toArray("tcp"); + assert((int16)transportArrayOut->size() == (address_max * priority_max)); for(int32 i = 0; i < address_max * priority_max; i++) { - assert(transportArrayIn[i] == transportArrayOut[i]); + assert(transportArrayIn.at(i).get() == transportArrayOut->at(i).get()); } - delete[] transportArrayOut; - transportArrayOut = reinterpret_cast(registry->toArray(size)); - assert(size == (address_max * priority_max)); + + transportArrayOut = registry->toArray(); + assert((int16)transportArrayOut->size() == (address_max * priority_max)); for(int32 i = 0; i < address_max * priority_max; i++) { - assert(transportArrayIn[i] == transportArrayOut[i]); + assert(transportArrayIn.at(i).get() == transportArrayOut->at(i).get()); } - delete[] transportArrayOut; for(int32 i = 0; i < address_max; i++) { for(int16 j = 0; j < priority_max; j++) { - assert(transportArrayIn[i * priority_max + j] == registry->remove(static_cast(transportArrayIn[i * priority_max + j]))); + assert(transportArrayIn.at(i * priority_max + j) == registry->remove(transportArrayIn.at(i * priority_max + j))); } } assert(registry->numberOfActiveTransports() == 0); @@ -127,27 +140,21 @@ int main(int argc, char *argv[]) { for(int16 j = 0; j < priority_max; j++) { - registry->put(static_cast(transportArrayIn[i * priority_max + j]));; + registry->put(transportArrayIn.at(i * priority_max + j)); } } assert(registry->numberOfActiveTransports() == (priority_max * address_max)); registry->clear(); assert(registry->numberOfActiveTransports() == 0); - for(int32 i = 0; i < address_max; i++) + for(osiSockAddrVector_t::iterator iter = addrArray.begin(); iter != addrArray.end(); iter++) { - if( addrArray[i]) delete addrArray[i]; - for(int16 j = 0; j < priority_max; j++) - { - if(transportArrayIn[i * priority_max + j]) delete transportArrayIn[i * priority_max + j]; - } + delete *iter; } - - if(addrArray) delete[] addrArray; - if(transportArrayIn) delete[] transportArrayIn; + addrArray.clear(); if(registry) delete registry; - epicsExitCallAtExits(); - CDRMonitor::get().show(stdout); + epicsExitCallAtExits(); + CDRMonitor::get().show(stdout); return 0; }