PDB provider get() working
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user