more work on memory issues.

Still problems.
Added channelLocalDebug.
This commit is contained in:
Marty Kraimer
2013-05-23 13:19:22 -04:00
parent ec7601392d
commit 6d894788a3
12 changed files with 1568 additions and 175 deletions

View File

@ -38,7 +38,7 @@
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 16-May-2013</h2>
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 23-May-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
@ -46,11 +46,11 @@
</dd>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@ -74,24 +74,29 @@ The minimum that an extenson must provide is a top level PVStructure and a proce
<h2 class="nocount">Status of this Document</h2>
<p>This is the 16-May-2013 version of the definition of pvDatabaseCPP.
<p>This is the 23-May-2013 version of the definition of pvDatabaseCPP.
</p>
<p>The following Channel methods are implemented and working: getField,
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
But lots of work remains:</p>
<dl>
<dt>Other Channel Methods</dt>
<dd>ChannelArray is next.</dd>
<dd>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.
</dd>
<dt>Monitor Algorithms</dt>
<dd>Monitor algorithms have no been implemented.
<dd>Monitor algorithms have not been implemented.
Thus all monitors are onPut.</dd>
<dt>Lifecycle problems</dt>
<dd>Problems when channel clients disconnect.
May need help from Matej</dd>
<dt>Memory leaks at exit</dt>
<dd>May need help from Matej.</dd>
I am asking for help from Matej</dd>
<dt>Memory leak at exit</dt>
<dd>I am asking for help from Matej</dd>
<dt>Scalar Arrays</dt>
<dd>Have not been tested. Share has not been implemented.</dd>
<dd>Share has not been implemented.
This will wait until Michael has new implementation of ScalarArray.</dd>
<dt>Structure Arrays</dt>
<dd>Has not been implemented</dd>
<dt>Testing</dt>
@ -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.</p>
<p>This document describes components that provides the following features:
<p>This document describes components that provide the following features:
<dl>
<dt>database<dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
@ -188,8 +193,9 @@ mrk&gt; bin/linux-x86_64/exampleCounter
<h4>ExampleCounter.h</h4>
<p>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</p>
A serious implementation might break the code into a header and an
implementation file.<p>
</p>The description consists of</p>
<pre>
class ExampleCounter;
typedef std::tr1::shared_ptr&lt;ExampleCounter&gt; ExampleCounterPtr;
@ -455,6 +461,18 @@ The following are the minimium features required</p>
Thus code will be generated only if other code includes the
header file and creates a record instance.
</dd>
<dt>recordList.h</dt>
<dd>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:
<pre>
recordName = "laptoprecordListPGRPC";
pvRecord = RecordListRecord::create(recordName);
result = master-&gt;addRecord(pvRecord);
</pre>
</dd>
</dl>
<p>The classes in pvDatabase.h describe a database of memory resident
smart records.
@ -856,16 +874,123 @@ private:
<dd>Virtual message of Requester.</dd>
</dl>
<h2>pvAccess</h2>
<p>Not yet described.
It is only of interest to someone who wants to understand how it works.
</p>
<p>A brief description is that it implements the following components of pvIOCJava:</p>
<p>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.</p>
<h3>channelProviderLocal</h3>
<p>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.</p>
<h3>ChannelLocalDebug</h3>
<p>The channelProvider implementation provides the ability to generate
debug messages based a debug level with the following meaning:</p>
<dl>
<dt>pvCopy</dt>
<dt>monitor</dt>
<dt>local ChannelProvider and Channel</dt>
<dt>&lt;=0</dt>
<dd>No debug messages </dd>
<dt>&gt;0</dt>
<dd>Generate a message when anything is created or destroyed</dd>
<dt>&gt;1</dt>
<dd>Also generate processing messages.</dd>
</dl>
<p>ChannelProviderLocal has a method:</p>
<pre>
void createChannelLocalDebugRecord(
String const &amp; recordName);
</pre>
<p>This method creates a PVRecord that allows a pvAccess client to set the
debug level.</p>
<h3>pvCopy</h3>
<p>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.
</p>
<h3>monitorAlgorithm</h3>
<p>Currently all that is implemented is a header file.
The only algorithm currently implemented is <b>onPut</b>
</p>
<h3>monitorFactory</h3>
<h4>Overview</h4>
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
as seen by a client.
See
<a href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the
monitoring interfaces for a PVRecord.
It implements queueSize=0 and queueSize&gt;=2.
</p>
<p>
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.</p>
<p>Currently only algorithm <b>onPut</b> is implemented but,
like pvIOCJava there are plans to support for the following monitor algorithms:</p>
<dl>
<dt>onPut</dt>
<dd>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.</dd>
<dt>onChange</dt>
<dd>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.</dd>
<dt>deadband</dt>
<dd>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.</dd>
<dt>periodic</dt>
<dd>A monitor is issued at a periodic rate if a put was issued to any field
being monitored.</dd>
</dl>
<h4>MonitorFactory</h4>
<p>MonitorFactory provides the following methods:</p>
<pre>class MonitorFactory
{
static MonitorPtr create(
PVRecordPtr const &amp; pvRecord,
MonitorRequester::shared_pointer const &amp; monitorRequester,
PVStructurePtr const &amp; pvRequest);
static void registerMonitorAlgorithmCreater(
MonitorAlgorithmCreatePtr const &amp; monitorAlgorithmCreate,
String const &amp; algorithmName);
}</pre>
<p>where</p>
<dl>
<dt>create</dt>
<dd>Create a monitor. The arguments are:
<dl>
<dt>pvRecord</dt>
<dd>The record being monitored.</dd>
<dt>monitorRequester</dt>
<dd>The monitor requester. This is the code to which monitot events
will be delivered.</dd>
<dt>pvRequest</dt>
<dd>The request options</dd>
</dl>
</dd>
<dt>registerMonitorAlgorithmCreater</dt>
<dd>Called by code that implements a monitor algorithm.</dd>
</dl>
<h3>channelLocalDebugRecord</h3>
<p>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.</p>
<p>ChannelProviderLocal has a method:</p>
<pre>
void createChannelLocalDebugRecord(String const &amp; recordName);
</pre>
<p>This creates an instance of a ChannelLocalDebugRecord and installs it
into the PVDatabase.</p>
</div>
</body>
</html>

View File

@ -0,0 +1,996 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>pvDatabaseCPP</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 23-May-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
<hr />
</div>
<h2 class="nocount">Abstract</h2>
<p>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.
</p>
<h2 class="nocount">Status of this Document</h2>
<p>This is the 23-May-2013 version of the definition of pvDatabaseCPP.
</p>
<p>The following Channel methods are implemented and working: getField,
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
But lots of work remains:</p>
<dl>
<dt>Other Channel Methods</dt>
<dd>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.
</dd>
<dt>Monitor Algorithms</dt>
<dd>Monitor algorithms have not been implemented.
Thus all monitors are onPut.</dd>
<dt>Lifecycle problems</dt>
<dd>Problems when channel clients disconnect.
I am asking for help from Matej</dd>
<dt>Memory leak at exit</dt>
<dd>I am asking for help from Matej</dd>
<dt>Scalar Arrays</dt>
<dd>Share has not been implemented.
This will wait until Michael has new implementation of ScalarArray.</dd>
<dt>Structure Arrays</dt>
<dd>Has not been implemented</dd>
<dt>Testing</dt>
<dd>Needs lots more testing</dd>
</dl>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<h3>Overview</h3>
<p>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.</p>
<p>This document describes components that provide the following features:
<dl>
<dt>database<dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
The two main components are:
<dl>
<dt>pvRecord</dt>
<dd>This encapsulates the concept of a smart record. It can be processed.
Changes to field values can be trapped. A record can be locked.</dd>
<dt>pvDatabase<dt>
<dd>This is a database of pvRecords.
Records can be added and removed from a database.</dd>
</dl>
<dt>pvAccess</dt>
<dd>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</dd>
</dl>
<p>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:</p>
<dl>
<dt>init</dt>
<dd>This is a method for initializing the support.
It returns true if successful and false otherwise.
</dd>
<dt>process</dt>
<dd>This is what makes a record smart.
</dd>
</dl>
<h3>Relationship with pvIOCJava.</h3>
<p>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.</p>
<p>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.</p>
</p>
<h3>Example PVRecord Extension</h3>
<p>The example implements a simple counter.
The example can be run on linux as follows:</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP
mrk&gt; bin/linux-x86_64/exampleCounter
</pre>
<p>The example consists of two components:</p>
<dl>
<dt>ExampleCounter.h</dt>
<dd>The source code for the counter.</dd>
<dt>exampleCounterMain.cpp</dt>
<dd>A main program that runs the example so that it can be accessed
by a pvAccess client.</dd>
</dl>
<h4>ExampleCounter.h</h4>
<p>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.<p>
</p>The description consists of</p>
<pre>
class ExampleCounter;
typedef std::tr1::shared_ptr&lt;ExampleCounter&gt; ExampleCounterPtr;
class ExampleCounter :
public PVRecord
{
public:
POINTER_DEFINITIONS(ExampleCounter);
static ExampleCounterPtr create(
epics::pvData::String const &amp; recordName);
virtual ~ExampleCounter();
virtual void destroy();
virtual bool init();
virtual void process();
private:
ExampleCounter(epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
epics::pvData::PVLongPtr pvValue;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
};
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dd>This is example specific but each support could provide
a similar static method.
</dd>
<dt>~ExampleCounter<dt>
<dd>The destructor must be declared virtual.</dd>
<dt><destroy</dt>
<dd>Called when the record is being destroyed.
This must call the base class destroy method.
<dt>init<dt>
<dd>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.</dd>
<dt>process<dt>
<dd>
This again is a virtual method of PVRecord.
</dd>
<dt>ExampleCounter<dt>
<dd>For the example this is private.</dd>
<dt>pvValue</dt>
<dd>This is the field of the top level structure that process
accesses.
</dd>
<dl>
<p>The implementation of create method is:</p>
<pre>
ExampleCounterPtr ExampleCounter::create(
epics::pvData::String const &amp; recordName)
{
epics::pvData::PVStructurePtr pvStructure =
epics::pvData::getStandardPVField()-&gt;scalar(
epics::pvData::pvDouble,"timeStamp,alarm"");
ExampleCounterPtr pvRecord(
new ExampleCounter(recordName,pvStructure));
if(!pvRecord-&gt;init()) pvRecord.reset();
return pvRecord;
}
</pre>
This:
<ul>
<li>Creates the top level structure.</li>
<li>Creates a ExampleCounterPtr via the constructor.</li>
<li>Calls init and if it fails resets the shared pointer.</li>
<li>Returns the shared pointer to the newly created record.</li>
</ul>
<p>The private constructor method is:</p>
<pre>
ExampleCounter::ExampleCounter(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure)
: PVRecord(recordName,pvStructure)
{
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
}
</pre>
The example is very simple. It just calls the base class constructor.
<p>The destructor and destroy methods are:</p>
<pre>
ExampleCounter::~ExampleCounter()
{
destroy();
}
void ExampleCounter::destroy()
{
PVRecord::destroy();
}
</pre>
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.
<p>The implementation of init is:</p>
<pre>
bool ExampleCounter::init()
{
initPVRecord();
epics::pvData::PVFieldPtr pvField;
pvValue = getPVStructure()-&gt;getLongField("value");
if(pvValue.get()==NULL) return false;
return true;
}
</pre>
This:
<ul>
<li>Calls initRecord which is implemented by the base class.
It MUST be called.</li>
<li>Calls getLongField to get the interface to the value field,
which must be a scalar with type long.</li>
<li>If a long value field was not found it returns false.</li>
<li>Returns true</li>
</ul>
<p>The implementation of process is:</p>
<pre>
void ExampleCounter::process()
{
pvValue-&gt;put(pvValue-&gt;get() + 1.0);
timeStamp.getCurrent();
pvTimeStamp.set(timeStamp);
}
</pre>
It adds 1.0 to the current value.
It then sets the timeStamp to the current time.
<h4>exampleCounterMain.cpp</h4>
<p>This is in test/server.
The main program is:</p>
<pre>
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-&gt;addRecord(pvRecord);
cout &lt;&lt; "result of addRecord " &lt;&lt; recordName &lt;&lt; " " &lt;&lt; result &lt;&lt; endl;
pvRecord.reset();
cout &lt;&lt; "exampleServer\n";
string str;
while(true) {
cout &lt;&lt; "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
return 0;
}
</pre>
This:
<ul>
<li>Gets a pointer to the master database.</li>
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
<li>Creates a ExampleCounter record with the name exampleCounter
</li>
<li>Prints exampleCounter on standard out.</li>
<li>Runs forever until the user types exit on standard in.</li>
</ul>
<h3>Phased Development</h3>
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
<dl>
<dt>pvRecord</d>
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
<dt>pvDatabase</d>
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
<dt>Local Channel Provider</dt>
<dd>Complete implementation of ChannelProvider and Channel.
This means that pvCopy and monitor are also implemented.</dd>
</dl>
<p>Future phases of pvDatabaseCPP might include:</p>
<dl>
<dt>Install</dt>
<dd>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.
</dd>
<dt>Field support</dt>
<dd>Add the ability to optionally add support to fields.
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
<dt>XML parser</dt>
<dd>This provides the ability to create record instances without writing any code.</dd>
</dl>
<p>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.</p>
<h3>Features Required for localChannelProvider</h3>
<dl>
<dt>pvCopy</dt>
<dd>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.<dd>
<dt>monitor</dt>
<dd>This provides the ability to monitor changes to fields of a record.</dd>
<dt>PVRecord and PVDatabase</dt>
<dd>Defined below.</dd>
<dt>The localChannelProvider itself</dt>
<dd>This is the pvAccess package in pvIOCJava.
The localChannelProvider will access data from PVRecords.
It will implement all channel methods.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>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</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
<dt>PVRecord</dt>
<dd>This, and a set of related interfaces, provides the following:
<dl>
<dt>Access to top level PVStructure</dt>
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
<dt>Record locking</dt>
<dd>A record can be locked and unlocked.
A record must be locked whenever data in the pvStructure is accessed.</dd>
<dt>Trapping data changes</dt>
<dd>A client can request to be notified when data in the pvStructure is modified.
It can do this on a field by field basis.</dd>
</dl>
</dd>
</dl>
<p>The following sections describes the classes required for the first phase.</p>
<h2>database</h2>
<p>This directory has the following files:</p>
<dl>
<dt>pvDatabase.h</dt>
<dd>
This is what is described in this section.
</dd>
<dt>pvDatabase.cpp</dt>
<dd>
The implementation of PVDatabase.
</dd>
<dt>pvRecord.cpp</dt>
<dd>
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.
</dd>
<dt>exampleCounter.h</dt>
<dd>
This was described in the introduction.
</dd>
<dt>powerSupplyRecordTest.h</dt>
<dd>
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.
</dd>
<dt>recordList.h</dt>
<dd>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:
<pre>
recordName = "laptoprecordListPGRPC";
pvRecord = RecordListRecord::create(recordName);
result = master-&gt;addRecord(pvRecord);
</pre>
</dd>
</dl>
<p>The classes in pvDatabase.h describe a database of memory resident
smart records.
It describes the following classes:</p>
<dl>
<dt>PVRecord</dt>
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
<dt>PVRecordField</dt>
<dt>PVRecordStructure</dt>
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
can be implemented.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
<dt>PVDatabase</dt>
<dd>This is a database of PVRecords.</dd>
</dl>
<p>Each class is described in a separate subsection.</p>
<h3>C++ namespace and typedefs</h3>
<pre>
namespace epics { namespace pvDatabase {
class PVRecord;
typedef std::tr1::shared_ptr&lt;PVRecord&gt; PVRecordPtr;
typedef std::map&lt;epics::pvData::String,PVRecordPtr&gt; PVRecordMap;
class PVRecordField;
typedef std::tr1::shared_ptr&lt;PVRecordField&gt; PVRecordFieldPtr;
typedef std::vector&lt;PVRecordFieldPtr&gt; PVRecordFieldPtrArray;
typedef std::tr1::shared_ptr&lt;PVRecordFieldPtrArray&gt; PVRecordFieldPtrArrayPtr;
class PVRecordStructure;
typedef std::tr1::shared_ptr&lt;PVRecordStructure&gt; PVRecordStructurePtr;
class PVRecordClient;
typedef std::tr1::shared_ptr&lt;PVRecordClient&gt; PVRecordClientPtr;
class PVListener;
typedef std::tr1::shared_ptr&lt;PVListener&gt; PVListenerPtr;
class RecordProcessRequester;
typedef std::tr1::shared_ptr&lt;RecordProcessRequester&gt; RecordProcessRequesterPtr;
class RecordPutRequester;
typedef std::tr1::shared_ptr&lt;RecordPutRequester&gt; RecordPutRequesterPtr;
class PVDatabase;
typedef std::tr1::shared_ptr&lt;PVDatabase&gt; PVDatabasePtr;
</pre>
<h3>class PVRecord</h3>
<p>NOTES:
<ul>
<li>This section uses the name record instead of "an instance of PVRecord".</li>
<li>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.</li>
<li>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.
</ul>
<hr>PVRecord Methods</h4>
<pre>
class PVRecord
public epics::pvData::Requester,
public std::tr1::enable_shared_from_this&lt;PVRecord&gt;
{
public:
POINTER_DEFINITIONS(PVRecord);
virtual bool init() {initPVRecord(); return true;}
virtual void process() {}
static PVRecordPtr create(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
virtual ~PVRecord();
virtual void destroy();
epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure();
PVRecordFieldPtr findPVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField);
bool addRequester(epics::pvData::RequesterPtr const &amp; requester);
bool removeRequester(epics::pvData::RequesterPtr const &amp; requester);
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
void lock();
void unlock();
bool tryLock();
void lockOtherRecord(PVRecordPtr const &amp; otherRecord);
bool addPVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
bool removePVRecordClient(PVRecordClientPtr const &amp; pvRecordClient);
void detachClients();
bool addListener(PVListenerPtr const &amp; pvListener);
bool removeListener(PVListenerPtr const &amp; pvListener);
void beginGroupPut();
void endGroupPut();
epics::pvData::String getRequesterName() {return getRecordName();}
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
void message(
PVRecordFieldPtr const &amp; pvRecordField,
epics::pvData::String const &amp; 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 &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
void initPVRecord();
epics::pvData::PVStructurePtr getPVStructure();
PVRecordPtr getPtrSelf()
{
return shared_from_this();
}
private:
...
}
</pre>
<p>The methods are:</h3>
<dl>
<dt>init</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
This method Must call initPVRecord.</p>
</dd>
<dt>process</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
The base implementation does nothing.</p>
</dd>
<dt>create</dt>
<dd>Static method to create dumb records, i.e. records with a process method
that does nothing.</dd>
<dt>~PVRecord</dt>
<dd>The destructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dt>destroy</dt>
<dd>This is a virtual method.
</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
<dd>Get the top level PVStructure.</dd>
<dt>findPVRecordField</dt>
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
<dt>addRequester</dt>
<dd>Add a requester to receive messages.</dd>
<dt>removeRequester</dt>
<dd>Remove a message requester.</dd>
<dt>lock_guard</dt>
<dd>This is an inline method that locks the record. The record will automatically
be unlocked when control leaves the block that has the call.
<dt>lock</dt>
<dt>unlock</dt>
<dd>Lock and Unlock the record.
Any code accessing the data in the record or calling other PVRecord methods
must have the record locked.</dd>
<dt>tryLock</dt>
<dd>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.
</dd>
<dt>lockOtherRecord</dt>
<dd>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.
</dd>
<dt>addPVRecordClient</dt>
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
<dt>removePVRecordClient</dt>
<dd>Client is no longer accessing the record.</dd>
<dt>detachClients</dt>
<dd>Ask all clients to detach from the record</dd>
<dt>addListener</dt>
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
<dt>removeListener</dt>
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
<dt>beginGroupPut</dt>
<dd>Begin a group of puts.
This results in all registered PVListeners being called</dd>
<dt>endGroupPut</dt>
<dd>End a group of puts.
This results in all registered PVListeners being called.</dd>
<dt>getRequesterName</dt>
<dd>virtual method of Requester
</dd>
<dt>message</dt>
<dd>Can be called by implementation code.
The message will be sent to every requester.</dd>
<dt>toString</dt>
<dd>Just calls the top level PVStructure toString method.</dd>
<dt>PVRecord</dt>
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
<dt>initPVRecord</dt>
<dd>This method must be called by derived class.</dd>
<dt>getPVStructure</dt>
<dd>Called by derived class.</dd>
</dl>
<h3>class PVRecordField</h3>
<pre>
class PVRecordField {
public virtual epics::pvData::PostHandler,
public std::tr1::enable_shared_from_this&lt;PVRecordField&gt;
public:
POINTER_DEFINITIONS(PVRecordField);
PVRecordField(
epics::pvData::PVFieldPtr const &amp; pvField,
PVRecordStructurePtr const &amp;parent,
PVRecordPtr const &amp; 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 &amp; pvListener);
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
virtual void message(
epics::pvData::String const &amp; message,
epics::pvData::MessageType messageType);
protected:
PVRecordFieldPtr getPtrSelf()
{
return shared_from_this();
}
virtual void init();
private:
...
};
</pre>
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordField</dt>
<dd>The constructor.</dd>
<dt>~PVRecordField</dt>
<dd>The destructor.</dd>
<dt>destroy</dt>
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
<dt>getParent</dt>
<dd>Get the parent PVRecordStructure for this field.</dd>
<dt>getPVField</dt>
<dd>Get the PVField associated with this PVRecordField.</dd>
<dt>getFullFieldName</dt>
<dd>This gets the full name of the field, i.e. field,field,..</dd>
<dt>getFullName</dt>
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
<dt>getPVRecord</dt>
<dd>Returns the PVRecord to which this field belongs.</dd>
<dt>addListener</dt>
<dd>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.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<dt>message</dt>
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
fieldname.</dd>
</dl>
<h3>class PVRecordStructure</h3>
<pre>
class PVRecordStructure : public PVRecordField {
public:
POINTER_DEFINITIONS(PVRecordStructure);
PVRecordStructure(
epics::pvData::PVStructurePtr const &amp; pvStructure,
PVRecordFieldPtrArrayPtr const &amp; pvRecordField);
virtual ~PVRecordStructure();
virtual void destroy();
PVRecordFieldPtrArrayPtr getPVRecordFields();
epics::pvData::PVStructurePtr getPVStructure();
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
protected:
virtual void init();
private:
...
};
</pre>
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
that holds the data. It has the following methods:
</p>
<dl>
<dt>PVRecordStructure</dt>
<dd>The constructor.</dd>
<dt>~PVRecordStructure</dt>
<dd>The destructor.</dd>
<dt>getPVRecordFields</dt>
<dd>Get the PVRecordField array for the subfields</dd>
<dt>getPVStructure</dt>
<dd>Get the PVStructure for this field.</dd>
<dt>removeListener</dt>
<dd>Remove a PVListener.</dd>
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
<h3>class PVRecordClient</h3>
<pre>
class PVRecordClient {
POINTER_DEFINITIONS(PVRecordClient);
virtual ~PVRecordClient();
virtual void detach(PVRecordPtr const &amp; pvRecord);
};
</pre>
<p>where</p>
<dl>
<dt>~PVRecordClient</dt>
<dd>The destructor.</dd>
<dt>detach</dt>
<dd>The record is being removed from the master database,</dd>
</dl>
</dl>
<h3>class PVListener</h3>
<pre>
class PVListener {
virtual public PVRecordClient
public:
POINTER_DEFINITIONS(PVListener);
virtual ~PVListener();
virtual void dataPut(PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
};
</pre>
<p>where</p>
<dl>
<dt>~PVListener</dt>
<dd>The destructor.</dd>
<dt>dataPut(PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
<dt>dataPut(
PVRecordStructurePtr const &amp;
requested,PVRecordFieldPtr const &amp; pvRecordField)</dt>
<dd>pvField has been modified.
Requested is the field to which the requester issued a pvField-&amp;addListener.
This is called if the listener has called PVRecordField-&amp;addListener for requested.</dd>
<dt>beginGroupPut</dt>
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
<dd>A related set of changes is done.</dd>
</dl>
<h3>class PVDatabase</h3>
<pre>
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&amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
bool removeRecord(PVRecordPtr const &amp; record);
virtual epics::pvData::String getRequesterName();
virtual void message(
epics::pvData::String const &amp;message,
epics::pvData::MessageType messageType);
private:
PVDatabase();
};
</pre>
<p>where</p>
<dl>
<dt>getMaster</dt>
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
<dt>~PVDatabase</dt>
<dd>The destructor.</dd>
<dt>destroy</dt>
<dd>This is called by remote channelAccess when process exits.
This destroys and removes all records in the PVDatabase.</dd>
<dt>findRecord</dt>
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
<dt>addRecord</dt>
<dd>Add a record to the database.
If the record already exists it is not modified and false is returned.</dd>
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
<dt>getRequesterName</dt>
<dd>Virtual method of Requester</dd>
<dt>message</dt>
<dd>Virtual message of Requester.</dd>
</dl>
<h2>pvAccess</h2>
<p>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.</p>
<h3>channelProviderLocal</h3>
<p>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.</p>
<h3>ChannelLocalDebug</h3>
<p>The channelProvider implementation provides the ability to generate
debug messages based a debug level with the following meaning:</p>
<dl>
<dt>&lt;=0</dt>
<dd>No debug messages </dd>
<dt>&gt;0</dt>
<dd>Generate a message when anything is created or destroyed</dd>
<dt>&gt;1</dt>
<dd>Also generate processing messages.</dd>
</dl>
<p>ChannelProviderLocal has a method:</p>
<pre>
void createChannelLocalDebugRecord(
String const &amp; recordName);
</pre>
<p>This method creates a PVRecord that allows a pvAccess client to set the
debug level.</p>
<h3>pvCopy</h3>
<p>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.
</p>
<h3>monitorAlgorithm</h3>
<p>Currently all that is implemented is a header file.
The only algorithm currently implemented is <b>onPut</b>
</p>
<h3>monitorFactory</h3>
<h4>Overview</h4>
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
as seen by a client.
See
<a href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the
monitoring interfaces for a PVRecord.
It implements queueSize=0 and queueSize&gt;=2.
</p>
<p>
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.</p>
<p>Currently only algorithm <b>onPut</b> is implemented but,
like pvIOCJava there are plans to support for the following monitor algorithms:</p>
<dl>
<dt>onPut</dt>
<dd>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.</dd>
<dt>onChange</dt>
<dd>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.</dd>
<dt>deadband</dt>
<dd>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.</dd>
<dt>periodic</dt>
<dd>A monitor is issued at a periodic rate if a put was issued to any field
being monitored.</dd>
</dl>
<h4>MonitorFactory</h4>
<p>MonitorFactory provides the following methods:</p>
<pre>class MonitorFactory
{
static MonitorPtr create(
PVRecordPtr const &amp; pvRecord,
MonitorRequester::shared_pointer const &amp; monitorRequester,
PVStructurePtr const &amp; pvRequest);
static void registerMonitorAlgorithmCreater(
MonitorAlgorithmCreatePtr const &amp; monitorAlgorithmCreate,
String const &amp; algorithmName);
}</pre>
<p>where</p>
<dl>
<dt>create</dt>
<dd>Create a monitor. The arguments are:
<dl>
<dt>pvRecord</dt>
<dd>The record being monitored.</dd>
<dt>monitorRequester</dt>
<dd>The monitor requester. This is the code to which monitot events
will be delivered.</dd>
<dt>pvRequest</dt>
<dd>The request options</dd>
</dl>
</dd>
<dt>registerMonitorAlgorithmCreater</dt>
<dd>Called by code that implements a monitor algorithm.</dd>
</dl>
<h3>channelLocalDebugRecord</h3>
<p>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.</p>
<p>ChannelProviderLocal has a method:</p>
<pre>
void createChannelLocalDebugRecord(String const &amp; recordName);
</pre>
<p>This creates an instance of a ChannelLocalDebugRecord and installs it
into the PVDatabase.</p>
</div>
</body>
</html>

View File

@ -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

View File

@ -39,12 +39,6 @@ typedef std::tr1::shared_ptr<ChannelRPCLocal> ChannelRPCLocalPtr;
class ChannelArrayLocal;
typedef std::tr1::shared_ptr<ChannelArrayLocal> 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<Monitor::shared_pointer>::iterator it;
it = channelMonitorList.begin();
if(it==channelMonitorList.end()) break;
it->get()->destroy();
channelMonitorList.erase(it);
}
while(true) {
std::set<ChannelRPC::shared_pointer>::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)

View File

@ -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 <pv/channelLocalDebugRecord.h>
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());
}
}}

View File

@ -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 <pv/channelProviderLocal.h>
namespace epics { namespace pvDatabase {
class ChannelLocalDebugRecord;
typedef std::tr1::shared_ptr<ChannelLocalDebugRecord> 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 */

View File

@ -11,6 +11,7 @@
#include <pv/serverContext.h>
#include <pv/channelProviderLocal.h>
#include <pv/channelLocalDebugRecord.h>
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;
}
}
}}

View File

@ -28,9 +28,16 @@
namespace epics { namespace pvDatabase {
class ChannelLocalDebug;
typedef std::tr1::shared_ptr<ChannelLocalDebug> ChannelLocalDebugPtr;
class MonitorFactory;
typedef std::tr1::shared_ptr<MonitorFactory> MonitorFactoryPtr;
class MonitorLocal;
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
class ChannelProviderLocal;
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
class ChannelLocal;
@ -42,6 +49,23 @@ class MonitorLocal;
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
typedef std::set<MonitorLocalPtr> 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<MonitorAlgorithmCreatePtr> 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<epics::pvAccess::ChannelProcess::shared_pointer> channelProcessList;
std::set<epics::pvAccess::ChannelGet::shared_pointer> channelGetList;
std::set<epics::pvAccess::ChannelPut::shared_pointer> channelPutList;
std::set<epics::pvAccess::ChannelPutGet::shared_pointer> channelPutGetList;
std::set<epics::pvData::Monitor::shared_pointer> channelMonitorList;
std::set<epics::pvAccess::ChannelRPC::shared_pointer> channelRPCList;
std::set<epics::pvAccess::ChannelArray::shared_pointer> channelArrayList;
epics::pvData::Mutex mutex;

View File

@ -38,9 +38,6 @@ typedef std::tr1::shared_ptr<NOQueue> NOQueuePtr;
class RealQueue;
typedef std::tr1::shared_ptr<RealQueue> RealQueuePtr;
class MonitorLocal;
typedef std::tr1::shared_ptr<MonitorLocal> 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<MonitorLocalPtr>::iterator iter;
for (iter = monitorLocalList.begin(); iter!= monitorLocalList.end(); ++iter) {
if(iter->get()==monitor) {
monitorLocalList.erase(iter);
return;
}
}
}
void MonitorFactory::registerMonitorAlgorithmCreate(
MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate)
{

View File

@ -1027,6 +1027,7 @@ void PVCopyMonitor::startMonitoring(
void PVCopyMonitor::stopMonitoring()
{
std::cout << "PVCopyMonitor::stopMonitoring()" << std::endl;
pvRecord->removeListener(getPtrSelf());
}

View File

@ -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);

View File

@ -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 =