EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: IOC Redundancy in R3.14.10
From: Andrew Johnson <[email protected]>
To: "Schoeneburg, Bernd" <[email protected]>
Cc: [email protected], Bob Dalesio <[email protected]>
Date: Thu, 3 Jul 2008 18:00:35 -0500
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  <20082009  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  <20082009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·