diff --git a/example/createdestroy/Makefile b/example/createdestroy/Makefile new file mode 100755 index 0000000..5313c10 --- /dev/null +++ b/example/createdestroy/Makefile @@ -0,0 +1,25 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#============================= +# Build the application + +TESTPROD_HOST = createdestroy + +createdestroy_SRCS += createdestroy.cpp + +# Add all the support libraries needed by this application +#pvatest_LIBS += xxx + +# Finally link to the EPICS Base libraries +createdestroy_LIBS += pvDatabase pvAccess pvData +createdestroy_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE diff --git a/example/createdestroy/README.md b/example/createdestroy/README.md new file mode 100644 index 0000000..a5caaf3 --- /dev/null +++ b/example/createdestroy/README.md @@ -0,0 +1,20 @@ +# pvDatabaseCPP/example/createdestroy + +This is an example that: + +1) Gets the master PVDatabase +2) Create ChannelProviderLocal +3) Creates a ServerContext + +Then it executes a forever loop that: + +1) creates a pvRecord and adds it to the pvDatabase. +2) creates a pvac::ClientProvider +3) creates a pvac::ClientChannel +4) creates a monitor on the channel +5) runs a loop 10 times that: does a put to the channel, and then gets the data for any outstanding monitors +6) removes the pvRecord from the pvDatabase + +It also has options to set trace level for the pvRecord and to periodically pause by asking for input. + + diff --git a/example/createdestroy/createdestroy.cpp b/example/createdestroy/createdestroy.cpp new file mode 100644 index 0000000..c432f34 --- /dev/null +++ b/example/createdestroy/createdestroy.cpp @@ -0,0 +1,179 @@ +/****************************************************************************** +* This is modeled after a test program created by Bertrand Bauvir from the ITER Organization +******************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include + +// Local header files + +// Constants + +#define DEFAULT_RECORD_NAME "examplechannel" + +using std::tr1::static_pointer_cast; + +class Record : public ::epics::pvDatabase::PVRecord +{ +public: + std::shared_ptr<::epics::pvData::PVStructure> __pv; + static std::shared_ptr create (std::string const & name, std::shared_ptr<::epics::pvData::PVStructure> const & pvstruct); + Record (std::string const & name, std::shared_ptr const & pvstruct) + : epics::pvDatabase::PVRecord(name, pvstruct) { __pv = pvstruct; }; + virtual void process (void); +}; + +std::shared_ptr Record::create (std::string const & name, std::shared_ptr<::epics::pvData::PVStructure> const & pvstruct) +{ + std::shared_ptr pvrecord (new Record (name, pvstruct)); + // Need to be explicitly called .. not part of the base constructor + if(!pvrecord->init()) pvrecord.reset(); + return pvrecord; +} + +void Record::process (void) +{ + PVRecord::process(); + std::string name = this->getRecordName(); + std::cout << this->getRecordName() + << " process\n"; +} + +class MyMonitor +{ +private: + std::tr1::shared_ptr<::pvac::MonitorSync> monitor; + MyMonitor(std::tr1::shared_ptr<::pvac::ClientChannel> const &channel) + { + monitor = std::tr1::shared_ptr<::pvac::MonitorSync>(new ::pvac::MonitorSync(channel->monitor())); + } +public: + static std::tr1::shared_ptr create(std::tr1::shared_ptr<::pvac::ClientChannel> const &channel) + { + return std::tr1::shared_ptr(new MyMonitor(channel)); + } + void getData(); +}; + +void MyMonitor::getData() +{ + while (true) { + if(!monitor->wait(.001)) break; + switch(monitor->event.event) { + case pvac::MonitorEvent::Fail: + std::cerr<name()<<" : Error : "<event.message<<"\n"; + return; + case pvac::MonitorEvent::Cancel: + std::cout<name()<<" \n"; + return; + case pvac::MonitorEvent::Disconnect: + std::cout<name()<<" \n"; + return; + case pvac::MonitorEvent::Data: + while(monitor->poll()) { + std::cout<name()<<" : "<root; + } + if(monitor->complete()) { + return; + } + } + } +} + + +int main (int argc, char** argv) +{ + int verbose = 0; + unsigned loopctr = 0; + unsigned pausectr = 0; + bool allowExit = false; + bool callRecord = false; + bool callDatabase = false; + int opt; + while((opt = getopt(argc, argv, "v:ardh")) != -1) { + switch(opt) { + case 'v': + verbose = std::stoi(optarg); + break; + case 'a' : + allowExit = true; + break; + case 'r' : + callRecord = true; + break; + case 'd' : + callDatabase = true; + break; + case 'h': + std::cout << " -v level -a -r -d -h \n"; + std::cout << "-r call pvRecord->remove -d call master->removeRecord\n"; + std::cout << "default\n"; + std::cout << "-v " << verbose + << " -a false" + << " -d" + << "\n"; + return 0; + default: + std::cerr<<"Unknown argument: "< pvstruct + = ::epics::pvData::getPVDataCreate()->createPVStructure(builder->createStructure()); + std::shared_ptr pvrecord = Record::create(std::string(name), pvstruct); + master->addRecord(pvrecord); + pvrecord->setTraceLevel(verbose); + // Start PVA (local) client + std::tr1::shared_ptr<::pvac::ClientProvider> provider + = std::tr1::shared_ptr<::pvac::ClientProvider>(new ::pvac::ClientProvider ("pva")); + std::tr1::shared_ptr<::pvac::ClientChannel> channel + = std::tr1::shared_ptr<::pvac::ClientChannel>(new ::pvac::ClientChannel (provider->connect(name))); + std::tr1::shared_ptr mymonitor = MyMonitor::create(channel); + unsigned valuectr = loopctr; + std::cout << startset << loopctr << "\n"; + for (int ind=0; ind<100; ind++) { + channel->put().set("value",valuectr++).exec(); + mymonitor->getData(); + } + pausectr++; + if(allowExit && pausectr>10) { + pausectr = 0; + std::cout << "Type exit to stop: \n"; + int c = std::cin.peek(); // peek character + if ( c == EOF ) continue; + std::string str; + std::getline(std::cin,str); + if(str.compare("exit")==0) break; + } + if(callRecord) { +std::cout << "callRecord\n"; + pvrecord->remove(); + } + if(callDatabase) { +std::cout << "callDatabase\n"; + master->removeRecord(pvrecord); + } + } + return (0); +} diff --git a/src/database/pvDatabase.cpp b/src/database/pvDatabase.cpp index 1d3b1e0..a73a3fe 100644 --- a/src/database/pvDatabase.cpp +++ b/src/database/pvDatabase.cpp @@ -56,14 +56,6 @@ PVDatabase::PVDatabase() PVDatabase::~PVDatabase() { if(DEBUG_LEVEL>0) cout << "PVDatabase::~PVDatabase()\n"; - size_t len = recordMap.size(); - shared_vector names(len); - PVRecordMap::iterator iter; - size_t i = 0; - for(iter = recordMap.begin(); iter!=recordMap.end(); ++iter) { - names[i++] = (*iter).first; - } - for(size_t i=0; igetTraceLevel()>0) { - cout << "PVDatabase::removeRecord " << record->getRecordName() << endl; - } epicsGuard guard(mutex); string recordName = record->getRecordName(); PVRecordMap::iterator iter = recordMap.find(recordName); if(iter!=recordMap.end()) { PVRecordPtr pvRecord = (*iter).second; recordMap.erase(iter); + return pvRecord->shared_from_this(); + } + return PVRecordWPtr(); +} + +bool PVDatabase::removeRecord(PVRecordPtr const & record) +{ + if(record->getTraceLevel()>0) { + cout << "PVDatabase::removeRecord " << record->getRecordName() << endl; + } + epicsGuard guard(mutex); + PVRecordWPtr pvRecord = removeFromMap(record); + if(pvRecord.use_count()!=0) { + pvRecord.lock()->unlistenClients(); return true; } return false; diff --git a/src/database/pvRecord.cpp b/src/database/pvRecord.cpp index ec54b59..2701da4 100644 --- a/src/database/pvRecord.cpp +++ b/src/database/pvRecord.cpp @@ -58,64 +58,16 @@ PVRecord::PVRecord( { } -void PVRecord::notifyClients() -{ - { - epicsGuard guard(mutex); - if(traceLevel>0) { - cout << "PVRecord::notifyClients() " << recordName - << endl; - } - } - pvTimeStamp.detach(); - for(std::list::iterator iter = pvListenerList.begin(); - iter!=pvListenerList.end(); - iter++ ) - { - PVListenerPtr listener = iter->lock(); - if(!listener) continue; - if(traceLevel>0) { - cout << "PVRecord::notifyClients() calling listener->unlisten " - << recordName << endl; - } - listener->unlisten(shared_from_this()); - } - pvListenerList.clear(); - for (std::list::iterator iter = clientList.begin(); - iter!=clientList.end(); - iter++ ) - { - PVRecordClientPtr client = iter->lock(); - if(!client) continue; - if(traceLevel>0) { - cout << "PVRecord::notifyClients() calling client->detach " - << recordName << endl; - } - client->detach(shared_from_this()); - } - if(traceLevel>0) { - cout << "PVRecord::notifyClients() calling clientList.clear() " - << recordName << endl; - } - clientList.clear(); - if(traceLevel>0) { - cout << "PVRecord::notifyClients() returning " << recordName << endl; - } -} - PVRecord::~PVRecord() { if(traceLevel>0) { cout << "~PVRecord() " << recordName << endl; } - notifyClients(); } -void PVRecord::remove() +void PVRecord::unlistenClients() { - PVDatabasePtr pvDatabase(PVDatabase::getMaster()); - if(pvDatabase) pvDatabase->removeRecord(shared_from_this()); - pvTimeStamp.detach(); + epicsGuard guard(mutex); for(std::list::iterator iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) @@ -142,6 +94,19 @@ void PVRecord::remove() clientList.clear(); } + +void PVRecord::remove() +{ + if(traceLevel>0) { + cout << "PVRecord::remove() " << recordName << endl; + } + unlistenClients(); + epicsGuard guard(mutex); + PVDatabasePtr pvDatabase(PVDatabase::getMaster()); + if(pvDatabase) pvDatabase->removeFromMap(shared_from_this()); + pvTimeStamp.detach(); +} + void PVRecord::initPVRecord() { PVRecordStructurePtr parent; diff --git a/src/pv/pvDatabase.h b/src/pv/pvDatabase.h index 09e6be9..a445dc2 100644 --- a/src/pv/pvDatabase.h +++ b/src/pv/pvDatabase.h @@ -101,7 +101,7 @@ public: virtual void remove(); /** * @brief Optional method for derived class. - * + * * Return a service corresponding to the specified request PVStructure. * @param pvRequest The request PVStructure * @return The corresponding service @@ -252,10 +252,12 @@ protected: */ void initPVRecord(); private: + friend class PVDatabase; + void unlistenClients(); + PVRecordFieldPtr findPVRecordField( PVRecordStructurePtr const & pvrs, epics::pvData::PVFieldPtr const & pvField); - void notifyClients(); std::string recordName; epics::pvData::PVStructurePtr pvStructure; @@ -499,6 +501,7 @@ public: /** * @brief Remove a record. * @param record The record to remove. + * * @return true if record was removed. */ bool removeRecord(PVRecordPtr const & record); @@ -508,6 +511,9 @@ public: */ epics::pvData::PVStringArrayPtr getRecordNames(); private: + friend class PVRecord; + + PVRecordWPtr removeFromMap(PVRecordPtr const & record); PVDatabase(); void lock(); void unlock(); diff --git a/src/pvAccess/channelLocal.cpp b/src/pvAccess/channelLocal.cpp index 3f57471..90d9aab 100644 --- a/src/pvAccess/channelLocal.cpp +++ b/src/pvAccess/channelLocal.cpp @@ -156,10 +156,7 @@ ChannelProcessLocalPtr ChannelProcessLocal::create( ChannelProcessLocal::~ChannelProcessLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(pvr && pvr->getTraceLevel()>0) { - cout << "~ChannelProcessLocal() " << pvr->getRecordName() << endl; - } +//cout << "~ChannelProcessLocal()\n"; } std::tr1::shared_ptr ChannelProcessLocal::getChannel() @@ -304,10 +301,7 @@ ChannelGetLocalPtr ChannelGetLocal::create( ChannelGetLocal::~ChannelGetLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(pvr && pvr->getTraceLevel()>0) { - cout << "~ChannelGetLocal() " << pvr->getRecordName() << endl; - } +//cout << "~ChannelGetLocal()\n"; } std::tr1::shared_ptr ChannelGetLocal::getChannel() @@ -469,10 +463,7 @@ ChannelPutLocalPtr ChannelPutLocal::create( ChannelPutLocal::~ChannelPutLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(pvr && pvr->getTraceLevel()>0) { - cout << "~ChannelPutLocal() " << pvr->getRecordName() << endl; - } +//cout << "~ChannelPutLocal()\n"; } std::tr1::shared_ptr ChannelPutLocal::getChannel() @@ -662,10 +653,7 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create( ChannelPutGetLocal::~ChannelPutGetLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(pvr && pvr->getTraceLevel()>0) { - cout << "~ChannelPutGetLocal() " << pvr->getRecordName() << endl; - } +//cout << "~ChannelPutGetLocal()\n"; } std::tr1::shared_ptr ChannelPutGetLocal::getChannel() @@ -862,10 +850,7 @@ ChannelRPCLocalPtr ChannelRPCLocal::create( ChannelRPCLocal::~ChannelRPCLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(pvr && pvr->getTraceLevel()>0) { - cout << "~ChannelRPCLocal() " << pvr->getRecordName() << endl; - } +//cout << "~ChannelRPCLocal()\n"; } std::tr1::shared_ptr ChannelRPCLocal::getChannel() @@ -1104,10 +1089,7 @@ ChannelArrayLocalPtr ChannelArrayLocal::create( ChannelArrayLocal::~ChannelArrayLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(pvr && pvr->getTraceLevel()>0) { - cout << "~ChannelArrayLocal() " << pvr->getRecordName() << endl; - } +//cout << "~ChannelArrayLocal()\n"; } std::tr1::shared_ptr ChannelArrayLocal::getChannel() @@ -1261,12 +1243,7 @@ ChannelLocal::ChannelLocal( ChannelLocal::~ChannelLocal() { - PVRecordPtr pvr(pvRecord.lock()); - if(!pvr) return; - if(pvr->getTraceLevel()>0) - { - cout << "~ChannelLocal()" << endl; - } +// cout << "~ChannelLocal()" << endl; } ChannelProvider::shared_pointer ChannelLocal::getProvider() diff --git a/src/pvAccess/monitorFactory.cpp b/src/pvAccess/monitorFactory.cpp index 6b300a9..ed3d368 100644 --- a/src/pvAccess/monitorFactory.cpp +++ b/src/pvAccess/monitorFactory.cpp @@ -191,10 +191,7 @@ MonitorLocal::MonitorLocal( MonitorLocal::~MonitorLocal() { - if(pvRecord->getTraceLevel()>0) - { - cout << "MonitorLocal::~MonitorLocal()" << endl; - } +//cout << "MonitorLocal::~MonitorLocal()" << endl; } diff --git a/src/support/controlSupport.cpp b/src/support/controlSupport.cpp index a45d0f2..96cbf94 100644 --- a/src/support/controlSupport.cpp +++ b/src/support/controlSupport.cpp @@ -29,7 +29,7 @@ namespace epics { namespace pvDatabase { ControlSupport::~ControlSupport() { -cout << "ControlSupport::~ControlSupport()\n"; +//cout << "ControlSupport::~ControlSupport()\n"; } epics::pvData::StructureConstPtr ControlSupport::controlField(ScalarType scalarType) diff --git a/src/support/scalarAlarmSupport.cpp b/src/support/scalarAlarmSupport.cpp index 3505c1d..7045787 100644 --- a/src/support/scalarAlarmSupport.cpp +++ b/src/support/scalarAlarmSupport.cpp @@ -30,7 +30,7 @@ namespace epics { namespace pvDatabase { ScalarAlarmSupport::~ScalarAlarmSupport() { -cout << "ScalarAlarmSupport::~ScalarAlarmSupport()\n"; +//cout << "ScalarAlarmSupport::~ScalarAlarmSupport()\n"; }