Merged changes from 3.15 branch to revno 12699

This commit is contained in:
Andrew Johnson
2015-07-24 12:01:53 -05:00
13 changed files with 55 additions and 53 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -1 +0,0 @@
record(ai, "somename") {}

View File

@@ -689,6 +689,9 @@ int iocShutdown(void)
/* stop and "join" threads */
scanStop();
callbackStop();
}
dbCaShutdown();
if (iocBuildMode==buildIsolated) {
/* free resources */
scanCleanup();
callbackCleanup();

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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";