EPICS exampleCPP/exampleLink

2016.08.30

Abstract

exampleLink implements a PVRecord that that links to another channel.

Table of Contents


Overview

This example shows how a PVRecord can have support that accesses another channel. It creates records named exampleMonitorLink, exampleGetLink, and examplePutLink. Each has a link to another channel. The process method of the records use pvaChannelMonitor, pvaChannelGet, and pvaChannelPut to connect to the other channel.

exampleLink can be started either as a main program of as part of an EPICS V3 IOC.

Start as a main program

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink
mrk> bin/$EPICS_HOST_ARCH/exampleLinkMain

Start it as part of an EPICS V3 IOC:

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink/iocBoot/exampleLink
mrk> ../../bin/$EPICS_HOST_ARCH/exampleLink st.cmd

exampleLinkClient

A pvaClient test is available to test exampleLink. Start the example and then:

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink
mrk> bin/$EPICS_HOST_ARCH/exampleLinkClient

Discussion

Access Alternatives

The process routine of a PVRecord can access other PVRecords in two ways:

Directly accessing local pvDatabase
If the other PVRecord is accessed via the master PVDatabase then threading issues are up to the implementation.
Access via channelProvider pva or ca
If provider pva or ca is used then locking is handled by pvAccess.
Access via channelProvider local
If provider local is used the implementation must be careful that it does not cause deadlocks. When the process method is called the pvRecord for the process method is locked. When it makes a pvAccess get, put, etc request the other record is locked. Thus if a set of pvAccess links are implemented the possibility of deadlocks exists. A simple example is two records that have links to each other. More complex sets are easily created. Unless the developer has complete control of the set of records then remote pvAccess should be used. But this results in more context switches.

Data synchronization

If pvAccess (provider pva or ca) is used then it handles data synchronization. This is done by making a copy of the data that is transferred between the two pvRecords. This is true if either remote or local pvAccess is used. Each get, put, etc request results in data being copied between the two records.

If the linked channel is a local pvRecord then, for scalar and structure arrays, raw data is NOT copied for gets. This is because pvData uses shared_vector to hold the raw data. Instead of copying the raw data the reference count is incremented.

For puts the linked array will force a new allocation of the raw data in the linked record, i. e. copy on write semantics are enforced. This is done automatically by pvData and not by pvDatabase.

Some details

As mentioned before a pvDatabase server can be either a separate process, i. e. a main program, or can be part of a V3IOC.

A main pvDatabase server issues the following calls:

...
    PVDatabasePtr master = PVDatabase::getMaster();
    ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
    PvaClientPtr pva= PvaClient::create("providerList");
    ServerContext::shared_pointer ctx =
    startPVAServer("local",0,true,true);
    
... 
    master->addRecord(...
...
    cout << "exampleLink\n";
    string str;
    while(true) {
        cout << "Type exit to stop: \n";
        getline(cin,str);
        if(str.compare("exit")==0) break;
    }
...

PvaClientPtr pva= PvaClient::create(providerList) is only necessary if some of the pvRecords have pva or ca links. This must be called before any code that uses links is initialized.

A pvDatabase that is part of a V3IOC has the following in the st.cmd file.

...
iocInit()
startPVAServer local
## commands to create pvRecords

Using exampleLinkMain to test providers local pva and ca

Options

The options supported by exampleLinkMain are shown by:

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink
mrk> bin/linux-x86_64/exampleLinkMain -help
provider exampleLinkRecordName . generateLinkedRecord
default
pva exampleLink doubleArray true
mrk>

Thus to run it with default options:

bin/linux-x86_64/exampleLinkMain 

exampleLinkMain creates an instance of ExampleLinkRecord. The record name is exampleLinkRecordName. The ExampleLinkRecord monitors linkedRecordName using the specified provider.

Monitor exampleLink

After exampleLinkMain is started then in another window:

pvget -m -r "field()" exampleMonitorLink

This can be kept running while exampleLinkMain is stopped and then restarted with other options as long as exampleLinkRecordName is doubleArray.

exampleLinkClient

This makes changes to the record that exampleLink monitors. It has the options:

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink
mrk> bin/linux-x86_64/exampleLinkClient -help
provider
default
pva

NOTE: If exampleLinkMain is stated with provider ca then exampleLinkClient must also be run with provider ca

exampleLinkClient only works if linkedRecordName is doubleArray.

Testing via provider local

This can be tested via:

bin/linux-x86_64/exampleLinkMain local 

Testing via provider pva

This can be done via the default options:

bin/linux-x86_64/exampleLinkMain 

It can also be run with pva accessing a record in another IOC:

bin/linux-x86_64/exampleLinkMain pva exampleLink doubleArray  false

But this only starts running when the following is also started:

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink
mrk> bin/linux-x86_64/doubleArrayMain 

NOTE do not leave this running for other exampleLinkMain options.

Testing via provider ca

This can be tested as follows:

bin/linux-x86_64/exampleLinkMain ca exampleLink doubleArray  false

But a softIoc for record doubleArray must also be started:

mrk> pwd
/home/epicsv4/master/exampleCPP/exampleLink/v3IOC
mrk> softIoc st.cmd

Directory Layout

exampleLink
    configure
       ExampleRELEASE.local
       ...
    src
       pv
          exampleLinkRecord.h
       exampleLinkRecord.cpp
       exampleLinkInclude.dbd
       exampleLinkRegister.cpp
       exampleLinkClient.cpp
       exampleLinkMain.cpp
       doubleArrayMain.cpp
    ioc
       Db
       src
          exampleLinkInclude.dbd
          exampleLinkMain.cpp
    iocBoot
        exampleLink
           st.local
           st.remote
    v3IOC
        db
            doubleArray.db
        st.cmd
        README
         ...