Merged Michael's dbcadynamic branch

This commit is contained in:
Andrew Johnson
2016-02-12 10:22:47 -06:00
5 changed files with 79 additions and 57 deletions

View File

@@ -346,15 +346,15 @@ long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
assert(pca->pgetNative);
status = fConvert(pca->pgetNative, pdest, 0);
} else {
long ntoget = *nelements;
unsigned long ntoget = *nelements;
struct dbAddr dbAddr;
long (*aConvert)(struct dbAddr *paddr, void *to, long nreq, long nto, long off);
aConvert = dbGetConvertRoutine[newType][dbrType];
assert(pca->pgetNative);
if (ntoget > pca->nelements)
ntoget = pca->nelements;
if (ntoget > pca->usedelements)
ntoget = pca->usedelements;
*nelements = ntoget;
memset((void *)&dbAddr, 0, sizeof(dbAddr));
@@ -409,6 +409,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
if (!pca->pputNative) {
pca->pputNative = dbCalloc(pca->nelements,
dbr_value_size[ca_field_type(pca->chid)]);
pca->putnelements = 0;
/* Fixed and disabled by ANJ, see comment above.
plink->value.pv_link.pvlMask |= pvlOptOutNative;
*/
@@ -418,6 +419,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
fConvert = dbFastPutConvertRoutine[dbrType][newType];
status = fConvert(pbuffer, pca->pputNative, 0);
pca->putnelements = 1;
} else {
struct dbAddr dbAddr;
long (*aConvert)(struct dbAddr *paddr, const void *from, long nreq, long nfrom, long off);
@@ -430,10 +432,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
if(nRequest>pca->nelements)
nRequest = pca->nelements;
status = aConvert(&dbAddr, pbuffer, nRequest, pca->nelements, 0);
if(nRequest<pca->nelements) {
long elemsize = dbr_value_size[ca_field_type(pca->chid)];
memset(nRequest*elemsize+(char*)pca->pputNative, 0, (pca->nelements-nRequest)*elemsize);
}
pca->putnelements = nRequest;
}
link_action |= CA_WRITE_NATIVE;
pca->gotOutNative = TRUE;
@@ -705,6 +704,7 @@ static void connectionCallback(struct connection_handler_args arg)
}
pca->gotFirstConnection = TRUE;
pca->nelements = ca_element_count(arg.chid);
pca->usedelements = 0;
pca->dbrType = ca_field_type(arg.chid);
if ((plink->value.pv_link.pvlMask & pvlOptInpNative) && !pca->pgetNative) {
link_action |= CA_MONITOR_NATIVE;
@@ -757,6 +757,7 @@ static void eventCallback(struct event_handler_args arg)
goto done;
}
assert(arg.dbr);
assert(arg.count<=pca->nelements);
size = arg.count * dbr_value_size[arg.type];
if (arg.type == DBR_TIME_STRING &&
ca_field_type(pca->chid) == DBR_ENUM) {
@@ -773,6 +774,7 @@ static void eventCallback(struct event_handler_args arg)
case DBR_TIME_DOUBLE:
assert(pca->pgetNative);
memcpy(pca->pgetNative, dbr_value_ptr(arg.dbr, arg.type), size);
pca->usedelements = arg.count;
pca->gotInNative = TRUE;
break;
default:
@@ -978,11 +980,11 @@ static void dbCaTask(void *arg)
assert(pca->pputNative);
if (pca->putType == CA_PUT) {
status = ca_array_put(
pca->dbrType, pca->nelements,
pca->dbrType, pca->putnelements,
pca->chid, pca->pputNative);
} else if (pca->putType==CA_PUT_CALLBACK) {
status = ca_array_put_callback(
pca->dbrType, pca->nelements,
pca->dbrType, pca->putnelements,
pca->chid, pca->pputNative,
putComplete, pca);
} else {
@@ -1032,15 +1034,15 @@ static void dbCaTask(void *arg)
}
}
if (link_action & CA_MONITOR_NATIVE) {
size_t element_size;
element_size = dbr_value_size[ca_field_type(pca->chid)];
epicsMutexMustLock(pca->lock);
pca->pgetNative = dbCalloc(pca->nelements, element_size);
pca->elementSize = dbr_value_size[ca_field_type(pca->chid)];
pca->pgetNative = dbCalloc(pca->nelements, pca->elementSize);
epicsMutexUnlock(pca->lock);
status = ca_add_array_event(
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
ca_element_count(pca->chid),
0, /* dynamic size */
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
if (status != ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",

View File

@@ -35,7 +35,7 @@
/* write type */
#define CA_PUT 0x1
#define CA_PUT_CALLBACK 0x2
typedef struct caLink
{
ELLNODE node;
@@ -51,7 +51,10 @@ typedef struct caLink
epicsTimeStamp timeStamp;
/* The following have values after connection*/
short dbrType;
long nelements;
size_t elementSize; /* size of one element in pgetNative */
unsigned long nelements; /* PVs max array size */
unsigned long usedelements; /* currently used in pgetNative */
unsigned long putnelements; /* currently used in pputNative */
char hasReadAccess;
char hasWriteAccess;
char isConnected;

View File

@@ -154,7 +154,8 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
const struct db_field_log * pfl,
cacStateNotify & notifyIn )
{
unsigned long size = dbr_size_n ( type, count );
long realcount = (count==0)?dbChannelElements(dbch):count;
unsigned long size = dbr_size_n ( type, realcount );
if ( type > INT_MAX ) {
epicsGuard < epicsMutex > guard ( this->mutex );
@@ -181,8 +182,13 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
this->stateNotifyCacheSize = size;
}
void *pvfl = (void *) pfl;
int status = dbChannel_get ( dbch, static_cast <int> ( type ),
this->pStateNotifyCache, static_cast <int> ( count ), pvfl );
int status;
if(count==0) /* fetch actual number of elements (dynamic array) */
status = dbChannel_get_count( dbch, static_cast <int> ( type ),
this->pStateNotifyCache, &realcount, pvfl );
else /* fetch requested number of elements, truncated or zero padded */
status = dbChannel_get( dbch, static_cast <int> ( type ),
this->pStateNotifyCache, realcount, pvfl );
if ( status ) {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.exception ( guard, ECA_GETFAIL,
@@ -190,7 +196,7 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
}
else {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.current ( guard, type, count, this->pStateNotifyCache );
notifyIn.current ( guard, type, realcount, this->pStateNotifyCache );
}
}

View File

@@ -61,27 +61,32 @@ void dbContextReadNotifyCache::callReadNotify (
return;
}
if ( dbChannelElements(dbch) < 0 ) {
const long maxcount = dbChannelElements(dbch);
if ( maxcount < 0 ) {
notify.exception ( guard, ECA_BADCOUNT,
"database has negetive element count",
type, count);
return;
}
if ( count > static_cast < unsigned long > ( dbChannelElements(dbch) ) ) {
} else if ( count > (unsigned long)maxcount ) {
notify.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
}
unsigned long size = dbr_size_n ( type, count );
long realcount = (count==0)?maxcount:count;
unsigned long size = dbr_size_n ( type, realcount );
privateAutoDestroyPtr ptr ( _allocator, size );
int status;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
status = dbChannel_get ( dbch, static_cast <int> ( type ),
ptr.get (), static_cast <long> ( count ), 0 );
if ( count==0 )
status = dbChannel_get_count ( dbch, (int)type, ptr.get(), &realcount, 0);
else
status = dbChannel_get ( dbch, (int)type, ptr.get (), realcount, 0 );
}
if ( status ) {
notify.exception ( guard, ECA_GETFAIL,
@@ -90,7 +95,7 @@ void dbContextReadNotifyCache::callReadNotify (
}
else {
notify.completion (
guard, type, count, ptr.get () );
guard, type, realcount, ptr.get () );
}
}

View File

@@ -16,6 +16,7 @@
#include "epicsString.h"
#include "dbUnitTest.h"
#include "epicsThread.h"
#include "cantProceed.h"
#include "epicsEvent.h"
#include "iocInit.h"
#include "dbBase.h"
@@ -301,7 +302,7 @@ static void fillArrayDouble(double *buf, unsigned count, double first)
static void checkArray(const char *msg,
epicsInt32 *buf, epicsInt32 first,
unsigned used, unsigned total)
unsigned used)
{
int match = 1;
unsigned i;
@@ -309,22 +310,17 @@ static void checkArray(const char *msg,
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
match &= (*b)==x;
for(;i<total;i++,x++,b++)
match &= (*b)==0;
testOk(match, "%s", msg);
if(!match) {
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
if((*b)!=x)
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
for(;i<total;i++,x++,b++)
if((*b)!=0)
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
}
}
static void checkArrayDouble(const char *msg,
double *buf, double first,
unsigned used, unsigned total)
unsigned used)
{
int match = 1;
unsigned i;
@@ -332,16 +328,11 @@ static void checkArrayDouble(const char *msg,
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
match &= (*b)==x;
for(;i<total;i++,x++,b++)
match &= (*b)==0;
testOk(match, "%s", msg);
if(!match) {
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
if((*b)!=x)
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
for(;i<total;i++,x++,b++)
if((*b)!=0)
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
}
}
@@ -362,12 +353,13 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
char buf[100];
arrRecord *psrc, *ptarg;
DBLINK *psrclnk;
epicsInt32 *bufsrc, *buftarg;
epicsInt32 *bufsrc, *buftarg, *tmpbuf;
long nReq;
unsigned num;
unsigned num_min, num_max;
testDiag("Link to a array numeric field");
/* source.INP = "target CA" */
epicsSnprintf(buf, sizeof(buf), "TARGET=target CA,FTVL=LONG,SNELM=%u,TNELM=%u",
nsrc, ntarg);
testDiag("%s", buf);
@@ -391,9 +383,15 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
bufsrc = psrc->bptr;
buftarg= ptarg->bptr;
num=psrc->nelm;
if(num>ptarg->nelm)
num=ptarg->nelm;
num_max=num_min=psrc->nelm;
if(num_min>ptarg->nelm)
num_min=ptarg->nelm;
if(num_max<ptarg->nelm)
num_max=ptarg->nelm;
/* always request more than can possibly be filled */
num_max += 2;
tmpbuf = callocMustSucceed(num_max, sizeof(*tmpbuf), "tmpbuf");
startWait(psrclnk);
@@ -406,11 +404,22 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
waitForUpdate(psrclnk);
dbScanLock((dbCommon*)psrc);
testDiag("fetch source.INP into source.BPTR");
nReq = psrc->nelm;
if(dbGetLink(psrclnk, DBR_LONG, bufsrc, NULL, &nReq)==0) {
testPass("dbGetLink");
testOp("%ld",nReq,==,(long)num);
checkArray("array update", bufsrc, 1, nReq, psrc->nelm);
testOp("%ld",nReq,==,(long)num_min);
checkArray("array update", bufsrc, 1, nReq);
} else {
testFail("dbGetLink");
testSkip(2, "dbGetLink fails");
}
testDiag("fetch source.INP into temp buffer w/ larger capacity");
nReq = num_max;
if(dbGetLink(psrclnk, DBR_LONG, tmpbuf, NULL, &nReq)==0) {
testPass("dbGetLink");
testOp("%ld",nReq,==,(long)ntarg);
checkArray("array update", tmpbuf, 1, nReq);
} else {
testFail("dbGetLink");
testSkip(2, "dbGetLink fails");
@@ -422,12 +431,8 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
putLink(psrclnk, DBR_LONG, bufsrc, psrc->nelm);
dbScanLock((dbCommon*)ptarg);
/* CA links always write the full target array length */
testOp("%ld",(long)ptarg->nord,==,(long)ptarg->nelm);
/* However, if the source length is less, then the target
* is zero filled
*/
checkArray("array update", buftarg, 2, num, ptarg->nelm);
testOp("%ld",(long)ptarg->nord,==,(long)num_min);
dbScanUnlock((dbCommon*)ptarg);
/* write again to ensure that buffer is completely updated */
@@ -436,14 +441,15 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
putLink(psrclnk, DBR_LONG, bufsrc, psrc->nelm);
dbScanLock((dbCommon*)ptarg);
testOp("%ld",(long)ptarg->nord,==,(long)ptarg->nelm);
checkArray("array update", buftarg, 3, num, ptarg->nelm);
testOp("%ld",(long)ptarg->nord,==,(long)num_min);
checkArray("array update", buftarg, 3, num_min);
dbScanUnlock((dbCommon*)ptarg);
testIocShutdownOk();
testdbCleanup();
free(tmpbuf);
/* records don't cleanup after themselves
* so do here to silence valgrind
*/
@@ -522,7 +528,7 @@ static void testreTargetTypeChange(void)
dbScanLock((dbCommon*)psrc);
testOp("%ld",(long)psrc->nord,==,(long)5);
checkArrayDouble("array update", bufsrc, 1, 5, psrc->nelm);
checkArrayDouble("array update", bufsrc, 1, 5);
dbScanUnlock((dbCommon*)psrc);
testDiag("Retarget");
@@ -532,7 +538,7 @@ static void testreTargetTypeChange(void)
dbScanLock((dbCommon*)psrc);
testOp("%ld",(long)psrc->nord,==,(long)5);
checkArrayDouble("array update", bufsrc, 2, 5, psrc->nelm);
checkArrayDouble("array update", bufsrc, 2, 5);
dbScanUnlock((dbCommon*)psrc);
testIocShutdownOk();
@@ -592,7 +598,7 @@ static void testCAC(void)
MAIN(dbCaLinkTest)
{
testPlan(91);
testPlan(99);
testNativeLink();
testStringLink();
testCP();