Merged changes from 3.15 branch to revno 12699
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
record(ai, "somename") {}
|
||||
@@ -689,6 +689,9 @@ int iocShutdown(void)
|
||||
/* stop and "join" threads */
|
||||
scanStop();
|
||||
callbackStop();
|
||||
}
|
||||
dbCaShutdown();
|
||||
if (iocBuildMode==buildIsolated) {
|
||||
/* free resources */
|
||||
scanCleanup();
|
||||
callbackCleanup();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -80,7 +80,7 @@ open my $out, '>', $opt_o or
|
||||
my $pod = join "\n", '=for html <div class="pod">', '',
|
||||
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 <div class="pod">', '',
|
||||
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 {
|
||||
'</table></blockquote>', '', '=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";
|
||||
|
||||
Reference in New Issue
Block a user