Compare commits

...

39 Commits

Author SHA1 Message Date
Andrew Johnson
72be690fec Set Base version to 7.0.2.1 (final) 2019-03-20 15:24:51 -05:00
Andrew Johnson
a5b3157ec1 Update version numbers for libcom and database 2019-03-20 15:18:05 -05:00
Andrew Johnson
9a062cd6a1 Update submodules 2019-03-20 15:16:55 -05:00
Andrew Johnson
592b935146 Document the macOS -flat_namespace flag change 2019-03-20 13:46:47 -05:00
Andrew Johnson
638391249d Update EPICS_TIMEZONE settings in CONFIG_SITE_ENV
Deleted 2018, added 2023.
2019-03-20 13:44:02 -05:00
Michael Davidsaver
cde682f7ba nonEpicsThreadPriorityTest is Linux only 2019-03-18 16:08:20 -07:00
Michael Davidsaver
89da4130fc make-tar.sh allow HEAD for testing 2019-03-18 13:49:25 -07:00
Michael Davidsaver
1d2637a04e update submodules 2019-03-18 13:26:47 -07:00
Michael Davidsaver
a2123db9fb Merge branch 'fix_1816841_only' into 7.0
* fix_1816841_only:
  Another hack to deal with RTEMS which is POSIX but still different
  stripped-down fix for 1816841 only
2019-03-17 18:43:34 -07:00
till straumann
7f55bb0386 Another hack to deal with RTEMS which is POSIX but still different 2019-03-14 11:47:52 -07:00
till straumann
511a541f31 stripped-down fix for 1816841 only 2019-03-14 10:36:55 -07:00
Michael Davidsaver
394c39da51 update release notes 2019-03-13 18:17:57 -07:00
Michael Davidsaver
632d1f45c8 Merge branch 'putf-pact' into 7.0
* putf-pact:
  RPRO/PUTF log instead of assert()
  RPRO/PUTF test all three link types
  RPRO/PUTF rename
  RPRO/PUTF also handle self link case
  fix RPRO/PUTF regression
  test for RPRO/PUTF regression
  dbRec2Pvt()
  Remove Warning: 'blah.PUTF' found true with PACT false
  dbNotify set PUTF
2019-03-13 18:04:18 -07:00
Michael Davidsaver
0f75e0aa7f RPRO/PUTF log instead of assert() 2019-03-13 17:57:41 -07:00
Michael Davidsaver
c93ec231a2 update PVD and PVA 2019-03-11 19:45:37 -07:00
Michael Davidsaver
d1149a0ba9 iocsh epicsMutexShowAll accepts 2 arguments 2019-03-11 17:53:51 -07:00
Andrew Johnson
8c3c5a9731 Restore the -flat_namespace linker flag on macOS
Latest versions of Apple XCode require it.
2019-03-11 16:00:54 -05:00
Andrew Johnson
44510f2fb2 Merge 3.15 branch into 7.0 2019-03-07 12:56:57 -06:00
Andrew Johnson
933733465e Improve timeout diagnostics from netget.plt 2019-02-13 16:02:16 -06:00
Michael Davidsaver
688f32cff0 RPRO/PUTF test all three link types
Shouldn't be any difference, but check IN_LINK
and FWD_LINK to be sure.
2019-02-06 16:07:40 -08:00
Michael Davidsaver
d3feb1e2f9 RPRO/PUTF rename 2019-02-04 16:37:20 -08:00
Michael Davidsaver
62c11c22c9 RPRO/PUTF also handle self link case 2019-02-02 15:34:59 -08:00
Andrew Johnson
736075daf6 Document macOS Mojave fix 2019-02-01 16:49:11 -06:00
Andrew Johnson
9ef3b77348 Fix ca/client/perl/Makefile for macOS Mojave
... in which Apple moved the Perl headers into XCode.
This should also make the build a little more forgiving on other
architectures that have incomplete Perl installations; it gives up
trying to build the Perl bindings with a warning if perl.h is missing.
2019-02-01 16:14:45 -06:00
Andrew Johnson
d15c8093ec Extract dbEntryToAddr() from dbChannelCreate() & dbNameToAddr() 2019-02-01 15:26:35 -06:00
Andrew Johnson
0211698b69 Move dbAccess prototypes to the correct header file 2019-02-01 12:02:41 -06:00
Michael Davidsaver
e860617389 fix RPRO/PUTF regression 2019-01-31 20:16:09 -08:00
Michael Davidsaver
e918994704 test for RPRO/PUTF regression 2019-01-31 20:16:06 -08:00
Michael Davidsaver
5eb7da4595 dbRec2Pvt() 2019-01-31 20:16:03 -08:00
Andrew Johnson
2206934ae2 Fix MacOS build warning
The MacOS ld linker complains if a -L option points to
a directory that doesn't exist, so create that directory
before running the linker. Might be unnecessary, but...
2019-01-21 16:08:29 -06:00
Andrew Johnson
318fc96912 dbStatic: Removed old DCT_ macros and routines 2019-01-15 16:21:32 -06:00
Andrew Johnson
a58cc37a5e Fix dbhcr before iocInit 2019-01-15 16:03:17 -06:00
Andrew Johnson
b5e041b991 Update Release Notes version number to 7.0.3 2019-01-15 16:01:55 -06:00
Andrew Johnson
5e1bad2b34 dbStatic parser: Reject empty object names 2019-01-10 14:45:18 -06:00
Andrew Johnson
0ae50485cf Fix int64inRecord::get_units() 2019-01-08 14:42:43 -06:00
Michael Davidsaver
bc7ee94e2c Remove Warning: 'blah.PUTF' found true with PACT false 2019-01-03 20:34:12 -08:00
Michael Davidsaver
3fb10b6d59 dbNotify set PUTF 2019-01-03 20:34:12 -08:00
Andrew Johnson
a8fdf2efeb realclean rule must delete all RELEASE.<host>.local files 2018-12-18 15:43:18 -06:00
Andrew Johnson
c9eda3ca48 Reset snapshot to -DEV after tagging 2018-12-17 17:42:57 -06:00
34 changed files with 694 additions and 345 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,7 +52,7 @@ 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 = 1
# This will end in -DEV between official releases
#EPICS_DEV_SNAPSHOT=-DEV

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

@@ -202,9 +202,9 @@ endif
$(TESTPRODNAME) $(PRODNAME): $(PRODUCT_OBJS) $(PROD_RESS) $(PROD_DEPLIBS)
$(TESTPRODNAME) $(PRODNAME): %$(EXE):
$(TESTPRODNAME) $(PRODNAME): %$(EXE): | $(INSTALL_LIB)
@$(RM) $@
$(DEBUGCMD) $(LINK.cpp)
$(LINK.cpp)
$(MT_EXE_COMMAND)
%_ctdt$(OBJ) : %_ctdt.c
@@ -305,6 +305,10 @@ $(LOADABLE_SHRLIBNAME): $(LOADABLE_SHRLIB_PREFIX)%$(LOADABLE_SHRLIB_SUFFIX):
$(LINK.shrlib)
$(MT_DLL_COMMAND)
$(LIBNAME) $(SHRLIBNAME) $(LOADABLE_SHRLIBNAME): | $(INSTALL_LIB)
$(INSTALL_LIB):
@$(MKDIR) $@
#---------------------------------------------------------------
# C++ munching for VxWorks
@@ -467,9 +471,11 @@ $(INSTALL_TCLLIB)/%: ../%
@$(INSTALL) -d -m $(BIN_PERMISSIONS) $< $(INSTALL_TCLLIB)
endif
ifneq ($(TCLINDEX),)
$(INSTALL_TCLLIB)/$(TCLINDEX): $(INSTALL_TCLLIBS)
$(ECHO) "Updating $@"
$(ECHO) eval auto_mkindex $(INSTALL_TCLLIB) "$(TCLLIBNAME)" | tclsh
endif
$(INSTALL_LOADABLE_SHRLIBS): $(INSTALL_SHRLIB)/%: %
$(ECHO) "Installing loadable shared library $@"

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

@@ -21,16 +21,63 @@ which should also be read to understand what has changed since an earlier
release.</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>
<p>Support for some obsolete dbStaticLib Database Configuration Tool (DCT) APIs
was removed some time ago, but vestiges of them still remained. The following
routines and macros and have now finally been removed:</p>
<ul>
<li>int dbGetFieldType(DBENTRY *pdbentry)</li>
<li>int dbGetLinkType(DBENTRY *pdbentry)</li>
<li>DCT_STRING</li>
<li>DCT_INTEGER</li>
<li>DCT_REAL</li>
<li>DCT_MENU</li>
<li>DCT_MENUFORM</li>
<li>DCT_INLINK</li>
<li>DCT_OUTLINK</li>
<li>DCT_FWDLINK</li>
<li>DCT_NOACCESS</li>
<li>DCT_LINK_CONSTANT</li>
<li>DCT_LINK_FORM</li>
<li>DCT_LINK_PV</li>
</ul>
<h3>Fix for <tt>dbhcr</tt> before <tt>iocInit</tt></h3>
<p>The <tt>dbhcr</tt> command used to work before <tt>iocInit</tt> as well as
afterwards. It displays all records that have hardware addresses (VME_IO,
CAMAC_IO, GPIB_IO, INST_IO etc.) but stopped working if run before iocInit due
to the rewrite of the link address parser code in dbStaticLib. This release
fixes that issue, although in some cases the output may be slightly different
than it used to be.</p>
<h1 align="center">EPICS Release 7.0.2</h1>
<!-- Insert new items immediately below this template ...
<h3>Title...</h3>
<p>Description</p>
-->
<h3>Launchpad Bugs</h3>
<p>The list of tracked bugs fixed in this release can be found on the
@@ -920,6 +967,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

@@ -55,4 +55,4 @@ $(RELEASE_LOCAL):
$(ECHO) Creating $@, EPICS_BASE = $(INSTALL_LOCATION_ABS)
@echo EPICS_BASE = $(INSTALL_LOCATION_ABS)> $@
realclean:
$(RM) $(RELEASE_LOCAL)
$(RM) $(wildcard RELEASE.*.local)

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

@@ -601,6 +601,31 @@ all_done:
return status;
}
long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr)
{
dbFldDes *pflddes = pdbentry->pflddes;
short dbfType = pflddes->field_type;
paddr->precord = pdbentry->precnode->precord;
paddr->pfield = pdbentry->pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
const rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
return prset->cvt_dbaddr(paddr);
}
}
return 0;
}
/*
* Fill out a database structure (*paddr) for
* a record given by the name "pname."
@@ -611,9 +636,7 @@ all_done:
long dbNameToAddr(const char *pname, DBADDR *paddr)
{
DBENTRY dbEntry;
dbFldDes *pflddes;
long status = 0;
short dbfType;
if (!pname || !*pname || !pdbbase)
return S_db_notFound;
@@ -628,46 +651,28 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
status = dbGetAttributePart(&dbEntry, &pname);
if (status) goto finish;
pflddes = dbEntry.pflddes;
dbfType = pflddes->field_type;
paddr->precord = dbEntry.precnode->precord;
paddr->pfield = dbEntry.pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
status = prset->cvt_dbaddr(paddr);
if (status)
goto finish;
dbfType = paddr->field_type;
}
}
status = dbEntryToAddr(&dbEntry, paddr);
if (status) goto finish;
/* Handle field modifiers */
if (*pname++ == '$') {
short dbfType = paddr->field_type;
/* Some field types can be accessed as char arrays */
if (dbfType == DBF_STRING) {
paddr->no_elements = paddr->field_size;
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
}
else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
}
else {
status = S_dbLib_fieldNotFound;
goto finish;
}
}
@@ -679,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));
@@ -693,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

@@ -204,6 +204,8 @@ struct dbr_alDouble {DBRalDouble};
#define S_db_notInit (M_dbAccess|67) /*Not initialized*/
#define S_db_bufFull (M_dbAccess|68) /*Buffer full*/
struct dbEntry;
epicsShareFunc long dbPutSpecial(struct dbAddr *paddr,int pass);
epicsShareFunc rset * dbGetRset(const struct dbAddr *paddr);
epicsShareFunc long dbPutAttribute(
@@ -213,8 +215,29 @@ epicsShareFunc int dbGetFieldIndex(const struct dbAddr *paddr);
epicsShareFunc long dbScanPassive(
struct dbCommon *pfrom,struct dbCommon *pto);
epicsShareFunc long dbProcess(struct dbCommon *precord);
epicsShareFunc long dbNameToAddr(
const char *pname,struct dbAddr *);
epicsShareFunc long dbNameToAddr(const char *pname, struct dbAddr *paddr);
/** Initialize DBADDR from a dbEntry
* Also handles SPC_DBADDR processing. This is really an internal
* routine for use by dbNameToAddr() and dbChannelCreate().
*/
epicsShareFunc long dbEntryToAddr(const struct dbEntry *pdbentry,
struct dbAddr *paddr);
/** Initialize DBENTRY from a valid dbAddr*
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias().
*/
epicsShareFunc void dbInitEntryFromAddr(struct dbAddr *paddr,
struct dbEntry *pdbentry);
/** Initialize DBENTRY from a valid record (dbCommon*)
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias() when no field is specified.
*/
epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec,
struct dbEntry *pdbentry);
epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset);
epicsShareFunc long dbGetField(

View File

@@ -473,9 +473,7 @@ dbChannel * dbChannelCreate(const char *name)
dbChannel *chan = NULL;
char *cname;
dbAddr *paddr;
dbFldDes *pflddes;
long status;
short dbfType;
if (!name || !*name || !pdbbase)
return NULL;
@@ -498,32 +496,14 @@ dbChannel * dbChannelCreate(const char *name)
ellInit(&chan->post_chain);
paddr = &chan->addr;
pflddes = dbEntry.pflddes;
dbfType = pflddes->field_type;
paddr->precord = dbEntry.precnode->precord;
paddr->pfield = dbEntry.pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
status = prset->cvt_dbaddr(paddr);
if (status)
goto finish;
dbfType = paddr->field_type;
}
}
status = dbEntryToAddr(&dbEntry, paddr);
if (status)
goto finish;
/* Handle field modifiers */
if (*pname) {
short dbfType = paddr->field_type;
if (*pname == '$') {
/* Some field types can be accessed as char arrays */
if (dbfType == DBF_STRING) {
@@ -531,12 +511,14 @@ dbChannel * dbChannelCreate(const char *name)
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
}
else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
}
else {
status = S_dbLib_fieldNotFound;
goto finish;
}

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

@@ -79,16 +79,6 @@ epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = {
{"VXI_IO",VXI_IO}
};
static int mapDBFtoDCT[DBF_NOACCESS+1] = {
DCT_STRING,
DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,DCT_INTEGER,
DCT_REAL,DCT_REAL,
DCT_INTEGER,
DCT_MENU,
DCT_MENUFORM,
DCT_INLINK,DCT_OUTLINK,DCT_FWDLINK,
DCT_NOACCESS};
/*forward references for private routines*/
static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...)
EPICS_PRINTF_STYLE(2,3);
@@ -166,38 +156,6 @@ void dbFreePath(DBBASE *pdbbase)
}
static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess)
{
char message[200];
char *pmessage=&message[0];
dbRecordNode *precnode = pdbentry->precnode;
dbFldDes *pflddes = pdbentry->pflddes;
char *pname = NULL;
*pmessage=0;
if(pdbentry->precordType) pname = pdbentry->precordType->name;
if(pname) {
strcat(pmessage,"RecordType:");
strcat(pmessage,pname);
}
if(precnode){
if (dbIsAlias(pdbentry))
strcat(pmessage," Record Alias:");
else
strcat(pmessage," Record:");
strcat(pmessage,(char *)precnode->precord);
}
if(pflddes) {
char *pstr=pflddes->name;
strcat(pmessage," Field:");
strcat(pmessage,pstr);
}
strcat(pmessage,"\n");
strcat(pmessage,mess);
errMessage(status,pmessage);
}
static void zeroDbentry(DBENTRY *pdbentry)
{
/*NOTE that pdbbase and message MUST NOT be set to NULL*/
@@ -1398,19 +1356,6 @@ long dbNextField(DBENTRY *pdbentry,int dctonly)
}
}
int dbGetFieldType(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
long status;
if(!pflddes){
status = S_dbLib_flddesNotFound;
entryErrMessage(pdbentry,status,"dbGetFieldType");
return(status);
}
return(mapDBFtoDCT[pflddes->field_type]);
}
int dbGetNFields(DBENTRY *pdbentry,int dctonly)
{
dbRecordType *precordType = pdbentry->precordType;
@@ -3216,48 +3161,21 @@ int dbGetNLinks(DBENTRY *pdbentry)
return((int)precordType->no_links);
}
long dbGetLinkField(DBENTRY *pdbentry,int index)
long dbGetLinkField(DBENTRY *pdbentry, int index)
{
dbRecordType *precordType = pdbentry->precordType;
dbFldDes *pflddes;
dbRecordType *precordType = pdbentry->precordType;
dbFldDes *pflddes;
if (!precordType)
return S_dbLib_recordTypeNotFound;
if (index < 0 || index >= precordType->no_links)
return S_dbLib_badLink;
if(!precordType) return(S_dbLib_recordTypeNotFound);
if(index<0 || index>=precordType->no_links) return(S_dbLib_badLink);
pdbentry->indfield = precordType->link_ind[index];
pdbentry->pflddes = pflddes = precordType->papFldDes[pdbentry->indfield];
dbGetFieldAddress(pdbentry);
return(0);
}
int dbGetLinkType(DBENTRY *pdbentry)
{
dbFldDes *pflddes;
DBLINK *plink;
int field_type;
dbGetFieldAddress(pdbentry);
pflddes = pdbentry->pflddes;
if(!pflddes) return(-1);
plink = (DBLINK *)pdbentry->pfield;
if(!plink) return(-1);
field_type = pflddes->field_type;
switch (field_type) {
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK:
switch(plink->type) {
case CONSTANT:
return(DCT_LINK_CONSTANT);
case PV_LINK:
case PN_LINK:
case DB_LINK:
case CA_LINK:
return(DCT_LINK_PV);
default:
return(DCT_LINK_FORM);
}
}
return(-1);
return 0;
}
void dbDumpPath(DBBASE *pdbbase)
@@ -3556,68 +3474,110 @@ void dbDumpBreaktable(DBBASE *pdbbase,const char *name)
return;
}
static char *bus[VXI_IO+1] = {"","","VME","CAMAC","AB",
"GPIB","BITBUS","","","","","","INST","BBGPIB","VXI"};
void dbReportDeviceConfig(dbBase *pdbbase,FILE *report)
static char *bus[LINK_NTYPES] = {
"", /* CONSTANT */
NULL, /* PV_LINK */
"VME",
"CAMAC",
"AB",
"GPIB",
"BITBUS",
NULL, /* MACRO_LINK */
NULL, /* JSON_LINK */
NULL, /* PN_LINK */
NULL, /* DB_LINK */
NULL, /* CA_LINK */
"INST",
"BBGPIB",
"VXI"
};
void dbReportDeviceConfig(dbBase *pdbbase, FILE *report)
{
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
char linkValue[messagesize];
char dtypValue[50];
char cvtValue[40];
int ilink,nlinks;
struct link *plink;
int linkType;
FILE *stream = (report==0) ? stdout : report;
DBENTRY dbentry, *pdbentry = &dbentry;
long status;
FILE *stream = report ? report : stdout;
if(!pdbbase) {
fprintf(stderr,"pdbbase not specified\n");
return;
if (!pdbbase) {
fprintf(stderr, "dbReportDeviceConfig: pdbbase not specified\n");
return;
}
dbInitEntry(pdbbase,pdbentry);
status = dbFirstRecordType(pdbentry);
while(!status) {
status = dbFirstRecord(pdbentry);
while(!status) {
nlinks = dbGetNLinks(pdbentry);
for(ilink=0; ilink<nlinks; ilink++) {
status = dbGetLinkField(pdbentry,ilink);
if(status || dbGetLinkType(pdbentry)!=DCT_LINK_FORM) continue;
plink = pdbentry->pfield;
linkType = plink->type;
if(bus[linkType][0]==0) continue;
strncpy(linkValue, dbGetString(pdbentry), NELEMENTS(linkValue)-1);
linkValue[NELEMENTS(linkValue)-1] = '\0';
status = dbFindField(pdbentry,"DTYP");
if(status) break;
strcpy(dtypValue,dbGetString(pdbentry));
status = dbFindField(pdbentry,"LINR");
if(status) {
cvtValue[0] = 0;
} else {
if(strcmp(dbGetString(pdbentry),"LINEAR")!=0) {
cvtValue[0] = 0;
} else {
strcpy(cvtValue,"cvt(");
status = dbFindField(pdbentry,"EGUL");
if(!status) strcat(cvtValue,dbGetString(pdbentry));
status = dbFindField(pdbentry,"EGUF");
if(!status) {
strcat(cvtValue,",");
strcat(cvtValue,dbGetString(pdbentry));
}
strcat(cvtValue,")");
}
}
fprintf(stream,"%-8s %-20s %-20s %-20s %-s\n",
bus[linkType],linkValue,dtypValue,
dbGetRecordName(pdbentry),cvtValue);
break;
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
while (!status) {
const int nlinks = dbGetNLinks(pdbentry);
status = dbFirstRecord(pdbentry);
while (!status) {
int ilink;
for (ilink=0; ilink<nlinks; ilink++) {
char linkValue[messagesize];
char dtypValue[50];
char cvtValue[40];
struct link *plink;
int linkType;
status = dbGetLinkField(pdbentry, ilink);
if (status)
continue;
plink = pdbentry->pfield;
linkType = plink->type;
if (plink->text) { /* Not yet parsed */
dbLinkInfo linfo;
if (dbParseLink(plink->text, pdbentry->pflddes->field_type, &linfo))
continue;
linkType = linfo.ltype;
if (linkType && bus[linkType])
strncpy(linkValue, plink->text, messagesize-1);
dbFreeLinkInfo(&linfo);
}
else {
strncpy(linkValue, dbGetString(pdbentry), messagesize-1);
}
if (!linkType || !bus[linkType])
continue;
linkValue[messagesize-1] = '\0';
status = dbFindField(pdbentry, "DTYP");
if (status)
break; /* Next record type */
strcpy(dtypValue, dbGetString(pdbentry));
status = dbFindField(pdbentry, "LINR");
if (status) {
cvtValue[0] = 0;
}
else {
if (strcmp(dbGetString(pdbentry), "LINEAR") != 0) {
cvtValue[0] = 0;
}
else {
strcpy(cvtValue,"cvt(");
status = dbFindField(pdbentry, "EGUL");
if (!status)
strcat(cvtValue, dbGetString(pdbentry));
status = dbFindField(pdbentry, "EGUF");
if (!status) {
strcat(cvtValue, ",");
strcat(cvtValue, dbGetString(pdbentry));
}
strcat(cvtValue, ")");
}
}
fprintf(stream,"%-8s %-20s %-20s %-20s %-s\n",
bus[linkType], linkValue, dtypValue,
dbGetRecordName(pdbentry), cvtValue);
break;
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
finishOutstream(stream);

View File

@@ -28,25 +28,9 @@
extern "C" {
#endif
/*Field types as seen by static database access clients*/
#define DCT_STRING 0
#define DCT_INTEGER 1
#define DCT_REAL 2
#define DCT_MENU 3
#define DCT_MENUFORM 4
#define DCT_INLINK 5
#define DCT_OUTLINK 6
#define DCT_FWDLINK 7
#define DCT_NOACCESS 8
/*Link types as seen by static database access clients*/
#define DCT_LINK_CONSTANT 0
#define DCT_LINK_FORM 1
#define DCT_LINK_PV 2
typedef dbBase DBBASE;
typedef struct{
typedef struct dbEntry {
DBBASE *pdbbase;
dbRecordType *precordType;
dbFldDes *pflddes;
@@ -57,9 +41,6 @@ typedef struct{
short indfield;
} DBENTRY;
struct dbAddr;
struct dbCommon;
/* Static database access routines*/
epicsShareFunc DBBASE * dbAllocBase(void);
epicsShareFunc void dbFreeBase(DBBASE *pdbbase);
@@ -68,18 +49,6 @@ epicsShareFunc void dbFreeEntry(DBENTRY *pdbentry);
epicsShareFunc void dbInitEntry(DBBASE *pdbbase,
DBENTRY *pdbentry);
/** Initialize DBENTRY from a valid dbAddr*.
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias()
*/
epicsShareFunc void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry);
/** Initialize DBENTRY from a valid record (dbCommon*).
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias() when no field is specified.
*/
epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry);
epicsShareFunc void dbFinishEntry(DBENTRY *pdbentry);
epicsShareFunc DBENTRY * dbCopyEntry(DBENTRY *pdbentry);
epicsShareFunc void dbCopyEntryContents(DBENTRY *pfrom,
@@ -139,7 +108,6 @@ epicsShareFunc long dbGetAttributePart(DBENTRY *pdbentry,
epicsShareFunc long dbFirstField(DBENTRY *pdbentry, int dctonly);
epicsShareFunc long dbNextField(DBENTRY *pdbentry, int dctonly);
epicsShareFunc int dbGetFieldType(DBENTRY *pdbentry);
epicsShareFunc int dbGetNFields(DBENTRY *pdbentry, int dctonly);
epicsShareFunc char * dbGetFieldName(DBENTRY *pdbentry);
epicsShareFunc char * dbGetDefault(DBENTRY *pdbentry);
@@ -231,7 +199,6 @@ epicsShareFunc linkSup * dbFindLinkSup(dbBase *pdbbase,
epicsShareFunc int dbGetNLinks(DBENTRY *pdbentry);
epicsShareFunc long dbGetLinkField(DBENTRY *pdbentry, int index);
epicsShareFunc int dbGetLinkType(DBENTRY *pdbentry);
/* Dump routines */
epicsShareFunc void dbDumpPath(DBBASE *pdbbase);

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

@@ -183,17 +183,16 @@ static long special(DBADDR *paddr, int after)
#define indexof(field) int64inRecord##field
static long get_units(DBADDR *paddr,char *units)
static long get_units(DBADDR *paddr, char *units)
{
int64inRecord *prec=(int64inRecord *)paddr->precord;
int64inRecord *prec = (int64inRecord *) paddr->precord;
if(paddr->pfldDes->field_type == DBF_LONG) {
strncpy(units,prec->egu,DB_UNITS_SIZE);
if (paddr->pfldDes->field_type == DBF_INT64) {
strncpy(units, prec->egu, DB_UNITS_SIZE);
}
return(0);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
int64inRecord *prec=(int64inRecord *)paddr->precord;
@@ -255,7 +254,7 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
static void checkAlarms(int64inRecord *prec, epicsTimeStamp *timeLast)
{
enum {
enum {
range_Lolo = 1,
range_Low,
range_Normal,

View File

@@ -212,7 +212,7 @@ sub _getline {
my $line = readline $self->{stdout};
if (defined $line) {
chomp $line;
$line =~ s/[\r\n]+ $//x; # chomp broken on Windows?
printf "#%d >> %s\n", $self->{pid}, $line if $self->{debug};
}
elsif (eof($self->{stdout})) {

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

@@ -14,6 +14,7 @@ $ENV{HARNESS_ACTIVE} = 1 if scalar @ARGV && shift eq '-tap';
$ENV{EPICS_CA_AUTO_ADDR_LIST} = 'NO';
$ENV{EPICS_CA_ADDR_LIST} = 'localhost';
$ENV{EPICS_CA_SERVER_PORT} = 55064;
$ENV{EPICS_CAS_BEACON_PORT} = 55065;
$ENV{EPICS_CAS_INTF_ADDR_LIST} = 'localhost';
$ENV{EPICS_PVA_AUTO_ADDR_LIST} = 'NO';
@@ -29,13 +30,32 @@ my $prefix = "test-$$";
my $ioc = EPICS::IOC->new();
#$ioc->debug(1);
$SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = $SIG{ALRM} = sub {
$ioc->kill
if ref($ioc) eq 'EPICS::IOC' && $ioc->started;
$SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub {
$ioc->kill;
BAIL_OUT('Caught signal');
};
alarm 30;
# Watchdog utilities
sub kill_bail {
my $doing = shift;
return sub {
$ioc->kill;
BAIL_OUT("Timeout $doing");
}
}
sub watchdog (&$$) {
my ($do, $timeout, $abort) = @_;
$SIG{ALRM} = $abort;
alarm $timeout;
&$do;
alarm 0;
}
# Start the IOC
my $softIoc = "$bin/softIocPVA$exe";
$softIoc = "$bin/softIoc$exe"
@@ -43,42 +63,78 @@ $softIoc = "$bin/softIoc$exe"
BAIL_OUT("Can't find a softIoc executable")
unless -x $softIoc;
$ioc->start($softIoc, '-x', $prefix);
$ioc->cmd; # Wait for command prompt
watchdog {
$ioc->start($softIoc, '-x', $prefix);
$ioc->cmd; # Wait for command prompt
} 10, kill_bail('starting softIoc');
# Get Base Version number from PV
my $pv = "$prefix:BaseVersion";
my @pvs = $ioc->dbl('stringin');
grep(m/$pv/, @pvs)
or BAIL_OUT('No BaseVersion record found');
watchdog {
my @pvs = $ioc->dbl('stringin');
grep(m/^ $pv $/x, @pvs)
or BAIL_OUT('No BaseVersion record found');
} 10, kill_bail('running dbl');
my $version = $ioc->dbgf("$pv");
my $version;
watchdog {
$version = $ioc->dbgf("$pv");
} 10, kill_bail('getting BaseVersion');
like($version, qr/^ \d+ \. \d+ \. \d+ /x,
"Got BaseVersion '$version' from iocsh");
note("CA server configuration:\n",
map(" $_\n", $ioc->cmd('casr', 1)));
my $caget = "$bin/caget$exe";
# Channel Access
SKIP: {
skip "caget not available", 1 unless -x $caget;
my $caVersion = `$caget -w5 $pv`;
like($caVersion, qr/$pv \s+ \Q$version\E/x,
'Got same BaseVersion from caget');
my $caget = "$bin/caget$exe";
skip "caget not available", 1
unless -x $caget;
# CA Server Diagnostics
watchdog {
note("CA server configuration:\n",
map(" $_\n", $ioc->cmd('casr', 1)));
} 10, kill_bail('running casr');
# CA Client test
watchdog {
my $caVersion = `$caget -w5 $pv`;
like($caVersion, qr/^ $pv \s+ \Q$version\E $/x,
'Got same BaseVersion from caget');
} 10, kill_bail('doing caget');
}
my $pvget = "$bin/pvget$exe";
# PV Access
SKIP: {
my $pvget = "$bin/pvget$exe";
skip "softIocPVA not available", 1
if $softIoc eq "$bin/softIoc$exe";
note("PVA server configuration:\n",
map(" $_\n", $ioc->cmd('pvasr')));
# PVA Server Diagnostics
watchdog {
note("PVA server configuration:\n",
map(" $_\n", $ioc->cmd('pvasr')));
} 10, kill_bail('running pvasr');
skip "pvget not available", 1
unless -x $pvget;
my $pvaVersion = `$pvget -w5 $pv`;
like($pvaVersion, qr/$pv \s .* \Q$version\E/x,
'Got same BaseVersion from pvget');
# PVA Client test
watchdog {
my $pvaVersion = `$pvget -w5 $pv`;
like($pvaVersion, qr/^ $pv \s .* \Q$version\E \s* $/x,
'Got same BaseVersion from pvget');
} 10, kill_bail('doing pvget');
}
$ioc->kill;

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

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