Experimental Physics and Industrial Control System
Hi Bernd,
On Thursday 03 July 2008 09:01:13 Schoeneburg, Bernd wrote:
>
> I want to remind you that we are highly interested in base modifications
> for IOC redundancy.
As I have said to you before, the next release *will* allow you to implement
redundancy without modifying Base, although not using the patches that you
developed.
> The proposed model gives maximal freedom of usage.
>
> -- If the define (REDUNDANCY) is not done, Episc runs as usual and no
> additional object code is loaded.
I am less worried about adding a small amount of additional code than I am of
getting the plug-in interface wrong. I do not like your conditional
compilation solution because it makes the result hard to test (you have to
completely rebuild Base with the conditional in the other state to be
completely sure it compiles properly), and it requires me to ship a copy of
your rmtDrvIf.h file with Base (which makes it hard for you to make any
changes to that file).
I am attaching a file which should become part of the Redundancy Monitor and
hooks into the interfaces I am providing. You won't be able to use this yet
because I haven't committed the parallel changes that are needed to Base, but
it shows you that it will be possible to make an IOC redundant without adding
more code to Base. This source code compiles without errors on my system,
although it won't link because I don't have the rmtRegister() routine or the
rest of the RMT subsystem. It is likely that you'll have to make some
changes, but I think the majority of this code is correct.
I accept that you need to be able to control some of the internal threads
inside the IOC, and as a result I am adding a series of 'xxxPause()'
and 'xxxRun()' routines to the various internal subsystems, as well as adding
top level 'iocBuild', 'iocPause' and 'iocRun' commands (in a redundant IOC
you will use 'iocBuild' instead of 'iocInit' in the startup script, ensuring
that the server and scan tasks are not started). While doing that I have
also been cleaning up the startup and shutdown procedure for the IOC, so
there is some advantage in this work for others as well.
After some more tests early next week, I will be committing my changes to CVS
and you'll be able to try them out.
- Andrew
--
Talk is cheap. Show me the code. -- Linus Torvalds
/* Redundancy monitor plugin to the IOC taskwd */
#include <string.h>
#include "dbDefs.h"
#include "cantProceed.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "taskwd.h"
#include "dbScan.h"
#include "link.h"
#include "dbCa.h"
#include "rsrv.h"
#include "rmtDrvIf.h"
typedef struct {
epicsThreadId tid;
const char *name;
modeType mode;
} pvtType;
/*** Start/stop individual scan threads ***/
static long scanStart(pvtType *ppvt)
{
scanRunThread(ppvt->tid);
ppvt->mode = MODE_run;
return 0;
}
static long scanStop(pvtType *ppvt)
{
scanPauseThread(ppvt->tid);
ppvt->mode = MODE_stop;
return 0;
}
/*** Start/stop dbCa ***/
static long dbcaStart(pvtType *ppvt)
{
dbCaRun();
ppvt->mode = MODE_run;
return 0;
}
static long dbcaStop(pvtType *ppvt)
{
dbCaPause();
ppvt->mode = MODE_stop;
return 0;
}
/*** Start/stop castcp ***/
static long castcpStart(pvtType *ppvt)
{
castcpRun();
ppvt->mode = MODE_run;
return 0;
}
static long castcpStop(pvtType *ppvt)
{
castcpPause();
ppvt->mode = MODE_stop;
return 0;
}
/*** Start/stop casudp ***/
static long casudpStart(pvtType *ppvt)
{
casudpRun();
ppvt->mode = MODE_run;
return 0;
}
static long casudpStop(pvtType *ppvt)
{
casudpPause();
ppvt->mode = MODE_stop;
return 0;
}
/*** Start/stop beacons ***/
static long beaconStart(pvtType *ppvt)
{
beaconRun();
ppvt->mode = MODE_run;
return 0;
}
static long beaconStop(pvtType *ppvt)
{
beaconPause();
ppvt->mode = MODE_stop;
return 0;
}
/*** Generic routines ***/
static void* makePrvt(epicsThreadId tid, const char *name, rmtEntryTabType *preg)
{
pvtType *ppvt = (pvtType *)mallocMustSucceed(sizeof(pvtType), "scanMakePrvt");
ppvt->tid = tid;
ppvt->name = name;
ppvt->mode = MODE_stop;
return ppvt;
}
static long getStatus(pvtType *ppvt, drvStatusType *pstatus)
{
pstatus->mode = ppvt->mode;
pstatus->testResult = TEST_undefined;
pstatus->error = epicsThreadIsSuspended(ppvt->tid) ? INVALID_ERROR : NO_ERROR;
pstatus->updateBusy = FALSE;
pstatus->inSync = TRUE;
pstatus->activeFlag = TRUE;
return 0;
}
static long getInfo(pvtType *ppvt, char *pString, short *psize, char *preqString)
{
size_t needed;
if (!psize || !pString) return -1;
needed = epicsSnprintf(pString, *psize,
"<XML><NAME>%s</NAME><STATUS>%s</STATUS></XML>",
ppvt->name, ppvt->mode == MODE_run ? "active" : "inactive");
if (needed > (size_t)*psize) {
*psize = needed + 1;
return -1;
}
return 0;
}
/*** Thread Table ***/
const struct threadInfo {
const char *prefix;
size_t len;
const char *type;
void *(*pMakePrvt)();
RMTSUPFUN pStart;
RMTSUPFUN pStop;
RMTSUPFUN pGetStatus;
RMTSUPFUN pGetInfo;
} baseThreadInfo[] = {
{"scan", 4,
"ScanPeriodic", makePrvt,
scanStart, scanStop,
getStatus, getInfo},
{"dbCaLink", 8,
"dbCaLink", makePrvt,
dbcaStart, dbcaStop,
getStatus, getInfo},
{"CAS-TCP", 7,
"cas-tcp", makePrvt,
castcpStart, castcpStop,
getStatus, getInfo},
{"CAS-UDP", 7,
"cas-tcp", makePrvt,
casudpStart, casudpStop,
getStatus, getInfo},
{"CAS-beacon", 10,
"cas-beacon", makePrvt,
beaconStart, beaconStop,
getStatus, getInfo},
};
/* RMT registration */
static void rwtdRegister(epicsThreadId tid, const char *name, const struct threadInfo *pti)
{
rmtEntryTabType *preg = (rmtEntryTabType *)mallocMustSucceed(sizeof(rmtEntryTabType), "rwtdRegister");
preg->type = pti->type;
preg->instanceName = name;
preg->testTimeTypical = 0;
preg->pPrvt = pti->pMakePrvt(tid, name, preg);
preg->pStart = pti->pStart;
preg->pStop = pti->pStop;
preg->pTestIO = NULL;
preg->pGetStatus = pti->pGetStatus;
preg->pShutdown = NULL;
preg->pGetInfo = pti->pGetInfo;
preg->pGetUpdate = NULL;
preg->pStartUpdate = NULL;
preg->pStopUpdate = NULL;
rmtRegister(preg, NULL); /* NULL may not be legal here... */
}
/* Interface to the taskwd */
static void rtwdInsert(void *usr, epicsThreadId tid)
{
epicsThreadId self = epicsThreadGetIdSelf();
const char *name;
int i;
if (tid == self) {
name = epicsThreadGetNameSelf();
} else {
char buf[80];
epicsThreadGetName(tid, buf, sizeof(buf));
name = epicsStrDup(buf);
}
for (i=0; i<NELEMENTS(baseThreadInfo); i++) {
const struct threadInfo *pti = &baseThreadInfo[i];
if (!strncmp(name, pti->prefix, pti->len)) {
rwtdRegister(tid, name, pti);
return;
}
}
/* Thread not listed, ignore it */
if (tid != self) {
/* We allocated storage for the name */
free((char *)name);
}
}
const taskwdMonitor rtwdMonitor = {
rtwdInsert, NULL, NULL
};
void rtwdInit(void)
{
taskwdMonitorAdd(&rtwdMonitor, NULL);
}
- Replies:
- Re: IOC Redundancy in R3.14.10 Bernd Schoeneburg
- Re: IOC Redundancy in R3.14.10 Artem Kazakov
- References:
- IOC Redundancy in R3.14.10 Schoeneburg, Bernd
- Navigate by Date:
- Prev:
IOC Redundancy in R3.14.10 Schoeneburg, Bernd
- Next:
Re: IOC Redundancy in R3.14.10 Bernd Schoeneburg
- Index:
2002
2003
2004
2005
2006
2007
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
IOC Redundancy in R3.14.10 Schoeneburg, Bernd
- Next:
Re: IOC Redundancy in R3.14.10 Bernd Schoeneburg
- Index:
2002
2003
2004
2005
2006
2007
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024