PDB provider get() working

This commit is contained in:
Michael Davidsaver
2016-03-02 17:32:53 -05:00
parent 3425aaba7a
commit fc19ab7164
10 changed files with 128 additions and 23 deletions

View File

@@ -12,7 +12,7 @@
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
int PDBProviderDebug = 0;
int PDBProviderDebug = 3;
namespace {
struct GroupMemberInfo {
@@ -66,14 +66,14 @@ PDBProvider::PDBProvider()
const char *next = strchr(pos, '|'),
*equal= strchr(pos, '=');
if(!equal || equal>next)
if(!equal || (next && equal>next))
throw std::runtime_error("expected '='");
info.members.push_back(GroupMemberInfo(recbase + (next ? std::string(equal+1, next-pos) : std::string(equal+1)),
info.members.push_back(GroupMemberInfo(recbase + (next ? std::string(equal+1, next-equal-1) : std::string(equal+1)),
std::string(pos, equal-pos)));
if(PDBProviderDebug>2) {
fprintf(stderr, " pdbGroup '%s' add %s=%s\n",
fprintf(stderr, " pdbGroup '%s' add '%s'='%s'\n",
info.name.c_str(),
info.members.back().pvfldname.c_str(),
info.members.back().pvname.c_str());
@@ -104,19 +104,26 @@ PDBProvider::PDBProvider()
pvd::shared_vector<DBCH> chans(nchans);
std::vector<dbCommon*> records(nchans);
pvd::FieldBuilderPtr builder(pvd::getFieldCreate()->createFieldBuilder());
for(size_t i=0; i<nchans; i++)
{
GroupMemberInfo &mem = info.members[i];
DBCH chan(mem.pvname);
builder->add(mem.pvfldname, PVIF::dtype(chan));
pv->attachments[i] = mem.pvfldname;
records[i] = dbChannelRecord(chan);
chans[i].swap(chan);
}
pv->fielddesc = builder->createStructure();
pv->chan.swap(chans);
pv->locker.reset(dbLockerAlloc(&records[0], records.size(), 0));
if(!pv->locker.get())
throw std::runtime_error("Failed to create dbLocker");
DBManyLock L(&records[0], records.size(), 0);
pv->locker.swap(L);
persist_pv_map[info.name] = pv;

View File

@@ -1,3 +1,5 @@
#include <epicsAtomic.h>
#include <dbAccess.h>
#include "pdbgroup.h"
@@ -6,6 +8,18 @@
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
size_t PDBGroupPV::ninstances;
PDBGroupPV::PDBGroupPV()
{
epics::atomic::increment(ninstances);
}
PDBGroupPV::~PDBGroupPV()
{
epics::atomic::decrement(ninstances);
}
pva::Channel::shared_pointer
PDBGroupPV::connect(const std::tr1::shared_ptr<PDBProvider>& prov,
const pva::ChannelRequester::shared_pointer& req)
@@ -18,8 +32,8 @@ PDBGroupChannel::PDBGroupChannel(const PDBGroupPV::shared_pointer& pv,
const std::tr1::shared_ptr<pva::ChannelProvider>& prov,
const pva::ChannelRequester::shared_pointer& req)
:BaseChannel(pv->name, prov, req, pv->fielddesc)
{
}
,pv(pv)
{}
void PDBGroupChannel::printInfo(std::ostream& out)
{
@@ -71,7 +85,7 @@ void PDBGroupGet::get()
changed->clear();
if(atomic) {
DBManyLocker L(channel->pv->locker.get());
DBManyLocker L(channel->pv->locker);
for(size_t i=0; i<npvs; i++)
pvif[i]->put(*changed, DBE_VALUE|DBE_ALARM|DBE_PROPERTY, NULL);
} else {

View File

@@ -19,10 +19,12 @@ struct PDBGroupPV : public PDBPV, public std::tr1::enable_shared_from_this<PDBGr
std::string name;
epics::pvData::shared_vector<DBCH> chan;
std::vector<std::string> attachments;
std::auto_ptr<dbLocker> locker;
DBManyLock locker;
PDBGroupPV() {}
virtual ~PDBGroupPV() {}
static size_t ninstances;
PDBGroupPV();
virtual ~PDBGroupPV();
virtual
epics::pvAccess::Channel::shared_pointer

View File

@@ -1,4 +1,5 @@
#include <dbAccess.h>
#include <epicsAtomic.h>
#include "pdbsingle.h"
#include "pdb.h"
@@ -6,12 +7,20 @@
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
size_t PDBSinglePV::ninstances;
PDBSinglePV::PDBSinglePV(DBCH& chan,
const PDBProvider::shared_pointer& prov)
:provider(prov)
{
this->chan.swap(chan);
fielddesc = PVIF::dtype(this->chan);
epics::atomic::increment(ninstances);
}
PDBSinglePV::~PDBSinglePV()
{
epics::atomic::decrement(ninstances);
}
pva::Channel::shared_pointer

View File

@@ -18,9 +18,11 @@ struct PDBSinglePV : public PDBPV, public std::tr1::enable_shared_from_this<PDBS
DBCH chan;
PDBProvider::shared_pointer provider;
static size_t ninstances;
PDBSinglePV(DBCH& chan,
const PDBProvider::shared_pointer& prov);
virtual ~PDBSinglePV() {}
virtual ~PDBSinglePV();
epics::pvAccess::Channel::shared_pointer
connect(const std::tr1::shared_ptr<PDBProvider>& prov,

View File

@@ -55,7 +55,12 @@ struct pdbRecordIterator {
{
dbInitEntry(pdbbase, &ent);
m_done = dbFirstRecordType(&ent)!=0;
if(!m_done) m_done = dbFirstRecord(&ent)!=0;
while(!m_done) {
if(dbFirstRecord(&ent)==0)
break;
// not instances of this type
m_done = dbNextRecordType(&ent)!=0;
}
}
~pdbRecordIterator()
{
@@ -63,8 +68,17 @@ struct pdbRecordIterator {
}
bool done() const { return m_done; }
bool next() {
m_done = dbNextRecord(&ent)!=0;
if(m_done) m_done = dbNextRecordType(&ent)!=0;
if(!m_done && dbNextRecord(&ent)!=0)
{
// done with this recordType
while(true) {
m_done = dbNextRecordType(&ent)!=0;
if(m_done) break;
if(dbFirstRecord(&ent)==0)
break;
// not instances of this type
}
}
return m_done;
}
dbCommon* record() const {
@@ -92,6 +106,20 @@ struct DBScanLocker
{ dbScanUnlock(prec); }
};
struct DBManyLock
{
dbLocker *plock;
DBManyLock() :plock(NULL) {}
DBManyLock(dbCommon **precs, size_t nrecs, unsigned flags=0)
:plock(dbLockerAlloc(precs, nrecs, flags))
{
if(!plock) throw std::invalid_argument("Failed to create locker");
}
~DBManyLock() { if(plock) dbLockerFree(plock); }
void swap(DBManyLock& O) { std::swap(plock, O.plock); }
operator dbLocker*() { return plock; }
};
struct DBManyLocker
{
dbLocker *plock;

View File

@@ -7,6 +7,7 @@ include $(TOP)/configure/CONFIG
USR_CPPFLAGS += -I$(TOP)/p2pApp
USR_CPPFLAGS += -I$(TOP)/pdbApp
USR_CPPFLAGS += -I$(TOP)/common
TARGETS += $(COMMON_DIR)/p2pTestIoc.dbd
p2pTestIoc_DBD += base.dbd

View File

@@ -1,12 +1,15 @@
#include <testMain.h>
#include <epicsAtomic.h>
#include <dbAccess.h>
#include <pv/epicsException.h>
#include "utilities.h"
#include "pdb.h"
#include "pdbgroup.h"
#include "pdbsingle.h"
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
@@ -21,8 +24,7 @@ void testFieldEqual(const pvd::PVStructurePtr& val, const char *name, typename P
testFail("field '%s' with type %s does not exist", name, typeid(PVD).name());
} else {
typename PVD::value_type actual(fval->get());
std::cout<<"# expect='"<<expect<<"' actual='"<<actual<<"'\n";
testOk1(actual==expect);
testEqualx(name, "expect", actual, expect);
}
}
@@ -67,11 +69,16 @@ pvd::PVStructurePtr pvget(const pva::ChannelProvider::shared_pointer& prov, cons
testOk1(!!greq->value);
if(!greq->value)
testAbort("'%s' get w/o data", name);
get->destroy();
chan->destroy();
return greq->value;
}
void testSingle(const PDBProvider::shared_pointer& prov)
void testSingleGet(const PDBProvider::shared_pointer& prov)
{
testDiag("test single get");
pvd::PVStructurePtr value;
value = pvget(prov, "rec1", false);
@@ -81,6 +88,26 @@ void testSingle(const PDBProvider::shared_pointer& prov)
testFieldEqual<pvd::PVInt>(value, "value", 10);
}
void testGroupGet(const PDBProvider::shared_pointer& prov)
{
testDiag("test group get");
pvd::PVStructurePtr value;
testDiag("get non-atomic");
value = pvget(prov, "grp1", false);
testFieldEqual<pvd::PVDouble>(value, "fld1.value", 3.0);
testFieldEqual<pvd::PVInt>(value, "fld2.value", 30);
testFieldEqual<pvd::PVDouble>(value, "fld3.value", 4.0);
testFieldEqual<pvd::PVInt>(value, "fld4.value", 40);
testDiag("get atomic");
value = pvget(prov, "grp1", true);
testFieldEqual<pvd::PVDouble>(value, "fld1.value", 3.0);
testFieldEqual<pvd::PVInt>(value, "fld2.value", 30);
testFieldEqual<pvd::PVDouble>(value, "fld3.value", 4.0);
testFieldEqual<pvd::PVInt>(value, "fld4.value", 40);
}
} // namespace
extern "C"
@@ -98,8 +125,14 @@ MAIN(testpdb)
IOC.init();
PDBProvider::shared_pointer prov(new PDBProvider());
testSingle(prov);
{
PDBProvider::shared_pointer prov(new PDBProvider());
testSingleGet(prov);
testGroupGet(prov);
}
testDiag("check to see that all dbChannel are closed before IOC shuts down");
testEqual(epics::atomic::get(PDBGroupPV::ninstances), 0u);
testEqual(epics::atomic::get(PDBSinglePV::ninstances), 0u);
}catch(std::exception& e){
PRINT_EXCEPTION(e);

View File

@@ -26,7 +26,7 @@ TestChannelRequester::~TestChannelRequester()
void TestChannelRequester::channelCreated(const pvd::Status& status, pva::Channel::shared_pointer const & channel)
{
testDiag("channelCreated %s", channel->getChannelName().c_str());
testDiag("channelCreated %s", channel ? channel->getChannelName().c_str() : "<fails>");
Guard G(lock);
laststate = pva::Channel::CONNECTED;
this->status = status;

View File

@@ -50,6 +50,15 @@ void test_method(const char *kname, const char *mname)
// Construct an instance and run one method
#define TEST_METHOD(klass, method) test_method<klass, &klass::method>(#klass, #method)
template<typename LHS, typename RHS>
void testEqualx(const char *nLHS, const char *nRHS, LHS l, RHS r)
{
std::ostringstream msg;
msg<<nLHS<<" ("<<l<<") == "<<nRHS<<" ("<<r<<")";
testOk(l==r, "%s", msg.str().c_str());
}
#define testEqual(LHS, RHS) testEqualx(#LHS, #RHS, LHS, RHS)
// Boilerplate reduction for accessing a scalar field
template<typename T>
struct ScalarAccessor {