From ec7601392d2f67016055a28c781f67509dab032b Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Thu, 16 May 2013 09:32:32 -0400 Subject: [PATCH] monitors now implemented --- documentation/pvDatabaseCPP.html | 20 +- documentation/pvDatabaseCPP_20130516.html | 871 ++++++++++++++++++++++ src/Makefile | 3 + src/database/exampleCounter.h | 1 + src/database/pvDatabase.cpp | 8 +- src/database/pvDatabase.h | 8 + src/database/pvRecord.cpp | 45 +- src/pvAccess/channelLocal.cpp | 106 +-- src/pvAccess/channelProviderLocal.cpp | 17 +- src/pvAccess/channelProviderLocal.h | 43 +- src/pvAccess/monitorAlgorithm.h | 64 +- src/pvAccess/monitorFactory.cpp | 541 ++++++++++++++ src/pvAccess/pvCopy.cpp | 211 +++++- src/pvAccess/pvCopy.h | 48 +- src/pvAccess/pvShare.cpp | 5 +- src/pvAccess/pvShareStructureArray.cpp | 5 +- test/server/exampleCounterMain.cpp | 2 +- test/server/testExampleServerMain.cpp | 2 +- 18 files changed, 1860 insertions(+), 140 deletions(-) create mode 100644 documentation/pvDatabaseCPP_20130516.html create mode 100644 src/pvAccess/monitorFactory.cpp diff --git a/documentation/pvDatabaseCPP.html b/documentation/pvDatabaseCPP.html index 097c145..4c5aef2 100644 --- a/documentation/pvDatabaseCPP.html +++ b/documentation/pvDatabaseCPP.html @@ -38,7 +38,7 @@

pvDatabaseCPP

-

EPICS v4 Working Group, Working Draft, 17-Apr-2013

+

EPICS v4 Working Group, Working Draft, 16-May-2013

Latest version:
This version:
pvDatabaseCPP20130417.html + href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html
Previous version:
pvDatabaseCPP20121211.html + href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html
Editors:
Marty Kraimer, BNL
@@ -74,14 +74,20 @@ The minimum that an extenson must provide is a top level PVStructure and a proce

Status of this Document

-

This is the 17-Apr-2013 version of the definition of pvDatabaseCPP. +

This is the 16-May-2013 version of the definition of pvDatabaseCPP.

-

The following Channel methods are implemented and working: getField,i -channelProcess, channelGet, channelPut, and channelPutGet. +

The following Channel methods are implemented and working: getField, +channelProcess, channelGet, channelPut, channelPutGet, and Monitor. But lots of work remains:

Other Channel Methods
-
Monitor is next.
+
ChannelArray is next.
+
Monitor Algorithms
+
Monitor algorithms have no been implemented. + Thus all monitors are onPut.
+
Lifecycle problems
+
Problems when channel clients disconnect. + May need help from Matej
Memory leaks at exit
May need help from Matej.
Scalar Arrays
diff --git a/documentation/pvDatabaseCPP_20130516.html b/documentation/pvDatabaseCPP_20130516.html new file mode 100644 index 0000000..4c5aef2 --- /dev/null +++ b/documentation/pvDatabaseCPP_20130516.html @@ -0,0 +1,871 @@ + + + + + + pvDatabaseCPP + + + + + + + + + +
+

pvDatabaseCPP

+ + +

EPICS v4 Working Group, Working Draft, 16-May-2013

+
+
Latest version:
+
pvDatabaseCPP.html +
+
This version:
+
pvDatabaseCPP20130516.html +
+
Previous version:
+
pvDatabaseCPP20130417.html +
+
Editors:
+
Marty Kraimer, BNL
+
+ + +
+
+ +

Abstract

+ +

This document describes pvDatabaseCPP, +which is a framework for implementing a network accessable database of smart memory resident +records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by +pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess. +The framework can be extended in order to create record instances that implements services. +The minimum that an extenson must provide is a top level PVStructure and a process method. +

+ + +

Status of this Document

+ +

This is the 16-May-2013 version of the definition of pvDatabaseCPP. +

+

The following Channel methods are implemented and working: getField, +channelProcess, channelGet, channelPut, channelPutGet, and Monitor. +But lots of work remains:

+
+
Other Channel Methods
+
ChannelArray is next.
+
Monitor Algorithms
+
Monitor algorithms have no been implemented. + Thus all monitors are onPut.
+
Lifecycle problems
+
Problems when channel clients disconnect. + May need help from Matej
+
Memory leaks at exit
+
May need help from Matej.
+
Scalar Arrays
+
Have not been tested. Share has not been implemented.
+
Structure Arrays
+
Has not been implemented
+
Testing
+
Needs lots more testing
+
+ +
+

Table of Contents

+
+
+ + +

Introduction

+

Overview

+

A brief description of a pvDatabase is that it is a set of network accessible, smart, +memory resident records. +Each record has data composed of a top level PVStructure. +Each record has a name which is the channelName for pvAccess. +A local Channel Provider implements the complete ChannelProvider and +Channel interfaces as defined by pvAccess. +The local provider provides access to the records in the pvDatabase. +This local provider is accessed by the remote pvAccess server. +A record is smart because code can be attached to a record, which is accessed via a method named process.

+ +

This document describes components that provides the following features: +

+
database
+
This encapsulates the concept of a database of memory resident smart records. + The two main components are: +
+
pvRecord
+
This encapsulates the concept of a smart record. It can be processed. + Changes to field values can be trapped. A record can be locked.
+
pvDatabase
+
This is a database of pvRecords. + Records can be added and removed from a database.
+
+
pvAccess
+
This is a complete implementation of ChannelProvider and Channel + as defined by pvAccess. + It is used by the server side of pvAccess to attach to pvRecords. + This component also includes the monitor and pvCopy components from pvIOCJava
+
+

database provides base classes that make it easy to create record instances. +The code attached to each record must create the top +level PVStructure and the following two methods:

+
+
init
+
This is a method for initializing the support. + It returns true if successful and false otherwise. +
+
process
+
This is what makes a record smart. +
+
+

Relationship with pvIOCJava.

+

This document descibes a C++ implementation of some of the components in pvIOCJava, +which also implements a pvDatabase. +PVDatabaseCPP extracts the core components required to create a network accessible database of smart +memory resident records. +pvDatabaseCPP does not implement any of the specialized support that pvIOCJava +provides. +It is expected that many services will be created that do not require the full features provided +by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of +them named pvDatabaseJava.

+

Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing. +For pvDatabaseCPP the process method is allowed to block. +Until a need is demonstrated this will remain true. +The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess. +The server side of remote pvAccess creates two threads for each client and always accesses +a record via these threads. +It is expected that these threads will be sufficient to efficently handle all channel methods except +channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests. +If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility, +then the scanning facility will have to provide some way of handling process requests that block.

+

+

Example PVRecord Extension

+

The example implements a simple counter. +The example can be run on linux as follows:

+
+mrk> pwd
+/home/hg/pvDatabaseCPP
+mrk> bin/linux-x86_64/exampleCounter 
+
+
+

The example consists of two components:

+
+
ExampleCounter.h
+
The source code for the counter.
+
exampleCounterMain.cpp
+
A main program that runs the example so that it can be accessed + by a pvAccess client.
+
+

ExampleCounter.h

+

The example resides in src/database. +The complete implementation is in the header file. +A serious implementation would probably break the code into two files: +1) a header, and 2) the implementation. The description consists of

+
+class ExampleCounter;
+typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
+
+class ExampleCounter :
+    public PVRecord
+{
+public:
+    POINTER_DEFINITIONS(ExampleCounter);
+    static ExampleCounterPtr create(
+        epics::pvData::String const & recordName);
+    virtual ~ExampleCounter();
+    virtual void destroy();
+    virtual bool init();
+    virtual void process();
+private:
+    ExampleCounter(epics::pvData::String const & recordName,
+        epics::pvData::PVStructurePtr const & pvStructure);
+    epics::pvData::PVLongPtr pvValue;
+    epics::pvData::PVTimeStamp pvTimeStamp;
+    epics::pvData::TimeStamp timeStamp;
+};
+
+

where

+
+
create
+
This is example specific but each support could provide + a similar static method. +
+
~ExampleCounter
+
The destructor must be declared virtual.
+
+
Called when the record is being destroyed. + This must call the base class destroy method. +
init
+
A method to initialize the support. It returns true + if initialization is successful and false if not. + NOTE that this is a virtual method of PVRecord itself.
+
process
+
+ This again is a virtual method of PVRecord. +
+
ExampleCounter
+
For the example this is private.
+
pvValue
+
This is the field of the top level structure that process + accesses. +
+
+

The implementation of create method is:

+
+ExampleCounterPtr ExampleCounter::create(
+    epics::pvData::String const & recordName)
+{
+    epics::pvData::PVStructurePtr pvStructure =
+       epics::pvData::getStandardPVField()->scalar(
+           epics::pvData::pvDouble,"timeStamp,alarm"");
+    ExampleCounterPtr pvRecord(
+        new ExampleCounter(recordName,pvStructure));
+    if(!pvRecord->init()) pvRecord.reset();
+    return pvRecord;
+}
+
+This: +
    +
  • Creates the top level structure.
  • +
  • Creates a ExampleCounterPtr via the constructor.
  • +
  • Calls init and if it fails resets the shared pointer.
  • +
  • Returns the shared pointer to the newly created record.
  • +
+

The private constructor method is:

+
+ExampleCounter::ExampleCounter(
+    epics::pvData::String const & recordName,
+    epics::pvData::PVStructurePtr const & pvStructure)
+: PVRecord(recordName,pvStructure)
+{
+    pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
+}
+
+The example is very simple. It just calls the base class constructor. +

The destructor and destroy methods are:

+
+ExampleCounter::~ExampleCounter()
+{
+    destroy();
+}
+
+void ExampleCounter::destroy()
+{
+    PVRecord::destroy();
+}
+
+The destructor just calls destroy. +The destroy method, which is virtual, just calls the destroy method of the base class. +A more complicated example can clean up any resources it used but must call the base +class destroy method. +

The implementation of init is:

+
+bool ExampleCounter::init()
+{
+
+    initPVRecord();
+    epics::pvData::PVFieldPtr pvField;
+    pvValue = getPVStructure()->getLongField("value");
+    if(pvValue.get()==NULL) return false;
+    return true;
+}
+
+This: +
    +
  • Calls initRecord which is implemented by the base class. + It MUST be called.
  • +
  • Calls getLongField to get the interface to the value field, + which must be a scalar with type long.
  • +
  • If a long value field was not found it returns false.
  • +
  • Returns true
  • +
+

The implementation of process is:

+
+void ExampleCounter::process()
+{
+    pvValue->put(pvValue->get() + 1.0);
+    timeStamp.getCurrent();
+    pvTimeStamp.set(timeStamp);
+}
+
+It adds 1.0 to the current value. +It then sets the timeStamp to the current time. +

exampleCounterMain.cpp

+

This is in test/server. +The main program is:

+
+int main(int argc,char *argv[])
+{
+    PVDatabasePtr master = PVDatabase::getMaster();
+    ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
+    String recordName("exampleCounter");
+    PVRecordPtr pvRecord = ExampleCounter::create(recordName);
+    bool result = master->addRecord(pvRecord);
+    cout << "result of addRecord " << recordName << " " << result << endl;
+    pvRecord.reset();
+    cout << "exampleServer\n";
+    string str;
+    while(true) {
+        cout << "Type exit to stop: \n";
+        getline(cin,str);
+        if(str.compare("exit")==0) break;
+
+    }
+    return 0;
+}
+
+This: +
    +
  • Gets a pointer to the master database.
  • +
  • Creates the local Channel Provider. This starts the pvAccess server.
  • +
  • Creates a ExampleCounter record with the name exampleCounter +
  • +
  • Prints exampleCounter on standard out.
  • +
  • Runs forever until the user types exit on standard in.
  • +
+

Phased Development

+

This documentation describes the first phase of a phased implementation of pvDatabaseCPP: +

+
pvRecord +
Wrapper on PVStructure that implements methods required by Local Channel Provider.
+
pvDatabase +
Database of PVRecords. Has methods find, add, and remove.
+
Local Channel Provider
+
Complete implementation of ChannelProvider and Channel. + This means that pvCopy and monitor are also implemented.
+
+

Future phases of pvDatabaseCPP might include:

+
+
Install
+
This provides complete support for on-line add and delete + of sets of records. + With the first phase each "service" is responsible for it's own implementation. + All that is provided is addRecord and removeRecord. +
+
Field support
+
Add the ability to optionally add support to fields. + In addition some of the basic support defined in pvIOCJava could also be implemented.
+
XML parser
+
This provides the ability to create record instances without writing any code.
+
+

The completion of each phase provides useful features that can be used without waiting for the +completion of later phases. +The rest of this document discusses only the first phase.

+

Features Required for localChannelProvider

+
+
pvCopy
+
Creates a PVStructure that contains a copy of an arbitary + subset of the fields of another top level PVStructure. + It can copy data between the two and maintains a bitSet that show + which fields are changed.
+
monitor
+
This provides the ability to monitor changes to fields of a record.
+
PVRecord and PVDatabase
+
Defined below.
+
The localChannelProvider itself
+
This is the pvAccess package in pvIOCJava. + The localChannelProvider will access data from PVRecords. + It will implement all channel methods.
+
+

Minumum Features Required for pvRecord

+

The first phase will only implement record processing, i. e. +the process method has to do everything itself without any generic field support. +This will be sufficient for starting to implement services. +The following are the minimium features required

+
+
PVDatabase
+
This holds a set of PVRecords. It has methods to find, add, and remove records.
+
PVRecord
+
This, and a set of related interfaces, provides the following: +
+
Access to top level PVStructure
+
PVRecord is a wrapper on a top level pvStructure.
+
Record locking
+
A record can be locked and unlocked. + A record must be locked whenever data in the pvStructure is accessed.
+
Trapping data changes
+
A client can request to be notified when data in the pvStructure is modified. + It can do this on a field by field basis.
+
+
+
+

The following sections describes the classes required for the first phase.

+ +

database

+

This directory has the following files:

+
+
pvDatabase.h
+
+ This is what is described in this section. +
+
pvDatabase.cpp
+
+ The implementation of PVDatabase. +
+
pvRecord.cpp
+
+ The implementation of the base class for PVREcord. + It can also implement record instances with a process + method does nothing. + This can be used to create a "dumb" record where all changes are + done by clients. + The complete implementation is provided in the header file. + Thus code will be generated only if other code includes the + header file and creates a record instance. +
+
exampleCounter.h
+
+ This was described in the introduction. +
+
powerSupplyRecordTest.h
+
+ This provides code that simulates a power supply. + It computes the current from the voltage and power. + It is used for testing. + The complete implementation is provided in the header file. + Thus code will be generated only if other code includes the + header file and creates a record instance. +
+
+

The classes in pvDatabase.h describe a database of memory resident +smart records. +It describes the following classes:

+
+
PVRecord
+
This provides the methods required by localChannelProvider to implement Channel.
+
PVRecordField
+
PVRecordStructure
+
These wrap PVField and PVStructure so that pvCopy and monitor + can be implemented.
+
PVRecordClient
+
This is called by anything that acceses PVRecord.
+
PVListener
+
This is implemented by anything that wants to trap calls to PVRecord::message.
+
PVDatabase
+
This is a database of PVRecords.
+
+

Each class is described in a separate subsection.

+

C++ namespace and typedefs

+
+namespace epics { namespace pvDatabase {
+
+class PVRecord;
+typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
+typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
+
+class PVRecordField;
+typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
+typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
+typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
+
+class PVRecordStructure;
+typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
+
+class PVRecordClient;
+typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
+
+class PVListener;
+typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
+
+class RecordProcessRequester;
+typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
+
+class RecordPutRequester;
+typedef std::tr1::shared_ptr<RecordPutRequester> RecordPutRequesterPtr;
+
+class PVDatabase;
+typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
+
+ +

class PVRecord

+

NOTES: +

    +
  • This section uses the name record instead of "an instance of PVRecord".
  • +
  • Most clients will access a record via the local channel provider, + i. e. via pvAccess. + Thus this section is mainly of interest to + the local channel provider and record implementers.
  • +
  • Most readers will not care about most of the PVRecord methods. + Most of the methods are used by the pvAccess code. + Service implementers will mostly be interested in methods init and process. + These are described first. +
+
PVRecord Methods +
+class PVRecord
+     public epics::pvData::Requester,
+     public std::tr1::enable_shared_from_this<PVRecord>
+{
+public:
+    POINTER_DEFINITIONS(PVRecord);
+
+    virtual bool init() {initPVRecord(); return true;}
+    virtual void process() {}
+
+    static PVRecordPtr create(
+        epics::pvData::String const & recordName,
+        epics::pvData::PVStructurePtr const & pvStructure);
+    virtual ~PVRecord();
+    virtual void destroy();
+    epics::pvData::String getRecordName();
+    PVRecordStructurePtr getPVRecordStructure();
+    PVRecordFieldPtr findPVRecordField(
+        epics::pvData::PVFieldPtr const & pvField);
+    bool addRequester(epics::pvData::RequesterPtr const & requester);
+    bool removeRequester(epics::pvData::RequesterPtr const & requester);
+    inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
+    void lock();
+    void unlock();
+    bool tryLock();
+    void lockOtherRecord(PVRecordPtr const & otherRecord);
+    bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
+    bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
+    void detachClients();
+    bool addListener(PVListenerPtr const & pvListener);
+    bool removeListener(PVListenerPtr const & pvListener);
+    void beginGroupPut();
+    void endGroupPut();
+    epics::pvData::String getRequesterName() {return getRecordName();}
+    virtual void message(
+        epics::pvData::String const & message,
+        epics::pvData::MessageType messageType);
+    void message(
+        PVRecordFieldPtr const & pvRecordField,
+        epics::pvData::String const & message,
+        epics::pvData::MessageType messageType);
+    void toString(epics::pvData::StringBuilder buf);
+    void toString(epics::pvData::StringBuilder buf,int indentLevel);
+protected:
+    PVRecord(
+        epics::pvData::String const & recordName,
+        epics::pvData::PVStructurePtr const & pvStructure);
+    void initPVRecord();
+    epics::pvData::PVStructurePtr getPVStructure();
+    PVRecordPtr getPtrSelf()
+    {
+        return shared_from_this();
+    }
+private:
+...
+}
+
+

The methods are: +

+
init
+
Virtual method. +

Derived classes must implement this method. + This method Must call initPVRecord.

+
+
process
+
Virtual method. +

Derived classes must implement this method. + The base implementation does nothing.

+
+
create
+
Static method to create dumb records, i.e. records with a process method + that does nothing.
+
~PVRecord
+
The destructor which must be virtual. A derived class must also have + a virtual destructor.
+
destroy
+
This is a virtual method. +
+
getRecordName
+
Return the recordName.
+
getPVRecordStructure
+
Get the top level PVStructure.
+
findPVRecordField
+
Given a PVFieldPtr return the PVRecordFieldPtr for the field.
+
addRequester
+
Add a requester to receive messages.
+
removeRequester
+
Remove a message requester.
+
lock_guard
+
This is an inline method that locks the record. The record will automatically + be unlocked when control leaves the block that has the call. +
lock
+
unlock
+
Lock and Unlock the record. + Any code accessing the data in the record or calling other PVRecord methods + must have the record locked.
+
tryLock
+
If true then just like lock. + If falseclient can not access record. + A client can try to simultaneously hold the lock for more than two records + by calling this method. But must be willing to accept failure. +
+
lockOtherRecord
+
A client that holds the lock for one record can lock one other record. + A client must not call this if the client already has the lock for + more then one record. +
+
addPVRecordClient
+
Every client that accesses the record must call this so that the client can be notified when the record is deleted.
+
removePVRecordClient
+
Client is no longer accessing the record.
+
detachClients
+
Ask all clients to detach from the record
+
addListener
+
Add a PVListener. This must be called before calling pvRecordField.addListener.
+
removeListener
+
Removes a listener. The listener will also be removed from all fields to which it is attached.
+
beginGroupPut
+
Begin a group of puts. + This results in all registered PVListeners being called
+
endGroupPut
+
End a group of puts. + This results in all registered PVListeners being called.
+
getRequesterName
+
virtual method of Requester +
+
message
+
Can be called by implementation code. + The message will be sent to every requester.
+
toString
+
Just calls the top level PVStructure toString method.
+
PVRecord
+
The constructor. It requires a recordName and a top level PVStructure.
+
initPVRecord
+
This method must be called by derived class.
+
getPVStructure
+
Called by derived class.
+
+

class PVRecordField

+
+class PVRecordField {
+     public virtual epics::pvData::PostHandler,
+     public std::tr1::enable_shared_from_this<PVRecordField>
+public:
+    POINTER_DEFINITIONS(PVRecordField);
+    PVRecordField(
+        epics::pvData::PVFieldPtr const & pvField,
+        PVRecordStructurePtr const &parent,
+        PVRecordPtr const & pvRecord);
+    virtual ~PVRecordField();
+    virtual void destroy();
+    PVRecordStructurePtr getParent();
+    epics::pvData::PVFieldPtr getPVField();
+    epics::pvData::String getFullFieldName();
+    epics::pvData::String getFullName();
+    PVRecordPtr getPVRecord();
+    bool addListener(PVListenerPtr const & pvListener);
+    virtual void removeListener(PVListenerPtr const & pvListener);
+    virtual void postPut();
+    virtual void message(
+        epics::pvData::String const & message,
+        epics::pvData::MessageType messageType);
+protected:
+    PVRecordFieldPtr getPtrSelf()
+    {
+        return shared_from_this();
+    }
+    virtual void init();
+private:
+...
+};
+
+

When PVRecord is created it creates a PVRecordField for every field in the PVStructure +that holds the data. It has the following methods: +

+ +
+
PVRecordField
+
The constructor.
+
~PVRecordField
+
The destructor.
+
destroy
+
Called by PVRecordStructure when it's destroy method is called.
+
getParent
+
Get the parent PVRecordStructure for this field.
+
getPVField
+
Get the PVField associated with this PVRecordField.
+
getFullFieldName
+
This gets the full name of the field, i.e. field,field,..
+
getFullName
+
This gets recordName plus the full name of the field, i.e. recordName.field,field,..
+
getPVRecord
+
Returns the PVRecord to which this field belongs.
+
addListener
+
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.
+
removeListener
+
Remove a PVListener.
+
postPut
+
This is called by the code that implements the data interface. + It is called whenever the put method is called.
+
message
+
Called by implementation code. It calls PVRecord::message after prepending the full + fieldname.
+
+

class PVRecordStructure

+
+class PVRecordStructure : public PVRecordField {
+public:
+    POINTER_DEFINITIONS(PVRecordStructure);
+    PVRecordStructure(
+        epics::pvData::PVStructurePtr const & pvStructure,
+        PVRecordFieldPtrArrayPtr const & pvRecordField);
+    virtual ~PVRecordStructure();
+    virtual void destroy();
+    PVRecordFieldPtrArrayPtr getPVRecordFields();
+    epics::pvData::PVStructurePtr getPVStructure();
+    virtual void removeListener(PVListenerPtr const & pvListener);
+    virtual void postPut();
+protected:
+    virtual void init();
+private:
+...
+};
+
+

When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure +that holds the data. It has the following methods: +

+
+
PVRecordStructure
+
The constructor.
+
~PVRecordStructure
+
The destructor.
+
getPVRecordFields
+
Get the PVRecordField array for the subfields
+
getPVStructure
+
Get the PVStructure for this field.
+
removeListener
+
Remove a PVListener.
+
postPut
+
This is called by the code that implements the data interface. + It is called whenever the put method is called.
+

class PVRecordClient

+
+class PVRecordClient {
+    POINTER_DEFINITIONS(PVRecordClient);
+    virtual ~PVRecordClient();
+    virtual void detach(PVRecordPtr const & pvRecord);
+};
+
+

where

+
+
~PVRecordClient
+
The destructor.
+
detach
+
The record is being removed from the master database,
+
+
+

class PVListener

+
+class PVListener {
+    virtual public PVRecordClient
+public:
+    POINTER_DEFINITIONS(PVListener);
+    virtual ~PVListener();
+    virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
+    virtual void dataPut(
+        PVRecordStructurePtr const &
+        requested,PVRecordFieldPtr const & pvRecordField) = 0;
+    virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
+    virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
+};
+
+

where

+
+
~PVListener
+
The destructor.
+
dataPut(PVRecordFieldPtr const & pvRecordField)
+
pvField has been modified. + This is called if the listener has called PVRecordField::addListener for pvRecordField.
+
dataPut( + PVRecordStructurePtr const & + requested,PVRecordFieldPtr const & pvRecordField)
+
pvField has been modified. + Requested is the field to which the requester issued a pvField-&addListener. + This is called if the listener has called PVRecordField-&addListener for requested.
+
beginGroupPut
+
A related set of changes is being started.
+
endGroupPut
+
A related set of changes is done.
+
+

class PVDatabase

+
+class PVDatabase : virtual public epics::pvData::Requester {
+public:
+    POINTER_DEFINITIONS(PVDatabase);
+    static PVDatabasePtr getMaster();
+    virtual ~PVDatabase();
+    virtual void destroy();
+    PVRecordPtr findRecord(epics::pvData::String const& recordName);
+    bool addRecord(PVRecordPtr const & record);
+    bool removeRecord(PVRecordPtr const & record);
+    virtual epics::pvData::String getRequesterName();
+    virtual void message(
+        epics::pvData::String const &message,
+        epics::pvData::MessageType messageType);
+private:
+    PVDatabase();
+};
+
+

where

+
+
getMaster
+
Get the master database. This is the database that localChannelProvider access.
+
~PVDatabase
+
The destructor.
+
destroy
+
This is called by remote channelAccess when process exits. + This destroys and removes all records in the PVDatabase.
+
findRecord
+
Find a record. An empty pointer is returned if the record is not in the database.
+
addRecord
+
Add a record to the database. + If the record already exists it is not modified and false is returned.
+
removeRecord
+
Remove a record from the database. + If the record was not in the database false is returned.
+
getRequesterName
+
Virtual method of Requester
+
message
+
Virtual message of Requester.
+
+

pvAccess

+

Not yet described. +It is only of interest to someone who wants to understand how it works. +

+

A brief description is that it implements the following components of pvIOCJava:

+
+
pvCopy
+
monitor
+
local ChannelProvider and Channel
+
+ +
+ + diff --git a/src/Makefile b/src/Makefile index d98552a..3f5b37a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,9 +19,12 @@ LIBSRCS += recordList.cpp SRC_DIRS += $(DATABASE)/pvAccess INC += channelProviderLocal.h INC += pvCopy.h +INC += monitorAlgorithm.h LIBSRCS += channelProviderLocal.cpp LIBSRCS += channelLocal.cpp LIBSRCS += pvCopy.cpp +LIBSRCS += monitorFactory.cpp + include $(TOP)/configure/RULES diff --git a/src/database/exampleCounter.h b/src/database/exampleCounter.h index e6ce96e..3c8baab 100644 --- a/src/database/exampleCounter.h +++ b/src/database/exampleCounter.h @@ -11,6 +11,7 @@ #ifndef EXAMPLECOUNTER_H #define EXAMPLECOUNTER_H + #include #include #include diff --git a/src/database/pvDatabase.cpp b/src/database/pvDatabase.cpp index c13d696..9b6ee66 100644 --- a/src/database/pvDatabase.cpp +++ b/src/database/pvDatabase.cpp @@ -61,9 +61,13 @@ void PVDatabase::destroy() } } -void PVDatabase::lock() {thelock.lock();} +void PVDatabase::lock() { + thelock.lock(); +} -void PVDatabase::unlock() {thelock.unlock();} +void PVDatabase::unlock() { + thelock.unlock(); +} PVRecordPtr PVDatabase::findRecord(String const& recordName) { diff --git a/src/database/pvDatabase.h b/src/database/pvDatabase.h index 871d889..ad036a0 100644 --- a/src/database/pvDatabase.h +++ b/src/database/pvDatabase.h @@ -346,11 +346,14 @@ protected: return shared_from_this(); } virtual void init(); + virtual void postParent(PVRecordFieldPtr const & subField); + virtual void postSubField(); private: void callListener(); std::list pvListenerList; epics::pvData::PVFieldPtr pvField; + bool isStructure; PVRecordStructurePtr parent; PVRecordPtr pvRecord; epics::pvData::String fullName; @@ -470,6 +473,11 @@ public: * @param pvRecord The record. */ virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0; + /** + * Connection to record is being terminated. + * @param pvRecord The record. + */ + virtual void unlisten(PVRecordPtr const & pvRecord) = 0; }; /** diff --git a/src/database/pvRecord.cpp b/src/database/pvRecord.cpp index aa17bd0..a65eba5 100644 --- a/src/database/pvRecord.cpp +++ b/src/database/pvRecord.cpp @@ -169,11 +169,17 @@ PVRecordFieldPtr PVRecord::findPVRecordField( + pvField->getFieldName() + " not in PVRecord"); } -void PVRecord::lock() {thelock.lock();} +void PVRecord::lock() { + thelock.lock(); +} -void PVRecord::unlock() {thelock.unlock();} +void PVRecord::unlock() { + thelock.unlock(); +} -bool PVRecord::tryLock() {return thelock.tryLock();} +bool PVRecord::tryLock() { + return thelock.tryLock(); +} void PVRecord::lockOtherRecord(PVRecordPtr const & otherRecord) { @@ -347,6 +353,7 @@ PVRecordField::PVRecordField( PVRecordStructurePtr const &parent, PVRecordPtr const & pvRecord) : pvField(pvField), + isStructure(pvField->getField()->getType()==structure ? true : false), parent(parent), pvRecord(pvRecord) { @@ -419,15 +426,33 @@ void PVRecordField::removeListener(PVListenerPtr const & pvListener) void PVRecordField::postPut() { - callListener(); + if(parent!=NULL) { + parent->postParent(getPtrSelf()); + } + postSubField(); +} + +void PVRecordField::postParent(PVRecordFieldPtr const & subField) +{ + PVRecordStructurePtr pvrs = static_pointer_cast(getPtrSelf()); std::list::iterator iter; - PVRecordStructurePtr pvParent = getParent(); - while(pvParent.get()!=NULL) { - std::list list = pvParent->pvListenerList; - for (iter = list.begin(); iter!=list.end(); iter++ ) { - (*iter)->dataPut(pvParent,getPtrSelf()); + for(iter = pvListenerList.begin(); iter != pvListenerList.end(); ++iter) + { + (*iter)->dataPut(pvrs,subField); + } + if(parent!=NULL) parent->postParent(subField); +} + +void PVRecordField::postSubField() +{ + callListener(); + if(isStructure) { + PVRecordStructurePtr pvrs = static_pointer_cast(getPtrSelf()); + PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields(); + PVRecordFieldPtrArray::iterator iter; + for(iter = pvRecordFields->begin() ; iter !=pvRecordFields->end(); iter++) { + (*iter)->postSubField(); } - pvParent = pvParent->getParent(); } } diff --git a/src/pvAccess/channelLocal.cpp b/src/pvAccess/channelLocal.cpp index 881f8b9..723b99d 100644 --- a/src/pvAccess/channelLocal.cpp +++ b/src/pvAccess/channelLocal.cpp @@ -5,10 +5,16 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk + * @author Marty Kraimer + * @date 2013.04 */ +#include + +#include + #include +#include namespace epics { namespace pvDatabase { using namespace epics::pvData; @@ -16,6 +22,8 @@ using namespace epics::pvAccess; using std::tr1::static_pointer_cast; using std::tr1::dynamic_pointer_cast; +static ConvertPtr convert = getConvert(); + class ChannelProcessLocal; typedef std::tr1::shared_ptr ChannelProcessLocalPtr; class ChannelGetLocal; @@ -79,13 +87,15 @@ private: ChannelProcessLocal( ChannelLocalPtr const &channelLocal, ChannelProcessRequester::shared_pointer const & channelProcessRequester, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + int nProcess) : isDestroyed(false), channelLocal(channelLocal), channelProcessRequester(channelProcessRequester), pvRecord(pvRecord), - thelock(mutex) + thelock(mutex), + nProcess(nProcess) { thelock.unlock(); } @@ -96,6 +106,7 @@ private: PVRecordPtr pvRecord; Mutex mutex; Lock thelock; + int nProcess; }; ChannelProcessLocalPtr ChannelProcessLocal::create( @@ -104,10 +115,29 @@ ChannelProcessLocalPtr ChannelProcessLocal::create( PVStructurePtr const & pvRequest, PVRecordPtr const &pvRecord) { + PVFieldPtr pvField; + PVStructurePtr pvOptions; + int nProcess = 1; + if(pvRequest!=NULL) pvField = pvRequest->getSubField("record._options"); + if(pvField.get()!=NULL) { + pvOptions = static_pointer_cast(pvField); + pvField = pvOptions->getSubField("nProcess"); + if(pvField.get()!=NULL) { + PVStringPtr pvString = pvOptions->getStringField("nProcess"); + if(pvString.get()!=NULL) { + int size; + std::stringstream ss; + ss << pvString->get(); + ss >> size; + nProcess = size; + } + } + } ChannelProcessLocalPtr process(new ChannelProcessLocal( channelLocal, channelProcessRequester, - pvRecord)); + pvRecord, + nProcess)); channelLocal->addChannelProcess(process); channelProcessRequester->channelProcessConnect(Status::Ok, process); return process; @@ -126,9 +156,13 @@ void ChannelProcessLocal::destroy() void ChannelProcessLocal::process(bool lastRequest) { - pvRecord->lock(); - pvRecord->process(); - pvRecord->unlock(); + for(int i=0; i< nProcess; i++) { + pvRecord->lock(); + pvRecord->beginGroupPut(); + pvRecord->process(); + pvRecord->endGroupPut(); + pvRecord->unlock(); + } if(isDestroyed) { Status status( Status::Status::STATUSTYPE_ERROR, @@ -259,7 +293,11 @@ void ChannelGetLocal::get(bool lastRequest) } bitSet->clear(); pvRecord->lock(); - if(callProcess) pvRecord->process(); + if(callProcess) { + pvRecord->beginGroupPut(); + pvRecord->process(); + pvRecord->endGroupPut(); + } pvCopy->updateCopySetBitSet(pvStructure, bitSet, false); pvRecord->unlock(); if(firstTime) { @@ -404,8 +442,12 @@ void ChannelPutLocal::put(bool lastRequest) channelPutRequester->getDone(status); } pvRecord->lock(); + pvRecord->beginGroupPut(); pvCopy->updateRecord(pvStructure, bitSet, false); - if(callProcess) pvRecord->process(); + if(callProcess) { + pvRecord->process(); + } + pvRecord->endGroupPut(); pvRecord->unlock(); channelPutRequester->getDone(Status::Ok); if(lastRequest) destroy(); @@ -555,9 +597,11 @@ void ChannelPutGetLocal::putGet(bool lastRequest) putBitSet->clear(); putBitSet->set(0); pvRecord->lock(); + pvRecord->beginGroupPut(); pvPutCopy->updateRecord(pvPutStructure, putBitSet, false); if(callProcess) pvRecord->process(); pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet, false); + pvRecord->endGroupPut(); pvRecord->unlock(); getBitSet->clear(); getBitSet->set(0); @@ -597,23 +641,6 @@ void ChannelPutGetLocal::getGet() channelPutGetRequester->getGetDone(Status::Ok); } -class ChannelMonitorLocal : - public Monitor -{ -public: - POINTER_DEFINITIONS(ChannelMonitorLocal); - virtual ~ChannelMonitorLocal(); - static Monitor::shared_pointer create( - ChannelProviderLocalPtr const &channelProvider, - MonitorRequester::shared_pointer const & channelMonitorRequester, - PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord); - virtual Status start(); - virtual Status stop(); - virtual MonitorElementPtr poll(); - virtual void release(MonitorElementPtr const & monitorElement); -}; - class ChannelRPCLocal : public ChannelRPC { @@ -630,22 +657,6 @@ public: bool lastRequest); }; -class ChannelArrayLocal : - public ChannelArray -{ -public: - POINTER_DEFINITIONS(ChannelArrayLocal); - virtual ~ChannelArrayLocal(); - static ChannelArray::shared_pointer create( - ChannelProviderLocalPtr const &channelProvider, - ChannelArray::shared_pointer const & channelArrayRequester, - PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord); - virtual void putArray(bool lastRequest, int offset, int count); - virtual void getArray(bool lastRequest, int offset, int count); - virtual void setLength(bool lastRequest, int length, int capacity); -}; - int ChannelLocalDebugLevel = 0; void ChannelLocalDebug::setLevel(int level) {ChannelLocalDebugLevel = level;} int ChannelLocalDebug::getLevel() {return ChannelLocalDebugLevel;} @@ -1009,14 +1020,9 @@ Monitor::shared_pointer ChannelLocal::createMonitor( MonitorRequester::shared_pointer const &monitorRequester, PVStructure::shared_pointer const &pvRequest) { - Status status(Status::STATUSTYPE_ERROR, - String("ChannelMonitor not supported")); - Monitor::shared_pointer thisPointer = dynamic_pointer_cast(getPtrSelf()); - monitorRequester->monitorConnect( - status, - thisPointer, - StructureConstPtr()); - return Monitor::shared_pointer(); + MonitorPtr monitor = + getMonitorFactory()->createMonitor(pvRecord,monitorRequester,pvRequest); + return monitor; } ChannelArray::shared_pointer ChannelLocal::createChannelArray( diff --git a/src/pvAccess/channelProviderLocal.cpp b/src/pvAccess/channelProviderLocal.cpp index a292228..0373b66 100644 --- a/src/pvAccess/channelProviderLocal.cpp +++ b/src/pvAccess/channelProviderLocal.cpp @@ -5,7 +5,8 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk + * @author Marty Kraimer + * @date 2013.04 */ #include @@ -98,11 +99,17 @@ void LocalChannelCTX::run() } -ChannelProviderLocalPtr ChannelProviderLocal::create() +ChannelProviderLocalPtr getChannelProviderLocal() { - ChannelProviderLocalPtr channelProvider(new ChannelProviderLocal()); - LocalChannelCTX::create(channelProvider); - return channelProvider; + static ChannelProviderLocalPtr channelProviderLocal; + static Mutex mutex; + Lock xx(mutex); + if(channelProviderLocal.get()==NULL) { + channelProviderLocal = ChannelProviderLocalPtr( + new ChannelProviderLocal()); + LocalChannelCTX::create(channelProviderLocal); + } + return channelProviderLocal; } ChannelProviderLocal::ChannelProviderLocal() diff --git a/src/pvAccess/channelProviderLocal.h b/src/pvAccess/channelProviderLocal.h index 1ce8e85..c6f4a60 100644 --- a/src/pvAccess/channelProviderLocal.h +++ b/src/pvAccess/channelProviderLocal.h @@ -5,7 +5,8 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk + * @author Marty Kraimer + * @data 2013.04 */ #ifndef CHANNELPROVIDERLOCAL_H #define CHANNELPROVIDERLOCAL_H @@ -22,10 +23,13 @@ #include #include #include +#include namespace epics { namespace pvDatabase { +class MonitorFactory; +typedef std::tr1::shared_ptr MonitorFactoryPtr; class ChannelProviderLocal; typedef std::tr1::shared_ptr ChannelProviderLocalPtr; @@ -33,14 +37,45 @@ class ChannelLocal; typedef std::tr1::shared_ptr ChannelLocalPtr; typedef std::set ChannelLocalList; +extern MonitorFactoryPtr getMonitorFactory(); +class MonitorLocal; +typedef std::tr1::shared_ptr MonitorLocalPtr; +typedef std::set MonitorLocalList; + + +class MonitorFactory +{ +public: + POINTER_DEFINITIONS(MonitorFactory); + virtual ~MonitorFactory(); + virtual void destroy(); + epics::pvData::MonitorPtr createMonitor( + PVRecordPtr const & pvRecord, + epics::pvData::MonitorRequester::shared_pointer const & monitorRequester, + epics::pvData::PVStructurePtr const & pvRequest); + void registerMonitorAlgorithmCreate( + MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate); + MonitorAlgorithmCreatePtr getMonitorAlgorithmCreate(epics::pvData::String algorithmName); +private: + MonitorFactory(); + void removeMonitor(MonitorLocal * monitor); + friend class MonitorLocal; + friend MonitorFactoryPtr getMonitorFactory(); + std::set monitorAlgorithmCreateList; + std::set monitorLocalList; + bool isDestroyed; + epics::pvData::Mutex mutex; +}; + + +extern ChannelProviderLocalPtr getChannelProviderLocal(); + class ChannelProviderLocal : public epics::pvAccess::ChannelProvider, public std::tr1::enable_shared_from_this { public: POINTER_DEFINITIONS(ChannelProviderLocal); - - static ChannelProviderLocalPtr create(); virtual ~ChannelProviderLocal(); virtual void destroy(); virtual epics::pvData::String getProviderName(); @@ -64,7 +99,7 @@ private: return shared_from_this(); } ChannelProviderLocal(); - + friend ChannelProviderLocalPtr getChannelProviderLocal(); PVDatabasePtr pvDatabase; ChannelLocalList channelList; epics::pvData::Mutex mutex; diff --git a/src/pvAccess/monitorAlgorithm.h b/src/pvAccess/monitorAlgorithm.h index 420b7f6..8355a43 100644 --- a/src/pvAccess/monitorAlgorithm.h +++ b/src/pvAccess/monitorAlgorithm.h @@ -4,35 +4,55 @@ * EPICS pvData is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ -/* Marty Kraimer 2011.03 */ +/** + * @author Marty Kraimer + * @data 2013.04 + */ #ifndef MONITORALGORITHM_H #define MONITORALGORITHM_H -#include -#include +#include -namespace epics { namespace pvIOC { +namespace epics { namespace pvDatabase { -class MonitorAlgorithm { +class MonitorAlgorithm; +typedef std::tr1::shared_ptr MonitorAlgorithmPtr; +class MonitorAlgorithmCreate; +typedef std::tr1::shared_ptr MonitorAlgorithmCreatePtr; + +class MonitorAlgorithm +{ public: - MonitorAlgorithm(){} - virtual ~MonitorAlgorithm(){} - virtual epics::pvData::String getAlgorithmName() = 0; - virtual bool causeMonitor() = 0; - void monitorIssued() = 0; -}} - -class MonitorAlgorithmCreate { -public: - virtual String getAlgorithmName() = 0; - virtual std::auto_ptr create( - PVRecord &pvRecord; - MonitorRequester &requester; - PVRecordField &pvRecordField; - PVStructure &pvStructure); + POINTER_DEFINITIONS(MonitorAlgorithm); + virtual ~MonitorAlgorithm(){} + virtual epics::pvData::String getAlgorithmName(){return algorithmName;} + virtual bool causeMonitor() = 0; + virtual void monitorIssued() = 0; +protected: + MonitorAlgorithm(epics::pvData::String algorithmName) + : algorithmName(algorithmName) + {} + epics::pvData::String algorithmName; }; -extern MonitorAlgorithmCreate& getAlgorithmDeadband(); -extern MonitorAlgorithmCreate& getAlgorithmOnChange(); +class MonitorAlgorithmCreate +{ +public: + POINTER_DEFINITIONS(MonitorAlgorithmCreate); + virtual ~MonitorAlgorithmCreate(){} + virtual epics::pvData::String getAlgorithmName(){return algorithmName;} + virtual MonitorAlgorithmPtr create( + PVRecordPtr const &pvRecord, + epics::pvData::MonitorRequester::shared_pointer const &requester, + PVRecordFieldPtr const &fromPVRecord, + epics::pvData::PVStructurePtr const &pvOptions) = 0; +protected: + MonitorAlgorithmCreate(epics::pvData::String algorithmName) + : algorithmName(algorithmName) + {} + epics::pvData::String algorithmName; +}; + +}} #endif /* MONITORALGORITHM_H */ diff --git a/src/pvAccess/monitorFactory.cpp b/src/pvAccess/monitorFactory.cpp new file mode 100644 index 0000000..fefc71b --- /dev/null +++ b/src/pvAccess/monitorFactory.cpp @@ -0,0 +1,541 @@ +/* monitorFactory.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 + +#include +#include +#include +#include + +namespace epics { namespace pvDatabase { +using namespace epics::pvData; +using namespace epics::pvAccess; +using std::tr1::static_pointer_cast; +using std::tr1::dynamic_pointer_cast; + +static MonitorAlgorithmCreatePtr nullMonitorAlgorithmCreate; +static MonitorPtr nullMonitor; +static MonitorElementPtr NULLMonitorElement; + +static ConvertPtr convert = getConvert(); + +//class MonitorFieldNode; +//typedef std::tr1::shared_ptr MonitorFieldNodePtr; + +class MonitorQueue; +typedef std::tr1::shared_ptr MonitorQueuePtr; +class NOQueue; +typedef std::tr1::shared_ptr NOQueuePtr; +class RealQueue; +typedef std::tr1::shared_ptr RealQueuePtr; + +class MonitorLocal; +typedef std::tr1::shared_ptr MonitorLocalPtr; + +//class MonitorFieldNode +//{ +//public: +// MonitorAlgorithmPtr monitorAlgorithm; +// size_t bitOffset; // pv pvCopy +//}; + +class MonitorQueue : + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(MonitorQueue); + virtual ~MonitorQueue(){} + virtual Status start() = 0; + virtual void stop() = 0; + virtual bool dataChanged() = 0; + virtual MonitorElementPtr poll() = 0; + virtual void release(MonitorElementPtr const &monitorElement) = 0; +protected: + MonitorQueuePtr getPtrSelf() + { + return shared_from_this(); + } +}; + +class NOQueue : + public MonitorQueue +{ +public: + POINTER_DEFINITIONS(NOQueue); + virtual ~NOQueue(){} + NOQueue( + MonitorLocalPtr const &monitorLocal); + + virtual Status start(); + virtual void stop(); + virtual bool dataChanged(); + virtual MonitorElementPtr poll(); + virtual void release(MonitorElementPtr const &monitorElement); +private: + MonitorLocalPtr monitorLocal; + PVStructurePtr pvCopyStructure; + MonitorElementPtr monitorElement; + bool gotMonitor; + bool wasReleased; + BitSetPtr changedBitSet; + BitSetPtr overrunBitSet; + Mutex mutex; +}; + +class RealQueue : + public MonitorQueue +{ +public: + POINTER_DEFINITIONS(RealQueue); + virtual ~RealQueue(){} + RealQueue( + MonitorLocalPtr const &monitorLocal, + std::vector &monitorElementArray); + virtual Status start(); + virtual void stop(); + virtual bool dataChanged(); + virtual MonitorElementPtr poll(); + virtual void release(MonitorElementPtr const &monitorElement); +private: + MonitorLocalPtr monitorLocal; + Queue queue; + bool queueIsFull; + MonitorElementPtr monitorElement; + Mutex mutex; +}; + + +class MonitorLocal : + public Monitor, + public PVCopyMonitorRequester, + public std::tr1::enable_shared_from_this +{ +public: + POINTER_DEFINITIONS(MonitorLocal); + virtual ~MonitorLocal(); + virtual Status start(); + virtual Status stop(); + virtual MonitorElementPtr poll(); + virtual void destroy(); + virtual void dataChanged(); + virtual void unlisten(); + virtual void release(MonitorElementPtr const & monitorElement); + bool init(PVStructurePtr const & pvRequest); + MonitorLocal( + ChannelProviderLocalPtr const &channelProvider, + MonitorRequester::shared_pointer const & channelMonitorRequester, + PVRecordPtr const &pvRecord); + PVCopyPtr getPVCopy() { return pvCopy;} + PVCopyMonitorPtr getPVCopyMonitor() { return pvCopyMonitor;} +private: + MonitorLocalPtr getPtrSelf() + { + return shared_from_this(); + } + PVRecordPtr pvRecord; + MonitorRequester::shared_pointer monitorRequester; + bool isDestroyed; + bool firstMonitor; + PVCopyPtr pvCopy; + MonitorQueuePtr queue; + PVCopyMonitorPtr pvCopyMonitor; +// std::list monitorFieldList; + Mutex mutex; +}; + +MonitorLocal::MonitorLocal( + ChannelProviderLocalPtr const &channelProvider, + MonitorRequester::shared_pointer const & channelMonitorRequester, + PVRecordPtr const &pvRecord) +: pvRecord(pvRecord), + monitorRequester(channelMonitorRequester), + isDestroyed(false), + firstMonitor(true) +{ +} + +MonitorLocal::~MonitorLocal() +{ + destroy(); +} + +void MonitorLocal::destroy() +{ +//std::cout << "MonitorLocal::destroy " << isDestroyed << std::endl; + { + Lock xx(mutex); + if(isDestroyed) return; + isDestroyed = true; + } + stop(); +// monitorFieldList.clear(); + pvCopyMonitor.reset(); + queue.reset(); + pvCopy.reset(); + monitorRequester.reset(); + pvRecord.reset(); +} + +Status MonitorLocal::start() +{ +//std::cout << "MonitorLocal::start" << std::endl; + firstMonitor = true; + return queue->start(); +} + +Status MonitorLocal::stop() +{ +//std::cout << "MonitorLocal::stop" << std::endl; + pvCopyMonitor->stopMonitoring(); + queue->stop(); + return Status::Ok; +} + +MonitorElementPtr MonitorLocal::poll() +{ +//std::cout << "MonitorLocal::poll" << std::endl; + return queue->poll(); +} + +void MonitorLocal::dataChanged() +{ +//std::cout << "MonitorLocal::dataChanged" << std::endl; + if(firstMonitor) { + queue->dataChanged(); + firstMonitor = false; + monitorRequester->monitorEvent(getPtrSelf()); + return; + } + if(queue->dataChanged()) { + monitorRequester->monitorEvent(getPtrSelf()); + } +} + +void MonitorLocal::unlisten() +{ +//std::cout << "MonitorLocal::unlisten" << std::endl; + monitorRequester->unlisten(getPtrSelf()); +} + +void MonitorLocal::release(MonitorElementPtr const & monitorElement) +{ +//std::cout << "MonitorLocal::release" << std::endl; + queue->release(monitorElement); +} + +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(pvField); + pvField = pvOptions->getSubField("queueSize"); + if(pvField.get()!=NULL) { + PVStringPtr pvString = pvOptions->getStringField("queueSize"); + if(pvString.get()!=NULL) { + int32 size; + std::stringstream ss; + ss << pvString->get(); + ss >> size; + queueSize = size; + } + } + } + if(queueSize==1) { + monitorRequester->message("queueSize can not be 1",errorMessage); + return false; + } + pvField = pvRequest->getSubField("field"); + if(pvField.get()==NULL) { + pvCopy = PVCopy::create(pvRecord,pvRequest,""); + if(pvCopy.get()==NULL) { + monitorRequester->message("illegal pvRequest",errorMessage); + return false; + } + } else { + if(pvField->getField()->getType()!=structure) { + monitorRequester->message("illegal pvRequest",errorMessage); + return false; + } + pvCopy = PVCopy::create(pvRecord,pvRequest,"field"); + if(pvCopy.get()==NULL) { + monitorRequester->message("illegal pvRequest",errorMessage); + return false; + } + } + pvCopyMonitor = pvCopy->createPVCopyMonitor(getPtrSelf()); + // MARTY MUST IMPLEMENT periodic + if(queueSize==0) { + queue = NOQueuePtr(new NOQueue(getPtrSelf())); + } else { + std::vector monitorElementArray; + monitorElementArray.reserve(queueSize); + for(size_t i=0; icreatePVStructure(); + MonitorElementPtr monitorElement( + new MonitorElement(pvStructure)); + monitorElementArray.push_back(monitorElement); + } + queue = RealQueuePtr(new RealQueue(getPtrSelf(),monitorElementArray)); + } + // MARTY MUST IMPLEMENT algorithm + monitorRequester->monitorConnect( + Status::Ok, + getPtrSelf(), + pvCopy->getStructure()); + return true; +} + + +MonitorFactory::MonitorFactory() +: isDestroyed(false) +{ +} + +MonitorFactory::~MonitorFactory() +{ +} + +void MonitorFactory::destroy() +{ +//std::cout << "MonitorFactory::destroy " << isDestroyed << std::endl; + Lock lock(mutex); + if(isDestroyed) return; + isDestroyed = true; + while(true) { + std::set::iterator it; + it = monitorLocalList.begin(); + if(it==monitorLocalList.end()) break; + monitorLocalList.erase(it); + lock.unlock(); + it->get()->destroy(); + lock.lock(); + } +} + +MonitorPtr MonitorFactory::createMonitor( + PVRecordPtr const & pvRecord, + MonitorRequester::shared_pointer const & monitorRequester, + PVStructurePtr const & pvRequest) +{ + Lock xx(mutex); + if(isDestroyed) { + monitorRequester->message("MonitorFactory is destroyed",errorMessage); + return nullMonitor; + } + MonitorLocalPtr monitor(new MonitorLocal( + getChannelProviderLocal(),monitorRequester,pvRecord)); + bool result = monitor->init(pvRequest); + if(!result) return nullMonitor; + monitorLocalList.insert(monitor); + return monitor; +} + +void MonitorFactory::removeMonitor(MonitorLocal * monitor) +{ +//std::cout << "MonitorFactory::removeMonitor" << std::endl; + Lock xx(mutex); + if(isDestroyed) return; + std::set::iterator iter; + for (iter = monitorLocalList.begin(); iter!= monitorLocalList.end(); ++iter) { + if(iter->get()==monitor) { + monitorLocalList.erase(iter); + return; + } + } +} + +void MonitorFactory::registerMonitorAlgorithmCreate( + MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate) +{ + Lock xx(mutex); + if(isDestroyed) return; +// monitorAlgorithmCreateList.insert(monitorAlgorithmCreate); +} + +MonitorAlgorithmCreatePtr MonitorFactory::getMonitorAlgorithmCreate( + String algorithmName) +{ + Lock xx(mutex); + if(isDestroyed) return nullMonitorAlgorithmCreate; +// std::set::iterator iter; +// for(iter = monitorAlgorithmCreateList.begin(); +// iter!= monitorAlgorithmCreateList.end(); +// ++iter) +// { +// if((*iter)->getAlgorithmName().compare(algorithmName)) +// return *iter; +// } + return nullMonitorAlgorithmCreate; +} + +NOQueue::NOQueue( + MonitorLocalPtr const &monitorLocal) +: monitorLocal(monitorLocal), + pvCopyStructure(monitorLocal->getPVCopy()->createPVStructure()), + monitorElement(new MonitorElement(pvCopyStructure)), + gotMonitor(false), + wasReleased(false), + changedBitSet(new BitSet(pvCopyStructure->getNumberFields())), + overrunBitSet(new BitSet(pvCopyStructure->getNumberFields())) +{ + monitorElement->pvStructurePtr = pvCopyStructure; + monitorElement->changedBitSet = + BitSetPtr(new BitSet(pvCopyStructure->getNumberFields())); + monitorElement->overrunBitSet = + BitSetPtr(new BitSet(pvCopyStructure->getNumberFields())); +} + +Status NOQueue::start() +{ + Lock xx(mutex); + gotMonitor = true; + wasReleased = true; + changedBitSet->clear(); + overrunBitSet->clear(); + monitorLocal->getPVCopyMonitor()->startMonitoring( + monitorElement->changedBitSet, + monitorElement->overrunBitSet); + return Status::Ok; +} + +void NOQueue::stop() +{ +} + +bool NOQueue::dataChanged() +{ + Lock xx(mutex); + (*changedBitSet) |= (*monitorElement->changedBitSet); + (*overrunBitSet) |= (*monitorElement->overrunBitSet); + gotMonitor = true; + return wasReleased ? true : false; +} + +MonitorElementPtr NOQueue::poll() +{ + Lock xx(mutex); + if(!gotMonitor) return NULLMonitorElement; + BitSetPtr changed = monitorElement->changedBitSet; + BitSetPtr overrun = monitorElement->overrunBitSet; + (*changed) |= (*changedBitSet); + (*overrun) |= (*overrunBitSet); + monitorLocal->getPVCopy()->updateCopyFromBitSet( + pvCopyStructure, changed,true); + BitSetUtil::compress(changed,pvCopyStructure); + BitSetUtil::compress(overrun,pvCopyStructure); + changedBitSet->clear(); + overrunBitSet->clear(); + return monitorElement; +} + +void NOQueue::release(MonitorElementPtr const &monitorElement) +{ + Lock xx(mutex); + gotMonitor = false; + monitorElement->changedBitSet->clear(); + monitorElement->overrunBitSet->clear(); +} + +RealQueue::RealQueue( + MonitorLocalPtr const &monitorLocal, + std::vector &monitorElementArray) +: monitorLocal(monitorLocal), + queue(monitorElementArray), + queueIsFull(false) +{ +} + +Status RealQueue::start() +{ + Lock xx(mutex); + queue.clear(); + monitorElement = queue.getFree(); + monitorElement->changedBitSet->clear(); + monitorElement->overrunBitSet->clear(); + monitorLocal->getPVCopyMonitor()->startMonitoring( + monitorElement->changedBitSet, + monitorElement->overrunBitSet); + return Status::Ok; +} + +void RealQueue::stop() +{ +} + +bool RealQueue::dataChanged() +{ + Lock xx(mutex); + PVStructurePtr pvStructure = monitorElement->pvStructurePtr; + monitorLocal->getPVCopy()->updateCopyFromBitSet( + pvStructure,monitorElement->changedBitSet,false); + MonitorElementPtr newElement = queue.getFree(); + if(newElement==NULL) { + queueIsFull = true; + return true; + } + BitSetUtil::compress(monitorElement->changedBitSet,pvStructure); + BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure); + convert->copy(pvStructure,newElement->pvStructurePtr); + newElement->changedBitSet->clear(); + newElement->overrunBitSet->clear(); + monitorLocal->getPVCopyMonitor()->switchBitSets( + newElement->changedBitSet,newElement->overrunBitSet,false); + queue.setUsed(monitorElement); + monitorElement = newElement; + return true; +} + +MonitorElementPtr RealQueue::poll() +{ + Lock xx(mutex); + return queue.getUsed(); +} + +void RealQueue::release(MonitorElementPtr const ¤tElement) +{ + Lock xx(mutex); + queue.releaseUsed(currentElement); + currentElement->changedBitSet->clear(); + currentElement->overrunBitSet->clear(); + if(!queueIsFull) return; + queueIsFull = false; + PVStructurePtr pvStructure = monitorElement->pvStructurePtr; + MonitorElementPtr newElement = queue.getFree(); + BitSetUtil::compress(monitorElement->changedBitSet,pvStructure); + BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure); + convert->copy(pvStructure,newElement->pvStructurePtr); + newElement->changedBitSet->clear(); + newElement->overrunBitSet->clear(); + monitorLocal->getPVCopyMonitor()->switchBitSets( + newElement->changedBitSet,newElement->overrunBitSet,false); + queue.setUsed(monitorElement); + monitorElement = newElement; + +} + +MonitorFactoryPtr getMonitorFactory() +{ + static MonitorFactoryPtr monitorFactoryPtr; + static Mutex mutex; + Lock xx(mutex); + + if(monitorFactoryPtr.get()==NULL) { + monitorFactoryPtr = MonitorFactoryPtr( + new MonitorFactory()); + } + return monitorFactoryPtr; +} + +}} diff --git a/src/pvAccess/pvCopy.cpp b/src/pvAccess/pvCopy.cpp index daf3430..40b4150 100644 --- a/src/pvAccess/pvCopy.cpp +++ b/src/pvAccess/pvCopy.cpp @@ -5,11 +5,13 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk + * @author Marty Kraimer + * @date 2013.04 */ #include #include #include +#include #include @@ -23,8 +25,8 @@ static PVCopyPtr NULLPVCopy; static FieldConstPtr NULLField; static StructureConstPtr NULLStructure; static PVStructurePtr NULLPVStructure; -static CopyNodePtr NULLCopyNodePtr; -static CopyRecordNodePtr NULLCopyRecordNodePtr; +static CopyNodePtr NULLCopyNode; +static CopyRecordNodePtr NULLCopyRecordNode; struct CopyNode { CopyNode() @@ -48,10 +50,6 @@ typedef std::vector CopyNodePtrArray; typedef std::tr1::shared_ptr CopyNodePtrArrayPtr; struct CopyStructureNode : public CopyNode { -// CopyStructureNode(size_t numNodes) -// : nodes(CopyNodePtrArrayPtr(new CopyNodePtrArray(numNodes))) -// { -// } CopyNodePtrArrayPtr nodes; }; @@ -92,7 +90,11 @@ StructureConstPtr PVCopy::getStructure() PVStructurePtr PVCopy::createPVStructure() { - if(cacheInitStructure.get()!=NULL) return cacheInitStructure; + if(cacheInitStructure.get()!=NULL) { + PVStructurePtr save = cacheInitStructure; + cacheInitStructure.reset(); + return save; + } PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure); return pvStructure; @@ -279,12 +281,51 @@ void PVCopy::updateRecord( PVCopyMonitorPtr PVCopy::createPVCopyMonitor( PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester) { - throw std::logic_error(String("Not Implemented")); + PVCopyMonitorPtr pvCopyMonitor( new PVCopyMonitor( + pvRecord,headNode,getPtrSelf(),pvCopyMonitorRequester)); + return pvCopyMonitor; } epics::pvData::String PVCopy::dump() { - throw std::logic_error(String("Not Implemented")); + String builder; + dump(&builder,headNode,0); + return builder; +} + +void PVCopy::dump(String *builder,CopyNodePtr const &node,int indentLevel) +{ + getConvert()->newLine(builder,indentLevel); + std::stringstream ss; + ss << (node->isStructure ? "structureNode" : "recordNode"); + ss << " structureOffset " << node->structureOffset; + ss << " nfields " << node->nfields; + *builder += ss.str(); + PVStructurePtr options = node->options; + if(options.get()!=NULL) { + getConvert()->newLine(builder,indentLevel +1); + options->toString(builder); + getConvert()->newLine(builder,indentLevel); + } + if(!node->isStructure) { + CopyRecordNodePtr recordNode = static_pointer_cast(node); + String name = recordNode->recordPVField->getFullName(); + *builder += " recordField " + name; + return; + } + CopyStructureNodePtr structureNode = + static_pointer_cast(node); + CopyNodePtrArrayPtr nodes = structureNode->nodes; + for(size_t i=0; isize(); ++i) { + if((*nodes)[i].get()==NULL) { + getConvert()->newLine(builder,indentLevel +1); + ss.str(""); + ss << "node[" << i << "] is null"; + *builder += ss.str(); + continue; + } + dump(builder,(*nodes)[i],indentLevel+1); + } } bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest) @@ -589,7 +630,7 @@ CopyNodePtr PVCopy::createStructureNodes( nameFromRecord = getFullName(pvFromRequest,nameFromRecord); PVFieldPtr pvField = pvRecordStructure-> getPVStructure()->getSubField(nameFromRecord); - if(pvField.get()==NULL) return NULLCopyNodePtr; + if(pvField.get()==NULL) return NULLCopyNode; PVRecordFieldPtr pvRecordField = pvRecordStructure-> getPVRecord()->findPVRecordField(pvField); size_t structureOffset = pvFromField->getFieldOffset(); @@ -650,7 +691,7 @@ CopyNodePtr PVCopy::createStructureNodes( ++indFromStructure; } size_t len = nodes->size(); - if(len==String::npos) return NULLCopyNodePtr; + if(len==String::npos) return NULLCopyNode; CopyStructureNodePtr structureNode(new CopyStructureNode()); structureNode->isStructure = true; structureNode->nodes = nodes; @@ -915,7 +956,7 @@ CopyRecordNodePtr PVCopy::getCopyOffset( if(recordNode.get()!=NULL) return recordNode; } } - return NULLCopyRecordNodePtr; + return NULLCopyRecordNode; } CopyRecordNodePtr PVCopy::getRecordNode( @@ -935,37 +976,163 @@ CopyRecordNodePtr PVCopy::getRecordNode( static_pointer_cast(node); return getRecordNode(subNode,structureOffset); } - return NULLCopyRecordNodePtr; + return NULLCopyRecordNode; } - -PVCopyMonitor::PVCopyMonitor() +PVCopyMonitor::PVCopyMonitor( + PVRecordPtr const &pvRecord, + CopyNodePtr const &headNode, + PVCopyPtr const &pvCopy, + PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester +) +: pvRecord(pvRecord), + headNode(headNode), + pvCopy(pvCopy), + pvCopyMonitorRequester(pvCopyMonitorRequester), + isGroupPut(false), + dataChanged(false) { - throw std::logic_error(String("Not Implemented")); } PVCopyMonitor::~PVCopyMonitor() { - throw std::logic_error(String("Not Implemented")); + pvRecord.reset(); + headNode.reset(); + pvCopy.reset(); + pvCopyMonitorRequester.reset(); + changeBitSet.reset(); + overrunBitSet.reset(); } void PVCopyMonitor::startMonitoring( BitSetPtr const &changeBitSet, BitSetPtr const &overrunBitSet) { - throw std::logic_error(String("Not Implemented")); + this->changeBitSet = changeBitSet; + this->overrunBitSet = overrunBitSet; + isGroupPut = false; + pvRecord->addListener(getPtrSelf()); + addListener(headNode); + pvRecord->lock(); + try { + changeBitSet->clear(); + overrunBitSet->clear(); + changeBitSet->set(0); + pvCopyMonitorRequester->dataChanged(); + pvRecord->unlock(); + } catch(...) { + pvRecord->unlock(); + } } void PVCopyMonitor::stopMonitoring() { - throw std::logic_error(String("Not Implemented")); + pvRecord->removeListener(getPtrSelf()); } void PVCopyMonitor::switchBitSets( BitSetPtr const &newChangeBitSet, - BitSetPtr const &newOverrunBitSet, bool lockRecord) + BitSetPtr const &newOverrunBitSet, + bool lockRecord) { - throw std::logic_error(String("Not Implemented")); + if(lockRecord) pvRecord->lock(); + try { + changeBitSet = newChangeBitSet; + overrunBitSet = newOverrunBitSet; + if(lockRecord) pvRecord->unlock(); + } catch(...) { + if(lockRecord) pvRecord->unlock(); + } +} + +void PVCopyMonitor::detach(PVRecordPtr const & pvRecord) +{ +} + +void PVCopyMonitor::dataPut(PVRecordFieldPtr const & pvRecordField) +{ + CopyNodePtr node = findNode(headNode,pvRecordField); + if(node.get()==NULL) { + throw std::logic_error("Logic error"); + } + size_t offset = node->structureOffset; + bool isSet = changeBitSet->get(offset); + changeBitSet->set(offset); + if(isSet) overrunBitSet->set(offset); + if(!isGroupPut) pvCopyMonitorRequester->dataChanged(); + dataChanged = true; +} + +void PVCopyMonitor::dataPut( + PVRecordStructurePtr const & requested, + PVRecordFieldPtr const & pvRecordField) +{ + CopyNodePtr node = findNode(headNode,requested); + if(node.get()==NULL || node->isStructure) { + throw std::logic_error("Logic error"); + } + CopyRecordNodePtr recordNode = static_pointer_cast(node); + size_t offset = recordNode->structureOffset + + (pvRecordField->getPVField()->getFieldOffset() + - recordNode->recordPVField->getPVField()->getFieldOffset()); + bool isSet = changeBitSet->get(offset); + changeBitSet->set(offset); + if(isSet) overrunBitSet->set(offset); + if(!isGroupPut) pvCopyMonitorRequester->dataChanged(); + dataChanged = true; +} + +void PVCopyMonitor::beginGroupPut(PVRecordPtr const & pvRecord) +{ + isGroupPut = true; + dataChanged = false; +} + +void PVCopyMonitor::endGroupPut(PVRecordPtr const & pvRecord) +{ + isGroupPut = false; + if(dataChanged) { + dataChanged = false; + pvCopyMonitorRequester->dataChanged(); + } +} + +void PVCopyMonitor::unlisten(PVRecordPtr const & pvRecord) +{ + pvCopyMonitorRequester->unlisten(); +} + + +void PVCopyMonitor::addListener(CopyNodePtr const & node) +{ + if(!node->isStructure) { + PVRecordFieldPtr pvRecordField = + pvCopy->getRecordPVField(node->structureOffset); + pvRecordField->addListener(getPtrSelf()); + return; + } + CopyStructureNodePtr structureNode = + static_pointer_cast(node); + for(size_t i=0; i< structureNode->nodes->size(); i++) { + addListener((*structureNode->nodes)[i]); + } +} + +CopyNodePtr PVCopyMonitor::findNode( + CopyNodePtr const & node, + PVRecordFieldPtr const & pvRecordField) +{ + if(!node->isStructure) { + CopyRecordNodePtr recordNode = static_pointer_cast(node); + if(recordNode->recordPVField==pvRecordField) return node; + return NULLCopyNode; + } + CopyStructureNodePtr structureNode = static_pointer_cast(node); + for(size_t i=0; inodes->size(); i++) { + CopyNodePtr xxx = findNode((*structureNode->nodes)[i],pvRecordField); + if(xxx.get()!=NULL) return xxx; + } + return NULLCopyNode; } }} diff --git a/src/pvAccess/pvCopy.h b/src/pvAccess/pvCopy.h index 4463c19..c408491 100644 --- a/src/pvAccess/pvCopy.h +++ b/src/pvAccess/pvCopy.h @@ -5,8 +5,8 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk - * @date 2013.03.25 + * @author Marty Kraimer + * @date 2013.04 */ #ifndef PVCOPY_H #define PVCOPY_H @@ -81,6 +81,10 @@ public: epics::pvData::PVStructurePtr const ©PVStructure,std::size_t fieldOffset); epics::pvData::String dump(); private: + void dump( + epics::pvData::String *builder, + CopyNodePtr const &node, + int indentLevel); PVCopyPtr getPtrSelf() { return shared_from_this(); @@ -92,6 +96,7 @@ private: epics::pvData::PVStructurePtr cacheInitStructure; private: PVCopy(PVRecordPtr const &pvRecord); + friend class PVCopyMonitor; bool init(epics::pvData::PVStructurePtr const &pvRequest); epics::pvData::String dump( epics::pvData::String const &value, @@ -154,7 +159,8 @@ private: }; -class PVCopyMonitor : +class PVCopyMonitor : + public PVListener, public std::tr1::enable_shared_from_this { public: @@ -167,28 +173,46 @@ public: void switchBitSets( epics::pvData::BitSetPtr const &newChangeBitSet, epics::pvData::BitSetPtr const &newOverrunBitSet, bool lockRecord); + // following are PVListener methods + virtual void detach(PVRecordPtr const & pvRecord); + 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); private: + void addListener(CopyNodePtr const & node); + CopyNodePtr findNode( + CopyNodePtr const & node, + PVRecordFieldPtr const & pvRecordField); PVCopyMonitorPtr getPtrSelf() { return shared_from_this(); } - PVCopyMonitor(); + PVCopyMonitor( + PVRecordPtr const &pvRecord, + CopyNodePtr const &headNode, + PVCopyPtr const &pvCopy, + PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester); friend class PVCopy; - // TBD + PVRecordPtr pvRecord; + CopyNodePtr headNode; + PVCopyPtr pvCopy; + PVCopyMonitorRequesterPtr pvCopyMonitorRequester; + epics::pvData::BitSetPtr changeBitSet; + epics::pvData::BitSetPtr overrunBitSet; + bool isGroupPut; + bool dataChanged; }; -class PVCopyMonitorRequester : - public std::tr1::enable_shared_from_this +class PVCopyMonitorRequester { public: POINTER_DEFINITIONS(PVCopyMonitorRequester); virtual void dataChanged() = 0; virtual void unlisten() = 0; -private: - PVCopyMonitorRequesterPtr getPtrSelf() - { - return shared_from_this(); - } }; diff --git a/src/pvAccess/pvShare.cpp b/src/pvAccess/pvShare.cpp index f24dd19..1f655e9 100644 --- a/src/pvAccess/pvShare.cpp +++ b/src/pvAccess/pvShare.cpp @@ -5,7 +5,8 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk + * @author Marty Kraimer + * @date 2013.04 */ #include #include @@ -18,7 +19,7 @@ #include #include -namespace epics { namespace pvIOC { +namespace epics { namespace pvDatabase { using namespace epics::pvData; diff --git a/src/pvAccess/pvShareStructureArray.cpp b/src/pvAccess/pvShareStructureArray.cpp index 451680f..a5fa3b1 100644 --- a/src/pvAccess/pvShareStructureArray.cpp +++ b/src/pvAccess/pvShareStructureArray.cpp @@ -5,7 +5,8 @@ * in file LICENSE that is included with this distribution. */ /** - * @author mrk + * @author Marty Kraimer + * @date 2013.04 */ #include #include @@ -18,7 +19,7 @@ #include #include -namespace epics { namespace pvIOC { +namespace epics { namespace pvDatabase { using namespace epics::pvData; diff --git a/test/server/exampleCounterMain.cpp b/test/server/exampleCounterMain.cpp index 460f9a3..f42c029 100644 --- a/test/server/exampleCounterMain.cpp +++ b/test/server/exampleCounterMain.cpp @@ -32,7 +32,7 @@ using namespace epics::pvDatabase; int main(int argc,char *argv[]) { PVDatabasePtr master = PVDatabase::getMaster(); - ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create(); + ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); String recordName("exampleCounter"); PVRecordPtr pvRecord = ExampleCounter::create(recordName); bool result = master->addRecord(pvRecord); diff --git a/test/server/testExampleServerMain.cpp b/test/server/testExampleServerMain.cpp index d22afe8..e0030b6 100644 --- a/test/server/testExampleServerMain.cpp +++ b/test/server/testExampleServerMain.cpp @@ -61,7 +61,7 @@ static PVStructurePtr createPowerSupply() int main(int argc,char *argv[]) { PVDatabasePtr master = PVDatabase::getMaster(); - ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create(); + ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); StandardPVFieldPtr standardPVField = getStandardPVField(); String properties; ScalarType scalarType;