diff --git a/documentation/pvDatabaseCPP.html b/documentation/pvDatabaseCPP.html index 4c5aef2..ca4feee 100644 --- a/documentation/pvDatabaseCPP.html +++ b/documentation/pvDatabaseCPP.html @@ -38,7 +38,7 @@

pvDatabaseCPP

-

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

+

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

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

Status of this Document

-

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

This is the 23-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.
+
Only ChannelArray remains. + Note that pvIOCJava does not implement the pvRequest for channelArray + correctly. It uses a private convention rather than using the output + of CreateRequest. This will be fixed before pvDatabaseCPP implements ChannelArray. +
Monitor Algorithms
-
Monitor algorithms have no been implemented. +
Monitor algorithms have not 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.
+ I am asking for help from Matej +
Memory leak at exit
+
I am asking for help from Matej
Scalar Arrays
-
Have not been tested. Share has not been implemented.
+
Share has not been implemented. + This will wait until Michael has new implementation of ScalarArray.
Structure Arrays
Has not been implemented
Testing
@@ -116,7 +121,7 @@ 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: +

This document describes components that provide the following features:

database
This encapsulates the concept of a database of memory resident smart records. @@ -188,8 +193,9 @@ mrk> bin/linux-x86_64/exampleCounter

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

+A serious implementation might break the code into a header and an +implementation file.

+

The description consists of

 class ExampleCounter;
 typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
@@ -455,6 +461,18 @@ The following are the minimium features required

Thus code will be generated only if other code includes the header file and creates a record instance.
+
recordList.h
+
This implements a PVRecord that provides a list of the names + of the records in the PVDatabase. + It also serves as an example of how to implement a service. + The testExampleServer creates an instance via the following code: +
+recordName = "laptoprecordListPGRPC";
+pvRecord = RecordListRecord::create(recordName);
+result = master->addRecord(pvRecord);
+      
+
+

The classes in pvDatabase.h describe a database of memory resident smart records. @@ -856,16 +874,123 @@ private:

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:

+

This is code that provides an implementation of channelProvider as +defined by pvAccess. +It provides access to PVRecords and is access by the server side of remote pvAccess.

+

channelProviderLocal

+

This is a complete implementation of channelProvider and , +except for channelRPC, provides a complete implementation of Channel +as defined by pvAccess. +For monitors it calls the code described in the following sections.

+

ChannelLocalDebug

+

The channelProvider implementation provides the ability to generate +debug messages based a debug level with the following meaning:

-
pvCopy
-
monitor
-
local ChannelProvider and Channel
+
<=0
+
No debug messages
+
>0
+
Generate a message when anything is created or destroyed
+
>1
+
Also generate processing messages.
+

ChannelProviderLocal has a method:

+
+    void createChannelLocalDebugRecord(
+        String const & recordName);
+
+

This method creates a PVRecord that allows a pvAccess client to set the +debug level.

+

pvCopy

+

This provides code that creates a top level PVStructure that is an arbitrary +subset of the fields in the PVStructure from a PVRecord. +In addition it provides code that monitors changes to the fields in a PVRecord. +A client configures the desired set of subfields and monitoring options +via a pvRequest structure. +pvAccess provides a class CreatePVRequest that creates a pvRequest. +The pvCopy code provides the same functionality as the pvCopy code in pvIOCJava. +

+

monitorAlgorithm

+

Currently all that is implemented is a header file. +The only algorithm currently implemented is onPut +

+

monitorFactory

+

Overview

+

epics::pvData::monitor defines the monitor interfaces +as seen by a client. +See + pvDatabaseCPP.html + For details.

+

+monitorFactory implements the +monitoring interfaces for a PVRecord. +It implements queueSize=0 and queueSize>=2. +

+

+The implementation uses PVCopy and PVCopyMonitor which are implemented in pvCopy. +When PVCopyMonitor tells monitor that changes +have occurred, monitor applies the appropriate algorithm to each changed field.

+ +

Currently only algorithm onPut is implemented but, +like pvIOCJava there are plans to support for the following monitor algorithms:

+
+
onPut
+
A monitor is issued whenever a put is issued to the field. This is the + default unless the record defines deadbands for a field. An exception is + the top level timeStamp which by default is made onChange and monitor + will not be raised.
+
onChange
+
This provides two options: 1) A monitor is raised whenever a field + changes value, and 2) A monitor will never be raised for the field.
+
deadband
+
The field must be a numeric scalar. Whenever the absolute or percentage + value of the field changes by more than a deadband a monitor is issued. + The record instance can also define deadbands.
+
periodic
+
A monitor is issued at a periodic rate if a put was issued to any field + being monitored.
+
+

MonitorFactory

+

MonitorFactory provides the following methods:

+
class MonitorFactory
+{
+    static MonitorPtr create(
+        PVRecordPtr const & pvRecord,
+        MonitorRequester::shared_pointer const & monitorRequester,
+        PVStructurePtr const & pvRequest);
+    static void registerMonitorAlgorithmCreater(
+        MonitorAlgorithmCreatePtr const & monitorAlgorithmCreate,
+        String const & algorithmName);
+}
+ +

where

+
+
create
+
Create a monitor. The arguments are: +
+
pvRecord
+
The record being monitored.
+
monitorRequester
+
The monitor requester. This is the code to which monitot events + will be delivered.
+
pvRequest
+
The request options
+
+
+
registerMonitorAlgorithmCreater
+
Called by code that implements a monitor algorithm.
+
+

channelLocalDebugRecord

+

This implements a PVRecord that allows a client to set +a debug level for the local channel provider implementation. +The top level structure has a single integer field named value. +See ChannelProviderLocal for the meaning associated with value.

+

ChannelProviderLocal has a method:

+
+    void createChannelLocalDebugRecord(String const & recordName);
+
+

This creates an instance of a ChannelLocalDebugRecord and installs it +into the PVDatabase.

diff --git a/documentation/pvDatabaseCPP_20130523.html b/documentation/pvDatabaseCPP_20130523.html new file mode 100644 index 0000000..ca4feee --- /dev/null +++ b/documentation/pvDatabaseCPP_20130523.html @@ -0,0 +1,996 @@ + + + + + + pvDatabaseCPP + + + + + + + + + +
+

pvDatabaseCPP

+ + +

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

+
+
Latest version:
+
pvDatabaseCPP.html +
+
This version:
+
pvDatabaseCPP20130523.html +
+
Previous version:
+
pvDatabaseCPP20130516.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 23-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
+
Only ChannelArray remains. + Note that pvIOCJava does not implement the pvRequest for channelArray + correctly. It uses a private convention rather than using the output + of CreateRequest. This will be fixed before pvDatabaseCPP implements ChannelArray. +
+
Monitor Algorithms
+
Monitor algorithms have not been implemented. + Thus all monitors are onPut.
+
Lifecycle problems
+
Problems when channel clients disconnect. + I am asking for help from Matej
+
Memory leak at exit
+
I am asking for help from Matej
+
Scalar Arrays
+
Share has not been implemented. + This will wait until Michael has new implementation of ScalarArray.
+
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 provide 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 might break the code into a header and an +implementation file.

+

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. +
+
recordList.h
+
This implements a PVRecord that provides a list of the names + of the records in the PVDatabase. + It also serves as an example of how to implement a service. + The testExampleServer creates an instance via the following code: +
+recordName = "laptoprecordListPGRPC";
+pvRecord = RecordListRecord::create(recordName);
+result = master->addRecord(pvRecord);
+      
+
+ +
+

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

+

This is code that provides an implementation of channelProvider as +defined by pvAccess. +It provides access to PVRecords and is access by the server side of remote pvAccess.

+

channelProviderLocal

+

This is a complete implementation of channelProvider and , +except for channelRPC, provides a complete implementation of Channel +as defined by pvAccess. +For monitors it calls the code described in the following sections.

+

ChannelLocalDebug

+

The channelProvider implementation provides the ability to generate +debug messages based a debug level with the following meaning:

+
+
<=0
+
No debug messages
+
>0
+
Generate a message when anything is created or destroyed
+
>1
+
Also generate processing messages.
+
+

ChannelProviderLocal has a method:

+
+    void createChannelLocalDebugRecord(
+        String const & recordName);
+
+

This method creates a PVRecord that allows a pvAccess client to set the +debug level.

+

pvCopy

+

This provides code that creates a top level PVStructure that is an arbitrary +subset of the fields in the PVStructure from a PVRecord. +In addition it provides code that monitors changes to the fields in a PVRecord. +A client configures the desired set of subfields and monitoring options +via a pvRequest structure. +pvAccess provides a class CreatePVRequest that creates a pvRequest. +The pvCopy code provides the same functionality as the pvCopy code in pvIOCJava. +

+

monitorAlgorithm

+

Currently all that is implemented is a header file. +The only algorithm currently implemented is onPut +

+

monitorFactory

+

Overview

+

epics::pvData::monitor defines the monitor interfaces +as seen by a client. +See + pvDatabaseCPP.html + For details.

+

+monitorFactory implements the +monitoring interfaces for a PVRecord. +It implements queueSize=0 and queueSize>=2. +

+ +

+The implementation uses PVCopy and PVCopyMonitor which are implemented in pvCopy. +When PVCopyMonitor tells monitor that changes +have occurred, monitor applies the appropriate algorithm to each changed field.

+ +

Currently only algorithm onPut is implemented but, +like pvIOCJava there are plans to support for the following monitor algorithms:

+
+
onPut
+
A monitor is issued whenever a put is issued to the field. This is the + default unless the record defines deadbands for a field. An exception is + the top level timeStamp which by default is made onChange and monitor + will not be raised.
+
onChange
+
This provides two options: 1) A monitor is raised whenever a field + changes value, and 2) A monitor will never be raised for the field.
+
deadband
+
The field must be a numeric scalar. Whenever the absolute or percentage + value of the field changes by more than a deadband a monitor is issued. + The record instance can also define deadbands.
+
periodic
+
A monitor is issued at a periodic rate if a put was issued to any field + being monitored.
+
+

MonitorFactory

+

MonitorFactory provides the following methods:

+
class MonitorFactory
+{
+    static MonitorPtr create(
+        PVRecordPtr const & pvRecord,
+        MonitorRequester::shared_pointer const & monitorRequester,
+        PVStructurePtr const & pvRequest);
+    static void registerMonitorAlgorithmCreater(
+        MonitorAlgorithmCreatePtr const & monitorAlgorithmCreate,
+        String const & algorithmName);
+}
+ +

where

+
+
create
+
Create a monitor. The arguments are: +
+
pvRecord
+
The record being monitored.
+
monitorRequester
+
The monitor requester. This is the code to which monitot events + will be delivered.
+
pvRequest
+
The request options
+
+
+
registerMonitorAlgorithmCreater
+
Called by code that implements a monitor algorithm.
+
+

channelLocalDebugRecord

+

This implements a PVRecord that allows a client to set +a debug level for the local channel provider implementation. +The top level structure has a single integer field named value. +See ChannelProviderLocal for the meaning associated with value.

+

ChannelProviderLocal has a method:

+
+    void createChannelLocalDebugRecord(String const & recordName);
+
+

This creates an instance of a ChannelLocalDebugRecord and installs it +into the PVDatabase.

+
+ + diff --git a/src/Makefile b/src/Makefile index 3f5b37a..c9da1fa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,10 +20,12 @@ SRC_DIRS += $(DATABASE)/pvAccess INC += channelProviderLocal.h INC += pvCopy.h INC += monitorAlgorithm.h +INC += channelLocalDebugRecord.h LIBSRCS += channelProviderLocal.cpp LIBSRCS += channelLocal.cpp LIBSRCS += pvCopy.cpp LIBSRCS += monitorFactory.cpp +LIBSRCS += channelLocalDebugRecord.cpp include $(TOP)/configure/RULES diff --git a/src/pvAccess/channelLocal.cpp b/src/pvAccess/channelLocal.cpp index 723b99d..5077670 100644 --- a/src/pvAccess/channelLocal.cpp +++ b/src/pvAccess/channelLocal.cpp @@ -39,12 +39,6 @@ typedef std::tr1::shared_ptr ChannelRPCLocalPtr; class ChannelArrayLocal; typedef std::tr1::shared_ptr ChannelArrayLocalPtr; -class ChannelLocalDebug { -public: - static void setLevel(int level); - static int getLevel(); -}; - static bool getProcess(PVStructurePtr pvRequest,bool processDefault) { PVFieldPtr pvField = pvRequest->getSubField("record._options.process"); @@ -69,12 +63,19 @@ class ChannelProcessLocal : { public: POINTER_DEFINITIONS(ChannelProcessLocal); - virtual ~ChannelProcessLocal() {destroy();} + virtual ~ChannelProcessLocal() + { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "~ChannelProcessLocal() " << std::endl; + } + } static ChannelProcessLocalPtr create( ChannelLocalPtr const &channelLocal, ChannelProcessRequester::shared_pointer const & channelProcessRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord); + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug); virtual void process(bool lastRequest); virtual void destroy(); virtual void lock() {thelock.lock();} @@ -88,12 +89,14 @@ private: ChannelLocalPtr const &channelLocal, ChannelProcessRequester::shared_pointer const & channelProcessRequester, PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug, int nProcess) : isDestroyed(false), channelLocal(channelLocal), channelProcessRequester(channelProcessRequester), pvRecord(pvRecord), + channelLocalDebug(channelLocalDebug), thelock(mutex), nProcess(nProcess) { @@ -104,6 +107,7 @@ private: ChannelLocalPtr channelLocal; ChannelProcessRequester::shared_pointer channelProcessRequester,; PVRecordPtr pvRecord; + ChannelLocalDebugPtr channelLocalDebug; Mutex mutex; Lock thelock; int nProcess; @@ -113,7 +117,8 @@ ChannelProcessLocalPtr ChannelProcessLocal::create( ChannelLocalPtr const &channelLocal, ChannelProcessRequester::shared_pointer const & channelProcessRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) { PVFieldPtr pvField; PVStructurePtr pvOptions; @@ -137,7 +142,13 @@ ChannelProcessLocalPtr ChannelProcessLocal::create( channelLocal, channelProcessRequester, pvRecord, + channelLocalDebug, nProcess)); + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelProcessLocal::create"; + std::cout << " recordName " << pvRecord->getRecordName() << std::endl; + } channelLocal->addChannelProcess(process); channelProcessRequester->channelProcessConnect(Status::Ok, process); return process; @@ -146,6 +157,11 @@ ChannelProcessLocalPtr ChannelProcessLocal::create( void ChannelProcessLocal::destroy() { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelProcessLocal::destroy"; + std::cout << " destroyed " << isDestroyed << std::endl; + } if(isDestroyed) return; isDestroyed = true; channelLocal->removeChannelProcess(getPtrSelf()); @@ -156,6 +172,18 @@ void ChannelProcessLocal::destroy() void ChannelProcessLocal::process(bool lastRequest) { + if(isDestroyed) { + Status status( + Status::Status::STATUSTYPE_ERROR, + "was destroyed"); + channelProcessRequester->processDone(status); + return; + } + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelProcessLocal::process"; + std::cout << " nProcess " << nProcess << std::endl; + } for(int i=0; i< nProcess; i++) { pvRecord->lock(); pvRecord->beginGroupPut(); @@ -163,12 +191,6 @@ void ChannelProcessLocal::process(bool lastRequest) pvRecord->endGroupPut(); pvRecord->unlock(); } - if(isDestroyed) { - Status status( - Status::Status::STATUSTYPE_ERROR, - "was destroyed"); - channelProcessRequester->processDone(status); - } channelProcessRequester->processDone(Status::Ok); if(lastRequest) destroy(); } @@ -179,12 +201,19 @@ class ChannelGetLocal : { public: POINTER_DEFINITIONS(ChannelGetLocal); - virtual ~ChannelGetLocal(){destroy();} + virtual ~ChannelGetLocal() + { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "~ChannelGetLocal()" << std::endl; + } + } static ChannelGetLocalPtr create( ChannelLocalPtr const &channelLocal, ChannelGetRequester::shared_pointer const & channelGetRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord); + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug); virtual void get(bool lastRequest); virtual void destroy(); virtual void lock() {thelock.lock();} @@ -201,7 +230,8 @@ private: PVCopyPtr const &pvCopy, PVStructurePtr const&pvStructure, BitSetPtr const & bitSet, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) : firstTime(true), isDestroyed(false), @@ -212,6 +242,7 @@ private: pvStructure(pvStructure), bitSet(bitSet), pvRecord(pvRecord), + channelLocalDebug(channelLocalDebug), thelock(mutex) { thelock.unlock(); @@ -225,6 +256,7 @@ private: PVStructurePtr pvStructure; BitSetPtr bitSet; PVRecordPtr pvRecord; + ChannelLocalDebugPtr channelLocalDebug; Mutex mutex; Lock thelock; }; @@ -233,7 +265,8 @@ ChannelGetLocalPtr ChannelGetLocal::create( ChannelLocalPtr const &channelLocal, ChannelGetRequester::shared_pointer const & channelGetRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) { PVCopyPtr pvCopy = PVCopy::create( pvRecord, @@ -263,7 +296,13 @@ ChannelGetLocalPtr ChannelGetLocal::create( pvCopy, pvStructure, bitSet, - pvRecord)); + pvRecord, + channelLocalDebug)); + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelGetLocal::create"; + std::cout << " recordName " << pvRecord->getRecordName() << std::endl; + } channelLocal->addChannelGet(get); channelGetRequester->channelGetConnect(Status::Ok, get, pvStructure,bitSet); return get; @@ -272,6 +311,11 @@ ChannelGetLocalPtr ChannelGetLocal::create( void ChannelGetLocal::destroy() { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelGetLocal::destroy"; + std::cout << " destroyed " << isDestroyed << std::endl; + } if(isDestroyed) return; isDestroyed = true; channelLocal->removeChannelGet(getPtrSelf()); @@ -290,6 +334,7 @@ void ChannelGetLocal::get(bool lastRequest) Status::Status::STATUSTYPE_ERROR, "was destroyed"); channelGetRequester->getDone(status); + return; } bitSet->clear(); pvRecord->lock(); @@ -306,6 +351,10 @@ void ChannelGetLocal::get(bool lastRequest) firstTime = false; } channelGetRequester->getDone(Status::Ok); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelGetLocal::get" << std::endl; + } if(lastRequest) destroy(); } @@ -315,12 +364,19 @@ class ChannelPutLocal : { public: POINTER_DEFINITIONS(ChannelPutLocal); - virtual ~ChannelPutLocal(){destroy();} + virtual ~ChannelPutLocal() + { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "~ChannelPutLocal()" << std::endl; + } + } static ChannelPutLocalPtr create( ChannelLocalPtr const &channelLocal, ChannelPutRequester::shared_pointer const & channelPutRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord); + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug); virtual void put(bool lastRequest); virtual void get(); virtual void destroy(); @@ -338,7 +394,8 @@ private: PVCopyPtr const &pvCopy, PVStructurePtr const&pvStructure, BitSetPtr const & bitSet, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) : isDestroyed(false), callProcess(callProcess), @@ -348,6 +405,7 @@ private: pvStructure(pvStructure), bitSet(bitSet), pvRecord(pvRecord), + channelLocalDebug(channelLocalDebug), thelock(mutex) { thelock.unlock(); @@ -360,6 +418,7 @@ private: PVStructurePtr pvStructure; BitSetPtr bitSet; PVRecordPtr pvRecord; + ChannelLocalDebugPtr channelLocalDebug; Mutex mutex; Lock thelock; }; @@ -368,7 +427,8 @@ ChannelPutLocalPtr ChannelPutLocal::create( ChannelLocalPtr const &channelLocal, ChannelPutRequester::shared_pointer const & channelPutRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) { PVCopyPtr pvCopy = PVCopy::create( pvRecord, @@ -398,14 +458,25 @@ ChannelPutLocalPtr ChannelPutLocal::create( pvCopy, pvStructure, bitSet, - pvRecord)); + pvRecord, + channelLocalDebug)); channelLocal->addChannelPut(put); channelPutRequester->channelPutConnect(Status::Ok, put, pvStructure,bitSet); + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelPutLocal::create"; + std::cout << " recordName " << pvRecord->getRecordName() << std::endl; + } return put; } void ChannelPutLocal::destroy() { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelPutLocal::destroy"; + std::cout << " destroyed " << isDestroyed << std::endl; + } if(isDestroyed) return; isDestroyed = true; channelLocal->removeChannelPut(getPtrSelf()); @@ -424,6 +495,7 @@ void ChannelPutLocal::get() Status::Status::STATUSTYPE_ERROR, "was destroyed"); channelPutRequester->getDone(status); + return; } bitSet->clear(); bitSet->set(0); @@ -431,6 +503,10 @@ void ChannelPutLocal::get() pvCopy->updateCopyFromBitSet(pvStructure, bitSet, false); pvRecord->unlock(); channelPutRequester->getDone(Status::Ok); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelPutLocal::get" << std::endl; + } } void ChannelPutLocal::put(bool lastRequest) @@ -440,6 +516,7 @@ void ChannelPutLocal::put(bool lastRequest) Status::Status::STATUSTYPE_ERROR, "was destroyed"); channelPutRequester->getDone(status); + return; } pvRecord->lock(); pvRecord->beginGroupPut(); @@ -449,7 +526,11 @@ void ChannelPutLocal::put(bool lastRequest) } pvRecord->endGroupPut(); pvRecord->unlock(); - channelPutRequester->getDone(Status::Ok); + channelPutRequester->putDone(Status::Ok); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelPutLocal::get" << std::endl; + } if(lastRequest) destroy(); } @@ -460,12 +541,19 @@ class ChannelPutGetLocal : { public: POINTER_DEFINITIONS(ChannelPutGetLocal); - virtual ~ChannelPutGetLocal(){destroy();} + virtual ~ChannelPutGetLocal() + { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "~ChannelPutGetLocal()" << std::endl; + } + } static ChannelPutGetLocalPtr create( ChannelLocalPtr const &channelLocal, ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord); + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug); virtual void putGet(bool lastRequest); virtual void getPut(); virtual void getGet(); @@ -487,7 +575,8 @@ private: PVStructurePtr const&pvGetStructure, BitSetPtr const & putBitSet, BitSetPtr const & getBitSet, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) : isDestroyed(false), callProcess(callProcess), @@ -500,6 +589,7 @@ private: putBitSet(putBitSet), getBitSet(getBitSet), pvRecord(pvRecord), + channelLocalDebug(channelLocalDebug), thelock(mutex) { thelock.unlock(); @@ -515,6 +605,7 @@ private: BitSetPtr putBitSet; BitSetPtr getBitSet; PVRecordPtr pvRecord; + ChannelLocalDebugPtr channelLocalDebug; Mutex mutex; Lock thelock; }; @@ -523,7 +614,8 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create( ChannelLocalPtr const &channelLocal, ChannelPutGetRequester::shared_pointer const & channelPutGetRequester, PVStructurePtr const & pvRequest, - PVRecordPtr const &pvRecord) + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) { PVCopyPtr pvPutCopy = PVCopy::create( pvRecord, @@ -562,7 +654,13 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create( pvGetStructure, putBitSet, getBitSet, - pvRecord)); + pvRecord, + channelLocalDebug)); + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelPutGetLocal::create"; + std::cout << " recordName " << pvRecord->getRecordName() << std::endl; + } channelLocal->addChannelPutGet(putGet); channelPutGetRequester->channelPutGetConnect( Status::Ok, putGet, pvPutStructure,pvGetStructure); @@ -572,6 +670,11 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create( void ChannelPutGetLocal::destroy() { + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelPutGetLocal::destroy"; + std::cout << " destroyed " << isDestroyed << std::endl; + } if(isDestroyed) return; isDestroyed = true; channelLocal->removeChannelPutGet(getPtrSelf()); @@ -593,6 +696,7 @@ void ChannelPutGetLocal::putGet(bool lastRequest) Status::Status::STATUSTYPE_ERROR, "was destroyed"); channelPutGetRequester->putGetDone(status); + return; } putBitSet->clear(); putBitSet->set(0); @@ -606,6 +710,10 @@ void ChannelPutGetLocal::putGet(bool lastRequest) getBitSet->clear(); getBitSet->set(0); channelPutGetRequester->putGetDone(Status::Ok); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelPutGetLocal::putGet" << std::endl; + } if(lastRequest) destroy(); } @@ -616,6 +724,7 @@ void ChannelPutGetLocal::getPut() Status::Status::STATUSTYPE_ERROR, "was destroyed"); channelPutGetRequester->getPutDone(status); + return; } pvRecord->lock(); pvPutCopy->updateCopySetBitSet(pvPutStructure, putBitSet, false); @@ -623,6 +732,10 @@ void ChannelPutGetLocal::getPut() putBitSet->clear(); putBitSet->set(0); channelPutGetRequester->getPutDone(Status::Ok); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelPutGetLocal::getPut" << std::endl; + } } void ChannelPutGetLocal::getGet() @@ -632,6 +745,7 @@ void ChannelPutGetLocal::getGet() Status::Status::STATUSTYPE_ERROR, "was destroyed"); channelPutGetRequester->getGetDone(status); + return; } pvRecord->lock(); pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet, false); @@ -639,6 +753,10 @@ void ChannelPutGetLocal::getGet() getBitSet->clear(); getBitSet->set(0); channelPutGetRequester->getGetDone(Status::Ok); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelPutGetLocal::getGet" << std::endl; + } } class ChannelRPCLocal : @@ -657,38 +775,32 @@ public: bool lastRequest); }; -int ChannelLocalDebugLevel = 0; -void ChannelLocalDebug::setLevel(int level) {ChannelLocalDebugLevel = level;} -int ChannelLocalDebug::getLevel() {return ChannelLocalDebugLevel;} - - ChannelLocal::ChannelLocal( ChannelProviderLocalPtr const & provider, ChannelRequester::shared_pointer const & requester, - PVRecordPtr const & pvRecord) + PVRecordPtr const & pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) : provider(provider), requester(requester), pvRecord(pvRecord), + channelLocalDebug(channelLocalDebug), beingDestroyed(false) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::ChannelLocal\n"); - } } ChannelLocal::~ChannelLocal() { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::~ChannelLocal\n"); + if(channelLocalDebug->getLevel()>0) { + std::cout << "~ChannelLocal()" << std::endl; } } void ChannelLocal::destroy() { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::destroy beingDestroyed %s\n", - (beingDestroyed ? "true" : "false")); + if(channelLocalDebug->getLevel()>0) { + std::cout << "ChannelLocal::destroy() "; + std::cout << "beingDestroyed " << beingDestroyed << std::endl; } { Lock xx(mutex); @@ -723,13 +835,6 @@ void ChannelLocal::destroy() it->get()->destroy(); channelPutGetList.erase(it); } - while(true) { - std::set::iterator it; - it = channelMonitorList.begin(); - if(it==channelMonitorList.end()) break; - it->get()->destroy(); - channelMonitorList.erase(it); - } while(true) { std::set::iterator it; it = channelRPCList.begin(); @@ -750,8 +855,8 @@ void ChannelLocal::destroy() void ChannelLocal::addChannelProcess(ChannelProcess::shared_pointer const & channelProcess) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelProcess\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::addChannelProcess() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -760,8 +865,8 @@ void ChannelLocal::addChannelProcess(ChannelProcess::shared_pointer const & chan void ChannelLocal::addChannelGet(ChannelGet::shared_pointer const &channelGet) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelGet\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::addChannelGet() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -770,8 +875,8 @@ void ChannelLocal::addChannelGet(ChannelGet::shared_pointer const &channelGet) void ChannelLocal::addChannelPut(ChannelPut::shared_pointer const &channelPut) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelPut\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::addChannelPut() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -780,28 +885,18 @@ void ChannelLocal::addChannelPut(ChannelPut::shared_pointer const &channelPut) void ChannelLocal::addChannelPutGet(ChannelPutGet::shared_pointer const &channelPutGet) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelPutGet\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::addChannelPutGet() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; channelPutGetList.insert(channelPutGet); } -void ChannelLocal::addChannelMonitor(Monitor::shared_pointer const &monitor) -{ - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelMonitor\n"); - } - Lock xx(mutex); - if(beingDestroyed) return; - channelMonitorList.insert(monitor); -} - void ChannelLocal::addChannelRPC(ChannelRPC::shared_pointer const &channelRPC) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelRPC\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::addChannelRPC() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -810,8 +905,8 @@ void ChannelLocal::addChannelRPC(ChannelRPC::shared_pointer const &channelRPC) void ChannelLocal::addChannelArray(ChannelArray::shared_pointer const &channelArray) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::addChannelArray\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::addChannelArray() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -820,8 +915,8 @@ void ChannelLocal::addChannelArray(ChannelArray::shared_pointer const &channelAr void ChannelLocal::removeChannelProcess(ChannelProcess::shared_pointer const &ref) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelProcess\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::removeChannelProcess() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -830,8 +925,8 @@ void ChannelLocal::removeChannelProcess(ChannelProcess::shared_pointer const &re void ChannelLocal::removeChannelGet(ChannelGet::shared_pointer const &ref) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelGet\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::removeChannelGet() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -840,8 +935,8 @@ void ChannelLocal::removeChannelGet(ChannelGet::shared_pointer const &ref) void ChannelLocal::removeChannelPut(ChannelPut::shared_pointer const &ref) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelPut\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::removeChannelPut() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -850,28 +945,18 @@ void ChannelLocal::removeChannelPut(ChannelPut::shared_pointer const &ref) void ChannelLocal::removeChannelPutGet(ChannelPutGet::shared_pointer const &ref) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelPutGet\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::removeChannelPutGet() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; channelPutGetList.erase(ref); } -void ChannelLocal::removeChannelMonitor(Monitor::shared_pointer const &ref) -{ - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelMonitor\n"); - } - Lock xx(mutex); - if(beingDestroyed) return; - channelMonitorList.erase(ref); -} - void ChannelLocal::removeChannelRPC(ChannelRPC::shared_pointer const &ref) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelRPC\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::removeChannelRPC() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -880,8 +965,8 @@ void ChannelLocal::removeChannelRPC(ChannelRPC::shared_pointer const &ref) void ChannelLocal::removeChannelArray(ChannelArray::shared_pointer const &ref) { - if(ChannelLocalDebug::getLevel()>0) { - printf("ChannelLocal::removeChannelArray\n"); + if(channelLocalDebug->getLevel()>1) { + std::cout << "ChannelLocal::removeChannelArray() " << std::endl; } Lock xx(mutex); if(beingDestroyed) return; @@ -900,11 +985,6 @@ void ChannelLocal::message( requester->message(message,messageType); } -ChannelProvider::shared_pointer ChannelLocal::getProvider() -{ - return provider; -} - String ChannelLocal::getRemoteAddress() { return String("local"); @@ -963,7 +1043,8 @@ ChannelProcess::shared_pointer ChannelLocal::createChannelProcess( getPtrSelf(), channelProcessRequester, pvRequest, - pvRecord); + pvRecord, + channelLocalDebug); return channelProcess; } @@ -976,7 +1057,8 @@ ChannelGet::shared_pointer ChannelLocal::createChannelGet( getPtrSelf(), channelGetRequester, pvRequest, - pvRecord); + pvRecord, + channelLocalDebug); return channelGet; } @@ -989,7 +1071,8 @@ ChannelPut::shared_pointer ChannelLocal::createChannelPut( getPtrSelf(), channelPutRequester, pvRequest, - pvRecord); + pvRecord, + channelLocalDebug); return channelPut; } @@ -1002,7 +1085,8 @@ ChannelPutGet::shared_pointer ChannelLocal::createChannelPutGet( getPtrSelf(), channelPutGetRequester, pvRequest, - pvRecord); + pvRecord, + channelLocalDebug); return channelPutGet; } @@ -1021,7 +1105,11 @@ Monitor::shared_pointer ChannelLocal::createMonitor( PVStructure::shared_pointer const &pvRequest) { MonitorPtr monitor = - getMonitorFactory()->createMonitor(pvRecord,monitorRequester,pvRequest); + getMonitorFactory()->createMonitor( + pvRecord, + monitorRequester, + pvRequest, + channelLocalDebug); return monitor; } @@ -1040,7 +1128,7 @@ ChannelArray::shared_pointer ChannelLocal::createChannelArray( void ChannelLocal::printInfo() { - printf("ChannelLocal provides access to service\n"); + std::cout << "ChannelLocal provides access to service" << std::endl; } void ChannelLocal::printInfo(StringBuilder out) diff --git a/src/pvAccess/channelLocalDebugRecord.cpp b/src/pvAccess/channelLocalDebugRecord.cpp new file mode 100644 index 0000000..58d8150 --- /dev/null +++ b/src/pvAccess/channelLocalDebugRecord.cpp @@ -0,0 +1,75 @@ +/* channelListDebugRecord.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.04.18 + */ + +#include + +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace std; + +namespace epics { namespace pvDatabase { + +ChannelLocalDebugRecordPtr ChannelLocalDebugRecord::create( + ChannelLocalDebugPtr const &channelLocalDebug, + epics::pvData::String const & recordName) +{ + FieldCreatePtr fieldCreate = getFieldCreate(); + PVDataCreatePtr pvDataCreate = getPVDataCreate(); + StringArray argNames(1); + FieldConstPtrArray argFields(1); + argNames[0] = "value"; + argFields[0] = fieldCreate->createScalar(pvInt); + StructureConstPtr topStructure = + fieldCreate->createStructure(argNames,argFields); + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure); + ChannelLocalDebugRecordPtr pvRecord( + new ChannelLocalDebugRecord(channelLocalDebug,recordName,pvStructure)); + if(!pvRecord->init()) pvRecord.reset(); + return pvRecord; +} + +ChannelLocalDebugRecord::ChannelLocalDebugRecord( + ChannelLocalDebugPtr const &channelLocalDebug, + epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure) +: PVRecord(recordName,pvStructure), + channelLocalDebug(channelLocalDebug) +{ +} + +ChannelLocalDebugRecord::~ChannelLocalDebugRecord() +{ +} + +void ChannelLocalDebugRecord::destroy() +{ + PVRecord::destroy(); +} + +bool ChannelLocalDebugRecord::init() +{ + initPVRecord(); + PVStructurePtr pvStructure = getPVStructure(); + + pvValue = pvStructure->getIntField("value"); + if(pvValue==NULL) return false; + return true; +} + +void ChannelLocalDebugRecord::process() +{ + channelLocalDebug->setLevel(pvValue->get()); +} + + +}} + diff --git a/src/pvAccess/channelLocalDebugRecord.h b/src/pvAccess/channelLocalDebugRecord.h new file mode 100644 index 0000000..05a276f --- /dev/null +++ b/src/pvAccess/channelLocalDebugRecord.h @@ -0,0 +1,46 @@ +/* channelLocalDebugRecord.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.04.18 + */ +#ifndef CHANNELLOCALREBUGRECORD_H +#define CHANNELLOCALREBUGRECORD_H + +#include + +namespace epics { namespace pvDatabase { + + +class ChannelLocalDebugRecord; +typedef std::tr1::shared_ptr ChannelLocalDebugRecordPtr; + +class ChannelLocalDebugRecord : + public PVRecord +{ +public: + POINTER_DEFINITIONS(ChannelLocalDebugRecord); + static ChannelLocalDebugRecordPtr create( + ChannelLocalDebugPtr const &channelLocalDebug, + epics::pvData::String const & recordName); + virtual ~ChannelLocalDebugRecord(); + virtual void destroy(); + virtual bool init(); + virtual void process(); +private: + ChannelLocalDebugRecord( + ChannelLocalDebugPtr const &channelLocalDebug, + epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + ChannelLocalDebugPtr channelLocalDebug; + epics::pvData::PVIntPtr pvValue; + bool isDestroyed; +}; + +}} + +#endif /* CHANNELLOCALREBUGRECORD_H */ diff --git a/src/pvAccess/channelProviderLocal.cpp b/src/pvAccess/channelProviderLocal.cpp index 0373b66..6687b58 100644 --- a/src/pvAccess/channelProviderLocal.cpp +++ b/src/pvAccess/channelProviderLocal.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace epics { namespace pvDatabase { @@ -75,11 +76,13 @@ LocalChannelCTX::LocalChannelCTX( LocalChannelCTX::~LocalChannelCTX() { +std::cout << "LocalChannelCTX::~LocalChannelCTX()" << std::endl; ctx->shutdown(); // we need thead.waitForCompletion() event.wait(); epicsThreadSleep(1.0); ctx.reset(); + channelProvider.reset(); delete thread; } void LocalChannelCTX::run() @@ -90,11 +93,7 @@ void LocalChannelCTX::run() ctx->initialize(getChannelAccess()); ctx->printInfo(); ctx->run(0); -// Matej if I switch which is commented then errors when exit -// BUT this way causes lots of memory leaks - channelProvider->destroy(); - //ctx->destroy(); -// Matej end of comments + ctx->destroy(); event.signal(); } @@ -114,18 +113,27 @@ ChannelProviderLocalPtr getChannelProviderLocal() ChannelProviderLocal::ChannelProviderLocal() : pvDatabase(PVDatabase::getMaster()), - beingDestroyed(false) + beingDestroyed(false), + channelLocalDebug(new ChannelLocalDebug()) { } ChannelProviderLocal::~ChannelProviderLocal() { - destroy(); + if(channelLocalDebug->getLevel()>0) + { + std::cout << "~ChannelProviderLocal()" << std::endl; + } } void ChannelProviderLocal::destroy() { Lock xx(mutex); + if(channelLocalDebug->getLevel()>0) + { + std::cout << "ChannelProviderLocal::destroy"; + std::cout << " destroyed " << beingDestroyed << std::endl; + } if(beingDestroyed) return; beingDestroyed = true; ChannelLocalList::iterator iter; @@ -135,7 +143,6 @@ void ChannelProviderLocal::destroy() (*iter)->destroy(); channelList.erase(iter); } - pvDatabase->destroy(); } @@ -206,10 +213,15 @@ Channel::shared_pointer ChannelProviderLocal::createChannel( PVRecordPtr pvRecord = pvDatabase->findRecord(channelName); if(pvRecord.get()!=NULL) { Channel::shared_pointer channel(new ChannelLocal( - getPtrSelf(),channelRequester,pvRecord)); + getPtrSelf(),channelRequester,pvRecord,channelLocalDebug)); channelRequester->channelCreated( Status::Ok, channel); + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelProviderLocal::createChannel"; + std::cout << " channelName " << channelName << std::endl; + } return channel; } Status notFoundStatus(Status::STATUSTYPE_ERROR,String("pv not found")); @@ -228,10 +240,27 @@ void ChannelProviderLocal::removeChannel( for(iter = channelList.begin(); iter!=channelList.end(); ++iter) { if((*iter).get()==channel.get()) { + if(channelLocalDebug->getLevel()>1) + { + std::cout << "ChannelProviderLocal::createChannel"; + std::cout << " channelName " << channel->getChannelName() << std::endl; + } channelList.erase(iter); return; } } } +void ChannelProviderLocal::createChannelLocalDebugRecord( + String const &recordName) +{ + ChannelLocalDebugRecordPtr pvRecord + = ChannelLocalDebugRecord::create(channelLocalDebug,recordName); + PVDatabasePtr master = PVDatabase::getMaster(); + bool result = master->addRecord(pvRecord); + if(!result) { + cout << "result of addRecord " << recordName << " " << result << endl; + } +} + }} diff --git a/src/pvAccess/channelProviderLocal.h b/src/pvAccess/channelProviderLocal.h index c6f4a60..537a953 100644 --- a/src/pvAccess/channelProviderLocal.h +++ b/src/pvAccess/channelProviderLocal.h @@ -28,9 +28,16 @@ namespace epics { namespace pvDatabase { +class ChannelLocalDebug; +typedef std::tr1::shared_ptr ChannelLocalDebugPtr; + class MonitorFactory; typedef std::tr1::shared_ptr MonitorFactoryPtr; +class MonitorLocal; +typedef std::tr1::shared_ptr MonitorLocalPtr; + + class ChannelProviderLocal; typedef std::tr1::shared_ptr ChannelProviderLocalPtr; class ChannelLocal; @@ -42,6 +49,23 @@ class MonitorLocal; typedef std::tr1::shared_ptr MonitorLocalPtr; typedef std::set MonitorLocalList; +class ChannelLocalDebug { +public: + ChannelLocalDebug() + : channelLocalDebugLevel(0) + {} + ~ChannelLocalDebug(){} + void setLevel(int level) + { + channelLocalDebugLevel = level; + } + int getLevel() + { + return channelLocalDebugLevel; + } +private: + int channelLocalDebugLevel; +}; class MonitorFactory { @@ -52,13 +76,14 @@ public: epics::pvData::MonitorPtr createMonitor( PVRecordPtr const & pvRecord, epics::pvData::MonitorRequester::shared_pointer const & monitorRequester, - epics::pvData::PVStructurePtr const & pvRequest); + epics::pvData::PVStructurePtr const & pvRequest, + ChannelLocalDebugPtr const &channelLocalDebug); void registerMonitorAlgorithmCreate( MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate); - MonitorAlgorithmCreatePtr getMonitorAlgorithmCreate(epics::pvData::String algorithmName); + MonitorAlgorithmCreatePtr getMonitorAlgorithmCreate( + epics::pvData::String algorithmName); private: MonitorFactory(); - void removeMonitor(MonitorLocal * monitor); friend class MonitorLocal; friend MonitorFactoryPtr getMonitorFactory(); std::set monitorAlgorithmCreateList; @@ -93,6 +118,7 @@ public: epics::pvData::String const &address); void removeChannel( epics::pvAccess::Channel::shared_pointer const &channel); + void createChannelLocalDebugRecord(epics::pvData::String const &recordName); private: shared_pointer getPtrSelf() { @@ -104,6 +130,7 @@ private: ChannelLocalList channelList; epics::pvData::Mutex mutex; bool beingDestroyed; + ChannelLocalDebugPtr channelLocalDebug; friend class ChannelProviderLocalRun; }; @@ -116,7 +143,8 @@ public: ChannelLocal( ChannelProviderLocalPtr const &channelProvider, epics::pvAccess::ChannelRequester::shared_pointer const & requester, - PVRecordPtr const & pvRecord + PVRecordPtr const & pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug ); virtual ~ChannelLocal(); virtual void destroy(); @@ -124,7 +152,10 @@ public: virtual void message( epics::pvData::String const & message, epics::pvData::MessageType messageType); - virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider(); + virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider() + { + return provider; + } virtual epics::pvData::String getRemoteAddress(); virtual epics::pvAccess::Channel::ConnectionState getConnectionState(); virtual epics::pvData::String getChannelName(); @@ -163,14 +194,12 @@ public: void addChannelGet(epics::pvAccess::ChannelGet::shared_pointer const &); void addChannelPut(epics::pvAccess::ChannelPut::shared_pointer const &); void addChannelPutGet(epics::pvAccess::ChannelPutGet::shared_pointer const &); - void addChannelMonitor(epics::pvData::Monitor::shared_pointer const &); void addChannelRPC(epics::pvAccess::ChannelRPC::shared_pointer const &); void addChannelArray(epics::pvAccess::ChannelArray::shared_pointer const &); void removeChannelProcess(epics::pvAccess::ChannelProcess::shared_pointer const &); void removeChannelGet(epics::pvAccess::ChannelGet::shared_pointer const &); void removeChannelPut(epics::pvAccess::ChannelPut::shared_pointer const &); void removeChannelPutGet(epics::pvAccess::ChannelPutGet::shared_pointer const &); - void removeChannelMonitor(epics::pvData::Monitor::shared_pointer const &); void removeChannelRPC(epics::pvAccess::ChannelRPC::shared_pointer const &); void removeChannelArray(epics::pvAccess::ChannelArray::shared_pointer const &); protected: @@ -182,12 +211,12 @@ private: ChannelProviderLocalPtr provider; epics::pvAccess::ChannelRequester::shared_pointer requester; PVRecordPtr pvRecord; + ChannelLocalDebugPtr channelLocalDebug; bool beingDestroyed; std::set channelProcessList; std::set channelGetList; std::set channelPutList; std::set channelPutGetList; - std::set channelMonitorList; std::set channelRPCList; std::set channelArrayList; epics::pvData::Mutex mutex; diff --git a/src/pvAccess/monitorFactory.cpp b/src/pvAccess/monitorFactory.cpp index fefc71b..e984d77 100644 --- a/src/pvAccess/monitorFactory.cpp +++ b/src/pvAccess/monitorFactory.cpp @@ -38,9 +38,6 @@ 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: @@ -131,9 +128,9 @@ public: virtual void release(MonitorElementPtr const & monitorElement); bool init(PVStructurePtr const & pvRequest); MonitorLocal( - ChannelProviderLocalPtr const &channelProvider, MonitorRequester::shared_pointer const & channelMonitorRequester, - PVRecordPtr const &pvRecord); + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug); PVCopyPtr getPVCopy() { return pvCopy;} PVCopyMonitorPtr getPVCopyMonitor() { return pvCopyMonitor;} private: @@ -141,8 +138,9 @@ private: { return shared_from_this(); } - PVRecordPtr pvRecord; MonitorRequester::shared_pointer monitorRequester; + PVRecordPtr pvRecord; + ChannelLocalDebugPtr channelLocalDebug; bool isDestroyed; bool firstMonitor; PVCopyPtr pvCopy; @@ -153,11 +151,12 @@ private: }; MonitorLocal::MonitorLocal( - ChannelProviderLocalPtr const &channelProvider, MonitorRequester::shared_pointer const & channelMonitorRequester, - PVRecordPtr const &pvRecord) -: pvRecord(pvRecord), - monitorRequester(channelMonitorRequester), + PVRecordPtr const &pvRecord, + ChannelLocalDebugPtr const &channelLocalDebug) +: monitorRequester(channelMonitorRequester), + pvRecord(pvRecord), + channelLocalDebug(channelLocalDebug), isDestroyed(false), firstMonitor(true) { @@ -165,17 +164,18 @@ MonitorLocal::MonitorLocal( MonitorLocal::~MonitorLocal() { - destroy(); +std::cout << "MonitorLocal::~MonitorLocal()" << std::endl; } void MonitorLocal::destroy() { -//std::cout << "MonitorLocal::destroy " << isDestroyed << std::endl; +std::cout << "MonitorLocal::destroy " << isDestroyed << std::endl; { Lock xx(mutex); if(isDestroyed) return; isDestroyed = true; } + unlisten(); stop(); // monitorFieldList.clear(); pvCopyMonitor.reset(); @@ -194,7 +194,7 @@ Status MonitorLocal::start() Status MonitorLocal::stop() { -//std::cout << "MonitorLocal::stop" << std::endl; +std::cout << "MonitorLocal::stop" << std::endl; pvCopyMonitor->stopMonitoring(); queue->stop(); return Status::Ok; @@ -222,7 +222,7 @@ void MonitorLocal::dataChanged() void MonitorLocal::unlisten() { -//std::cout << "MonitorLocal::unlisten" << std::endl; +std::cout << "MonitorLocal::unlisten" << std::endl; monitorRequester->unlisten(getPtrSelf()); } @@ -309,7 +309,7 @@ MonitorFactory::~MonitorFactory() void MonitorFactory::destroy() { -//std::cout << "MonitorFactory::destroy " << isDestroyed << std::endl; +std::cout << "MonitorFactory::destroy " << isDestroyed << std::endl; Lock lock(mutex); if(isDestroyed) return; isDestroyed = true; @@ -327,7 +327,8 @@ void MonitorFactory::destroy() MonitorPtr MonitorFactory::createMonitor( PVRecordPtr const & pvRecord, MonitorRequester::shared_pointer const & monitorRequester, - PVStructurePtr const & pvRequest) + PVStructurePtr const & pvRequest, + ChannelLocalDebugPtr const &channelLocalDebug) { Lock xx(mutex); if(isDestroyed) { @@ -335,27 +336,18 @@ MonitorPtr MonitorFactory::createMonitor( return nullMonitor; } MonitorLocalPtr monitor(new MonitorLocal( - getChannelProviderLocal(),monitorRequester,pvRecord)); + monitorRequester,pvRecord,channelLocalDebug)); bool result = monitor->init(pvRequest); if(!result) return nullMonitor; + if(channelLocalDebug->getLevel()>0) + { + std::cout << "MonitorFactory::createMonitor"; + std::cout << " recordName " << pvRecord->getRecordName() << std::endl; + } 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) { diff --git a/src/pvAccess/pvCopy.cpp b/src/pvAccess/pvCopy.cpp index 40b4150..22d17ff 100644 --- a/src/pvAccess/pvCopy.cpp +++ b/src/pvAccess/pvCopy.cpp @@ -1027,6 +1027,7 @@ void PVCopyMonitor::startMonitoring( void PVCopyMonitor::stopMonitoring() { +std::cout << "PVCopyMonitor::stopMonitoring()" << std::endl; pvRecord->removeListener(getPtrSelf()); } diff --git a/test/server/exampleCounterMain.cpp b/test/server/exampleCounterMain.cpp index f42c029..61e6b28 100644 --- a/test/server/exampleCounterMain.cpp +++ b/test/server/exampleCounterMain.cpp @@ -33,6 +33,7 @@ int main(int argc,char *argv[]) { PVDatabasePtr master = PVDatabase::getMaster(); ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); + channelProvider->createChannelLocalDebugRecord("channelLocalDebug"); 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 e0030b6..6e60cc0 100644 --- a/test/server/testExampleServerMain.cpp +++ b/test/server/testExampleServerMain.cpp @@ -62,6 +62,7 @@ int main(int argc,char *argv[]) { PVDatabasePtr master = PVDatabase::getMaster(); ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); + channelProvider->createChannelLocalDebugRecord("channelLocalDebug"); StandardPVFieldPtr standardPVField = getStandardPVField(); String properties; ScalarType scalarType; @@ -82,6 +83,14 @@ int main(int argc,char *argv[]) pvRecord->process(); } result = master->addRecord(pvRecord); + recordName = "exampleDoubleArray"; + pvStructure = standardPVField->scalarArray(scalarType,properties); + pvRecord = PVRecord::create(recordName,pvStructure); + { + pvRecord->lock_guard(); + pvRecord->process(); + } + result = master->addRecord(pvRecord); recordName = "examplePowerSupply"; pvStructure = createPowerSupply(); PowerSupplyRecordTestPtr psr =