simplify monitors; cleanup code; fix race condidition for monitor cleanup

This commit is contained in:
Marty Kraimer
2015-02-06 14:49:28 -05:00
parent e30e4f3638
commit 30dd2ed046
7 changed files with 262 additions and 674 deletions

View File

@ -21,8 +21,9 @@
#include <deque>
#include <pv/pvData.h>
#include <pv/pvCopy.h>
#include <pv/convert.h>
#include <pv/pvTimeStamp.h>
#ifdef pvdatabaseEpicsExportSharedSymbols
# define epicsExportSharedSymbols
@ -61,6 +62,7 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
* @author mrk
*/
class epicsShareClass PVRecord :
public epics::pvData::PVCopyTraverseMasterCallback,
public std::tr1::enable_shared_from_this<PVRecord>
{
public:
@ -84,7 +86,7 @@ public:
* If it encounters errors it should raise alarms and/or
* call the <b>message</b> method provided by the base class.
*/
virtual void process() {}
virtual void process();
/**
* Destroy the PVRecord. Release any resources used and
* get rid of listeners and requesters.
@ -168,15 +170,26 @@ public:
* Add a PVListener.
* This must be called before calling pvRecordField.addListener.
* @param pvListener The listener.
* @param pvCopy The pvStructure that has the client fields.
* @return <b>true</b> if the listener was added.
*/
bool addListener(PVListenerPtr const & pvListener);
bool addListener(
PVListenerPtr const & pvListener,
epics::pvData::PVCopyPtr const & pvCopy);
/*
* PVCopyTraverseMasterCallback method
* @param pvField The next client field.
*/
void nextMasterPVField(epics::pvData::PVFieldPtr const & pvField);
/**
* Remove a listener.
* @param pvListener The listener.
* @param pvCopy The pvStructure that has the client fields.
* @return <b>true</b> if the listener was removed.
*/
bool removeListener(PVListenerPtr const & pvListener);
bool removeListener(
PVListenerPtr const & pvListener,
epics::pvData::PVCopyPtr const & pvCopy);
/**
* Begins a group of puts.
*/
@ -221,6 +234,7 @@ private:
PVRecordFieldPtr findPVRecordField(
PVRecordStructurePtr const & pvrs,
epics::pvData::PVFieldPtr const & pvField);
std::string recordName;
epics::pvData::PVStructurePtr pvStructure;
epics::pvData::ConvertPtr convert;
@ -231,6 +245,13 @@ private:
std::size_t depthGroupPut;
int traceLevel;
bool isDestroyed;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
// following only valid while addListener or removeListener is active.
bool isAddListener;
PVListenerPtr pvListener;
};
epicsShareExtern std::ostream& operator<<(std::ostream& o, const PVRecord& record);
@ -289,21 +310,6 @@ public:
* @return The shared pointer,
*/
PVRecordPtr getPVRecord();
/**
* Add A PVListener to this field.
* Whenever this field or any subfield if this field is modified the listener will be notified.
* PVListener is described below.
* Before a listener can call addListener it must first call PVRecord.registerListener.
* @param pvListener The listener.
* @return <b<true</b> if listener is added.
*/
bool addListener(PVListenerPtr const & pvListener);
/**
* Remove a listener.
* @param pvListener The listener.
* @return <b<true</b> if listener is removed.
*/
virtual void removeListener(PVListenerPtr const & pvListener);
/**
* This is called by the code that implements the data interface.
* It is called whenever the put method is called.
@ -318,6 +324,8 @@ protected:
virtual void postParent(PVRecordFieldPtr const & subField);
virtual void postSubField();
private:
bool addListener(PVListenerPtr const & pvListener);
virtual void removeListener(PVListenerPtr const & pvListener);
void callListener();
std::list<PVListenerPtr> pvListenerList;
@ -368,11 +376,6 @@ public:
* @return The shared pointer.
*/
epics::pvData::PVStructurePtr getPVStructure();
/**
* Called by PVRecord::removeListener.
* @param pvListener The listener.
*/
virtual void removeListener(PVListenerPtr const & pvListener);
/**
* Called by implementation code of PVRecord.
*/
@ -383,6 +386,8 @@ protected:
*/
virtual void init();
private:
virtual void removeListener(PVListenerPtr const & pvListener);
epics::pvData::PVStructurePtr pvStructure;
PVRecordFieldPtrArrayPtr pvRecordFields;
friend class PVRecord;

View File

@ -42,7 +42,8 @@ PVRecord::PVRecord(
convert(getConvert()),
depthGroupPut(0),
traceLevel(0),
isDestroyed(false)
isDestroyed(false),
isAddListener(false)
{
}
@ -59,6 +60,8 @@ void PVRecord::initPVRecord()
pvRecordStructure = PVRecordStructurePtr(
new PVRecordStructure(pvStructure,parent,getPtrSelf()));
pvRecordStructure->init();
PVFieldPtr pvField = pvStructure->getSubField("timeStamp");
if(pvField) pvTimeStamp.attach(pvField);
}
void PVRecord::destroy()
@ -73,6 +76,7 @@ void PVRecord::destroy()
return;
}
isDestroyed = true;
pvTimeStamp.detach();
std::list<PVRecordClientPtr>::iterator clientIter;
while(true) {
@ -103,6 +107,17 @@ void PVRecord::destroy()
}
}
void PVRecord::process()
{
if(traceLevel>2) {
cout << "PVRecord::process() " << recordName << endl;
}
if(pvTimeStamp.isAttached()) {
timeStamp.getCurrent();
pvTimeStamp.set(timeStamp);
}
}
string PVRecord::getRecordName() const {return recordName;}
PVRecordStructurePtr PVRecord::getPVRecordStructure() const {return pvRecordStructure;}
@ -263,7 +278,9 @@ void PVRecord::detachClients()
}
}
bool PVRecord::addListener(PVListenerPtr const & pvListener)
bool PVRecord::addListener(
PVListenerPtr const & pvListener,
PVCopyPtr const & pvCopy)
{
if(traceLevel>1) {
cout << "PVRecord::addListener() " << recordName << endl;
@ -283,6 +300,10 @@ bool PVRecord::addListener(PVListenerPtr const & pvListener)
}
}
pvListenerList.push_back(pvListener);
this->pvListener = pvListener;
isAddListener = true;
pvCopy->traverseMaster(getPtrSelf());
this->pvListener = PVListenerPtr();;
unlock();
return true;
} catch(...) {
@ -291,7 +312,19 @@ bool PVRecord::addListener(PVListenerPtr const & pvListener)
}
}
bool PVRecord::removeListener(PVListenerPtr const & pvListener)
void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
{
PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
if(isAddListener) {
pvRecordField->addListener(pvListener);
} else {
pvRecordField->removeListener(pvListener);
}
}
bool PVRecord::removeListener(
PVListenerPtr const & pvListener,
PVCopyPtr const & pvCopy)
{
if(traceLevel>1) {
cout << "PVRecord::removeListener() " << recordName << endl;
@ -307,7 +340,10 @@ bool PVRecord::removeListener(PVListenerPtr const & pvListener)
{
if((*iter).get()==pvListener.get()) {
pvListenerList.erase(iter);
pvRecordStructure->removeListener(pvListener);
this->pvListener = pvListener;
isAddListener = false;
pvCopy->traverseMaster(getPtrSelf());
this->pvListener = PVListenerPtr();;
unlock();
return true;
}
@ -411,6 +447,9 @@ PVRecordPtr PVRecordField::getPVRecord() {return pvRecord;}
bool PVRecordField::addListener(PVListenerPtr const & pvListener)
{
if(pvRecord->getTraceLevel()>1) {
cout << "PVRecordField::addListener() " << getFullName() << endl;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
if((*iter).get()==pvListener.get()) {
@ -423,6 +462,9 @@ bool PVRecordField::addListener(PVListenerPtr const & pvListener)
void PVRecordField::removeListener(PVListenerPtr const & pvListener)
{
if(pvRecord->getTraceLevel()>1) {
cout << "PVRecordField::removeListener() " << getFullName() << endl;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
if((*iter).get()==pvListener.get()) {

View File

@ -3,13 +3,11 @@
SRC_DIRS += $(PVDATABASE_SRC)/pvAccess
INC += channelProviderLocal.h
INC += pvCopyMonitor.h
DBD += registerChannelProviderLocal.dbd
LIBSRCS += channelProviderLocal.cpp
LIBSRCS += channelLocal.cpp
LIBSRCS += pvCopyMonitor.cpp
LIBSRCS += monitorFactory.cpp
LIBSRCS += registerChannelProviderLocal.cpp

View File

@ -109,8 +109,8 @@ public:
{return channelLocal;}
virtual void cancel(){}
virtual void lastRequest() {}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
virtual void lock() {pvRecord->lock();}
virtual void unlock() {pvRecord->unlock();}
private:
shared_pointer getPtrSelf()
{
@ -133,8 +133,8 @@ private:
ChannelLocalPtr channelLocal;
ChannelProcessRequester::shared_pointer channelProcessRequester;
PVRecordPtr pvRecord;
Mutex mutex;
int nProcess;
Mutex mutex;
};
ChannelProcessLocalPtr ChannelProcessLocal::create(
@ -242,8 +242,8 @@ public:
{return channelLocal;}
virtual void cancel(){}
virtual void lastRequest() {}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
virtual void lock() {pvRecord->lock();}
virtual void unlock() {pvRecord->unlock();}
private:
shared_pointer getPtrSelf()
{
@ -401,8 +401,8 @@ public:
{return channelLocal;}
virtual void cancel(){}
virtual void lastRequest() {}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
virtual void lock() {pvRecord->lock();}
virtual void unlock() {pvRecord->unlock();}
private:
shared_pointer getPtrSelf()
{
@ -570,8 +570,8 @@ public:
{return channelLocal;}
virtual void cancel(){}
virtual void lastRequest() {}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
virtual void lock() {pvRecord->lock();}
virtual void unlock() {pvRecord->unlock();}
private:
shared_pointer getPtrSelf()
{
@ -783,8 +783,8 @@ public:
{return channelLocal;}
virtual void cancel(){}
virtual void lastRequest() {}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
virtual void lock() {pvRecord->lock();}
virtual void unlock() {pvRecord->unlock();}
private:
shared_pointer getPtrSelf()
{
@ -873,66 +873,29 @@ ChannelArrayLocalPtr ChannelArrayLocal::create(
PVScalarArrayPtr xxx = static_pointer_cast<PVScalarArray>(pvField);
pvCopy = getPVDataCreate()->createPVScalarArray(
xxx->getScalarArray()->getElementType());
ChannelArrayLocalPtr array(new ChannelArrayLocal(
channelLocal,
channelArrayRequester,
pvArray,
pvCopy,
pvRecord));
if(pvRecord->getTraceLevel()>0)
{
cout << "ChannelArrayLocal::create";
cout << " recordName " << pvRecord->getRecordName() << endl;
}
channelArrayRequester->channelArrayConnect(
Status::Ok, array, pvCopy->getArray());
return array;
}
if(pvField->getField()->getType()==structureArray) {
} else if(pvField->getField()->getType()==structureArray) {
PVStructureArrayPtr xxx = static_pointer_cast<PVStructureArray>(pvField);
pvCopy = getPVDataCreate()->createPVStructureArray(
xxx->getStructureArray()->getStructure());
ChannelArrayLocalPtr array(new ChannelArrayLocal(
channelLocal,
channelArrayRequester,
pvArray,
pvCopy,
pvRecord));
if(pvRecord->getTraceLevel()>0)
{
cout << "ChannelArrayLocal::create";
cout << " recordName " << pvRecord->getRecordName() << endl;
}
channelArrayRequester->channelArrayConnect(
Status::Ok, array, pvCopy->getArray());
return array;
}
if(pvField->getField()->getType()==unionArray) {
} else {
PVUnionArrayPtr xxx = static_pointer_cast<PVUnionArray>(pvField);
pvCopy = getPVDataCreate()->createPVUnionArray(
xxx->getUnionArray()->getUnion());
ChannelArrayLocalPtr array(new ChannelArrayLocal(
channelLocal,
channelArrayRequester,
pvArray,
pvCopy,
pvRecord));
if(pvRecord->getTraceLevel()>0)
{
cout << "ChannelArrayLocal::create";
cout << " recordName " << pvRecord->getRecordName() << endl;
}
channelArrayRequester->channelArrayConnect(
Status::Ok, array, pvCopy->getArray());
return array;
}
Status status(Status::STATUSTYPE_ERROR,
"Logic error. Should not reach this code");
ChannelArrayLocalPtr channelArray;
ArrayConstPtr array;
channelArrayRequester->channelArrayConnect(status,channelArray,array);
return channelArray;
ChannelArrayLocalPtr array(new ChannelArrayLocal(
channelLocal,
channelArrayRequester,
pvArray,
pvCopy,
pvRecord));
if(pvRecord->getTraceLevel()>0)
{
cout << "ChannelArrayLocal::create";
cout << " recordName " << pvRecord->getRecordName() << endl;
}
channelArrayRequester->channelArrayConnect(
Status::Ok, array, pvCopy->getArray());
return array;
}
@ -1083,23 +1046,6 @@ void ChannelArrayLocal::setLength(size_t length)
}
class ChannelRPCLocal :
public ChannelRPC
{
public:
POINTER_DEFINITIONS(ChannelRPCLocal);
virtual ~ChannelRPCLocal();
static ChannelRPC::shared_pointer create(
ChannelProviderLocalPtr const &channelProvider,
ChannelRPC::shared_pointer const & channelRPCRequester,
PVStructurePtr const & pvRequest,
PVRecordPtr const &pvRecord);
virtual void request(
PVStructurePtr const & pvArgument,
bool lastRequest);
};
ChannelLocal::ChannelLocal(
ChannelProviderLocalPtr const & provider,
ChannelRequester::shared_pointer const & requester,
@ -1161,6 +1107,8 @@ string ChannelLocal::getRemoteAddress()
Channel::ConnectionState ChannelLocal::getConnectionState()
{
Lock xx(mutex);
if(beingDestroyed) return Channel::DESTROYED;
return Channel::CONNECTED;
}
@ -1176,6 +1124,8 @@ ChannelRequester::shared_pointer ChannelLocal::getChannelRequester()
bool ChannelLocal::isConnected()
{
Lock xx(mutex);
if(beingDestroyed) return false;
return true;
}

View File

@ -18,7 +18,6 @@
#define epicsExportSharedSymbols
#include <pv/pvCopyMonitor.h>
#include <pv/channelProviderLocal.h>
using namespace epics::pvData;
@ -33,6 +32,7 @@ namespace epics { namespace pvDatabase {
static MonitorPtr nullMonitor;
static MonitorElementPtr NULLMonitorElement;
static Status failedToCreateMonitorStatus(Status::STATUSTYPE_ERROR,"failed to create monitor");
static Status wasDestroyedStatus(Status::STATUSTYPE_ERROR,"was destroyed");
static Status alreadyStartedStatus(Status::STATUSTYPE_ERROR,"already started");
static Status notStartedStatus(Status::STATUSTYPE_ERROR,"not started");
@ -47,7 +47,7 @@ typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
class MonitorLocal :
public Monitor,
public PVCopyMonitorRequester,
public PVListener,
public std::tr1::enable_shared_from_this<MonitorLocal>
{
enum MonitorState {idle,active, destroyed};
@ -58,16 +58,22 @@ public:
virtual Status stop();
virtual MonitorElementPtr poll();
virtual void destroy();
virtual void detach(PVRecordPtr const & pvRecord){destroy();}
virtual void release(MonitorElementPtr const & monitorElement);
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
virtual void dataPut(
PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField);
virtual void beginGroupPut(PVRecordPtr const & pvRecord);
virtual void endGroupPut(PVRecordPtr const & pvRecord);
virtual void unlisten(PVRecordPtr const & pvRecord);
MonitorElementPtr getActiveElement();
MonitorElementPtr releaseActiveElement();
void unlisten();
void releaseActiveElement();
bool init(PVStructurePtr const & pvRequest);
MonitorLocal(
MonitorRequester::shared_pointer const & channelMonitorRequester,
PVRecordPtr const &pvRecord);
PVCopyPtr getPVCopy() { return pvCopy;}
PVCopyMonitorPtr getPVCopyMonitor() { return pvCopyMonitor;}
private:
MonitorLocalPtr getPtrSelf()
{
@ -76,12 +82,13 @@ private:
MonitorRequester::shared_pointer monitorRequester;
PVRecordPtr pvRecord;
MonitorState state;
bool firstMonitor;
PVCopyPtr pvCopy;
MonitorElementQueuePtr queue;
MonitorElementPtr activeElement;
PVCopyMonitorPtr pvCopyMonitor;
bool isGroupPut;
bool dataChanged;
Mutex mutex;
Mutex queueMutex;
};
MonitorLocal::MonitorLocal(
@ -90,7 +97,8 @@ MonitorLocal::MonitorLocal(
: monitorRequester(channelMonitorRequester),
pvRecord(pvRecord),
state(idle),
firstMonitor(true)
isGroupPut(false),
dataChanged(false)
{
}
@ -111,12 +119,16 @@ void MonitorLocal::destroy()
{
Lock xx(mutex);
if(state==destroyed) return;
}
if(pvCopy) pvCopy->destroy();
{
Lock xx(mutex);
state = destroyed;
}
pvCopyMonitor->destroy();
pvCopy->destroy();
pvCopyMonitor.reset();
queue.reset();
{
Lock xx(queueMutex);
queue.reset();
}
pvCopy.reset();
}
@ -130,14 +142,23 @@ Status MonitorLocal::start()
Lock xx(mutex);
if(state==destroyed) return wasDestroyedStatus;
if(state==active) return alreadyStartedStatus;
}
pvRecord->addListener(getPtrSelf(),pvCopy);
pvRecord->lock();
try {
Lock xx(mutex);
state = active;
firstMonitor = true;
queue->clear();
isGroupPut = false;
activeElement = queue->getFree();
activeElement->changedBitSet->clear();
activeElement->overrunBitSet->clear();
activeElement->changedBitSet->set(0);
releaseActiveElement();
pvRecord->unlock();
} catch(...) {
pvRecord->unlock();
}
pvCopyMonitor->startMonitoring(activeElement);
return Status::Ok;
}
@ -152,7 +173,7 @@ Status MonitorLocal::stop()
if(state==idle) return notStartedStatus;
state = idle;
}
pvCopyMonitor->stopMonitoring();
pvRecord->removeListener(getPtrSelf(),pvCopy);
return Status::Ok;
}
@ -162,9 +183,11 @@ MonitorElementPtr MonitorLocal::poll()
{
cout << "MonitorLocal::poll() " << endl;
}
Lock xx(mutex);
if(state!=active) return NULLMonitorElement;
return queue->getUsed();
{
Lock xx(queueMutex);
if(state!=active) return NULLMonitorElement;
return queue->getUsed();
}
}
void MonitorLocal::release(MonitorElementPtr const & monitorElement)
@ -173,22 +196,24 @@ void MonitorLocal::release(MonitorElementPtr const & monitorElement)
{
cout << "MonitorLocal::release() " << endl;
}
Lock xx(mutex);
if(state!=active) return;
queue->releaseUsed(monitorElement);
{
Lock xx(queueMutex);
if(state!=active) return;
queue->releaseUsed(monitorElement);
}
}
MonitorElementPtr MonitorLocal::releaseActiveElement()
void MonitorLocal::releaseActiveElement()
{
if(pvRecord->getTraceLevel()>1)
{
cout << "MonitorLocal::releaseActiveElement() " << endl;
}
{
Lock xx(mutex);
if(state!=active) return NULLMonitorElement;
Lock xx(queueMutex);
if(state!=active) return;
MonitorElementPtr newActive = queue->getFree();
if(!newActive) return activeElement;
if(!newActive) return;
pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
BitSetUtil::compress(activeElement->changedBitSet,activeElement->pvStructurePtr);
BitSetUtil::compress(activeElement->overrunBitSet,activeElement->pvStructurePtr);
@ -198,45 +223,128 @@ MonitorElementPtr MonitorLocal::releaseActiveElement()
activeElement->overrunBitSet->clear();
}
monitorRequester->monitorEvent(getPtrSelf());
return activeElement;
return;
}
void MonitorLocal::unlisten()
void MonitorLocal::dataPut(PVRecordFieldPtr const & pvRecordField)
{
if(pvRecord->getTraceLevel()>0)
if(pvRecord->getTraceLevel()>1)
{
cout << "MonitorLocal::unlisten() " << endl;
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl;
}
if(state!=active) return;
{
Lock xx(mutex);
size_t offset = pvCopy->getCopyOffset(pvRecordField->getPVField());
BitSetPtr const &changedBitSet = activeElement->changedBitSet;
BitSetPtr const &overrunBitSet = activeElement->overrunBitSet;
bool isSet = changedBitSet->get(offset);
changedBitSet->set(offset);
if(isSet) overrunBitSet->set(offset);
dataChanged = true;
}
if(!isGroupPut) {
releaseActiveElement();
dataChanged = false;
}
monitorRequester->unlisten(getPtrSelf());
}
void MonitorLocal::dataPut(
PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl;
}
if(state!=active) return;
{
Lock xx(mutex);
BitSetPtr const &changedBitSet = activeElement->changedBitSet;
BitSetPtr const &overrunBitSet = activeElement->overrunBitSet;
size_t offsetCopyRequested = pvCopy->getCopyOffset(
requested->getPVField());
size_t offset = offsetCopyRequested
+ (pvRecordField->getPVField()->getFieldOffset()
- requested->getPVField()->getFieldOffset());
bool isSet = changedBitSet->get(offset);
changedBitSet->set(offset);
if(isSet) overrunBitSet->set(offset);
dataChanged = true;
}
if(!isGroupPut) {
releaseActiveElement();
dataChanged = false;
}
}
void MonitorLocal::beginGroupPut(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::beginGroupPut()" << endl;
}
if(state!=active) return;
{
Lock xx(mutex);
isGroupPut = true;
dataChanged = false;
}
}
void MonitorLocal::endGroupPut(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::endGroupPut() dataChanged " << dataChanged << endl;
}
if(state!=active) return;
{
Lock xx(mutex);
isGroupPut = false;
}
if(dataChanged) {
dataChanged = false;
releaseActiveElement();
}
}
void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::unlisten\n";
}
pvRecord->removeListener(getPtrSelf(),pvCopy);
}
bool MonitorLocal::init(PVStructurePtr const & pvRequest)
{
PVFieldPtr pvField;
PVStructurePtr pvOptions;
size_t queueSize = 2;
pvField = pvRequest->getSubField("record._options");
if(pvField.get()!=NULL) {
pvOptions = static_pointer_cast<PVStructure>(pvField);
pvField = pvOptions->getSubField("queueSize");
if(pvField.get()!=NULL) {
PVStringPtr pvString = pvOptions->getStringField("queueSize");
if(pvString.get()!=NULL) {
PVStructurePtr pvOptions = pvRequest->getSubField<PVStructure>("record._options");
if(pvOptions) {
PVStringPtr pvString = pvOptions->getSubField<PVString>("queueSize");
if(pvString) {
try {
int32 size;
std::stringstream ss;
ss << pvString->get();
ss >> size;
queueSize = size;
} catch (...) {
monitorRequester->message("queueSize " +pvString->get() + " illegal",errorMessage);
return false;
}
}
}
pvField = pvRequest->getSubField("field");
if(pvField.get()==NULL) {
if(!pvField) {
pvCopy = PVCopy::create(
pvRecord->getPVRecordStructure()->getPVStructure(),
pvRequest,"");
if(pvCopy.get()==NULL) {
if(!pvCopy) {
monitorRequester->message("illegal pvRequest",errorMessage);
return false;
}
@ -248,27 +356,21 @@ bool MonitorLocal::init(PVStructurePtr const & pvRequest)
pvCopy = PVCopy::create(
pvRecord->getPVRecordStructure()->getPVStructure(),
pvRequest,"field");
if(pvCopy.get()==NULL) {
if(!pvCopy) {
monitorRequester->message("illegal pvRequest",errorMessage);
return false;
}
}
pvCopyMonitor = PVCopyMonitor::create(
getPtrSelf(),pvRecord,pvCopy);
// MARTY MUST IMPLEMENT periodic
if(queueSize<2) queueSize = 2;
std::vector<MonitorElementPtr> monitorElementArray;
monitorElementArray.reserve(queueSize);
size_t nfields = 0;
for(size_t i=0; i<queueSize; i++) {
PVStructurePtr pvStructure = pvCopy->createPVStructure();
if(nfields==0) nfields = pvStructure->getNumberFields();
MonitorElementPtr monitorElement(
new MonitorElement(pvStructure));
monitorElementArray.push_back(monitorElement);
}
queue = MonitorElementQueuePtr(new MonitorElementQueue(monitorElementArray));
// MARTY MUST IMPLEMENT algorithm
monitorRequester->monitorConnect(
Status::Ok,
getPtrSelf(),
@ -289,7 +391,6 @@ MonitorFactory::~MonitorFactory()
void MonitorFactory::destroy()
{
Lock lock(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
@ -306,7 +407,12 @@ MonitorPtr MonitorFactory::createMonitor(
MonitorLocalPtr monitor(new MonitorLocal(
monitorRequester,pvRecord));
bool result = monitor->init(pvRequest);
if(!result) return nullMonitor;
if(!result) {
MonitorPtr monitor;
StructureConstPtr structure;
monitorRequester->monitorConnect(failedToCreateMonitorStatus,monitor,structure);
return nullMonitor;
}
if(pvRecord->getTraceLevel()>0)
{
cout << "MonitorFactory::createMonitor";

View File

@ -1,325 +0,0 @@
/* pvCopyMonitor.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 Marty Kraimer
* @date 2013.04
*/
#include <string>
#include <stdexcept>
#include <memory>
#include <sstream>
#include <pv/thread.h>
#define epicsExportSharedSymbols
#include <pv/channelProviderLocal.h>
#include <pv/pvCopyMonitor.h>
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::size_t;
using std::cout;
using std::endl;
using std::string;
namespace epics { namespace pvDatabase {
struct PVCopyMonitorFieldNode
{
MonitorPluginPtr monitorPlugin;
size_t offset; // in pvCopy
};
PVCopyMonitorPtr PVCopyMonitor::create(
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester,
PVRecordPtr const &pvRecord,
PVCopyPtr const & pvCopy)
{
PVCopyMonitorPtr pvCopyMonitor( new PVCopyMonitor(
pvRecord,pvCopy,pvCopyMonitorRequester));
pvCopyMonitor->init(pvRecord->getPVRecordStructure()->getPVStructure());
return pvCopyMonitor;
}
PVCopyMonitor::PVCopyMonitor(
PVRecordPtr const &pvRecord,
PVCopyPtr const &pvCopy,
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester
)
: pvRecord(pvRecord),
pvCopy(pvCopy),
pvCopyMonitorRequester(pvCopyMonitorRequester),
isGroupPut(false),
dataChanged(false),
isMonitoring(false),
isDestroyed(false)
{
}
PVCopyMonitor::~PVCopyMonitor()
{
if(pvRecord->getTraceLevel()>0)
{
cout << "~PVCopyMonitor" << endl;
}
}
// pvField is in top level structure of PVRecord.
void PVCopyMonitor::init(PVFieldPtr const &pvField)
{
size_t offset = pvCopy->getCopyOffset(pvField);
if(offset==string::npos) return;
PVStructurePtr pvOptions = pvCopy->getOptions(offset);
if(pvOptions) {
PVStringPtr pvName = pvOptions->getSubField<PVString>("plugin");
if(pvName) {
string pluginName = pvName->get();
MonitorPluginManagerPtr manager = MonitorPluginManager::get();
MonitorPluginCreatorPtr pluginCreator = manager->findPlugin(pluginName);
if(pluginCreator) {
StructureConstPtr top = pvCopy->getStructure();
FieldConstPtr field = pvField->getField();
MonitorPluginPtr monitorPlugin = pluginCreator->create(field,top,pvOptions);
if(monitorPlugin) {
PVCopyMonitorFieldNodePtr fieldNode(new PVCopyMonitorFieldNode());
fieldNode->monitorPlugin = monitorPlugin;
fieldNode->offset = offset;
monitorFieldNodeList.push_back(fieldNode);
}
}
}
}
if(pvField->getField()->getType()!=structure) return;
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
const PVFieldPtrArray &pvFields = pv->getPVFields();
for(size_t i=0; i<pvFields.size(); ++i ) init(pvFields[i]);
}
MonitorPluginPtr PVCopyMonitor::getMonitorPlugin(size_t offset)
{
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
{
if((*iter)->offset==offset) return (*iter)->monitorPlugin;
}
return MonitorPluginPtr();
}
void PVCopyMonitor::destroy()
{
if(pvRecord->getTraceLevel()>0)
{
cout << "PVCopyMonitor::destroy()" << endl;
}
{
Lock xx(mutex);
if(isDestroyed) return;
}
stopMonitoring();
Lock xx(mutex);
isDestroyed = true;
pvCopyMonitorRequester.reset();
pvCopy.reset();
}
void PVCopyMonitor::startMonitoring(MonitorElementPtr const & startElement)
{
if(pvRecord->getTraceLevel()>0)
{
cout << "PVCopyMonitor::startMonitoring()" << endl;
}
{
Lock xx(mutex);
if(isDestroyed) return;
if(isMonitoring) return;
monitorElement = startElement;
isMonitoring = true;
isGroupPut = false;
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
{
(*iter)->monitorPlugin->startMonitoring();
}
}
pvRecord->addListener(getPtrSelf());
pvRecord->lock();
try {
Lock xx(mutex);
pvCopy->traverseMaster(getPtrSelf());
monitorElement->changedBitSet->clear();
monitorElement->overrunBitSet->clear();
monitorElement->changedBitSet->set(0);
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
pvRecord->unlock();
} catch(...) {
pvRecord->unlock();
}
}
void PVCopyMonitor::nextMasterPVField(epics::pvData::PVFieldPtr const &pvField)
{
pvRecord->findPVRecordField(pvField)->addListener(getPtrSelf());
}
void PVCopyMonitor::stopMonitoring()
{
if(pvRecord->getTraceLevel()>0)
{
cout << "PVCopyMonitor::stopMonitoring()" << endl;
}
{
Lock xx(mutex);
if(isDestroyed) return;
if(!isMonitoring) return;
isMonitoring = false;
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
{
(*iter)->monitorPlugin->stopMonitoring();
}
}
pvRecord->removeListener(getPtrSelf());
}
void PVCopyMonitor::detach(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>0)
{
cout << "PVCopyMonitor::detach()" << endl;
}
}
void PVCopyMonitor::dataPut(PVRecordFieldPtr const & pvRecordField)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl;
}
if(isDestroyed) return;
bool causeMonitor = true;
{
Lock xx(mutex);
size_t offset = pvCopy->getCopyOffset(pvRecordField->getPVField());
BitSetPtr const &changedBitSet = monitorElement->changedBitSet;
BitSetPtr const &overrunBitSet = monitorElement->overrunBitSet;
bool isSet = changedBitSet->get(offset);
changedBitSet->set(offset);
if(isSet) overrunBitSet->set(offset);
MonitorPluginPtr monitorPlugin = getMonitorPlugin(offset);
if(monitorPlugin) {
causeMonitor = monitorPlugin->causeMonitor(
pvRecordField->getPVField(),
pvRecord->getPVRecordStructure()->getPVStructure(),
monitorElement);
}
if(causeMonitor) dataChanged = true;
}
if(causeMonitor) {
if(!isGroupPut) {
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
dataChanged = false;
}
}
}
void PVCopyMonitor::dataPut(
PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl;
}
if(isDestroyed) return;
bool causeMonitor = true;
{
Lock xx(mutex);
BitSetPtr const &changedBitSet = monitorElement->changedBitSet;
BitSetPtr const &overrunBitSet = monitorElement->overrunBitSet;
size_t offsetCopyRequested = pvCopy->getCopyOffset(
requested->getPVField());
size_t offset = offsetCopyRequested
+ (pvRecordField->getPVField()->getFieldOffset()
- requested->getPVField()->getFieldOffset());
bool isSet = changedBitSet->get(offset);
changedBitSet->set(offset);
if(isSet) overrunBitSet->set(offset);
MonitorPluginPtr monitorPlugin = getMonitorPlugin(offsetCopyRequested);
if(monitorPlugin) {
causeMonitor = monitorPlugin->causeMonitor(
requested->getPVField(),
pvRecord->getPVRecordStructure()->getPVStructure(),
monitorElement);
}
if(causeMonitor) dataChanged = true;
}
if(causeMonitor) {
if(!isGroupPut) {
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
dataChanged = false;
}
}
}
void PVCopyMonitor::beginGroupPut(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::beginGroupPut()" << endl;
}
if(isDestroyed) return;
{
Lock xx(mutex);
isGroupPut = true;
dataChanged = false;
}
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
for (iter = monitorFieldNodeList.begin();
iter!=monitorFieldNodeList.end();
++iter)
{
(*iter)->monitorPlugin->beginGroupPut();
}
}
void PVCopyMonitor::endGroupPut(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::endGroupPut() dataChanged " << dataChanged << endl;
}
if(isDestroyed) return;
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
{
(*iter)->monitorPlugin->endGroupPut();
}
{
Lock xx(mutex);
isGroupPut = false;
}
if(dataChanged) {
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
dataChanged = false;
}
}
void PVCopyMonitor::unlisten(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1)
{
cout << "PVCopyMonitor::unlisten\n";
}
if(isDestroyed) return;
pvCopyMonitorRequester->unlisten();
}
}}

View File

@ -1,188 +0,0 @@
/* pvCopyMonitor.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 Marty Kraimer
* @date 2013.04
*/
#ifndef PVCOPYMONITOR_H
#define PVCOPYMONITOR_H
#ifdef epicsExportSharedSymbols
# define pvCopyMonitorEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <string>
#include <stdexcept>
#include <memory>
#include <list>
#include <pv/monitorPlugin.h>
#include <pv/pvCopy.h>
#include <pv/pvAccess.h>
#ifdef pvCopyMonitorEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef pvCopyMonitorEpicsExportSharedSymbols
#endif
#include <shareLib.h>
#include <pv/pvDatabase.h>
namespace epics { namespace pvDatabase {
class PVCopyMonitor;
typedef std::tr1::shared_ptr<PVCopyMonitor> PVCopyMonitorPtr;
class PVCopyMonitorRequester;
typedef std::tr1::shared_ptr<PVCopyMonitorRequester> PVCopyMonitorRequesterPtr;
struct PVCopyMonitorFieldNode;
typedef std::tr1::shared_ptr<PVCopyMonitorFieldNode> PVCopyMonitorFieldNodePtr;
/**
* @brief Monitor changes to a PVRecord.
*
* This class manages changes to fields being monitored in a PVRecord.
*/
class epicsShareClass PVCopyMonitor :
public PVListener,
public epics::pvData::PVCopyTraverseMasterCallback,
public std::tr1::enable_shared_from_this<PVCopyMonitor>
{
public:
POINTER_DEFINITIONS(PVCopyMonitor);
/**
* Factory method to create a PVCopyMonoitor
* @param pvCopyMonitorRequester This is usually MonitorLocal.
* @param pvRecord The record being monitored.
* @param pvCopy An instance of pvCopy
* @return A shared pointer to a PVCopyMonitor.
*/
static PVCopyMonitorPtr create(
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester,
PVRecordPtr const &pvRecord,
epics::pvData::PVCopyPtr const & pvCopy);
/**
* Destructor
*/
virtual ~PVCopyMonitor();
/**
* Destroy the PVCopyMonitor
*/
virtual void destroy();
/**
* Calls pvRecord methods to start monitoring for calls to postPut.
* @param monitorElement the initial monotorElement
* This holds the change and overrun bitSets that are updated
* when postPut is called.
*/
void startMonitoring(
epics::pvData::MonitorElementPtr const & monitorElement);
/**
* Calls pvRecord methods to stop monitoring for calls to postPut.
*/
void stopMonitoring();
// following are PVListener methods
/**
* The record is being removed from the PVDatabase.
* @param The record being removed.
*/
virtual void detach(PVRecordPtr const & pvRecord);
/**
* A postPut has been issued to a field being monitored.
* @param pvRecordField The field.
*/
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
/**
* A postPut has been issued to a subfield of a field being monitored.
* @param requested The field being monitored.
* @param pvRecordField The field being modified.
*/
virtual void dataPut(
PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField);
/**
* A group of puts are being changed.
* No monitors should be issued until endGroupPut is called.
* @param pvRecord The record.
*/
virtual void beginGroupPut(PVRecordPtr const & pvRecord);
/**
* The end of a group of puts.
* If any fields have changed value since beginGroupPut a monitor
* can be issued.
* @param pvRecord The record.
*/
virtual void endGroupPut(PVRecordPtr const & pvRecord);
/**
* The record is being removed from the database.
* @param pvRecord The record.
*/
virtual void unlisten(PVRecordPtr const & pvRecord);
// following is PVCopyTraverseMasterCallback method
/**
* The PVCopyTraverseMasterCallback callback
* Called for every field of PVRecord that is being monoitored.
* @param pvField The field in the PVRecord.
*/
virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField);
private:
PVCopyMonitorPtr getPtrSelf()
{
return shared_from_this();
}
PVCopyMonitor(
PVRecordPtr const &pvRecord,
epics::pvData::PVCopyPtr const &pvCopy,
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester);
void init(epics::pvData::PVFieldPtr const &pvField);
epics::pvData::MonitorPluginPtr getMonitorPlugin(size_t offset);
PVRecordPtr pvRecord;
epics::pvData::PVCopyPtr pvCopy;
PVCopyMonitorRequesterPtr pvCopyMonitorRequester;
epics::pvData::MonitorElementPtr monitorElement;
bool isGroupPut;
bool dataChanged;
bool isMonitoring;
bool isDestroyed;
epics::pvData::Mutex mutex;
std::list<PVCopyMonitorFieldNodePtr> monitorFieldNodeList;
};
/**
* @brief Class implemented by monitorFactory
*
* This is not of interest to users.
* It is for communication between monitorfactory and pvCopyMonitor.
*
*/
class epicsShareClass PVCopyMonitorRequester
{
public:
POINTER_DEFINITIONS(PVCopyMonitorRequester);
/**
*
* Destructor
*/
virtual ~PVCopyMonitorRequester() {}
/**
* Release active element and return a new element.
* @return new element to use.
*/
virtual epics::pvData::MonitorElementPtr releaseActiveElement() = 0;
/**
*
* stop listening for changes.
*/
virtual void unlisten() = 0;
};
}}
#endif /* PVCOPYMONITOR_H */