Compare commits
35 Commits
R3.15.4-pr
...
R3.15.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65574b5971 | ||
|
|
4284222b54 | ||
|
|
54bab1e2f0 | ||
|
|
df200de27f | ||
|
|
22d6ebe7e1 | ||
|
|
9c3ed1bfe2 | ||
|
|
23fd4e202b | ||
|
|
a5b8b0b890 | ||
|
|
988614ae8a | ||
|
|
fe887b4f83 | ||
|
|
7be7ad2768 | ||
|
|
6c9555310a | ||
|
|
4ccc2e9d3a | ||
|
|
122fb6c731 | ||
|
|
3b8fd13152 | ||
|
|
04a9fdb4e3 | ||
|
|
3c61880d79 | ||
|
|
8081d3ada4 | ||
|
|
6d35ee9c3c | ||
|
|
b5a0657adc | ||
|
|
b87f3eaaee | ||
|
|
6db0e13809 | ||
|
|
0f6c997288 | ||
|
|
704c748fbd | ||
|
|
82456f83ee | ||
|
|
e98a6bbafa | ||
|
|
9b51444fb7 | ||
|
|
3be97865b3 | ||
|
|
67097456e3 | ||
|
|
3c8af4c571 | ||
|
|
26c04844cf | ||
|
|
a3d981ad0a | ||
|
|
924aa2f93b | ||
|
|
51dd371784 | ||
|
|
72745d7b0c |
@@ -37,7 +37,7 @@ EPICS_PATCH_LEVEL = 0
|
||||
|
||||
# This will end in -DEV between official releases
|
||||
#EPICS_DEV_SNAPSHOT=-DEV
|
||||
EPICS_DEV_SNAPSHOT=-pre1
|
||||
#EPICS_DEV_SNAPSHOT=-pre1
|
||||
#EPICS_DEV_SNAPSHOT=-pre1-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-pre2
|
||||
#EPICS_DEV_SNAPSHOT=-pre2-DEV
|
||||
@@ -45,7 +45,7 @@ EPICS_DEV_SNAPSHOT=-pre1
|
||||
#EPICS_DEV_SNAPSHOT=-rc1-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-rc2
|
||||
#EPICS_DEV_SNAPSHOT=-rc2-DEV
|
||||
#EPICS_DEV_SNAPSHOT=
|
||||
EPICS_DEV_SNAPSHOT=
|
||||
|
||||
# No changes should be needed below here
|
||||
|
||||
|
||||
@@ -118,6 +118,13 @@ CROSS_COMPILER_TARGET_ARCHS=
|
||||
# configure/os/CONFIG_SITE.<host>.Common files instead.
|
||||
CROSS_COMPILER_HOST_ARCHS=
|
||||
|
||||
# The 'make runtests' and 'make tapfiles' build targets normally only run
|
||||
# self-tests for the EPICS_HOST_ARCH architecture. If the host can execute
|
||||
# the self-test programs for any other cross-built architectures such as
|
||||
# a -debug architecture, those architectures can be named here.
|
||||
#
|
||||
CROSS_COMPILER_RUNTEST_ARCHS=
|
||||
|
||||
# Build shared libraries (DLLs on Windows).
|
||||
# Must be either YES or NO. Definitions in the target-specific
|
||||
# os/CONFIG.Common.<target> and os/CONFIG_SITE.Common.<target> files may
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
# local timezone info for vxWorks and RTEMS IOCs. The format is
|
||||
# <name>::<minutesWest>:<start daylight>:<end daylight>
|
||||
# where the start and end are mmddhh - that is month,day,hour
|
||||
# e.g. for ANL in 2015: EPICS_TIMEZONE=CST/CDT::360:030802:110102
|
||||
# e.g. for ANL in 2016: EPICS_TIMEZONE=CST/CDT::360:031302:110602
|
||||
#
|
||||
# DST for 2015 US: Mar 08 - Nov 01
|
||||
# EU: Mar 29 - Oct 25
|
||||
# DST for 2016 US: Mar 13 - Nov 06
|
||||
# EU: Mar 27 - Oct 30
|
||||
# DST for 2017 US: Mar 12 - Nov 05
|
||||
@@ -42,11 +40,15 @@
|
||||
# EU: Mar 25 - Oct 28
|
||||
# DST for 2019 US: Mar 10 - Nov 03
|
||||
# EU: Mar 31 - Oct 27
|
||||
# (see: http://www.timeanddate.com/time/map/)
|
||||
# DST for 2020 US: Mar 08 - Nov 01
|
||||
# EU: Mar 29 - Oct 25
|
||||
# DST for 2021 US: Mar 14 - Nov 07
|
||||
# EU: Mar 28 - Oct 31
|
||||
# (see: http://www.timeanddate.com/time/dst/2016.html etc. )
|
||||
#
|
||||
# These values are for 2015:
|
||||
EPICS_TIMEZONE=CST/CDT::360:030802:110102
|
||||
#EPICS_TIMEZONE=CET/CEST::-60:032902:102502
|
||||
# These values are for 2016:
|
||||
EPICS_TIMEZONE=CST/CDT::360:031302:110602
|
||||
#EPICS_TIMEZONE=CET/CEST::-60:032702:103002
|
||||
|
||||
# EPICS_TS_NTP_INET
|
||||
# NTP time server ip address. Uses boot host if not set.
|
||||
|
||||
@@ -325,7 +325,9 @@ $(MODNAME): %$(MODEXT): %$(EXE)
|
||||
# Automated testing
|
||||
|
||||
runtests: $(TESTSCRIPTS)
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
|
||||
endif
|
||||
|
||||
testspec: $(TESTSCRIPTS)
|
||||
@$(RM) $@
|
||||
@@ -339,7 +341,9 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
||||
|
||||
# A .tap file is the output from running the associated test script
|
||||
%.tap: %.t
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
-$(PERL) $< -tap > $@
|
||||
endif
|
||||
|
||||
# If there's a perl test script (.plt) available, use it
|
||||
%.t: ../%.plt
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# CONFIG_SITE.Common.cygwin-x86_64
|
||||
#
|
||||
# $Revision-Id$
|
||||
#
|
||||
# Site Specific definitions for cygwin-x86_64 target
|
||||
# Only the local epics system manager should modify this file
|
||||
|
||||
# If readline is installed uncomment the following line
|
||||
# to add command-line editing and history support
|
||||
#COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
# Uncomment the following line if readline has problems
|
||||
#LDLIBS_READLINE = -lreadline -lcurses
|
||||
|
||||
|
||||
# It makes sense to include debugging symbols even in optimized builds
|
||||
# in case you want to attach gdb to the process or examine a core-dump.
|
||||
# This does cost disk space, but not memory as debug symbols are not
|
||||
# loaded into RAM when the binary is loaded.
|
||||
OPT_CFLAGS_YES += -g
|
||||
OPT_CXXFLAGS_YES += -g
|
||||
|
||||
# CONFIG_SITE.Common.cygwin-x86_64
|
||||
#
|
||||
# $Revision-Id$
|
||||
#
|
||||
# Site Specific definitions for cygwin-x86_64 target
|
||||
# Only the local epics system manager should modify this file
|
||||
|
||||
# If readline is installed uncomment the following line
|
||||
# to add command-line editing and history support
|
||||
#COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
# Uncomment the following line if readline has problems
|
||||
#LDLIBS_READLINE = -lreadline -lcurses
|
||||
|
||||
|
||||
# It makes sense to include debugging symbols even in optimized builds
|
||||
# in case you want to attach gdb to the process or examine a core-dump.
|
||||
# This does cost disk space, but not memory as debug symbols are not
|
||||
# loaded into RAM when the binary is loaded.
|
||||
OPT_CFLAGS_YES += -g
|
||||
OPT_CXXFLAGS_YES += -g
|
||||
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
<body lang="en">
|
||||
<h1 align="center">EPICS Base Release 3.15.4</h1>
|
||||
|
||||
<p style="color:red">This version of EPICS Base has not been released yet.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes made on the 3.15 branch since 3.15.3</h2>
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>New string input device support "getenv"</h3>
|
||||
|
||||
<p>A new "getenv" device support for both the stringin and lsi (long string
|
||||
input) record types can be used to read the value of an environment variable
|
||||
from the IOC at runtime. See base/db/softIocExit.db for sample usage.</p>
|
||||
|
||||
<h3>Build rules and DELAY_INSTALL_LIBS</h3>
|
||||
|
||||
<p>A new order-only prerequisite build rule has been added to ensure that
|
||||
@@ -52,6 +55,12 @@ plus space-dash-space to allow proper sorting of groups.</p>
|
||||
has been deprecated. Instead, use the conversion functions between index number
|
||||
and group string that have been added to dbStaticLib.</p>
|
||||
|
||||
<p>When a DBD file containing record-type descriptions is expanded, any
|
||||
old-style <tt>GUI_xxx</tt> group names will be replaced by a new-style
|
||||
string for use by the IOC. This permits an older record type to be used with
|
||||
the 3.15.4 release, although eventually record types should be converted by
|
||||
hand with better group names used.</p>
|
||||
|
||||
<h3>CA server configuration changes</h3>
|
||||
|
||||
<p>RSRV now honors EPICS_CAS_INTF_ADDR_LIST and binds only to the provided list
|
||||
@@ -109,6 +118,67 @@ dbQuietMacroWarnings=1 <i>VxWorks</i>
|
||||
<h2 align="center">Changes pulled from the 3.14 branch since 3.15.3</h2>
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Making IOC ca_get operations atomic</h3>
|
||||
|
||||
<p>When a CA client gets data from an IOC record using a compound data type such
|
||||
as <tt>DBR_TIME_DOUBLE</tt> the value field is fetched from the database in a
|
||||
separate call than the other metadata, without keeping the record locked. This
|
||||
allows some other thread such as a periodic scan thread a chance to interrupt
|
||||
the get operation and process the record in between. CA monitors have always
|
||||
been atomic as long as the value data isn't a string or an array, but this race
|
||||
condition in the CA get path has now been fixed so the record will stay locked
|
||||
between the two fetch operations.</p>
|
||||
|
||||
<p>This fixes <a href="https://bugs.launchpad.net/epics-base/+bug/1581212">
|
||||
Launchpad bug #1581212</a>, thanks to Till Strauman and Dehong Zhang.</p>
|
||||
|
||||
<h3>New CONFIG_SITE variable for running self-tests</h3>
|
||||
|
||||
<p>The 'make runtests' and 'make tapfiles' build targets normally only run the
|
||||
self-tests for the main <tt>EPICS_HOST_ARCH</tt> architecture. If the host is
|
||||
able to execute self-test programs for other target architectures that are being
|
||||
built by the host, such as when building a <tt>-debug</tt> version of the host
|
||||
architecture for example, the names of those other architectures can be added to
|
||||
the new <tt>CROSS_COMPILER_RUNTEST_ARCHS</tt> variable in either the
|
||||
<tt>configure/CONFIG_SITE</tt> file or in an appropriate
|
||||
<tt>configure/os/CONFIG_SITE.<host>.Common</tt> file to have the test
|
||||
programs for those targets be run as well.</p>
|
||||
|
||||
<h3>Additional RELEASE file checks</h3>
|
||||
|
||||
<p>An additional check has been added at build-time for the contents of the
|
||||
configure/RELEASE file(s), which will mostly only affect users of the Debian
|
||||
EPICS packages published by NSLS-2. Support modules may share an install path,
|
||||
but all such modules must be listed adjacent to each other in any RELEASE files
|
||||
that point to them. For example the following will fail the new checks:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
AUTOSAVE = /usr/lib/epics
|
||||
ASYN = /home/mdavidsaver/asyn
|
||||
EPICS_BASE = /usr/lib/epics
|
||||
</pre></blockquote>
|
||||
|
||||
<p>giving the compile-time error</p>
|
||||
|
||||
<blockquote><pre>
|
||||
This application's RELEASE file(s) define
|
||||
EPICS_BASE = /usr/lib/epics
|
||||
after but not adjacent to
|
||||
AUTOSAVE = /usr/lib/epics
|
||||
Module definitions that share paths must be grouped together.
|
||||
Either remove a definition, or move it to a line immediately
|
||||
above or below the other(s).
|
||||
Any non-module definitions belong in configure/CONFIG_SITE.
|
||||
</pre></blockquote>
|
||||
|
||||
|
||||
<p>In many cases such as the one above the order of the <tt>AUTOSAVE</tt> and
|
||||
<tt>ASYN</tt> lines can be swapped to let the checks pass, but if the
|
||||
<tt>AUTOSAVE</tt> module depended on <tt>ASYN</tt> and hence had to appear
|
||||
before it in the list this error indicates that <tt>AUTOSAVE</tt> should also be
|
||||
built in its own private area; a shared copy would likely be incompatible with
|
||||
the version of <tt>ASYN</tt> built in the home directory.</p>
|
||||
|
||||
<h3>String field buffer overflows</h3>
|
||||
|
||||
<p>Two buffer overflow bugs that can crash the IOC have been fixed, caused by
|
||||
|
||||
@@ -333,6 +333,12 @@ cac::~cac ()
|
||||
|
||||
this->ipToAEngine.release ();
|
||||
|
||||
// clean-up the list of un-notified msg objects
|
||||
while ( msgForMultiplyDefinedPV * msg = this->msgMultiPVList.get() ) {
|
||||
msg->~msgForMultiplyDefinedPV ();
|
||||
this->mdpvFreeList.release ( msg );
|
||||
}
|
||||
|
||||
errlogFlush ();
|
||||
|
||||
osiSockRelease ();
|
||||
@@ -606,6 +612,8 @@ void cac::transferChanToVirtCircuit (
|
||||
msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList )
|
||||
msgForMultiplyDefinedPV ( this->ipToAEngine,
|
||||
*this, pChan->pName ( guard ), acc );
|
||||
// cac keeps a list of these objects for proper clean-up in ~cac
|
||||
this->msgMultiPVList.add ( *pMsg );
|
||||
// It is possible for the ioInitiate call below to
|
||||
// call the callback directly if queue quota is exceeded.
|
||||
// This callback takes the callback lock and therefore we
|
||||
@@ -1297,6 +1305,8 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->exception ( mgr.cbGuard, guard, ECA_DBLCHNL, buf, __FILE__, __LINE__ );
|
||||
}
|
||||
// remove from the list and delete msg object
|
||||
this->msgMultiPVList.remove ( mfmdpv );
|
||||
mfmdpv.~msgForMultiplyDefinedPV ();
|
||||
this->mdpvFreeList.release ( & mfmdpv );
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ private:
|
||||
resTable < tcpiiu, caServerID > serverTable;
|
||||
tsDLList < tcpiiu > circuitList;
|
||||
tsDLList < SearchDest > searchDestList;
|
||||
tsDLList < msgForMultiplyDefinedPV > msgMultiPVList;
|
||||
tsFreeList
|
||||
< class tcpiiu, 32, epicsMutexNOOP >
|
||||
freeListVirtualCircuit;
|
||||
|
||||
@@ -55,8 +55,10 @@ msgForMultiplyDefinedPV::~msgForMultiplyDefinedPV ()
|
||||
|
||||
void msgForMultiplyDefinedPV::transactionComplete ( const char * pHostNameRej )
|
||||
{
|
||||
// calls into cac for the notification
|
||||
// the msg object (= this) is being deleted as part of the notification
|
||||
this->cb.pvMultiplyDefinedNotify ( *this, this->channel, this->acc, pHostNameRej );
|
||||
// !! dont touch this pointer after this point because object has been deleted !!
|
||||
// !! dont touch 'this' pointer after this point because object has been deleted !!
|
||||
}
|
||||
|
||||
void * msgForMultiplyDefinedPV::operator new ( size_t size,
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "tsDLList.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef msgForMultiplyDefinedPVh_epicsExportSharedSymbols
|
||||
@@ -47,7 +48,9 @@ public:
|
||||
const char * pAcc, const char * pRej ) = 0;
|
||||
};
|
||||
|
||||
class msgForMultiplyDefinedPV : public ipAddrToAsciiCallBack {
|
||||
class msgForMultiplyDefinedPV :
|
||||
public ipAddrToAsciiCallBack,
|
||||
public tsDLNode < msgForMultiplyDefinedPV > {
|
||||
public:
|
||||
msgForMultiplyDefinedPV ( ipAddrToAsciiEngine & engine,
|
||||
callbackForMultiplyDefinedPV &, const char * pChannelName,
|
||||
@@ -62,8 +65,8 @@ private:
|
||||
ipAddrToAsciiTransaction & dnsTransaction;
|
||||
callbackForMultiplyDefinedPV & cb;
|
||||
void transactionComplete ( const char * pHostName );
|
||||
msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & );
|
||||
msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & );
|
||||
msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & );
|
||||
msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
|
||||
@@ -20,10 +20,19 @@ ifeq ($(OS_CLASS),Darwin)
|
||||
LOADABLE_SHRLIB_SUFFIX = .$(shell $(PERL) ../perlConfig.pl dlext)
|
||||
endif
|
||||
|
||||
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
|
||||
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
|
||||
PERL_ARCHPATH = $(PERL_VERSION)/$(PERL_ARCHNAME)
|
||||
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 ($(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 ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
|
||||
LOADABLE_LIBRARY_HOST = Cap5
|
||||
@@ -41,6 +50,8 @@ ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
|
||||
HTMLS = CA.html
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
Cap5_SRCS = Cap5.xs
|
||||
Cap5_LIBS = ca Com
|
||||
@@ -52,10 +63,6 @@ CLEANS += Cap5.c pod2htmd.tmp pod2htmi.tmp
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
ifdef T_A
|
||||
EXTUTILS = $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
|
||||
PERLBIN = $(shell $(PERL) ../perlConfig.pl bin)
|
||||
XSUBPP = $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
|
||||
|
||||
%.c: ../%.xs
|
||||
$(RM) $@ $@_new
|
||||
$(PERL) $(XSUBPP) -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@
|
||||
|
||||
@@ -492,14 +492,13 @@ int main (int argc, char *argv[])
|
||||
} else { /* Not an ENUM */
|
||||
|
||||
if (charArrAsStr) {
|
||||
count = len;
|
||||
dbrType = DBR_CHAR;
|
||||
ebuf = calloc(strlen(cbuf)+1, sizeof(char));
|
||||
ebuf = calloc(len, sizeof(char));
|
||||
if(!ebuf) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
epicsStrnRawFromEscaped(ebuf, strlen(cbuf)+1, cbuf, strlen(cbuf));
|
||||
count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1;
|
||||
} else {
|
||||
for (i = 0; i < count; ++i) {
|
||||
epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr));
|
||||
|
||||
@@ -348,10 +348,8 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
//
|
||||
caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
|
||||
{
|
||||
int status;
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
status = this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
|
||||
this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
|
||||
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available, 0 );
|
||||
|
||||
this->out.commitMsg ();
|
||||
|
||||
@@ -402,19 +402,29 @@ struct rset * dbGetRset(const struct dbAddr *paddr)
|
||||
}
|
||||
|
||||
long dbPutAttribute(
|
||||
const char *recordTypename,const char *name,const char*value)
|
||||
const char *recordTypename, const char *name, const char *value)
|
||||
{
|
||||
DBENTRY dbEntry;
|
||||
DBENTRY *pdbEntry = &dbEntry;
|
||||
long status=0;
|
||||
DBENTRY dbEntry;
|
||||
DBENTRY *pdbEntry = &dbEntry;
|
||||
long status = 0;
|
||||
|
||||
if(!pdbbase) return(S_db_notFound);
|
||||
dbInitEntry(pdbbase,pdbEntry);
|
||||
status = dbFindRecordType(pdbEntry,recordTypename);
|
||||
if(!status) status = dbPutRecordAttribute(pdbEntry,name,value);
|
||||
dbFinishEntry(pdbEntry);
|
||||
if(status) errMessage(status,"dbPutAttribute failure");
|
||||
return(status);
|
||||
if (!pdbbase)
|
||||
return S_db_notFound;
|
||||
if (!name) {
|
||||
status = S_db_badField;
|
||||
goto done;
|
||||
}
|
||||
if (!value)
|
||||
value = "";
|
||||
dbInitEntry(pdbbase, pdbEntry);
|
||||
status = dbFindRecordType(pdbEntry, recordTypename);
|
||||
if (!status)
|
||||
status = dbPutRecordAttribute(pdbEntry, name, value);
|
||||
dbFinishEntry(pdbEntry);
|
||||
done:
|
||||
if (status)
|
||||
errMessage(status, "dbPutAttribute failure");
|
||||
return status;
|
||||
}
|
||||
|
||||
int dbIsValueField(const struct dbFldDes *pdbFldDes)
|
||||
|
||||
@@ -224,6 +224,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
return S_db_badDbrtype;
|
||||
|
||||
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
|
||||
&& paddr->special != SPC_DBADDR
|
||||
&& paddr->special != SPC_ATTRIBUTE) {
|
||||
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "dbChannel.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbNotify.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "recSup.h"
|
||||
@@ -153,28 +154,30 @@ int dbChannel_get_count(
|
||||
* in the dbAccess.c dbGet() and getOptions() routines.
|
||||
*/
|
||||
|
||||
dbScanLock(dbChannelRecord(chan));
|
||||
|
||||
switch(buffer_type) {
|
||||
case(oldDBR_STRING):
|
||||
status = dbChannelGetField(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
/* case(oldDBR_INT): */
|
||||
case(oldDBR_SHORT):
|
||||
status = dbChannelGetField(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_FLOAT):
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_ENUM):
|
||||
status = dbChannelGetField(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_CHAR):
|
||||
status = dbChannelGetField(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_LONG):
|
||||
status = dbChannelGetField(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_DOUBLE):
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
|
||||
case(oldDBR_STS_STRING):
|
||||
@@ -187,10 +190,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_STRING, pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_STRING, pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -203,10 +206,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -218,10 +221,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -233,10 +236,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -248,10 +251,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -263,10 +266,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -278,11 +281,11 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -296,12 +299,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_STRING, pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_STRING, pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -315,12 +318,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -333,12 +336,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -351,12 +354,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -369,12 +372,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_CHAR, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_CHAR, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -387,12 +390,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -405,12 +408,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -428,7 +431,7 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -440,7 +443,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -457,7 +460,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -470,7 +473,7 @@ int dbChannel_get_count(
|
||||
pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
|
||||
pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -486,7 +489,7 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -498,7 +501,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -513,7 +516,7 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -525,7 +528,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -542,7 +545,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -555,7 +558,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -574,7 +577,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
|
||||
DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -588,7 +591,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -606,7 +609,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -621,7 +624,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
|
||||
pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit);
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -638,7 +641,7 @@ int dbChannel_get_count(
|
||||
memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
|
||||
/* first get status and severity */
|
||||
options = DBR_STATUS | DBR_ENUM_STRS;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
no_str = newSt.no_str;
|
||||
@@ -648,7 +651,7 @@ int dbChannel_get_count(
|
||||
strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i]));
|
||||
/*now get values*/
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -665,7 +668,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
|
||||
DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -679,7 +682,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -696,7 +699,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
|
||||
DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -710,7 +713,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -728,7 +731,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -743,7 +746,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -756,13 +759,13 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->ackt = newSt.ackt;
|
||||
pold->acks = newSt.acks;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_STRING, pold->value,
|
||||
status = dbChannelGet(chan, DBR_STRING, pold->value,
|
||||
&options, nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -791,8 +794,12 @@ int dbChannel_get_count(
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
dbScanUnlock(dbChannelRecord(chan));
|
||||
|
||||
if (status) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
#ifndef INCLdb_field_logh
|
||||
#define INCLdb_field_logh
|
||||
|
||||
#include "epicsTime.h"
|
||||
#include <epicsTime.h>
|
||||
#include <epicsTypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -32,18 +33,20 @@ extern "C" {
|
||||
* priority task pending on the event queue wakes up). Strings would slow down
|
||||
* events for more reasonable size values. DB fields of native type string
|
||||
* will most likely change infrequently.
|
||||
*
|
||||
*
|
||||
* Strings can be added to the set of types for which updates will be queued
|
||||
* by defining the macro DB_EVENT_LOG_STRINGS. The code in db_add_event()
|
||||
* will adjust automatically, it just compares field sizes.
|
||||
*/
|
||||
union native_value {
|
||||
short dbf_int;
|
||||
short dbf_short;
|
||||
float dbf_float;
|
||||
short dbf_enum;
|
||||
char dbf_char;
|
||||
long dbf_long;
|
||||
double dbf_double;
|
||||
epicsInt8 dbf_char;
|
||||
epicsInt16 dbf_short;
|
||||
epicsEnum16 dbf_enum;
|
||||
epicsInt32 dbf_long;
|
||||
epicsFloat32 dbf_float;
|
||||
epicsFloat64 dbf_double;
|
||||
#ifdef DB_EVENT_LOG_STRINGS
|
||||
char dbf_string[MAX_STRING_SIZE];
|
||||
char dbf_string[MAX_STRING_SIZE];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ MAIN(callbackParallelTest)
|
||||
myPvt *pcbt[NCALLBACKS];
|
||||
epicsTimeStamp start;
|
||||
int noCpus = epicsThreadGetCPUs();
|
||||
int i, j;
|
||||
int i, j, slowups, faults;
|
||||
/* Statistics: min/max/sum/sum^2/n for each priority */
|
||||
double setupError[NUM_CALLBACK_PRIORITIES][5];
|
||||
double timeError[NUM_CALLBACK_PRIORITIES][5];
|
||||
@@ -109,7 +109,7 @@ MAIN(callbackParallelTest)
|
||||
for (j = 0; j < 5; j++)
|
||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||
|
||||
testPlan(NCALLBACKS * 2 + 1);
|
||||
testPlan(4);
|
||||
|
||||
testDiag("Starting %d parallel callback threads", noCpus);
|
||||
|
||||
@@ -138,7 +138,7 @@ MAIN(callbackParallelTest)
|
||||
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
|
||||
pcbt[NCALLBACKS-1]->pass = 0;
|
||||
|
||||
testOk1(epicsTimeGetCurrent(&start)==epicsTimeOK);
|
||||
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
callbackRequest(&pcbt[i]->cb1);
|
||||
@@ -147,28 +147,43 @@ MAIN(callbackParallelTest)
|
||||
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
|
||||
|
||||
epicsEventWait(finished);
|
||||
|
||||
slowups = 0;
|
||||
faults = 0;
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
testFail("pass = %d for delay = %f", pcbt[i]->pass, pcbt[i]->delay);
|
||||
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
|
||||
++faults, pcbt[i]->pass, pcbt[i]->delay);
|
||||
else {
|
||||
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
|
||||
testOk(fabs(delta) < 0.05, "callback %.02f setup time |%f| < 0.05",
|
||||
|
||||
if (fabs(delta) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
|
||||
pcbt[i]->delay, delta);
|
||||
}
|
||||
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
|
||||
}
|
||||
}
|
||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
||||
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
|
||||
|
||||
slowups = 0;
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
double delta, error;
|
||||
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
continue;
|
||||
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
|
||||
error = delta - pcbt[i]->delay;
|
||||
testOk(fabs(error) < 0.05, "delay %.02f seconds, callback time error |%.04f| < 0.05",
|
||||
if (fabs(error) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
|
||||
pcbt[i]->delay, error);
|
||||
}
|
||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
||||
}
|
||||
testOk(slowups < 5, "%d slowups during callbacks", slowups);
|
||||
|
||||
testDiag("Setup time statistics");
|
||||
printStats(setupError[0], "LOW");
|
||||
|
||||
@@ -99,7 +99,7 @@ MAIN(callbackTest)
|
||||
{
|
||||
myPvt *pcbt[NCALLBACKS];
|
||||
epicsTimeStamp start;
|
||||
int i, j;
|
||||
int i, j, slowups, faults;
|
||||
/* Statistics: min/max/sum/sum^2/n for each priority */
|
||||
double setupError[NUM_CALLBACK_PRIORITIES][5];
|
||||
double timeError[NUM_CALLBACK_PRIORITIES][5];
|
||||
@@ -109,7 +109,7 @@ MAIN(callbackTest)
|
||||
for (j = 0; j < 5; j++)
|
||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||
|
||||
testPlan(NCALLBACKS * 2 + 1);
|
||||
testPlan(4);
|
||||
|
||||
callbackInit();
|
||||
epicsThreadSleep(1.0);
|
||||
@@ -135,7 +135,7 @@ MAIN(callbackTest)
|
||||
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
|
||||
pcbt[NCALLBACKS-1]->pass = 0;
|
||||
|
||||
testOk1(epicsTimeGetCurrent(&start)==epicsTimeOK);
|
||||
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
callbackRequest(&pcbt[i]->cb1);
|
||||
@@ -144,28 +144,43 @@ MAIN(callbackTest)
|
||||
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
|
||||
|
||||
epicsEventWait(finished);
|
||||
|
||||
slowups = 0;
|
||||
faults = 0;
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
testFail("pass = %d for delay = %f", pcbt[i]->pass, pcbt[i]->delay);
|
||||
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
|
||||
++faults, pcbt[i]->pass, pcbt[i]->delay);
|
||||
else {
|
||||
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
|
||||
testOk(fabs(delta) < 0.05, "callback %.02f setup time |%f| < 0.05",
|
||||
|
||||
if (fabs(delta) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
|
||||
pcbt[i]->delay, delta);
|
||||
}
|
||||
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
|
||||
}
|
||||
}
|
||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
||||
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
|
||||
|
||||
slowups = 0;
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
double delta, error;
|
||||
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
continue;
|
||||
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
|
||||
error = delta - pcbt[i]->delay;
|
||||
testOk(fabs(error) < 0.05, "delay %.02f seconds, callback time error |%.04f| < 0.05",
|
||||
if (fabs(error) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
|
||||
pcbt[i]->delay, error);
|
||||
}
|
||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
||||
}
|
||||
testOk(slowups < 5, "%d slowups during callbacks", slowups);
|
||||
|
||||
testDiag("Setup time statistics");
|
||||
printStats(setupError[0], "LOW");
|
||||
|
||||
@@ -1112,7 +1112,7 @@ unsigned cid
|
||||
* casAccessRightsCB()
|
||||
*
|
||||
* If access right state changes then inform the client.
|
||||
*
|
||||
* asLock is held
|
||||
*/
|
||||
static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
|
||||
{
|
||||
@@ -1568,6 +1568,9 @@ static void sendAllUpdateAS ( struct client *client )
|
||||
else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ) {
|
||||
access_rights_reply ( pciu );
|
||||
}
|
||||
else if ( pciu->state == rsrvCS_shutdown ) {
|
||||
/* no-op */
|
||||
}
|
||||
else {
|
||||
errlogPrintf (
|
||||
"%s at %d: corrupt channel state detected durring AR update\n",
|
||||
@@ -2047,10 +2050,15 @@ static int clear_channel_reply ( caHdrLargeArray *mp,
|
||||
if ( pciu->state == rsrvCS_inService ||
|
||||
pciu->state == rsrvCS_pendConnectResp ) {
|
||||
ellDelete ( &client->chanList, &pciu->node );
|
||||
pciu->state = rsrvCS_shutdown;
|
||||
}
|
||||
else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ||
|
||||
pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) {
|
||||
ellDelete ( &client->chanPendingUpdateARList, &pciu->node );
|
||||
pciu->state = rsrvCS_shutdown;
|
||||
}
|
||||
else if ( pciu->state == rsrvCS_shutdown ) {
|
||||
/* no-op */
|
||||
}
|
||||
else {
|
||||
epicsMutexUnlock( client->chanListLock );
|
||||
|
||||
@@ -1134,6 +1134,7 @@ static void destroyAllChannels (
|
||||
|
||||
epicsMutexMustLock ( client->chanListLock );
|
||||
pciu = (struct channel_in_use *) ellGet ( pList );
|
||||
if(pciu) pciu->state = rsrvCS_shutdown;
|
||||
epicsMutexUnlock ( client->chanListLock );
|
||||
|
||||
if ( ! pciu ) {
|
||||
|
||||
@@ -99,12 +99,25 @@ typedef struct client {
|
||||
char disconnect; /* disconnect detected */
|
||||
} client;
|
||||
|
||||
/* Channel state shows which struct client list a
|
||||
* channel_in_us::node is in.
|
||||
*
|
||||
* client::chanList
|
||||
* rsrvCS_pendConnectResp, rsrvCS_inService
|
||||
* client::chanPendingUpdateARList
|
||||
* rsrvCS_pendConnectRespUpdatePendAR, rsrvCS_inServiceUpdatePendAR
|
||||
* Not in any list
|
||||
* rsrvCS_shutdown
|
||||
*
|
||||
* rsrvCS_invalid is not used
|
||||
*/
|
||||
enum rsrvChanState {
|
||||
rsrvCS_invalid,
|
||||
rsrvCS_pendConnectResp,
|
||||
rsrvCS_inService,
|
||||
rsrvCS_pendConnectRespUpdatePendAR,
|
||||
rsrvCS_inServiceUpdatePendAR
|
||||
rsrvCS_inServiceUpdatePendAR,
|
||||
rsrvCS_shutdown
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -155,7 +155,7 @@ epicsShareFunc long
|
||||
break;
|
||||
|
||||
case ABS_VAL:
|
||||
if (*ptop < 0.0) *ptop = - *ptop;
|
||||
*ptop = fabs(*ptop);
|
||||
break;
|
||||
|
||||
case EXP:
|
||||
|
||||
@@ -70,12 +70,12 @@ epicsShareFunc int
|
||||
/* These macros return 1 if successful, 0 on failure.
|
||||
* This is analagous to the return value from sscanf()
|
||||
*/
|
||||
#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base, NULL)
|
||||
#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base, NULL)
|
||||
#define epicsScanLLong(str, to, base) !epicsParseLLong(str, to, base, NULL)
|
||||
#define epicsScanULLong(str, to, base) !epicsParseULLong(str, to, base, NULL)
|
||||
#define epicsScanFloat(str, to) !epicsParseFloat(str, to, NULL)
|
||||
#define epicsScanDouble(str, to) !epicsParseDouble(str, to, NULL)
|
||||
#define epicsScanLong(str, to, base) (!epicsParseLong(str, to, base, NULL))
|
||||
#define epicsScanULong(str, to, base) (!epicsParseULong(str, to, base, NULL))
|
||||
#define epicsScanLLong(str, to, base) (!epicsParseLLong(str, to, base, NULL))
|
||||
#define epicsScanULLong(str, to, base) (!epicsParseULLong(str, to, base, NULL))
|
||||
#define epicsScanFloat(str, to) (!epicsParseFloat(str, to, NULL))
|
||||
#define epicsScanDouble(str, to) (!epicsParseDouble(str, to, NULL))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -265,12 +265,16 @@ void ipAddrToAsciiEnginePrivate::run ()
|
||||
continue;
|
||||
}
|
||||
|
||||
// fix for lp:1580623
|
||||
// a destructing cac sets pCurrent to NULL, so
|
||||
// make local copy to avoid race when releasing the guard
|
||||
ipAddrToAsciiTransactionPrivate *pCur = this->pCurrent;
|
||||
this->callbackInProgress = true;
|
||||
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// dont call callback with lock applied
|
||||
this->pCurrent->pCB->transactionComplete ( this->nameTmp );
|
||||
pCur->pCB->transactionComplete ( this->nameTmp );
|
||||
}
|
||||
|
||||
this->callbackInProgress = false;
|
||||
|
||||
@@ -73,6 +73,21 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
struct ifreq *pifreq;
|
||||
struct ifreq *pnextifreq;
|
||||
osiSockAddrNode *pNewNode;
|
||||
|
||||
if ( pMatchAddr->sa.sa_family == AF_INET ) {
|
||||
if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) {
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) );
|
||||
if ( pNewNode == NULL ) {
|
||||
errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" );
|
||||
return;
|
||||
}
|
||||
pNewNode->addr.ia.sin_family = AF_INET;
|
||||
pNewNode->addr.ia.sin_port = htons ( 0 );
|
||||
pNewNode->addr.ia.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||
ellAdd ( pList, &pNewNode->node );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* use pool so that we avoid using too much stack space
|
||||
@@ -100,7 +115,6 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
|
||||
for ( pifreq = pIfreqList; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) {
|
||||
uint32_t current_ifreqsize;
|
||||
struct sockaddr_in if_addr;
|
||||
|
||||
/*
|
||||
* find the next ifreq
|
||||
@@ -124,7 +138,6 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): interface \"%s\" was not AF_INET\n", pIfreqList->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
if_addr = *(struct sockaddr_in *)&pIfreqList->ifr_addr;
|
||||
|
||||
/*
|
||||
* if it isnt a wildcarded interface then look for
|
||||
@@ -135,7 +148,8 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
continue;
|
||||
}
|
||||
if ( pMatchAddr->ia.sin_addr.s_addr != htonl (INADDR_ANY) ) {
|
||||
if ( if_addr.sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) {
|
||||
struct sockaddr_in *pInetAddr = (struct sockaddr_in *) &pIfreqList->ifr_addr;
|
||||
if ( pInetAddr->sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" didnt match\n", pIfreqList->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
@@ -156,6 +170,14 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if ( pIfreqList->ifr_flags & IFF_LOOPBACK ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): ignoring loopback interface: \"%s\"\n", pIfreqList->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) );
|
||||
if ( pNewNode == NULL ) {
|
||||
errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" );
|
||||
@@ -174,14 +196,22 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
* interface.
|
||||
*/
|
||||
if ( pIfreqList->ifr_flags & IFF_BROADCAST ) {
|
||||
osiSockAddr baddr;
|
||||
status = socket_ioctl (socket, SIOCGIFBRDADDR, pIfreqList);
|
||||
if ( status ) {
|
||||
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": bcast addr fetch fail\n", pIfreqList->ifr_name);
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
|
||||
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( pNewNode->addr.ia.sin_addr.s_addr ) ) );
|
||||
baddr.sa = pIfreqList->ifr_broadaddr;
|
||||
if (baddr.ia.sin_family==AF_INET && baddr.ia.sin_addr.s_addr != INADDR_ANY) {
|
||||
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
|
||||
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
|
||||
} else {
|
||||
ifDepenDebugPrintf ( ( "Ignoring broadcast addr = \n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#if defined (IFF_POINTOPOINT)
|
||||
else if ( pIfreqList->ifr_flags & IFF_POINTOPOINT ) {
|
||||
@@ -193,22 +223,6 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
}
|
||||
pNewNode->addr.sa = pIfreqList->ifr_dstaddr;
|
||||
}
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
/* On Linux, even though the 'lo' interface doesn't set IFF_BROADCAST
|
||||
* a broadcast route often exists. Assume that sending to 127.255.255.255
|
||||
* reaches all local listeners.
|
||||
*
|
||||
* $ ip route show table local scope link dev lo
|
||||
* broadcast 127.0.0.0 proto kernel src 127.0.0.1
|
||||
* broadcast 127.255.255.255 proto kernel src 127.0.0.1
|
||||
*/
|
||||
else if ( pIfreqList->ifr_flags & IFF_LOOPBACK && if_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK) ) {
|
||||
memset(&pNewNode->addr.ia, 0, sizeof(pNewNode->addr.ia));
|
||||
pNewNode->addr.ia.sin_family = AF_INET;
|
||||
pNewNode->addr.ia.sin_addr.s_addr = htonl(0x7fffffff);
|
||||
ifDepenDebugPrintf ( ( "assume loopback broadcast addr = %x\n", ntohl ( pNewNode->addr.ia.sin_addr.s_addr ) ) );
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
ifDepenDebugPrintf ( ( "osiSockDiscoverBroadcastAddresses(): net intf \"%s\": not point to point or bcast?\n", pIfreqList->ifr_name ) );
|
||||
|
||||
@@ -66,6 +66,7 @@ dbRecStd_SRCS += devSoSoftCallback.c
|
||||
|
||||
dbRecStd_SRCS += devTimestamp.c
|
||||
dbRecStd_SRCS += devStdio.c
|
||||
dbRecStd_SRCS += devEnviron.c
|
||||
|
||||
dbRecStd_SRCS += asSubRecordFunctions.c
|
||||
|
||||
|
||||
128
src/std/dev/devEnviron.c
Normal file
128
src/std/dev/devEnviron.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/* devEnviron.c */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alarm.h"
|
||||
#include "dbCommon.h"
|
||||
#include "devSup.h"
|
||||
#include "errlog.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
|
||||
#include "lsiRecord.h"
|
||||
#include "stringinRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* lsi device support */
|
||||
|
||||
static long add_lsi(dbCommon *pcommon) {
|
||||
lsiRecord *prec = (lsiRecord *) pcommon;
|
||||
|
||||
if (prec->inp.type != INST_IO)
|
||||
return S_dev_badInpType;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long del_lsi(dbCommon *pcommon) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dsxt dsxtLsiEnviron = {
|
||||
add_lsi, del_lsi
|
||||
};
|
||||
|
||||
static long init_lsi(int pass)
|
||||
{
|
||||
if (pass == 0)
|
||||
devExtend(&dsxtLsiEnviron);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long read_lsi(lsiRecord *prec)
|
||||
{
|
||||
const char *val = getenv(prec->inp.value.instio.string);
|
||||
|
||||
if (val) {
|
||||
strncpy(prec->val, val, prec->sizv);
|
||||
prec->val[prec->sizv - 1] = 0;
|
||||
prec->len = strlen(prec->val);
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
else {
|
||||
prec->val[0] = 0;
|
||||
prec->len = 1;
|
||||
prec->udf = TRUE;
|
||||
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lsidset devLsiEnviron = {
|
||||
5, NULL, init_lsi, NULL, NULL, read_lsi
|
||||
};
|
||||
epicsExportAddress(dset, devLsiEnviron);
|
||||
|
||||
|
||||
/* stringin device support */
|
||||
|
||||
static long add_stringin(dbCommon *pcommon) {
|
||||
stringinRecord *prec = (stringinRecord *) pcommon;
|
||||
|
||||
if (prec->inp.type != INST_IO)
|
||||
return S_dev_badInpType;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long del_stringin(dbCommon *pcommon) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dsxt dsxtSiEnviron = {
|
||||
add_stringin, del_stringin
|
||||
};
|
||||
|
||||
static long init_stringin(int pass)
|
||||
{
|
||||
if (pass == 0)
|
||||
devExtend(&dsxtSiEnviron);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long read_stringin(stringinRecord *prec)
|
||||
{
|
||||
const char *val = getenv(prec->inp.value.instio.string);
|
||||
|
||||
if (val) {
|
||||
strncpy(prec->val, val, MAX_STRING_SIZE);
|
||||
prec->val[MAX_STRING_SIZE - 1] = 0;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
else {
|
||||
prec->val[0] = 0;
|
||||
prec->udf = TRUE;
|
||||
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
dset common;
|
||||
DEVSUPFUN read;
|
||||
} devSiEnviron = {
|
||||
{5, NULL, init_stringin, NULL, NULL}, read_stringin
|
||||
};
|
||||
epicsExportAddress(dset, devSiEnviron);
|
||||
@@ -58,5 +58,8 @@ device(lso,INST_IO,devLsoStdio,"stdio")
|
||||
device(printf,INST_IO,devPrintfStdio,"stdio")
|
||||
device(stringout,INST_IO,devSoStdio,"stdio")
|
||||
|
||||
device(lsi,INST_IO,devLsiEnviron,"getenv")
|
||||
device(stringin,INST_IO,devSiEnviron,"getenv")
|
||||
|
||||
device(bi, INST_IO, devBiDbState, "Db State")
|
||||
device(bo, INST_IO, devBoDbState, "Db State")
|
||||
|
||||
@@ -158,9 +158,10 @@ static long put_array_info(DBADDR *paddr, long nNew)
|
||||
{
|
||||
lsiRecord *prec = (lsiRecord *) paddr->precord;
|
||||
|
||||
if (nNew == prec->sizv)
|
||||
--nNew; /* truncated string */
|
||||
prec->val[nNew] = 0; /* ensure data is terminated */
|
||||
if (nNew >= prec->sizv)
|
||||
nNew = prec->sizv - 1; /* truncated string */
|
||||
if (paddr->field_type == DBF_CHAR)
|
||||
prec->val[nNew] = 0; /* ensure data is terminated */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -200,9 +200,10 @@ static long put_array_info(DBADDR *paddr, long nNew)
|
||||
{
|
||||
lsoRecord *prec = (lsoRecord *) paddr->precord;
|
||||
|
||||
if (nNew == prec->sizv)
|
||||
--nNew; /* truncated string */
|
||||
prec->val[nNew] = 0; /* ensure data is terminated */
|
||||
if (nNew >= prec->sizv)
|
||||
nNew = prec->sizv - 1; /* truncated string */
|
||||
if (paddr->field_type == DBF_CHAR)
|
||||
prec->val[nNew] = 0; /* ensure data is terminated */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,14 @@ testHarness_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/analogMonitorTest.dbd ../analogMonitorTest.db
|
||||
TESTS += analogMonitorTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/regressTest.dbd
|
||||
regressTest_DBD += base.dbd
|
||||
TESTPROD_HOST += regressTest
|
||||
regressTest_SRCS += regressTest.c
|
||||
regressTest_SRCS += regressTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/regressTest.dbd ../regressArray1.db
|
||||
TESTS += regressTest
|
||||
|
||||
# epicsRunRecordTests runs all the test programs in a known working order.
|
||||
testHarness_SRCS += epicsRunRecordTests.c
|
||||
|
||||
|
||||
9
src/std/rec/test/regressArray1.db
Normal file
9
src/std/rec/test/regressArray1.db
Normal file
@@ -0,0 +1,9 @@
|
||||
record(waveform, "wf") {
|
||||
field(FTVL, "DOUBLE")
|
||||
field(NELM, "1")
|
||||
field(FLNK, "co")
|
||||
}
|
||||
record(calcout, "co") {
|
||||
field(CALC, "A")
|
||||
field(INPA, "wf")
|
||||
}
|
||||
73
src/std/rec/test/regressTest.c
Normal file
73
src/std/rec/test/regressTest.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <dbUnitTest.h>
|
||||
#include <testMain.h>
|
||||
#include <dbAccess.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#include <calcoutRecord.h>
|
||||
#include <waveformRecord.h>
|
||||
|
||||
/*
|
||||
* Test the some identified regressions
|
||||
*/
|
||||
|
||||
void regressTest_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
/*
|
||||
* https://bugs.launchpad.net/epics-base/+bug/1577108
|
||||
*/
|
||||
static
|
||||
void testArrayLength1(void)
|
||||
{
|
||||
waveformRecord *precwf;
|
||||
calcoutRecord *precco;
|
||||
double *pbuf;
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("regressTest.dbd", NULL, NULL);
|
||||
|
||||
regressTest_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
testdbReadDatabase("regressArray1.db", NULL, NULL);
|
||||
|
||||
precwf = (waveformRecord*)testdbRecordPtr("wf");
|
||||
precco = (calcoutRecord*)testdbRecordPtr("co");
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
dbScanLock((dbCommon*)precwf);
|
||||
pbuf = (double*)precwf->bptr;
|
||||
dbScanUnlock((dbCommon*)precwf);
|
||||
|
||||
testdbPutFieldOk("wf", DBF_DOUBLE, 2.0);
|
||||
|
||||
dbScanLock((dbCommon*)precwf);
|
||||
testOk(precwf->nord==1, "wf.NORD = %u == 1", (unsigned)precwf->nord);
|
||||
testOk(pbuf[0]==2.0, "wf.VAL[0] = %f == 2.0", pbuf[0]);
|
||||
dbScanUnlock((dbCommon*)precwf);
|
||||
|
||||
dbScanLock((dbCommon*)precco);
|
||||
testOk(precco->a==2.0, "co.A = %f == 2.0", precco->a);
|
||||
dbScanUnlock((dbCommon*)precco);
|
||||
|
||||
testdbGetFieldEqual("co", DBF_DOUBLE, 2.0);
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
MAIN(regressTest)
|
||||
{
|
||||
testPlan(5);
|
||||
testArrayLength1();
|
||||
return testDone();
|
||||
}
|
||||
@@ -1,7 +1,15 @@
|
||||
# $Revision-Id$
|
||||
#
|
||||
# softIocExit.db
|
||||
|
||||
record(sub,"$(IOC):exit") {
|
||||
field(DESC,"Exit subroutine")
|
||||
field(SCAN,"Passive")
|
||||
field(SNAM,"exit")
|
||||
field(DESC,"Exit subroutine")
|
||||
field(SCAN,"Passive")
|
||||
field(SNAM,"exit")
|
||||
}
|
||||
|
||||
record(stringin,"$(IOC):BaseVersion") {
|
||||
field(DESC,"EPICS Base Version")
|
||||
field(DTYP,"getenv")
|
||||
field(INP,"@EPICS_VERSION_FULL")
|
||||
field(PINI,"YES")
|
||||
field(DISP,1)
|
||||
}
|
||||
|
||||
@@ -62,10 +62,11 @@ sub toDeclaration {
|
||||
my @choices = map {
|
||||
sprintf " %-31s /* %s */", @{$_}[0], escapeCcomment(@{$_}[1]);
|
||||
} $this->choices;
|
||||
my $num = scalar @choices;
|
||||
return "typedef enum {\n" .
|
||||
join(",\n", @choices) .
|
||||
",\n ${name}_NUM_CHOICES\n" .
|
||||
"} $name;\n\n";
|
||||
"\n} $name;\n" .
|
||||
"#define ${name}_NUM_CHOICES $num\n\n";
|
||||
}
|
||||
|
||||
sub toDefinition {
|
||||
|
||||
@@ -39,6 +39,35 @@ our %field_attrs = (
|
||||
prop => qr/^(?:YES|NO)$/
|
||||
);
|
||||
|
||||
# Convert old promptgroups into new-style
|
||||
my %promptgroupMap = (
|
||||
GUI_COMMON => '10 - Common',
|
||||
GUI_ALARMS => '70 - Alarm',
|
||||
GUI_BITS1 => '41 - Bits (1)',
|
||||
GUI_BITS2 => '42 - Bits (2)',
|
||||
GUI_CALC => '30 - Action',
|
||||
GUI_CLOCK => '30 - Action',
|
||||
GUI_COMPRESS => '30 - Action',
|
||||
GUI_CONVERT => '60 - Convert',
|
||||
GUI_DISPLAY => '80 - Display',
|
||||
GUI_HIST => '30 - Action',
|
||||
GUI_INPUTS => '40 - Input',
|
||||
GUI_LINKS => '40 - Link',
|
||||
GUI_MBB => '30 - Action',
|
||||
GUI_MOTOR => '30 - Action',
|
||||
GUI_OUTPUT => '50 - Output',
|
||||
GUI_PID => '30 - Action',
|
||||
GUI_PULSE => '30 - Action',
|
||||
GUI_SELECT => '40 - Input',
|
||||
GUI_SEQ1 => '51 - Output (1)',
|
||||
GUI_SEQ2 => '52 - Output (2)',
|
||||
GUI_SEQ3 => '53 - Output (3)',
|
||||
GUI_SUB => '30 - Action',
|
||||
GUI_TIMER => '30 - Action',
|
||||
GUI_WAVE => '30 - Action',
|
||||
GUI_SCAN => '20 - Scan',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ($class, $name, $type) = @_;
|
||||
dieContext("Illegal field type '$type', valid field types are:",
|
||||
@@ -76,6 +105,8 @@ sub number {
|
||||
sub add_attribute {
|
||||
my ($this, $attr, $value) = @_;
|
||||
unquote $value;
|
||||
$value = $promptgroupMap{$value}
|
||||
if $attr eq 'promptgroup' && exists $promptgroupMap{$value};
|
||||
my $match = $field_attrs{$attr};
|
||||
if (defined $match) {
|
||||
dieContext("Bad value '$value' for field attribute '$attr'")
|
||||
|
||||
@@ -215,7 +215,7 @@ sub checkRelease {
|
||||
delete $macros{RULES};
|
||||
delete $macros{TOP};
|
||||
delete $macros{TEMPLATE_TOP};
|
||||
|
||||
|
||||
while (my ($app, $path) = each %macros) {
|
||||
my %check = (TOP => $path);
|
||||
my @order = ();
|
||||
@@ -238,7 +238,35 @@ sub checkRelease {
|
||||
}
|
||||
}
|
||||
}
|
||||
print "\n" if ($status);
|
||||
|
||||
my @modules = @apps;
|
||||
my $app = shift @modules;
|
||||
my $latest = AbsPath($macros{$app});
|
||||
my %paths = ($latest => $app);
|
||||
foreach $app (@modules) {
|
||||
my $path = AbsPath($macros{$app});
|
||||
if ($path ne $latest && exists $paths{$path}) {
|
||||
my $prev = $paths{$path};
|
||||
print "\n" unless ($status);
|
||||
print "This application's RELEASE file(s) define\n";
|
||||
print "\t$app = $macros{$app}\n";
|
||||
print "after but not adjacent to\n\t$prev = $macros{$prev}\n";
|
||||
print "both of which resolve to $path\n"
|
||||
if $path ne $macros{$app} || $path ne $macros{$prev};
|
||||
$status = 2;
|
||||
}
|
||||
$paths{$path} = $app;
|
||||
$latest = $path;
|
||||
}
|
||||
if ($status == 2) {
|
||||
print "Module definitions that share paths must be grouped together.\n";
|
||||
print "Either remove a definition, or move it to a line immediately\n";
|
||||
print "above or below the other(s).\n";
|
||||
print "Any non-module definitions belong in configure/CONFIG_SITE.\n";
|
||||
$status = 1;
|
||||
}
|
||||
|
||||
print "\n" if $status;
|
||||
exit $status;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ ok !$menu->legal_choice('Choice 3'), 'Third choice not legal';
|
||||
is_deeply $menu->choice(2), undef, 'Third choice undefined';
|
||||
|
||||
like $menu->toDeclaration, qr/ ^
|
||||
\s* typedef \s+ enum \s+ {
|
||||
\s+ ch1 \s+ \/\* [^*]* \*\/,
|
||||
\s+ ch2 \s+ \/\* [^*]* \*\/,
|
||||
\s+ test_NUM_CHOICES ,?
|
||||
\s+ } \s+ test; \s* $ /x, 'C declaration';
|
||||
\s* typedef \s+ enum \s+ \{ \s* \n
|
||||
\s* ch1 \s+ \/\* [^*]* \*\/, \s* \n
|
||||
\s* ch2 \s+ \/\* [^*]* \*\/ \s* \n
|
||||
\s* \} \s* test \s* ; \s* \n
|
||||
\s* \# \s* define \s+ test_NUM_CHOICES \s+ 2 \s* \n
|
||||
\s* $ /x, 'C declaration';
|
||||
|
||||
Reference in New Issue
Block a user