From a4fcd2296a3e3f25bc858a9a29d1d64108f92d79 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 22 Jan 2018 21:14:31 -0800 Subject: [PATCH] propagate PUTF through DB_LINK and use to RPRO async For async records to be usable in user triggered (eg. via RSRV) scan chains, queuing must be handled properly in the event that a second dbPutField() is made before the scan chain has completed (eg. a double click on an OPI). We change the meaning of PUTF so that it is propagated through DB links to indicate the pass through the scan chain directly triggered by a dbPutField(). propagation is broken if a busy async record is found, and that record is instead scheduled to re-process on completion. --- src/ioc/db/dbAccess.c | 22 ++++++++-- src/ioc/db/dbDbLink.c | 94 +++++++++++++++++++++++++++++++++++-------- src/ioc/db/dbDbLink.h | 5 +++ 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 973a66836..716adee1e 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -23,6 +23,8 @@ #include #include +#define EPICS_PRIVATE_API + #include "alarm.h" #include "cantProceed.h" #include "cvtFast.h" @@ -49,6 +51,7 @@ #include "dbFldTypes.h" #include "dbFldTypes.h" #include "dbLink.h" +#include "dbDbLink.h" /* for dbDbLinkPUTF() */ #include "dbLockPvt.h" #include "dbNotify.h" #include "dbScan.h" @@ -449,13 +452,26 @@ int dbGetFieldIndex(const struct dbAddr *paddr) */ long dbScanPassive(dbCommon *pfrom, dbCommon *pto) { + long status; + epicsUInt8 pact_save; + /* if not passive just return success */ if (pto->scan != 0) return 0; + pact_save = pfrom->pact; + pfrom->pact = 1; + + dbDbLinkPUTF(pfrom, pto); + if (pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto); - return dbProcess(pto); + + status = dbProcess(pto); + + pfrom->pact = pact_save; + + return status; } /* @@ -523,7 +539,7 @@ long dbProcess(dbCommon *precord) unsigned short monitor_mask; if (*ptrace) - printf("%s: Active %s\n", context, precord->name); + printf("%s: Active%s %s\n", context, precord->rpro ? " Q" : "", precord->name); /* raise scan alarm after MAX_LOCK times */ if ((precord->stat == SCAN_ALARM) || @@ -1210,7 +1226,7 @@ long dbPutField(DBADDR *paddr, short dbrType, dbrType < DBR_PUT_ACKT)) { if (precord->pact) { if (precord->tpro) - printf("%s: Active %s\n", + printf("%s: Active Q %s\n", epicsThreadGetNameSelf(), precord->name); precord->rpro = TRUE; } else { diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c index 105799876..5a129c2d3 100644 --- a/src/ioc/db/dbDbLink.c +++ b/src/ioc/db/dbDbLink.c @@ -18,6 +18,8 @@ #include #include +#define EPICS_PRIVATE_API + #include "alarm.h" #include "cantProceed.h" #include "cvtFast.h" @@ -43,17 +45,81 @@ #include "dbNotify.h" #include "dbScan.h" #include "dbStaticLib.h" +#include "dbServer.h" #include "devSup.h" #include "link.h" #include "recGbl.h" #include "recSup.h" #include "special.h" +#include "dbDbLink.h" /***************************** Database Links *****************************/ /* Forward definition */ static lset dbDb_lset; +/* call before each call of dbProcess() (also dbScanPassive()) + * + * PUTF - This flag is set in dbPutField() prior to calling dbProcess(). + * It is normally cleared at the end of processing in recGblFwdLink(). + * It may also be cleared in dbProcess() if DISA==DISV (scan disabled), + * or by this function. + * If PUTF==1 before a call to dbProcess(prec), then afterwards + * PACT | !PUTF must be true. + * + * RPRO - Set by dbPutField() or this function when the record to be processed + * is found to be busy (PACT==1). + * Cleared in recGblFwdLink() when a record is scheduled for re-processing, + * or DISA==DISV. + */ +static +void propPUTF(struct link *plink) +{ + struct pv_link *ppv_link = &plink->value.pv_link; + DBADDR *paddr = ppv_link->pvt; + dbCommon *psrc = plink->precord, + *pdst = paddr->precord; + + dbDbLinkPUTF(psrc, pdst); +} + +void dbDbLinkPUTF(dbCommon *psrc, dbCommon *pdst) +{ + char context[40] = ""; + int trace = *dbLockSetAddrTrace(psrc); + + if (trace && dbServerClient(context, sizeof(context))) { + /* No client, use thread name */ + strncpy(context, epicsThreadGetNameSelf(), sizeof(context)); + context[sizeof(context) - 1] = 0; + } + + if(!pdst->pact) { + /* normal propagation of PUTF from src to target */ + if(trace) + printf("%s: %s -> %s prop PUTF=%u\n", context, psrc->name, pdst->name, psrc->putf); + + assert(!pdst->putf); + pdst->putf = psrc->putf; + } else if(psrc->putf) { + /* found a busy async record, + * we were originally triggered by a dbPutField() + * so queue for reprocessing on completion, + * but only this one time. + */ + if(trace) + printf("%s: %s -> %s prop RPRO=1\n", context, psrc->name, pdst->name); + pdst->putf = FALSE; + pdst->rpro = TRUE; + } else { + /* busy async record, but not originally triggered + * by dbPutField(). Do nothing. + */ + if(trace) + printf("%s: %s -> %s prop DROP\n", context, psrc->name, pdst->name); + } +} + long dbDbInitLink(struct link *plink, short dbfType) { DBADDR dbaddr; @@ -138,11 +204,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, /* scan passive records if link is process passive */ if (ppv_link->pvlMask & pvlOptPP) { - unsigned char pact = precord->pact; - - precord->pact = TRUE; status = dbScanPassive(precord, paddr->precord); - precord->pact = pact; if (status) return status; } @@ -312,20 +374,18 @@ static long dbDbPutValue(struct link *plink, short dbrType, if (paddr->pfield == (void *) &pdest->proc || (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) { - /* if dbPutField caused asyn record to process */ - /* ask for reprocessing*/ - if (pdest->putf) { - pdest->rpro = TRUE; - } else { /* process dest record with source's PACT true */ - unsigned char pact; + epicsUInt8 pact_save = psrce->pact; - if (psrce && psrce->ppn) - dbNotifyAdd(psrce, pdest); - pact = psrce->pact; - psrce->pact = TRUE; - status = dbProcess(pdest); - psrce->pact = pact; - } + psrce->pact = 1; + + if (psrce && psrce->ppn) + dbNotifyAdd(psrce, pdest); + + propPUTF(plink); + + status = dbProcess(pdest); + + psrce->pact = pact_save; } return status; } diff --git a/src/ioc/db/dbDbLink.h b/src/ioc/db/dbDbLink.h index c36772004..e19685427 100644 --- a/src/ioc/db/dbDbLink.h +++ b/src/ioc/db/dbDbLink.h @@ -23,11 +23,16 @@ extern "C" { struct link; struct dbLocker; +struct dbCommon; epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType); epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptarget); +#ifdef EPICS_PRIVATE_API +void dbDbLinkPUTF(dbCommon *psrc, dbCommon *pdst); +#endif + #ifdef __cplusplus } #endif