main addition is array performance example
This commit is contained in:
@ -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> 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()->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->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> pwd
|
||||
/home/hg/pvDatabaseCPP-md
|
||||
mrk> bin/linux-x86_64/arrayPerformanceMain -help
|
||||
arrayPerformanceMain recordName size delay providerName nMonitor useQueue
|
||||
default
|
||||
arrayPerformance arrayPerformance 50000000 0.001 local 1 false
|
||||
mrk> bin/linux-x86_64/longArrayMonitorMain -help
|
||||
longArrayMonitorMain channelName useQueue
|
||||
default
|
||||
longArrayMonitorMain arrayPerformance false
|
||||
mrk>
|
||||
</pre>
|
||||
<h3>Example output</h3>
|
||||
<pre>
|
||||
mrk> 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> pwd
|
||||
/home/hg/pvDatabaseCPP-md
|
||||
mrk> 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> pwd
|
||||
/home/hg/pvDatabaseCPP-md
|
||||
mrk> 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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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> 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
|
||||
|
@ -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
|
||||
|
1727
documentation/pvDatabaseCPP_20130828.html
Normal file
1727
documentation/pvDatabaseCPP_20130828.html
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,7 @@ DIRS += pvCopy
|
||||
DIRS += exampleCounter
|
||||
DIRS += exampleServer
|
||||
DIRS += examplePVADoubleArrayGet
|
||||
DIRS += arrayPerformance
|
||||
DIRS += v3IOC
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
|
20
example/arrayPerformance/Makefile
Normal file
20
example/arrayPerformance/Makefile
Normal 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
|
||||
|
108
example/arrayPerformance/arrayPerformanceMain.cpp
Normal file
108
example/arrayPerformance/arrayPerformanceMain.cpp
Normal 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;
|
||||
}
|
||||
|
70
example/arrayPerformance/longArrayMonitorMain.cpp
Normal file
70
example/arrayPerformance/longArrayMonitorMain.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
173
example/src/arrayPerformance/arrayPerformance.cpp
Normal file
173
example/src/arrayPerformance/arrayPerformance.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
80
example/src/arrayPerformance/arrayPerformance.h
Normal file
80
example/src/arrayPerformance/arrayPerformance.h
Normal 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 */
|
284
example/src/arrayPerformance/longArrayMonitor.cpp
Normal file
284
example/src/arrayPerformance/longArrayMonitor.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
71
example/src/arrayPerformance/longArrayMonitor.h
Normal file
71
example/src/arrayPerformance/longArrayMonitor.h
Normal 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 */
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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 ¤tElement)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
queue.releaseUsed(currentElement);
|
||||
currentElement->changedBitSet->clear();
|
||||
currentElement->overrunBitSet->clear();
|
||||
if(!queueIsFull) return;
|
||||
queueIsFull = false;
|
||||
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
|
||||
MonitorElementPtr newElement = queue.getFree();
|
||||
BitSetUtil::compress(monitorElement->changedBitSet,pvStructure);
|
||||
BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure);
|
||||
convert->copy(pvStructure,newElement->pvStructurePtr);
|
||||
newElement->changedBitSet->clear();
|
||||
newElement->overrunBitSet->clear();
|
||||
monitorLocal->getPVCopyMonitor()->switchBitSets(
|
||||
newElement->changedBitSet,newElement->overrunBitSet,false);
|
||||
queue.setUsed(monitorElement);
|
||||
monitorElement = newElement;
|
||||
|
||||
Lock xx(mutex);
|
||||
queue.releaseUsed(currentElement);
|
||||
queueIsFull = false;
|
||||
}
|
||||
|
||||
MonitorFactoryPtr getMonitorFactory()
|
||||
|
@ -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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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)
|
||||
|
@ -55,20 +55,16 @@ public:
|
||||
PVRecordFieldPtr getRecordPVField(std::size_t structureOffset);
|
||||
void initCopy(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet,
|
||||
bool lockRecord);
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateCopySetBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet,
|
||||
bool lockRecord);
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateCopyFromBitSet(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
epics::pvData::BitSetPtr const &bitSet,
|
||||
bool lockRecord);
|
||||
epics::pvData::BitSetPtr const &bitSet);
|
||||
void updateRecord(
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
@ -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
|
||||
|
Reference in New Issue
Block a user