From 88971886c55d97cc69d457e449b04b062b8a8133 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 2 Apr 2009 14:11:27 +0000
Subject: [PATCH] PINI Processing support for PHAS.
---
documentation/RELEASE_NOTES.html | 26 ++-
src/db/dbScan.h | 5 +
src/misc/iocInit.c | 316 +++++++++++++++----------------
3 files changed, 173 insertions(+), 174 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index fc15ddd2c..d74aae675 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -12,6 +12,12 @@
Changes between 3.14.10 and 3.14.11
+PINI Processing Phases
+
+The PHAS field now controls the order in which records with PINI set are
+processed at initialization time, lower values of PHAS are scanned before
+higher ones.
+
Channel Access command line tool changes
The caget/caput/camonitor programs in src/catools now use '\' escape
@@ -22,17 +28,19 @@ to be used instead of the default space character.
New functions for escaping non-printables in epicsString.h
-The existing routines used to escape non-printable characters have been replaced
-by a new set of functions that are prototyped in the epicsString.h header file:
+The existing routines used to escape non-printable characters have been
+replaced by a new set of functions that are prototyped in the epicsString.h
+header file:
int epicsStrnRawFromEscaped(char *outbuf, size_t outsize, const char *inbuf, size_t inlen);
epicsShareFunc int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf, size_t inlen);
epicsShareFunc size_t epicsStrnEscapedFromRawSize(const char *inbuf, size_t inlen);
-Both conversion functions take the output buffer (and its size), and the input
-buffer (and its size) as argument. They will convert non-printable characters
-from/to their '\'-escaped versions. The third function scans a raw input string
-and returns the number of characters needed for the escaped version.
+Both conversion functions take the output buffer (and its size), and the
+input buffer (and its size) as argument. They will convert non-printable
+characters from/to their '\'-escaped versions. The third function scans a raw
+input string and returns the number of characters needed for the escaped
+version.
The existing function interfaces will be kept for compatibility, but their
further use is deprecated.
@@ -58,7 +66,7 @@ string length limit imposed by the DBF_STRING type is replaced by the amount of
storage allocated for the string on the IOC (for link fields the limit is
related to the maximum length of a record name).
-The caget/caput/camonitor programs in src/catools can use long strings by
+
The caget/caput/camonitor programs in src/catools can now use long strings by
adding the command-line option -S which causes them to handle an array
of DBF_CHAR as a string. Both MEDM and EDM can already present such DBF_CHAR
arrays as strings in their text widgets (although you do have to configure the
@@ -190,8 +198,8 @@ epicsTime class has also gone.
RTEMS Release
-RTEMS release 4.9.2 or newer is required. EPICS now configures RTEMS to use unified executive/malloc memory pools if available (RTEMS 4.10 and up).
-
+RTEMS release 4.9.2 or newer is required. EPICS now configures RTEMS to use
+unified executive/malloc memory pools if available (RTEMS 4.10 and up).
RTEMS
RTEMS stack sizes have been reduced. This allows more clients in machines
diff --git a/src/db/dbScan.h b/src/db/dbScan.h
index 7f50d3e8d..717bae8ba 100644
--- a/src/db/dbScan.h
+++ b/src/db/dbScan.h
@@ -15,6 +15,8 @@
#ifndef INCdbScanH
#define INCdbScanH
+#include
+
#include "menuScan.h"
#include "shareLib.h"
@@ -27,6 +29,9 @@ extern "C" {
#define SCAN_IO_EVENT menuScanI_O_Intr
#define SCAN_1ST_PERIODIC (menuScanI_O_Intr + 1)
+#define MAX_PHASE SHRT_MAX
+#define MIN_PHASE SHRT_MIN
+
/*definitions for I/O Interrupt Scanning */
struct io_scan_list;
diff --git a/src/misc/iocInit.c b/src/misc/iocInit.c
index d7b88c11a..5db3d6de6 100644
--- a/src/misc/iocInit.c
+++ b/src/misc/iocInit.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include "dbDefs.h"
#include "epicsThread.h"
@@ -204,13 +205,9 @@ static void initDrvSup(void) /* Locate all driver support entry tables */
continue;
}
pdrvSup->pdrvet = pdrvet;
- /*
- * If an initialization routine is defined (not NULL),
- * for the driver support call it.
- */
- if (pdrvet->init) {
+
+ if (pdrvet->init)
pdrvet->init();
- }
}
}
@@ -295,221 +292,210 @@ static void finishDevSup(void)
pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) {
struct dset *pdset = pthisDevSup->pdset;
- if (pdset && pdset->init) {
+ if (pdset && pdset->init)
pdset->init(1);
- }
}
-
}
}
-static void initDatabase(void)
+/*
+ * Iterate through all record instances (but not aliases),
+ * calling a function for each one.
+ */
+typedef void (*recIterFunc)(dbRecordType *pdbRecordType, dbCommon *precord);
+
+static void iterateRecords(recIterFunc func)
{
dbRecordType *pdbRecordType;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
- struct rset *prset = pdbRecordType->prset;
dbRecordNode *pdbRecordNode;
- if (!prset) continue;
-
for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
dbCommon *precord = pdbRecordNode->precord;
- devSup *pdevSup;
- struct dset *pdset;
if (!precord->name[0] ||
pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
continue;
- precord->rset = prset;
- precord->rdes = pdbRecordType;
- precord->mlok = epicsMutexMustCreate();
- ellInit(&precord->mlis);
-
- /* Reset the process active field */
- precord->pact = FALSE;
-
- /* Init DSET NOTE that result may be NULL */
- pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
- pdset = pdevSup ? pdevSup->pdset : NULL;
- precord->dset = pdset;
- if (prset->init_record) {
- prset->init_record(precord, 0);
- }
+ func(pdbRecordType, precord);
}
}
+ return;
+}
+
+static void doInitRecord0(dbRecordType *pdbRecordType, dbCommon *precord)
+{
+ struct rset *prset = pdbRecordType->prset;
+ devSup *pdevSup;
- /* Second pass to resolve links */
- for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
- pdbRecordType;
- pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
- dbRecordNode *pdbRecordNode;
+ if (!prset) return; /* unlikely */
- for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
- pdbRecordNode;
- pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
- dbCommon *precord = pdbRecordNode->precord;
- int j;
- devSup *pdevSup;
+ precord->rset = prset;
+ precord->rdes = pdbRecordType;
+ precord->mlok = epicsMutexMustCreate();
+ ellInit(&precord->mlis);
- if (!precord->name[0] ||
- pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
- continue;
+ /* Reset the process active field */
+ precord->pact = FALSE;
- /* Convert all PV_LINKs to DB_LINKs or CA_LINKs */
- /* For all the links in the record type... */
- for (j = 0; j < pdbRecordType->no_links; j++) {
- dbFldDes *pdbFldDes =
- pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
- DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
+ /* Init DSET NOTE that result may be NULL */
+ pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
+ precord->dset = pdevSup ? pdevSup->pdset : NULL;
- if (plink->type == PV_LINK) {
- DBADDR dbaddr;
+ if (prset->init_record)
+ prset->init_record(precord, 0);
+}
- if (plink == &precord->tsel) recGblTSELwasModified(plink);
- if (!(plink->value.pv_link.pvlMask&(pvlOptCA|pvlOptCP|pvlOptCPP))
- && (dbNameToAddr(plink->value.pv_link.pvname,&dbaddr)==0)) {
- DBADDR *pdbAddr;
+static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord)
+{
+ devSup *pdevSup;
+ int j;
- plink->type = DB_LINK;
- pdbAddr = dbCalloc(1,sizeof(struct dbAddr));
- *pdbAddr = dbaddr; /*structure copy*/;
- plink->value.pv_link.pvt = pdbAddr;
- } else {/*It is a CA link*/
+ /* Convert all PV_LINKs to DB_LINKs or CA_LINKs */
+ /* For all the links in the record type... */
+ for (j = 0; j < pdbRecordType->no_links; j++) {
+ dbFldDes *pdbFldDes =
+ pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
+ DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
- if (pdbFldDes->field_type == DBF_INLINK) {
- plink->value.pv_link.pvlMask |= pvlOptInpNative;
- }
- dbCaAddLink(plink);
- if (pdbFldDes->field_type == DBF_FWDLINK) {
- char *pperiod =
- strrchr(plink->value.pv_link.pvname,'.');
+ if (plink->type == PV_LINK) {
+ DBADDR dbaddr;
- if (pperiod && strstr(pperiod,"PROC")) {
- plink->value.pv_link.pvlMask |= pvlOptFWD;
- } else {
- errlogPrintf("%s.FLNK is a Channel Access Link "
- " but does not link to a PROC field\n",
- precord->name);
- }
- }
+ if (plink == &precord->tsel) recGblTSELwasModified(plink);
+ if (!(plink->value.pv_link.pvlMask&(pvlOptCA|pvlOptCP|pvlOptCPP))
+ && (dbNameToAddr(plink->value.pv_link.pvname,&dbaddr)==0)) {
+ DBADDR *pdbAddr;
+
+ plink->type = DB_LINK;
+ pdbAddr = dbCalloc(1,sizeof(struct dbAddr));
+ *pdbAddr = dbaddr; /*structure copy*/;
+ plink->value.pv_link.pvt = pdbAddr;
+ } else {/*It is a CA link*/
+
+ if (pdbFldDes->field_type == DBF_INLINK) {
+ plink->value.pv_link.pvlMask |= pvlOptInpNative;
+ }
+ dbCaAddLink(plink);
+ if (pdbFldDes->field_type == DBF_FWDLINK) {
+ char *pperiod =
+ strrchr(plink->value.pv_link.pvname,'.');
+
+ if (pperiod && strstr(pperiod,"PROC")) {
+ plink->value.pv_link.pvlMask |= pvlOptFWD;
+ } else {
+ errlogPrintf("%s.FLNK is a Channel Access Link "
+ " but does not link to a PROC field\n",
+ precord->name);
}
}
}
- pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
- if (pdevSup) {
- struct dsxt *pdsxt = pdevSup->pdsxt;
- if (pdsxt && pdsxt->add_record) {
- pdsxt->add_record(precord);
- }
- }
}
}
-
- /* Call record support init_record routine - Second pass */
- for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
- pdbRecordType;
- pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
- struct rset *prset = pdbRecordType->prset;
- dbRecordNode *pdbRecordNode;
-
- if (!prset) continue;
-
- for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
- pdbRecordNode;
- pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
- dbCommon *precord = pdbRecordNode->precord;
-
- if (!precord->name[0] ||
- pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
- continue;
-
- precord->rset = prset;
- if (prset->init_record) {
- prset->init_record(precord, 1);
- }
+ pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
+ if (pdevSup) {
+ struct dsxt *pdsxt = pdevSup->pdsxt;
+ if (pdsxt && pdsxt->add_record) {
+ pdsxt->add_record(precord);
}
}
+}
+
+/* Find range of PHAS for records where PINI is true */
+static short minPhase, maxPhase;
+
+static void doInitRecord1(dbRecordType *pdbRecordType, dbCommon *precord)
+{
+ struct rset *prset = pdbRecordType->prset;
+ short phase = precord->phas;
+
+ if (!prset) return; /* unlikely */
+
+ if (prset->init_record)
+ prset->init_record(precord, 1);
+
+ if (precord->pini) {
+ if (phase > maxPhase) maxPhase = phase;
+ if (phase < minPhase) minPhase = phase;
+ }
+}
+
+static void initDatabase(void)
+{
+ minPhase = MAX_PHASE;
+ maxPhase = MIN_PHASE;
+
+ iterateRecords(doInitRecord0);
+ iterateRecords(doResolveLinks);
+ iterateRecords(doInitRecord1);
+
epicsAtExit(exitDatabase, NULL);
return;
}
/*
- * Process database records at initialization if
- * their pini (process at init) field is set.
+ * Process database records at initialization ordered by phase
+ * if their pini (process at init) field is set.
*/
+static short piniPhase, nextPhase;
+
+static void doRecordPini(dbRecordType *pdbRecordType, dbCommon *precord)
+{
+ int phase;
+
+ if (!precord->pini) return;
+
+ phase = precord->phas;
+ if (phase == piniPhase)
+ dbProcess(precord);
+ else if (phase > piniPhase && phase < nextPhase)
+ nextPhase = phase;
+}
+
static void initialProcess(void)
{
- dbRecordType *pdbRecordType;
-
- for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
- pdbRecordType;
- pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
- dbRecordNode *pdbRecordNode;
-
- for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
- pdbRecordNode;
- pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
- dbCommon *precord = pdbRecordNode->precord;
-
- if (!precord->name[0] ||
- pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
- continue;
-
- if (precord->pini) {
- dbProcess(precord);
- }
- }
- }
- return;
+ nextPhase = minPhase;
+ do {
+ piniPhase = nextPhase;
+ nextPhase = maxPhase;
+ iterateRecords(doRecordPini);
+ } while (piniPhase != maxPhase);
}
-static void exitDatabase(void *dummy)
+/*
+ * Shutdown processing.
+ */
+static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord)
{
- dbRecordType *pdbRecordType;
+ devSup *pdevSup;
+ struct dsxt *pdsxt;
+ int j;
- for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
- pdbRecordType;
- pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
- dbRecordNode *pdbRecordNode;
+ for (j = 0; j < pdbRecordType->no_links; j++) {
+ dbFldDes *pdbFldDes =
+ pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
+ DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
- for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
- pdbRecordNode;
- pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
- dbCommon *precord = pdbRecordNode->precord;
- int j;
- devSup *pdevSup;
- struct dsxt *pdsxt;
-
- if (!precord->name[0] ||
- pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
- continue;
-
- /* For all the links in the record type... */
- for (j = 0; j < pdbRecordType->no_links; j++) {
- dbFldDes *pdbFldDes =
- pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
- DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
-
- if (plink->type == CA_LINK) {
- dbCaRemoveLink(plink);
- }
- }
-
- if (precord->dset &&
- (pdevSup = dbDSETtoDevSup(pdbRecordType, precord->dset)) &&
- (pdsxt = pdevSup->pdsxt) &&
- pdsxt->del_record) {
- pdsxt->del_record(precord);
- }
+ if (plink->type == CA_LINK) {
+ dbCaRemoveLink(plink);
}
}
+ if (precord->dset &&
+ (pdevSup = dbDSETtoDevSup(pdbRecordType, precord->dset)) &&
+ (pdsxt = pdevSup->pdsxt) &&
+ pdsxt->del_record) {
+ pdsxt->del_record(precord);
+ }
+}
+
+static void exitDatabase(void *dummy)
+{
+ iterateRecords(doCloseLinks);
iocState = iocStopped;
}