Skip to content

Commit

Permalink
loop safe wrapper for dbGet added
Browse files Browse the repository at this point in the history
  • Loading branch information
dirk-zimoch committed Nov 29, 2024
1 parent 1567da1 commit e206843
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 30 deletions.
70 changes: 40 additions & 30 deletions modules/database/src/ioc/db/dbDbLink.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ long dbDbInitLink(struct link *plink, short dbfType)
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
plink->value.pv_link.pvt = chan;
plink->flags &= ~(DBLINK_FLAG_VISITED|DBLINK_FLAG_LOOPS|DBLINK_FLAG_LOOPFREE);
ellAdd(&precord->bklnk, &plink->value.pv_link.backlinknode);
/* merging into the same lockset is deferred to the caller.
* cf. initPVLinks()
Expand Down Expand Up @@ -232,19 +233,48 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
return status;
}

static long dbDbGetControlLimits(const struct link *plink, double *low,
double *high)
/* Some records get options (precsision, units, ...) for some fields
* from an input link. We need to catch the case that this link
* points back to the same field or we will end in an infinite recursion.
*/
static long dbGetLoopSafe(const struct link *plink, short dbrType,
void *pbuffer, long option)
{
/* We need to cast away const.
That's ok because we know that plink is never actually readonly.
*/
struct link *mutable_plink = (struct link *)plink;
long status = S_dbLib_badLink;
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
long number_elements = 0;

if (plink->flags & DBLINK_FLAG_LOOPS)
return status;
if (!(plink->flags & DBLINK_FLAG_LOOPFREE))
return dbGet(paddr, dbrType, pbuffer, &option, &number_elements, NULL);
dbScanLock(paddr->precord);
if (mutable_plink->flags & DBLINK_FLAG_VISITED) {
mutable_plink->flags |= DBLINK_FLAG_LOOPS;
} else {
mutable_plink->flags |= DBLINK_FLAG_VISITED;
status = dbGet(paddr, dbrType, pbuffer, &option, &number_elements, NULL);
if (!(mutable_plink->flags & DBLINK_FLAG_LOOPS))
mutable_plink->flags |= DBLINK_FLAG_LOOPFREE;
mutable_plink->flags &= ~DBLINK_FLAG_VISITED;
}
dbScanUnlock(paddr->precord);
return status;
}

static long dbDbGetControlLimits(const struct link *plink, double *low,
double *high)
{
struct buffer {
DBRctrlDouble
double value;
} buffer;
long options = DBR_CTRL_DOUBLE;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
NULL);
long status = dbGetLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_CTRL_DOUBLE);

if (status)
return status;
Expand All @@ -257,16 +287,11 @@ static long dbDbGetControlLimits(const struct link *plink, double *low,
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
double *high)
{
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer {
DBRgrDouble
double value;
} buffer;
long options = DBR_GR_DOUBLE;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
NULL);
long status = dbGetLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_GR_DOUBLE);

if (status)
return status;
Expand All @@ -279,16 +304,11 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low,
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
double *low, double *high, double *hihi)
{
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer {
DBRalDouble
double value;
} buffer;
long options = DBR_AL_DOUBLE;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
long status = dbGetLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_AL_DOUBLE);

if (status)
return status;
Expand All @@ -302,16 +322,11 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,

static long dbDbGetPrecision(const struct link *plink, short *precision)
{
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer {
DBRprecision
double value;
} buffer;
long options = DBR_PRECISION;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
long status = dbGetLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_PRECISION);

if (status)
return status;
Expand All @@ -322,16 +337,11 @@ static long dbDbGetPrecision(const struct link *plink, short *precision)

static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
{
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer {
DBRunits
double value;
} buffer;
long options = DBR_UNITS;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
long status = dbGetLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_UNITS);

if (status)
return status;
Expand Down
3 changes: 3 additions & 0 deletions modules/database/src/ioc/dbStatic/link.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ DBCORE_API extern const maplinkType pamaplinkType[LINK_NTYPES];
/* DBLINK Flag bits */
#define DBLINK_FLAG_INITIALIZED 1 /* dbInitLink() called */
#define DBLINK_FLAG_TSELisTIME 2 /* Use TSEL to get timeStamp */
#define DBLINK_FLAG_VISITED 4 /* Used in loop detection */
#define DBLINK_FLAG_LOOPS 8 /* Used in loop detection */
#define DBLINK_FLAG_LOOPFREE 16 /* Used in loop detection */

struct macro_link {
char *macroStr;
Expand Down

0 comments on commit e206843

Please sign in to comment.