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:
115
src/db/dbCa.c
115
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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user