lset version and report

This commit is contained in:
Michael Davidsaver
2016-03-24 10:06:18 -04:00
parent 47b3c68af1
commit 905c5e3336
6 changed files with 153 additions and 61 deletions

View File

@@ -709,6 +709,8 @@ static void scanLinkOnce(dbCommon *prec, caLink *pca) {
}
static lset dbCa_lset = {
LSET_API_VERSION,
dbCaReportLink,
dbCaRemoveLink,
isConnected,
getDBFtype, getElements,

View File

@@ -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 */

View File

@@ -20,6 +20,7 @@
#include <string.h>
#include <errno.h>
#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; j<pdbRecordType->no_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++;
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -47,7 +47,7 @@ extern "C" {
typedef dbBase DBBASE;
typedef struct{
typedef struct DBENTRY {
DBBASE *pdbbase;
dbRecordType *precordType;
dbFldDes *pflddes;