From 785d6541295d1270e3be84e9271976655f1affdd Mon Sep 17 00:00:00 2001 From: mrkraimer Date: Fri, 7 Feb 2020 08:54:18 -0500 Subject: [PATCH 1/5] first attempt to fix issue 53; add example --- examples/createdestroy | 1 + src/database/pvRecord.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 160000 examples/createdestroy diff --git a/examples/createdestroy b/examples/createdestroy new file mode 160000 index 0000000..b64329f --- /dev/null +++ b/examples/createdestroy @@ -0,0 +1 @@ +Subproject commit b64329f789953dd7921d2426da3947950ccd6287 diff --git a/src/database/pvRecord.cpp b/src/database/pvRecord.cpp index ec54b59..41f7c2f 100644 --- a/src/database/pvRecord.cpp +++ b/src/database/pvRecord.cpp @@ -108,12 +108,13 @@ PVRecord::~PVRecord() if(traceLevel>0) { cout << "~PVRecord() " << recordName << endl; } - notifyClients(); +// notifyClients(); } void PVRecord::remove() { PVDatabasePtr pvDatabase(PVDatabase::getMaster()); + notifyClients(); if(pvDatabase) pvDatabase->removeRecord(shared_from_this()); pvTimeStamp.detach(); for(std::list::iterator iter = pvListenerList.begin(); From 3173e9aeae7134d9452c555b2bacff343590bdee Mon Sep 17 00:00:00 2001 From: mrkraimer Date: Fri, 7 Feb 2020 09:17:08 -0500 Subject: [PATCH 2/5] problems with examples --- examples/createdestroy | 1 - 1 file changed, 1 deletion(-) delete mode 160000 examples/createdestroy diff --git a/examples/createdestroy b/examples/createdestroy deleted file mode 160000 index b64329f..0000000 --- a/examples/createdestroy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b64329f789953dd7921d2426da3947950ccd6287 From 42ba054e5f674bd2cdf1a9f7392a7d47fab529ef Mon Sep 17 00:00:00 2001 From: mrkraimer Date: Fri, 7 Feb 2020 10:58:55 -0500 Subject: [PATCH 3/5] add createdestroy example --- example/createdestroy/Makefile | 25 +++++++ example/createdestroy/createdestroy.cpp | 94 +++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100755 example/createdestroy/Makefile create mode 100644 example/createdestroy/createdestroy.cpp 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/createdestroy.cpp b/example/createdestroy/createdestroy.cpp new file mode 100644 index 0000000..4d546c2 --- /dev/null +++ b/example/createdestroy/createdestroy.cpp @@ -0,0 +1,94 @@ +/****************************************************************************** +* This is modeled after a test program created by Bertrand Bauvir from the ITER Organization +******************************************************************************/ + + +#include +#include +#include +#include +#include + +// Local header files + +// Constants + +#define DEFAULT_RECORD_NAME "examplechannel" + +using std::tr1::static_pointer_cast; + +// Type definition + +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() + << this->getPVStructure() + << "\n"; +} + + +int main (int argc, char** argv) +{ + bool verbose = false; + unsigned loopctr = 0; + + // Create PVA context + ::epics::pvDatabase::PVDatabasePtr master = epics::pvDatabase::PVDatabase::getMaster(); + ::epics::pvDatabase::ChannelProviderLocalPtr channelProvider = epics::pvDatabase::getChannelProviderLocal(); + + // Start PVA server + epics::pvAccess::ServerContext::shared_pointer context = epics::pvAccess::startPVAServer(epics::pvAccess::PVACCESS_ALL_PROVIDERS, 0, true, true); + + + while (true) { + loopctr++; + std::string name = DEFAULT_RECORD_NAME + std::to_string(loopctr); + + // Create record + // Create record structure + ::epics::pvData::FieldBuilderPtr builder = epics::pvData::getFieldCreate()->createFieldBuilder(); + builder->add("value", ::epics::pvData::pvULong); + 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); + // 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()); + unsigned valuectr = loopctr; + for (int ind=0; ind<10; ind++) channel->put().set("value",valuectr++).exec(); + master->removeRecord(pvrecord); + } + return (0); +} From 083dffac3c2ed5e990c9e517e9c0706cf2cd4e17 Mon Sep 17 00:00:00 2001 From: mrkraimer Date: Mon, 10 Feb 2020 06:15:59 -0500 Subject: [PATCH 4/5] pvDatabase::removeRecord and pvRecord::remove changes;descructors now have at most a print statement --- example/createdestroy/README.md | 20 ++++ example/createdestroy/createdestroy.cpp | 121 +++++++++++++++++++----- src/database/pvDatabase.cpp | 11 +-- src/database/pvRecord.cpp | 59 ++---------- src/pv/pvDatabase.h | 11 ++- src/pvAccess/channelLocal.cpp | 37 ++------ src/pvAccess/monitorFactory.cpp | 5 +- src/support/controlSupport.cpp | 2 +- src/support/scalarAlarmSupport.cpp | 2 +- 9 files changed, 143 insertions(+), 125 deletions(-) create mode 100644 example/createdestroy/README.md 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"; } From 75c16bd4232c27710c93daaad3576d947a17187f Mon Sep 17 00:00:00 2001 From: mrkraimer Date: Wed, 12 Feb 2020 09:13:19 -0500 Subject: [PATCH 5/5] pvDatabase::removeRecord and pvRecord::remove no longer call eachother directly --- example/createdestroy/createdestroy.cpp | 60 ++++++++++++++++--------- src/database/pvDatabase.cpp | 20 ++++++--- src/database/pvRecord.cpp | 25 ++++++----- src/pv/pvDatabase.h | 15 ++++--- 4 files changed, 77 insertions(+), 43 deletions(-) diff --git a/example/createdestroy/createdestroy.cpp b/example/createdestroy/createdestroy.cpp index c4f47be..c432f34 100644 --- a/example/createdestroy/createdestroy.cpp +++ b/example/createdestroy/createdestroy.cpp @@ -93,28 +93,38 @@ int main (int argc, char** argv) 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"; + 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: "< mymonitor = MyMonitor::create(channel); unsigned valuectr = loopctr; std::cout << startset << loopctr << "\n"; - for (int ind=0; ind<10; ind++) { + for (int ind=0; ind<100; ind++) { channel->put().set("value",valuectr++).exec(); mymonitor->getData(); } pausectr++; - if(allowExit && pausectr>500) { + if(allowExit && pausectr>10) { pausectr = 0; std::cout << "Type exit to stop: \n"; int c = std::cin.peek(); // peek character @@ -156,8 +166,14 @@ int main (int argc, char** argv) std::getline(std::cin,str); if(str.compare("exit")==0) break; } - pvrecord->remove(); -// master->removeRecord(pvrecord); + 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 a74119c..a73a3fe 100644 --- a/src/database/pvDatabase.cpp +++ b/src/database/pvDatabase.cpp @@ -92,18 +92,28 @@ bool PVDatabase::addRecord(PVRecordPtr const & record) return true; } -bool PVDatabase::removeRecord(PVRecordPtr const & record,bool callRemove) +PVRecordWPtr PVDatabase::removeFromMap(PVRecordPtr const & record) { - if(record->getTraceLevel()>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; - if(callRemove) pvRecord->remove(false); 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 ba08eb0..2701da4 100644 --- a/src/database/pvRecord.cpp +++ b/src/database/pvRecord.cpp @@ -65,17 +65,9 @@ PVRecord::~PVRecord() } } -void PVRecord::remove(bool callpvDatabaseRemoveRecord) +void PVRecord::unlistenClients() { - 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(); + epicsGuard guard(mutex); for(std::list::iterator iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) @@ -102,6 +94,19 @@ void PVRecord::remove(bool callpvDatabaseRemoveRecord) 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 4b6ba28..a445dc2 100644 --- a/src/pv/pvDatabase.h +++ b/src/pv/pvDatabase.h @@ -97,10 +97,8 @@ 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(bool callpvDatabaseRemoveRecord = true); + virtual void remove(); /** * @brief Optional method for derived class. * @@ -254,6 +252,9 @@ protected: */ void initPVRecord(); private: + friend class PVDatabase; + void unlistenClients(); + PVRecordFieldPtr findPVRecordField( PVRecordStructurePtr const & pvrs, epics::pvData::PVFieldPtr const & pvField); @@ -500,17 +501,19 @@ 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 callRemove = true); + bool removeRecord(PVRecordPtr const & record); /** * @brief Get the names of all the records in the database. * @return The names. */ epics::pvData::PVStringArrayPtr getRecordNames(); private: + friend class PVRecord; + + PVRecordWPtr removeFromMap(PVRecordPtr const & record); PVDatabase(); void lock(); void unlock();