Files
pcas/src/misc/iocInit.c
2008-07-21 14:27:21 +00:00

496 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* iocInit.c ioc initialization */
/* $Id$ */
/* Author: Marty Kraimer Date: 06-01-91 */
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "dbDefs.h"
#include "epicsThread.h"
#include "epicsPrint.h"
#include "ellLib.h"
#include "dbDefs.h"
#include "dbBase.h"
#include "caeventmask.h"
#include "dbAddr.h"
#include "dbBkpt.h"
#include "dbFldTypes.h"
#include "link.h"
#include "dbLock.h"
#include "dbAccess.h"
#include "recGbl.h"
#include "dbNotify.h"
#include "dbCa.h"
#include "dbScan.h"
#include "taskwd.h"
#include "callback.h"
#include "dbCommon.h"
#include "dbLock.h"
#include "devSup.h"
#include "drvSup.h"
#include "registryRecordType.h"
#include "registryDeviceSupport.h"
#include "registryDriverSupport.h"
#include "errMdef.h"
#include "recSup.h"
#include "envDefs.h"
#include "rsrv.h"
epicsShareFunc int epicsShareAPI asInit (void);
#include "dbStaticLib.h"
#include "db_access_routines.h"
#include "initHooks.h"
#include "epicsExit.h"
#include "epicsSignal.h"
#define epicsExportSharedSymbols
#include "epicsRelease.h"
#include "iocInit.h"
static enum {
iocVirgin, iocBuilding, iocBuilt, iocRunning, iocPaused, iocStopped
} iocState = iocVirgin;
/* define forward references*/
static void initDrvSup(void);
static void initRecSup(void);
static void initDevSup(void);
static void finishDevSup(void);
static void initDatabase(void);
static void initialProcess(void);
static void exitDatabase(void *dummy);
/*
* Initialize EPICS on the IOC.
*/
int iocInit(void)
{
return iocBuild() || iocRun();
}
int iocBuild(void)
{
if (iocState != iocVirgin) {
errlogPrintf("iocBuild: IOC can only be initialized once\n");
return -1;
}
if (!epicsThreadIsOkToBlock()) {
epicsThreadSetOkToBlock(1);
}
errlogPrintf("Starting iocInit\n");
if (!pdbbase) {
errlogPrintf("iocBuild: Aborting, no database loaded!\n");
return -1;
}
epicsSignalInstallSigHupIgnore();
initHooks(initHookAtBeginning);
coreRelease();
/* After this point, further calls to iocInit() are disallowed. */
iocState = iocBuilding;
taskwdInit();
callbackInit();
initHooks(initHookAfterCallbackInit);
dbCaLinkInit();
initHooks(initHookAfterCaLinkInit);
initDrvSup();
initHooks(initHookAfterInitDrvSup);
initRecSup();
initHooks(initHookAfterInitRecSup);
initDevSup();
initHooks(initHookAfterInitDevSup);
initDatabase();
dbLockInitRecords(pdbbase);
dbBkptInit();
initHooks(initHookAfterInitDatabase);
finishDevSup();
initHooks(initHookAfterFinishDevSup);
scanInit();
if (asInit()) {
errlogPrintf("iocBuild: asInit Failed.\n");
return -1;
}
dbPutNotifyInit();
epicsThreadSleep(.5);
initHooks(initHookAfterScanInit);
initialProcess();
initHooks(initHookAfterInitialProcess);
/* Start CA server threads */
rsrv_init();
iocState = iocBuilt;
return 0;
}
int iocRun(void)
{
if (iocState != iocPaused && iocState != iocBuilt) {
errlogPrintf("iocRun: IOC not paused\n");
return -1;
}
/* Enable scan tasks and some driver support functions. */
scanRun();
dbCaRun();
interruptAccept = TRUE;
if (iocState == iocBuilt)
initHooks(initHookAfterInterruptAccept);
rsrv_run();
if (iocState == iocBuilt)
initHooks(initHookAtEnd);
errlogPrintf("iocRun: %s\n", iocState == iocBuilt ?
"All initialization complete" :
"IOC restarted");
iocState = iocRunning;
return 0;
}
int iocPause(void)
{
if (iocState != iocRunning) {
errlogPrintf("iocPause: IOC not running\n");
return -1;
}
rsrv_pause();
interruptAccept = FALSE;
dbCaPause();
scanPause();
iocState = iocPaused;
errlogPrintf("iocPause: IOC suspended\n");
return 0;
}
static void initDrvSup(void) /* Locate all driver support entry tables */
{
drvSup *pdrvSup;
struct drvet *pdrvet;
for (pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList); pdrvSup;
pdrvSup = (drvSup *)ellNext(&pdrvSup->node)) {
pdrvet = registryDriverSupportFind(pdrvSup->name);
if (!pdrvet) {
errlogPrintf("iocInit: driver %s not found\n", pdrvSup->name);
continue;
}
pdrvSup->pdrvet = pdrvet;
/*
* If an initialization routine is defined (not NULL),
* for the driver support call it.
*/
if (pdrvet->init) {
pdrvet->init();
}
}
}
static void initRecSup(void)
{
dbRecordType *pdbRecordType;
recordTypeLocation *precordTypeLocation;
struct rset *prset;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
precordTypeLocation = registryRecordTypeFind(pdbRecordType->name);
if (!precordTypeLocation) {
errlogPrintf("iocInit record support for %s not found\n",
pdbRecordType->name);
continue;
}
prset = precordTypeLocation->prset;
pdbRecordType->prset = prset;
if (prset->init) {
prset->init();
}
}
}
static long do_nothing(struct dbCommon *precord) { return 0; }
/* Dummy DSXT used for soft device supports */
struct dsxt devSoft_DSXT = {
do_nothing,
do_nothing
};
static devSup *pthisDevSup = NULL;
static void initDevSup(void)
{
dbRecordType *pdbRecordType;
struct dset *pdset;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList);
pthisDevSup;
pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) {
pdset = registryDeviceSupportFind(pthisDevSup->name);
if (!pdset) {
errlogPrintf("device support %s not found\n",pthisDevSup->name);
continue;
}
if (pthisDevSup->link_type == CONSTANT)
pthisDevSup->pdsxt = &devSoft_DSXT;
pthisDevSup->pdset = pdset;
if (pdset->init) {
pdset->init(0);
}
}
}
}
epicsShareFunc void devExtend(dsxt *pdsxt)
{
if (!pthisDevSup)
errlogPrintf("devExtend() called outside of initDevSup()\n");
else {
pthisDevSup->pdsxt = pdsxt;
}
}
static void finishDevSup(void)
{
dbRecordType *pdbRecordType;
struct dset *pdset;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList);
pthisDevSup;
pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) {
pdset = pthisDevSup->pdset;
if (pdset && pdset->init) {
pdset->init(1);
}
}
}
}
static void initDatabase(void)
{
dbRecordType *pdbRecordType;
dbFldDes *pdbFldDes;
dbRecordNode *pdbRecordNode;
devSup *pdevSup;
struct rset *prset;
struct dset *pdset;
dbCommon *precord;
DBADDR dbaddr;
DBLINK *plink;
int j;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
prset = pdbRecordType->prset;
for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
if (!prset) break;
/* Find pointer to record instance */
precord = pdbRecordNode->precord;
if (!precord->name[0]) 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);
}
}
}
/* Second pass to resolve links */
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
prset = pdbRecordType->prset;
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
if (!precord->name[0]) continue;
/* 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++) {
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if (plink->type == PV_LINK) {
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*/
char *pperiod;
if (pdbFldDes->field_type==DBF_INLINK) {
plink->value.pv_link.pvlMask |= pvlOptInpNative;
}
dbCaAddLink(plink);
if (pdbFldDes->field_type==DBF_FWDLINK) {
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 access field PROC\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)) {
prset = pdbRecordType->prset;
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
if (!prset) break;
/* Find pointer to record instance */
precord = pdbRecordNode->precord;
if (!precord->name[0]) continue;
precord->rset = prset;
if (prset->init_record) {
prset->init_record(precord, 1);
}
}
}
epicsAtExit(exitDatabase, NULL);
return;
}
/*
* Process database records at initialization if
* their pini (process at init) field is set.
*/
static void initialProcess(void)
{
dbRecordType *pdbRecordType;
dbRecordNode *pdbRecordNode;
dbCommon *precord;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
if (!precord->name[0]) continue;
if (precord->pini) {
dbProcess(precord);
}
}
}
return;
}
static void exitDatabase(void *dummy)
{
dbRecordType *pdbRecordType;
struct rset *prset;
dbRecordNode *pdbRecordNode;
dbCommon *precord;
dbFldDes *pdbFldDes;
devSup *pdevSup;
struct dsxt *pdsxt;
DBLINK *plink;
int j;
scanPause();
interruptAccept = FALSE;
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
prset = pdbRecordType->prset;
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) {
precord = pdbRecordNode->precord;
if (!precord->name[0]) continue;
/* For all the links in the record type... */
for (j = 0; j < pdbRecordType->no_links; j++) {
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
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);
}
}
}
iocState = iocStopped;
}