merge branch '7.0' into 'PSI-7.0'

This commit is contained in:
2019-07-22 15:44:08 +02:00
28 changed files with 419 additions and 78 deletions

View File

@@ -36,7 +36,10 @@ case "$PREFIX" in
esac
# Check for both <tag> and R<tag>
if ! [ `git tag -l $TOPREV` ]
if [ "$TOPREV" = "HEAD" ]
then
true
elif ! [ `git tag -l $TOPREV` ]
then
if [ `git tag -l R$TOPREV` ]
then

View File

@@ -52,9 +52,11 @@ EPICS_MODIFICATION = 2
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included if zero
EPICS_PATCH_LEVEL = 0
EPICS_PATCH_LEVEL = 2
# This will end in -DEV between official releases
# Between official releases, the EPICS_PATCH_LEVEL gets incremented
# and a -DEV suffix is added (similar to the Maven -SNAPSHOT versions)
#EPICS_DEV_SNAPSHOT=
EPICS_DEV_SNAPSHOT=-DEV
#EPICS_DEV_SNAPSHOT=-pre1
#EPICS_DEV_SNAPSHOT=-pre1-DEV
@@ -64,7 +66,6 @@ EPICS_DEV_SNAPSHOT=-DEV
#EPICS_DEV_SNAPSHOT=-rc1-DEV
#EPICS_DEV_SNAPSHOT=-rc2
#EPICS_DEV_SNAPSHOT=-rc2-DEV
#EPICS_DEV_SNAPSHOT=
# No changes should be needed below here

View File

@@ -34,14 +34,9 @@
# The future dates below assume the rules don't get changed;
# see http://www.timeanddate.com/time/dst/2018.html to check.
#
# DST for 2018 US: Mar 11 - Nov 04
# EU: Mar 25 - Oct 28
EPICS_TIMEZONE = CUS::360:031102:110402
#EPICS_TIMEZONE = MET::-60:032502:102803
#
# DST for 2019 US: Mar 10 - Nov 03
# EU: Mar 31 - Oct 27
#EPICS_TIMEZONE = CUS::360:031002:110302
EPICS_TIMEZONE = CUS::360:031002:110302
#EPICS_TIMEZONE = MET::-60:033102:102703
#
# DST for 2020 US: Mar 08 - Nov 01
@@ -58,6 +53,11 @@ EPICS_TIMEZONE = CUS::360:031102:110402
# EU: Mar 27 - Oct 30
#EPICS_TIMEZONE = CUS::360:031302:110602
#EPICS_TIMEZONE = MET::-60:032702:103003
#
# DST for 2023 US: Mar 13 - Nov 06
# EU: Mar 27 - Oct 30
#EPICS_TIMEZONE = CUS::360:031202:110502
#EPICS_TIMEZONE = MET::-60:032602:102903
# EPICS_TS_NTP_INET
# NTP time server ip address for VxWorks and RTEMS.

View File

@@ -26,8 +26,10 @@ realuninstall: uninstallDirs
UNINSTALL_DIRS += $(INSTALL_DBD) $(INSTALL_INCLUDE) $(INSTALL_DOC) \
$(INSTALL_HTML) $(INSTALL_TEMPLATES) $(INSTALL_DB) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
ifneq ($(INSTALL_LOCATION),$(EPICS_BASE))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
endif
uninstallDirs:
$(RMDIR) $(UNINSTALL_DIRS)

View File

@@ -65,7 +65,7 @@ GNU = NO
#
# Darwin shared libraries
#
SHRLIB_LDFLAGS = -dynamiclib -undefined dynamic_lookup \
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined dynamic_lookup \
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
$(addprefix -current_version , $(SHRLIB_VERSION))

View File

@@ -20,8 +20,7 @@ release.</p>
which should also be read to understand what has changed since an earlier
release.</p>
<h1 align="center">EPICS Release 7.0.3</h1>
<h1 align="center">EPICS Release 7.0.2.2</h1>
<!-- Insert new items immediately below this template ...
@@ -31,15 +30,28 @@ release.</p>
-->
<h3>Skipping build of modules and re-enabling vxWorks 5</h3>
<p>Any module can be skipped during the build for a given architecture by setting
the Makfile variable <tt>SKIP_BUILDS</tt> to a list of patterns matching the
module directories to skip. For example to skip building any pvAccess related
modules set <code>SKIP_BUILDS=pv%&nbsp;normativeTypes</code> in the
CONFIG.Common.&lt;arch&gt; file for that architecture.
The builds for vxWorks 5 and up to 6.2 do that.
</p>
<h1 align="center">EPICS Release 7.0.2.1</h1>
<h3>Linking shared libraries on macOS</h3>
<p>The linker flag <tt>-flat_namespace</tt> has been restored for creating
shared libraries, although not for loadable libraries (bundles). This was
required for building using the latest versions of Apple XCode.</p>
<h3>Fix DB_LINK loop breaking</h3>
<p>A regression was introduced in 7.0.2 which caused record chains with loops to
be incorrectly broken. Processing should be skipped when a DB_LINK with Process
Passive (PP) closes a loop to a synchronous record.</p>
<p>Instead in 7.0.2 the targeted record would be processed if processing began
with a remote action (or some other caller of <tt>dbPutField()</tt>). This would
result in the loop running a second time. The loop would be broken on the second
iteration.</p>
<p><a href="https://bugs.launchpad.net/epics-base/+bug/1809570">See lp:
#1809570</a></p>
<h3>Old dbStaticLib APIs removed</h3>
@@ -82,6 +94,7 @@ than it used to be.</p>
<a href="https://launchpad.net/epics-base/+milestone/7.0.2">Launchpad Milestone
page for EPICS Base 7.0.2</a>.</p>
<h3>Git Branches Recombined</h3>
<p>The four separate Git branches <tt>core/master</tt>, <tt>libcom/master</tt>,
@@ -92,6 +105,7 @@ more than one of these modules. The layout of the source files has not changed
at all however, so the source code for libcom, ca and the database are still
found separately under the module subdirectory.</p>
<h1 align="center">EPICS Release 7.0.1.1</h1>
<h3>Changed SIML failure behavior</h3>
@@ -963,6 +977,15 @@ of its CALLBACK objects.</p>
<!-- Insert inherited items immediately below here ... -->
<h3>Perl CA bindings fixed for macOS Mojave</h3>
<p>Apple removed some Perl header files from macOS Mojave that were available
in their SDK, requiring a change to the include paths used when compiling the
CA bindings. The new version should build on new and older macOS versions, and
these changes may also help other targets that have an incomplete installation
of Perl (the build will continue after printing a warning that the Perl CA
bindings could not be built).</p>
<h3>Routine <tt>epicsTempName()</tt> removed from libCom</h3>
<p>This routine was a simple wrapper around the C89 function <tt>tmpnam()</tt>

View File

@@ -37,6 +37,8 @@ that should be performed when creating production releases of EPICS Base.</p>
<h3>The Release Process</h3>
<h4>Full Process</h4>
<p>The version released on the Feature Freeze date is designated the first
pre-release, <tt>-pre1</tt>. The first release candidate <tt>-rc1</tt> is the
first version that has undergone testing by the developers and has shown no
@@ -49,6 +51,12 @@ release candidate has been available for 2 weeks without any new problems being
reported or major changes having to be committed, the final release can be
made.</p>
<h4>Short Process for Patch Releases</h4>
<p>The Patch Release date and its scope are agreed upon about four weeks
ahead of time. If no blocking issues are raised, the release is made by the
release manager.</p>
<h3>Roles</h3>
<p>The following roles are used below:</p>
@@ -322,6 +330,21 @@ made.</p>
</tt></blockquote>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Edit and commit changes to the EPICS Base version number file and
the embedded module version files:
<ul>
<li>configure/CONFIG_BASE_VERSION </li>
<li>modules/libcom/configure/CONFIG_LIBCOM_VERSION</li>
<li>modules/ca/configure/CONFIG_CA_VERSION</li>
<li>modules/database/configure/CONFIG_DATABASE_VERSION</li>
</ul>
Version numbers should be set to the next expected patch release,
with a "-DEV" tag added (where applicable).
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>

View File

@@ -8,6 +8,18 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ifdef T_A
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
PERL_ARCHPATH := $(PERL_VERSION)/$(PERL_ARCHNAME)
PERL_ARCHLIB := $(shell $(PERL) ../perlConfig.pl archlib)
PERL_h = $(PERL_ARCHLIB)/CORE/perl.h
EXTUTILS := $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
PERLBIN := $(shell $(PERL) ../perlConfig.pl bin)
XSUBPP := $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
# Special settings for Darwin:
ifeq ($(OS_CLASS),Darwin)
# Use hdepends command (not GNU compiler flags)
@@ -18,22 +30,23 @@ ifeq ($(OS_CLASS),Darwin)
# Perl loadable libraries on Darwin have funny names
LOADABLE_SHRLIB_PREFIX =
LOADABLE_SHRLIB_SUFFIX = .$(shell $(PERL) ../perlConfig.pl dlext)
ifeq ($(wildcard $(PERL_h)),)
# Perl's headers moved in Mojave
SDK_PATH := $(shell xcodebuild -version -sdk macosx Path)
PERL_ARCHLIB := $(SDK_PATH)/$(PERL_ARCHLIB)
endif
endif
ifdef T_A
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
PERL_ARCHPATH := $(PERL_VERSION)/$(PERL_ARCHNAME)
EXTUTILS := $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
PERLBIN := $(shell $(PERL) ../perlConfig.pl bin)
XSUBPP := $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
ifeq ($(T_A),$(EPICS_HOST_ARCH)) # No cross-builds (wrong Perl!)
ifeq ($(strip $(XSUBPP)),)
$(warning Perl's xsubpp program was not found.)
$(warning The Perl CA module will not be built.)
else
ifeq ($(T_A),$(EPICS_HOST_ARCH)) # No cross-builds (wrong Perl!)
ifeq ($(wildcard $(PERL_h)),)
$(warning Perl's C header files were not found.)
$(warning The Perl CA module will not be built.)
else
ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
LOADABLE_LIBRARY_HOST = Cap5
@@ -50,10 +63,11 @@ endif
endif
endif
endif
endif
Cap5_SRCS = Cap5.xs
Cap5_LIBS = ca Com
Cap5_INCLUDES = -I$(shell $(PERL) ../perlConfig.pl archlib)/CORE
Cap5_INCLUDES = -I$(PERL_ARCHLIB)/CORE
Cap5_CFLAGS = $(shell $(PERL) ../perlConfig.pl ccflags)
CLEANS += Cap5.c

View File

@@ -1,4 +1,4 @@
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 17
EPICS_DATABASE_MAINTENANCE_VERSION = 2
EPICS_DATABASE_MAINTENANCE_VERSION = 3
EPICS_DATABASE_DEVELOPMENT_FLAG = 0

View File

@@ -684,7 +684,7 @@ finish:
void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
{
struct dbCommon *prec = paddr->precord;
dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common);
dbCommonPvt *ppvt = dbRec2Pvt(prec);
memset((char *)pdbentry,'\0',sizeof(DBENTRY));
@@ -698,7 +698,7 @@ void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
{
dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common);
dbCommonPvt *ppvt = dbRec2Pvt(prec);
memset((char *)pdbentry,'\0',sizeof(DBENTRY));

View File

@@ -1,14 +1,27 @@
#ifndef DBCOMMONPVT_H
#define DBCOMMONPVT_H
#include <compilerDependencies.h>
#include <dbDefs.h>
#include "dbCommon.h"
struct epicsThreadOSD;
/** Base internal additional information for every record
*/
typedef struct dbCommonPvt {
struct dbRecordNode *recnode;
/* Thread which is currently processing this record */
struct epicsThreadOSD* procThread;
struct dbCommon common;
} dbCommonPvt;
static EPICS_ALWAYS_INLINE
dbCommonPvt* dbRec2Pvt(struct dbCommon *prec)
{
return CONTAINER(prec, dbCommonPvt, common);
}
#endif // DBCOMMONPVT_H

View File

@@ -56,7 +56,7 @@
#include "dbAddr.h"
#include "dbBase.h"
#include "dbBkpt.h"
#include "dbCommon.h"
#include "dbCommonPvt.h"
#include "dbConvertFast.h"
#include "dbConvert.h"
#include "db_field_log.h"
@@ -386,8 +386,11 @@ static long processTarget(dbCommon *psrc, dbCommon *pdst)
{
char context[40] = "";
int trace = dbAccessDebugPUTF && *dbLockSetAddrTrace(psrc);
int claim_src = dbRec2Pvt(psrc)->procThread==NULL;
int claim_dst = psrc!=pdst && dbRec2Pvt(pdst)->procThread==NULL;
long status;
epicsUInt8 pact = psrc->pact;
epicsThreadId self = epicsThreadGetIdSelf();
psrc->pact = TRUE;
@@ -406,14 +409,11 @@ static long processTarget(dbCommon *psrc, dbCommon *pdst)
printf("%s: '%s' -> '%s' with PUTF=%u\n",
context, psrc->name, pdst->name, psrc->putf);
if (pdst->putf)
errlogPrintf("Warning: '%s.PUTF' found true with PACT false\n",
pdst->name);
pdst->putf = psrc->putf;
}
else if (psrc->putf) {
/* The dst record is busy (awaiting async reprocessing) and
else if (psrc->putf && claim_dst) {
/* The dst record is busy (awaiting async reprocessing),
* not being processed recursively by us, and
* we were originally triggered by a call to dbPutField(),
* so we mark the dst record for reprocessing once the async
* completion is over.
@@ -426,17 +426,43 @@ static long processTarget(dbCommon *psrc, dbCommon *pdst)
pdst->rpro = TRUE;
}
else {
/* The dst record is busy, but we weren't triggered by a call
* to dbPutField(). Do nothing.
/* The dst record is busy, but either is being processed recursively,
* or wasn't triggered by a call to dbPutField(). Do nothing.
*/
if (trace)
printf("%s: '%s' -> Active '%s', done\n",
context, psrc->name, pdst->name);
}
if(claim_src) {
dbRec2Pvt(psrc)->procThread = self;
}
if(claim_dst) {
dbRec2Pvt(pdst)->procThread = self;
}
if(dbRec2Pvt(psrc)->procThread!=self ||
dbRec2Pvt(pdst)->procThread!=self) {
errlogPrintf("Logic Error: processTarget 1 from %p, %s(%p) -> %s(%p)\n",
self, psrc->name, dbRec2Pvt(psrc), pdst->name, dbRec2Pvt(pdst));
}
status = dbProcess(pdst);
psrc->pact = pact;
if(dbRec2Pvt(psrc)->procThread!=self ||
dbRec2Pvt(pdst)->procThread!=self) {
errlogPrintf("Logic Error: processTarget 2 from %p, %s(%p) -> %s(%p)\n",
self, psrc->name, dbRec2Pvt(psrc), pdst->name, dbRec2Pvt(pdst));
}
if(claim_src) {
dbRec2Pvt(psrc)->procThread = NULL;
}
if(claim_dst) {
dbRec2Pvt(pdst)->procThread = NULL;
}
return status;
}

View File

@@ -86,12 +86,6 @@ typedef struct notifyGlobal {
static notifyGlobal *pnotifyGlobal = 0;
/*Local routines*/
static void notifyInit(processNotify *ppn);
static void notifyCleanup(processNotify *ppn);
static void restartCheck(processNotifyRecord *ppnr);
static void callDone(dbCommon *precord,processNotify *ppn);
static void processNotifyCommon(processNotify *ppn,dbCommon *precord);
static void notifyCallback(CALLBACK *pcallback);
#define ellSafeAdd(list,listnode) \
@@ -210,7 +204,7 @@ static void callDone(dbCommon *precord, processNotify *ppn)
return;
}
static void processNotifyCommon(processNotify *ppn,dbCommon *precord)
static void processNotifyCommon(processNotify *ppn, dbCommon *precord, int first)
{
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
int didPut = 0;
@@ -256,6 +250,9 @@ static void processNotifyCommon(processNotify *ppn,dbCommon *precord)
doProcess = 1;
if (doProcess) {
if (first) {
precord->putf = TRUE;
}
ppn->wasProcessed = 1;
precord->ppn = ppn;
ellSafeAdd(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
@@ -298,7 +295,7 @@ static void notifyCallback(CALLBACK *pcallback)
return;
}
if(pnotifyPvt->state == notifyRestartCallbackRequested) {
processNotifyCommon(ppn, precord);
processNotifyCommon(ppn, precord, 0);
return;
}
/* All done. Clean up and call userCallback */
@@ -382,7 +379,7 @@ void dbProcessNotify(processNotify *ppn)
precord->ppnr->precord = precord;
ellInit(&precord->ppnr->restartList);
}
processNotifyCommon(ppn, precord);
processNotifyCommon(ppn, precord, 1);
}
void dbNotifyCancel(processNotify *ppn)
@@ -582,7 +579,7 @@ static void tpnThread(void *pvt)
processNotify *ppn = (processNotify *) ptpnInfo->ppn;
dbProcessNotify(ppn);
epicsEventWait(ptpnInfo->callbackDone);
epicsEventMustWait(ptpnInfo->callbackDone);
dbNotifyCancel(ppn);
epicsEventDestroy(ptpnInfo->callbackDone);
dbChannelDelete(ppn->chan);

View File

@@ -434,6 +434,10 @@ static void dbMenuHead(char *name)
dbMenu *pdbMenu;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbMenuHead: Menu name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->menuList);
if(pgphentry) {
duplicate = TRUE;
@@ -447,6 +451,10 @@ static void dbMenuHead(char *name)
static void dbMenuChoice(char *name,char *value)
{
if (!*name) {
yyerror("dbMenuChoice: Menu choice name can't be empty");
return;
}
if(duplicate) return;
allocTemp(epicsStrDup(name));
allocTemp(epicsStrDup(value));
@@ -494,6 +502,10 @@ static void dbRecordtypeHead(char *name)
dbRecordType *pdbRecordType;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbRecordtypeHead: Recordtype name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->recordTypeList);
if(pgphentry) {
duplicate = TRUE;
@@ -512,6 +524,10 @@ static void dbRecordtypeFieldHead(char *name,char *type)
dbFldDes *pdbFldDes;
int i;
if (!*name) {
yyerrorAbort("dbRecordtypeFieldHead: Field name can't be empty");
return;
}
if(duplicate) return;
pdbFldDes = dbCalloc(1,sizeof(dbFldDes));
allocTemp(pdbFldDes);
@@ -580,7 +596,7 @@ static void dbRecordtypeFieldItem(char *name,char *value)
if(sscanf(value,"%hd",&pdbFldDes->special)==1) {
return;
}
yyerror("Illegal special value.");
yyerror("Illegal 'special' value.");
return;
}
if(strcmp(name,"pp")==0) {
@@ -589,13 +605,13 @@ static void dbRecordtypeFieldItem(char *name,char *value)
} else if((strcmp(value,"NO")==0) || (strcmp(value,"FALSE")==0)) {
pdbFldDes->process_passive = FALSE;
} else {
yyerror("Illegal value. Must be NO or YES");
yyerror("Illegal 'pp' value, must be YES/NO/TRUE/FALSE");
}
return;
}
if(strcmp(name,"interest")==0) {
if(sscanf(value,"%hd",&pdbFldDes->interest)!=1)
yyerror("Illegal value. Must be integer");
yyerror("Illegal 'interest' value, must be integer");
return;
}
if(strcmp(name,"base")==0) {
@@ -604,13 +620,13 @@ static void dbRecordtypeFieldItem(char *name,char *value)
} else if(strcmp(value,"HEX")==0) {
pdbFldDes->base = CT_HEX;
} else {
yyerror("Illegal value. Must be CT_DECIMAL or CT_HEX");
yyerror("Illegal 'base' value, must be DECIMAL/HEX");
}
return;
}
if(strcmp(name,"size")==0) {
if(sscanf(value,"%hd",&pdbFldDes->size)!=1)
yyerror("Illegal value. Must be integer");
yyerror("Illegal 'size' value, must be integer");
return;
}
if(strcmp(name,"extra")==0) {
@@ -802,6 +818,10 @@ static void dbDriver(char *name)
drvSup *pdrvSup;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbDriver: Driver name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
if(pgphentry) {
return;
@@ -841,6 +861,10 @@ static void dbRegistrar(char *name)
dbText *ptext;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbRegistrar: Registrar name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->registrarList);
if(pgphentry) {
return;
@@ -860,6 +884,10 @@ static void dbFunction(char *name)
dbText *ptext;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbFunction: Function name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->functionList);
if(pgphentry) {
return;
@@ -879,6 +907,10 @@ static void dbVariable(char *name, char *type)
dbVariableDef *pvar;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbVariable: Variable name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->variableList);
if(pgphentry) {
return;
@@ -899,6 +931,10 @@ static void dbBreakHead(char *name)
brkTable *pbrkTable;
GPHENTRY *pgphentry;
if (!*name) {
yyerrorAbort("dbBreakHead: Breaktable name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->bptList);
if(pgphentry) {
duplicate = TRUE;
@@ -1001,6 +1037,10 @@ static void dbRecordHead(char *recordType, char *name, int visible)
DBENTRY *pdbentry;
long status;
if (!*name) {
yyerrorAbort("dbRecordHead: Record name can't be empty");
return;
}
badch = strpbrk(name, " \"'.$");
if (badch) {
epicsPrintf("Bad character '%c' in record name \"%s\"\n",
@@ -1108,6 +1148,10 @@ static void dbRecordInfo(char *name, char *value)
tempListNode *ptempListNode;
long status;
if (!*name) {
yyerrorAbort("dbRecordInfo: Info item name can't be empty");
return;
}
if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
@@ -1132,6 +1176,10 @@ static void dbRecordAlias(char *name)
tempListNode *ptempListNode;
long status;
if (!*name) {
yyerrorAbort("dbRecordAlias: Alias name can't be empty");
return;
}
if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
@@ -1149,6 +1197,10 @@ static void dbAlias(char *name, char *alias)
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
if (!*alias) {
yyerrorAbort("dbAlias: Alias name can't be empty");
return;
}
dbInitEntry(pdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",

View File

@@ -179,7 +179,7 @@ long dbFreeRecord(DBENTRY *pdbentry)
if(!pdbRecordType) return(S_dbLib_recordTypeNotFound);
if(!precnode) return(S_dbLib_recNotFound);
if(!precnode->precord) return(S_dbLib_recNotFound);
free(CONTAINER(precnode->precord, dbCommonPvt, common));
free(dbRec2Pvt(precnode->precord));
precnode->precord = NULL;
return(0);
}

View File

@@ -9,6 +9,7 @@
#include <testMain.h>
#include <dbUnitTest.h>
#include <errlog.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <epicsEvent.h>
@@ -16,6 +17,7 @@
#include <iocsh.h>
#include "registryFunction.h"
#include <subRecord.h>
#include <dbScan.h>
epicsEventId done;
static int waitFor;
@@ -28,11 +30,17 @@ long doneSubr(subRecord *prec)
return 0;
}
static
void dummydone(void *usr, struct dbCommon* prec)
{
epicsEventMustTrigger(done);
}
void asyncproctest_registerRecordDeviceDriver(struct dbBase *);
MAIN(asyncproctest)
{
testPlan(21);
testPlan(27);
done = epicsEventMustCreate(epicsEventEmpty);
@@ -99,6 +107,40 @@ MAIN(asyncproctest)
testdbGetFieldEqual("chain3", DBF_LONG, 7);
testdbGetFieldEqual("chain3.A", DBF_LONG, 2);
testDiag("===== Chain 4 ======");
{
dbCommon *dummy=testdbRecordPtr("chain4_dummy");
testdbPutFieldOk("chain4_pos.PROC", DBF_LONG, 0);
/* sync once queue to wait for any queued RPRO */
scanOnceCallback(dummy, dummydone, NULL);
if (epicsEventWaitWithTimeout(done, 10.0) != epicsEventOK)
testAbort("Processing timed out");
testdbGetFieldEqual("chain4_pos", DBF_SHORT, 1);
testdbGetFieldEqual("chain4_rel", DBF_SHORT, 1);
testdbGetFieldEqual("chain4_lim", DBF_SHORT, 1);
}
testDiag("===== Chain 5 ======");
{
dbCommon *dummy=testdbRecordPtr("chain4_dummy");
testdbPutFieldOk("chain5_cnt.PROC", DBF_LONG, 0);
/* sync once queue to wait for any queued RPRO */
scanOnceCallback(dummy, dummydone, NULL);
if (epicsEventWaitWithTimeout(done, 10.0) != epicsEventOK)
testAbort("Processing timed out");
testdbGetFieldEqual("chain5_cnt", DBF_SHORT, 1);
}
testIocShutdownOk();
testdbCleanup();

View File

@@ -53,3 +53,41 @@ record(sub, "done3") {
field(FLNK, "chain3")
field(TPRO, "$(TPRO=)")
}
# loop breaking regression
# should _not_ RPRO
record(calcout,"chain4_pos") {
field(CALC, "E:=E+1;E")
field(OUT,"chain4_rel.A PP")
field(TPRO, "$(TPRO=)")
}
record(calc,"chain4_rel") {
field(CALC, "E:=E+1;E")
field(FLNK,"chain4_lim")
field(TPRO, "$(TPRO=)")
}
record(calc,"chain4_lim") {
field(CALC, "E:=E+1;E")
field(INPA,"chain4_pos PP")
field(INPB,"chain4_pos.HIGH PP")
field(INPC,"chain4_pos.LOW PP")
field(FLNK,"chain4_pos")
field(TPRO, "$(TPRO=)")
}
record(bo, "chain4_dummy") {
field(TPRO, "$(TPRO=)")
}
# loop breaking regression part 2
# selft link should _not_ RPRO
record(calcout,"chain5_cnt") {
field(CALC, "E:=E+1;E")
field(INPA,"chain5_cnt.A PP")
field(OUT,"chain5_cnt.A PP")
field(FLNK,"chain5_cnt")
field(TPRO, "$(TPRO=)")
}

View File

@@ -1,4 +1,4 @@
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 17
EPICS_LIBCOM_MAINTENANCE_VERSION = 2
EPICS_LIBCOM_MAINTENANCE_VERSION = 3
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0

View File

@@ -319,7 +319,7 @@ static const iocshArg epicsMutexShowAllArg1 = { "level",iocshArgInt};
static const iocshArg * const epicsMutexShowAllArgs[2] =
{&epicsMutexShowAllArg0,&epicsMutexShowAllArg1};
static const iocshFuncDef epicsMutexShowAllFuncDef =
{"epicsMutexShowAll",1,epicsMutexShowAllArgs};
{"epicsMutexShowAll",2,epicsMutexShowAllArgs};
static void epicsMutexShowAllCallFunc(const iocshArgBuf *args)
{
epicsMutexShowAll(args[0].ival,args[1].ival);

View File

@@ -18,9 +18,6 @@ void osdMonotonicInit(void)
{
unsigned i;
clockid_t ids[] = {
#ifdef CLOCK_MONOTONIC_RAW
CLOCK_MONOTONIC_RAW, /* Linux specific */
#endif
#ifdef CLOCK_HIGHRES
CLOCK_HIGHRES, /* solaris specific */
#endif

View File

@@ -567,14 +567,13 @@ static epicsThreadOSD *createImplicit(void)
pthreadInfo->osiPriority = 0;
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
{
struct sched_param param;
int policy;
if(pthread_getschedparam(tid,&policy,&param) == 0)
pthreadInfo->osiPriority =
(param.sched_priority - pcommonAttr->minPriority) * 100.0 /
if(pthread_getschedparam(tid,&pthreadInfo->schedPolicy,&pthreadInfo->schedParam) == 0) {
if ( pcommonAttr->usePolicy && pthreadInfo->schedPolicy == pcommonAttr->schedPolicy ) {
pthreadInfo->osiPriority =
(pthreadInfo->schedParam.sched_priority - pcommonAttr->minPriority) * 100.0 /
(pcommonAttr->maxPriority - pcommonAttr->minPriority + 1);
}
}
}
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);

View File

@@ -288,4 +288,15 @@ TESTPROD_HOST += cvtFastPerform
cvtFastPerform_SRCS += cvtFastPerform.cpp
testHarness_SRCS += cvtFastPerform.cpp
ifeq ($(OS_CLASS),Linux)
ifeq ($(USE_POSIX_THREAD_PRIORITY_SCHEDULING),YES)
TESTPROD_HOST += nonEpicsThreadPriorityTest
nonEpicsThreadPriorityTest_SRCS += nonEpicsThreadPriorityTest.cpp
nonEpicsThreadPriorityTest_SYS_LIBS += $(POSIX_LDLIBS:-l%=%)
testHarness_SRCS += nonEpicsThreadPriorityTest.cpp
epicsRunLibComTests_CFLAGS += -DHAVE_PTHREAD_PRIORITY_SCHEDULING
TESTS += nonEpicsThreadPriorityTest
endif
endif
include $(TOP)/configure/RULES

View File

@@ -0,0 +1,100 @@
#include <epicsThread.h>
#include "epicsUnitTest.h"
#include "testMain.h"
#include <stdio.h>
#include <string.h>
#ifdef __rtems__
/* RTEMS is posix but currently does not use the pthread API */
MAIN(nonEpicsThreadPriorityTest)
{
testPlan(1);
testSkip(1, "Platform does not use pthread API");
return testDone();
}
#else
static void *nonEpicsTestFunc(void *arg)
{
unsigned int pri;
// epicsThreadGetIdSelf() creates an EPICS context
// verify that the priority computed by epics context
// is OK
pri = epicsThreadGetPriority( epicsThreadGetIdSelf() );
if ( ! testOk( 0 == pri, "'createImplicit' assigned correct priority (%d) to non-EPICS thread", pri) ) {
return 0;
}
return (void*)1;
}
static void testFunc(void *arg)
{
epicsEventId ev = (epicsEventId)arg;
int policy;
struct sched_param param;
int status;
pthread_t tid;
void *rval;
pthread_attr_t attr;
status = pthread_getschedparam(pthread_self(), &policy,&param);
if ( status ) {
testSkip(1, "pthread_getschedparam failed");
goto done;
}
if ( SCHED_FIFO != policy ) {
testSkip(1, "nonEpicsThreadPriorityTest must be executed with privileges to use SCHED_FIFO");
goto done;
}
if ( pthread_attr_init( &attr ) ) {
testSkip(1, "pthread_attr_init failed");
goto done;
}
if ( pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ) ) {
testSkip(1, "pthread_attr_setinheritsched failed");
goto done;
}
if ( pthread_attr_setschedpolicy ( &attr, SCHED_OTHER ) ) {
testSkip(1, "pthread_attr_setschedpolicy failed");
goto done;
}
param.sched_priority = 0;
if ( pthread_attr_setschedparam ( &attr, &param ) ) {
testSkip(1, "pthread_attr_setschedparam failed");
goto done;
}
if ( pthread_create( &tid, &attr, nonEpicsTestFunc, 0 ) ) {
testSkip(1, "pthread_create failed");
goto done;
}
if ( pthread_join( tid, &rval ) ) {
testSkip(1, "pthread_join failed");
goto done;
}
done:
epicsEventSignal( ev );
}
MAIN(nonEpicsThreadPriorityTest)
{
testPlan(2);
epicsEventId testComplete = epicsEventMustCreate(epicsEventEmpty);
epicsThreadMustCreate("nonEpicsThreadPriorityTest", epicsThreadPriorityLow,
epicsThreadGetStackSize(epicsThreadStackMedium),
testFunc, testComplete);
epicsEventWaitStatus status = epicsEventWait(testComplete);
testOk(status == epicsEventWaitOK,
"epicsEventWait returned %d", status);
return testDone();
}
#endif