From 905c5e33362d940f92c12de5f528fe9ab00a0c20 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 24 Mar 2016 10:06:18 -0400 Subject: [PATCH] lset version and report --- src/ioc/db/dbCa.c | 2 + src/ioc/db/dbCa.h | 1 + src/ioc/db/dbCaTest.c | 118 +++++++++++++++++++++------------ src/ioc/db/dbLink.c | 61 ++++++++++++----- src/ioc/db/dbLink.h | 30 +++++++++ src/ioc/dbStatic/dbStaticLib.h | 2 +- 6 files changed, 153 insertions(+), 61 deletions(-) diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c index d05b8c7e5..e3fbbc044 100644 --- a/src/ioc/db/dbCa.c +++ b/src/ioc/db/dbCa.c @@ -709,6 +709,8 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) { } static lset dbCa_lset = { + LSET_API_VERSION, + dbCaReportLink, dbCaRemoveLink, isConnected, getDBFtype, getElements, diff --git a/src/ioc/db/dbCa.h b/src/ioc/db/dbCa.h index f1cfada40..4ddab6436 100644 --- a/src/ioc/db/dbCa.h +++ b/src/ioc/db/dbCa.h @@ -49,6 +49,7 @@ extern struct ca_client_context * dbCaClientContext; #ifdef EPICS_DBCA_PRIVATE_API epicsShareFunc void dbCaSync(void); +void dbCaReportLink(const struct link *plink, dbLinkReportInfo *pinfo); #endif /* These macros are for backwards compatibility */ diff --git a/src/ioc/db/dbCaTest.c b/src/ioc/db/dbCaTest.c index 450eb9463..427137e88 100644 --- a/src/ioc/db/dbCaTest.c +++ b/src/ioc/db/dbCaTest.c @@ -20,6 +20,7 @@ #include #include +#define EPICS_DBCA_PRIVATE_API #include "dbDefs.h" #include "epicsEvent.h" #include "epicsPrint.h" @@ -52,7 +53,60 @@ #include "dbLock.h" #include "link.h" - +void dbCaReportLink(const struct link *plink, dbLinkReportInfo *pinfo) +{ + caLink * const pca = (caLink *)plink->value.pv_link.pvt; + const char * fname = dbGetFieldName(pinfo->pentry), + * rname = dbGetRecordName(pinfo->pentry); + + assert(pca); + epicsMutexLock(pca->lock); + assert(pca->plink==plink); + + pinfo->connected = ca_field_type(pca->chid) != TYPENOTCONN; + pinfo->nWriteFail = pca->nNoWrite; + + if (pinfo->connected) { + pinfo->readable = ca_read_access(pca->chid); + pinfo->writable = ca_write_access(pca->chid); + + if (pinfo->filter==dbLinkReportAll || pinfo->filter==dbLinkReportConnected) { + int rw = pinfo->readable | + pinfo->writable << 1; + static const char *rights[4] = { + "No Access", "Read Only", + "Write Only", "Read/Write" + }; + int mask = plink->value.pv_link.pvlMask; + printf(LSET_REPORT_INDENT "%28s.%-4s ==> %-28s (%lu, %lu)\n", + rname, + fname, + plink->value.pv_link.pvname, + pca->nDisconnect, + pca->nNoWrite); + printf(LSET_REPORT_INDENT "%21s [%s%s%s%s] host %s, %s\n", "", + mask & pvlOptInpNative ? "IN" : " ", + mask & pvlOptInpString ? "IS" : " ", + mask & pvlOptOutNative ? "ON" : " ", + mask & pvlOptOutString ? "OS" : " ", + ca_host_name(pca->chid), + rights[rw]); + } + } else { + if (pinfo->filter==dbLinkReportAll || pinfo->filter==dbLinkReportDisconnected) { + printf("%28s.%-4s --> %-28s (%lu, %lu)\n", + rname, + fname, + plink->value.pv_link.pvname, + pca->nDisconnect, + pca->nNoWrite); + } + } + + epicsMutexUnlock(pca->lock); +} + + long dbcar(char *precordname, int level) { DBENTRY dbentry; @@ -68,7 +122,7 @@ long dbcar(char *precordname, int level) int noWriteAccess=0; unsigned long nDisconnect=0; unsigned long nNoWrite=0; - caLink *pca; + int j; if (!precordname || precordname[0] == '\0' || !strcmp(precordname, "*")) { @@ -90,50 +144,26 @@ long dbcar(char *precordname, int level) dbScanLock(precord); for (j=0; jno_links; j++) { pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[j]]; + pdbentry->pflddes = pdbFldDes; plink = (DBLINK *)((char *)precord + pdbFldDes->offset); if (plink->type == CA_LINK) { ncalinks++; - pca = (caLink *)plink->value.pv_link.pvt; - if (pca - && pca->chid - && (ca_field_type(pca->chid) != TYPENOTCONN)) { - nconnected++; - nDisconnect += pca->nDisconnect; - nNoWrite += pca->nNoWrite; - if (!ca_read_access(pca->chid)) noReadAccess++; - if (!ca_write_access(pca->chid)) noWriteAccess++; - if (level>1) { - int rw = ca_read_access(pca->chid) | - ca_write_access(pca->chid) << 1; - static const char *rights[4] = { - "No Access", "Read Only", - "Write Only", "Read/Write" - }; - int mask = plink->value.pv_link.pvlMask; - printf("%28s.%-4s ==> %-28s (%lu, %lu)\n", - precord->name, - pdbFldDes->name, - plink->value.pv_link.pvname, - pca->nDisconnect, - pca->nNoWrite); - printf("%21s [%s%s%s%s] host %s, %s\n", "", - mask & pvlOptInpNative ? "IN" : " ", - mask & pvlOptInpString ? "IS" : " ", - mask & pvlOptOutNative ? "ON" : " ", - mask & pvlOptOutString ? "OS" : " ", - ca_host_name(pca->chid), - rights[rw]); - } - } else { - if (level>0) { - printf("%28s.%-4s --> %-28s (%lu, %lu)\n", - precord->name, - pdbFldDes->name, - plink->value.pv_link.pvname, - pca->nDisconnect, - pca->nNoWrite); - } - } + dbLinkReportInfo linfo; + memset(&linfo, 0, sizeof(linfo)); + linfo.pentry = pdbentry; + if(level==0) + linfo.filter = dbLinkReportNone; + else if(level==1) + linfo.filter = dbLinkReportDisconnected; + else + linfo.filter = dbLinkReportAll; + if(level>2) + linfo.detailLevel = level-2; + dbReportLink(plink, &linfo); + nconnected += linfo.connected; + nDisconnect += !linfo.connected; + noReadAccess += !linfo.readable; + noWriteAccess += !linfo.writable; } } dbScanUnlock(precord); @@ -190,7 +220,7 @@ void dbcaStats(int *pchans, int *pdiscon) plink = (DBLINK *)((char *)precord + pdbFldDes->offset); if (plink->type == CA_LINK) { ncalinks++; - if (dbCaIsLinkConnected(plink)) { + if (dbIsLinkConnected(plink)) { nconnected++; } } diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c index d543c106f..1aa9105b3 100644 --- a/src/ioc/db/dbLink.c +++ b/src/ioc/db/dbLink.c @@ -139,6 +139,8 @@ static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer, } static lset dbConst_lset = { + LSET_API_VERSION, + NULL, NULL, NULL, NULL, dbConstGetNelements, @@ -431,6 +433,8 @@ static void dbDbScanFwdLink(struct link *plink) } static lset dbDb_lset = { + LSET_API_VERSION, + NULL, dbDbRemoveLink, dbDbIsConnected, dbDbGetDBFtype, dbDbGetElements, @@ -446,6 +450,36 @@ static lset dbDb_lset = { void (*dbAddLinkHook)(struct link *link, short dbfType); +/* initialize CA_LINK with possibly custom lset */ +static +void customlset(struct link *plink, short dbfType) +{ + int oops = 0; + plink->lset = NULL; + if(dbAddLinkHook) + (*dbAddLinkHook)(plink, dbfType); + + if((plink->lset==NULL) ^ (plink->type==PV_LINK)) { + oops = 1; + errlogPrintf("custom link types must set both type and lset.\n"); + } + if(plink->lset && plink->lset->version!=LSET_API_VERSION) { + oops = 1; + errlogPrintf("custom link types must set .version to LSET_API_VERSION (%u) not %u\n", + LSET_API_VERSION, plink->lset->version); + } + if(oops) + { + plink->lset = NULL; + plink->type = PV_LINK; + plink->value.pv_link.pvt = NULL; // leaking + /* TODO, turn into CONSTANT? */ + } + + if(!plink->lset) + dbCaAddLink(NULL, plink, dbfType); +} + void dbInitLink(struct link *plink, short dbfType) { struct dbCommon *precord = plink->precord; @@ -471,17 +505,7 @@ void dbInitLink(struct link *plink, short dbfType) if (dbfType == DBF_INLINK) plink->value.pv_link.pvlMask |= pvlOptInpNative; - plink->lset = NULL; - if(dbAddLinkHook) - (*dbAddLinkHook)(plink, dbfType); - if((plink->lset==NULL) ^ (plink->type==PV_LINK)) { - errlogPrintf("custom link types must set both type and lset.\n"); - plink->lset = NULL; - plink->type = PV_LINK; - plink->value.pv_link.pvt = NULL; // leaking - } - if(!plink->lset) - dbCaAddLink(NULL, plink, dbfType); + customlset(plink, dbfType); if (dbfType == DBF_FWDLINK) { char *pperiod = strrchr(plink->value.pv_link.pvname, '.'); @@ -520,11 +544,7 @@ void dbAddLink(dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptar if (dbfType == DBF_INLINK) plink->value.pv_link.pvlMask |= pvlOptInpNative; - plink->lset = NULL; - if(dbAddLinkHook) - (*dbAddLinkHook)(plink, dbfType); - if(!plink->lset) - dbCaAddLink(locker, plink, dbfType); + customlset(plink, dbfType); if (dbfType == DBF_FWDLINK) { char *pperiod = strrchr(plink->value.pv_link.pvname, '.'); @@ -553,6 +573,15 @@ void dbRemoveLink(dbLocker *locker, struct link *plink) } } +void dbReportLink(const struct link *plink, dbLinkReportInfo *pinfo) +{ + lset *plset = plink->lset; + + if (plset && plset->reportLink) { + plset->reportLink(plink, pinfo); + } +} + int dbIsLinkConnected(const struct link *plink) { lset *plset = plink->lset; diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h index a2e9175df..c24f89dc5 100644 --- a/src/ioc/db/dbLink.h +++ b/src/ioc/db/dbLink.h @@ -26,8 +26,36 @@ extern "C" { #endif struct dbLocker; +struct DBENTRY; + +#define LSET_API_VERSION 1 +#define LSET_REPORT_INDENT "" + +typedef enum { + dbLinkReportNone, + dbLinkReportAll, + dbLinkReportConnected, + dbLinkReportDisconnected, +} dbLinkReportFilter; + +typedef struct { + /* from caller */ + dbLinkReportFilter filter; + int detailLevel; + struct DBENTRY *pentry; + unsigned clearstats:1; /* after reporting, zero stat counters */ + /* callee fills in current state */ + unsigned connected:1; /* is this link connected to it's underlying data source */ + unsigned readable:1; /* would a dbGetLink() succeed at this moment */ + unsigned writable:1; /* would a dbPutLink() succeed at this moment */ + /* callee fills in statistics */ + unsigned nEvents; /* number of times new data has been received from the underlying data source */ + unsigned nWriteFail; /* number of times dbPutLink() has failed for this link */ +} dbLinkReportInfo; typedef struct lset { + unsigned version; /* must be set to LSET_API_VERSION */ + void (*reportLink)(const struct link *plink, dbLinkReportInfo *pinfo); void (*removeLink)(struct dbLocker *locker, struct link *plink); int (*isConnected)(const struct link *plink); int (*getDBFtype)(const struct link *plink); @@ -58,6 +86,8 @@ epicsShareFunc long dbLoadLink(struct link *plink, short dbrType, void *pbuffer); epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink); +epicsShareFunc void dbReportLink(const struct link *plink, dbLinkReportInfo *pinfo); + epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements); epicsShareFunc int dbIsLinkConnected(const struct link *plink); epicsShareFunc int dbGetLinkDBFtype(const struct link *plink); diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 93f7f27d2..d07e459ef 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -47,7 +47,7 @@ extern "C" { typedef dbBase DBBASE; -typedef struct{ +typedef struct DBENTRY { DBBASE *pdbbase; dbRecordType *precordType; dbFldDes *pflddes;