PINI Processing support for PHAS.
This commit is contained in:
@@ -12,6 +12,12 @@
|
||||
<h2 align="center">Changes between 3.14.10 and 3.14.11</h2>
|
||||
<!-- Insert new items below here ... -->
|
||||
|
||||
<h4>PINI Processing Phases</h4>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h4>Channel Access command line tool changes</h4>
|
||||
|
||||
<p>The caget/caput/camonitor programs in src/catools now use '\' escape
|
||||
@@ -22,17 +28,19 @@ to be used instead of the default space character.</p>
|
||||
|
||||
<h4>New functions for escaping non-printables in epicsString.h</h4>
|
||||
|
||||
<p>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:</p>
|
||||
<p>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:</p>
|
||||
|
||||
<pre>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);</pre>
|
||||
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
|
||||
<p>The existing function interfaces will be kept for compatibility, but their
|
||||
further use is deprecated.</p>
|
||||
@@ -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).</p>
|
||||
|
||||
<p>The caget/caput/camonitor programs in src/catools can use long strings by
|
||||
<p>The caget/caput/camonitor programs in src/catools can now use long strings by
|
||||
adding the command-line option <tt>-S</tt> 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.</p>
|
||||
|
||||
<h4>RTEMS Release</h4>
|
||||
|
||||
<p>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).</p>
|
||||
|
||||
<p>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).</p>
|
||||
<h4>RTEMS</h4>
|
||||
|
||||
<p>RTEMS stack sizes have been reduced. This allows more clients in machines
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef INCdbScanH
|
||||
#define INCdbScanH
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user