add removeRecord; more work on termination issues

This commit is contained in:
mrkraimer
2016-06-15 07:21:43 -04:00
parent e025e542ea
commit fde7953de0
10 changed files with 338 additions and 44 deletions

View File

@ -36,7 +36,7 @@
<div class="head">
<h1>pvDatabaseCPP</h1>
<h2 class="nocount">Release 4.2 - 2016.01.12</h2>
<h2 class="nocount">Release 4.2-SNAPSHOT - 2016.06.02</h2>
<h2 class="nocount">Abstract</h2>
@ -370,6 +370,7 @@ public:
void detachClients();
bool addListener(PVListenerPtr const &amp; pvListener);
bool removeListener(PVListenerPtr const &amp; pvListener);
ServicePtr getService(PVStructurePtr const &amp; pvRequest)
void beginGroupPut();
void endGroupPut();
int getTraceLevel();
@ -404,31 +405,44 @@ private:
<dt>process</dt>
<dd>Virtual method.
Derived classes usually implement this method.
It implements the semantics for the record.
The base implementation does nothing.
It implements the semantics for the record.
<br />
If a top level timeStamp exists the base class set it equal
to the current time.
</dd>
<dt>destroy</dt>
<dd>Virtual method.
Optional method for derived class.
If the derived class implements this it
must call the base class destroy method after it
has released any resources it uses.</dd>
<dd>
Destroy the PVRecord and any context.
<br />
Release any resources used and get rid of listeners and requesters.
If derived class overrides this then it must call this base class destroy()
after it has destroyed any resorces it uses.
<br />
It can be called for several reasons.
Some examples are:
<ul>
<li>By pvDatabase when it is destroyed.</li>
<li>By other code that wants to destroy the record</li>
</ul>
</dd>
<dt>create</dt>
<dd>Static method to create dumb records,
i.e. records with a process method that does nothing.
<dd>Static method to create a soft record.
A soft record implements process by setting an optional top level timeStamp
to the current time.
<br />
A derived class should have it's own static create method.
</dd>
<dt>~PVRecord</dt>
<dd>The destructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dd>
This calls destroy.
</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
<dd>Get the top level PVStructure.</dd>
<dt>findPVRecordField</dt>
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
<dt>lock</dt>
<dt>unlock</dt>
<dt>lock and unlock</dt>
<dd>Lock and Unlock the record.
Any code accessing the data in the record or calling other PVRecord methods
must have the record locked.</dd>
@ -444,15 +458,35 @@ private:
more then one record.
</dd>
<dt>addPVRecordClient</dt>
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
<dd>
Every client that accesses the record must call this so that
the client can be notified when the record is deleted.
</dd>
<dt>removePVRecordClient</dt>
<dd>Client is no longer accessing the record.</dd>
<dd>
Client is no longer accessing the record.
</dd>
<dt>detachClients</dt>
<dd>Ask all clients to detach from the record</dd>
<dd>
Ask all clients to detach from the record
</dd>
<dt>addListener</dt>
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
<dd>
Add a PVListener.
This must be called before calling pvRecordField.addListener.
</dd>
<dt>removeListener</dt>
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
<dd>
Removes a listener.
The listener will also be removed from all fields to which it is attached.
</dd>
<dt>getService</dt>
<dd>
Virtual method.
A derived class implements this method if it supports channelRPC.
It implements the semantics for the channelRPC.
The base class returns null.
</dd>
<dt>beginGroupPut</dt>
<dd>Begin a group of puts.
This results in all registered PVListeners being called</dd>
@ -496,7 +530,7 @@ public:
POINTER_DEFINITIONS(PVRecordField);
PVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField,
PVRecordStructurePtr const &amp;parent,
PVRecordStructurePtr const &amp; parent,
PVRecordPtr const &amp; pvRecord);
virtual ~PVRecordField();
virtual void destroy();
@ -615,8 +649,8 @@ public:
virtual ~PVListener();
virtual void dataPut(PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
PVRecordStructurePtr const &amp; requested,
PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void unlisten(PVRecordPtr const &amp; pvRecord);
@ -633,8 +667,8 @@ public:
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
Requested is the field to which the requester issued a pvField-&amp;addListener.
This is called if the listener has called PVRecordField-&amp;addListener for requested.</dd>
Requested is the field to which the requester issued a pvField-&gt;addListener.
This is called if the listener has called PVRecordField-&gt;addListener for requested.</dd>
<dt>beginGroupPut</dt>
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
@ -651,7 +685,7 @@ public:
static PVDatabasePtr getMaster();
virtual ~PVDatabase();
virtual void destroy();
PVRecordPtr findRecord(std::string const&amp; recordName);
PVRecordPtr findRecord(std::string const &amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
epics::pvData::PVStringArrayPtr getRecordNames();
bool removeRecord(PVRecordPtr const &amp; record);
@ -664,10 +698,14 @@ private:
<dt>getMaster</dt>
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
<dt>~PVDatabase</dt>
<dd>The destructor.</dd>
<dd>
The destructor.
</dd>
<dt>destroy</dt>
<dd>This is called by remote channelAccess when process exits.
This destroys and removes all records in the PVDatabase.</dd>
<dd>
This is called by remote channelAccess when process exits.
This destroys and removes all records in the PVDatabase.
</dd>
<dt>findRecord</dt>
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
<dt>addRecord</dt>

View File

@ -8,9 +8,13 @@ PVDATABASE_SRC = $(TOP)/src
LIBRARY += pvDatabase
# shared library ABI version.
SHRLIB_VERSION ?= 4.2-DEV
INC += pv/channelProviderLocal.h
INC += pv/pvDatabase.h
INC += pv/traceRecord.h
INC += pv/removeRecord.h
include $(PVDATABASE_SRC)/database/Makefile
include $(PVDATABASE_SRC)/pvAccess/Makefile
@ -20,8 +24,6 @@ include $(PVDATABASE_SRC)/special/Makefile
pvDatabase_LIBS += pvAccess pvData Com
pvDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
# shared library ABI version.
SHRLIB_VERSION ?= 4.2
include $(TOP)/configure/RULES

View File

@ -82,6 +82,9 @@ void PVRecord::destroy()
{
PVRecordClientPtr client = iter->lock();
if(client) {
if(traceLevel>1) {
cout << "PVRecord::destroy() calling client->detach " << recordName << endl;
}
epicsGuardRelease<epics::pvData::Mutex> unguard(guard);
client->detach(shared_from_this());
}
@ -92,10 +95,15 @@ void PVRecord::destroy()
{
PVListenerPtr listener = iter->lock();
if(listener) {
if(traceLevel>1) {
cout << "PVRecord::destroy() calling listener->unlisten " << recordName << endl;
}
epicsGuardRelease<epics::pvData::Mutex> unguard(guard);
listener->unlisten(shared_from_this());
}
}
PVDatabasePtr pvDatabase(PVDatabase::getMaster());
if(pvDatabase) pvDatabase->removeRecord(shared_from_this());
}
void PVRecord::process()
@ -232,7 +240,7 @@ bool PVRecord::removePVRecordClient(PVRecordClientPtr const & pvRecordClient)
void PVRecord::detachClients()
{
if(traceLevel>1) {
cout << "PVRecord::removePVRecordClient() " << recordName << endl;
cout << "PVRecord::detachClients() " << recordName << endl;
}
epicsGuard<epics::pvData::Mutex> guard(mutex);
if(isDestroyed) {
@ -244,8 +252,11 @@ void PVRecord::detachClients()
iter++ )
{
PVRecordClientPtr client = iter->lock();
if(!client.get()) continue;
if(!client) continue;
epicsGuardRelease <epics::pvData::Mutex> unguard(guard);
if(traceLevel>1) {
cout << "PVRecord::detachClients() calling client->detach " << recordName << endl;
}
client->detach(shared_from_this());
}
pvRecordClientList.clear();

View File

@ -393,8 +393,8 @@ protected:
return shared_from_this();
}
private:
ChannelProviderLocalPtr provider;
epics::pvAccess::ChannelRequester::weak_pointer requester;
ChannelProviderLocalPtr provider;
PVRecordPtr pvRecord;
bool beingDestroyed;
epics::pvData::Mutex mutex;

View File

@ -483,6 +483,7 @@ public:
virtual ~PVDatabase();
/**
* Destroy the PVDatabase.
* For each record in the database the record is removed and it's destroy method is called.
*/
virtual void destroy();
/**

73
src/pv/removeRecord.h Normal file
View File

@ -0,0 +1,73 @@
/* removeRecord.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#ifndef REMOVERECORD_H
#define REMOVERECORD_H
#include <shareLib.h>
#include <pv/channelProviderLocal.h>
namespace epics { namespace pvDatabase {
class RemoveRecord;
typedef std::tr1::shared_ptr<RemoveRecord> RemoveRecordPtr;
/**
* @brief Remove another record in the same database.
*
* A record to remove another record
* It is meant to be used via a channelPutGet request.
* The argument has one field: recordName.
* The result has a field named status.
*/
class epicsShareClass RemoveRecord :
public PVRecord
{
public:
POINTER_DEFINITIONS(RemoveRecord);
/**
* Factory methods to create RemoveRecord.
* @param recordName The name for the RemoveRecord.
* @return A shared pointer to RemoveRecord..
*/
static RemoveRecordPtr create(
std::string const & recordName);
/**
* destructor
*/
virtual ~RemoveRecord();
/**
* Clean up any resources used.
*/
virtual void destroy();
/**
* standard init method required by PVRecord
* @return true unless record name already exists.
*/
virtual bool init();
/**
* Set the trace level.
*/
virtual void process();
private:
RemoveRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure);
PVDatabasePtr pvDatabase;
epics::pvData::PVStringPtr pvRecordName;
epics::pvData::PVStringPtr pvResult;
bool isDestroyed;
};
}}
#endif /* REMOVERECORD_H */

View File

@ -187,7 +187,6 @@ void ChannelProcessLocal::destroy()
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
@ -336,7 +335,6 @@ void ChannelGetLocal::destroy()
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
void ChannelGetLocal::get()
@ -488,7 +486,6 @@ void ChannelPutLocal::destroy()
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
void ChannelPutLocal::get()
@ -683,7 +680,6 @@ void ChannelPutGetLocal::destroy()
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
void ChannelPutGetLocal::putGet(
@ -1164,7 +1160,6 @@ void ChannelArrayLocal::destroy()
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
void ChannelArrayLocal::getArray(size_t offset, size_t count, size_t stride)
@ -1310,11 +1305,18 @@ ChannelLocal::ChannelLocal(
ChannelProviderLocalPtr const & provider,
ChannelRequester::shared_pointer const & requester,
PVRecordPtr const & pvRecord)
: provider(provider),
:
requester(requester),
provider(provider),
pvRecord(pvRecord),
beingDestroyed(false)
{
if(pvRecord->getTraceLevel()>0) {
cout << "ChannelLocal::ChannelLocal()"
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
}
ChannelLocal::~ChannelLocal()
@ -1327,22 +1329,31 @@ ChannelLocal::~ChannelLocal()
void ChannelLocal::destroy()
{
ChannelRequester::shared_pointer requester(this->requester.lock());
if(pvRecord->getTraceLevel()>0) {
cout << "ChannelLocal::destroy() ";
cout << "beingDestroyed " << beingDestroyed << endl;
cout << "ChannelLocal::destroy()"
<< " recordName " << pvRecord->getRecordName()
<< " beingDestroyed " << beingDestroyed
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
{
Lock xx(mutex);
if(beingDestroyed) return;
beingDestroyed = true;
}
message("being destroyed",fatalErrorMessage);
pvRecord->removePVRecordClient(getPtrSelf());
}
void ChannelLocal::detach(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>0) {
cout << "ChannelLocal::detach() " << endl;
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::detach() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
destroy();
}
@ -1351,6 +1362,13 @@ void ChannelLocal::detach(PVRecordPtr const & pvRecord)
string ChannelLocal::getRequesterName()
{
ChannelRequester::shared_pointer req = requester.lock();
if(pvRecord->getTraceLevel()>1) {
cout << "ChannelLocal::getRequesterName() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (req ? "true" : "false")
<< endl;
}
if(!req) return string();
return req->getRequesterName();
}
@ -1360,8 +1378,20 @@ void ChannelLocal::message(
MessageType messageType)
{
ChannelRequester::shared_pointer req = requester.lock();
if(!req) return;
req->message(message,messageType);
if(pvRecord->getTraceLevel()>1) {
cout << "ChannelLocal::message() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (req ? "true" : "false")
<< endl;
}
if(req) {
req->message(message,messageType);
return;
}
cout << pvRecord->getRecordName()
<< " message " << message
<< " messageType " << getMessageTypeName(messageType)
<< endl;
}
string ChannelLocal::getRemoteAddress()
@ -1423,6 +1453,13 @@ ChannelProcess::shared_pointer ChannelLocal::createChannelProcess(
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
PVStructure::shared_pointer const & pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createChannelProcess() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
ChannelProcessLocalPtr channelProcess =
ChannelProcessLocal::create(
getPtrSelf(),
@ -1436,6 +1473,13 @@ ChannelGet::shared_pointer ChannelLocal::createChannelGet(
ChannelGetRequester::shared_pointer const &channelGetRequester,
PVStructure::shared_pointer const &pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createChannelGet() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
ChannelGetLocalPtr channelGet =
ChannelGetLocal::create(
getPtrSelf(),
@ -1449,6 +1493,14 @@ ChannelPut::shared_pointer ChannelLocal::createChannelPut(
ChannelPutRequester::shared_pointer const &channelPutRequester,
PVStructure::shared_pointer const &pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createChannelPut() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
ChannelPutLocalPtr channelPut =
ChannelPutLocal::create(
getPtrSelf(),
@ -1462,6 +1514,14 @@ ChannelPutGet::shared_pointer ChannelLocal::createChannelPutGet(
ChannelPutGetRequester::shared_pointer const &channelPutGetRequester,
PVStructure::shared_pointer const &pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createChannelPutGet() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
ChannelPutGetLocalPtr channelPutGet =
ChannelPutGetLocal::create(
getPtrSelf(),
@ -1475,6 +1535,14 @@ ChannelRPC::shared_pointer ChannelLocal::createChannelRPC(
ChannelRPCRequester::shared_pointer const & channelRPCRequester,
PVStructure::shared_pointer const & pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createChannelRPC() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
ChannelRPCLocalPtr channelRPC =
ChannelRPCLocal::create(
getPtrSelf(),
@ -1488,6 +1556,14 @@ Monitor::shared_pointer ChannelLocal::createMonitor(
MonitorRequester::shared_pointer const &monitorRequester,
PVStructure::shared_pointer const &pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createMonitor() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
MonitorPtr monitor =
getMonitorFactory()->createMonitor(
pvRecord,
@ -1500,6 +1576,13 @@ ChannelArray::shared_pointer ChannelLocal::createChannelArray(
ChannelArrayRequester::shared_pointer const &channelArrayRequester,
PVStructure::shared_pointer const &pvRequest)
{
if(pvRecord->getTraceLevel()>0) {
ChannelRequester::shared_pointer requester(this->requester.lock());
cout << "ChannelLocal::createChannelArray() "
<< " recordName " << pvRecord->getRecordName()
<< " requester exists " << (requester ? "true" : "false")
<< endl;
}
ChannelArrayLocalPtr channelArray =
ChannelArrayLocal::create(
getPtrSelf(),

View File

@ -3,3 +3,4 @@
SRC_DIRS += $(PVDATABASE_SRC)/special
LIBSRCS += traceRecord.cpp
LIBSRCS += removeRecord.cpp

View File

@ -0,0 +1,85 @@
/* removeRecord.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
* @date 2013.04.18
*/
#define epicsExportSharedSymbols
#include <pv/removeRecord.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace std;
namespace epics { namespace pvDatabase {
RemoveRecordPtr RemoveRecord::create(
std::string const & recordName)
{
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
addNestedStructure("argument")->
add("recordName",pvString)->
endNested()->
addNestedStructure("result") ->
add("status",pvString) ->
endNested()->
createStructure();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
RemoveRecordPtr pvRecord(
new RemoveRecord(recordName,pvStructure));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
RemoveRecord::RemoveRecord(
std::string const & recordName,
epics::pvData::PVStructurePtr const & pvStructure)
: PVRecord(recordName,pvStructure),
pvDatabase(PVDatabase::getMaster()),
isDestroyed(false)
{
}
RemoveRecord::~RemoveRecord()
{
}
void RemoveRecord::destroy()
{
PVRecord::destroy();
}
bool RemoveRecord::init()
{
initPVRecord();
PVStructurePtr pvStructure = getPVStructure();
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
if(!pvRecordName) return false;
pvResult = pvStructure->getSubField<PVString>("result.status");
if(!pvResult) return false;
return true;
}
void RemoveRecord::process()
{
string name = pvRecordName->get();
PVRecordPtr pvRecord = pvDatabase->findRecord(name);
if(!pvRecord) {
pvResult->put(name + " not found");
return;
}
pvRecord->destroy();
pvResult->put("success");
}
}}