From f716b1b26ab61ce80e4210d359c3832b1f0cf1c9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 28 Apr 2017 17:23:43 -0400 Subject: [PATCH 01/10] ioc/dbStatic: dbAllocRecord whitespace --- src/ioc/dbStatic/dbStaticRun.c | 126 ++++++++++++++++----------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index 886fa3501..f4a9d0709 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -75,84 +75,84 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) 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); } precord = dbCalloc(1, pdbRecordType->rec_size); 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; ino_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); } From 78a7ad168efee3d1784ee20611b44f11bba062f9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 28 Apr 2017 18:23:30 -0400 Subject: [PATCH 02/10] ioc/dbStatic: add dbInitEntryFromChannel() Constant time population of a DBENTRY from a valid dbAddr. --- src/ioc/db/dbAccess.c | 13 +++++ src/ioc/db/dbCommon.dbd | 6 ++ src/ioc/db/test/Makefile | 7 +++ src/ioc/db/test/dbStaticTest.c | 92 +++++++++++++++++++++++++++++++ src/ioc/db/test/dbStaticTest.db | 4 ++ src/ioc/db/test/epicsRunDbTests.c | 2 + src/ioc/dbStatic/dbStaticLib.h | 9 ++- src/ioc/dbStatic/dbStaticRun.c | 6 ++ 8 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/ioc/db/test/dbStaticTest.c create mode 100644 src/ioc/db/test/dbStaticTest.db diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 1c01da331..4fb25f0bd 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -682,6 +682,19 @@ finish: return status; } +void dbInitEntryFromChannel(struct dbAddr *paddr, DBENTRY *pdbentry) +{ + struct dbCommon *prec = paddr->precord; + pdbentry->pdbbase = pdbbase; + pdbentry->precordType = prec->rdes; + pdbentry->precnode = prec->rnde; + pdbentry->pflddes = paddr->pfldDes; + pdbentry->pinfonode = NULL; + pdbentry->pfield = paddr->pfield; + pdbentry->indfield = -1; /* invalid */ + pdbentry->message = NULL; +} + long dbValueSize(short dbr_type) { /* sizes for value associated with each DBR request type */ diff --git a/src/ioc/db/dbCommon.dbd b/src/ioc/db/dbCommon.dbd index 1b093e6a8..2df9957b8 100644 --- a/src/ioc/db/dbCommon.dbd +++ b/src/ioc/db/dbCommon.dbd @@ -217,6 +217,12 @@ interest(4) extra("struct dbRecordType *rdes") } + field(RNDE,DBF_NOACCESS) { + prompt("Address of dbRecordNode") + special(SPC_NOMOD) + interest(4) + extra("struct dbRecordNode *rnde") + } field(LSET,DBF_NOACCESS) { prompt("Lock Set") special(SPC_NOMOD) diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 17941a2bc..e3d4164ff 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -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 diff --git a/src/ioc/db/test/dbStaticTest.c b/src/ioc/db/test/dbStaticTest.c new file mode 100644 index 000000000..b6110162b --- /dev/null +++ b/src/ioc/db/test/dbStaticTest.c @@ -0,0 +1,92 @@ +#include + +#include +#include +#include +#include +#include +#include + +static void testEntry(void) +{ + DBENTRY entry; + + testDiag("testEntry"); + + dbInitEntry(pdbbase, &entry); + + testOk1(dbFindRecord(&entry, "testrec.VAL")==0); + + 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(dbFindInfo(&entry, "A")==0 && strcmp(dbGetInfoString(&entry), "B")==0); + + dbFinishEntry(&entry); +} + +static void testAddr2Entry(void) +{ + DBENTRY entry, entry2; + dbAddr addr; + + testDiag("testAddr2Entry"); + + memset(&entry, 0, sizeof(entry)); + memset(&entry2, 0, sizeof(entry2)); + + dbInitEntry(pdbbase, &entry); + + if(dbFindRecord(&entry, "testrec.VAL")!=0) + testAbort("no entry for testrec.VAL"); + + if(dbNameToAddr("testrec.VAL", &addr)) + testAbort("no addr for testrec.VAL"); + + dbInitEntryFromChannel(&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); +} + +void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); + +MAIN(dbStaticTest) +{ + testPlan(19); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + dbTestIoc_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase("dbStaticTest.db", NULL, NULL); + + testEntry(); + + eltc(0); + testIocInitOk(); + eltc(1); + + testEntry(); + testAddr2Entry(); + + testIocShutdownOk(); + + testdbCleanup(); + + return testDone(); +} + diff --git a/src/ioc/db/test/dbStaticTest.db b/src/ioc/db/test/dbStaticTest.db new file mode 100644 index 000000000..d44592979 --- /dev/null +++ b/src/ioc/db/test/dbStaticTest.db @@ -0,0 +1,4 @@ + +record(x, "testrec") { + info("A", "B") +} diff --git a/src/ioc/db/test/epicsRunDbTests.c b/src/ioc/db/test/epicsRunDbTests.c index 10f10e267..69f6b082e 100644 --- a/src/ioc/db/test/epicsRunDbTests.c +++ b/src/ioc/db/test/epicsRunDbTests.c @@ -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); diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 1619a9090..23eeba349 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -56,7 +56,9 @@ typedef struct{ char *message; short indfield; } DBENTRY; - + +struct dbAddr; + /*dbDumpFldDes is obsolete. It is only provided for compatibility*/ #define dbDumpFldDes dbDumpField @@ -67,6 +69,11 @@ 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() + * except that DBENTRY::indfield is not set + */ +epicsShareFunc void dbInitEntryFromChannel(struct dbAddr *paddr, DBENTRY *pdbentry); epicsShareFunc void dbFinishEntry(DBENTRY *pdbentry); epicsShareFunc DBENTRY * dbCopyEntry(DBENTRY *pdbentry); epicsShareFunc void dbCopyEntryContents(DBENTRY *pfrom, diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index f4a9d0709..a08322abf 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -79,8 +79,14 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) epicsPrintf("dbAllocRecord(%s) with %s rec_size = 0\n", precordName, pdbRecordType->name); return(S_dbLib_noRecSup); + } else if(pdbRecordType->rec_sizename); + 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); + precord->rnde = precnode; precnode->precord = precord; pflddes = pdbRecordType->papFldDes[0]; if(!pflddes) { From 12d68e6021b48ca6599331aa3940977c46918bf8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 28 Apr 2017 18:37:14 -0400 Subject: [PATCH 03/10] ioc/db: Add dbCommonPvt Add some hidden "fields" for every record. Allows Base internal hidden accounting which can be changed without an ABI break. --- src/ioc/db/dbAccess.c | 5 +++-- src/ioc/db/dbCommon.dbd | 6 ------ src/ioc/db/dbCommonPvt.h | 14 ++++++++++++++ src/ioc/dbStatic/dbStaticRun.c | 10 ++++++---- 4 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 src/ioc/db/dbCommonPvt.h diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 4fb25f0bd..ae21634b2 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -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" @@ -685,9 +685,10 @@ finish: void dbInitEntryFromChannel(struct dbAddr *paddr, DBENTRY *pdbentry) { struct dbCommon *prec = paddr->precord; + dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common); pdbentry->pdbbase = pdbbase; pdbentry->precordType = prec->rdes; - pdbentry->precnode = prec->rnde; + pdbentry->precnode = ppvt->node; pdbentry->pflddes = paddr->pfldDes; pdbentry->pinfonode = NULL; pdbentry->pfield = paddr->pfield; diff --git a/src/ioc/db/dbCommon.dbd b/src/ioc/db/dbCommon.dbd index 2df9957b8..1b093e6a8 100644 --- a/src/ioc/db/dbCommon.dbd +++ b/src/ioc/db/dbCommon.dbd @@ -217,12 +217,6 @@ interest(4) extra("struct dbRecordType *rdes") } - field(RNDE,DBF_NOACCESS) { - prompt("Address of dbRecordNode") - special(SPC_NOMOD) - interest(4) - extra("struct dbRecordNode *rnde") - } field(LSET,DBF_NOACCESS) { prompt("Lock Set") special(SPC_NOMOD) diff --git a/src/ioc/db/dbCommonPvt.h b/src/ioc/db/dbCommonPvt.h new file mode 100644 index 000000000..eddb12060 --- /dev/null +++ b/src/ioc/db/dbCommonPvt.h @@ -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 *node; + + struct dbCommon common; +} dbCommonPvt; + +#endif // DBCOMMONPVT_H diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index a08322abf..0855a4d0f 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -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,6 +69,7 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) dbRecordNode *precnode = pdbentry->precnode; dbFldDes *pflddes; int i; + dbCommonPvt *ppvt; dbCommon *precord; char *pfield; @@ -85,8 +86,9 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) precordName, pdbRecordType->name, pdbRecordType->rec_size); return(S_dbLib_noRecSup); } - precord = dbCalloc(1, pdbRecordType->rec_size); - precord->rnde = precnode; + ppvt = dbCalloc(1, offsetof(dbCommonPvt, common) + pdbRecordType->rec_size); + precord = &ppvt->common; + ppvt->node = precnode; precnode->precord = precord; pflddes = pdbRecordType->papFldDes[0]; if(!pflddes) { @@ -171,7 +173,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); } From 2eaede9925f92b887e40561c12ef3b25d23eb1b1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 1 May 2017 15:28:57 -0400 Subject: [PATCH 04/10] rename dbInitEntryFromChannel -> dbInitEntryFromAddr --- src/ioc/db/dbAccess.c | 2 +- src/ioc/db/test/dbStaticTest.c | 2 +- src/ioc/dbStatic/dbStaticLib.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index ae21634b2..df6b7adc8 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -682,7 +682,7 @@ finish: return status; } -void dbInitEntryFromChannel(struct dbAddr *paddr, DBENTRY *pdbentry) +void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry) { struct dbCommon *prec = paddr->precord; dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common); diff --git a/src/ioc/db/test/dbStaticTest.c b/src/ioc/db/test/dbStaticTest.c index b6110162b..77d0dc33c 100644 --- a/src/ioc/db/test/dbStaticTest.c +++ b/src/ioc/db/test/dbStaticTest.c @@ -44,7 +44,7 @@ static void testAddr2Entry(void) if(dbNameToAddr("testrec.VAL", &addr)) testAbort("no addr for testrec.VAL"); - dbInitEntryFromChannel(&addr, &entry2); + dbInitEntryFromAddr(&addr, &entry2); testOk1(entry.pdbbase==entry2.pdbbase); testOk1(entry.precordType==entry2.precordType); diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 23eeba349..32fa584c4 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -73,7 +73,7 @@ epicsShareFunc void dbInitEntry(DBBASE *pdbbase, * Constant time equivalent of dbInitEntry() then dbFindRecord() * except that DBENTRY::indfield is not set */ -epicsShareFunc void dbInitEntryFromChannel(struct dbAddr *paddr, DBENTRY *pdbentry); +epicsShareFunc void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry); epicsShareFunc void dbFinishEntry(DBENTRY *pdbentry); epicsShareFunc DBENTRY * dbCopyEntry(DBENTRY *pdbentry); epicsShareFunc void dbCopyEntryContents(DBENTRY *pfrom, From 5d37bc29967e28a78c7b58408813b223a26f142f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 10:58:31 -0400 Subject: [PATCH 05/10] ioc: populate RDES early The record type is known at allocation time, so store RDES immediately. --- src/ioc/dbStatic/dbStaticRun.c | 1 + src/ioc/misc/iocInit.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index 0855a4d0f..b8a8a7309 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -89,6 +89,7 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) ppvt = dbCalloc(1, offsetof(dbCommonPvt, common) + pdbRecordType->rec_size); precord = &ppvt->common; ppvt->node = precnode; + precord->rdes = pdbRecordType; precnode->precord = precord; pflddes = pdbRecordType->papFldDes[0]; if(!pflddes) { diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 795ef5341..aefeb6154 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -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); From 6ba949cdb42be9fd7e4d9f99c54c4ea84c68f817 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 1 May 2017 16:02:14 -0400 Subject: [PATCH 06/10] ioc/dbStatic: add dbInitEntryFromRecord() --- src/ioc/db/dbAccess.c | 17 +++++++++++++++-- src/ioc/dbStatic/dbStaticLib.h | 7 +++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index df6b7adc8..712d63d6d 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -686,14 +686,27 @@ 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->node; pdbentry->pflddes = paddr->pfldDes; - pdbentry->pinfonode = NULL; pdbentry->pfield = paddr->pfield; pdbentry->indfield = -1; /* invalid */ - pdbentry->message = NULL; +} + +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->node; + pdbentry->indfield = -1; /* invalid */ } long dbValueSize(short dbr_type) diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 32fa584c4..dbbd8db11 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -58,6 +58,7 @@ typedef struct{ } DBENTRY; struct dbAddr; +struct dbCommon; /*dbDumpFldDes is obsolete. It is only provided for compatibility*/ #define dbDumpFldDes dbDumpField @@ -74,6 +75,12 @@ epicsShareFunc void dbInitEntry(DBBASE *pdbbase, * 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() + * 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, From 62475a383e73a21769f987f96c635f4186d35a16 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 07:41:13 -0400 Subject: [PATCH 07/10] ioc/dbStatic: better alias tracking Ensure that alias of alias sets DBRN_FLAGS_HASALIAS on the aliased dbRecordNode. Add dbFollowAlias() for completeness. --- src/ioc/dbStatic/dbBase.h | 1 + src/ioc/dbStatic/dbStaticLib.c | 17 ++++++++++++++--- src/ioc/dbStatic/dbStaticLib.h | 6 ++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/ioc/dbStatic/dbBase.h b/src/ioc/dbStatic/dbBase.h index c7a7d7dc5..3dad551ba 100644 --- a/src/ioc/dbStatic/dbBase.h +++ b/src/ioc/dbStatic/dbBase.h @@ -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 */ diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 6d874398c..0a15e8bb3 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -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; diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index dbbd8db11..bc40ae6a2 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -71,12 +71,12 @@ 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() + * 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() + * 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. */ @@ -170,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, From ec3a89e43c0ff058d9d27c60c73f0697d2f62865 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 12:07:56 -0400 Subject: [PATCH 08/10] ioc: rename dbCommonPvt::recnode --- src/ioc/db/dbAccess.c | 4 ++-- src/ioc/db/dbCommonPvt.h | 2 +- src/ioc/dbStatic/dbStaticRun.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 712d63d6d..2b04280c0 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -691,7 +691,7 @@ void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry) pdbentry->pdbbase = pdbbase; pdbentry->precordType = prec->rdes; - pdbentry->precnode = ppvt->node; + pdbentry->precnode = ppvt->recnode; pdbentry->pflddes = paddr->pfldDes; pdbentry->pfield = paddr->pfield; pdbentry->indfield = -1; /* invalid */ @@ -705,7 +705,7 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry) pdbentry->pdbbase = pdbbase; pdbentry->precordType = prec->rdes; - pdbentry->precnode = ppvt->node; + pdbentry->precnode = ppvt->recnode; pdbentry->indfield = -1; /* invalid */ } diff --git a/src/ioc/db/dbCommonPvt.h b/src/ioc/db/dbCommonPvt.h index eddb12060..3dfce8b27 100644 --- a/src/ioc/db/dbCommonPvt.h +++ b/src/ioc/db/dbCommonPvt.h @@ -6,7 +6,7 @@ /** Base internal additional information for every record */ typedef struct dbCommonPvt { - struct dbRecordNode *node; + struct dbRecordNode *recnode; struct dbCommon common; } dbCommonPvt; diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index b8a8a7309..26bfa01d8 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -88,7 +88,7 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) } ppvt = dbCalloc(1, offsetof(dbCommonPvt, common) + pdbRecordType->rec_size); precord = &ppvt->common; - ppvt->node = precnode; + ppvt->recnode = precnode; precord->rdes = pdbRecordType; precnode->precord = precord; pflddes = pdbRecordType->papFldDes[0]; From da4bf2d5eeb67654e67e92beaafdae02b0b8742f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 10:38:34 -0400 Subject: [PATCH 09/10] ioc/db/test: dbStaticTest test operations on aliases --- src/ioc/db/test/dbStaticTest.c | 90 ++++++++++++++++++++++++++++----- src/ioc/db/test/dbStaticTest.db | 4 ++ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/ioc/db/test/dbStaticTest.c b/src/ioc/db/test/dbStaticTest.c index 77d0dc33c..76c0d1eba 100644 --- a/src/ioc/db/test/dbStaticTest.c +++ b/src/ioc/db/test/dbStaticTest.c @@ -7,42 +7,48 @@ #include #include -static void testEntry(void) +static void testEntry(const char *pv) { DBENTRY entry; - testDiag("testEntry"); + testDiag("testEntry(\"%s\")", pv); dbInitEntry(pdbbase, &entry); - testOk1(dbFindRecord(&entry, "testrec.VAL")==0); + 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(void) +static void testAddr2Entry(const char *pv) { DBENTRY entry, entry2; dbAddr addr; - testDiag("testAddr2Entry"); + testDiag("testAddr2Entry(\"%s\")", pv); memset(&entry, 0, sizeof(entry)); memset(&entry2, 0, sizeof(entry2)); dbInitEntry(pdbbase, &entry); - if(dbFindRecord(&entry, "testrec.VAL")!=0) - testAbort("no entry for testrec.VAL"); + if(dbFindRecord(&entry, pv)!=0) + testAbort("no entry for %s", pv); - if(dbNameToAddr("testrec.VAL", &addr)) - testAbort("no addr for testrec.VAL"); + if(dbFollowAlias(&entry)) + testAbort("Can't follow alias"); + + if(dbNameToAddr(pv, &addr)) + testAbort("no addr for %s", pv); dbInitEntryFromAddr(&addr, &entry2); @@ -61,27 +67,85 @@ static void testAddr2Entry(void) 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(19); + testPlan(156); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); dbTestIoc_registerRecordDeviceDriver(pdbbase); testdbReadDatabase("dbStaticTest.db", NULL, NULL); - testEntry(); + testEntry("testrec.VAL"); + testEntry("testalias.VAL"); + testEntry("testalias2.VAL"); + testEntry("testalias3.VAL"); + testRec2Entry("testrec"); + testRec2Entry("testalias"); + testRec2Entry("testalias2"); + testRec2Entry("testalias3"); eltc(0); testIocInitOk(); eltc(1); - testEntry(); - testAddr2Entry(); + 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(); diff --git a/src/ioc/db/test/dbStaticTest.db b/src/ioc/db/test/dbStaticTest.db index d44592979..c35ff9a91 100644 --- a/src/ioc/db/test/dbStaticTest.db +++ b/src/ioc/db/test/dbStaticTest.db @@ -1,4 +1,8 @@ record(x, "testrec") { info("A", "B") + alias("testalias") } + +alias("testrec", "testalias2") +alias("testalias2", "testalias3") From 1917d0563aa73798cce6526a9d16f5c7017bc41e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 21:30:43 -0400 Subject: [PATCH 10/10] ioc/db/test: dbStaticTest dbInitEntryFromAddr() works before iocInit() --- src/ioc/db/test/dbStaticTest.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/test/dbStaticTest.c b/src/ioc/db/test/dbStaticTest.c index 76c0d1eba..e1d0a9aae 100644 --- a/src/ioc/db/test/dbStaticTest.c +++ b/src/ioc/db/test/dbStaticTest.c @@ -114,7 +114,7 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); MAIN(dbStaticTest) { - testPlan(156); + testPlan(192); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -125,6 +125,10 @@ MAIN(dbStaticTest) 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");