main addition is array performance example

This commit is contained in:
Marty Kraimer
2013-08-28 10:51:04 -04:00
parent 614491c02e
commit 64afb395a8
38 changed files with 3277 additions and 982 deletions

View File

@ -38,23 +38,18 @@
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 06-Aug-2013</h2>
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 28-Aug-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>
href="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_20130806.html">
pvDatabaseCPP20130806.html</a>
href= "pvDatabaseCPP_20130828.html">pvDatabaseCPP20130828.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_20130725.html">
pvDatabaseCPP20130725.html</a>
<dd><a href="pvDatabaseCPP_20130725.html">pvDatabaseCPP20130725.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@ -78,33 +73,44 @@ 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 06-Aug-2013 version of the definition of pvDatabaseCPP.
<p>This is the 28-Aug-2013 version of of pvDatabaseCPP.
<p><b>NOTE:</b>
This is built against pvDataCPP-md NOT against pvDataCPP.
To build you must also
checkout pvAccessCPP and build it against pvDataCPP-md.
</p>
</p>
<p>All channel methods except channelRPCi, which is implemented
<p>All channel methods except channelRPC, which is implemented
by pvAccess, have been implemented.
This project is ready for alpha users.
</p>
<p>Future enhancements in priority order:</p>
<dl>
<dt>Termination issues.</dt>
<dd>There are memory leak and other issues when either the main programs or v3IOC terminates.</dd>
<dt>Array performance</dt>
<dd>Create an example record that continuously creates array data.
The idea is to compare performance allocating memory from the
heap vs using a free list.</dd>
<dt>Separate example that also has pvaSrv</dt>
<dd>Create a separate example that combines a V3IOC,
a pvDatabase, and pvaSrv.</dd>
a pvDatabase, and pvaSrv.
This will not be done until pvDataCPP-md is merged into pvDataCPP.
</dd>
<dt>channelArray</dt>
<dd>The arguments that have type <b>int</b> should be changed to <b>size_t</b>
This will not be done until pvDataCPP-md is merged into pvDataCPP.
</dd>
<dt>arrayPerformanceMain</dt>
<dd>When this is run without a pvAccess client the performance is great.
But when a pvAccess client is monitoring then the preformance slows
more then expected.
I do not understand and must spend more time determining why.</dd>
<dt>Monitor Algorithms</dt>
<dd>Monitor algorithms have not been implemented.
Thus all monitors are onPut.</dd>
<dt>Testing</dt>
<dd>Needs more testing</dd>
<dd>Needs more testing.
Also none of the examples that use pvAccess can be run with gdb.
</dd>
<dt>Termination issues.</dt>
<dd>longArrayMonitor has memory leaks when main terminates.</dt>
<dt>Create regression tests</dt>
<dd>Currently only examples exist and have been used for testing.</dd>
</dl>
<div id="toc">
@ -228,7 +234,7 @@ try starting exampleServerMain and exampleServer.
<p>This example provides the exampleCounter record in addition to a number of other PVRecords.
Like exampleCounter it can be started either as a standalone main program or as
a part of a V3IOC.
The exampleServer pvDatabase includes the following records:</p>
The exampleServer pvDatabase has many records including the following:</p>
<dl>
<dt>exampleCounter</dt>
<dd>A record that is an instance of exampleCounter described below.
@ -245,7 +251,7 @@ The exampleServer pvDatabase includes the following records:</p>
<dd>Can be used by channelGet, channelPut, channelPutGet, and monitor.</dd>
<dt>laptoprecordListPGRPC</dt>
<dd>Implements the record expected by swtshell channelList.
It can also be used via channelPutGet but unnecessary.</dd>
It can also be used via channelPutGet.</dd>
<dt>traceRecordPGRPC</dt>
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
</dl>
@ -253,14 +259,14 @@ The exampleServer pvDatabase includes the following records:</p>
<h3>swtshell</h3>
<p>The Java program
<a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
href="http://epics-pvdata.sourceforge.net/docbuild/swtshellJava/tip/documentation/swtshellJava.html">
swtshell</a>
can be used to access pvDatabase.</p>
<p>In particular read the sections "Getting Started" and "Simple Example".
They will work on the exampleServer with the following differences:
<dl>
<dt>startExample.zip</dt>
<dd>Do NOT use this. Instead run exampleServer</dd>
<dd>Do NOT use this. Instead run the exampleServer as described above.</dd>
<dt>channelList result</dt>
<dd>The result of channelList will show the list of records that
exampleServer has rather than the records from startExample.zip</dd>
@ -270,7 +276,7 @@ They will work on the exampleServer with the following differences:
<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
PVDatabaseCPP implements 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.
@ -308,11 +314,11 @@ mrk&gt; bin/linux-x86_64/exampleCounter
by a pvAccess client.
It is located in directory pvDatabaseCPP/example/exampleCounter.
</dd>
<dt>v3IOC/exampleCounter</dt>
<dt>V3IOC/exampleCounter</dt>
<dd>This is a directory that packages exampleCounter to make it
part of a v3IOC.</dd>
part of a V3IOC.</dd>
<dt>iocBoot/exampleCounter</dt>
<dd>A place to start exampleCounter as part of a v3IOC.
<dd>A place to start exampleCounter as part of a V3IOC.
It follows the normal iocCore conventions.</dd>
</dl>
<h4>ExampleCounter.h</h4>
@ -425,7 +431,7 @@ bool ExampleCounter::init()
initPVRecord();
epics::pvData::PVFieldPtr pvField;
pvValue = getPVStructure()-&gt;getLongField("value");
if(pvValue.get()==NULL) return false;
if(pvValue==NULL) return false;
return true;
}
</pre>
@ -487,19 +493,19 @@ This:
<li>Prints exampleCounter on standard out.</li>
<li>Runs forever until the user types exit on standard in.</li>
</ul>
<h4>v3IOC exampleCounter</h4>
<h4>V3IOC exampleCounter</h4>
<p>This has two subdirectories:
<dl>
<dt>Db</dt>
<dd>This has a template for a single v3Record.</dd>
<dt>src</dt>
<dd>This has code to allow exampleCounter to reside in a v3IOC.</dd>
<dd>This has code to allow exampleCounter to reside in a V3IOC.</dd>
</dl>
</p>
<p>The src directory has the following components:</p>
<dl>
<dt>exampleCounterMain.cpp</dt>
<dd>This is just a standard Main for a v3IOC.</dd>
<dd>This is just a standard Main for a V3IOC.</dd>
<dt>exampleCounterInclude.dbd</dt>
<dd>This is:
<pre>
@ -514,7 +520,7 @@ registrar("exampleCounterRegister")
</dd>
<dt>exampleCounter.cpp</dt>
<dd>This is the code that registers a command the can be issued
via the iocsh, which is the console for a v3IOC.
via the iocsh, which is the console for a V3IOC.
The example supports a single command:
<pre>
exampleCounterCreateRecord recordName
@ -561,9 +567,9 @@ The rest of this document discusses only the first phase.</p>
<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>
<dd>This is the C++ implementation of package pvAccess in pvIOCJava.
The localChannelProvider accesses data from PVRecords.
It implements all channel methods except channelRPC, which is implemented by pvAccessCPP.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
@ -590,7 +596,7 @@ The following are the minimium features required</p>
<p>The following sections describes the classes required for the first phase.</p>
<h2>iocshell commands</h2>
<p>The following iocsh commands are provided:</p>
<p>The following iocsh commands are provided for a V3IOC:</p>
<dl>
<dt>startPVAClient</dt>
<dd>Starts the client side of pvAccess.s
@ -608,15 +614,16 @@ The following are the minimium features required</p>
<dd>Provides a list of all the pvRecords in database <b>master</b>
It is similar to the iocsh command <b>dbl</b></dd>
</dl>
<p>The client commands are provided via PVAClientRegister.dbd and the othet commands
<p>The client commands are provided via PVAClientRegister.dbd and the other commands
via PVAServerRegister.dbd.</p>
<p>In addition any code that implements a PVRecord must implement an ioc command.
The directory example has examples of how to implement the registration code.
See example/v3IOC/exampleCounter/src/ for a simple example.</p>
See example/V3IOC/exampleCounter/src/ for a simple example.</p>
<h2>database</h2>
<p>This directory has the following files:</p>
<h3>src/database</h3>
<p>This Directory has the following files:</p>
<dl>
<dt>pvDatabase.h</dt>
<dd>
@ -634,10 +641,10 @@ See example/v3IOC/exampleCounter/src/ for a simple example.</p>
This can be used to create a "dumb" record where all changes are
done by clients.
</dd>
<dt>exampleCounter.h</dt>
<dd>
This was described in the introduction.
</dd>
</dl>
<h3>src/special</h3>
<p>This directory has the following files:</p>
<dl>
<dt>powerSupplyRecordTest.h</dt>
<dd>
This provides code that simulates a power supply.
@ -663,6 +670,7 @@ result = master-&gt;addRecord(pvRecord);
another record. See below for a discussion of trace level.</dd>
</dl>
<h3>pvDatabase.h</h3>
<p>The classes in pvDatabase.h describe a database of memory resident
smart records.
It describes the following classes:</p>
@ -1121,7 +1129,7 @@ The only algorithm currently implemented is <b>onPut</b>
<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>
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the
@ -1324,7 +1332,7 @@ i. e. copy on write semantics are enforced. This is done automatically
by pvData and not by pvDatabase.</p>
<h4>Some details</h4>
<p>As mentioned before a pvDatabase server can be either a separate process,
i. e. a main program, or can be part of a v3IOC.</p>
i. e. a main program, or can be part of a V3IOC.</p>
<p>A main pvDatabase server issues the following calls:</p>
<pre>
ClientFactory::start();
@ -1363,7 +1371,7 @@ examplePVADoubleArrayGet shows how to use pvAccess to get data.</p>
<dd>This is the implementation code for the example.</dd>
<dt>example/examplePVADoubleArrayGet</dt>
<dd>This is the code that starts the example as a main program.</dd>
<dt>example/v3IOC/examplePVADoubleArrayGet/src</dt>
<dt>example/V3IOC/examplePVADoubleArrayGet/src</dt>
<dd>This is the code for starting the example as part of a V3IOC.</dd>
<dt>iocBoot/examplePVADoubleArrayGet</dt>
<dd>This has the st.cmd files to start the example.</dd>
@ -1557,7 +1565,7 @@ This is the record that can be accessed via pvAccess if the channelName is
<p>It the runs forever until the exit is typed.</p>
<h4>Start the example as part of a V3IOC</h4>
The directory example/v3IOC/examplePVADoubleArrayGet has two subdirectories: Db and src.
The directory example/V3IOC/examplePVADoubleArrayGet has two subdirectories: Db and src.
These are like for any other V3IOC application.
The Db directory is for a regular ai record.
The src directory has code similar to any V3IOC application.
@ -1579,6 +1587,140 @@ where
<dd>This creates the example using the remote channel provider.</dd>
</dl>
<h2>Array Performance</h2>
<p>Two main programs are available for testing the performance of large
arrays: arrayPerformanceMain and longArrayMonitorMain.
Each has support for <b>-help</b>.</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/arrayPerformanceMain -help
arrayPerformanceMain recordName size delay providerName nMonitor useQueue
default
arrayPerformance arrayPerformance 50000000 0.001 local 1 false
mrk&gt; bin/linux-x86_64/longArrayMonitorMain -help
longArrayMonitorMain channelName useQueue
default
longArrayMonitorMain arrayPerformance false
mrk&gt;
</pre>
<h3>Example output</h3>
<pre>
mrk&gt; bin/linux-x86_64/arrayPerformanceMain
arrayPerformance arrayPerformance 50000000 0.01 local 1 false
...
first 0 last 0 sum 0 elements/sec 525.011million changed {1, 2} overrun {}
first 1 last 1 sum 50000000 elements/sec 494.511million changed {1, 2} overrun {}
first 2 last 2 sum 100000000 elements/sec 515.34million changed {1, 2} overrun {}
first 3 last 3 sum 150000000 elements/sec 154.402million changed {1, 2} overrun {}
first 4 last 4 sum 200000000 elements/sec 513.414million changed {1, 2} overrun {}
first 5 last 5 sum 250000000 elements/sec 473.672million changed {1, 2} overrun {}
first 6 last 6 sum 300000000 elements/sec 503.855million changed {1, 2} overrun {}
arrayPerformance value 8 time 1.66373 iterations/sec 4.80847 elements/sec 240.424million
...
</pre>
<h3>arrayPerformance</h3>
<p>
This creates a PVRecord that has the structure:.
<pre>
recordName
long[] value
timeStamp timeStamp
alarm alarm
</pre>
Thus it holds an array of 64 bit integers.</p>
<p>The record has support that consists of a separate thread that runs
until the record is destroyed executing the following algorithm:</p>
<dl>
<dt>report</dt>
<dd>At least once a second it produces a report.
In the above example output each line starting with
<b>ArrayPerformance</b> is an arrayPerformance report.
</dd>
<dt>create array</dt>
<dd>A new shared_vector is created and each element is set equal
to the interation count.</dd>
<dt>lock</dt>
<dd>The arrayPerformance record is locked.</dd>
<dt>Begin group put</dt>
<dd>beginGroupReport is called.</dd>
<dt>replace</dt>
<dd>The value field of the record is replaced
with the newly created shared_vector.</dd>
<dt>process</dt>
<dd>The record is then processed. This causes the timeStamp to
be set to the current time.</dd>
<dt>End group put</dt>
<dd>endGroupPut is called.</dd>
<dt>unlock</dt>
<dd>The arrayPerformance record is unlocked.</dd>
<dt>delay</dt>
<dd>If delay is greater than zero epicsThreadSleep is called.</dd>
</dl>
<p>The arguments for arrayPerforamanceMain are:</p>
<dl>
<dt>recordName</dt>
<dd>The name for the arrayPerform record.</dd>
<dt>size</dt>
<dd>The size for the long array of the value field.</dd>
<dt>delay</dt>
<dd>The time in seconds to sleep after each iteration.</dd>
<dt>providerName</dt>
<dd>The name of the channel provider for the longArrayMonitors
created by the main program. This must be either <b>local</b>
or <b>pvAccess</b>.
</dd>
<dt>nMonitor</dt>
<dd>The number of longArrayMonitors to create.</dd>
<dt>useQueue</dt>
<dd>Should the longArrayMonitors use a queue?
This must be <b>true</b> or <b>false</b>.
</dd>
</dl>
<h3>longArrayMonitor</h3>
<p>This is a pvAccess client that monitors an arrayPerformance record.
It generates a report for each monitor event.
In the example output shown above each line starting with <b>first</b>
is a report.</p>
<p>The arguments for longArrayMonitorMain are:</p>
<dl>
<dt>channelName</dt>
<dt>useQueue</dt>
</dl>
<h3>Some results</h3>
<p>The results were from my laptop.
It has a 2.2Ghz intel core i7 with 4Gbytes of memory.
The operating system is linux fedora 16.</p>
<p>When test are performed with large arrays it is a good idea to also
run a system monitor facility and check memory and swap history.
If a test configuration causes physical memory to be exhausted
then performance becomes <b>very</b> poor.
You do not want to do this.</p>
<h4>arrayPerformance results</h4>
<p>The simplest test to run arrayPerformance with the defaults:</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/arrayPerformanceMain
</pre>
<p>This means that the array will hold 50 million elements.
The delay will be a millisecond.
There will be a single monitor and it will connect directly
to the local channelProvider, i. e. it will not use any network
connection.</p>
<p>The report shows that arrayPerformance can perform about 8 iterations per second
and is putting about 350million elements per second.
Since each element is an int64 this means about 2.8gigaBytes per second.
</p>
<p>When no monitors are requested and a remote longArrayMonitorMain is run:<p>
<pre>
mr&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/longArrayMonitorMain
</pre>
<p>The performance drops to about 90million elements per second.
In addition the time between reports varies from just over 1 second to 3 seconds.
I do not understand why.</p>
</div>
</body>

View File

@ -73,21 +73,21 @@ but the framework provides for complex extensions.</p>
V4 control system programming environment:</p>
<dl>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataJava/raw-file/tip/documentation/pvDataJava.html">pvData</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvDataJava/tip/documentation/pvDataJava.html">pvData</a></dt>
<dd>pvData (Process Variable Data) defines and implements an efficent way
to store, access, and communicate memory resident structured data</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessJava/raw-file/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvAccessJava/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
<dd>pvAccess is a software library for high speed controls network communications,
optimized for pvData</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCJava/raw-file/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvIOCJava/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
<dd>pvIOC is a software framework for building network accessable "smart" real time
databases, suitable for interfacing devices in a distributed control system,
that can exchange pvData over pvAccess.
</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvServiceJava/raw-file/tip/documentation/pvAccessJava.html">pvService</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvServiceJava/tip/documentation/pvAccessJava.html">pvService</a></dt>
<dd>A middle layer for implementing data services.</dd>
</dl>

View File

@ -42,15 +42,15 @@
<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>
href="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_20121211.html">pvDatabaseCPP20121211.html</a>
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.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_20121127.html">pvDatabaseCPP_20121127.html</a>
href="pvDatabaseCPP_20121127.html">pvDatabaseCPP_20121127.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@ -75,21 +75,21 @@ but the framework provides for complex extensions.</p>
V4 control system programming environment:</p>
<dl>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataJava/raw-file/tip/documentation/pvDataJava.html">pvData</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvDataJava/tip/documentation/pvDataJava.html">pvData</a></dt>
<dd>pvData (Process Variable Data) defines and implements an efficent way
to store, access, and communicate memory resident structured data</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessJava/raw-file/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvAccessJava/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
<dd>pvAccess is a software library for high speed controls network communications,
optimized for pvData</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCJava/raw-file/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvIOCJava/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
<dd>pvIOC is a software framework for building network accessable "smart" real time
databases, suitable for interfacing devices in a distributed control system,
that can exchange pvData over pvAccess.
</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvServiceJava/raw-file/tip/documentation/pvAccessJava.html">pvService</a></dt>
href="http://epics-pvdata.sourceforge.net/docbuild/pvServiceJava/tip/documentation/pvAccessJava.html">pvService</a></dt>
<dd>A middle layer for implementing data services.</dd>
</dl>

View File

@ -42,15 +42,15 @@
<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>
href="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_20130417.html">pvDatabaseCPP20130417.html</a>
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.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_20121211.html">pvDatabaseCPP20121211.html</a>
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>

View File

@ -42,15 +42,15 @@
<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>
href="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_20130516.html">pvDatabaseCPP20130516.html</a>
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.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="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>

View File

@ -42,15 +42,15 @@
<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>
href="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>
href="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>
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@ -918,7 +918,7 @@ The only algorithm currently implemented is <b>onPut</b>
<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>
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the

View File

@ -42,15 +42,15 @@
<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>
href="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_20130627.html">pvDatabaseCPP20130627.html</a>
href="pvDatabaseCPP_20130627.html">pvDatabaseCPP20130627.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_20130523.html">pvDatabaseCPP20130523.html</a>
href="pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@ -175,7 +175,7 @@ mrk&gt; bin/linux-x86_64/testExampleServer
</pre></p>
<p>The Java programs
<a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
href="http://epics-pvdata.sourceforge.net/docbuild/swtshellJava/tip/documentation/swtshellJava.html">
swtshellJava.html</a>
can be used to access the database.</p>
<p>In particular read the sections "Getting Started" and "Simple Example".
@ -994,7 +994,7 @@ The only algorithm currently implemented is <b>onPut</b>
<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>
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the

View File

@ -42,18 +42,15 @@
<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>
href="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_20130725.html">
pvDatabaseCPP20130725.html</a>
href= "pvDatabaseCPP_20130725.html">pvDatabaseCPP20130725.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_20130627.html">
pvDatabaseCPP20130627.html</a>
href="pvDatabaseCPP_20130627.html">pvDatabaseCPP20130627.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@ -221,7 +218,7 @@ try starting exampleServerMain and exampleServer.
<h3>swtshell</h3>
<p>The Java program
<a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
href="http://epics-pvdata.sourceforge.net/docbuild/swtshellJava/tip/documentation/swtshellJava.html">
swtshell</a>
can be used to access pvDatabase.</p>
<p>In particular read the sections "Getting Started" and "Simple Example".
@ -1086,7 +1083,7 @@ The only algorithm currently implemented is <b>onPut</b>
<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>
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@ DIRS += pvCopy
DIRS += exampleCounter
DIRS += exampleServer
DIRS += examplePVADoubleArrayGet
DIRS += arrayPerformance
DIRS += v3IOC
include $(TOP)/configure/RULES_DIRS

View File

@ -0,0 +1,20 @@
TOP=../..
include $(TOP)/configure/CONFIG
PROD_HOST += arrayPerformanceMain
arrayPerformanceMain_SRCS += arrayPerformanceMain.cpp
arrayPerformanceMain_LIBS += pvDatabase pvAccess pvData Com
arrayPerformanceMain_LIBS += pvDatabaseExample
PROD_HOST += longArrayMonitorMain
longArrayMonitorMain_SRCS += longArrayMonitorMain.cpp
longArrayMonitorMain_LIBS += pvDatabase pvAccess pvData Com
longArrayMonitorMain_LIBS += pvDatabaseExample
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@ -0,0 +1,108 @@
/*arrayPerformanceMain.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.08.08
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/arrayPerformance.h>
#include <pv/longArrayMonitor.h>
#include <pv/traceRecord.h>
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
#include <pv/clientFactory.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
bool result(false);
String recordName;
recordName = "arrayPerformance";
size_t size = 50000000;
double delay = .01;
String providerName("local");
size_t nMonitor = 1;
bool useQueue = false;
if(argc==2 && String(argv[1])==String("-help")) {
cout << "arrayPerformanceMain recordName size";
cout << " delay providerName nMonitor useQueue" << endl;
cout << "default" << endl;
cout << "arrayPerformance ";
cout << recordName << " ";
cout << size << " ";
cout << delay << " ";
cout << providerName << " ";
cout << nMonitor << " ";
cout << (useQueue ? "true" : "false") << endl;
return 0;
}
if(argc>1) recordName = argv[1];
if(argc>2) size = strtoul(argv[2],0,0);
if(argc>3) delay = atof(argv[3]);
if(argc>4) providerName = argv[4];
if(argc>5) nMonitor = strtoul(argv[5],0,0);
if(argc>6) useQueue = (argv[6]==String("true") ? true : false);
cout << "arrayPerformance ";
cout << recordName << " ";
cout << size << " ";
cout << delay << " ";
cout << providerName << " ";
cout << nMonitor << " ";
cout << (useQueue ? "true" : "false") << endl;
ClientFactory::start();
PVDatabasePtr master = PVDatabase::getMaster();
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
PVRecordPtr pvRecord;
pvRecord = ArrayPerformance::create(recordName,size,delay);
result = master->addRecord(pvRecord);
pvRecord = TraceRecord::create("traceRecordPGRPC");
result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
pvRecord.reset();
ServerContext::shared_pointer pvaServer =
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
std::vector<LongArrayMonitorPtr> longArrayMonitor(nMonitor);
for(size_t i=0; i<nMonitor; ++i) {
longArrayMonitor[i]
= LongArrayMonitor::create(providerName,recordName,useQueue);
}
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->start();
cout << "arrayPerformance\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
for(size_t i=0; i<nMonitor; ++i) longArrayMonitor[i]->stop();
pvaServer->shutdown();
epicsThreadSleep(1.0);
pvaServer->destroy();
ClientFactory::stop();
channelProvider->destroy();
return 0;
}

View File

@ -0,0 +1,70 @@
/*longArrayMonitorMain.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.08.10
*/
/* Author: Marty Kraimer */
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <vector>
#include <pv/standardField.h>
#include <pv/standardPVField.h>
#include <pv/arrayPerformance.h>
#include <pv/longArrayMonitor.h>
#include <pv/traceRecord.h>
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
#include <pv/clientFactory.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
int main(int argc,char *argv[])
{
String channelName("arrayPerformance");
bool useQueue = false;
if(argc==2 && String(argv[1])==String("-help")) {
cout << "longArrayMonitorMain channelName useQueue" << endl;
cout << "default" << endl;
cout << "longArrayMonitorMain " << channelName << " ";
cout << (useQueue ? "true" : "false") << endl;
return 0;
}
ClientFactory::start();
if(argc>1) channelName = argv[1];
if(argc>2) useQueue = (String(argv[2])==String("true") ? true : false);
cout << "longArrayMonitorMain " << channelName << " ";
cout << (useQueue ? "true" : "false") << endl;
LongArrayMonitorPtr longArrayMonitor
= LongArrayMonitor::create("pvAccess",channelName,useQueue);
longArrayMonitor->start();
cout << "longArrayMonitor\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
longArrayMonitor->destroy();
longArrayMonitor.reset();
ClientFactory::stop();
return 0;
}

View File

@ -47,7 +47,8 @@ int main(int argc,char *argv[])
result = master->addRecord(pvRecord);
if(!result) cout<< "record " << recordName << " not added" << endl;
pvRecord.reset();
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
ServerContext::shared_pointer pvaServer =
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
cout << "exampleCounter\n";
string str;
while(true) {
@ -56,6 +57,10 @@ int main(int argc,char *argv[])
if(str.compare("exit")==0) break;
}
pvaServer->shutdown();
epicsThreadSleep(1.0);
pvaServer->destroy();
channelProvider->destroy();
return 0;
}

View File

@ -116,7 +116,6 @@ static void testPVScalar(
size_t offset;
ConvertPtr convert = getConvert();
pvRecord->lock_guard();
cout << endl;
pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
pvField = pvStructureRecord->getSubField(valueNameRecord);
@ -129,11 +128,11 @@ static void testPVScalar(
pvField = pvStructureCopy->getSubField(valueNameCopy);
pvValueCopy = static_pointer_cast<PVScalar>(pvField);
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
pvCopy->initCopy(pvStructureCopy, bitSet, true);
pvCopy->initCopy(pvStructureCopy, bitSet);
cout << "after initCopy pvValueCopy " << convert->toDouble(pvValueCopy);
cout << endl;
convert->fromDouble(pvValueRecord,.06);
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet,true);
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
cout << "after put(.06) pvValueCopy " << convert->toDouble(pvValueCopy);
builder.clear();
bitSet->toString(&builder);
@ -156,7 +155,7 @@ static void testPVScalar(
cout << " bitSet " << builder;
cout << endl;
bitSet->set(0);
pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet,true);
pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
cout << "after updateCopyFromBitSet";
cout << " recordValue " << convert->toDouble(pvValueRecord);
cout << " copyValue " << convert->toDouble(pvValueCopy);
@ -169,7 +168,7 @@ static void testPVScalar(
cout << " copyValue " << convert->toDouble(pvValueCopy);
cout << " bitSet " << builder;
cout << endl;
pvCopy->updateRecord(pvStructureCopy,bitSet,true);
pvCopy->updateRecord(pvStructureCopy,bitSet);
cout << "after updateRecord";
cout << " recordValue " << convert->toDouble(pvValueRecord);
cout << " copyValue " << convert->toDouble(pvValueCopy);
@ -194,7 +193,6 @@ static void testPVScalarArray(
size_t offset;
size_t n = 5;
shared_vector<double> values(n);
pvRecord->lock_guard();
cout << endl;
pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
pvValueRecord = pvStructureRecord->getScalarArrayField(valueNameRecord,scalarType);
@ -207,7 +205,7 @@ static void testPVScalarArray(
pvStructureCopy = pvCopy->createPVStructure();
pvValueCopy = pvStructureCopy->getScalarArrayField(valueNameCopy,scalarType);
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
pvCopy->initCopy(pvStructureCopy, bitSet, true);
pvCopy->initCopy(pvStructureCopy, bitSet);
builder.clear(); pvValueCopy->toString(&builder);
cout << "after initCopy pvValueCopy " << builder << endl;
cout << endl;
@ -215,7 +213,7 @@ static void testPVScalarArray(
for(size_t i=0; i<n; i++) values[i] = i + .06;
const shared_vector<const double> yyy(freeze(values));
pvValueRecord->putFrom(yyy);
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet,true);
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
builder.clear(); pvValueCopy->toString(&builder);
cout << "after put(i+ .06) pvValueCopy " << builder << endl;
builder.clear();
@ -248,7 +246,7 @@ static void testPVScalarArray(
bitSet->toString(&builder);
cout << endl;
bitSet->set(0);
pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet,true);
pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
cout << "after updateCopyFromBitSet";
builder.clear(); pvValueRecord->toString(&builder);
cout << " recordValue " << builder << endl;
@ -272,7 +270,7 @@ static void testPVScalarArray(
bitSet->toString(&builder);
cout << " bitSet " << builder;
cout << endl;
pvCopy->updateRecord(pvStructureCopy,bitSet,true);
pvCopy->updateRecord(pvStructureCopy,bitSet);
cout << "after updateRecord";
builder.clear(); pvValueRecord->toString(&builder);
cout << " recordValue " << builder << endl;

View File

@ -64,7 +64,7 @@ static PVStructurePtr createPowerSupply()
}
int main(int argc,char *argv[])
void test()
{
StandardPVFieldPtr standardPVField = getStandardPVField();
String properties;
@ -77,11 +77,13 @@ int main(int argc,char *argv[])
pvStructure = standardPVField->scalar(scalarType,properties);
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
{
pvRecord->lock_guard();
pvRecord->lock();
pvRecord->process();
pvRecord->unlock();
}
cout << "processed exampleDouble " << endl;
pvRecord->destroy();
pvRecord.reset();
recordName = "powerSupplyExample";
pvStructure.reset();
pvStructure = createPowerSupply();
@ -89,14 +91,16 @@ int main(int argc,char *argv[])
PowerSupplyRecordTest::create(recordName,pvStructure);
if(psr.get()==NULL) {
cout << "PowerSupplyRecordTest::create failed" << endl;
return 1;
return;
}
pvStructure.reset();
double voltage,power,current;
{
psr->lock_guard();
psr->lock();
voltage = psr->getVoltage();
power = psr->getPower();
current = psr->getCurrent();
psr->unlock();
}
cout << "initial ";
cout << " voltage " << voltage ;
@ -110,21 +114,29 @@ int main(int argc,char *argv[])
cout << " power " << power;
cout << endl;
{
psr->lock_guard();
psr->lock();
psr->put(power,voltage);
psr->process();
psr->unlock();
}
{
psr->lock_guard();
psr->lock();
cout << "after put ";
cout << " voltage " << psr->getVoltage() ;
cout << " power " << psr->getPower();
cout << " current " << psr->getCurrent();
cout << endl;
psr->unlock();
}
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
pvDatabase->addRecord(psr);
psr.reset();
pvDatabase->destroy();
}
int main(int argc,char *argv[])
{
test();
return 0;
}

View File

@ -18,6 +18,12 @@ SRC_DIRS += $(EXAMPLESRC)/examplePVADoubleArrayGet
INC+= examplePVADoubleArrayGet.h
LIBSRCS += examplePVADoubleArrayGet.cpp
SRC_DIRS += $(EXAMPLESRC)/arrayPerformance
INC+= arrayPerformance.h
LIBSRCS += arrayPerformance.cpp
INC+= longArrayMonitor.h
LIBSRCS += longArrayMonitor.cpp
include $(TOP)/configure/RULES

View File

@ -0,0 +1,173 @@
/* arrayPerformance.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.08.08
*/
#include <pv/lock.h>
#include <pv/arrayPerformance.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
ArrayPerformancePtr ArrayPerformance::create(
epics::pvData::String const & recordName,
size_t size,
double delay)
{
epics::pvData::PVStructurePtr pvStructure =
epics::pvData::getStandardPVField()->scalarArray(epics::pvData::pvLong,"timeStamp,alarm");
ArrayPerformancePtr pvRecord(
new ArrayPerformance(recordName,pvStructure,size,delay));
if(!pvRecord->init()) pvRecord.reset();
return pvRecord;
}
ArrayPerformance::ArrayPerformance(
epics::pvData::String const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
size_t size,
double delay)
: PVRecord(recordName,pvStructure),
size(size),
delay(delay),
isDestroyed(false)
{
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
}
ArrayPerformance::~ArrayPerformance()
{
}
bool ArrayPerformance::init()
{
initPVRecord();
PVScalarArrayPtr pvScalarArray = getPVStructure()->getScalarArrayField("value",pvLong);
if(pvScalarArray==NULL) return false;
pvValue = static_pointer_cast<PVLongArray>(pvScalarArray);
ArrayPerformancePtr xxx = dynamic_pointer_cast<ArrayPerformance>(getPtrSelf());
arrayPerformanceThread = ArrayPerformanceThreadPtr(new ArrayPerformanceThread(xxx));
arrayPerformanceThread->init();
return true;
}
void ArrayPerformance::start()
{
arrayPerformanceThread->start();
}
void ArrayPerformance::process()
{
timeStamp.getCurrent();
pvTimeStamp.set(timeStamp);
}
void ArrayPerformance::destroy()
{
if(isDestroyed) return;
isDestroyed = true;
arrayPerformanceThread->destroy();
arrayPerformanceThread.reset();
PVRecord::destroy();
}
ArrayPerformanceThread::ArrayPerformanceThread(ArrayPerformancePtr const & arrayPerformance)
:
arrayPerformance(arrayPerformance),
isDestroyed(false),
runReturned(false),
threadName("arrayPerformance")
{}
void ArrayPerformanceThread::init()
{
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
threadName.c_str(),
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityHigh));
}
void ArrayPerformanceThread::start()
{
thread->start();
}
void ArrayPerformanceThread::destroy()
{
Lock lock(mutex);
if(isDestroyed) return;
isDestroyed = true;
while(true) {
if(runReturned) break;
lock.unlock();
epicsThreadSleep(.01);
lock.lock();
}
thread->exitWait();
thread.reset();
arrayPerformance.reset();
}
void ArrayPerformanceThread::run()
{
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
int nSinceLastReport = 0;
while(true) {
if(arrayPerformance->delay>0.0) epicsThreadSleep(arrayPerformance->delay);
{
Lock lock(mutex);
if(isDestroyed) {
runReturned = true;
return;
}
}
timeStamp.getCurrent();
double diff = TimeStamp::diff(timeStamp,timeStampLast);
if(diff>=1.0) {
cout << "arrayPerformance value " << value;
cout << " time " << diff;
double iterations = nSinceLastReport;
iterations /= diff;
cout << " iterations/sec " << iterations;
double elementSize = arrayPerformance->size;
double elementsPerSecond = elementSize*nSinceLastReport;
elementsPerSecond /= diff;
elementsPerSecond /= 1e6;
cout << " elements/sec " << elementsPerSecond << "million" << endl;
cout.flush();
timeStampLast = timeStamp;
nSinceLastReport = 0;
}
++nSinceLastReport;
shared_vector<int64> xxx(arrayPerformance->size,value++);
shared_vector<const int64> data(freeze(xxx));
arrayPerformance->lock();
try {
arrayPerformance->beginGroupPut();
arrayPerformance->pvValue->replace(data);
arrayPerformance->process();
arrayPerformance->endGroupPut();
} catch(...) {
arrayPerformance->unlock();
throw;
}
arrayPerformance->unlock();
}
}
}}

View File

@ -0,0 +1,80 @@
/* arrayPerformance.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.08.08
*/
#ifndef ARRAYPERFORMANCE_H
#define ARRAYPERFORMANCE_H
#include <epicsThread.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvDatabase.h>
namespace epics { namespace pvDatabase {
class ArrayPerformance;
typedef std::tr1::shared_ptr<ArrayPerformance> ArrayPerformancePtr;
class ArrayPerformanceThread;
typedef std::tr1::shared_ptr<ArrayPerformanceThread> ArrayPerformanceThreadPtr;
class ArrayPerformance :
public PVRecord
{
public:
POINTER_DEFINITIONS(ArrayPerformance);
static ArrayPerformancePtr create(
epics::pvData::String const & recordName,
size_t size,
double delay);
virtual ~ArrayPerformance();
virtual bool init();
virtual void start();
virtual void process();
virtual void destroy();
private:
ArrayPerformance(epics::pvData::String const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
size_t size,
double delay);
size_t size;
double delay;
bool isDestroyed;
epics::pvData::PVLongArrayPtr pvValue;
epics::pvData::PVTimeStamp pvTimeStamp;
epics::pvData::TimeStamp timeStamp;
ArrayPerformanceThreadPtr arrayPerformanceThread;
friend class ArrayPerformanceThread;
};
class ArrayPerformanceThread :
public epicsThreadRunable
{
public:
ArrayPerformanceThread(ArrayPerformancePtr const & arrayPerformance);
virtual ~ArrayPerformanceThread(){};
void init();
void start();
virtual void run();
void destroy();
private:
ArrayPerformancePtr arrayPerformance;
bool isDestroyed;
bool runReturned;
epics::pvData::String threadName;
epics::pvData::Mutex mutex;
epics::pvData::int64 value;
std::auto_ptr<epicsThread> thread;
};
}}
#endif /* ARRAYPERFORMANCE_H */

View File

@ -0,0 +1,284 @@
/* longArrayMonitor.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.08.09
*/
#include <epicsThread.h>
#include <pv/longArrayMonitor.h>
#include <pv/caProvider.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using namespace epics::pvAccess;
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::cout;
using std::endl;
static String requesterName("longArrayMonitor");
static void messagePvt(String const & message, MessageType messageType)
{
cout << requesterName << " message " << message << endl;
}
class LAMChannelRequester :
public ChannelRequester
{
public:
LAMChannelRequester(LongArrayMonitorPtr const &longArrayMonitor)
: longArrayMonitor(longArrayMonitor)
{}
virtual ~LAMChannelRequester(){}
virtual String getRequesterName() { return requesterName;}
virtual void message(String const & message, MessageType messageType)
{ messagePvt(message,messageType);}
virtual void channelCreated(const Status& status, Channel::shared_pointer const & channel);
virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState);
private:
LongArrayMonitorPtr longArrayMonitor;
};
void LAMChannelRequester::channelCreated(const Status& status, Channel::shared_pointer const & channel)
{
if(!status.isOK()) messagePvt(status.getMessage(),errorMessage);
longArrayMonitor->status = status;
longArrayMonitor->channel = channel;
longArrayMonitor->event.signal();
}
void LAMChannelRequester::channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState)
{
MessageType messageType = (connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
messagePvt("channelStateChange",messageType);
}
class LAMMonitorRequester :
public MonitorRequester,
public epicsThreadRunable
{
public:
LAMMonitorRequester(LongArrayMonitorPtr const &longArrayMonitor)
: longArrayMonitor(longArrayMonitor),
isDestroyed(false),
runReturned(false),
threadName("longArrayMonitor")
{}
virtual ~LAMMonitorRequester(){}
void init();
virtual void destroy();
virtual void run();
virtual String getRequesterName() { return requesterName;}
virtual void message(String const & message, MessageType messageType)
{ messagePvt(message,messageType);}
virtual void monitorConnect(Status const & status,
MonitorPtr const & monitor, StructureConstPtr const & structure);
virtual void monitorEvent(MonitorPtr const & monitor);
virtual void unlisten(MonitorPtr const & monitor);
private:
void handleMonitor();
LongArrayMonitorPtr longArrayMonitor;
bool isDestroyed;
bool runReturned;
epics::pvData::String threadName;
Event event;
std::auto_ptr<epicsThread> thread;
};
void LAMMonitorRequester::init()
{
thread = std::auto_ptr<epicsThread>(new epicsThread(
*this,
threadName.c_str(),
epicsThreadGetStackSize(epicsThreadStackSmall),
epicsThreadPriorityLow));
thread->start();
}
void LAMMonitorRequester::destroy()
{
if(isDestroyed) return;
isDestroyed = true;
event.signal();
while(true) {
if(runReturned) break;
epicsThreadSleep(.01);
}
thread->exitWait();
longArrayMonitor.reset();
}
void LAMMonitorRequester::monitorConnect(Status const & status,
MonitorPtr const & monitor, StructureConstPtr const & structure)
{
longArrayMonitor->status = status;
longArrayMonitor->monitor = monitor;
if(!status.isOK()) {
messagePvt(status.getMessage(),errorMessage);
longArrayMonitor->event.signal();
return;
}
bool structureOK(true);
FieldConstPtr field = structure->getField("timeStamp");
if(field==NULL) structureOK = false;
field = structure->getField("value");
if(field==NULL) {
structureOK = false;
} else {
if(field->getType()!=scalarArray) {
structureOK = false;
} else {
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
if(scalarArray->getElementType()!=pvLong) structureOK = false;
}
}
if(!structureOK) {
String message("monitorConnect: illegal structure");
messagePvt(message,errorMessage);
longArrayMonitor->status = Status(Status::STATUSTYPE_ERROR,message);
}
longArrayMonitor->event.signal();
}
void LAMMonitorRequester::run()
{
PVLongArrayPtr pvValue;
PVTimeStamp pvTimeStamp;
TimeStamp timeStamp;
TimeStamp timeStampLast;
timeStampLast.getCurrent();
while(true) {
event.wait();
if(isDestroyed) {
runReturned = true;
return;
}
while(true) {
MonitorElementPtr monitorElement = longArrayMonitor->monitor->poll();
if(monitorElement==NULL) break;
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
pvTimeStamp.get(timeStamp);
pvValue = dynamic_pointer_cast<PVLongArray>(pvStructure->getSubField("value"));
shared_vector<const int64> data = pvValue->view();
if(data.size()>0) {
int64 first = data[0];
int64 last = data[data.size()-1];
int64 sum = 0;
for(size_t i=0; i<data.size(); ++i) sum += data[i];
double diff = TimeStamp::diff(timeStamp,timeStampLast);
double elementsPerSecond = data.size();
elementsPerSecond = 1e-6*elementsPerSecond/diff;
cout.flush();
cout << "first " << first << " last " << last << " sum " << sum;
cout << " elements/sec " << elementsPerSecond << "million";
BitSetPtr changed = monitorElement->changedBitSet;
BitSetPtr overrun = monitorElement->overrunBitSet;
String buffer;
changed->toString(&buffer);
cout << " changed " << buffer;
buffer.clear();
overrun->toString(&buffer);
cout << " overrun " << buffer;
cout << endl;
cout.flush();
timeStampLast = timeStamp;
} else {
cout << "size = 0" << endl;
}
longArrayMonitor->monitor->release(monitorElement);
}
}
}
void LAMMonitorRequester::monitorEvent(MonitorPtr const & monitor)
{
event.signal();
}
void LAMMonitorRequester::unlisten(MonitorPtr const & monitor)
{
messagePvt("unlisten called",errorMessage);
}
LongArrayMonitorPtr LongArrayMonitor::create(
String const &providerName,
String const & channelName,
bool useQueue)
{
LongArrayMonitorPtr longArrayMonitor(new LongArrayMonitor());
if(!longArrayMonitor->init(providerName,channelName,useQueue)) longArrayMonitor.reset();
return longArrayMonitor;
}
LongArrayMonitor::LongArrayMonitor() {}
LongArrayMonitor::~LongArrayMonitor() {}
bool LongArrayMonitor::init(
String const &providerName,
String const &channelName,
bool useQueue)
{
channelRequester = LAMChannelRequesterPtr(new LAMChannelRequester(getPtrSelf()));
monitorRequester = LAMMonitorRequesterPtr(new LAMMonitorRequester(getPtrSelf()));
monitorRequester->init();
ChannelProvider::shared_pointer channelProvider = getChannelAccess()->getProvider(providerName);
if(channelProvider==NULL) {
cout << "provider " << providerName << " not found" << endl;
return false;
}
channel = channelProvider->createChannel(channelName,channelRequester,0);
event.wait();
if(!status.isOK()) return false;
String queueSize("0");
if(useQueue) queueSize="2";
String request("record[queueSize=");
request += queueSize;
request += "]field(value,timeStamp,alarm)";
PVStructurePtr pvRequest =
getCreateRequest()->createRequest(request,channelRequester);
if(pvRequest==NULL) {
cout << "request logic error " << request << endl;
return false;
}
monitor = channel->createMonitor(monitorRequester,pvRequest);
event.wait();
if(!status.isOK()) return false;
return true;
}
void LongArrayMonitor::start()
{
monitor->start();
}
void LongArrayMonitor::stop()
{
monitor->stop();
}
void LongArrayMonitor::destroy()
{
monitorRequester->destroy();
monitorRequester.reset();
monitor->destroy();
monitor.reset();
channel->destroy();
channel.reset();
channelRequester.reset();
}
}}

View File

@ -0,0 +1,71 @@
/* longArrayMonitor.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.08.09
*/
#ifndef LONGARRAYMONITOR_H
#define LONGARRAYMONITOR_H
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/standardPVField.h>
#include <pv/timeStamp.h>
#include <pv/pvTimeStamp.h>
#include <pv/pvAccess.h>
namespace epics { namespace pvDatabase {
class LongArrayMonitor;
typedef std::tr1::shared_ptr<LongArrayMonitor> LongArrayMonitorPtr;
class LAMChannelRequester;
typedef std::tr1::shared_ptr<LAMChannelRequester> LAMChannelRequesterPtr;
class LAMMonitorRequester;
typedef std::tr1::shared_ptr<LAMMonitorRequester> LAMMonitorRequesterPtr;
class LongArrayMonitor :
public std::tr1::enable_shared_from_this<LongArrayMonitor>
{
public:
POINTER_DEFINITIONS(LongArrayMonitor);
static LongArrayMonitorPtr create(
epics::pvData::String const & providerName,
epics::pvData::String const & channelName,
bool useQueue = false);
~LongArrayMonitor();
void start();
void stop();
void destroy();
private:
static epics::pvData::Mutex printMutex;
bool init(
epics::pvData::String const & providerName,
epics::pvData::String const & channelName,
bool useQueue);
LongArrayMonitorPtr getPtrSelf()
{
return shared_from_this();
}
LongArrayMonitor();
LAMChannelRequesterPtr channelRequester;
LAMMonitorRequesterPtr monitorRequester;
epics::pvAccess::Channel::shared_pointer channel;
epics::pvData::Monitor::shared_pointer monitor;
epics::pvData::Event event;
epics::pvData::Status status;
friend class LAMChannelRequester;
friend class LAMMonitorRequester;
};
}}
#endif /* LONGARRAYMONITOR_H */

View File

@ -70,7 +70,6 @@ private:
epics::pvData::Alarm alarm;
epics::pvAccess::Channel::shared_pointer channel;
epics::pvAccess::ChannelGet::shared_pointer channelGet;
epics::pvData::Mutex mutex;
epics::pvData::Event event;
epics::pvData::Status status;
epics::pvData::PVStructurePtr getPVStructure;

View File

@ -25,7 +25,7 @@ LIBSRCS += pvCopy.cpp
LIBSRCS += channelLocal.cpp
LIBSRCS += monitorFactory.cpp
SRC_DIRS += $(DATABASE)/v3IOC
SRC_DIRS += $(DATABASE)/V3IOC
DBD += PVAServerRegister.dbd
DBD += PVAClientRegister.dbd
LIBSRCS += PVAServerRegister.cpp

View File

@ -29,10 +29,8 @@ PVDatabasePtr PVDatabase::getMaster()
}
PVDatabase::PVDatabase()
: thelock(mutex),
isDestroyed(false)
: isDestroyed(false)
{
thelock.unlock();
}
PVDatabase::~PVDatabase()
@ -42,88 +40,132 @@ PVDatabase::~PVDatabase()
void PVDatabase::destroy()
{
lock();
if(isDestroyed) {
try {
if(isDestroyed) {
unlock();
return;
}
isDestroyed = true;
PVRecordMap::iterator iter;
while(true) {
iter = recordMap.begin();
if(iter==recordMap.end()) break;
PVRecordPtr pvRecord = (*iter).second;
recordMap.erase(iter);
if(pvRecord.get()!=NULL) pvRecord->destroy();
}
unlock();
return;
}
isDestroyed = true;
PVRecordMap::iterator iter;
while(true) {
iter = recordMap.begin();
if(iter==recordMap.end()) break;
PVRecordPtr pvRecord = (*iter).second;
recordMap.erase(iter);
} catch (...) {
unlock();
if(pvRecord.get()!=NULL) pvRecord->destroy();
lock();
throw;
}
}
void PVDatabase::lock() {
thelock.lock();
mutex.lock();
}
void PVDatabase::unlock() {
thelock.unlock();
mutex.unlock();
}
PVRecordPtr PVDatabase::findRecord(String const& recordName)
{
lock_guard();
PVRecordPtr xxx;
if(isDestroyed) return xxx;
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
return (*iter).second;
lock();
try {
PVRecordPtr xxx;
if(isDestroyed) {
unlock();
return xxx;
}
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
unlock();
return (*iter).second;
}
unlock();
return xxx;
} catch(...) {
unlock();
throw;
}
return xxx;
}
PVStringArrayPtr PVDatabase::getRecordNames()
{
lock_guard();
PVStringArrayPtr pvStringArray = static_pointer_cast<PVStringArray>
(getPVDataCreate()->createPVScalarArray(pvString));
size_t len = recordMap.size();
shared_vector<String> names(len);
PVRecordMap::iterator iter;
size_t i = 0;
for(iter = recordMap.begin(); iter!=recordMap.end(); ++iter) {
names[i++] = (*iter).first;
lock();
try {
PVStringArrayPtr xxx;
if(isDestroyed) {
unlock();
return xxx;
}
PVStringArrayPtr pvStringArray = static_pointer_cast<PVStringArray>
(getPVDataCreate()->createPVScalarArray(pvString));
size_t len = recordMap.size();
shared_vector<String> names(len);
PVRecordMap::iterator iter;
size_t i = 0;
for(iter = recordMap.begin(); iter!=recordMap.end(); ++iter) {
names[i++] = (*iter).first;
}
shared_vector<const String> temp(freeze(names));
pvStringArray->replace(temp);
unlock();
return pvStringArray;
} catch(...) {
unlock();
throw;
}
shared_vector<const String> temp(freeze(names));
pvStringArray->replace(temp);
return pvStringArray;
}
bool PVDatabase::addRecord(PVRecordPtr const & record)
{
lock_guard();
if(isDestroyed) return false;
String recordName = record->getRecordName();
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
return false;
lock();
try {
if(isDestroyed) {
unlock();
return false;
}
String recordName = record->getRecordName();
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
unlock();
return false;
}
record->start();
recordMap.insert(PVRecordMap::value_type(recordName,record));
unlock();
return true;
} catch(...) {
unlock();
throw;
}
recordMap.insert(PVRecordMap::value_type(recordName,record));
return true;
}
bool PVDatabase::removeRecord(PVRecordPtr const & record)
{
lock();
if(isDestroyed) return false;
String recordName = record->getRecordName();
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
PVRecordPtr pvRecord = (*iter).second;
recordMap.erase(iter);
try {
if(isDestroyed) {
unlock();
return false;
}
String recordName = record->getRecordName();
PVRecordMap::iterator iter = recordMap.find(recordName);
if(iter!=recordMap.end()) {
PVRecordPtr pvRecord = (*iter).second;
recordMap.erase(iter);
if(pvRecord.get()!=NULL) pvRecord->destroy();
unlock();
return true;
}
unlock();
if(pvRecord.get()!=NULL) pvRecord->destroy();
return true;
return false;
} catch(...) {
unlock();
throw;
}
unlock();
return false;
}
String PVDatabase::getRequesterName()

View File

@ -59,6 +59,11 @@ public:
* @return <b>true</b> for success and <b>false</b> for failure.
*/
virtual bool init() {initPVRecord(); return true;}
/**
* Optional method for derived class.
* It is called before record is added to database.
*/
virtual void start() {}
/**
* Must be implemented by derived classes.
* It is the method that makes a record smart.
@ -69,6 +74,8 @@ public:
/**
* Destroy the PVRecord. Release any resources used and
* get rid of listeners and requesters.
* If derived class overrides this then it must call PVRecord::destroy()
* after it has destroyed rewsorces it uses.
*/
virtual void destroy();
/**
@ -113,12 +120,6 @@ public:
* @return <b>true</b> if requester was removed.
*/
bool removeRequester(epics::pvData::RequesterPtr const & requester);
/**
* This is an inline method that locks the record.
* The record will automatically
* be unlocked when control leaves the block that has the call.
*/
inline void lock_guard() { epics::pvData::Lock thelock(mutex); }
/**
* Lock the record.
* Any code must lock while accessing a record.
@ -262,7 +263,6 @@ private:
std::list<PVRecordClientPtr> pvRecordClientList;
std::list<epics::pvData::RequesterPtr> requesterList;
epics::pvData::Mutex mutex;
epics::pvData::Lock thelock;
std::size_t depthGroupPut;
int traceLevel;
bool isDestroyed;
@ -553,10 +553,8 @@ private:
PVDatabase();
void lock();
void unlock();
inline void lock_guard() { epics::pvData::Lock thelock(mutex); }
PVRecordMap recordMap;
epics::pvData::Mutex mutex;
epics::pvData::Lock thelock;
bool isDestroyed;
};

View File

@ -10,6 +10,7 @@
*/
#include <pv/pvDatabase.h>
#include <epicsThread.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
@ -36,17 +37,17 @@ PVRecord::PVRecord(
: recordName(recordName),
pvStructure(pvStructure),
convert(getConvert()),
thelock(mutex),
depthGroupPut(0),
traceLevel(0),
isDestroyed(false)
{
thelock.unlock();
}
PVRecord::~PVRecord()
{
destroy();
if(traceLevel>1) {
cout << "~PVRecord() " << recordName << endl;
}
}
void PVRecord::initPVRecord()
@ -60,46 +61,54 @@ void PVRecord::initPVRecord()
void PVRecord::destroy()
{
if(traceLevel>1) {
cout << "PVRecord::destroy() " << recordName << endl;
}
lock();
if(isDestroyed) {
try {
if(isDestroyed) {
unlock();
return;
}
isDestroyed = true;
std::list<RequesterPtr>::iterator requesterIter;
while(true) {
requesterIter = requesterList.begin();
if(requesterIter==requesterList.end()) break;
requesterList.erase(requesterIter);
unlock();
(*requesterIter)->message("record destroyed",fatalErrorMessage);
lock();
}
std::list<PVRecordClientPtr>::iterator clientIter;
while(true) {
clientIter = pvRecordClientList.begin();
if(clientIter==pvRecordClientList.end()) break;
pvRecordClientList.erase(clientIter);
unlock();
(*clientIter)->detach(getPtrSelf());
lock();
}
std::list<PVListenerPtr>::iterator listenerIter;
while(true) {
listenerIter = pvListenerList.begin();
if(listenerIter==pvListenerList.end()) break;
pvListenerList.erase(listenerIter);
unlock();
(*listenerIter)->unlisten(getPtrSelf());
lock();
}
pvRecordStructure->destroy();
pvRecordStructure.reset();
convert.reset();
pvStructure.reset();
unlock();
return;
}
isDestroyed = true;
std::list<RequesterPtr>::iterator requesterIter;
while(true) {
requesterIter = requesterList.begin();
if(requesterIter==requesterList.end()) break;
requesterList.erase(requesterIter);
} catch(...) {
unlock();
(*requesterIter)->message("record destroyed",fatalErrorMessage);
lock();
throw;
}
std::list<PVRecordClientPtr>::iterator clientIter;
while(true) {
clientIter = pvRecordClientList.begin();
if(clientIter==pvRecordClientList.end()) break;
pvRecordClientList.erase(clientIter);
unlock();
(*clientIter)->detach(getPtrSelf());
lock();
}
std::list<PVListenerPtr>::iterator listenerIter;
while(true) {
listenerIter = pvListenerList.begin();
if(listenerIter==pvListenerList.end()) break;
pvListenerList.erase(listenerIter);
unlock();
(*listenerIter)->unlisten(getPtrSelf());
lock();
}
pvRecordStructure->destroy();
pvRecordStructure.reset();
convert.reset();
pvStructure.reset();
unlock();
}
String PVRecord::getRecordName() {return recordName;}
@ -115,40 +124,56 @@ PVRecordFieldPtr PVRecord::findPVRecordField(PVFieldPtr const & pvField)
bool PVRecord::addRequester(epics::pvData::RequesterPtr const & requester)
{
lock();
if(isDestroyed) {
unlock();
return false;
if(traceLevel>2) {
cout << "PVRecord::addRequester() " << recordName << endl;
}
std::list<RequesterPtr>::iterator iter;
for (iter = requesterList.begin(); iter!=requesterList.end(); iter++ ) {
if((*iter).get()==requester.get()) {
lock();
try {
if(isDestroyed) {
unlock();
return false;
}
std::list<RequesterPtr>::iterator iter;
for (iter = requesterList.begin(); iter!=requesterList.end(); iter++ ) {
if((*iter).get()==requester.get()) {
unlock();
return false;
}
}
requesterList.push_back(requester);
unlock();
return true;
} catch (...) {
unlock();
throw;
}
requesterList.push_back(requester);
unlock();
return true;
}
bool PVRecord::removeRequester(epics::pvData::RequesterPtr const & requester)
{
if(traceLevel>2) {
cout << "PVRecord::removeRequester() " << recordName << endl;
}
lock();
if(isDestroyed) {
unlock();
return false;
}
std::list<RequesterPtr>::iterator iter;
for (iter = requesterList.begin(); iter!=requesterList.end(); iter++ ) {
if((*iter).get()==requester.get()) {
requesterList.erase(iter);
try {
if(isDestroyed) {
unlock();
return true;
return false;
}
std::list<RequesterPtr>::iterator iter;
for (iter = requesterList.begin(); iter!=requesterList.end(); iter++ ) {
if((*iter).get()==requester.get()) {
requesterList.erase(iter);
unlock();
return true;
}
}
unlock();
return false;
} catch (...) {
unlock();
throw;
}
unlock();
return false;
}
PVRecordFieldPtr PVRecord::findPVRecordField(
@ -178,19 +203,31 @@ PVRecordFieldPtr PVRecord::findPVRecordField(
}
void PVRecord::lock() {
thelock.lock();
if(traceLevel>2) {
cout << "PVRecord::lock() " << recordName << endl;
}
mutex.lock();
}
void PVRecord::unlock() {
thelock.unlock();
if(traceLevel>2) {
cout << "PVRecord::unlock() " << recordName << endl;
}
mutex.unlock();
}
bool PVRecord::tryLock() {
return thelock.tryLock();
if(traceLevel>2) {
cout << "PVRecord::tryLock() " << recordName << endl;
}
return mutex.tryLock();
}
void PVRecord::lockOtherRecord(PVRecordPtr const & otherRecord)
{
if(traceLevel>2) {
cout << "PVRecord::lockOtherRecord() " << recordName << endl;
}
if(this<otherRecord.get()) {
otherRecord->lock();
return;
@ -202,110 +239,155 @@ void PVRecord::lockOtherRecord(PVRecordPtr const & otherRecord)
bool PVRecord::addPVRecordClient(PVRecordClientPtr const & pvRecordClient)
{
lock();
if(isDestroyed) {
unlock();
return false;
if(traceLevel>2) {
cout << "PVRecord::addPVRecordClient() " << recordName << endl;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
if((*iter).get()==pvRecordClient.get()) {
lock();
try {
if(isDestroyed) {
unlock();
return false;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
if((*iter).get()==pvRecordClient.get()) {
unlock();
return false;
}
}
pvRecordClientList.push_back(pvRecordClient);
unlock();
return true;
} catch (...) {
unlock();
throw;
}
pvRecordClientList.push_back(pvRecordClient);
unlock();
return true;
}
bool PVRecord::removePVRecordClient(PVRecordClientPtr const & pvRecordClient)
{
if(traceLevel>2) {
cout << "PVRecord::removePVRecordClient() " << recordName << endl;
}
lock();
if(isDestroyed) {
unlock();
return false;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
if((*iter).get()==pvRecordClient.get()) {
pvRecordClientList.erase(iter);
try {
if(isDestroyed) {
unlock();
return true;
return false;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
if((*iter).get()==pvRecordClient.get()) {
pvRecordClientList.erase(iter);
unlock();
return true;
}
}
unlock();
return false;
} catch (...) {
unlock();
throw;
}
unlock();
return false;
}
void PVRecord::detachClients()
{
if(traceLevel>1) {
cout << "PVRecord::removePVRecordClient() " << recordName << endl;
}
lock();
if(isDestroyed) {
unlock();
return;
try {
if(isDestroyed) {
unlock();
return;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
unlock();
(*iter)->detach(getPtrSelf());
lock();
}
pvRecordClientList.clear();
unlock();
} catch(...) {
unlock();
throw;
}
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
(*iter)->detach(getPtrSelf());
}
pvRecordClientList.clear();
unlock();
}
bool PVRecord::addListener(PVListenerPtr const & pvListener)
{
lock();
if(isDestroyed) {
unlock();
return false;
if(traceLevel>1) {
cout << "PVRecord::addListener() " << recordName << endl;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
if((*iter).get()==pvListener.get()) {
lock();
try {
if(isDestroyed) {
unlock();
return false;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
if((*iter).get()==pvListener.get()) {
unlock();
return false;
}
}
pvListenerList.push_back(pvListener);
unlock();
return true;
} catch(...) {
unlock();
throw;
}
pvListenerList.push_back(pvListener);
unlock();
return true;
}
bool PVRecord::removeListener(PVListenerPtr const & pvListener)
{
if(traceLevel>1) {
cout << "PVRecord::removeListener() " << recordName << endl;
}
lock();
if(isDestroyed) {
unlock();
return false;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
if((*iter).get()==pvListener.get()) {
pvListenerList.erase(iter);
pvRecordStructure->removeListener(pvListener);
try {
if(isDestroyed) {
unlock();
return true;
return false;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
if((*iter).get()==pvListener.get()) {
pvListenerList.erase(iter);
pvRecordStructure->removeListener(pvListener);
unlock();
return true;
}
}
unlock();
return false;
} catch(...) {
unlock();
throw;
}
unlock();
return false;
}
void PVRecord::beginGroupPut()
{
if(++depthGroupPut>1) return;
if(traceLevel>2) {
cout << "PVRecord::beginGroupPut() " << recordName << endl;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++)
{
@ -316,6 +398,9 @@ void PVRecord::beginGroupPut()
void PVRecord::endGroupPut()
{
if(--depthGroupPut>0) return;
if(traceLevel>2) {
cout << "PVRecord::endGroupPut() " << recordName << endl;
}
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++)
{

View File

@ -13,6 +13,7 @@
#include <epicsThread.h>
#include <pv/timeStamp.h>
#include <pv/channelProviderLocal.h>
#include <pv/convert.h>
#include <pv/pvSubArrayCopy.h>
@ -80,24 +81,8 @@ public:
PVRecordPtr const &pvRecord);
virtual void process(bool lastRequest);
virtual void destroy();
virtual void lock()
{
thelock.lock();
if(pvRecord->getTraceLevel()>2)
{
cout << "ChannelProcessLocal::lock";
cout << " recordName " << pvRecord->getRecordName() << endl;
}
}
virtual void unlock()
{
thelock.unlock();
if(pvRecord->getTraceLevel()>2)
{
cout << "ChannelProcessLocal::unlock";
cout << " recordName " << pvRecord->getRecordName() << endl;
}
}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
private:
shared_pointer getPtrSelf()
{
@ -113,10 +98,8 @@ private:
channelLocal(channelLocal),
channelProcessRequester(channelProcessRequester),
pvRecord(pvRecord),
thelock(mutex),
nProcess(nProcess)
{
thelock.unlock();
}
bool isDestroyed;
bool callProcess;
@ -124,7 +107,6 @@ private:
ChannelProcessRequester::shared_pointer channelProcessRequester,;
PVRecordPtr pvRecord;
Mutex mutex;
Lock thelock;
int nProcess;
};
@ -174,8 +156,11 @@ void ChannelProcessLocal::destroy()
cout << "ChannelProcessLocal::destroy";
cout << " destroyed " << isDestroyed << endl;
}
if(isDestroyed) return;
isDestroyed = true;
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
@ -229,8 +214,8 @@ public:
PVRecordPtr const &pvRecord);
virtual void get(bool lastRequest);
virtual void destroy();
virtual void lock() {thelock.lock();}
virtual void unlock() {thelock.unlock();}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
private:
shared_pointer getPtrSelf()
{
@ -253,10 +238,8 @@ private:
pvCopy(pvCopy),
pvStructure(pvStructure),
bitSet(bitSet),
pvRecord(pvRecord),
thelock(mutex)
pvRecord(pvRecord)
{
thelock.unlock();
}
bool firstTime;
bool isDestroyed;
@ -268,7 +251,6 @@ private:
BitSetPtr bitSet;
PVRecordPtr pvRecord;
Mutex mutex;
Lock thelock;
};
ChannelGetLocalPtr ChannelGetLocal::create(
@ -323,8 +305,11 @@ void ChannelGetLocal::destroy()
cout << "ChannelGetLocal::destroy";
cout << " destroyed " << isDestroyed << endl;
}
if(isDestroyed) return;
isDestroyed = true;
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
@ -345,7 +330,7 @@ void ChannelGetLocal::get(bool lastRequest)
pvRecord->process();
pvRecord->endGroupPut();
}
pvCopy->updateCopySetBitSet(pvStructure, bitSet, false);
pvCopy->updateCopySetBitSet(pvStructure, bitSet);
} catch(...) {
pvRecord->unlock();
throw;
@ -385,8 +370,8 @@ public:
virtual void put(bool lastRequest);
virtual void get();
virtual void destroy();
virtual void lock() {thelock.lock();}
virtual void unlock() {thelock.unlock();}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
private:
shared_pointer getPtrSelf()
{
@ -408,10 +393,8 @@ private:
pvCopy(pvCopy),
pvStructure(pvStructure),
bitSet(bitSet),
pvRecord(pvRecord),
thelock(mutex)
pvRecord(pvRecord)
{
thelock.unlock();
}
bool isDestroyed;
bool callProcess;
@ -422,7 +405,6 @@ private:
BitSetPtr bitSet;
PVRecordPtr pvRecord;
Mutex mutex;
Lock thelock;
};
ChannelPutLocalPtr ChannelPutLocal::create(
@ -476,8 +458,11 @@ void ChannelPutLocal::destroy()
cout << "ChannelPutLocal::destroy";
cout << " destroyed " << isDestroyed << endl;
}
if(isDestroyed) return;
isDestroyed = true;
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
@ -494,7 +479,7 @@ void ChannelPutLocal::get()
bitSet->set(0);
pvRecord->lock();
try {
pvCopy->updateCopyFromBitSet(pvStructure, bitSet, false);
pvCopy->updateCopyFromBitSet(pvStructure, bitSet);
} catch(...) {
pvRecord->unlock();
throw;
@ -519,7 +504,7 @@ void ChannelPutLocal::put(bool lastRequest)
pvRecord->lock();
try {
pvRecord->beginGroupPut();
pvCopy->updateRecord(pvStructure, bitSet, false);
pvCopy->updateRecord(pvStructure, bitSet);
if(callProcess) {
pvRecord->process();
}
@ -560,8 +545,8 @@ public:
virtual void getPut();
virtual void getGet();
virtual void destroy();
virtual void lock() {thelock.lock();}
virtual void unlock() {thelock.unlock();}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
private:
shared_pointer getPtrSelf()
{
@ -589,10 +574,8 @@ private:
pvGetStructure(pvGetStructure),
putBitSet(putBitSet),
getBitSet(getBitSet),
pvRecord(pvRecord),
thelock(mutex)
pvRecord(pvRecord)
{
thelock.unlock();
}
bool isDestroyed;
bool callProcess;
@ -606,7 +589,6 @@ private:
BitSetPtr getBitSet;
PVRecordPtr pvRecord;
Mutex mutex;
Lock thelock;
};
ChannelPutGetLocalPtr ChannelPutGetLocal::create(
@ -642,6 +624,15 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create(
PVStructurePtr pvGetStructure = pvGetCopy->createPVStructure();
BitSetPtr putBitSet(new BitSet(pvPutStructure->getNumberFields()));
BitSetPtr getBitSet(new BitSet(pvGetStructure->getNumberFields()));
pvRecord->lock();
try {
pvPutCopy->initCopy(pvPutStructure,putBitSet);
pvGetCopy->initCopy(pvGetStructure,getBitSet);
} catch(...) {
pvRecord->unlock();
throw;
}
pvRecord->unlock();
ChannelPutGetLocalPtr putGet(new ChannelPutGetLocal(
getProcess(pvRequest,true),
channelLocal,
@ -671,8 +662,11 @@ void ChannelPutGetLocal::destroy()
cout << "ChannelPutGetLocal::destroy";
cout << " destroyed " << isDestroyed << endl;
}
if(isDestroyed) return;
isDestroyed = true;
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
@ -690,9 +684,9 @@ void ChannelPutGetLocal::putGet(bool lastRequest)
pvRecord->lock();
try {
pvRecord->beginGroupPut();
pvPutCopy->updateRecord(pvPutStructure, putBitSet, false);
pvPutCopy->updateRecord(pvPutStructure, putBitSet);
if(callProcess) pvRecord->process();
pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet, false);
pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet);
pvRecord->endGroupPut();
} catch(...) {
pvRecord->unlock();
@ -720,7 +714,7 @@ void ChannelPutGetLocal::getPut()
}
pvRecord->lock();
try {
pvPutCopy->updateCopySetBitSet(pvPutStructure, putBitSet, false);
pvPutCopy->updateCopySetBitSet(pvPutStructure, putBitSet);
} catch(...) {
pvRecord->unlock();
throw;
@ -746,7 +740,7 @@ void ChannelPutGetLocal::getGet()
}
pvRecord->lock();
try {
pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet, false);
pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet);
} catch(...) {
pvRecord->unlock();
throw;
@ -785,8 +779,8 @@ public:
virtual void putArray(bool lastRequest,int offset, int count);
virtual void setLength(bool lastRequest,int length, int capacity);
virtual void destroy();
virtual void lock() {thelock.lock();}
virtual void unlock() {thelock.unlock();}
virtual void lock() {mutex.lock();}
virtual void unlock() {mutex.unlock();}
private:
shared_pointer getPtrSelf()
{
@ -805,10 +799,8 @@ private:
channelArrayRequester(channelArrayRequester),
pvArray(pvArray),
pvCopy(pvCopy),
pvRecord(pvRecord),
thelock(mutex)
pvRecord(pvRecord)
{
thelock.unlock();
}
bool isDestroyed;
bool callProcess;
@ -818,7 +810,6 @@ private:
PVArrayPtr pvCopy;
PVRecordPtr pvRecord;
Mutex mutex;
Lock thelock;
};
@ -891,10 +882,6 @@ ChannelArrayLocalPtr ChannelArrayLocal::create(
}
channelArrayRequester->channelArrayConnect(
Status::Ok, array, pvCopy);
if(pvRecord->getTraceLevel()>0)
{
cout << "ChannelArrayLocal::create" << endl;
}
return array;
}
@ -906,8 +893,11 @@ void ChannelArrayLocal::destroy()
cout << "ChannelArrayLocal::destroy";
cout << " destroyed " << isDestroyed << endl;
}
if(isDestroyed) return;
isDestroyed = true;
{
Lock xx(mutex);
if(isDestroyed) return;
isDestroyed = true;
}
channelLocal.reset();
}
@ -968,7 +958,6 @@ void ChannelArrayLocal::putArray(bool lastRequest,int offset, int count)
pvRecord->unlock();
channelArrayRequester->putArrayDone(Status::Ok);
if(lastRequest) destroy();
pvRecord->unlock();
}
void ChannelArrayLocal::setLength(bool lastRequest,int length, int capacity)
@ -1061,7 +1050,7 @@ void ChannelLocal::destroy()
void ChannelLocal::detach(PVRecordPtr const & pvRecord)
{
if(pvRecord->getTraceLevel()>1) {
if(pvRecord->getTraceLevel()>0) {
cout << "ChannelLocal::detach() " << endl;
}
destroy();

View File

@ -77,10 +77,12 @@ ChannelProviderLocal::ChannelProviderLocal()
ChannelProviderLocal::~ChannelProviderLocal()
{
cout << "~ChannelProviderLocal()" << endl;
}
void ChannelProviderLocal::destroy()
{
cout << "ChannelProviderLocal::destroy()" << endl;
Lock xx(mutex);
if(beingDestroyed) return;
beingDestroyed = true;

View File

@ -11,10 +11,12 @@
#include <sstream>
#include <pv/thread.h>
#include <pv/channelProviderLocal.h>
#include <pv/channelProviderLocal.h>
#include <pv/bitSetUtil.h>
#include <pv/queue.h>
#include <pv/timeStamp.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
@ -220,7 +222,7 @@ void MonitorLocal::dataChanged()
{
if(pvRecord->getTraceLevel()>1)
{
cout << "MonitorLocal::dataChanged() " << endl;
cout << "MonitorLocal::dataChanged() " "firstMonitor " << firstMonitor << endl;
}
if(firstMonitor) {
queue->dataChanged();
@ -389,11 +391,6 @@ NOQueue::NOQueue(
changedBitSet(new BitSet(pvCopyStructure->getNumberFields())),
overrunBitSet(new BitSet(pvCopyStructure->getNumberFields()))
{
monitorElement->pvStructurePtr = pvCopyStructure;
monitorElement->changedBitSet =
BitSetPtr(new BitSet(pvCopyStructure->getNumberFields()));
monitorElement->overrunBitSet =
BitSetPtr(new BitSet(pvCopyStructure->getNumberFields()));
}
Status NOQueue::start()
@ -404,8 +401,8 @@ Status NOQueue::start()
changedBitSet->clear();
overrunBitSet->clear();
monitorLocal->getPVCopyMonitor()->startMonitoring(
monitorElement->changedBitSet,
monitorElement->overrunBitSet);
changedBitSet,
overrunBitSet);
return Status::Ok;
}
@ -415,36 +412,31 @@ void NOQueue::stop()
bool NOQueue::dataChanged()
{
Lock xx(mutex);
(*changedBitSet) |= (*monitorElement->changedBitSet);
(*overrunBitSet) |= (*monitorElement->overrunBitSet);
gotMonitor = true;
return wasReleased ? true : false;
Lock xx(mutex);
monitorLocal->getPVCopy()->updateCopyFromBitSet(
pvCopyStructure, changedBitSet);
gotMonitor = true;
return wasReleased;
}
MonitorElementPtr NOQueue::poll()
{
Lock xx(mutex);
if(!gotMonitor) return NULLMonitorElement;
BitSetPtr changed = monitorElement->changedBitSet;
BitSetPtr overrun = monitorElement->overrunBitSet;
(*changed) |= (*changedBitSet);
(*overrun) |= (*overrunBitSet);
monitorLocal->getPVCopy()->updateCopyFromBitSet(
pvCopyStructure, changed,true);
BitSetUtil::compress(changed,pvCopyStructure);
BitSetUtil::compress(overrun,pvCopyStructure);
changedBitSet->clear();
overrunBitSet->clear();
return monitorElement;
Lock xx(mutex);
if(!gotMonitor) return NULLMonitorElement;
getConvert()->copyStructure(pvCopyStructure,monitorElement->pvStructurePtr);
BitSetUtil::compress(changedBitSet,pvCopyStructure);
BitSetUtil::compress(overrunBitSet,pvCopyStructure);
(*monitorElement->changedBitSet) = (*changedBitSet);
(*monitorElement->overrunBitSet) = (*overrunBitSet);
changedBitSet->clear();
overrunBitSet->clear();
return monitorElement;
}
void NOQueue::release(MonitorElementPtr const &monitorElement)
{
Lock xx(mutex);
gotMonitor = false;
monitorElement->changedBitSet->clear();
monitorElement->overrunBitSet->clear();
Lock xx(mutex);
gotMonitor = false;
}
RealQueue::RealQueue(
@ -478,19 +470,23 @@ bool RealQueue::dataChanged()
Lock xx(mutex);
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
monitorLocal->getPVCopy()->updateCopyFromBitSet(
pvStructure,monitorElement->changedBitSet,false);
MonitorElementPtr newElement = queue.getFree();
if(newElement==NULL) {
pvStructure,monitorElement->changedBitSet);
if(queue.getNumberFree()==0) {
if(queueIsFull) return false;
queueIsFull = true;
return true;
}
MonitorElementPtr newElement = queue.getFree();
if(newElement==NULL) {
throw std::logic_error(String("RealQueue::dataChanged() logic error"));
}
BitSetUtil::compress(monitorElement->changedBitSet,pvStructure);
BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure);
convert->copy(pvStructure,newElement->pvStructurePtr);
newElement->changedBitSet->clear();
newElement->overrunBitSet->clear();
monitorLocal->getPVCopyMonitor()->switchBitSets(
newElement->changedBitSet,newElement->overrunBitSet,false);
newElement->changedBitSet,newElement->overrunBitSet);
queue.setUsed(monitorElement);
monitorElement = newElement;
return true;
@ -498,30 +494,15 @@ bool RealQueue::dataChanged()
MonitorElementPtr RealQueue::poll()
{
Lock xx(mutex);
return queue.getUsed();
Lock xx(mutex);
return queue.getUsed();
}
void RealQueue::release(MonitorElementPtr const &currentElement)
{
Lock xx(mutex);
queue.releaseUsed(currentElement);
currentElement->changedBitSet->clear();
currentElement->overrunBitSet->clear();
if(!queueIsFull) return;
queueIsFull = false;
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
MonitorElementPtr newElement = queue.getFree();
BitSetUtil::compress(monitorElement->changedBitSet,pvStructure);
BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure);
convert->copy(pvStructure,newElement->pvStructurePtr);
newElement->changedBitSet->clear();
newElement->overrunBitSet->clear();
monitorLocal->getPVCopyMonitor()->switchBitSets(
newElement->changedBitSet,newElement->overrunBitSet,false);
queue.setUsed(monitorElement);
monitorElement = newElement;
Lock xx(mutex);
queue.releaseUsed(currentElement);
queueIsFull = false;
}
MonitorFactoryPtr getMonitorFactory()

View File

@ -13,6 +13,8 @@
#include <memory>
#include <sstream>
#include <pv/thread.h>
#include <pv/channelProviderLocal.h>
@ -170,124 +172,99 @@ PVRecordFieldPtr PVCopy::getRecordPVField(size_t structureOffset)
void PVCopy::initCopy(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet,
bool lockRecord)
BitSetPtr const &bitSet)
{
bitSet->clear();
bitSet->set(0);
updateCopyFromBitSet(copyPVStructure,bitSet,lockRecord);
updateCopyFromBitSet(copyPVStructure,bitSet);
}
void PVCopy::updateCopySetBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet,
bool lockRecord)
BitSetPtr const &bitSet)
{
if(lockRecord) pvRecord->lock();
try {
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeSetBitSet(copyPVStructure,node,bitSet);
} else {
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(headNode);
PVRecordFieldPtr pvRecordField= recordNode->recordPVField;
PVFieldPtr copyPVField = copyPVStructure;
PVFieldPtrArray const & pvCopyFields = copyPVStructure->getPVFields();
if(pvCopyFields.size()==1) {
copyPVField = pvCopyFields[0];
}
PVFieldPtr pvField = pvRecordField->getPVField();
if(pvField->getField()->getType()==epics::pvData::structure) {
updateSubFieldSetBitSet(copyPVField,pvRecordField,bitSet);
return;
}
if(pvCopyFields.size()!=1) {
throw std::logic_error("Logic error");
}
ConvertPtr convert = getConvert();
bool isEqual = convert->equals(copyPVField,pvField);
if(!isEqual) {
convert->copy(pvField, copyPVField);
bitSet->set(copyPVField->getFieldOffset());
}
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeSetBitSet(copyPVStructure,node,bitSet);
} else {
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(headNode);
PVRecordFieldPtr pvRecordField= recordNode->recordPVField;
PVFieldPtr copyPVField = copyPVStructure;
PVFieldPtrArray const & pvCopyFields = copyPVStructure->getPVFields();
if(pvCopyFields.size()==1) {
copyPVField = pvCopyFields[0];
}
PVFieldPtr pvField = pvRecordField->getPVField();
if(pvField->getField()->getType()==epics::pvData::structure) {
updateSubFieldSetBitSet(copyPVField,pvRecordField,bitSet);
return;
}
if(pvCopyFields.size()!=1) {
throw std::logic_error("Logic error");
}
ConvertPtr convert = getConvert();
bool isEqual = convert->equals(copyPVField,pvField);
if(!isEqual) {
convert->copy(pvField, copyPVField);
bitSet->set(copyPVField->getFieldOffset());
}
if(lockRecord) pvRecord->unlock();
} catch(...) {
if(lockRecord) pvRecord->unlock();
throw;
}
}
void PVCopy::updateCopyFromBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet,
bool lockRecord)
BitSetPtr const &bitSet)
{
bool doAll = bitSet->get(0);
if(lockRecord) pvRecord->lock();
try {
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(copyPVStructure,node,bitSet,true,doAll);
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(copyPVStructure,node,bitSet,true,doAll);
} else {
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(headNode);
PVFieldPtrArray const & pvCopyFields = copyPVStructure->getPVFields();
if(pvCopyFields.size()==1) {
updateSubFieldFromBitSet(
pvCopyFields[0],
recordNode->recordPVField,bitSet,
true,doAll);
} else {
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(headNode);
PVFieldPtrArray const & pvCopyFields = copyPVStructure->getPVFields();
if(pvCopyFields.size()==1) {
updateSubFieldFromBitSet(
pvCopyFields[0],
recordNode->recordPVField,bitSet,
true,doAll);
} else {
updateSubFieldFromBitSet(
copyPVStructure,
recordNode->recordPVField,bitSet,
true,doAll);
}
updateSubFieldFromBitSet(
copyPVStructure,
recordNode->recordPVField,bitSet,
true,doAll);
}
if(lockRecord) pvRecord->unlock();
} catch(...) {
if(lockRecord) pvRecord->unlock();
throw;
}
}
void PVCopy::updateRecord(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet,
bool lockRecord)
BitSetPtr const &bitSet)
{
bool doAll = bitSet->get(0);
if(lockRecord) pvRecord->lock();
try {
pvRecord->beginGroupPut();
if(headNode->isStructure) {
CopyStructureNodePtr node =
static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(
copyPVStructure,node,bitSet,false,doAll);
pvRecord->beginGroupPut();
if(headNode->isStructure) {
CopyStructureNodePtr node =
static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(
copyPVStructure,node,bitSet,false,doAll);
} else {
CopyRecordNodePtr recordNode =
static_pointer_cast<CopyRecordNode>(headNode);
PVFieldPtrArray const & pvCopyFields =
copyPVStructure->getPVFields();
if(pvCopyFields.size()==1) {
updateSubFieldFromBitSet(
pvCopyFields[0],
recordNode->recordPVField,bitSet,
false,doAll);
} else {
CopyRecordNodePtr recordNode =
static_pointer_cast<CopyRecordNode>(headNode);
PVFieldPtrArray const & pvCopyFields =
copyPVStructure->getPVFields();
if(pvCopyFields.size()==1) {
updateSubFieldFromBitSet(
pvCopyFields[0],
recordNode->recordPVField,bitSet,
false,doAll);
} else {
updateSubFieldFromBitSet(
copyPVStructure,
recordNode->recordPVField,bitSet,
false,doAll);
}
updateSubFieldFromBitSet(
copyPVStructure,
recordNode->recordPVField,bitSet,
false,doAll);
}
pvRecord->endGroupPut();
if(lockRecord) pvRecord->unlock();
} catch(...) {
if(lockRecord) pvRecord->unlock();
throw;
}
pvRecord->endGroupPut();
}
PVCopyMonitorPtr PVCopy::createPVCopyMonitor(
@ -1028,17 +1005,10 @@ void PVCopyMonitor::stopMonitoring()
void PVCopyMonitor::switchBitSets(
BitSetPtr const &newChangeBitSet,
BitSetPtr const &newOverrunBitSet,
bool lockRecord)
BitSetPtr const &newOverrunBitSet)
{
if(lockRecord) pvRecord->lock();
try {
changeBitSet = newChangeBitSet;
overrunBitSet = newOverrunBitSet;
if(lockRecord) pvRecord->unlock();
} catch(...) {
if(lockRecord) pvRecord->unlock();
}
changeBitSet = newChangeBitSet;
overrunBitSet = newOverrunBitSet;
}
void PVCopyMonitor::detach(PVRecordPtr const & pvRecord)

View File

@ -55,20 +55,16 @@ public:
PVRecordFieldPtr getRecordPVField(std::size_t structureOffset);
void initCopy(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet,
bool lockRecord);
epics::pvData::BitSetPtr const &bitSet);
void updateCopySetBitSet(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet,
bool lockRecord);
epics::pvData::BitSetPtr const &bitSet);
void updateCopyFromBitSet(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet,
bool lockRecord);
epics::pvData::BitSetPtr const &bitSet);
void updateRecord(
epics::pvData::PVStructurePtr const &copyPVStructure,
epics::pvData::BitSetPtr const &bitSet,
bool lockRecord);
epics::pvData::BitSetPtr const &bitSet);
PVCopyMonitorPtr createPVCopyMonitor(
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester);
epics::pvData::PVStructurePtr getOptions(
@ -164,7 +160,7 @@ public:
void stopMonitoring();
void switchBitSets(
epics::pvData::BitSetPtr const &newChangeBitSet,
epics::pvData::BitSetPtr const &newOverrunBitSet, bool lockRecord);
epics::pvData::BitSetPtr const &newOverrunBitSet);
// following are PVListener methods
virtual void detach(PVRecordPtr const & pvRecord);
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);

View File

@ -1,242 +0,0 @@
/* pvShare.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#include <string>
#include <stdexcept>
#include <memory>
#include <pv/pvData.h>
#include <pv/noDefaultMethods.h>
#include <pv/pvDatabase.h>
#include <pv/support.h>
#include <pv/pvCopy.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
template<typename T>
SharePVScalarArray<T>::SharePVScalarArray(
PVRecordField &pvRecordField,
epics::pvData::PVStructure *parent,
epics::pvData::PVScalarArray &pvShare)
: PVField(parent,pvShare.getField()),
pvRecordField(pvRecordField)
{
}
template<typename T>
SharePVScalarArray<T>::~SharePVScalarArray()
{
}
template<typename T>
void SharePVScalarArray<T>::lockShare() const
{
pvRecordField.getPVRecord().lock();
}
template<typename T>
void SharePVScalarArray<T>::unlockShare() const
{
pvRecordField.getPVRecord().unlock();
}
template<typename T>
void SharePVScalarArray<T>::message(String message,MessageType messageType)
{
pvRecordField.message(message,messageType);
}
template<typename T>
void SharePVScalarArray<T>::setImmutable()
{
lockShare();
try {
pvRecordField.getPVField().setImmutable();
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
bool SharePVScalarArray<T>::isImmutable()
{
return pvRecordField.getPVField().isImmutable();
}
template<typename T>
void SharePVScalarArray<T>::setCapacityMutable(bool isMutable)
{
lockShare();
try {
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
pvArray.setCapacityMutable(isMutable);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
bool SharePVScalarArray<T>::isCapacityMutable()
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
return pvArray.isCapacityMutable();
}
template<typename T>
void SharePVScalarArray<T>::setCapacity(int capacity)
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
lockShare();
try {
pvArray.setCapacity(capacity);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
void SharePVScalarArray<T>::setLength(int length)
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
lockShare();
try {
pvArray.setLength(length);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
int SharePVScalarArray<T>::getCapacity() const
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
return pvArray.getCapacity();
}
template<typename T>
int SharePVScalarArray<T>::getLength() const
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
return pvArray.getLength();
}
template<typename T>
int SharePVScalarArray<T>::get(int offset, int length, ArrayDataType *data)
{
class PVValueArray<T> &pvArray = static_cast<PVValueArray<T> &>(
pvRecordField.getPVField());
lockShare();
try {
return pvArray.get(offset,length,data);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
int SharePVScalarArray<T>::put(
int offset,int length, pointer from, int fromOffset)
{
class PVValueArray<T> &pvArray = static_cast<PVValueArray<T> &>(
pvRecordField.getPVField());
lockShare();
try {
pvRecordField.getPVRecord().beginGroupPut();
int len = pvArray.put(offset,length,from,fromOffset);
pvRecordField.getPVRecord().endGroupPut();
unlockShare();
return len;
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
void SharePVScalarArray<T>::shareData(pointer value,int capacity,int length)
{
class PVValueArray<T> &pvArray = static_cast<PVValueArray<T> &>(
pvRecordField.getPVField());
lockShare();
try {
pvArray.setImmutable(value,capacity,length);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
bool SharePVScalarArray<T>::equals(PVField &pv)
{
lockShare();
try {
return pvRecordField.getPVField().equals(pv);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
void SharePVScalarArray<T>::serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const
{
serialize(pbuffer, pflusher, 0, getLength());
}
template<typename T>
void SharePVScalarArray<T>::deserialize(
ByteBuffer *pbuffer,DeserializableControl *pflusher)
{
class PVValueArray<T> &pvArray = static_cast<PVValueArray<T> &>(
pvRecordField.getPVField());
lockShare();
try {
pvArray.deserialize(pbuffer,pflusher);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
template<typename T>
void SharePVScalarArray<T>::serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher,int offset,int count) const
{
class PVValueArray<T> &pvArray = static_cast<PVValueArray<T> &>(
pvRecordField.getPVField());
lockShare();
try {
pvArray.serialize(pbuffer,pflusher,offset,count);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
}}

View File

@ -1,219 +0,0 @@
/* pvShareStructureArray.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#include <string>
#include <stdexcept>
#include <memory>
#include <pv/pvData.h>
#include <pv/noDefaultMethods.h>
#include <pv/pvDatabase.h>
#include <pv/support.h>
#include <pv/pvCopy.h>
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
SharePVStructureArray::SharePVStructureArray(
PVRecordField &pvRecordField,
PVStructure *parent,
PVStructureArray &pvShare)
: PVArray(parent,pvShare.getField()),
pvRecordField(pvRecordField)
{
}
SharePVStructureArray::~SharePVStructureArray() {}
StructureArrayConstPtr SharePVStructureArray::getStructureArray()
{
PVStructureArray &pvArray = static_cast<PVStructureArray &>(
pvRecordField.getPVField());
return pvArray.getStructureArray();
}
void SharePVStructureArray::lockShare() const
{
pvRecordField.getPVRecord().lock();
}
void SharePVStructureArray::unlockShare() const
{
pvRecordField.getPVRecord().unlock();
}
void SharePVStructureArray::message(String message,MessageType messageType)
{
pvRecordField.message(message,messageType);
}
void SharePVStructureArray::setImmutable()
{
lockShare();
try {
pvRecordField.getPVField().setImmutable();
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
bool SharePVStructureArray::isImmutable()
{
return pvRecordField.getPVField().isImmutable();
}
void SharePVStructureArray::setCapacityMutable(bool isMutable)
{
lockShare();
try {
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
pvArray.setCapacityMutable(isMutable);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
bool SharePVStructureArray::isCapacityMutable()
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
return pvArray.isCapacityMutable();
}
void SharePVStructureArray::setCapacity(int capacity)
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
lockShare();
try {
pvArray.setCapacity(capacity);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
void SharePVStructureArray::setLength(int length)
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
lockShare();
try {
pvArray.setLength(length);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
int SharePVStructureArray::getCapacity() const
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
return pvArray.getCapacity();
}
int SharePVStructureArray::getLength() const
{
PVArray &pvArray = static_cast<PVArray &>(pvRecordField.getPVField());
return pvArray.getLength();
}
int SharePVStructureArray::get(int offset, int length, StructureArrayData *data)
{
class PVStructureArray &pvArray = static_cast<PVStructureArray &>(
pvRecordField.getPVField());
lockShare();
try {
return pvArray.get(offset,length,data);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
int SharePVStructureArray::put(
int offset,int length, PVStructurePtrArray from, int fromOffset)
{
class PVStructureArray &pvArray = static_cast<PVStructureArray &>(
pvRecordField.getPVField());
lockShare();
try {
pvRecordField.getPVRecord().beginGroupPut();
int len = pvArray.put(offset,length,from,fromOffset);
pvRecordField.getPVRecord().endGroupPut();
unlockShare();
return len;
} catch(...) {
unlockShare();
throw;
}
}
void SharePVStructureArray::shareData(
PVStructurePtrArray value,int capacity,int length)
{
throw std::logic_error("shareData not legal in this context");
}
bool SharePVStructureArray::equals(PVField &pv)
{
lockShare();
try {
return pvRecordField.getPVField().equals(pv);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
void SharePVStructureArray::serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const
{
serialize(pbuffer, pflusher, 0, getLength());
}
void SharePVStructureArray::deserialize(
ByteBuffer *pbuffer,DeserializableControl *pflusher)
{
class PVStructureArray &pvArray = static_cast<PVStructureArray &>(
pvRecordField.getPVField());
lockShare();
try {
pvArray.deserialize(pbuffer,pflusher);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
void SharePVStructureArray::serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher,int offset,int count) const
{
class PVStructureArray &pvArray = static_cast<PVStructureArray &>(
pvRecordField.getPVField());
lockShare();
try {
pvArray.serialize(pbuffer,pflusher,offset,count);
unlockShare();
} catch(...) {
unlockShare();
throw;
}
}
}}

View File

@ -1,4 +1,4 @@
/* recordListTest.cpp */
/* recordList.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found