diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 7bc4c77d9..3d3fc28c8 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -81,6 +81,8 @@ else host: endif +-include $(CONFIG)/RULES_FILE_TYPE + -include $(CONFIG)/RULES.Db #--------------------------------------------------------------- @@ -122,8 +124,6 @@ LIBTARGETS += $(LIBNAME) $(INSTALL_LIBS) $(TESTLIBNAME) \ $(LOADABLE_SHRLIBNAME) $(INSTALL_LOADABLE_SHRLIBS) --include $(CONFIG)/RULES_FILE_TYPE - # Main targets install: buildInstall diff --git a/src/ioc/db/callback.c b/src/ioc/db/callback.c index 897279ff9..b15220469 100644 --- a/src/ioc/db/callback.c +++ b/src/ioc/db/callback.c @@ -75,6 +75,8 @@ enum ctl {ctlInit, ctlRun, ctlPause, ctlExit}; static volatile enum ctl cbCtl; static epicsEventId startStopEvent; +static int callbackIsInit; + /* Static data */ static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = { "cbLow", "cbMedium", "cbHigh" @@ -89,7 +91,7 @@ static int priorityValue[NUM_CALLBACK_PRIORITIES] = {0, 1, 2}; int callbackSetQueueSize(int size) { - if (startStopEvent) { + if (callbackIsInit) { errlogPrintf("Callback system already initialized\n"); return -1; } @@ -99,7 +101,7 @@ int callbackSetQueueSize(int size) int callbackParallelThreads(int count, const char *prio) { - if (startStopEvent) { + if (callbackIsInit) { errlogPrintf("Callback system already initialized\n"); return -1; } @@ -209,8 +211,7 @@ void callbackCleanup(void) } epicsTimerQueueRelease(timerQueue); - epicsEventDestroy(startStopEvent); - startStopEvent = NULL; + callbackIsInit = 0; memset(callbackQueue, 0, sizeof(callbackQueue)); } @@ -220,10 +221,14 @@ void callbackInit(void) int j; char threadName[32]; - if (startStopEvent) + if (callbackIsInit) { + errlogMessage("Warning: callbackInit called again before callbackCleanup\n"); return; + } + callbackIsInit = 1; - startStopEvent = epicsEventMustCreate(epicsEventEmpty); + if(!startStopEvent) + startStopEvent = epicsEventMustCreate(epicsEventEmpty); cbCtl = ctlRun; timerQueue = epicsTimerQueueAllocate(0, epicsThreadPriorityScanHigh); diff --git a/src/ioc/db/dbCa.c b/src/ioc/db/dbCa.c index 1525bf5ab..b892b7e46 100644 --- a/src/ioc/db/dbCa.c +++ b/src/ioc/db/dbCa.c @@ -113,14 +113,11 @@ static int dbca_chan_count; * * dbCaPutLinkCallback causes an additional complication because * when dbCaRemoveLink is called the callback may not have occured. - * What is done is the following: - * If callback has not occured dbCaRemoveLink sets plinkPutCallback=plink - * If putCallback is called before dbCaTask calls ca_clear_channel - * it does NOT call the users callback. - * dbCaTask calls the users callback passing plinkPutCallback AFTER - * it has called ca_clear_channel - * Thus the users callback will get called exactly once. -*/ + * If putComplete sees plink==0 it will not call the user's code. + * If pca->putCallback is non-zero, dbCaTask will call the + * user's callback AFTER it has called ca_clear_channel. + * Thus the user's callback will get called exactly once. + */ static void addAction(caLink *pca, short link_action) { @@ -164,7 +161,7 @@ static void caLinkDec(caLink *pca) { int cnt; dbCaCallback callback; - struct link *plinkPutCallback = 0; + void *userPvt = 0; cnt = epicsAtomicDecrIntT(&pca->refcount); assert(cnt>=0); @@ -177,8 +174,7 @@ static void caLinkDec(caLink *pca) } callback = pca->putCallback; if (callback) { - plinkPutCallback = pca->plinkPutCallback; - pca->plinkPutCallback = 0; + userPvt = pca->putUserPvt; pca->putCallback = 0; pca->putType = 0; } @@ -189,12 +185,12 @@ static void caLinkDec(caLink *pca) free(pca->pvname); epicsMutexDestroy(pca->lock); free(pca); - if (callback) callback(plinkPutCallback); + if (callback) callback(userPvt); } -void dbCaCallbackProcess(void *usrPvt) +void dbCaCallbackProcess(void *userPvt) { - struct link *plink = (struct link *)usrPvt; + struct link *plink = (struct link *)userPvt; dbCommon *pdbCommon = plink->value.pv_link.precord; dbScanLock(pdbCommon); @@ -224,11 +220,6 @@ void dbCaShutdown(void) } } -static void dbCaExit(void *arg) -{ - dbCaShutdown(); -} - void dbCaLinkInitIsolated(void) { if (!workListLock) @@ -236,7 +227,6 @@ void dbCaLinkInitIsolated(void) if (!workListEvent) workListEvent = epicsEventMustCreate(epicsEventEmpty); dbCaCtl = ctlExit; - epicsAtExit(dbCaExit, NULL); } void dbCaLinkInit(void) @@ -299,8 +289,6 @@ void dbCaRemoveLink(struct link *plink) epicsMutexMustLock(pca->lock); pca->plink = 0; plink->value.pv_link.pvt = 0; - if (pca->putCallback) - pca->plinkPutCallback = plink; /* Unlock before addAction or dbCaTask might free first */ epicsMutexUnlock(pca->lock); addAction(pca, CA_CLEAR_CHANNEL); @@ -834,7 +822,7 @@ static void exceptionCallback(struct exception_handler_args args) } } -static void putCallback(struct event_handler_args arg) +static void putComplete(struct event_handler_args arg) { caLink *pca = (caLink *)arg.usr; struct link *plink; @@ -997,7 +985,7 @@ static void dbCaTask(void *arg) status = ca_array_put_callback( pca->dbrType, pca->nelements, pca->chid, pca->pputNative, - putCallback, pca); + putComplete, pca); } else { status = ECA_PUTFAIL; } @@ -1020,7 +1008,7 @@ static void dbCaTask(void *arg) status = ca_array_put_callback( DBR_STRING, 1, pca->chid, pca->pputString, - putCallback, pca); + putComplete, pca); } else { status = ECA_PUTFAIL; } diff --git a/src/ioc/db/dbCaPvt.h b/src/ioc/db/dbCaPvt.h index dc5a20557..d5274c577 100644 --- a/src/ioc/db/dbCaPvt.h +++ b/src/ioc/db/dbCaPvt.h @@ -64,7 +64,6 @@ typedef struct caLink short putType; dbCaCallback putCallback; void *putUserPvt; - struct link *plinkPutCallback; /* The following are for access to additional attributes*/ char gotAttributes; dbCaCallback getAttributes; diff --git a/src/ioc/db/dbEvent.c b/src/ioc/db/dbEvent.c index ce8f553b0..b3fce746a 100644 --- a/src/ioc/db/dbEvent.c +++ b/src/ioc/db/dbEvent.c @@ -979,6 +979,7 @@ static void event_task (void *pParm) { struct event_user * const evUser = (struct event_user *) pParm; struct event_que * ev_que; + unsigned char pendexit; /* init hook */ if (evUser->init_func) { @@ -1020,9 +1021,10 @@ static void event_task (void *pParm) event_read (ev_que); epicsMutexMustLock ( evUser->lock ); } + pendexit = evUser->pendexit; epicsMutexUnlock ( evUser->lock ); - } while ( ! evUser->pendexit ); + } while( ! pendexit ); epicsMutexDestroy(evUser->firstque.writelock); diff --git a/src/ioc/db/dbScan.c b/src/ioc/db/dbScan.c index 5a139a1ec..f566b77cb 100644 --- a/src/ioc/db/dbScan.c +++ b/src/ioc/db/dbScan.c @@ -177,10 +177,6 @@ void scanCleanup(void) epicsRingBytesDelete(onceQ); - epicsEventDestroy(startStopEvent); - epicsEventDestroy(onceSem); - onceSem = startStopEvent = NULL; - free(periodicTaskId); papPeriodic = NULL; periodicTaskId = NULL; @@ -190,7 +186,8 @@ long scanInit(void) { int i; - startStopEvent = epicsEventMustCreate(epicsEventEmpty); + if(!startStopEvent) + startStopEvent = epicsEventMustCreate(epicsEventEmpty); scanCtl = ctlPause; initPeriodic(); @@ -691,7 +688,8 @@ static void initOnce(void) if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) { cantProceed("initOnce: Ring buffer create failed\n"); } - onceSem = epicsEventMustCreate(epicsEventEmpty); + if(!onceSem) + onceSem = epicsEventMustCreate(epicsEventEmpty); onceTaskId = epicsThreadCreate("scanOnce", epicsThreadPriorityScanLow + nPeriodic, epicsThreadGetStackSize(epicsThreadStackBig), onceTask, 0); diff --git a/src/ioc/db/test/sRecord.db b/src/ioc/db/test/sRecord.db deleted file mode 100644 index 790a7df7c..000000000 --- a/src/ioc/db/test/sRecord.db +++ /dev/null @@ -1 +0,0 @@ -record(ai, "somename") {} diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 549392367..05d96a99e 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -689,6 +689,9 @@ int iocShutdown(void) /* stop and "join" threads */ scanStop(); callbackStop(); + } + dbCaShutdown(); + if (iocBuildMode==buildIsolated) { /* free resources */ scanCleanup(); callbackCleanup(); diff --git a/src/libCom/misc/epicsUnitTest.c b/src/libCom/misc/epicsUnitTest.c index 140ad6cb0..773b7b004 100644 --- a/src/libCom/misc/epicsUnitTest.c +++ b/src/libCom/misc/epicsUnitTest.c @@ -211,7 +211,7 @@ int testDone(void) { /* Our test harness, for RTEMS and vxWorks */ -static void harnessExit(void *dummy) { +void testHarnessExit(void *dummy) { epicsTimeStamp ended; int Faulty; @@ -248,7 +248,7 @@ static void harnessExit(void *dummy) { void testHarness(void) { epicsThreadOnce(&onceFlag, testOnce, NULL); - epicsAtExit(harnessExit, NULL); + epicsAtExit(testHarnessExit, NULL); Harness = 1; Programs = 0; Tests = 0; diff --git a/src/libCom/misc/epicsUnitTest.h b/src/libCom/misc/epicsUnitTest.h index 0489752a1..8a3bd6e17 100644 --- a/src/libCom/misc/epicsUnitTest.h +++ b/src/libCom/misc/epicsUnitTest.h @@ -43,9 +43,11 @@ epicsShareFunc int testDone(void); typedef int (*TESTFUNC)(void); epicsShareFunc void testHarness(void); +epicsShareFunc void testHarnessExit(void *dummy); epicsShareFunc void runTestFunc(const char *name, TESTFUNC func); #define runTest(func) runTestFunc(#func, func) +#define testHarnessDone() testHarnessExit(0) #ifdef __cplusplus } diff --git a/src/libCom/test/epicsRunLibComTests.c b/src/libCom/test/epicsRunLibComTests.c index fe308b061..0f10dbfc6 100644 --- a/src/libCom/test/epicsRunLibComTests.c +++ b/src/libCom/test/epicsRunLibComTests.c @@ -101,7 +101,12 @@ void epicsRunLibComTests(void) runTest(taskwdTest); /* - * Exit must come last as it never returns + * Report now in case epicsExitTest dies + */ + testHarnessDone(); + + /* + * epicsExitTest must come last as it never returns */ runTest(epicsExitTest); } diff --git a/src/std/dev/devAiSoftCallback.c b/src/std/dev/devAiSoftCallback.c index d9427d68b..3744509ed 100644 --- a/src/std/dev/devAiSoftCallback.c +++ b/src/std/dev/devAiSoftCallback.c @@ -23,6 +23,7 @@ #include "dbChannel.h" #include "dbNotify.h" #include "epicsAssert.h" +#include "epicsMath.h" #include "recGbl.h" #include "recSup.h" #include "devSup.h" @@ -190,7 +191,7 @@ static long read_ai(aiRecord *prec) } /* Apply smoothing algorithm */ - if (prec->smoo != 0.0 && pdevPvt->smooth) + if (prec->smoo != 0.0 && pdevPvt->smooth && finite(prec->val)) prec->val = prec->val * prec->smoo + pdevPvt->buffer.value * (1.0 - prec->smoo); else diff --git a/src/tools/dbdToHtml.pl b/src/tools/dbdToHtml.pl index 44f03fdbd..25064ce6e 100644 --- a/src/tools/dbdToHtml.pl +++ b/src/tools/dbdToHtml.pl @@ -80,7 +80,7 @@ open my $out, '>', $opt_o or my $pod = join "\n", '=for html
', '', map { # Handle a 'recordtype' Pod directive - if (m/^ =recordtype \s+ (.*)/x) { + if (m/^ =recordtype \s+ (\w+) /x) { my $rn = $1; my $rtyp = $dbd->recordtype($rn); die "Unknown recordtype '$rn' in $infile POD directive\n" @@ -88,7 +88,7 @@ my $pod = join "\n", '=for html
', '', rtypeToPod($rtyp, $dbd); } # Handle a 'menu' Pod directive - elsif (m/^ =menu \s+ (.*)/x) { + elsif (m/^ =menu \s+ (\w+) /x) { my $mn = $1; my $menu = $dbd->menu($mn); die "Unknown menu '$mn' in $infile POD directive\n" @@ -152,7 +152,7 @@ sub rtypeToPod { my ($rtyp, $dbd) = @_; return map { # Handle a 'fields' Pod directive - if (m/^ =fields \s+ (.*)/x) { + if (m/^ =fields \s+ (\w+ (?:\s* , \s* \w+ )* )/x) { my @names = split /\s*,\s*/, $1; # Look up the named fields my @fields = map { @@ -170,7 +170,7 @@ sub rtypeToPod { '', '', '=end html'; } # Handle a 'menu' Pod directive - elsif (m/^ =menu \s+ (.*)/x) { + elsif (m/^ =menu \s+ (\w+) /x) { my $mn = $1; my $menu = $dbd->menu($mn); die "Unknown menu '$mn' in $infile POD directive\n" @@ -218,7 +218,7 @@ sub fieldTableRow { # Native type presented to dbAccess users sub DBD::Recfield::public_type { my $fld = shift; - m/^=type (.+)$/i && return $1 for $fld->comments; + m/^ =type \s+ (.+) /x && return $1 for $fld->comments; my $type = $fld->dbf_type; $type =~ s/^DBF_//; return $type; @@ -227,7 +227,7 @@ sub DBD::Recfield::public_type { # Check if this field is readable sub DBD::Recfield::readable { my $fld = shift; - m/^=read (Yes|No)$/i && return $1 for $fld->comments; + m/^ =read \s+ (?i) (Yes|No) /x && return $1 for $fld->comments; return 'Probably' if $fld->attribute('special') eq "SPC_DBADDR"; return $fld->dbf_type eq 'DBF_NOACCESS' ? 'No' : 'Yes'; @@ -236,7 +236,7 @@ sub DBD::Recfield::readable { # Check if this field is writable sub DBD::Recfield::writable { my $fld = shift; - m/^=write (Yes|No)$/i && return $1 for $fld->comments; + m/^ =write \s+ (?i) (Yes|No) /x && return $1 for $fld->comments; my $special = $fld->attribute('special'); return 'No' if $special eq "SPC_NOMOD";