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 index 4d546c2..c4f47be 100644 --- a/example/createdestroy/createdestroy.cpp +++ b/example/createdestroy/createdestroy.cpp @@ -1,13 +1,15 @@ /****************************************************************************** * 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 @@ -17,12 +19,9 @@ using std::tr1::static_pointer_cast; -// Type definition - class Record : public ::epics::pvDatabase::PVRecord { - - public: +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) @@ -32,14 +31,10 @@ class Record : public ::epics::pvDatabase::PVRecord 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) @@ -47,24 +42,85 @@ void Record::process (void) PVRecord::process(); std::string name = this->getRecordName(); std::cout << this->getRecordName() - << this->getPVStructure() - << "\n"; + << " 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) { - bool verbose = false; + int verbose = 0; unsigned loopctr = 0; + unsigned pausectr = 0; + bool allowExit = false; + int opt; + while((opt = getopt(argc, argv, "v:ah")) != -1) { + switch(opt) { + case 'v': + verbose = std::stoi(optarg); + break; + case 'a' : + allowExit = true; + break; + case 'h': + std::cout << " -v level -a -h \n"; + std::cout << "default\n"; + std::cout << "-v " << verbose + << " -a false" + << "\n"; + return 0; + default: + std::cerr<<"Unknown argument: "< pvstruct = ::epics::pvData::getPVDataCreate()->createPVStructure(builder->createStructure()); + std::shared_ptr<::epics::pvData::PVStructure> pvstruct + = ::epics::pvData::getPVDataCreate()->createPVStructure(builder->createStructure()); std::shared_ptr pvrecord = Record::create(std::string(name), pvstruct); master->addRecord(pvrecord); - if (verbose) pvrecord->setTraceLevel(3); + 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))); - builder = epics::pvData::getFieldCreate()->createFieldBuilder(); - builder->add("value", ::epics::pvData::pvULong); - std::shared_ptr<::epics::pvData::PVStructure> c_pvstruct = - ::epics::pvData::getPVDataCreate()->createPVStructure(builder->createStructure()); + std::tr1::shared_ptr mymonitor = MyMonitor::create(channel); unsigned valuectr = loopctr; - for (int ind=0; ind<10; ind++) channel->put().set("value",valuectr++).exec(); - master->removeRecord(pvrecord); + std::cout << startset << loopctr << "\n"; + for (int ind=0; ind<10; ind++) { + channel->put().set("value",valuectr++).exec(); + mymonitor->getData(); + } + pausectr++; + if(allowExit && pausectr>500) { + 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; + } + pvrecord->remove(); +// master->removeRecord(pvrecord); } return (0); } diff --git a/src/database/pvDatabase.cpp b/src/database/pvDatabase.cpp index 1d3b1e0..a74119c 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; @@ -110,6 +102,7 @@ bool PVDatabase::removeRecord(PVRecordPtr const & record) PVRecordMap::iterator iter = recordMap.find(recordName); if(iter!=recordMap.end()) { PVRecordPtr pvRecord = (*iter).second; + if(callRemove) pvRecord->remove(false); recordMap.erase(iter); return true; } diff --git a/src/database/pvRecord.cpp b/src/database/pvRecord.cpp index 41f7c2f..ba08eb0 100644 --- a/src/database/pvRecord.cpp +++ b/src/database/pvRecord.cpp @@ -58,64 +58,23 @@ 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::remove(bool callpvDatabaseRemoveRecord) { - PVDatabasePtr pvDatabase(PVDatabase::getMaster()); - notifyClients(); - if(pvDatabase) pvDatabase->removeRecord(shared_from_this()); + if(traceLevel>0) { + cout << "PVRecord::remove() " << recordName << endl; + } + epicsGuard guard(mutex); + if(callpvDatabaseRemoveRecord) { + PVDatabasePtr pvDatabase(PVDatabase::getMaster()); + if(pvDatabase) pvDatabase->removeRecord(shared_from_this(),false); + } pvTimeStamp.detach(); for(std::list::iterator iter = pvListenerList.begin(); iter!=pvListenerList.end(); diff --git a/src/pv/pvDatabase.h b/src/pv/pvDatabase.h index 09e6be9..4b6ba28 100644 --- a/src/pv/pvDatabase.h +++ b/src/pv/pvDatabase.h @@ -97,11 +97,13 @@ public: * get rid of listeners and requesters. * If derived class overrides this then it must call PVRecord::remove() * after it has destroyed any resorces it uses. + * @param callpvDatabaseRemoveRecord Should pvDatabase.removeRecord be called. + * Normally this is only set false by PVDatabase::removeRecord. */ - virtual void remove(); + virtual void remove(bool callpvDatabaseRemoveRecord = true); /** * @brief Optional method for derived class. - * + * * Return a service corresponding to the specified request PVStructure. * @param pvRequest The request PVStructure * @return The corresponding service @@ -255,7 +257,6 @@ private: PVRecordFieldPtr findPVRecordField( PVRecordStructurePtr const & pvrs, epics::pvData::PVFieldPtr const & pvField); - void notifyClients(); std::string recordName; epics::pvData::PVStructurePtr pvStructure; @@ -499,9 +500,11 @@ public: /** * @brief Remove a record. * @param record The record to remove. + * @param callRemove Call pvRecord->remove() + * Normally this is only set false by pvRecord.remove() * @return true if record was removed. */ - bool removeRecord(PVRecordPtr const & record); + bool removeRecord(PVRecordPtr const & record,bool callRemove = true); /** * @brief Get the names of all the records in the database. * @return The names. diff --git a/src/pvAccess/channelLocal.cpp b/src/pvAccess/channelLocal.cpp index 80d1eaa..c81251a 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"; }