diff --git a/src/db/dbCa.c b/src/db/dbCa.c index 479eb056a..2428edcfc 100644 --- a/src/db/dbCa.c +++ b/src/db/dbCa.c @@ -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); } diff --git a/src/db/dbCa.h b/src/db/dbCa.h index 8aab33c1c..c919c18de 100644 --- a/src/db/dbCa.h +++ b/src/db/dbCa.h @@ -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) diff --git a/src/db/dbScan.c b/src/db/dbScan.c index d30350cb9..dd8be9c57 100644 --- a/src/db/dbScan.c +++ b/src/db/dbScan.c @@ -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) diff --git a/src/db/dbScan.h b/src/db/dbScan.h index c26c7ae70..03c1a7c3d 100644 --- a/src/db/dbScan.h +++ b/src/db/dbScan.h @@ -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 *); diff --git a/src/misc/iocInit.c b/src/misc/iocInit.c index 3f62a07c3..8a2346b4b 100644 --- a/src/misc/iocInit.c +++ b/src/misc/iocInit.c @@ -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; jno_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; +} diff --git a/src/misc/iocInit.h b/src/misc/iocInit.h index aa8ba3bae..7464f9217 100644 --- a/src/misc/iocInit.h +++ b/src/misc/iocInit.h @@ -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 } diff --git a/src/misc/miscIocRegister.c b/src/misc/miscIocRegister.c index 2de0c092b..0d482f7cf 100644 --- a/src/misc/miscIocRegister.c +++ b/src/misc/miscIocRegister.c @@ -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); } diff --git a/src/rsrv/camsgtask.c b/src/rsrv/camsgtask.c index 03df66b11..a5133caf6 100644 --- a/src/rsrv/camsgtask.c +++ b/src/rsrv/camsgtask.c @@ -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 diff --git a/src/rsrv/caservertask.c b/src/rsrv/caservertask.c index a171459f3..f632195e5 100644 --- a/src/rsrv/caservertask.c +++ b/src/rsrv/caservertask.c @@ -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; } diff --git a/src/rsrv/cast_server.c b/src/rsrv/cast_server.c index 4ad751ecd..29fd2adfc 100644 --- a/src/rsrv/cast_server.c +++ b/src/rsrv/cast_server.c @@ -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); diff --git a/src/rsrv/online_notify.c b/src/rsrv/online_notify.c index fac506879..34d91a7e6 100644 --- a/src/rsrv/online_notify.c +++ b/src/rsrv/online_notify.c @@ -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 */ + } } } diff --git a/src/rsrv/rsrv.h b/src/rsrv/rsrv.h index d690ea8d6..d2ad382fd 100644 --- a/src/rsrv/rsrv.h +++ b/src/rsrv/rsrv.h @@ -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 ); diff --git a/src/rsrv/server.h b/src/rsrv/server.h index 876f075f9..4df62aef8 100644 --- a/src/rsrv/server.h +++ b/src/rsrv/server.h @@ -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)