PINI Processing support for PHAS.

This commit is contained in:
Andrew Johnson
2009-04-02 14:11:27 +00:00
parent 433e400c4d
commit 88971886c5
3 changed files with 173 additions and 174 deletions

View File

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

View File

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

View File

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