Merge remote-tracking branch 'addr2entry/master'

* addr2entry/master:
  ioc/db/test: dbStaticTest dbInitEntryFromAddr() works before iocInit()
  ioc/db/test: dbStaticTest test operations on aliases
  ioc: rename dbCommonPvt::recnode
  ioc/dbStatic: better alias tracking
  ioc/dbStatic: add dbInitEntryFromRecord()
  ioc: populate RDES early
  rename dbInitEntryFromChannel -> dbInitEntryFromAddr
  ioc/db: Add dbCommonPvt
  ioc/dbStatic: add dbInitEntryFromChannel()
  ioc/dbStatic: dbAllocRecord whitespace
This commit is contained in:
Michael Davidsaver
2017-05-03 17:07:07 -04:00
11 changed files with 326 additions and 72 deletions

View File

@@ -42,7 +42,7 @@
#include "dbBase.h"
#include "dbBkpt.h"
#include "dbCa.h"
#include "dbCommon.h"
#include "dbCommonPvt.h"
#include "dbConvertFast.h"
#include "dbConvert.h"
#include "dbEvent.h"
@@ -682,6 +682,33 @@ finish:
return status;
}
void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
{
struct dbCommon *prec = paddr->precord;
dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common);
memset((char *)pdbentry,'\0',sizeof(DBENTRY));
pdbentry->pdbbase = pdbbase;
pdbentry->precordType = prec->rdes;
pdbentry->precnode = ppvt->recnode;
pdbentry->pflddes = paddr->pfldDes;
pdbentry->pfield = paddr->pfield;
pdbentry->indfield = -1; /* invalid */
}
void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
{
dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common);
memset((char *)pdbentry,'\0',sizeof(DBENTRY));
pdbentry->pdbbase = pdbbase;
pdbentry->precordType = prec->rdes;
pdbentry->precnode = ppvt->recnode;
pdbentry->indfield = -1; /* invalid */
}
long dbValueSize(short dbr_type)
{
/* sizes for value associated with each DBR request type */

14
src/ioc/db/dbCommonPvt.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef DBCOMMONPVT_H
#define DBCOMMONPVT_H
#include "dbCommon.h"
/** Base internal additional information for every record
*/
typedef struct dbCommonPvt {
struct dbRecordNode *recnode;
struct dbCommon common;
} dbCommonPvt;
#endif // DBCOMMONPVT_H

View File

@@ -159,6 +159,13 @@ testHarness_SRCS += dbPutGetTest.c
TESTFILES += ../dbPutGetTest.db
TESTS += testPutGetTest
TESTPROD_HOST += dbStaticTest
dbStaticTest_SRCS += dbStaticTest.c
dbStaticTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbStaticTest.c
TESTFILES += ../dbStaticTest.db
TESTS += dbStaticTest
# This runs all the test programs in a known working order:
testHarness_SRCS += epicsRunDbTests.c

View File

@@ -0,0 +1,160 @@
#include <string.h>
#include <errlog.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <dbStaticPvt.h>
#include <dbUnitTest.h>
#include <testMain.h>
static void testEntry(const char *pv)
{
DBENTRY entry;
testDiag("testEntry(\"%s\")", pv);
dbInitEntry(pdbbase, &entry);
testOk1(dbFindRecord(&entry, pv)==0);
testDiag("precordType=%p precnode=%p", entry.precordType, entry.precnode);
testOk1(entry.precordType && strcmp(entry.precordType->name, "x")==0);
testOk1(entry.precnode && strcmp(((dbCommon*)entry.precnode->precord)->name, "testrec")==0);
testOk1(entry.pflddes && strcmp(entry.pflddes->name, "VAL")==0);
testOk1(dbFollowAlias(&entry)==0);
testOk1(dbFindInfo(&entry, "A")==0 && strcmp(dbGetInfoString(&entry), "B")==0);
dbFinishEntry(&entry);
}
static void testAddr2Entry(const char *pv)
{
DBENTRY entry, entry2;
dbAddr addr;
testDiag("testAddr2Entry(\"%s\")", pv);
memset(&entry, 0, sizeof(entry));
memset(&entry2, 0, sizeof(entry2));
dbInitEntry(pdbbase, &entry);
if(dbFindRecord(&entry, pv)!=0)
testAbort("no entry for %s", pv);
if(dbFollowAlias(&entry))
testAbort("Can't follow alias");
if(dbNameToAddr(pv, &addr))
testAbort("no addr for %s", pv);
dbInitEntryFromAddr(&addr, &entry2);
testOk1(entry.pdbbase==entry2.pdbbase);
testOk1(entry.precordType==entry2.precordType);
testOk1(entry.pflddes==entry2.pflddes);
testOk1(entry.precnode==entry2.precnode);
testOk1(entry.pfield==entry2.pfield);
testOk1(entry2.indfield==-1);
testOk1(!entry2.pinfonode);
testOk1(!entry2.message);
/* no way to look this up, so not set */
entry.indfield = -1;
testOk1(memcmp(&entry, &entry2, sizeof(entry))==0);
dbFinishEntry(&entry);
dbFinishEntry(&entry2);
}
static void testRec2Entry(const char *recname)
{
DBENTRY entry, entry2;
dbCommon *prec;
testDiag("testRec2Entry(\"%s\")", recname);
memset(&entry, 0, sizeof(entry));
memset(&entry2, 0, sizeof(entry2));
prec = testdbRecordPtr(recname);
dbInitEntry(pdbbase, &entry);
if(dbFindRecord(&entry, recname)!=0)
testAbort("no entry for %s", recname);
if(dbFollowAlias(&entry))
testAbort("Can't follow alias");
dbInitEntryFromRecord(prec, &entry2);
testOk1(entry.pdbbase==entry2.pdbbase);
testOk1(entry.precordType==entry2.precordType);
testOk1(entry.pflddes==entry2.pflddes);
testOk1(entry.precnode==entry2.precnode);
testOk1(entry.pfield==entry2.pfield);
testOk1(entry2.indfield==-1);
testOk1(!entry2.pinfonode);
testOk1(!entry2.message);
/* no way to look this up, so not set */
entry.indfield = -1;
testOk1(memcmp(&entry, &entry2, sizeof(entry))==0);
dbFinishEntry(&entry);
dbFinishEntry(&entry2);
}
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(dbStaticTest)
{
testPlan(192);
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
dbTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("dbStaticTest.db", NULL, NULL);
testEntry("testrec.VAL");
testEntry("testalias.VAL");
testEntry("testalias2.VAL");
testEntry("testalias3.VAL");
testAddr2Entry("testrec.VAL");
testAddr2Entry("testalias.VAL");
testAddr2Entry("testalias2.VAL");
testAddr2Entry("testalias3.VAL");
testRec2Entry("testrec");
testRec2Entry("testalias");
testRec2Entry("testalias2");
testRec2Entry("testalias3");
eltc(0);
testIocInitOk();
eltc(1);
testEntry("testrec.VAL");
testEntry("testalias.VAL");
testEntry("testalias2.VAL");
testEntry("testalias3.VAL");
testAddr2Entry("testrec.VAL");
testAddr2Entry("testalias.VAL");
testAddr2Entry("testalias2.VAL");
testAddr2Entry("testalias3.VAL");
testRec2Entry("testrec");
testRec2Entry("testalias");
testRec2Entry("testalias2");
testRec2Entry("testalias3");
testIocShutdownOk();
testdbCleanup();
return testDone();
}

View File

@@ -0,0 +1,8 @@
record(x, "testrec") {
info("A", "B")
alias("testalias")
}
alias("testrec", "testalias2")
alias("testalias2", "testalias3")

View File

@@ -26,6 +26,7 @@ int dbScanTest(void);
int scanIoTest(void);
int dbLockTest(void);
int dbPutLinkTest(void);
int dbStaticTest(void);
int dbCaLinkTest(void);
int testDbChannel(void);
int chfPluginTest(void);
@@ -46,6 +47,7 @@ void epicsRunDbTests(void)
runTest(scanIoTest);
runTest(dbLockTest);
runTest(dbPutLinkTest);
runTest(dbStaticTest);
runTest(dbCaLinkTest);
runTest(testDbChannel);
runTest(arrShorthandTest);

View File

@@ -109,6 +109,7 @@ typedef struct dbRecordNode {
char *recordname;
ELLLIST infoList; /*LIST head of info nodes*/
int flags;
struct dbRecordNode *aliasedRecord; /* NULL unless flags|DBRN_FLAGS_ISALIAS */
}dbRecordNode;
/*dbRecordAttribute is for "psuedo" fields */

View File

@@ -1652,8 +1652,10 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
dbRecordNode *pnewnode;
PVDENTRY *ppvd;
ELLLIST *preclist = NULL;
if (!precordType) return S_dbLib_recordTypeNotFound;
/* alias of alias still references actual record */
while(precnode && (precnode->flags&DBRN_FLAGS_ISALIAS))
precnode = precnode->aliasedRecord;
if (!precnode) return S_dbLib_recNotFound;
zeroDbentry(pdbentry);
if (!dbFindRecord(pdbentry, alias)) return S_dbLib_recExists;
@@ -1663,9 +1665,9 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
pnewnode = dbCalloc(1, sizeof(dbRecordNode));
pnewnode->recordname = epicsStrDup(alias);
pnewnode->precord = precnode->precord;
pnewnode->aliasedRecord = precnode;
pnewnode->flags = DBRN_FLAGS_ISALIAS;
if (!(precnode->flags & DBRN_FLAGS_ISALIAS))
precnode->flags |= DBRN_FLAGS_HASALIAS;
precnode->flags |= DBRN_FLAGS_HASALIAS;
ellInit(&pnewnode->infoList);
ellAdd(preclist, &pnewnode->node);
precordType->no_aliases++;
@@ -1675,6 +1677,15 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
return 0;
}
int dbFollowAlias(DBENTRY *pdbentry)
{
if(!pdbentry->precnode)
return S_dbLib_recNotFound;
if(pdbentry->precnode->aliasedRecord)
pdbentry->precnode = pdbentry->precnode->aliasedRecord;
return 0;
}
int dbIsAlias(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;

View File

@@ -56,7 +56,10 @@ typedef struct{
char *message;
short indfield;
} DBENTRY;
struct dbAddr;
struct dbCommon;
/*dbDumpFldDes is obsolete. It is only provided for compatibility*/
#define dbDumpFldDes dbDumpField
@@ -67,6 +70,17 @@ epicsShareFunc DBENTRY * dbAllocEntry(DBBASE *pdbbase);
epicsShareFunc void dbFreeEntry(DBENTRY *pdbentry);
epicsShareFunc void dbInitEntry(DBBASE *pdbbase,
DBENTRY *pdbentry);
/** Initialize DBENTRY from a valid dbAddr*.
* Constant time equivalent of dbInitEntry() then dbFindRecord(), and finally dbFollowAlias()
* except that DBENTRY::indfield is not set
*/
epicsShareFunc void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry);
/** Initialize DBENTRY from a valid record (dbCommon*).
* Constant time equivalent of dbInitEntry() then dbFindRecord(), and finally dbFollowAlias()
* when no field is specified (pflddes and pfield are NULL).
* except that DBENTRY::indfield is not set.
*/
epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry);
epicsShareFunc void dbFinishEntry(DBENTRY *pdbentry);
epicsShareFunc DBENTRY * dbCopyEntry(DBENTRY *pdbentry);
epicsShareFunc void dbCopyEntryContents(DBENTRY *pfrom,
@@ -156,6 +170,8 @@ epicsShareFunc int dbIsVisibleRecord(DBENTRY *pdbentry);
epicsShareFunc long dbCreateAlias(DBENTRY *pdbentry,
const char *paliasName);
epicsShareFunc int dbIsAlias(DBENTRY *pdbentry);
/* Follow alias to actual record */
epicsShareFunc int dbFollowAlias(DBENTRY *pdbentry);
epicsShareFunc long dbDeleteAliases(DBENTRY *pdbentry);
epicsShareFunc long dbFindFieldPart(DBENTRY *pdbentry,

View File

@@ -25,7 +25,7 @@
#define epicsExportSharedSymbols
#include "dbBase.h"
#include "dbCommon.h"
#include "dbCommonPvt.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "devSup.h"
@@ -69,90 +69,99 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName)
dbRecordNode *precnode = pdbentry->precnode;
dbFldDes *pflddes;
int i;
dbCommonPvt *ppvt;
dbCommon *precord;
char *pfield;
if(!pdbRecordType) return(S_dbLib_recordTypeNotFound);
if(!precnode) return(S_dbLib_recNotFound);
if(pdbRecordType->rec_size == 0) {
printf("\t*** Did you run x_RegisterRecordDeviceDriver(pdbbase) yet? ***\n");
epicsPrintf("dbAllocRecord(%s) with %s rec_size = 0\n",
precordName, pdbRecordType->name);
return(S_dbLib_noRecSup);
printf("\t*** Did you run x_RegisterRecordDeviceDriver(pdbbase) yet? ***\n");
epicsPrintf("dbAllocRecord(%s) with %s rec_size = 0\n",
precordName, pdbRecordType->name);
return(S_dbLib_noRecSup);
} else if(pdbRecordType->rec_size<sizeof(*precord)) {
printf("\t*** Recordtype %s must include \"dbCommon.dbd\"\n", pdbRecordType->name);
epicsPrintf("dbAllocRecord(%s) with %s rec_size = %d\n",
precordName, pdbRecordType->name, pdbRecordType->rec_size);
return(S_dbLib_noRecSup);
}
precord = dbCalloc(1, pdbRecordType->rec_size);
ppvt = dbCalloc(1, offsetof(dbCommonPvt, common) + pdbRecordType->rec_size);
precord = &ppvt->common;
ppvt->recnode = precnode;
precord->rdes = pdbRecordType;
precnode->precord = precord;
pflddes = pdbRecordType->papFldDes[0];
if(!pflddes) {
epicsPrintf("dbAllocRecord pflddes for NAME not found\n");
return(S_dbLib_flddesNotFound);
epicsPrintf("dbAllocRecord pflddes for NAME not found\n");
return(S_dbLib_flddesNotFound);
}
assert(pflddes->offset == 0);
assert(pflddes->size == sizeof(precord->name));
if(strlen(precordName) >= sizeof(precord->name)) {
epicsPrintf("dbAllocRecord: NAME(%s) too long\n",precordName);
return(S_dbLib_nameLength);
epicsPrintf("dbAllocRecord: NAME(%s) too long\n",precordName);
return(S_dbLib_nameLength);
}
strcpy(precord->name, precordName);
for(i=1; i<pdbRecordType->no_fields; i++) {
pflddes = pdbRecordType->papFldDes[i];
if(!pflddes) continue;
pfield = (char*)precord + pflddes->offset;
pdbentry->pfield = (void *)pfield;
pdbentry->pflddes = pflddes;
pdbentry->indfield = i;
switch(pflddes->field_type) {
case DBF_STRING:
if(pflddes->initial) {
if(strlen(pflddes->initial) >= pflddes->size) {
epicsPrintf("initial size > size for %s.%s\n",
pdbRecordType->name,pflddes->name);
} else {
strcpy(pfield,pflddes->initial);
}
}
break;
case DBF_CHAR:
case DBF_UCHAR:
case DBF_SHORT:
case DBF_USHORT:
case DBF_LONG:
case DBF_ULONG:
case DBF_FLOAT:
case DBF_DOUBLE:
case DBF_ENUM:
case DBF_MENU:
if(pflddes->initial) {
long status;
pflddes = pdbRecordType->papFldDes[i];
if(!pflddes) continue;
pfield = (char*)precord + pflddes->offset;
pdbentry->pfield = (void *)pfield;
pdbentry->pflddes = pflddes;
pdbentry->indfield = i;
switch(pflddes->field_type) {
case DBF_STRING:
if(pflddes->initial) {
if(strlen(pflddes->initial) >= pflddes->size) {
epicsPrintf("initial size > size for %s.%s\n",
pdbRecordType->name,pflddes->name);
} else {
strcpy(pfield,pflddes->initial);
}
}
break;
case DBF_CHAR:
case DBF_UCHAR:
case DBF_SHORT:
case DBF_USHORT:
case DBF_LONG:
case DBF_ULONG:
case DBF_FLOAT:
case DBF_DOUBLE:
case DBF_ENUM:
case DBF_MENU:
if(pflddes->initial) {
long status;
status = dbPutStringNum(pdbentry,pflddes->initial);
if(status)
epicsPrintf("Error initializing %s.%s initial %s\n",
pdbRecordType->name,pflddes->name,pflddes->initial);
}
break;
case DBF_DEVICE:
if(!pflddes->ftPvt) dbGetDeviceMenu(pdbentry);
break;
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK: {
DBLINK *plink = (DBLINK *)pfield;
status = dbPutStringNum(pdbentry,pflddes->initial);
if(status)
epicsPrintf("Error initializing %s.%s initial %s\n",
pdbRecordType->name,pflddes->name,pflddes->initial);
}
break;
case DBF_DEVICE:
if(!pflddes->ftPvt) dbGetDeviceMenu(pdbentry);
break;
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK: {
DBLINK *plink = (DBLINK *)pfield;
plink->type = CONSTANT;
if(pflddes->initial) {
plink->text =
dbCalloc(strlen(pflddes->initial)+1,sizeof(char));
strcpy(plink->text,pflddes->initial);
}
}
break;
case DBF_NOACCESS:
break;
default:
epicsPrintf("dbAllocRecord: Illegal field type\n");
}
plink->type = CONSTANT;
if(pflddes->initial) {
plink->text =
dbCalloc(strlen(pflddes->initial)+1,sizeof(char));
strcpy(plink->text,pflddes->initial);
}
}
break;
case DBF_NOACCESS:
break;
default:
epicsPrintf("dbAllocRecord: Illegal field type\n");
}
}
return(0);
}
@@ -165,7 +174,7 @@ long dbFreeRecord(DBENTRY *pdbentry)
if(!pdbRecordType) return(S_dbLib_recordTypeNotFound);
if(!precnode) return(S_dbLib_recNotFound);
if(!precnode->precord) return(S_dbLib_recNotFound);
free(precnode->precord);
free(CONTAINER(precnode->precord, dbCommonPvt, common));
precnode->precord = NULL;
return(0);
}

View File

@@ -493,7 +493,6 @@ static void doInitRecord0(dbRecordType *pdbRecordType, dbCommon *precord,
if (!prset) return; /* unlikely */
precord->rset = prset;
precord->rdes = pdbRecordType;
precord->mlok = epicsMutexMustCreate();
ellInit(&precord->mlis);