Added iocBuild, iocPause and iocRun commands.

These are mainly for redundant IOCs, but may be useful elsewhere.
iocBuild prepares the IOC and freezes it just before it goes live.
A subsequent iocRun kicks it into life, or restarts it when paused.
iocPause freezes all scan tasks and disconnects the server.
This commit is contained in:
Andrew Johnson
2008-07-09 21:31:56 +00:00
parent d0d8761d0d
commit c9bc70bd6a
13 changed files with 554 additions and 262 deletions

View File

@@ -51,19 +51,21 @@ epicsShareFunc void * epicsShareAPI dbCalloc(size_t nobj,size_t size);
#include "dbCaPvt.h"
#include "recSup.h"
#define STATIC static
STATIC ELLLIST workList; /* Work list for dbCaTask */
STATIC epicsMutexId workListLock; /*Mutual exclusions semaphores for workList*/
STATIC epicsEventId workListEvent; /*wakeup event for dbCaTask*/
STATIC int removesOutstanding = 0;
STATIC int removesOutstandingWarning = 10000;
STATIC volatile int exitRequest = 0;
STATIC epicsEventId exitEvent;
static ELLLIST workList; /* Work list for dbCaTask */
static epicsMutexId workListLock; /*Mutual exclusions semaphores for workList*/
static epicsEventId workListEvent; /*wakeup event for dbCaTask*/
static int removesOutstanding = 0;
static int removesOutstandingWarning = 10000;
static enum {
ctlRun, ctlPause, ctlExit
} dbCaCtl;
static epicsEventId startStopEvent;
struct ca_client_context * dbCaClientContext;
void dbCaTask(void); /*The Channel Access Task*/
static void dbCaTask(void *);
extern void dbServiceIOInit();
#define printLinks(pcaLink) \
@@ -127,7 +129,7 @@ extern void dbServiceIOInit();
* Thus the users callback will get called exactly once
*/
STATIC void addAction(caLink *pca, short link_action)
static void addAction(caLink *pca, short link_action)
{
int callAdd = FALSE;
@@ -166,16 +168,41 @@ void epicsShareAPI dbCaCallbackProcess(struct link *plink)
dbScanUnlock(pdbCommon);
}
static void dbCaShutdown(void *arg)
{
if (dbCaCtl == ctlRun) {
dbCaCtl = ctlExit;
epicsEventSignal(workListEvent);
epicsEventMustWait(startStopEvent);
}
}
void epicsShareAPI dbCaLinkInit(void)
{
dbServiceIOInit();
ellInit(&workList);
workListLock = epicsMutexMustCreate();
workListEvent = epicsEventMustCreate(epicsEventEmpty);
exitEvent = epicsEventMustCreate(epicsEventEmpty);
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
dbCaCtl = ctlPause;
epicsThreadCreate("dbCaLink", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC) dbCaTask,0);
dbCaTask, NULL);
epicsEventMustWait(startStopEvent);
epicsAtExit(dbCaShutdown, NULL);
}
void epicsShareAPI dbCaRun(void)
{
dbCaCtl = ctlRun;
epicsEventSignal(workListEvent);
}
void epicsShareAPI dbCaPause(void)
{
dbCaCtl = ctlPause;
epicsEventSignal(workListEvent);
}
void epicsShareAPI dbCaAddLinkCallback( struct link *plink,
@@ -516,7 +543,7 @@ long epicsShareAPI dbCaGetUnits(
return(gotAttributes ? 0 : -1);
}
STATIC void connectionCallback(struct connection_handler_args arg)
static void connectionCallback(struct connection_handler_args arg)
{
caLink *pca;
short link_action = 0;
@@ -584,7 +611,7 @@ done:
epicsMutexUnlock(pca->lock);
}
STATIC void eventCallback(struct event_handler_args arg)
static void eventCallback(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
DBLINK *plink;
@@ -649,7 +676,7 @@ done:
if(monitor) monitor(userPvt);
}
STATIC void exceptionCallback(struct exception_handler_args args)
static void exceptionCallback(struct exception_handler_args args)
{
const char *context = (args.ctx ? args.ctx : "unknown");
@@ -674,7 +701,7 @@ STATIC void exceptionCallback(struct exception_handler_args args)
}
}
STATIC void putCallback(struct event_handler_args arg)
static void putCallback(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
struct link *plink;
@@ -694,7 +721,7 @@ done:
if(callback) callback(userPvt);
}
STATIC void accessRightsCallback(struct access_rights_handler_args arg)
static void accessRightsCallback(struct access_rights_handler_args arg)
{
caLink *pca = (caLink *)ca_puser(arg.chid);
struct link *plink;
@@ -720,7 +747,7 @@ done:
epicsMutexUnlock(pca->lock);
}
STATIC void getAttribEventCallback(struct event_handler_args arg)
static void getAttribEventCallback(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
struct link *plink;
@@ -771,39 +798,34 @@ STATIC void getAttribEventCallback(struct event_handler_args arg)
if(connect) connect(userPvt);
}
static void exitHandler(void *pvt)
static void dbCaTask(void *arg)
{
exitRequest = 1;
epicsEventSignal(workListEvent);
epicsEventMustWait(exitEvent);
}
int chan_count = 0;
void dbCaTask()
{
taskwdInsert(epicsThreadGetIdSelf(),NULL,NULL);
taskwdInsert(0, NULL, NULL);
SEVCHK(ca_context_create(ca_enable_preemptive_callback),
"dbCaTask calling ca_context_create");
epicsAtExit(exitHandler,0);
dbCaClientContext = ca_current_context ();
SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
"ca_add_exception_event");
/*Dont do anything until iocInit initializes database*/
while(!interruptAccept) epicsThreadSleep(.1);
epicsEventSignal(startStopEvent);
/* channel access event loop */
while (TRUE){
epicsEventMustWait(workListEvent);
while(TRUE) { /* process all requests in workList*/
do {
epicsEventMustWait(workListEvent);
} while (dbCaCtl == ctlPause);
while (TRUE) { /* process all requests in workList*/
caLink *pca;
short link_action;
int status;
if(exitRequest) break;
epicsMutexMustLock(workListLock);
if(!(pca = (caLink *)ellFirst(&workList))){/*Take off list head*/
if(!(pca = (caLink *)ellGet(&workList))){/*Take off list head*/
epicsMutexUnlock(workListLock);
if (dbCaCtl == ctlExit) goto shutdown;
break; /*workList is empty*/
}
ellDelete(&workList,&pca->node);
link_action = pca->link_action;
pca->link_action = 0;
if(link_action&CA_CLEAR_CHANNEL) --removesOutstanding;
@@ -812,7 +834,10 @@ void dbCaTask()
dbCaCallback callback;
struct link *plinkPutCallback = 0;
if(pca->chid) ca_clear_channel(pca->chid);
if(pca->chid) {
ca_clear_channel(pca->chid);
--chan_count;
}
callback = pca->putCallback;
if(callback) {
plinkPutCallback = pca->plinkPutCallback;
@@ -841,6 +866,7 @@ void dbCaTask()
printLinks(pca);
continue;
}
chan_count++;
status = ca_replace_access_rights_event(pca->chid,
accessRightsCallback);
if(status!=ECA_NORMAL) {
@@ -938,19 +964,14 @@ void dbCaTask()
printLinks(pca);
}
}
if(exitRequest) break;
}
if(exitRequest) break;
SEVCHK(ca_flush_io(),"dbCaTask");
}
/* This is not sufficient to clean up dbCa connections.
* The following should be done:
* 1) All device support that uses dbCa should clean up
* This means that all channels should be deleted
* dbCa should ckeck that this has been done
* 2) dbCa should do the following:
* a) check that all channels have been deleted.
* b) call ca_context_destroy();
*/
epicsEventSignal(exitEvent);
shutdown:
taskwdRemove(0);
if (chan_count == 0)
ca_context_destroy();
else
fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", chan_count);
epicsEventSignal(startStopEvent);
}

View File

@@ -13,6 +13,8 @@
#define INCdbCah
#include "shareLib.h"
#include "epicsTime.h"
#include "link.h"
#ifdef __cplusplus
extern "C" {
@@ -22,6 +24,9 @@ typedef void (*dbCaCallback)(void *userPvt);
epicsShareFunc void epicsShareAPI dbCaCallbackProcess(struct link *plink);
epicsShareFunc void epicsShareAPI dbCaLinkInit(void);
epicsShareFunc void epicsShareAPI dbCaRun(void);
epicsShareFunc void epicsShareAPI dbCaPause(void);
epicsShareFunc void epicsShareAPI dbCaAddLinkCallback(struct link *plink,
dbCaCallback connect,dbCaCallback monitor,void *userPvt);
#define dbCaAddLink(plink) dbCaAddLinkCallback((plink),0,0,0)

View File

@@ -1,10 +1,9 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2008 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 Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbScan.c */
@@ -28,6 +27,7 @@
#include "taskwd.h"
#include "epicsMutex.h"
#include "epicsEvent.h"
#include "epicsExit.h"
#include "epicsInterrupt.h"
#include "epicsThread.h"
#include "epicsTime.h"
@@ -49,12 +49,21 @@
#include "dbScan.h"
/* Task Control */
enum ctl {ctlRun, ctlPause, ctlExit};
/* Task Startup/Shutdown Synchronization */
static epicsEventId startStopEvent;
volatile enum ctl scanCtl;
/* SCAN ONCE */
static int onceQueueSize = 1000;
static epicsEventId onceSem;
static epicsRingPointerId onceQ;
static epicsThreadId onceTaskId;
static void *exitOnce;
/* All other scan types */
@@ -76,6 +85,8 @@ typedef struct scan_element{
typedef struct periodic_scan_list {
scan_list scan_list;
double period;
volatile enum ctl scanCtl;
epicsEventId loopEvent;
} periodic_scan_list;
static int nPeriodic = 0;
@@ -126,19 +137,56 @@ static void buildScanLists(void);
static void addToList(struct dbCommon *precord, scan_list *psl);
static void deleteFromList(struct dbCommon *precord, scan_list *psl);
static void scanShutdown(void *arg)
{
int i;
scanOnce((dbCommon *)&exitOnce);
epicsEventWait(startStopEvent);
for (i = 0; i < nPeriodic; i++) {
papPeriodic[i]->scanCtl = ctlExit;
epicsEventSignal(papPeriodic[i]->loopEvent);
epicsEventWait(startStopEvent);
}
}
long scanInit()
{
int i;
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
scanCtl = ctlPause;
initOnce();
initPeriodic();
initEvent();
buildScanLists();
for (i = 0; i < nPeriodic; i++)
spawnPeriodic(i);
epicsAtExit(scanShutdown, NULL);
return 0;
}
void scanRun(void)
{
int i;
scanCtl = ctlRun;
for (i = 0; i < nPeriodic; i++)
papPeriodic[i]->scanCtl = ctlRun;
}
void scanPause(void)
{
int i;
scanCtl = ctlPause;
for (i = 0; i < nPeriodic; i++)
papPeriodic[i]->scanCtl = ctlPause;
}
void scanAdd(struct dbCommon *precord)
{
int scan;
@@ -380,7 +428,7 @@ void post_event(int event)
int prio;
event_scan_list *pesl;
if (!interruptAccept) return; /* not awake yet */
if (scanCtl != ctlRun) return;
if (event < 0 || event >= MAX_EVENTS) {
errMessage(-1, "illegal event passed to post_event");
return;
@@ -417,7 +465,7 @@ void scanIoRequest(IOSCANPVT pioscanpvt)
{
int prio;
if (!interruptAccept) return;
if (scanCtl != ctlRun) return;
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
io_scan_list *piosl = &pioscanpvt[prio];
if (ellCount(&piosl->scan_list.list) > 0)
@@ -447,17 +495,23 @@ void scanOnce(struct dbCommon *precord)
static void onceTask(void *arg)
{
taskwdInsert(0, NULL, NULL);
epicsEventSignal(startStopEvent);
while (TRUE) {
void *precord;
epicsEventMustWait(onceSem);
while ((precord = epicsRingPointerPop(onceQ))) {
if (precord == &exitOnce) goto shutdown;
dbScanLock(precord);
dbProcess(precord);
dbScanUnlock(precord);
}
}
shutdown:
taskwdRemove(0);
epicsEventSignal(startStopEvent);
}
int scanOnceSetQueueSize(int size)
@@ -474,6 +528,8 @@ static void initOnce(void)
onceSem = epicsEventMustCreate(epicsEventEmpty);
onceTaskId = epicsThreadCreate("scanOnce", epicsThreadPriorityScanHigh,
epicsThreadGetStackSize(epicsThreadStackBig), onceTask, 0);
epicsEventWait(startStopEvent);
}
static void periodicTask(void *arg)
@@ -484,15 +540,19 @@ static void periodicTask(void *arg)
double delay;
taskwdInsert(0, NULL, NULL);
epicsEventSignal(startStopEvent);
while (TRUE) {
while (ppsl->scanCtl != ctlExit) {
epicsTimeGetCurrent(&start_time);
if (interruptAccept) scanList(&ppsl->scan_list);
if (ppsl->scanCtl == ctlRun) scanList(&ppsl->scan_list);
epicsTimeGetCurrent(&end_time);
delay = ppsl->period - epicsTimeDiffInSeconds(&end_time, &start_time);
if (delay <= 0.0) delay = 0.1;
epicsThreadSleep(delay);
epicsEventWaitWithTimeout(ppsl->loopEvent, delay);
}
taskwdRemove(0);
epicsEventSignal(startStopEvent);
}
@@ -517,6 +577,8 @@ static void initPeriodic()
ellInit(&ppsl->scan_list.list);
epicsScanDouble(pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC],
&ppsl->period);
ppsl->scanCtl = ctlPause;
ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);
papPeriodic[i] = ppsl;
}
@@ -533,6 +595,8 @@ static void spawnPeriodic(int ind)
taskName, epicsThreadPriorityScanLow + ind,
epicsThreadGetStackSize(epicsThreadStackBig),
periodicTask, (void *)ppsl);
epicsEventWait(startStopEvent);
}
static void ioeventCallback(CALLBACK *pcallback)

View File

@@ -1,10 +1,9 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2008 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 Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* $Id$
@@ -36,6 +35,8 @@ typedef struct io_scan_list *IOSCANPVT;
struct dbCommon;
epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
epicsShareFunc void post_event(int event);
epicsShareFunc void scanAdd(struct dbCommon *);

View File

@@ -52,130 +52,188 @@ epicsShareFunc int epicsShareAPI asInit (void);
#include "dbStaticLib.h"
#include "db_access_routines.h"
#include "initHooks.h"
#include "epicsTime.h"
#include "epicsExit.h"
#include "epicsSignal.h"
#define epicsExportSharedSymbols
#include "epicsRelease.h"
#include "iocInit.h"
LOCAL int initialized=FALSE;
static enum {
iocVirgin, iocBuilding, iocBuilt, iocRunning, iocPaused, iocStopped
} iocState = iocVirgin;
/* define forward references*/
LOCAL void initDrvSup(void);
LOCAL void initRecSup(void);
LOCAL void initDevSup(void);
LOCAL void finishDevSup(void);
LOCAL void initDatabase(void);
LOCAL void initialProcess(void);
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 epicsShareAPI iocInit()
int iocInit(void)
{
epicsTimeStamp timeStamp;
if (initialized) {
errlogPrintf("iocInit can only be called once\n");
return(-1);
return iocBuild() || iocRun();
}
int iocBuild(void)
{
if (iocState != iocVirgin) {
errlogPrintf("iocBuild: IOC can only be initialized once\n");
return -1;
}
if(!epicsThreadIsOkToBlock()) epicsThreadSetOkToBlock(1);
if (!epicsThreadIsOkToBlock()) {
epicsThreadSetOkToBlock(1);
}
errlogPrintf("Starting iocInit\n");
if (!pdbbase) {
errlogPrintf("iocInit aborting because No database\n");
return(-1);
errlogPrintf("iocBuild: Aborting, no database loaded!\n");
return -1;
}
epicsSignalInstallSigHupIgnore();
initHooks(initHookAtBeginning);
coreRelease();
/* After this point, further calls to iocInit() are disallowed. */
initialized = TRUE;
iocState = iocBuilding;
taskwdInit();
callbackInit();
/* let threads start */
epicsThreadSleep(.1);
initHooks(initHookAfterCallbackInit);
dbCaLinkInit(); initHooks(initHookAfterCaLinkInit);
initDrvSup(); initHooks(initHookAfterInitDrvSup);
initRecSup(); initHooks(initHookAfterInitRecSup);
initDevSup(); initHooks(initHookAfterInitDevSup);
dbCaLinkInit();
initHooks(initHookAfterCaLinkInit);
initDrvSup();
initHooks(initHookAfterInitDrvSup);
initRecSup();
initHooks(initHookAfterInitRecSup);
initDevSup();
initHooks(initHookAfterInitDevSup);
initDatabase();
dbLockInitRecords(pdbbase);
dbBkptInit();
initHooks(initHookAfterInitDatabase);
finishDevSup(); initHooks(initHookAfterFinishDevSup);
finishDevSup();
initHooks(initHookAfterFinishDevSup);
scanInit();
if(asInit()) {
errlogPrintf("iocInit: asInit Failed during initialization\n");
return(-1);
if (asInit()) {
errlogPrintf("iocBuild: asInit Failed.\n");
return -1;
}
dbPutNotifyInit();
epicsThreadSleep(.5);
initHooks(initHookAfterScanInit);
initialProcess(); initHooks(initHookAfterInitialProcess);
initialProcess();
initHooks(initHookAfterInitialProcess);
/* Enable scan tasks and some driver support functions. */
interruptAccept=TRUE; initHooks(initHookAfterInterruptAccept);
epicsThreadSleep(1.0);
dbBkptInit();
/* Start up CA server */
/* Start CA server threads */
rsrv_init();
errlogPrintf("iocInit: All initialization complete\n");
initHooks(initHookAtEnd);
return(0);
iocState = iocBuilt;
return 0;
}
LOCAL void initDrvSup(void) /* Locate all driver support entry tables */
int iocRun(void)
{
drvSup *pdrvSup;
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==0) {
errlogPrintf("iocInit: driver %s not found\n",pdrvSup->name);
continue;
}
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))();
if (pdrvet->init) {
pdrvet->init();
}
}
return;
}
LOCAL void initRecSup(void)
static void initRecSup(void)
{
dbRecordType *pdbRecordType;
recordTypeLocation *precordTypeLocation;
struct rset *prset;
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
precordTypeLocation = registryRecordTypeFind(pdbRecordType->name);
if (precordTypeLocation==0) {
if (!precordTypeLocation) {
errlogPrintf("iocInit record support for %s not found\n",
pdbRecordType->name);
continue;
}
prset = precordTypeLocation->prset;
continue;
}
prset = precordTypeLocation->prset;
pdbRecordType->prset = prset;
if(prset->init) (*prset->init)();
if (prset->init) {
prset->init();
}
}
return;
}
static long do_nothing(struct dbCommon *precord) { return 0; }
@@ -186,171 +244,182 @@ struct dsxt devSoft_DSXT = {
do_nothing
};
LOCAL devSup *pthisDevSup = NULL;
static devSup *pthisDevSup = NULL;
LOCAL void initDevSup(void)
static void initDevSup(void)
{
dbRecordType *pdbRecordType;
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==0) {
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);
}
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);
}
}
}
return;
}
void devExtend(dsxt *pdsxt)
{
if (!pthisDevSup)
errlogPrintf("devExtend() called outside of initDevSup()\n");
else
pthisDevSup->pdsxt = pdsxt;
errlogPrintf("devExtend() called outside of initDevSup()\n");
else {
pthisDevSup->pdsxt = pdsxt;
}
}
LOCAL void finishDevSup(void)
static void finishDevSup(void)
{
dbRecordType *pdbRecordType;
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);
}
for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList);
pthisDevSup;
pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) {
pdset = pthisDevSup->pdset;
if (pdset && pdset->init) {
pdset->init(1);
}
}
}
return;
}
LOCAL void initDatabase(void)
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;
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;
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 = pdbRecordNode->precord;
if (!precord->name[0]) continue;
precord->rset = prset;
precord->rdes = pdbRecordType;
precord->mlok = epicsMutexMustCreate();
ellInit(&(precord->mlis));
ellInit(&precord->mlis);
/* Reset the process active field */
precord->pact=FALSE;
precord->pact = FALSE;
/* Init DSET NOTE that result may be NULL */
pdevSup = dbDTYPtoDevSup(pdbRecordType,precord->dtyp);
pdset = (pdevSup ? pdevSup->pdset : 0);
precord->dset = pdset;
if(prset->init_record) (*prset->init_record)(precord,0);
}
/* 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);
}
}
}
/* initDatabse cont. */
/* 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;
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;
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;
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;
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);
}
}
}
}
pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
if (pdevSup) {
struct dsxt *pdsxt = pdevSup->pdsxt;
if (pdsxt && pdsxt->add_record)
(*pdsxt->add_record)(precord);
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;
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);
}
precord = pdbRecordNode->precord;
if (!precord->name[0]) continue;
precord->rset = prset;
if (prset->init_record) {
prset->init_record(precord, 1);
}
}
}
epicsAtExit(exitDatabase, NULL);
return;
}
@@ -358,23 +427,69 @@ LOCAL void initDatabase(void)
* Process database records at initialization if
* their pini (process at init) field is set.
*/
LOCAL void initialProcess(void)
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) continue;
(void)dbProcess(precord);
}
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;
}

View File

@@ -18,7 +18,10 @@
extern "C" {
#endif
epicsShareFunc int epicsShareAPI iocInit();
epicsShareFunc int iocInit(void);
epicsShareFunc int iocBuild(void);
epicsShareFunc int iocRun(void);
epicsShareFunc int iocPause(void);
#ifdef __cplusplus
}

View File

@@ -19,13 +19,33 @@
#include "miscIocRegister.h"
/* iocInit */
static const iocshFuncDef iocInitFuncDef =
{"iocInit",0,NULL};
static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL};
static void iocInitCallFunc(const iocshArgBuf *args)
{
iocInit();
}
/* iocBuild */
static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL};
static void iocBuildCallFunc(const iocshArgBuf *args)
{
iocBuild();
}
/* iocRun */
static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL};
static void iocRunCallFunc(const iocshArgBuf *args)
{
iocRun();
}
/* iocPause */
static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL};
static void iocPauseCallFunc(const iocshArgBuf *args)
{
iocPause();
}
/* coreRelease */
static const iocshFuncDef coreReleaseFuncDef = {"coreRelease",0,NULL};
static void coreReleaseCallFunc(const iocshArgBuf *args)
@@ -37,6 +57,9 @@ static void coreReleaseCallFunc(const iocshArgBuf *args)
void epicsShareAPI miscIocRegister(void)
{
iocshRegister(&iocInitFuncDef,iocInitCallFunc);
iocshRegister(&iocBuildFuncDef,iocBuildCallFunc);
iocshRegister(&iocRunFuncDef,iocRunCallFunc);
iocshRegister(&iocPauseFuncDef,iocPauseCallFunc);
iocshRegister(&coreReleaseFuncDef, coreReleaseCallFunc);
}

View File

@@ -59,7 +59,7 @@ void camsgtask ( void *pParm )
return;
}
while ( ! client->disconnect ) {
while (castcp_ctl == ctlRun && !client->disconnect) {
/*
* allow message to batch up if more are comming

View File

@@ -170,6 +170,9 @@ LOCAL void req_server (void *pParm)
priorityOfBeacons = priorityOfSelf;
}
beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
beacon_ctl = ctlPause;
tid = epicsThreadCreate ( "CAS-beacon", priorityOfBeacons,
epicsThreadGetStackSize (epicsThreadStackSmall),
rsrv_online_notify_task, 0 );
@@ -177,10 +180,17 @@ LOCAL void req_server (void *pParm)
epicsPrintf ( "CAS: unable to start beacon thread\n" );
}
epicsEventMustWait(beacon_startStopEvent);
epicsEventSignal(castcp_startStopEvent);
while (TRUE) {
struct sockaddr sockAddr;
osiSocklen_t addLen = sizeof(sockAddr);
while (castcp_ctl == ctlPause) {
epicsThreadSleep(0.1);
}
clientSock = epicsSocketAccept ( IOC_sock, &sockAddr, &addLen );
if ( clientSock == INVALID_SOCKET ) {
char sockErrBuf[64];
@@ -225,7 +235,7 @@ LOCAL void req_server (void *pParm)
/*
* rsrv_init ()
*/
int epicsShareAPI rsrv_init (void)
int rsrv_init (void)
{
epicsThreadBooleanStatus tbs;
unsigned priorityOfConnectDaemon;
@@ -270,6 +280,9 @@ int epicsShareAPI rsrv_init (void)
prsrv_cast_client = NULL;
pCaBucket = NULL;
castcp_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
castcp_ctl = ctlPause;
/*
* go down two levels so that we are below
* the TCP and event threads started on behalf
@@ -296,6 +309,26 @@ int epicsShareAPI rsrv_init (void)
epicsPrintf ( "CAS: unable to start connection request thread\n" );
}
epicsEventMustWait(castcp_startStopEvent);
return RSRV_OK;
}
int rsrv_run (void)
{
castcp_ctl = ctlRun;
casudp_ctl = ctlRun;
beacon_ctl = ctlRun;
return RSRV_OK;
}
int rsrv_pause (void)
{
beacon_ctl = ctlPause;
casudp_ctl = ctlPause;
castcp_ctl = ctlPause;
return RSRV_OK;
}

View File

@@ -211,7 +211,9 @@ void cast_server(void *pParm)
* add placeholder for the first version message should it be needed
*/
rsrv_version_reply ( prsrv_cast_client );
epicsEventSignal(casudp_startStopEvent);
while (TRUE) {
status = recvfrom (
IOC_cast_sock,
@@ -228,7 +230,7 @@ void cast_server(void *pParm)
sockErrBuf);
epicsThreadSleep(1.0);
}
else {
else if (casudp_ctl == ctlRun) {
prsrv_cast_client->recv.cnt = (unsigned) status;
prsrv_cast_client->recv.stk = 0ul;
epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv);

View File

@@ -223,18 +223,24 @@ void rsrv_online_notify_task(void *pParm)
priorityOfUDP = priorityOfSelf;
}
casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
casudp_ctl = ctlPause;
tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP,
epicsThreadGetStackSize (epicsThreadStackMedium),
cast_server, 0 );
if ( tid == 0 ) {
epicsPrintf ( "CAS: unable to start UDP daemon thread\n" );
}
while (TRUE) {
epicsEventMustWait(casudp_startStopEvent);
epicsEventSignal(beacon_startStopEvent);
while (TRUE) {
pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList);
while (pNode) {
char buf[64];
status = connect (sock, &pNode->addr.sa,
sizeof(pNode->addr.sa));
if (status<0) {
@@ -285,6 +291,11 @@ void rsrv_online_notify_task(void *pParm)
}
beaconCounter++; /* expected to overflow */
while (beacon_ctl == ctlPause) {
epicsThreadSleep(0.1);
delay = 0.02; /* Restart beacon timing if paused */
}
}
}

View File

@@ -22,11 +22,14 @@
#include "shareLib.h"
epicsShareFunc int epicsShareAPI rsrv_init (void);
epicsShareFunc int rsrv_init(void);
epicsShareFunc int rsrv_run(void);
epicsShareFunc int rsrv_pause(void);
epicsShareFunc void epicsShareAPI casr (unsigned level);
epicsShareFunc void epicsShareAPI casHostNameInitiatingCurrentThread (
epicsShareFunc void epicsShareAPI casHostNameInitiatingCurrentThread (
char * pBuf, unsigned bufSize );
epicsShareFunc void epicsShareAPI casUserNameInitiatingCurrentThread (
epicsShareFunc void epicsShareAPI casUserNameInitiatingCurrentThread (
char * pBuf, unsigned bufSize );
void casStatsFetch ( unsigned *pChanCount, unsigned *pConnCount );

View File

@@ -141,6 +141,9 @@ struct event_ext {
char modified; /* mod & ev flw ctrl enbl */
};
enum ctl {ctlRun, ctlPause, ctlExit};
/* NOTE: external used so they remember the state across loads */
#ifdef GLBLSOURCE
# define GLBLTYPE
@@ -178,6 +181,14 @@ GLBLTYPE unsigned rsrvSizeofLargeBufTCP;
GLBLTYPE void *rsrvPutNotifyFreeList;
GLBLTYPE unsigned rsrvChannelCount;
GLBLTYPE epicsEventId casudp_startStopEvent;
GLBLTYPE epicsEventId beacon_startStopEvent;
GLBLTYPE epicsEventId castcp_startStopEvent;
GLBLTYPE volatile enum ctl casudp_ctl;
GLBLTYPE volatile enum ctl beacon_ctl;
GLBLTYPE volatile enum ctl castcp_ctl;
#define CAS_HASH_TABLE_SIZE 4096
#define SEND_LOCK(CLIENT) epicsMutexMustLock((CLIENT)->lock)