From 84b22522cb087d0ea548f502e78e0d4da8ab8b09 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 20 Dec 2010 19:48:06 +0100 Subject: [PATCH 1/3] Destruction. --- pvAccessApp/client/pvAccess.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 2758c93..4c5b72c 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -32,6 +32,8 @@ namespace epics { namespace pvAccess { enum ConnectionState { NEVER_CONNECTED, CONNECTED, DISCONNECTED, DESTROYED }; + + const char* ConnectionStateNames[] = { "NEVER_CONNECTED", "CONNECTED", "DISCONNECTED", "DESTROYED" }; class Channel; @@ -118,7 +120,7 @@ namespace epics { namespace pvAccess { * @author mrk * */ - class ChannelFind { + class ChannelFind : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: virtual ChannelProvider* getChannelProvider() = 0; virtual void cancelChannelFind() = 0; @@ -592,6 +594,7 @@ namespace epics { namespace pvAccess { */ class ChannelAccess : private epics::pvData::NoDefaultMethods { public: + virtual ~ChannelAccess() {}; /** * Get the provider with the specified name. @@ -617,7 +620,7 @@ namespace epics { namespace pvAccess { * @author mrk * */ - class ChannelProvider : private epics::pvData::NoDefaultMethods { + class ChannelProvider : public epics::pvData::Destroyable, private epics::pvData::NoDefaultMethods { public: /** Minimal priority. */ @@ -633,11 +636,6 @@ namespace epics { namespace pvAccess { /** OPI priority. */ static const short PRIORITY_OPI = PRIORITY_MIN; - /** - * Terminate. - */ - virtual void destroy() = 0; - /** * Get the provider name. * @return The name. @@ -659,7 +657,7 @@ 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) = 0; + virtual Channel* createChannel(epics::pvData::String channelName,ChannelRequester *channelRequester,short priority = PRIORITY_DEFAULT) = 0; /** * Create a channel. @@ -684,7 +682,7 @@ namespace epics { namespace pvAccess { * Get context implementation version. * @return version of the context implementation. */ - virtual const Version* getVersion() = 0; + virtual Version* getVersion() = 0; /** * Initialize client context. This method is called immediately after instance construction (call of constructor). @@ -695,7 +693,7 @@ namespace epics { namespace pvAccess { * Get channel provider implementation. * @return the channel provider. */ - virtual const ChannelProvider* getProvider() = 0; + virtual ChannelProvider* getProvider() = 0; /** * Prints detailed information about the context to the standard output stream. From 956627152d05b67c03bb890e49d3a131e4a21c72 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 20 Dec 2010 19:48:24 +0100 Subject: [PATCH 2/3] Further impl. --- testApp/client/MockClientImpl.cpp | 230 +++++++++++++++++++++++++++++- 1 file changed, 225 insertions(+), 5 deletions(-) diff --git a/testApp/client/MockClientImpl.cpp b/testApp/client/MockClientImpl.cpp index 5bb0392..e6e6844 100644 --- a/testApp/client/MockClientImpl.cpp +++ b/testApp/client/MockClientImpl.cpp @@ -4,14 +4,196 @@ #include #include +#include +#include using namespace epics::pvData; using namespace epics::pvAccess; + + +static volatile int64 mockChannel_totalConstruct = 0; +static volatile int64 mockChannel_totalDestruct = 0; +static Mutex *mockChannel_globalMutex = 0; + +static int64 mockChannel_getTotalConstruct() +{ + Lock xx(mockChannel_globalMutex); + return mockChannel_totalConstruct; +} + +static int64 mockChannel_getTotalDestruct() +{ + Lock xx(mockChannel_globalMutex); + return mockChannel_totalDestruct; +} + +static ConstructDestructCallback *mockChannel_pConstructDestructCallback; + +static void mockChannel_init() +{ + static Mutex mutex = Mutex(); + Lock xx(&mutex); + if(mockChannel_globalMutex==0) { + mockChannel_globalMutex = new Mutex(); + mockChannel_pConstructDestructCallback = new ConstructDestructCallback( + String("mockChannel"), + mockChannel_getTotalConstruct,mockChannel_getTotalDestruct,0); + } +} + + +class MockChannel : public Channel { + private: + ChannelProvider* m_provider; + ChannelRequester* m_requester; + String m_name; + String m_remoteAddress; + + private: + ~MockChannel() + { + Lock xx(mockChannel_globalMutex); + mockChannel_totalDestruct++; + } + + public: + + MockChannel( + ChannelProvider* provider, + ChannelRequester* requester, + String name, + String remoteAddress) : + m_provider(provider), + m_requester(requester), + m_name(name), + m_remoteAddress(remoteAddress) + { + mockChannel_init(); + + Lock xx(mockChannel_globalMutex); + mockChannel_totalConstruct++; + + // already connected, report state + m_requester->channelStateChange(this, CONNECTED); + } + + virtual void destroy() + { + delete this; + }; + + virtual String getRequesterName() + { + return getChannelName(); + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual ChannelProvider* getProvider() + { + return m_provider; + } + + virtual epics::pvData::String getRemoteAddress() + { + return m_remoteAddress; + } + + virtual epics::pvData::String getChannelName() + { + return m_name; + } + + virtual ChannelRequester* getChannelRequester() + { + return m_requester; + } + + virtual ConnectionState getConnectionState() + { + return CONNECTED; + } + + virtual bool isConnected() + { + return getConnectionState() == CONNECTED; + } + + virtual AccessRights getAccessRights(epics::pvData::PVField *pvField) + { + return readWrite; + } + + virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) + { + // TODO + } + + virtual ChannelProcess* createChannelProcess( + ChannelProcessRequester *channelProcessRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual ChannelGet* createChannelGet( + ChannelGetRequester *channelGetRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual ChannelPut* createChannelPut( + ChannelPutRequester *channelPutRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual ChannelPutGet* createChannelPutGet( + ChannelPutGetRequester *channelPutGetRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual ChannelRPC* createChannelRPC(ChannelRPCRequester *channelRPCRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual epics::pvData::Monitor* createMonitor( + epics::pvData::MonitorRequester *monitorRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual ChannelArray* createChannelArray( + ChannelArrayRequester *channelArrayRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } +}; + + class MockChannelProvider : public ChannelProvider { -public: + public: virtual epics::pvData::String getProviderName() { @@ -48,15 +230,15 @@ public: { if (address == "local") { - Channel* channel = 0; + Channel* channel = new MockChannel(this, channelRequester, channelName, address); channelRequester->channelCreated(getStatusCreate()->getStatusOK(), channel); - // TODO state change return channel; } else { Status* errorStatus = getStatusCreate()->createStatus(STATUSTYPE_ERROR, "only local supported", 0); channelRequester->channelCreated(errorStatus, 0); + delete errorStatus; // TODO guard from CB return 0; } } @@ -78,11 +260,11 @@ class MockClientContext : public ClientContext initialize(); } - virtual const Version* getVersion() { + virtual Version* getVersion() { return m_version; } - virtual const ChannelProvider* getProvider() { + virtual ChannelProvider* getProvider() { return m_provider; } @@ -120,12 +302,50 @@ class MockClientContext : public ClientContext }; +class ChannelRequesterImpl : public ChannelRequester +{ + virtual String getRequesterName() + { + return "ChannelRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void channelCreated(epics::pvData::Status* status, Channel *channel) + { + std::cout << "channelCreated("; + String str; + status->toString(&str); + std::cout << str << ", " << (channel ? channel->getChannelName() : "(null)") << ")" << std::endl; + } + + virtual void channelStateChange(Channel *c, ConnectionState connectionState) + { + std::cout << "channelStateChange(" << c->getChannelName() << ", " << ConnectionStateNames[connectionState] << ")" << std::endl; + } +}; + int main(int argc,char *argv[]) { MockClientContext* context = new MockClientContext(); context->printInfo(); + ChannelRequesterImpl requester; + + /*Channel* noChannel =*/ context->getProvider()->createChannel("test", &requester, ChannelProvider::PRIORITY_DEFAULT, "over the rainbow"); + + Channel* channel = context->getProvider()->createChannel("test", &requester); + std::cout << channel->getChannelName() << std::endl; + channel->destroy(); + + context->destroy(); + + std::cout << "-----------------------------------------------------------------------" << std::endl; + getShowConstructDestruct()->constuctDestructTotals(stdout); return(0); } From 15e435ddf668ef470883e54441aa77570ca6bd68 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Mon, 20 Dec 2010 23:56:29 +0100 Subject: [PATCH 3/3] Channel::getField() --- pvAccessApp/client/pvAccess.h | 2 +- testApp/client/MockClientImpl.cpp | 118 +++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 12 deletions(-) diff --git a/pvAccessApp/client/pvAccess.h b/pvAccessApp/client/pvAccess.h index 4c5b72c..c85a9da 100644 --- a/pvAccessApp/client/pvAccess.h +++ b/pvAccessApp/client/pvAccess.h @@ -405,7 +405,7 @@ namespace epics { namespace pvAccess { * @param status Completion status. * @param field The Structure for the request. */ - virtual void getDone(epics::pvData::Status *status,epics::pvData::Field *field) = 0; + virtual void getDone(epics::pvData::Status *status,epics::pvData::FieldConstPtr field) = 0; }; diff --git a/testApp/client/MockClientImpl.cpp b/testApp/client/MockClientImpl.cpp index e6e6844..5558625 100644 --- a/testApp/client/MockClientImpl.cpp +++ b/testApp/client/MockClientImpl.cpp @@ -6,14 +6,11 @@ #include #include #include +#include using namespace epics::pvData; using namespace epics::pvAccess; - - - - static volatile int64 mockChannel_totalConstruct = 0; static volatile int64 mockChannel_totalDestruct = 0; static Mutex *mockChannel_globalMutex = 0; @@ -52,9 +49,13 @@ class MockChannel : public Channel { String m_name; String m_remoteAddress; + PVStructure* pvStructure; + private: ~MockChannel() { + delete pvStructure; + Lock xx(mockChannel_globalMutex); mockChannel_totalDestruct++; } @@ -75,6 +76,16 @@ class MockChannel : public Channel { Lock xx(mockChannel_globalMutex); mockChannel_totalConstruct++; + + + ScalarType stype = pvDouble; + String allProperties("alarm,timeStamp,display,control,valueAlarm"); + + pvStructure = getStandardPVField()->scalar( + 0,name,stype,allProperties); + PVDouble *pvField = pvStructure->getDoubleField(String("value")); + pvField->put(1.123e35); + // already connected, report state m_requester->channelStateChange(this, CONNECTED); @@ -132,7 +143,7 @@ class MockChannel : public Channel { virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) { - // TODO + requester->getDone(getStatusCreate()->getStatusOK(),pvStructure->getSubField(subField)->getField()); } virtual ChannelProcess* createChannelProcess( @@ -191,10 +202,45 @@ class MockChannel : public Channel { } }; +class MockChannelProvider; + +class MockChannelFind : public ChannelFind +{ + public: + MockChannelFind(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 MockChannelProvider; + virtual ~MockChannelFind() {} + + ChannelProvider* m_provider; +}; class MockChannelProvider : public ChannelProvider { public: + MockChannelProvider() : m_mockChannelFind(new MockChannelFind(this)) { + } + virtual epics::pvData::String getProviderName() { return "MockChannelProvider"; @@ -202,6 +248,7 @@ class MockChannelProvider : public ChannelProvider { virtual void destroy() { + delete m_mockChannelFind; delete this; } @@ -209,9 +256,8 @@ class MockChannelProvider : public ChannelProvider { epics::pvData::String channelName, ChannelFindRequester *channelFindRequester) { - ChannelFind* channelFind = 0; // TODO - channelFindRequester->channelFindResult(getStatusCreate()->getStatusOK(), channelFind, true); - return channelFind; + channelFindRequester->channelFindResult(getStatusCreate()->getStatusOK(), m_mockChannelFind, true); + return m_mockChannelFind; } virtual Channel* createChannel( @@ -246,6 +292,8 @@ class MockChannelProvider : public ChannelProvider { private: ~MockChannelProvider() {}; + MockChannelFind* m_mockChannelFind; + }; @@ -302,6 +350,17 @@ class MockClientContext : public ClientContext }; +class ChannelFindRequesterImpl : public ChannelFindRequester +{ + virtual void channelFindResult(epics::pvData::Status *status,ChannelFind *channelFind,bool wasFound) + { + std::cout << "[ChannelFindRequesterImpl] channelFindResult("; + String str; + status->toString(&str); + std::cout << str << ", ..., " << wasFound << ")" << std::endl; + } +}; + class ChannelRequesterImpl : public ChannelRequester { virtual String getRequesterName() @@ -328,17 +387,54 @@ class ChannelRequesterImpl : public ChannelRequester } }; +class GetFieldRequesterImpl : public GetFieldRequester +{ + virtual String getRequesterName() + { + return "GetFieldRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void getDone(epics::pvData::Status *status,epics::pvData::FieldConstPtr field) + { + std::cout << "getDone("; + String str; + status->toString(&str); + std::cout << str << ", "; + if (field) + { + str.clear(); + field->toString(&str); + std::cout << str; + } + else + std::cout << "(null)"; + std::cout << ")" << std::endl; + } +}; + int main(int argc,char *argv[]) { MockClientContext* context = new MockClientContext(); context->printInfo(); - ChannelRequesterImpl requester; - /*Channel* noChannel =*/ context->getProvider()->createChannel("test", &requester, ChannelProvider::PRIORITY_DEFAULT, "over the rainbow"); + ChannelFindRequesterImpl findRequester; + context->getProvider()->channelFind("something", &findRequester); + + ChannelRequesterImpl channelRequester; + /*Channel* noChannel =*/ context->getProvider()->createChannel("test", &channelRequester, ChannelProvider::PRIORITY_DEFAULT, "over the rainbow"); - Channel* channel = context->getProvider()->createChannel("test", &requester); + Channel* channel = context->getProvider()->createChannel("test", &channelRequester); std::cout << channel->getChannelName() << std::endl; + + GetFieldRequesterImpl getFieldRequesterImpl; + channel->getField(&getFieldRequesterImpl, "timeStamp.secondsPastEpoch"); + channel->destroy();