Merged dbscan-update branch

This commit is contained in:
Andrew Johnson
2015-02-17 14:12:38 -06:00
7 changed files with 231 additions and 73 deletions

View File

@@ -629,6 +629,31 @@ long dbCaGetUnits(const struct link *plink,
return gotAttributes ? 0 : -1;
}
static void scanComplete(void *raw, dbCommon *prec)
{
caLink *pca = raw;
epicsMutexMustLock(pca->lock);
if(pca->scanningOnce==0)
errlogPrintf("dbCa.c complete callback w/ scanningOnce==0\n");
else if(--pca->scanningOnce){
/* another scan is queued */
if(scanOnceCallback(prec, scanComplete, raw)) {
errlogPrintf("dbCa.c failed to re-queue scanOnce\n");
}
}
epicsMutexUnlock(pca->lock);
}
/* must be called with pca->lock held */
static void scanLinkOnce(dbCommon *prec, caLink *pca) {
if(pca->scanningOnce==0 && scanOnceCallback(prec, scanComplete, pca)) {
errlogPrintf("dbCa.c failed to queue scanOnce\n");
}
if(pca->scanningOnce<5)
pca->scanningOnce++;
/* else too many scans queued */
}
static void connectionCallback(struct connection_handler_args arg)
{
caLink *pca;
@@ -649,7 +674,7 @@ static void connectionCallback(struct connection_handler_args arg)
if (precord &&
((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
scanOnce(precord);
scanLinkOnce(precord, pca);
goto done;
}
pca->hasReadAccess = ca_read_access(arg.chid);
@@ -762,7 +787,7 @@ static void eventCallback(struct event_handler_args arg)
if ((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0))
scanOnce(precord);
scanLinkOnce(precord, pca);
}
done:
epicsMutexUnlock(pca->lock);
@@ -835,7 +860,7 @@ static void accessRightsCallback(struct access_rights_handler_args arg)
if (precord &&
((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
scanOnce(precord);
scanLinkOnce(precord, pca);
done:
epicsMutexUnlock(pca->lock);
}

View File

@@ -38,56 +38,57 @@
typedef struct caLink
{
ELLNODE node;
epicsMutexId lock;
struct link *plink;
char *pvname;
chid chid;
short link_action;
/* The following have new values after each data event*/
epicsEnum16 sevr;
epicsEnum16 stat;
epicsTimeStamp timeStamp;
/* The following have values after connection*/
short dbrType;
long nelements;
char hasReadAccess;
char hasWriteAccess;
char isConnected;
char gotFirstConnection;
/* The following are for dbCaAddLinkCallback */
dbCaCallback connect;
dbCaCallback monitor;
void *userPvt;
/* The following are for write request */
short putType;
dbCaCallback putCallback;
void *putUserPvt;
struct link *plinkPutCallback;
/* The following are for access to additional attributes*/
char gotAttributes;
dbCaCallback getAttributes;
void *getAttributesPvt;
/* The following have values after getAttribEventCallback*/
double controlLimits[2];
double displayLimits[2];
double alarmLimits[4];
short precision;
char units[MAX_UNITS_SIZE]; /* units of value */
/* The following are for handling data*/
void *pgetNative;
char *pgetString;
void *pputNative;
char *pputString;
char gotInNative;
char gotInString;
char gotOutNative;
char gotOutString;
char newOutNative;
char newOutString;
/* The following are for dbcar*/
unsigned long nDisconnect;
unsigned long nNoWrite; /*only modified by dbCaPutLink*/
ELLNODE node;
epicsMutexId lock;
struct link *plink;
char *pvname;
chid chid;
short link_action;
/* The following have new values after each data event*/
epicsEnum16 sevr;
epicsEnum16 stat;
epicsTimeStamp timeStamp;
/* The following have values after connection*/
short dbrType;
long nelements;
char hasReadAccess;
char hasWriteAccess;
char isConnected;
char gotFirstConnection;
/* The following are for dbCaAddLinkCallback */
dbCaCallback connect;
dbCaCallback monitor;
void *userPvt;
/* The following are for write request */
short putType;
dbCaCallback putCallback;
void *putUserPvt;
struct link *plinkPutCallback;
/* The following are for access to additional attributes*/
char gotAttributes;
dbCaCallback getAttributes;
void *getAttributesPvt;
/* The following have values after getAttribEventCallback*/
double controlLimits[2];
double displayLimits[2];
double alarmLimits[4];
short precision;
char units[MAX_UNITS_SIZE]; /* units of value */
/* The following are for handling data*/
void *pgetNative;
char *pgetString;
void *pputNative;
char *pputString;
char gotInNative;
char gotInString;
char gotOutNative;
char gotOutString;
char newOutNative;
char newOutString;
unsigned char scanningOnce;
/* The following are for dbcar*/
unsigned long nDisconnect;
unsigned long nNoWrite; /*only modified by dbCaPutLink*/
}caLink;
#endif /* INC_dbCaPvt_H */

View File

@@ -26,10 +26,9 @@
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsExit.h"
#include "epicsInterrupt.h"
#include "epicsMutex.h"
#include "epicsPrint.h"
#include "epicsRingPointer.h"
#include "epicsRingBytes.h"
#include "epicsStdio.h"
#include "epicsStdlib.h"
#include "epicsString.h"
@@ -64,7 +63,7 @@ static volatile enum ctl scanCtl;
static int onceQueueSize = 1000;
static epicsEventId onceSem;
static epicsRingPointerId onceQ;
static epicsRingBytesId onceQ;
static epicsThreadId onceTaskId;
static void *exitOnce;
@@ -172,7 +171,7 @@ void scanShutdown(void)
deletePeriodic();
ioscanDestroy();
epicsRingPointerDelete(onceQ);
epicsRingBytesDelete(onceQ);
epicsEventDestroy(startStopEvent);
epicsEventDestroy(onceSem);
@@ -456,7 +455,9 @@ event_list *eventNameToHandle(const char *eventname)
if (strcmp(pel->event_name, eventname) == 0) break;
}
if (pel == NULL) {
pel = dbCalloc(1, sizeof(event_list));
pel = calloc(1, sizeof(event_list));
if (!pel)
goto done;
strcpy(pel->event_name, eventname);
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
@@ -474,6 +475,7 @@ event_list *eventNameToHandle(const char *eventname)
pevent_list[e] = pel;
}
}
done:
epicsMutexUnlock(event_lock);
return pel;
}
@@ -580,6 +582,28 @@ unsigned int scanIoRequest(IOSCANPVT piosh)
return queued;
}
unsigned int scanIoImmediate(IOSCANPVT piosh, int prio)
{
io_scan_list *piosl;
if (prio<0 || prio>=NUM_CALLBACK_PRIORITIES)
return S_db_errArg;
else if (scanCtl != ctlRun)
return 0;
piosl = &piosh->iosl[prio];
if (ellCount(&piosl->scan_list.list) == 0)
return 0;
scanList(&piosl->scan_list);
if (piosh->cb)
piosh->cb(piosh->arg, piosh, prio);
return 1 << prio;
}
/* May not be called while a scan request is queued or running */
void scanIoSetComplete(IOSCANPVT piosh, io_scan_complete cb, void *arg)
{
@@ -587,15 +611,27 @@ void scanIoSetComplete(IOSCANPVT piosh, io_scan_complete cb, void *arg)
piosh->arg = arg;
}
void scanOnce(struct dbCommon *precord)
int scanOnce(struct dbCommon *precord) {
return scanOnceCallback(precord, NULL, NULL);
}
typedef struct {
struct dbCommon *prec;
once_complete cb;
void *usr;
} onceEntry;
int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr)
{
static int newOverflow = TRUE;
int lockKey;
onceEntry ent;
int pushOK;
lockKey = epicsInterruptLock();
pushOK = epicsRingPointerPush(onceQ, precord);
epicsInterruptUnlock(lockKey);
ent.prec = precord;
ent.cb = cb;
ent.usr = usr;
pushOK = epicsRingBytesPut(onceQ, (void*)&ent, sizeof(ent));
if (!pushOK) {
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
@@ -604,6 +640,8 @@ void scanOnce(struct dbCommon *precord)
newOverflow = TRUE;
}
epicsEventSignal(onceSem);
return !pushOK;
}
static void onceTask(void *arg)
@@ -612,14 +650,24 @@ static void onceTask(void *arg)
epicsEventSignal(startStopEvent);
while (TRUE) {
void *precord;
epicsEventMustWait(onceSem);
while ((precord = epicsRingPointerPop(onceQ))) {
if (precord == &exitOnce) goto shutdown;
dbScanLock(precord);
dbProcess(precord);
dbScanUnlock(precord);
while(1) {
onceEntry ent;
int bytes = epicsRingBytesGet(onceQ, (void*)&ent, sizeof(ent));
if(bytes==0)
break;
if(bytes!=sizeof(ent)) {
errlogPrintf("onceTask: received incomplete %d of %u\n",
bytes, (unsigned)sizeof(ent));
continue; /* what to do? */
} else if (ent.prec == (void*)&exitOnce) goto shutdown;
dbScanLock(ent.prec);
dbProcess(ent.prec);
dbScanUnlock(ent.prec);
if(ent.cb)
ent.cb(ent.usr, ent.prec);
}
}
@@ -636,7 +684,7 @@ int scanOnceSetQueueSize(int size)
static void initOnce(void)
{
if ((onceQ = epicsRingPointerCreate(onceQueueSize)) == NULL) {
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
cantProceed("initOnce: Ring buffer create failed\n");
}
onceSem = epicsEventMustCreate(epicsEventEmpty);

View File

@@ -39,10 +39,11 @@ struct ioscan_head;
typedef struct ioscan_head *IOSCANPVT;
typedef struct event_list *EVENTPVT;
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
struct dbCommon;
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
typedef void (*once_complete)(void *usr, struct dbCommon*);
epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
@@ -54,7 +55,8 @@ epicsShareFunc void post_event(int event) EPICS_DEPRECATED;
epicsShareFunc void scanAdd(struct dbCommon *);
epicsShareFunc void scanDelete(struct dbCommon *);
epicsShareFunc double scanPeriod(int scan);
epicsShareFunc void scanOnce(struct dbCommon *);
epicsShareFunc int scanOnce(struct dbCommon *);
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
epicsShareFunc int scanOnceSetQueueSize(int size);
/*print periodic lists*/
@@ -68,6 +70,7 @@ epicsShareFunc int scanpiol(void);
epicsShareFunc void scanIoInit(IOSCANPVT *ppios);
epicsShareFunc unsigned int scanIoRequest(IOSCANPVT pios);
epicsShareFunc unsigned int scanIoImmediate(IOSCANPVT pios, int prio);
epicsShareFunc void scanIoSetComplete(IOSCANPVT, io_scan_complete, void *usr);
#ifdef __cplusplus

View File

@@ -28,6 +28,12 @@ testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
PROD_LIBS = dbTestIoc dbCore ca Com
TESTPROD_HOST += dbScanTest
dbScanTest_SRCS += dbScanTest.c
dbScanTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbScanTest.c
TESTS += dbScanTest
TESTPROD_HOST += dbShutdownTest
dbShutdownTest_SRCS += dbShutdownTest.c
dbShutdownTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp

View File

@@ -0,0 +1,73 @@
/*************************************************************************\
* Copyright (c) 2015 Brookhaven Science Assoc. as operator of Brookhaven
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Michael Davidsaver <mdavidsaver@bnl.gov>
*/
#include <string.h>
#include "dbScan.h"
#include "epicsEvent.h"
#include "dbUnitTest.h"
#include "testMain.h"
#include "dbAccess.h"
#include "errlog.h"
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
static epicsEventId waiter;
static int called;
static dbCommon *prec;
static void onceComp(void *junk, dbCommon *prec)
{
testOk1(junk==(void*)&waiter);
testOk1(strcmp(prec->name, "reca")==0);
called = 1;
epicsEventMustTrigger(waiter);
}
static void testOnce(void)
{
testDiag("check scanOnceCallback() callback");
waiter = epicsEventMustCreate(epicsEventError);
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
dbTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("dbLockTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
prec = testdbRecordPtr("reca");
testDiag("scanOnce %s", prec->name);
scanOnceCallback(prec, onceComp, &waiter);
testDiag("Waiting");
epicsEventMustWait(waiter);
testOk1(called==1);
if(!called)
testSkip(2, "callback failed to run");
testIocShutdownOk();
testdbCleanup();
epicsEventDestroy(waiter);
}
MAIN(dbScanTest)
{
testPlan(3);
testOnce();
return testDone();
}

View File

@@ -22,6 +22,7 @@ int callbackParallelTest(void);
int dbStateTest(void);
int dbCaStatsTest(void);
int dbShutdownTest(void);
int dbScanTest(void);
int scanIoTest(void);
int dbLockTest(void);
int dbPutLinkTest(void);
@@ -40,6 +41,7 @@ void epicsRunDbTests(void)
runTest(dbStateTest);
runTest(dbCaStatsTest);
runTest(dbShutdownTest);
runTest(dbScanTest);
runTest(scanIoTest);
runTest(dbLockTest);
runTest(dbPutLinkTest);