simplify monitors; cleanup code; fix race condidition for monitor cleanup
This commit is contained in:
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}}
|
@ -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 */
|
Reference in New Issue
Block a user