Merge branch '7.0' (after codeathon 2023) into PSI-7.0

This commit is contained in:
2023-03-29 13:36:52 +02:00
36 changed files with 662 additions and 181 deletions

View File

@@ -58,6 +58,7 @@ typedef struct cbQueueSet {
int shutdown; // use atomic
int threadsConfigured;
int threadsRunning;
epicsThreadId *threads;
} cbQueueSet;
static cbQueueSet callbackQueue[NUM_CALLBACK_PRIORITIES];
@@ -242,11 +243,15 @@ void callbackStop(void)
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
int j;
while (epicsAtomicGetIntT(&mySet->threadsRunning)) {
epicsEventSignal(mySet->semWakeUp);
epicsEventWaitWithTimeout(startStopEvent, 0.1);
}
for(j=0; j<mySet->threadsConfigured; j++) {
epicsThreadMustJoin(mySet->threads[j]);
}
}
}
@@ -266,6 +271,8 @@ void callbackCleanup(void)
mySet->semWakeUp = NULL;
epicsRingPointerDelete(mySet->queue);
mySet->queue = NULL;
free(mySet->threads);
mySet->threads = NULL;
}
epicsTimerQueueRelease(timerQueue);
@@ -297,17 +304,25 @@ void callbackInit(void)
cantProceed("epicsRingPointerLockedCreate failed for %s\n",
threadNamePrefix[i]);
callbackQueue[i].queueOverflow = FALSE;
if (callbackQueue[i].threadsConfigured == 0)
callbackQueue[i].threadsConfigured = callbackThreadsDefault;
callbackQueue[i].threads = callocMustSucceed(callbackQueue[i].threadsConfigured,
sizeof(*callbackQueue[i].threads),
"callbackInit");
for (j = 0; j < callbackQueue[i].threadsConfigured; j++) {
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = threadPriority[i];
opts.stackSize = epicsThreadStackBig;
if (callbackQueue[i].threadsConfigured > 1 )
sprintf(threadName, "%s-%d", threadNamePrefix[i], j);
else
strcpy(threadName, threadNamePrefix[i]);
tid = epicsThreadCreate(threadName, threadPriority[i],
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)callbackTask, &priorityValue[i]);
callbackQueue[i].threads[j] = tid = epicsThreadCreateOpt(threadName,
(EPICSTHREADFUNC)callbackTask, &priorityValue[i], &opts);
if (tid == 0) {
cantProceed("Failed to spawn callback thread %s\n", threadName);
} else {

View File

@@ -154,7 +154,7 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
const char *pstr = plink->value.constantStr;
size_t len;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
len = strlen(pstr);
@@ -181,7 +181,7 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
const char *pstr = plink->value.constantStr;
long status;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
status = dbLSConvertJSON(pstr, pbuffer, size, plen);
@@ -197,7 +197,7 @@ static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
const char *pstr = plink->value.constantStr;
long status;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
/* Choice values must be numeric */

View File

@@ -76,6 +76,7 @@ struct event_que {
unsigned short quota; /* the number of assigned entries*/
unsigned short nDuplicates; /* N events duplicated on this q */
unsigned short nCanceled; /* the number of canceled entries */
unsigned possibleStall;
};
struct event_user {
@@ -934,6 +935,7 @@ void db_post_single_event (dbEventSubscription event)
static int event_read ( struct event_que *ev_que )
{
db_field_log *pfl;
int notifiedRemaining = 0;
void ( *user_sub ) ( void *user_arg, struct dbChannel *chan,
int eventsRemaining, db_field_log *pfl );
@@ -955,6 +957,7 @@ static int event_read ( struct event_que *ev_que )
while ( ev_que->evque[ev_que->getix] != EVENTQEMPTY ) {
struct evSubscrip *pevent = ev_que->evque[ev_que->getix];
int eventsRemaining;
pfl = ev_que->valque[ev_que->getix];
if ( pevent == &canceledEvent ) {
@@ -977,6 +980,7 @@ static int event_read ( struct event_que *ev_que )
event_remove ( ev_que, ev_que->getix, EVENTQEMPTY );
ev_que->getix = RNGINC ( ev_que->getix );
eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY && !ev_que->nCanceled;
/*
* create a local copy of the call back parameters while
@@ -1009,7 +1013,8 @@ static int event_read ( struct event_que *ev_que )
if (pfl) {
/* Issue user callback */
( *user_sub ) ( pevent->user_arg, pevent->chan,
ev_que->evque[ev_que->getix] != EVENTQEMPTY, pfl );
eventsRemaining, pfl );
notifiedRemaining = eventsRemaining;
}
LOCKEVQUE (ev_que);
@@ -1036,6 +1041,11 @@ static int event_read ( struct event_que *ev_que )
db_delete_field_log(pfl);
}
if(notifiedRemaining && !ev_que->possibleStall) {
ev_que->possibleStall = 1;
errlogPrintf(ERL_WARNING " dbEvent possible queue stall\n");
}
UNLOCKEVQUE (ev_que);
return DB_EVENT_OK;

View File

@@ -168,9 +168,13 @@ void scanStop(void)
epicsEventSignal(ppsl->loopEvent);
epicsEventWait(startStopEvent);
}
for (i = 0; i < nPeriodic; i++) {
epicsThreadMustJoin(periodicTaskId[i]);
}
scanOnce((dbCommon *)&exitOnce);
epicsEventWait(startStopEvent);
epicsThreadMustJoin(onceTaskId);
}
void scanCleanup(void)
@@ -761,14 +765,16 @@ void scanOnceQueueShow(const int reset)
static void initOnce(void)
{
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = epicsThreadPriorityScanLow + nPeriodic;
opts.stackSize = epicsThreadStackBig;
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
cantProceed("initOnce: Ring buffer create failed\n");
}
if(!onceSem)
onceSem = epicsEventMustCreate(epicsEventEmpty);
onceTaskId = epicsThreadCreate("scanOnce",
epicsThreadPriorityScanLow + nPeriodic,
epicsThreadGetStackSize(epicsThreadStackBig), onceTask, 0);
onceTaskId = epicsThreadCreateOpt("scanOnce", onceTask, 0, &opts);
epicsEventWait(startStopEvent);
}
@@ -932,14 +938,16 @@ static void spawnPeriodic(int ind)
{
periodic_scan_list *ppsl = papPeriodic[ind];
char taskName[20];
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = epicsThreadPriorityScanLow + ind;
opts.stackSize = epicsThreadStackBig;
if (!ppsl) return;
sprintf(taskName, "scan-%g", ppsl->period);
periodicTaskId[ind] = epicsThreadCreate(
taskName, epicsThreadPriorityScanLow + ind,
epicsThreadGetStackSize(epicsThreadStackBig),
periodicTask, (void *)ppsl);
periodicTaskId[ind] = epicsThreadCreateOpt(
taskName, periodicTask, (void *)ppsl, &opts);
epicsEventWait(startStopEvent);
}

View File

@@ -339,7 +339,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
break;
}
#define OP(DBR,Type,pat) case DBR: {Type expect = *(Type*)pbuf, actual = *(Type*)gbuf; assert(vSize==sizeof(Type)); match &= expect==actual; \
if(expect!=actual) testDiag("[%lu] expected=" pat " actual=" pat, n, expect, actual); break;}
if(expect!=actual) {testDiag("[%lu] expected=" pat " actual=" pat, n, expect, actual);} break;}
OP(DBR_CHAR, char, "%c");
OP(DBR_UCHAR, unsigned char, "%u");

View File

@@ -111,7 +111,8 @@ typedef struct inputFile{
static ELLLIST inputFileList = ELLLIST_INIT;
static inputFile *pinputFileNow = NULL;
static DBBASE *pdbbase = NULL;
/* The DBBASE most recently allocated/used by dbReadCOM() */
static DBBASE *savedPdbbase = NULL;
typedef struct tempListNode {
ELLNODE node;
@@ -233,15 +234,15 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
}
if(*ppdbbase == 0) *ppdbbase = dbAllocBase();
pdbbase = *ppdbbase;
savedPdbbase = *ppdbbase;
if(path && strlen(path)>0) {
dbPath(pdbbase,path);
dbPath(savedPdbbase,path);
} else {
penv = getenv("EPICS_DB_INCLUDE_PATH");
if(penv) {
dbPath(pdbbase,penv);
dbPath(savedPdbbase,penv);
} else {
dbPath(pdbbase,".");
dbPath(savedPdbbase,".");
}
}
my_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
@@ -271,7 +272,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
FILE *fp1 = 0;
if (pinputFile->filename)
pinputFile->path = dbOpenFile(pdbbase, pinputFile->filename, &fp1);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp1);
if (!pinputFile->filename || !fp1) {
errPrintf(0, __FILE__, __LINE__,
"dbRead opening file %s\n",pinputFile->filename);
@@ -297,13 +298,13 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
while (ellCount(&tempList))
popFirstTemp(); /* Memory leak on parser failure */
dbFreePath(pdbbase);
dbFreePath(savedPdbbase);
if(!status) { /*add RTYP and VERS as an attribute */
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
long localStatus;
dbInitEntry(pdbbase,pdbEntry);
dbInitEntry(savedPdbbase,pdbEntry);
localStatus = dbFirstRecordType(pdbEntry);
while(!localStatus) {
localStatus = dbPutRecordAttribute(pdbEntry,"RTYP",
@@ -323,7 +324,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
cleanup:
if(dbRecordsAbcSorted) {
ELLNODE *cur;
for(cur = ellFirst(&pdbbase->recordTypeList); cur; cur=ellNext(cur))
for(cur = ellFirst(&savedPdbbase->recordTypeList); cur; cur=ellNext(cur))
{
dbRecordType *rtype = CONTAINER(cur, dbRecordType, node);
@@ -416,12 +417,12 @@ static void dbIncludePrint(void)
static void dbPathCmd(char *path)
{
dbPath(pdbbase,path);
dbPath(savedPdbbase,path);
}
static void dbAddPathCmd(char *path)
{
dbAddPath(pdbbase,path);
dbAddPath(savedPdbbase,path);
}
static void dbIncludeNew(char *filename)
@@ -431,7 +432,7 @@ static void dbIncludeNew(char *filename)
pinputFile = dbCalloc(1,sizeof(inputFile));
pinputFile->filename = macEnvExpand(filename);
pinputFile->path = dbOpenFile(pdbbase, pinputFile->filename, &fp);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp);
if (!fp) {
epicsPrintf("Can't open include file \"%s\"\n", filename);
yyerror(NULL);
@@ -453,7 +454,7 @@ static void dbMenuHead(char *name)
yyerrorAbort("dbMenuHead: Menu name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->menuList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->menuList);
if(pgphentry) {
duplicate = TRUE;
return;
@@ -501,14 +502,14 @@ static void dbMenuBody(void)
}
if(ellCount(&tempList)) yyerrorAbort("dbMenuBody: tempList not empty");
/* Add menu in sorted order */
pMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
pMenu = (dbMenu *)ellFirst(&savedPdbbase->menuList);
while(pMenu && strcmp(pMenu->name,pnewMenu->name) >0 )
pMenu = (dbMenu *)ellNext(&pMenu->node);
if(pMenu)
ellInsert(&pdbbase->menuList,ellPrevious(&pMenu->node),&pnewMenu->node);
ellInsert(&savedPdbbase->menuList,ellPrevious(&pMenu->node),&pnewMenu->node);
else
ellAdd(&pdbbase->menuList,&pnewMenu->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewMenu->name,&pdbbase->menuList);
ellAdd(&savedPdbbase->menuList,&pnewMenu->node);
pgphentry = gphAdd(savedPdbbase->pgpHash,pnewMenu->name,&savedPdbbase->menuList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
@@ -525,14 +526,14 @@ static void dbRecordtypeHead(char *name)
yyerrorAbort("dbRecordtypeHead: Recordtype name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->recordTypeList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->recordTypeList);
if(pgphentry) {
duplicate = TRUE;
return;
}
pdbRecordType = dbCalloc(1,sizeof(dbRecordType));
pdbRecordType->name = epicsStrDup(name);
if (pdbbase->loadCdefs) ellInit(&pdbRecordType->cdefList);
if (savedPdbbase->loadCdefs) ellInit(&pdbRecordType->cdefList);
if(ellCount(&tempList))
yyerrorAbort("dbRecordtypeHead tempList not empty");
allocTemp(pdbRecordType);
@@ -564,13 +565,13 @@ static short findOrAddGuiGroup(const char *name)
{
dbGuiGroup *pdbGuiGroup;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
pgphentry = gphFind(savedPdbbase->pgpHash, name, &savedPdbbase->guiGroupList);
if (!pgphentry) {
pdbGuiGroup = dbCalloc(1,sizeof(dbGuiGroup));
pdbGuiGroup->name = epicsStrDup(name);
ellAdd(&pdbbase->guiGroupList, &pdbGuiGroup->node);
pdbGuiGroup->key = ellCount(&pdbbase->guiGroupList);
pgphentry = gphAdd(pdbbase->pgpHash, pdbGuiGroup->name, &pdbbase->guiGroupList);
ellAdd(&savedPdbbase->guiGroupList, &pdbGuiGroup->node);
pdbGuiGroup->key = ellCount(&savedPdbbase->guiGroupList);
pgphentry = gphAdd(savedPdbbase->pgpHash, pdbGuiGroup->name, &savedPdbbase->guiGroupList);
pgphentry->userPvt = pdbGuiGroup;
}
return ((dbGuiGroup *)pgphentry->userPvt)->key;
@@ -653,8 +654,8 @@ static void dbRecordtypeFieldItem(char *name,char *value)
return;
}
if(strcmp(name,"menu")==0) {
pdbFldDes->ftPvt = (dbMenu *)dbFindMenu(pdbbase,value);
if(!pdbbase->ignoreMissingMenus && !pdbFldDes->ftPvt)
pdbFldDes->ftPvt = (dbMenu *)dbFindMenu(savedPdbbase,value);
if(!savedPdbbase->ignoreMissingMenus && !pdbFldDes->ftPvt)
yyerrorAbort("menu not found");
return;
}
@@ -672,7 +673,7 @@ static void dbRecordtypeCdef(char *text) {
tempListNode *ptempListNode;
dbRecordType *pdbRecordType;
if (!pdbbase->loadCdefs || duplicate) return;
if (!savedPdbbase->loadCdefs || duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
@@ -781,14 +782,14 @@ static void dbRecordtypeBody(void)
ellInit(&pdbRecordType->attributeList);
ellInit(&pdbRecordType->recList);
ellInit(&pdbRecordType->devList);
pgphentry = gphAdd(pdbbase->pgpHash,pdbRecordType->name,
&pdbbase->recordTypeList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pdbRecordType->name,
&savedPdbbase->recordTypeList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
pgphentry->userPvt = pdbRecordType;
}
ellAdd(&pdbbase->recordTypeList,&pdbRecordType->node);
ellAdd(&savedPdbbase->recordTypeList,&pdbRecordType->node);
}
static void dbDevice(char *recordtype,char *linktype,
@@ -798,7 +799,7 @@ static void dbDevice(char *recordtype,char *linktype,
dbRecordType *pdbRecordType;
GPHENTRY *pgphentry;
int i,link_type;
pgphentry = gphFind(pdbbase->pgpHash,recordtype,&pdbbase->recordTypeList);
pgphentry = gphFind(savedPdbbase->pgpHash,recordtype,&savedPdbbase->recordTypeList);
if(!pgphentry) {
epicsPrintf("Record type \"%s\" not found for device \"%s\"\n",
recordtype, choicestring);
@@ -819,7 +820,7 @@ static void dbDevice(char *recordtype,char *linktype,
return;
}
pdbRecordType = (dbRecordType *)pgphentry->userPvt;
pgphentry = gphFind(pdbbase->pgpHash,choicestring,&pdbRecordType->devList);
pgphentry = gphFind(savedPdbbase->pgpHash,choicestring,&pdbRecordType->devList);
if(pgphentry) {
return;
}
@@ -827,7 +828,7 @@ static void dbDevice(char *recordtype,char *linktype,
pdevSup->name = epicsStrDup(dsetname);
pdevSup->choice = epicsStrDup(choicestring);
pdevSup->link_type = link_type;
pgphentry = gphAdd(pdbbase->pgpHash,pdevSup->choice,&pdbRecordType->devList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pdevSup->choice,&pdbRecordType->devList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
@@ -845,18 +846,18 @@ static void dbDriver(char *name)
yyerrorAbort("dbDriver: Driver name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->drvList);
if(pgphentry) {
return;
}
pdrvSup = dbCalloc(1,sizeof(drvSup));
pdrvSup->name = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,pdrvSup->name,&pdbbase->drvList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pdrvSup->name,&savedPdbbase->drvList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pdrvSup;
ellAdd(&pdbbase->drvList,&pdrvSup->node);
ellAdd(&savedPdbbase->drvList,&pdrvSup->node);
}
static void dbLinkType(char *name, char *jlif_name)
@@ -864,19 +865,19 @@ static void dbLinkType(char *name, char *jlif_name)
linkSup *pLinkSup;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->linkList);
pgphentry = gphFind(savedPdbbase->pgpHash, name, &savedPdbbase->linkList);
if (pgphentry) {
return;
}
pLinkSup = dbCalloc(1,sizeof(linkSup));
pLinkSup->name = epicsStrDup(name);
pLinkSup->jlif_name = epicsStrDup(jlif_name);
pgphentry = gphAdd(pdbbase->pgpHash, pLinkSup->name, &pdbbase->linkList);
pgphentry = gphAdd(savedPdbbase->pgpHash, pLinkSup->name, &savedPdbbase->linkList);
if (!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pLinkSup;
ellAdd(&pdbbase->linkList, &pLinkSup->node);
ellAdd(&savedPdbbase->linkList, &pLinkSup->node);
}
static void dbRegistrar(char *name)
@@ -888,18 +889,18 @@ static void dbRegistrar(char *name)
yyerrorAbort("dbRegistrar: Registrar name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->registrarList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->registrarList);
if(pgphentry) {
return;
}
ptext = dbCalloc(1,sizeof(dbText));
ptext->text = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,ptext->text,&pdbbase->registrarList);
pgphentry = gphAdd(savedPdbbase->pgpHash,ptext->text,&savedPdbbase->registrarList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = ptext;
ellAdd(&pdbbase->registrarList,&ptext->node);
ellAdd(&savedPdbbase->registrarList,&ptext->node);
}
static void dbFunction(char *name)
@@ -911,18 +912,18 @@ static void dbFunction(char *name)
yyerrorAbort("dbFunction: Function name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->functionList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->functionList);
if(pgphentry) {
return;
}
ptext = dbCalloc(1,sizeof(dbText));
ptext->text = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,ptext->text,&pdbbase->functionList);
pgphentry = gphAdd(savedPdbbase->pgpHash,ptext->text,&savedPdbbase->functionList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = ptext;
ellAdd(&pdbbase->functionList,&ptext->node);
ellAdd(&savedPdbbase->functionList,&ptext->node);
}
static void dbVariable(char *name, char *type)
@@ -934,19 +935,19 @@ static void dbVariable(char *name, char *type)
yyerrorAbort("dbVariable: Variable name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->variableList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->variableList);
if(pgphentry) {
return;
}
pvar = dbCalloc(1,sizeof(dbVariableDef));
pvar->name = epicsStrDup(name);
pvar->type = epicsStrDup(type);
pgphentry = gphAdd(pdbbase->pgpHash,pvar->name,&pdbbase->variableList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pvar->name,&savedPdbbase->variableList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pvar;
ellAdd(&pdbbase->variableList,&pvar->node);
ellAdd(&savedPdbbase->variableList,&pvar->node);
}
static void dbBreakHead(char *name)
@@ -958,7 +959,7 @@ static void dbBreakHead(char *name)
yyerrorAbort("dbBreakHead: Breaktable name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->bptList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->bptList);
if(pgphentry) {
duplicate = TRUE;
return;
@@ -1042,17 +1043,17 @@ static void dbBreakBody(void)
/* Continue with last slope beyond the final point */
paBrkInt[number-1].slope = paBrkInt[number-2].slope;
/* Add brkTable in sorted order */
pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
pbrkTable = (brkTable *)ellFirst(&savedPdbbase->bptList);
while (pbrkTable) {
if (strcmp(pbrkTable->name, pnewbrkTable->name) > 0) {
ellInsert(&pdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
ellInsert(&savedPdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
(ELLNODE *)pnewbrkTable);
break;
}
pbrkTable = (brkTable *)ellNext(&pbrkTable->node);
}
if (!pbrkTable) ellAdd(&pdbbase->bptList, &pnewbrkTable->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewbrkTable->name,&pdbbase->bptList);
if (!pbrkTable) ellAdd(&savedPdbbase->bptList, &pnewbrkTable->node);
pgphentry = gphAdd(savedPdbbase->pgpHash,pnewbrkTable->name,&savedPdbbase->bptList);
if (!pgphentry) {
yyerrorAbort("dbBreakBody: gphAdd failed");
return;
@@ -1103,7 +1104,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
if(dbRecordNameValidate(name))
return;
pdbentry = dbAllocEntry(pdbbase);
pdbentry = dbAllocEntry(savedPdbbase);
if (ellCount(&tempList))
yyerrorAbort("dbRecordHead: tempList not empty");
allocTemp(pdbentry);
@@ -1260,7 +1261,7 @@ static void dbAlias(char *name, char *alias)
if(dbRecordNameValidate(alias))
return;
dbInitEntry(pdbbase, pdbEntry);
dbInitEntry(savedPdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);

View File

@@ -716,13 +716,13 @@ int iocShutdown(void)
iterateRecords(doCloseLinks, NULL);
initHookAnnounce(initHookAfterCloseLinks);
if (iocBuildMode == buildIsolated) {
/* stop and "join" threads */
scanStop();
initHookAnnounce(initHookAfterStopScan);
callbackStop();
initHookAnnounce(initHookAfterStopCallback);
} else {
/* stop and "join" threads */
scanStop();
initHookAnnounce(initHookAfterStopScan);
callbackStop();
initHookAnnounce(initHookAfterStopCallback);
if (iocBuildMode != buildIsolated) {
dbStopServers();
}

View File

@@ -28,6 +28,7 @@
#include "dbEvent.h"
#include "dbFldTypes.h"
#include "errMdef.h"
#include "menuYesNo.h"
#include "special.h"
#include "recSup.h"
#include "recGbl.h"
@@ -166,9 +167,9 @@ static int compress_array(compressRecord *prec,
}
if (prec->n <= 0)
prec->n = 1;
n = prec->n;
if (no_elements < n)
if (no_elements < prec->n && prec->pbuf != menuYesNoYES)
return 1; /*dont do anything*/
n = no_elements;
/* determine number of samples to take */
if (no_elements < nsam * n)
@@ -272,7 +273,7 @@ static int array_average(compressRecord *prec,
prec->inx = 0;
return 0;
}
static int compress_scalar(struct compressRecord *prec,double *psource)
{
double value = *psource;
@@ -292,19 +293,13 @@ static int compress_scalar(struct compressRecord *prec,double *psource)
/* for scalars, Median not implemented => use average */
case (compressALG_N_to_1_Average):
case (compressALG_N_to_1_Median):
if (inx == 0)
*pdest = value;
else {
*pdest += value;
if (inx + 1 >= prec->n)
*pdest = *pdest / (inx + 1);
}
*pdest = (inx * (*pdest) + value) / (inx + 1);
break;
}
inx++;
if (inx >= prec->n) {
if ((inx >= prec->n) || (prec->pbuf == menuYesNoYES)) {
put_value(prec,pdest,1);
prec->inx = 0;
prec->inx = (inx >= prec->n) ? 0 : inx;
return 0;
} else {
prec->inx = inx;

View File

@@ -40,7 +40,7 @@ the beginning or the end of the VAL array.
=head2 Parameter Fields
The record-specific fields are described below.
The record-specific fields are described below, grouped by functionality.
=recordtype compress
@@ -60,10 +60,6 @@ menu(bufferingALG) {
}
recordtype(compress) {
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=head3 Scanning Parameters
The compression record has the standard fields for specifying under what
@@ -85,7 +81,7 @@ algorithms which can be specified as follows:
The following fields determine what channel to read and how to compress the data:
=fields ALG, INP, NSAM, N, ILIL, IHIL, OFF, RES
=fields ALG, INP, NSAM, N, ILIL, IHIL, OFF, RES, PBUF
As stated above, the ALG field specifies which algorithm to be performed on the data.
@@ -167,6 +163,23 @@ Compress N to 1 samples, taking the median value.
=back
The behaviour of the record for partially filled buffers depends on the field PBUF.
If PBUF is set to NO, then the record will wait until the buffer is completely full
before processing. If PBUF is set to YES, then it will start processing immediately.
For example, if ALG is set to C<<< N to 1 Average >>> with NSAM equal to 4, N equal
to 1, and PBUF set to NO, then the first three times that the compress record is
processed it will remain in an undefined state. On the fourth process, the average
of all four records will be calculated and placed into the VAL field.
If PBUF is set to YES, then after each process the average of the first several
elements will be calculated.
Note that PBUF has no impact on the C<<< Average >>> method. If one wishes to have a
rolling average computed, then the best way to achieve that is with two compress
records: a C<<< Circular buffer >>> which is linked to an C<<< N to 1 Average >>>
record with PBUF set to YES.
The compression record keeps NSAM data samples.
The field N determines the number of elements to compress into each result.
@@ -393,7 +406,15 @@ Scan forward link if necessary, set PACT FALSE, and return.
interest(1)
menu(compressALG)
}
field(BALG,DBF_MENU) {
field(PBUF,DBF_MENU) {
prompt("Use Partial buffers")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
menu(menuYesNo)
initial("NO")
}
field(BALG,DBF_MENU) {
prompt("Buffering Algorithm")
promptgroup("30 - Action")
special(SPC_RESET)

View File

@@ -271,7 +271,7 @@ static long special(DBADDR *paddr, int after)
} else if(after==1 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) {
/* Adjust VAL corresponding to the bit changed */
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
epicsUInt32 bit = 1 << (pBn - &prec->b0);
epicsUInt32 bit = 1u << (pBn - &prec->b0);
/* Because this is !(VAL and PP), dbPut() will always post a monitor on this B* field
* after we return. We must keep track of this change separately from MLST to handle

View File

@@ -162,7 +162,7 @@ static long process(struct dbCommon *pcommon)
recGblFwdLink(prec);
prec->pact = FALSE;
return 0;
return status;
}
static long special(DBADDR *paddr, int after)

View File

@@ -146,7 +146,7 @@ __EOF__
" prt->papFldDes[${rn}Record${fn}]->size = " .
"sizeof(prec->${cn});\n" .
" prt->papFldDes[${rn}Record${fn}]->offset = " .
"(unsigned short)((char *)&prec->${cn} - (char *)prec);"
"(unsigned short)offsetof(${rn}Record, ${cn});"
} @fields), << "__EOF__";
prt->rec_size = sizeof(*prec);