Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redo conversion between DBD and pvData #96

Merged
merged 46 commits into from
Jul 17, 2018
Merged

redo conversion between DBD and pvData #96

merged 46 commits into from
Jul 17, 2018

Conversation

mrkraimer
Copy link
Contributor

The code that converts between DVD and pvData is greatly modified.
The new implementation is provided by src/ca/dbdToPv.
To see how it supports pvRequest look at DbdToPv::activate.

Note that the new implementation no longer uses pvCopy but still properly implements bitSet for
channelGet and channelMonitor.

I tried to fix issue #77 but was not successful.
I did try changing code so that ca_clear_channel was called from a separate thread instead of from
CAChannel::~CAChannel thread.
But this did not work because CAChannel::~CAChannel was never called..

I have not tested dbr_char_t or dbr_short_t.
I am going to add DBRecords for those types in exampleCPP/database so that I can test those types before this pull request is merged.

In the meantime I am creating this pull request just in case someone has an interest in the new conversion and also has time.

@mrkraimer
Copy link
Contributor Author

except for the travis build for BRBASE=3.14 the following is true:
The builds with TEST=NO all work.
The other builds fail when running tests.

I know that qsrv will fail for 3.14 release.
But were some changes also made to pvAccessCPP so that it will not work with 3.14?

I merged with latest from epics-base.
I do see a failure in
make runtests.

But I see the same failure when I build in latest version in master branch of pvAccessCPP.
The failures are the same as for the travis builds.

I do not know what to do next.

@mrkraimer
Copy link
Contributor Author

I think I fixed the BRBASE=3.14 build.

@mrkraimer
Copy link
Contributor Author

Note that BRBASE=3.14 now only fails when running the tests.
Thus
The builds with TEST=NO all work.
All other builds fail only when running tests.

pvAccessCPP itself falis the same way when
make runtests
is executed.

Copy link
Member

@mdavidsaver mdavidsaver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See various inline comments on two general themes: 1) use shared_vector<const void> to avoid big switch(dbfType), and 2) unit tests are needed.

string properties;
if(alarmRequested && timeStampRequested) {
properties += "alarm,timeStamp";
caRequestType += DBR_TIME_STRING + caValueType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sort of DBR type promotion is best done with dbf_type_to_DBR_TIME(caValueType).

}


void DbdToPv::activate(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks to me that the bulk of this method is working with a native DBR type, and a pvRequest, to produce the actual DBR type(s) requested. This is logic which I would like to see being tested.

I can see two ways to do this. The first is to take advantage of the fact that local CA (aka dbContext.cpp) can be used in unit tests (since 3.16 I think). This would allow an fairly realistic end to end test. eg. Create a Provider and connect via libca to local records.

The second is to refactor a few methods (including this one) to split out a helper method which doesn't need a live chid and could be unit tested separately. In this case, such a (static) method would have a signature like:

void dbrMapRequest(short channelType, const PVStructurePtr& pvRequest, short *caRequestType, StructurePtr *structure);

Where channelType is a native type DBF_. caRequestType is the promoted DBR_ type code, and structure is the PVD structure. This method could then be tested more or less exhaustively for all of the DBF_* code, and a pre-defined list of pvRequests.

These two options are not mutually exclusive. Ideally both would be done. My preference would be to start with the second, as i think this will more quickly expose any gaps in the logic.

Also, as proof that I'm eating my own dog food. The equivalent testing in QSRV of mapping between PVD and dbAccess.h is done here:

https://github.com/epics-base/pva2pva/blob/master/testApp/testpvif.cpp

return getPVDataCreate()->createPVStructure(structure);
}

Status DbdToPv::getFromDBD(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is another case which needs testing. As with DbdToPv::activate the second option will involve some refactoring. In this case, I would try to separate out the logic as:

void fromDBD(const void *dbr, short dbrType, long dbrCount, const PVStructurePtr& dest, const BitSetPtr& changed)

}
break;
}
case DBR_STRING:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excepting enum and string, which continues to need special cases, the other DBF_* cases can be combined into two. Well, really two. One for scalars and one for array.

The array case will use PVScalarArray::putFrom(shared_vector<const void>&). A working example from QSRV is

https://github.com/epics-base/pva2pva/blob/1d0be31d3f96d33514b3e4cd795de48f430d8e26/pdbApp/pvif.cpp#L386-L394

For the scalar case, I'd like to say you could use PVScalar::putFrom(const AnyScalar&), but I realize that I'm missing a piece (ctor from type code and void*). Instead I'll recommend what is current use in QSRV, which is a union dbrbuf and "pv/typemap.h" to condense the switch statement.

https://github.com/epics-base/pva2pva/blob/1d0be31d3f96d33514b3e4cd795de48f430d8e26/pdbApp/pvif.cpp#L292-L313

dbr_short_t status = 0;
dbr_short_t severity = 0;
epicsTimeStamp stamp = {0,0};
if(caRequestType>=DBR_CTRL_STRING) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I found myself writing code like this for QSRV, I stopped and asked. If I only need display/control as double, why am I asking the server (which also only stores doubles) to convert to something else for transport and I have to undo this conversion? The outcome is that QSRV always subscribes to display/control meta-data as DBR_CTRL_DOUBLE.

If you for some reason can't/don't want to do this, then this section cries out for a template'd helper to avoid this repetition.

return Status::Ok;
}

Status DbdToPv::putToDBD(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A third case for testing. Here I'd separate the logic as:

void toDBD(const PVStructurePtr& dest, const BitSetPtr& changed, void *dbr, short* dbrType, long* dbrCount)

dbr_long_t ivalue(0);
dbr_float_t fvalue(0);
dbr_double_t dvalue(0);
char *ca_stringBuffer(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, std::vector<char> would be a great way to avoid leaking this local temp buffer.

https://github.com/epics-base/pva2pva/blob/1d0be31d3f96d33514b3e4cd795de48f430d8e26/pdbApp/pvif.cpp#L363

}
break;
}
case DBR_CHAR:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if(isArray) {
PVByteArrayPtr pvValue = pvStructure->getSubField<PVByteArray>("value");
count = pvValue->getLength();
pValue = pvValue->view().data();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Evil! shared_vector::data() is returning an internal reference from the instance which is returned by view(). Strictly speaking, this internal reference is invalidated when it's instance is destroyed, which happens immediately.

Please make pValue a shared_vector<const void> instead of const void*.

dbr_short_t svalue(0);
dbr_long_t ivalue(0);
dbr_float_t fvalue(0);
dbr_double_t dvalue(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdavidsaver
Copy link
Member

I do not know what to do next.

This was my doing. You happened to start work from a point where I had unwittingly broken Timer is PVD while trying to find ref. leaks in PVA (cf. epics-base/pva2pva#12). Both are now fixed.

You will need to do a re-base of your changes to get this fix.

FYI, I try to remember to run the tests as a baseline before I start making changes. Similarly, checking the latest CI results can help to avoid finding someone else's bugs https://travis-ci.org/epics-base/pvAccessCPP/branches

@mrkraimer
Copy link
Contributor Author

mrkraimer commented Apr 6, 2018

I need time to look at all of Michael's comments but I do have a comment(maybe question) about

When I found myself writing code like this for QSRV, I stopped and asked. If I only need display/control as double, why am I asking the server (which also only stores doubles) to convert to something else for transport and I have to undo this conversion? The outcome is that QSRV always subscribes to display/control meta-data as DBR_CTRL_DOUBLE.

The only reason for not just using DBR_CTRL_DOUBLE. is valueAlarm.
For standard fields control and display all limit fields are always double.
But for valueAlarm all numeric scalar types are defined.
Maybe provider ca should only support type double, i.e.

valueAlarm_t valueAlarm
        boolean active
        double lowAlarmLimit
        double lowWarningLimit
        double highWarningLimit
        double highAlarmLimit
        int lowAlarmSeverity
        int lowWarningSeverity
        int highWarningSeverity
        int highAlarmSeverity
        double hysteresis

Note that currently both qsrv and ca support the other types

mrk> pvget -p pva -r "" DBRlongout
DBRlongout
epics:nt/NTScalar:1.0 
    int value 0
    alarm_t alarm INVALID DRIVER UDF
    time_t timeStamp <undefined> 0
    display_t display
        double limitLow -100
        double limitHigh 100
        string description longout
        string format 
        string units volts
    control_t control
        double limitLow -90
        double limitHigh 90
        double minStep 0
    valueAlarm_t valueAlarm
        boolean active false
        int lowAlarmLimit -80
        int lowWarningLimit -60
        int highWarningLimit 60
        int highAlarmLimit 80
        int lowAlarmSeverity 0
        int lowWarningSeverity 0
        int highWarningSeverity 0
        int highAlarmSeverity 0
        int hysteresis 0


mrk> pvget -p ca -r "" DBRlongout
DBRlongout
structure 
    int value 0
    alarm_t alarm INVALID 17 UDF
    display_t display
        double limitLow -100
        double limitHigh 100
        string description 
        string format I12
        string units volts
    control_t control
        double limitLow -90
        double limitHigh 90
        double minStep 0
    valueAlarm_t valueAlarm
        boolean active false
        int lowAlarmLimit -80
        int lowWarningLimit -60
        int highWarningLimit 60
        int highAlarmLimit 80
        int lowAlarmSeverity 0
        int lowWarningSeverity 0
        int highWarningSeverity 0
        int highAlarmSeverity 0
        int hysteresis 0

If ca is changed to use double for alarm limits then I think qsrv also should make the same change.
I will guess that most (maybe all) will want valueAlarm limits as double.

Michael,
What do You think?

@mdavidsaver
Copy link
Member

QSRV always subscribes to display/control meta-data as DBR_CTRL_DOUBLE

Firstly, to clarify. QSRV uses dbAccess.h, where DBR_CTRL_DOUBLE refers to DBRctrlDouble. I also always use DBRgrDouble and DBRalDouble for all DBF types. So the limit values extracted via. dbGet() are always double. As I'm using the StandardField class to build types, these values are stored on the PVD side as int/short/float/... depending on the value type. This conversion is handled transparently via PVScalar::putFrom() (I'd forgotten this was happening).

If ca is changed to use double for alarm limits then I think qsrv also should make the same change.

(I'm assuming that "ca" means "caProvider" here)

QSRV already uses PVScalar to interact with the limit values. So this particular change wouldn't break anything.

Using StandardField has caused me a little pain in the past. Not in this way, but because it doesn't mesh well with FieldBuilder. Also, when I looked at adding other members under 'timeStamp' I had to stop using StandardField::timestamp(). So I find myself wishing that StandardField allowed a more piecemeal approach to building types. And didn't do any string parsing.

@mrkraimer
Copy link
Contributor Author

I am committing major changes to dbdToPv including using templates.
I have not added any tests in pvAccessCPP.
I have made changes to examplCPP/database so that all DBF types can be tested.
See the documentatiion in exampleCPP for a brief description.

I do not know how to fix issue #77, i.e. possible deadlock on termination.
I did spend a short amount if time on this issue but was not successful.

I am starting to create a document describing compatibility between

  • channel access
  • ca provider
  • qsrv
    I hope to have this ready in time so that we can discuss it at BNL FTF meeting in May 2018

@mrkraimer
Copy link
Contributor Author

Michael,
Can this pull request be merged?

@mdavidsaver
Copy link
Member

My original review:

See various inline comments on two general themes: 1) use shared_vector to avoid big switch(dbfType), and 2) unit tests are needed.

With these changes 1) has been partially addressed via. templates. There is still no unit test coverage.

I really want to see unit test coverage of the type and value handling code. All my experience with CA and PVD tells me that there will be bugs here. If not now, then if future. Manual testing is nice, and necessary, but doesn't help me with verification, nor the long term maintainability of this code.

@mrkraimer Will you create unit tests for the 3 pieces of code I commented on? These need to cover the range of user inputs (pvRequest) and native field types (DBF_*).

  • DbdToPv::activate
  • DbdToPv::getFromDBD
  • DbdToPv::putToDBD

@mrkraimer
Copy link
Contributor Author

I have added tests for provider ca.
But

cd testApp
make runtests

fails with

......LOTS OF OUTPUT.....
testServerContext.t ..... ok   
testCaProvider.t ........ Starting iocInit
.....MORE OUTPUT...
testCaProvider.t ........ Failed 1/11 subtests 

Test Summary Report
-------------------
testCaProvider.t      (Wstat: 0 Tests: 10 Failed: 0)
  Parse errors: Tests out of sequence.  Found (2) but expected (1)
                Tests out of sequence.  Found (3) but expected (2)
                Tests out of sequence.  Found (4) but expected (3)
                Tests out of sequence.  Found (5) but expected (4)
                Tests out of sequence.  Found (6) but expected (5)
Displayed the first 5 of 11 TAP syntax errors.
Re-run prove with the -p option to see them all.
Files=11, Tests=6202, 27 wallclock secs ( 0.34 usr  0.02 sys +  0.38 cusr  0.17 csys =  0.91 CPU)
Result: FAIL
Failed 1/11 test programs. 0/6202 subtests failed.
make[1]: [/home/epicsv4/masterCPP/epics-base/configure/RULES_BUILD:342: runtests] Error 255 (ignored)
make[1]: Leaving directory '/home/epicsv4/masterCPP/pvAccessCPP/testApp/O.linux-x86_64'
mrk> 

But the following works:

mrk> cd O.linux-x86_64/
mrk> ./testCaProvider 
1..11
# ===Test caProvider===
.....LOTS OF OUTPUT...

    Results
    =======
       Tests: 11 
      Passed:  11 = 100.00%
mrk> 

Any ideas?

@mdavidsaver
Copy link
Member

@mrkraimer We now have a lot of infrastructure which can cut way down on the boilerplate, and make tests like this work better.

Instead of starting an IOC as a separate process, have a look at dbUnitTest.h. You'll find a number of usages of this under "src/ioc/db/test/" and "src/std/rec/test/". For example:

https://github.com/epics-base/epics-base/blob/3.16/src/ioc/db/test/dbPutLinkTest.c#L394

And I know you won't like this, but using "pva/client.h" will massively reduce the client boilerplate. This boilerplate accounts for ~600 of the ~700 lines of the test code.

pvac::ClientProvider prov("ca");
pvac::Channel ch(prov.connect("pv:name"));
// ...
epics::pvData::PVStructure::const_shared_ptr val(ch.get(3.0, pvRequest));
// ...
ch.put(pvRequest)
 .set<epics::pvData::uint32>("field", 42)
 .exec();

@mrkraimer
Copy link
Contributor Author

I have moved the tests for ca provider from testApp to testCa,
I am still trying to use softIoc to start the IOC instead of epics-base/src/ioc/test.
But the following still fails:

mrk> pwd
/home/epicsv4/masterCPP/pvAccessCPP/testCa
mrk> make runtests
....MORE OUTPUT...
..................................................................
testCaProvider.t .. Failed 1/11 subtests 

Test Summary Report
-------------------
testCaProvider.t (Wstat: 0 Tests: 10 Failed: 0)
  Parse errors: Tests out of sequence.  Found (2) but expected (1)
                Tests out of sequence.  Found (3) but expected (2)
                Tests out of sequence.  Found (4) but expected (3)
                Tests out of sequence.  Found (5) but expected (4)
                Tests out of sequence.  Found (6) but expected (5)
Displayed the first 5 of 11 TAP syntax errors.
Re-run prove with the -p option to see them all.
Files=1, Tests=10,  1 wallclock secs ( 0.03 usr  0.00 sys +  0.03 cusr  0.02 csys =  0.08 CPU)
Result: FAIL
Failed 1/1 test programs. 0/10 subtests failed.
make[1]: [/home/epicsv4/masterCPP/epics-base/configure/RULES_BUILD:342: runtests] Error 255 (ignored)
make[1]: Leaving directory '/home/epicsv4/masterCPP/pvAccessCPP/testCa/O.linux-x86_64'
mrk> 

But when I run

mrk> pwd
/home/epicsv4/masterCPP/pvAccessCPP/testCa/O.linux-x86_64
mrk> ./testCaProvider 
1..11
# ===Test caProvider===
... MORE OUTPUT...
    Results
    =======
       Tests: 11 
      Passed:  11 = 100.00%
mrk> 

Does anyone know what is happening?
Note that I am creating a separate thread that starts softIoc.
The softIoc terminates when a put is issued to a calc record which calls exit,

@mrkraimer
Copy link
Contributor Author

Note that

mrk> pwd
/home/epicsv4/masterCPP/pvAccessCPP/testCa
mrk> make runtests

Now works for me but some travis builds still fail.

@mdavidsaver
Copy link
Member

I certainly know that dbUnitTest.h was introduced in 3.15. I thought that the local CA changes were on 3.15 as well, but I see that this is not the case (epics-base/epics-base@3e8ba7d). My concern is maintainability going forward, so I have no problem with only running this test when built against 3.16.

I can't stress enough how much I dislike using system() to launch softIoc. This is going to be a very hard sell with me. At minimum, there must be a mechanism to kill the child process if testAbort() is hit. Also, there needs to be some isolation. The ugly approach would be a different random name prefix for all records needs to be chosen each run to prevent name collisions if there should happen to be two processes running (cf. testAbort()). Better, a randomly chosen UDP port should be used, and the client and RSRV should be restricted to localhost.

@mrkraimer
Copy link
Contributor Author

Michael said

I can't stress enough how much I dislike using system() to launch softIoc

An argument for implementing a call to system is:
A server process needs to be started in order to test client code,
but the server is NOT running as part of an IOC .

I realize that this is a problem for RTEMS and vvWorks.
Maybe a libCom/osi could provide a solution?

@ralphlange
Copy link
Contributor

IMHO, your argument supports starting a separate process, but not the use of the system() call.

@mrkraimer
Copy link
Contributor Author

mrkraimer commented May 29, 2018

Ralph said

MHO, your argument supports starting a separate process, but not the use of the system() call.

So how do I do this in RTEMS and vxWorks?

@ralphlange
Copy link
Contributor

Let's talk about that in the telecon.
I don't think Michael's statement is about RTEMS/VxWorks; I think it is about the system() call leaving the parent with almost no control over the child. Which you need in case you e.g. want to shut down the test prematurely.

@mrkraimer
Copy link
Contributor Author

Note the name of this pull request.
The initial pull request was to be able to deprecate destroy in ca provider.
I did this by implementing the rules Michael developed for when to use weak pointers.
I did my initial testing via exampleCPP.
It has been almost two months since this pull request was issued.

But then it was requested that I develop a test in pvAccessCPP for ca provider even though no test ever existed.
Now it looks like it there may not be a quick resolution about the use of system.
I think the pull request should be merged and then further work can be done on testCa.

@mrkraimer
Copy link
Contributor Author

Andrew said

In particular the tests you wrote currently only try doing puts as a string value,

Actually this is not true. The string values for the test are converted to the type for the channel.
For example put has the code:

void TestChannelPut::put(string const & value)
{
    PVFieldPtr pvField(pvStructure->getSubField("value"));
    if(!pvField) throw std::runtime_error(testChannel->getChannelName() 
         + " TestChannelPut::put no value ");
    FieldConstPtr field(pvField->getField());
    Type type(field->getType());
    if(type==scalar) {
        PVScalarPtr pvScalar(std::tr1::static_pointer_cast<PVScalar>(pvField));
        getConvert()->fromString(pvScalar,value);
        bitSet->set(pvField->getFieldOffset());
        channelPut->put(pvStructure,bitSet);
        return;
    }
    if(type==scalarArray) {
        PVScalarArrayPtr pvScalarArray(std::tr1::static_pointer_cast<PVScalarArray>(pvField));
        std::vector<string> values;
        size_t pos = 0;
        size_t n = 1;
        while(true)
        {
            size_t offset = value.find(" ",pos);
            if(offset==string::npos) {
                values.push_back(value.substr(pos));
                break;
            }
            values.push_back(value.substr(pos,offset-pos));
            pos = offset+1;
            n++;    
        }
        pvScalarArray->setLength(n);
        getConvert()->fromStringArray(pvScalarArray,0,n,values,0);       
        bitSet->set(pvField->getFieldOffset());
        channelPut->put(pvStructure,bitSet);
        return;
    }
    if(type==structure) {
       PVScalarPtr pvScalar(pvStructure->getSubField<PVScalar>("value.index"));
       if(pvScalar) {
          getConvert()->fromString(pvScalar,value);
          bitSet->set(pvScalar->getFieldOffset());
          channelPut->put(pvStructure,bitSet);
          return;
       }
    }
    throw std::runtime_error(testChannel->getChannelName() 
        + " TestChannelPut::put not supported  type");
}

Marty

@anjohnson
Copy link
Member

@mrkraimer you're right, my apologies for forgetting that pvAccess only allows puts in the native type of the channel anyway, and for not reading your code carefully enough.

My point about your always using a pvRequest of "value" for puts and "value,alarm,timestamp" for gets still stands though. IIRC you discussed a bug several months back that you found when the pvRequest fields were named in a different order, shouldn't there be some regression tests for that problem?

@mrkraimer
Copy link
Contributor Author

mrkraimer commented Jun 8, 2018

I have been spending lots of time trying to fix the Deadlock in ca_clear_subscription problem.
https://bugs.launchpad.net/epics-base/7.0/+bug/1751380

I did arrange to have an aux thread issue the ca_clear_subscription, but this did not fix the problem.
I suspect that ALL client calls need to be handled by the aux thread.
I am going to push my latest changes to my repository in case anyone wants to see what I did.

I also created tests in
https://github.com/mrkraimer/testClientCPP

Note that the tests that use pvaClientCPP do not fail but they also did not fail without the aux thread.
But these tests do not hold any mutexes while calling ca_clear_subscription.

The tests that use pvAccessCP/src/client/pva/client.h do fail when monitoring on more than one channel.

@mrkraimer
Copy link
Contributor Author

I made some more changes for what happens when a monitor is destructed.
BUT tests that use pvAccessCP/src/client/pva/client.h still fail.

@mrkraimer
Copy link
Contributor Author

mrkraimer commented Jun 19, 2018

I am going to push changes.
Instead of a separate thread for stopping monitors there is now separate thread for client monitor events.

Now

mrk> pwd
/home/epicsv4/masterCPP/pvAccessCPP
mrk> examples/O.linux-x86_64/monitorme -p ca FAST1 FAST2 FAST3 FAST4

works just fine.
I have run several other tests and they also work just fine.
This should fix
https://bugs.launchpad.net/epics-base/7.0/+bug/1751380)

I am not ready for this pull request to be merged since I still want to do more testing.
But I am pushing so that I can see if the travis builds succeed.
Also so that anyone interested can see what I have done.

@mrkraimer
Copy link
Contributor Author

It is approaching three months since this pull request was issued.
It evolved into a lot more than just "redo conversion between DBD and pvData".
I just added caProvider.md, which provides many details about what caProvider does.

I really really want this pull request merged since it is a real improvement.

@anjohnson
Copy link
Member

Hi Marty,

I'm seeing lots of warnings when testCaProvider.cpp gets built because it includes both dbAccess.h and cadef.h (through caProvider.h). This change removes them:

diff --git a/src/ca/pv/caProvider.h b/src/ca/pv/caProvider.h
index a147d26..2a18acd 100644
--- a/src/ca/pv/caProvider.h
+++ b/src/ca/pv/caProvider.h
@@ -8,9 +8,10 @@
 #define CAPROVIDER_H
 
 #include <shareLib.h>
-#include <cadef.h>
 #include <pv/pvAccess.h>
 
+struct ca_client_context;
+
 namespace epics {
 namespace pvAccess {
 namespace ca {
@@ -39,7 +40,7 @@ public:
      * This can be called by an application specific auxiliary thread.
      * See ca documentation. Not for casual use.
      */
-    static ca_client_context * get_ca_client_context();
+    static struct ca_client_context * get_ca_client_context();
     /** @brief stop provider ca
      *
      * This does nothing since epicsAtExit is used to destroy the instance.
  • Andrew

@mrkraimer
Copy link
Contributor Author

mrkraimer commented Jul 10, 2018

I have now implemented code to call channelGet and channelPut callbacks via separate threads.

I have successfully run a test that connects to four records that process at maximum rate.
The client test has a monitor on each record as well as issuing gets and puts as fast as possible.

I developed the code for the ca provider in

https://github.com/mrkraimer/pva2ca

I put the new code in a new repository because I do not know what the plans are the ca provider that is the subject of this pull request. But it would be easy for me to move the code back to pvAccess.

The test is in

https://github.com/mrkraimer/testClientCPP

The name of the new test is getputmonitorrate.

I think that it is important that the latest version of the ca provider be part of the next EPICS 7 release.
But how:

If it is a separate repository, i. e. it is unbundled from pvAccess then I maintain that pvTools also be unbundled or else "pvget -p ca" and "pvput -p ca" will not work.

If it is not separate repository will I be allowed to merge after I move code from mrkraimer/pva2ca back to pvAccess?

@mrkraimer
Copy link
Contributor Author

mdavidsaver said

#114

It works with my latest in mrkraimer:

mrk> pvget -p ca -r "value" -i DBRbo00
DBRbo00
epics:nt/NTEnum:1.0 
    enum_t value
        int index 0
        string[] choices [zero,one]
mrk> pvput -p ca DBRbo00 1
Old : DBRbo00                        zero
New : DBRbo00                        one
mrk> pvput -p ca DBRbo00 zero
Old : DBRbo00                        one
New : DBRbo00                        zero
mrk> pvput -p pva DBRbo00 1
Old : DBRbo00                        zero
New : DBRbo00                        one
mrk> pvput -p pva DBRbo00 zaro
Old : DBRbo00                        one
Error: parseToPOD: No digits to convert
mrk> pvput -p pva DBRbo00 zaro
Old : DBRbo00                        one
Error: parseToPOD: No digits to convert
New : DBRbo00                        one
mrk> pvput -p pva DBRbo00 zero
Old : DBRbo00                        one
New : DBRbo00                        zero
mrk> 

@ralphlange
Copy link
Contributor

I think that it is important that the latest version of the ca provider be part of the next EPICS 7 release.
But how:

If it is a separate repository, i. e. it is unbundled from pvAccess then I maintain that pvTools also be unbundled or else "pvget -p ca" and "pvput -p ca" will not work.

It is not separate repository will I be allowed to merge after I move code from mrkraimer/pva2ca back to pvAccess?

I do not understand that question.
The "unbundling" that we were talking about recently would move the ca provider code into its own repository, inside the EPICS organization, its sources inside the EPICS 7 bundle source tree (via git submodule).
It was never discussed or considered to take the ca provider out of the distribution.

For configuration-less adding of providers I would suggest a plug-in architecture, where the presence of a shared library in a well-known place is enough to use it. For the PVA client, any provider except PVA itself should be pluggable.
Until such a mechanism exists, configuring the supported protocols at compile time is fine (preferably in the build system, not in the sources).

@anjohnson
Copy link
Member

anjohnson commented Jul 13, 2018

Marty, do you need to push some recent changes to github? My copy of your branch still prints some debugging messages as I showed in #114

tux% bin/linux-x86_64/pvput -p ca anj:bo1 1
Old : anj:bo1                        Zero
New : anj:bo1                        One
CAChannelProvider::~CAChannelProvider() returning
MonitorEventThread::~MonitorEventThread()

Andrew,

The latest push should fix remove the extra messages.

@anjohnson anjohnson merged commit 613bfc5 into epics-base:master Jul 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants