pvalink: use cached values for triggered scan

This commit is contained in:
Michael Davidsaver
2016-03-24 17:03:46 -04:00
parent 457ef87d95
commit f1f6db989e
4 changed files with 359 additions and 70 deletions

36
common/pvatypemap.h Normal file
View File

@ -0,0 +1,36 @@
/* #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE)
*
* BASETYPE is suffix of type from epicsTypes.h
* epics ## BASETYPE -> eg. epicsUInt8
* PVATYPE is storage type
* PVATYPE -> eg epics::pvData::uint8
* DBFTYPE is suffix of DBF_*
* DBF_ ## DBFTYPE -> eg. DBF_UCHAR
* PVACODE is suffix of ScalarType enum
* epics::pvData::pv ## PVACODE -> epics::pvData::pvUByte
*/
CASE(UInt8, epics::pvData::uint8, UCHAR, UByte)
CASE(Int8, epics::pvData::int8, CHAR, Byte)
CASE(UInt16, epics::pvData::uint16, USHORT, UShort)
CASE(Int16, epics::pvData::int16, SHORT, Short)
CASE(UInt32, epics::pvData::uint32, ULONG, UInt)
CASE(Int32, epics::pvData::int32, LONG, Int)
CASE(Float32, float, FLOAT, Float)
CASE(Float64, double, DOUBLE, Double)
#ifndef CASE_SKIP_BOOL
CASE(UInt8, epics::pvData::boolean, UCHAR, Boolean)
#endif
#ifdef CASE_REAL_INT64
CASE(UInt64, epics::pvData::uint64, UINT64, ULong)
CASE(Int64, epics::pvData::int64, INT64, Long)
#elif defined(CASE_SQUEEZE_INT64)
CASE(UInt32, epics::pvData::uint64, ULONG, ULong)
CASE(Int32, epics::pvData::int64, LONG, Long)
#else
/* nothing */
#endif
#ifdef CASE_ENUM
// yes really, Base uses SHORT (16-bit) while PVD uses Int (32-bit)
CASE(Enum16, epics::pvData::int32, ENUM, Int)
#endif
/* #undef CASE */

View File

@ -12,11 +12,14 @@
#include <errlog.h>
#include <initHooks.h>
#include <alarm.h>
#include <epicsAtomic.h>
#include <epicsThreadPool.h>
#include <pv/pvAccess.h>
#include <pv/clientFactory.h>
#include "helper.h"
#include "iocshelper.h"
#include "pvif.h"
namespace pvd = epics::pvData;
@ -27,6 +30,7 @@ extern "C" void (*dbAddLinkHook)(struct link *link, short dbfType);
namespace {
typedef epicsGuard<pvd::Mutex> Guard;
typedef epicsGuardRelease<pvd::Mutex> UnGuard;
struct pvaLink;
struct pvaLinkChannel;
@ -39,6 +43,16 @@ struct pvaGlobal_t {
pvd::Mutex lock;
struct Scan {
// the PVA channel which triggered this scan
std::tr1::weak_ptr<pvaLinkChannel> chan;
bool usecached;
Scan() :usecached(false) {}
};
epicsThreadPrivate<Scan> scanmagic;
epicsThreadPool *scanpool;
typedef std::map<std::string, std::tr1::shared_ptr<pvaLinkChannel> > channels_t;
channels_t channels;
@ -52,6 +66,18 @@ struct pvaGlobal_t {
{
if(!provider)
throw std::runtime_error("No pva provider");
epicsThreadPoolConfig conf;
epicsThreadPoolConfigDefaults(&conf);
conf.workerPriority = epicsThreadPriorityLow+10; // similar to once thread
conf.initialThreads = 1;
scanpool = epicsThreadPoolCreate(&conf);
if(!scanpool)
throw std::runtime_error("Failed to create pvaLink scan pool");
}
~pvaGlobal_t()
{
provider->destroy();
epicsThreadPoolDestroy(scanpool);
}
} *pvaGlobal;
@ -60,6 +86,8 @@ struct pvaLinkChannel : public pva::ChannelRequester, pva::MonitorRequester,
{
const std::string name;
static size_t refs;
typedef std::set<pvaLink*> links_t;
links_t links;
@ -71,13 +99,28 @@ struct pvaLinkChannel : public pva::ChannelRequester, pva::MonitorRequester,
//pva::ChannelPut::shared_pointer chanput;
pvd::PVStructurePtr lastval;
pvd::PVScalarPtr isatomic;
epicsJob *scanjob;
std::tr1::shared_ptr<pvaLinkChannel> scanself; // create ref loop while scan is queued
bool scanatomic;
pvaLinkChannel(const char *name)
:name(name)
{}
,scanjob(epicsJobCreate(pvaGlobal->scanpool, &pvaLinkChannel::scan, this))
,scanatomic(false)
{
if(!scanjob)
throw std::runtime_error("failed to create job for pvaLink");
epics::atomic::increment(refs);
}
virtual ~pvaLinkChannel() {
channelStateChange(chan, pva::Channel::DESTROYED);
if(chan) chan->destroy();
Guard G(lock);
assert(links.empty());
epicsJobDestroy(scanjob);
scanjob = NULL;
epics::atomic::decrement(refs);
std::cerr<<"pvaLinkChannel: destroy "<<name<<"\n";
}
void doConnect() {
@ -86,9 +129,15 @@ struct pvaLinkChannel : public pva::ChannelRequester, pva::MonitorRequester,
}
void doClose() {
Guard G(lock);
errlogPrintf("pvaLink closing %s\n", name.c_str());
channelStateChange(chan, pva::Channel::DESTROYED);
chan->destroy();
chan.reset();
std::cerr<<"pvaLink: channel destroy "<<name<<"\n";
}
static void scan(void* arg, epicsJobMode mode);
virtual std::string getRequesterName() { return "pvaLink"; }
virtual void message(std::string const & message, pva::MessageType messageType)
{
@ -153,17 +202,33 @@ std::tr1::shared_ptr<pvaLinkChannel> pvaGlobal_t::connect(const char *name)
struct pvaLink
{
static size_t refs;
link * const plink;
const short dbf;
std::string name, field;
const pva::Channel::shared_pointer chan;
bool alive;
bool alive; // attempt to catch some use after free
std::tr1::shared_ptr<pvaLinkChannel> lchan;
pvd::PVScalarPtr valueS;
pvd::PVScalarArray::shared_pointer valueA;
pvd::PVScalar::shared_pointer sevr, sec, nsec;
pvd::ScalarType etype;
struct Value {
bool valid;
bool scalar;
pvd::ScalarType etype;
pvd::shared_vector<const void> valueA;
dbrbuf valueS;
epicsUInt16 sevr;
epicsTimeStamp time;
Value() :valid(false) {}
};
Value atomcache;
pvaLink(link *L, const char *name, short f)
:plink(L)
@ -181,6 +246,7 @@ struct pvaLink
lchan->links.insert(this);
if(lchan->lastval)
attach();
epics::atomic::increment(refs);
}
~pvaLink()
{
@ -192,6 +258,7 @@ struct pvaLink
pvaGlobal->channels.erase(lchan->name);
lchan->doClose();
}
epics::atomic::decrement(refs);
}
void detach()
@ -206,6 +273,7 @@ struct pvaLink
bool attach()
{
pvd::PVStructurePtr base(lchan->lastval);
if(!field.empty())
base = base->getSubField<pvd::PVStructure>(field);
if(!base) {
@ -218,9 +286,11 @@ struct pvaLink
{
case pvd::scalar:
valueS = std::tr1::static_pointer_cast<pvd::PVScalar>(value);
etype = valueS->getScalar()->getScalarType();
break;
case pvd::scalarArray:
valueA = std::tr1::static_pointer_cast<pvd::PVScalarArray>(value);
etype = valueA->getScalarArray()->getElementType();
break;
default:
errlogPrintf("pvaLink not .value : %s%c%s\n", name.c_str(), field.empty() ? ' ' : '.', field.c_str());
@ -232,8 +302,45 @@ struct pvaLink
nsec = base->getSubField<pvd::PVScalar>("timeStamp.nanoseconds");
return true;
}
void get(Value& v)
{
if(valueA) {
valueA->getAs<const void>(v.valueA);
v.etype = v.valueA.original_type();
v.scalar = false;
} else if(valueS) {
switch(etype) {
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pvd::pv ## PVACODE: v.valueS.dbf_##DBFTYPE = valueS->getAs<PVATYPE>(); break;
#define CASE_SQUEEZE_INT64
#include "pvatypemap.h"
#undef CASE_SQUEEZE_INT64
#undef CASE
case pvd::pvString: {
strncpy(v.valueS.dbf_STRING, valueS->getAs<std::string>().c_str(), sizeof(v.valueS.dbf_STRING));
v.valueS.dbf_STRING[sizeof(v.valueS.dbf_STRING)-1] = '\0';
}
break;
default:
throw std::runtime_error("putValue unsupported DBR code");
}
v.etype = etype;
v.scalar = true;
}
v.sevr = sevr->getAs<epicsUInt16>();
v.time.secPastEpoch = sec->getAs<epicsUInt32>()-POSIX_TIME_AT_EPICS_EPOCH;
v.time.nsec = nsec->getAs<epicsUInt32>();
v.valid = true;
}
};
size_t pvaLinkChannel::refs;
size_t pvaLink::refs;
void pvaLinkChannel::channelStateChange(pva::Channel::shared_pointer const & channel, pva::Channel::ConnectionState connectionState)
{
Guard G(lock);
@ -251,10 +358,12 @@ void pvaLinkChannel::channelStateChange(pva::Channel::shared_pointer const & cha
L->detach();
}
lastval.reset();
isatomic.reset();
if(chanmon) {
chanmon->destroy();
chanmon.reset();
std::cerr<<"pvaLink: monitor destroy "<<name<<"\n";
}
}
}
@ -270,6 +379,7 @@ void pvaLinkChannel::monitorConnect(pvd::Status const & status,
Guard G(lock);
lastval = pvaGlobal->create->createPVStructure(structure);
isatomic = lastval->getSubField<pvd::PVScalar>("record._options.atomic");
chanmon = monitor;
pvd::Status sstatus = monitor->start();
@ -287,13 +397,16 @@ void pvaLinkChannel::monitorConnect(pvd::Status const & status,
void pvaLinkChannel::monitorEvent(pva::Monitor::shared_pointer const & monitor)
{
Guard G(lock);
if(!lastval) return;
pva::MonitorElementPtr elem;
bool updated = false;
bool atomic = false;
while(!!(elem=monitor->poll())) {
try{
lastval->copyUnchecked(*elem->pvStructurePtr, *elem->changedBitSet);
atomic = isatomic->getAs<pvd::boolean>();
updated = true;
monitor->release(elem);
@ -303,8 +416,9 @@ void pvaLinkChannel::monitorEvent(pva::Monitor::shared_pointer const & monitor)
}
}
bool doscan = false;
if(updated) {
// std::cout<<"Update "<<lastval<<"\n";
// check if we actually need to scan anything
FOREACH(it, end, links) {
pvaLink* L = *it;
struct pv_link *ppv_link = &L->plink->value.pv_link;
@ -312,13 +426,85 @@ void pvaLinkChannel::monitorEvent(pva::Monitor::shared_pointer const & monitor)
if ((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && L->plink->precord->scan == 0))
{
// TODO: overflow once queue
scanOnce(L->plink->precord);
doscan = true;
}
}
}
if(doscan && !scanself) { // need to scan, and not already queued, then queue
std::cerr<<"pvaLink: queue scan from "<<name<<"\n";
if(epicsJobQueue(scanjob)) {
errlogPrintf("pvaLink: failed to queue scan from %s\n", name.c_str());
} else {
scanself = shared_from_this();
scanatomic = atomic;
}
}
}
void pvaLinkChannel::scan(void* arg, epicsJobMode mode)
{
pvaLinkChannel *selfraw = (pvaLinkChannel*)arg;
pvaGlobal_t::Scan myscan;
try {
std::tr1::shared_ptr<pvaLinkChannel> self;
Guard G(selfraw->lock);
selfraw->scanself.swap(self); // we take over ref, to keep channel alive, and allow re-queue
if(mode==epicsJobModeCleanup) return;
myscan.chan = self; // store a weak ref
links_t links(self->links); // TODO: avoid copy if set not changing
bool usecached = self->scanatomic;
myscan.usecached = usecached;
if(usecached) {
FOREACH(it, end, links) {
pvaLink *link = *it;
link->get(link->atomcache);
}
}
pvaGlobal->scanmagic.set(usecached ? &myscan : NULL);
std::cerr<<"pvaLink: scan from "<<self->name<<" "<<(usecached?" use cached":"")<<"\n";
{
UnGuard U(G);
// we may scan a record after the originating link is re-targeted
FOREACH(it, end, links) {
pvaLink *link = *it;
struct pv_link *ppv_link = &link->plink->value.pv_link;
dbCommon *prec=link->plink->precord;
if ((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && link->plink->precord->scan == 0))
{
DBScanLocker L(prec);
dbProcess(prec);
}
}
}
// another scan may be queued by this point
if(usecached) {
FOREACH(it, end, links) {
pvaLink *link = *it;
link->atomcache.valid = false;
}
}
}catch(std::exception& e){
errlogPrintf("%s: pvaLink exception while processing: %s\n", selfraw->name.c_str(), e.what());
// what to do?
}
pvaGlobal->scanmagic.set(NULL);
}
#define TRY pvaLink *self = (pvaLink*)plink->value.pv_link.pvt; assert(self->alive); try
#define CATCH(LOC) catch(std::exception& e) { \
errlogPrintf("pvaLink " #LOC " fails %s: %s\n", plink->precord->name, e.what()); \
@ -370,6 +556,8 @@ void pvaRemoveLink(struct dbLocker *locker, struct link *plink)
int pvaIsConnected(const struct link *plink)
{
TRY {
if(pvaGlobal->scanmagic.get()) return 1;
Guard G(self->lchan->lock);
return !!self->lchan->chanmon && (self->valueS || self->valueA);
@ -381,6 +569,8 @@ int pvaIsConnected(const struct link *plink)
int pvaGetDBFtype(const struct link *plink)
{
TRY {
if(pvaGlobal->scanmagic.get()) return PVD2DBR(self->atomcache.etype);
Guard G(self->lchan->lock);
pvd::ScalarType ftype;
if(self->valueS)
@ -390,21 +580,12 @@ int pvaGetDBFtype(const struct link *plink)
else
return DBF_LONG;
switch(ftype) {
#define MAP(DTYPE, PTYPE) case pvd::pv##PTYPE: return DBF_##DTYPE;
MAP(CHAR, Byte);
MAP(UCHAR, UByte);
MAP(UCHAR, Boolean);
MAP(SHORT, Short);
MAP(USHORT, UShort);
//MAP(ENUM, Int); // yes really, Base uses SHORT (16-bit) while PVD uses Int (32-bit)
MAP(LONG, Int);
MAP(ULONG, UInt);
MAP(LONG, Long); // truncation
MAP(ULONG, ULong);// truncation
MAP(FLOAT, Float);
MAP(DOUBLE, Double);
MAP(STRING, String);
#undef MAP
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pvd::pv##PVACODE: return DBF_##DBFTYPE;
#define CASE_SQUEEZE_INT64
#include "pvatypemap.h"
#undef CASE_SQUEEZE_INT64
#undef CASE
case pvd::pvString: return DBF_STRING; // TODO: long string?
}
}CATCH(pvaIsConnected)
@ -414,6 +595,11 @@ int pvaGetDBFtype(const struct link *plink)
long pvaGetElements(const struct link *plink, long *nelements)
{
TRY {
if(pvaGlobal->scanmagic.get()) {
if(self->atomcache.scalar) return 1;
else return self->atomcache.valueA.size();
}
Guard G(self->lchan->lock);
if(self->valueA)
return self->valueA->getLength();
@ -427,9 +613,24 @@ long pvaGetValue(struct link *plink, short dbrType, void *pbuffer,
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
{
TRY {
if(pvaGlobal->scanmagic.get()) {
const void *buf;
size_t count = pnRequest ? *pnRequest : 0;
if(self->atomcache.scalar) {
buf = (void*)&self->atomcache.valueS;
count = std::min((size_t)1u, count);
} else {
buf = self->atomcache.valueA.data();
count = std::min(self->atomcache.valueA.size(), count);
}
pvd::castUnsafeV(count, DBR2PVD(dbrType), pbuffer, self->atomcache.etype, buf);
*psevr = self->atomcache.sevr;
*pstat = *psevr ? LINK_ALARM : 0;
}
Guard G(self->lchan->lock);
if(self->valueA) {
//pvd::ScalarType ftype = DBR2PVD(dbrType);
pvd::shared_vector<const void> arrval;
self->valueA->getAs<const void>(arrval);
@ -437,20 +638,17 @@ long pvaGetValue(struct link *plink, short dbrType, void *pbuffer,
pvd::castUnsafeV(nelem, DBR2PVD(dbrType), pbuffer, arrval.original_type(), arrval.data());
*psevr = self->sevr->getAs<epicsUInt16>();
} else if(self->valueS) {
switch(dbrType) {
#define CASE(FTYPE, CTYPE) case DBR_##FTYPE: *((CTYPE*)pbuffer) = self->valueS->getAs<CTYPE>(); break
CASE(CHAR, epicsInt8);
CASE(UCHAR, epicsUInt8);
CASE(SHORT, epicsInt16);
CASE(USHORT, epicsUInt16);
CASE(ENUM, epicsEnum16);
CASE(LONG, epicsInt32);
CASE(ULONG, epicsUInt32);
CASE(FLOAT, epicsFloat32);
CASE(DOUBLE, epicsFloat64);
#undef CASE
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: *((epics##BASETYPE*)pbuffer) = self->valueS->getAs<epics##BASETYPE>(); break;
#define CASE_SKIP_BOOL
#define CASE_ENUM
#include "pvatypemap.h"
#undef CASE_SKIP_BOOL
#undef CASE_ENUM
#undef CASE
case DBR_STRING: {
char *cbuf = (char*)pbuffer;
strncpy(cbuf, self->valueS->getAs<std::string>().c_str(), MAX_STRING_SIZE);
@ -460,7 +658,12 @@ long pvaGetValue(struct link *plink, short dbrType, void *pbuffer,
default:
throw std::runtime_error("putValue unsupported DBR code");
}
*psevr = self->sevr->getAs<epicsUInt16>();
} else {
*psevr = INVALID_ALARM;
}
*pstat = *psevr ? LINK_ALARM : 0;
return 0;
}CATCH(pvaIsConnected)
return S_dbLib_badLink;
@ -469,7 +672,7 @@ long pvaGetValue(struct link *plink, short dbrType, void *pbuffer,
long pvaGetControlLimits(const struct link *plink, double *lo, double *hi)
{
TRY {
Guard G(self->lchan->lock);
//Guard G(self->lchan->lock);
*lo = *hi = 0.0;
}CATCH(pvaIsConnected)
return 0;
@ -478,7 +681,7 @@ long pvaGetControlLimits(const struct link *plink, double *lo, double *hi)
long pvaGetGraphicLimits(const struct link *plink, double *lo, double *hi)
{
TRY {
Guard G(self->lchan->lock);
//Guard G(self->lchan->lock);
*lo = *hi = 0.0;
}CATCH(pvaIsConnected)
return 0;
@ -488,7 +691,7 @@ long pvaGetAlarmLimits(const struct link *plink, double *lolo, double *lo,
double *hi, double *hihi)
{
TRY {
Guard G(self->lchan->lock);
//Guard G(self->lchan->lock);
*lolo = *lo = *hi = *hihi = 0.0;
}CATCH(pvaIsConnected)
return 0;
@ -497,7 +700,7 @@ long pvaGetAlarmLimits(const struct link *plink, double *lolo, double *lo,
long pvaGetPrecision(const struct link *plink, short *precision)
{
TRY {
Guard G(self->lchan->lock);
//Guard G(self->lchan->lock);
*precision = 0;
}CATCH(pvaIsConnected)
return 0;
@ -506,7 +709,7 @@ long pvaGetPrecision(const struct link *plink, short *precision)
long pvaGetUnits(const struct link *plink, char *units, int unitsSize)
{
TRY {
Guard G(self->lchan->lock);
//Guard G(self->lchan->lock);
}CATCH(pvaIsConnected)
return 0;
}
@ -516,9 +719,12 @@ long pvaGetAlarm(const struct link *plink, epicsEnum16 *status,
{
TRY {
Guard G(self->lchan->lock);
unsigned sevr = 0;
if(self->sevr)
unsigned sevr = INVALID_ALARM;
if(pvaGlobal->scanmagic.get()) {
sevr = self->atomcache.sevr;
} else if(self->sevr) {
sevr = self->sevr->getAs<epicsInt32>();
}
if(sevr)
*status = LINK_ALARM;
*severity = std::max(0u, std::min(sevr, 3u));
@ -530,7 +736,9 @@ long pvaGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
{
TRY {
Guard G(self->lchan->lock);
if(self->sec && self->nsec) {
if(pvaGlobal->scanmagic.get()) {
*pstamp = self->atomcache.time;
} else if(self->sec && self->nsec) {
pstamp->secPastEpoch = self->sec->getAs<epicsUInt32>()-POSIX_TIME_AT_EPICS_EPOCH;
pstamp->nsec = self->sec->getAs<epicsUInt32>();
} else {
@ -633,9 +841,24 @@ void initPVALink(initHookState state)
std::cout<<"cleanupPVALink\n";
dbAddLinkHook = nextAddLinkHook;
{
Guard G(pvaGlobal->lock);
if(pvaGlobal->channels.size()) {
std::cerr<<"pvaLink still has "<<pvaGlobal->channels.size()
<<"active channels after doCloseLinks()\n";
}
}
delete pvaGlobal;
pvaGlobal = NULL;
if(epics::atomic::get(pvaLink::refs)) {
std::cerr<<"pvaLink leaking "<<epics::atomic::get(pvaLink::refs)<<" links\n";
}
if(epics::atomic::get(pvaLinkChannel::refs)) {
std::cerr<<"pvaLink leaking "<<epics::atomic::get(pvaLinkChannel::refs)<<" channels\n";
}
}catch(std::exception& e){
errlogPrintf("Error initializing pva link handling : %s\n", e.what());
}
@ -643,11 +866,23 @@ void initPVALink(initHookState state)
}
}
} // namespace
void pvalr(int level)
{
try {
std::cout<<"pvaLink count "<<epics::atomic::get(pvaLink::refs)<<"\n"
"pvaLinkChannel count "<<epics::atomic::get(pvaLinkChannel::refs)<<"\n";
}catch(std::exception& e){
std::cerr<<"Error :"<<e.what()<<"\n";
}
}
static
void installPVAAddLinkHook()
{
initHookRegister(&initPVALink);
iocshRegister<int, &pvalr>("pvalr", "level");
}
} // namespace
epicsExportRegistrar(installPVAAddLinkHook);

View File

@ -212,19 +212,6 @@ void putTime(const pvCommon& pv, unsigned dbe, db_field_log *pfl)
}
}
union dbrbuf {
epicsInt8 dbf_CHAR;
epicsUInt8 dbf_UCHAR;
epicsInt16 dbf_SHORT;
epicsUInt16 dbf_USHORT;
epicsEnum16 dbf_ENUM;
epicsInt32 dbf_LONG;
epicsUInt32 dbf_ULONG;
epicsFloat32 dbf_FLOAT;
epicsFloat64 dbf_DOUBLE;
char dbf_STRING[MAX_STRING_SIZE];
};
void putValue(const pvScalar& pv, unsigned dbe, db_field_log *pfl)
{
dbrbuf buf;
@ -449,23 +436,32 @@ struct PVIFScalarNumeric : public PVIF
pvd::ScalarType DBR2PVD(short dbr)
{
switch(dbr) {
#define MAP(DTYPE, PTYPE) case DBR_##DTYPE: return pvd::pv##PTYPE
MAP(CHAR, Byte);
MAP(UCHAR, UByte);
MAP(SHORT, Short);
MAP(USHORT, UShort);
MAP(ENUM, Int); // yes really, Base uses SHORT (16-bit) while PVD uses Int (32-bit)
MAP(LONG, Int);
MAP(ULONG, UInt);
MAP(FLOAT, Float);
MAP(DOUBLE, Double);
MAP(STRING, String);
#undef MAP
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: return pvd::pv##PVACODE;
#define CASE_ENUM
#define CASE_SKIP_BOOL
#include "pvatypemap.h"
#undef CASE_ENUM
#undef CASE_SKIP_BOOL
#undef CASE
case DBF_STRING: return pvd::pvString;
default:
throw std::invalid_argument("Unsupported DBR code");
}
}
short PVD2DBR(pvd::ScalarType pvt)
{
switch(pvt) {
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pvd::pv##PVACODE: return DBR_##DBFTYPE;
#define CASE_SQUEEZE_INT64
#include "pvatypemap.h"
#undef CASE_SQUEEZE_INT64
#undef CASE
default:
throw std::invalid_argument("Unsupported pvType code");
}
}
void PVIF::Init()
{
}

View File

@ -13,6 +13,20 @@
#include <pv/pvData.h>
epics::pvData::ScalarType DBR2PVD(short dbr);
short PVD2DBR(epics::pvData::ScalarType pvt);
union dbrbuf {
epicsInt8 dbf_CHAR;
epicsUInt8 dbf_UCHAR;
epicsInt16 dbf_SHORT;
epicsUInt16 dbf_USHORT;
epicsEnum16 dbf_ENUM;
epicsInt32 dbf_LONG;
epicsUInt32 dbf_ULONG;
epicsFloat32 dbf_FLOAT;
epicsFloat64 dbf_DOUBLE;
char dbf_STRING[MAX_STRING_SIZE];
};
struct DBCH {
dbChannel *chan;
@ -167,7 +181,12 @@ struct DBManyLock
{
dbLocker *plock;
DBManyLock() :plock(NULL) {}
DBManyLock(dbCommon **precs, size_t nrecs, unsigned flags=0)
DBManyLock(const std::vector<dbCommon*>& recs, unsigned flags)
:plock(dbLockerAlloc(&recs[0], recs.size(), flags))
{
if(!plock) throw std::invalid_argument("Failed to create locker");
}
DBManyLock(dbCommon * const *precs, size_t nrecs, unsigned flags=0)
:plock(dbLockerAlloc(precs, nrecs, flags))
{
if(!plock) throw std::invalid_argument("Failed to create locker");
@ -175,6 +194,9 @@ struct DBManyLock
~DBManyLock() { if(plock) dbLockerFree(plock); }
void swap(DBManyLock& O) { std::swap(plock, O.plock); }
operator dbLocker*() { return plock; }
private:
DBManyLock(const DBManyLock&);
DBManyLock& operator=(const DBManyLock&);
};
struct DBManyLocker