Merged dbscan-update branch
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
73
src/ioc/db/test/dbScanTest.c
Normal file
73
src/ioc/db/test/dbScanTest.c
Normal 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();
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user