Merged changes from 3.15 branch, to revno 12807

This commit is contained in:
Andrew Johnson
2017-02-01 11:57:04 -06:00
90 changed files with 1401 additions and 959 deletions

View File

@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
# in the file LICENSE that is included with this distribution.
#*************************************************************************
#
# EPICS Version information
@ -34,10 +34,10 @@ BASE_3_16 = YES
# EPICS_VERSION must be a number >0 and <256
EPICS_VERSION = 3
# EPICS_REVISION must be a number >=0 and <256
# EPICS_REVISION must be a number >=0 and <256
EPICS_REVISION = 16
# EPICS_MODIFICATION must be a number >=0 and <256
# EPICS_MODIFICATION must be a number >=0 and <256
EPICS_MODIFICATION = 0
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)

View File

@ -14,7 +14,7 @@ build$(DIVIDER)$(ARCH) build: buildInstall
install$(DIVIDER)$(ARCH) install: buildInstall
$(ARCH): buildInstall
ifeq ($(filter $(ARCH),$(BUILD_ARCHS)),$(ARCH))
ifeq ($(filter $(ARCH),$(BUILD_ARCHS)),$(strip $(ARCH)))
buildInstall$(DIVIDER)$(ARCH) buildInstall: $(TARGETS)
clean$(DIVIDER)$(ARCH) clean:
@ -35,4 +35,3 @@ envPaths: $(wildcard $(TOP)/configure/RELEASE*) \
realclean:
$(RM) cdCommands envPaths dllPath.bat relPaths.sh

View File

@ -105,13 +105,17 @@ endif
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
#---------------------------------------------------------------
# Generate a test specification if any tests are defined.
# Test specifications and test result files
#
ifneq (,$(strip $(TESTS)))
TARGETS += testspec
endif
# Enable testing if this host can run tests on the current target
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
RUNTESTS_ENABLED = YES
TAPFILES += $(TESTSCRIPTS:.t=.tap)
endif
#---------------------------------------------------------------
# Libraries
@ -324,7 +328,7 @@ $(MODNAME): %$(MODEXT): %$(EXE)
# Automated testing
runtests: $(TESTSCRIPTS)
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
ifdef RUNTESTS_ENABLED
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
endif
@ -340,7 +344,7 @@ 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)))
ifdef RUNTESTS_ENABLED
-$(PERL) $< -tap > $@
endif

View File

@ -22,7 +22,3 @@ GNU_LDLIBS_YES =
# Link with winsock2
OP_SYS_LDLIBS = -lws2_32
# Use static compiler-support libraries
OP_SYS_LDFLAGS += -static-libgcc -static-libstdc++
# There is no compiler flag for static libwinpthread

View File

@ -10,6 +10,8 @@ VALID_BUILDS = Host Ioc
CMPLR_CLASS = msvc
OPT_WHOLE_PROGRAM = YES
#-------------------------------------------------------
WINLINK = link
@ -42,11 +44,13 @@ WARN_CFLAGS_NO = -W1
# -Ox maximum optimizations
# -GL whole program optimization
# -Oy- re-enable creation of frame pointers
OPT_CFLAGS_YES = -Ox -GL -Oy-
OPT_CFLAGS_YES_YES = -Ox -GL -Oy-
OPT_CFLAGS_YES_NO = -Ox -Oy-
OPT_CFLAGS_YES = $(OPT_CFLAGS_YES_$(OPT_WHOLE_PROGRAM))
#
# -Zi generate program database for debugging information
# -RTCsu catch bugs occuring only inoptimized code
# -RTCsu enable run-time error checks
OPT_CFLAGS_NO = -Zi -RTCsu
# specify object file name and location
@ -96,17 +100,19 @@ CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
# -w44355 set "'this' used in the base initializer list" to be level 4
# -w44344 "behavior change: use of explicit template arguments results in ..."
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344
WARN_CXXFLAGS_NO = -W1
WARN_CXXFLAGS_NO = -W1
#
# -Ox maximum optimizations
# -GL whole program optimization
# -Oy- re-enable creation of frame pointers
OPT_CXXFLAGS_YES = -Ox -GL -Oy-
OPT_CXXFLAGS_YES_YES = -Ox -GL -Oy-
OPT_CXXFLAGS_YES_NO = -Ox -Oy-
OPT_CXXFLAGS_YES = $(OPT_CXXFLAGS_YES_$(OPT_WHOLE_PROGRAM))
#
# -Zi generate program database for debugging information
# -RTCsu catch bugs occurring only in optimized code
# -RTCsu enable run-time error checks
OPT_CXXFLAGS_NO = -RTCsu -Zi
# specify object file name and location
@ -136,11 +142,14 @@ RANLIB=
# -fixed:no generate relocatable code
# -version:<major>.<minor> - only 2 components allowed, 0-65535 each
# -debug generate debugging info
LINK_OPT_FLAGS_YES = -LTCG -incremental:no -opt:ref \
-release $(PROD_VERSION:%=-version:%)
LINK_OPT_FLAGS_WHOLE_YES = -LTCG
LINK_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM))
LINK_OPT_FLAGS_YES += -incremental:no -opt:ref
LINK_OPT_FLAGS_YES += -release $(PROD_VERSION:%=-version:%)
LINK_OPT_FLAGS_NO = -debug -incremental:no -fixed:no
OPT_LDFLAGS = $(LINK_OPT_FLAGS_$(HOST_OPT))
LIB_OPT_FLAGS_YES = -LTCG
LIB_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM))
LIB_OPT_LDFLAGS = $(LIB_OPT_FLAGS_$(HOST_OPT))
ARCH_DEP_CFLAGS=
@ -156,48 +165,38 @@ EXE=.exe
OBJ=.obj
RES=.res
# Problem: MS Visual C++ does not recognize *.cc as C++ source,
# so we do C++ compiles using the global flag -TP
# MS Visual C++ doesn't recognize *.cc as a C++ source file,
# so C++ compiles get the flag -TP
COMPILER_CXXFLAGS = -TP
# Operating system flags
# Operating system flags
OP_SYS_CFLAGS =
OP_SYS_CXXFLAGS = $(COMPILER_CXXFLAGS)
#
# Files and flags needed to link DLLs (used in RULES_BUILD)
#
WIN32_DLLFLAGS = /subsystem:windows /dll $(OPT_LDFLAGS) \
# Files and flags needed to link DLLs (used in RULES_BUILD)
WIN32_DLLFLAGS = -subsystem:windows -dll $(OPT_LDFLAGS) \
$(USR_LDFLAGS) $(CMD_LDFLAGS) $(TARGET_LDFLAGS) $(LIB_LDFLAGS)
#
# specify dll .def file only if it exists
#
# Specify dll .def file only if it exists
DLL_DEF_FLAG = $(addprefix -def:,$(wildcard ../$(addsuffix .def,$*)))
#
# A WIN32 dll has three parts:
# A WIN32 dll has three parts:
# x.dll: the real dll (SHRLIBNAME)
# x.lib: what you link to progs that use the dll (DLLSTUB_LIBNAME)
# x.exp: what you need to build the dll (in no variable)
#
LINK.shrlib = $(WINLINK) -nologo $(WIN32_DLLFLAGS) -out:$@ \
-implib:$(@:%$(SHRLIB_SUFFIX)=%$(LIB_SUFFIX)) \
$(DLL_DEF_FLAG) $(LIBRARY_LD_OBJS) $(LIBRARY_LD_RESS) $(SHRLIB_LDLIBS)
# adjust names of libraries to build
#
# Adjust names of libraries to build
SHRLIB_SUFFIX_BASE = .dll
SHRLIB_SUFFIX = $(SHRLIB_SUFFIX_BASE)
SHRLIBNAME_YES = $(BUILD_LIBRARY:%=%$(SHRLIB_SUFFIX))
LOADABLE_SHRLIBNAME = $(LOADABLE_BUILD_LIBRARY:%=%$(SHRLIB_SUFFIX))
TESTSHRLIBNAME_YES = $(TESTBUILD_LIBRARY:%=%$(SHRLIB_SUFFIX_BASE))
#
# When SHARED_LIBRARIES is YES we are building a DLL link library
# and when SHARED_LIBRARIES is NO we are building an object library
#
# When SHARED_LIBRARIES is YES we are building a DLL shared library.
# When SHARED_LIBRARIES is NO we are building an object library
DLLSTUB_SUFFIX = .lib
DLLSTUB_LIBNAME_YES = $(BUILD_LIBRARY:%=%.lib)
DLLSTUB_LIBNAME = $(DLLSTUB_LIBNAME_$(SHARED_LIBRARIES))
@ -211,7 +210,7 @@ LIBNAME = $(LIBNAME_$(SHARED_LIBRARIES))
TESTLIBNAME_NO = $(TESTBUILD_LIBRARY:%=%.lib)
TESTLIBNAME = $(TESTLIBNAME_$(SHARED_LIBRARIES))
# dll install location
# dll install location
INSTALL_SHRLIB = $(INSTALL_BIN)
@ -271,7 +270,7 @@ LINK.cpp = $(WINLINK) -nologo $(STATIC_LDFLAGS) $(LDFLAGS) $(PROD_LDFLAGS) \
#--------------------------------------------------
# UseManifestTool.pl checks MS Visual c++ compiler version number to
# decide whether or not to use the Manifest Tool command to embed the
# linker created .manifest file into a library or product target.
# linker created .manifest file into a library or product target.
# useManifestTool.pl returns 0(don't use) or 1(use).
#
MT.exe = mt.exe -nologo -manifest $@.manifest
@ -281,4 +280,3 @@ MT_EXE_COMMAND_NO = $(MT.exe) "-outputresource:$@;\#1"
MT_EXE_COMMAND1 = $(MT_EXE_COMMAND_$(STATIC_BUILD))
MT_DLL_COMMAND = $(MT_DLL_COMMAND$(shell $(PERL) $(TOOLS)/useManifestTool.pl))
MT_EXE_COMMAND = $(MT_EXE_COMMAND$(shell $(PERL) $(TOOLS)/useManifestTool.pl))

View File

@ -8,8 +8,7 @@
include $(CONFIG)/os/CONFIG.win32-x86.win32-x86
-include $(CONFIG)/os/CONFIG_SITE.win32-x86.win32-x86
OPT_LDFLAGS += /MACHINE:X64
# /MACHINE:X64
# /MACHINE:IA64 (Itanium)
# /MACHINE:X86
OPT_LDFLAGS += -MACHINE:X64
# -MACHINE:X64
# -MACHINE:IA64 (Itanium)
# -MACHINE:X86

View File

@ -0,0 +1,8 @@
# CONFIG_SITE.Common.win32-x86-static
#
# Site-specific settings for the win32-x86-static target
# Whole-program optimization doesn't work with Visual Studio 2010 when
# building static binaries. Newer versions of Visual Studio than 2010
# may work though, comment out or set this to YES to try.
OPT_WHOLE_PROGRAM = NO

View File

@ -1,9 +1,8 @@
# CONFIG_SITE.Common.windows-x64-static
#
# Site Specific definitions for windows-x64-static target
# Only the local epics system manager should modify this file
# 64-bit Visual Studio 2010 builds fail when built optimized.
# If you are using a newer version you can try removing this:
HOST_OPT = NO
# Site-specific settings for the windows-x64-static target
# Whole-program optimization doesn't work with Visual Studio 2010 when
# building static binaries. Newer versions of Visual Studio than 2010
# may work though, comment out or set this to YES to try.
OPT_WHOLE_PROGRAM = NO

View File

@ -4,10 +4,10 @@
#-------------------------------------------------------
# Early versions of the MinGW cross-build tools can only build
# static (non-DLL) libraries. For example RHEL's cross-gcc 4.4.6
# needs these uncommented, cross-gcc 4.6.3 for Ubuntu does not:
SHARED_LIBRARIES = NO
STATIC_BUILD = YES
# static (non-DLL) libraries. RHEL's cross-build of gcc 4.4.6
# needs these uncommented, cross-gcc 4.6.3 from Ubuntu does not:
#SHARED_LIBRARIES = NO
#STATIC_BUILD = YES
# The cross-build tools are in $(GNU_DIR)/bin
# Default is /usr
@ -20,3 +20,6 @@ CMPLR_PREFIX = i686-w64-mingw32-
#CMPLR_PREFIX = i686-pc-mingw32-
# Debian?
#CMPLR_PREFIX = i586-mingw32msvc-
# Use static compiler-support libraries
OP_SYS_LDFLAGS += -static-libgcc -static-libstdc++

View File

@ -18,3 +18,6 @@
#CMPLR_PREFIX = i686-w64-mingw32-
# RHEL:
CMPLR_PREFIX = x86_64-w64-mingw32-
# Use static compiler-support libraries
OP_SYS_LDFLAGS += -static-libgcc -static-libstdc++

View File

@ -4,17 +4,17 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Known Problems in R3.16.0.1</title>
<title>Known Problems in R3.16.1</title>
</head>
<body>
<h1 style="text-align: center">EPICS Base R3.16.0.1: Known Problems</h1>
<h1 style="text-align: center">EPICS Base R3.16.1: Known Problems</h1>
<p>Any patch files linked below should be applied at the root of the
base-3.16.0.1 tree. Download them, then use the GNU Patch program as
base-3.16.1 tree. Download them, then use the GNU Patch program as
follows:</p>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.16.0.1</b>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.16.1</b>
% <b>patch -p0 &lt; <i>/path/to/</i>file.patch</b></pre></blockquote>
<p>The following problems were known by the developers at the time of this

View File

@ -1,24 +1,24 @@
Installation Instructions
EPICS Base Release 3.16.0
EPICS Base Release 3.16.1
--------------------------------------------------------------------------
Table of Contents
*<2A>What is EPICS base?
*<2A>What is new in this release?
*<2A>Copyright
*<2A>Supported platforms
*<2A>Supported compilers
*<2A>Software requirements
*<2A>Host system storage requirements
*<2A>Documentation
*<2A>Directory Structure
*<2A>Build related components
*<2A>Building EPICS base (Unix and Win32)
*<2A>Example application and extension
*<2A>Multiple host platforms
*<2A>What is EPICS base?
*<2A>What is new in this release?
*<2A>Copyright
*<2A>Supported platforms
*<2A>Supported compilers
*<2A>Software requirements
*<2A>Host system storage requirements
*<2A>Documentation
*<2A>Directory Structure
*<2A>Build related components
*<2A>Building EPICS base (Unix and Win32)
*<2A>Example application and extension
*<2A>Multiple host platforms
--------------------------------------------------------------------------

View File

@ -9,7 +9,7 @@
<BODY>
<CENTER>
<H1>Installation Instructions</H1>
<H2>EPICS Base Release 3.16.0</H2><BR>
<H2>EPICS Base Release 3.16.1</H2><BR>
</CENTER>
<HR>
<H3> Table of Contents</H3>
@ -190,12 +190,12 @@
CONFIG.CrossCommon Cross build definitions
CONFIG.gnuCommon Gnu compiler build definitions for all archs
CONFIG_ADDONS Definitions for &lt;osclass&gt; and DEFAULT options
CONFIG_APP_INCLUDE
CONFIG_APP_INCLUDE
CONFIG_BASE EPICS base tool and location definitions
CONFIG_BASE_VERSION Definitions for EPICS base version number
CONFIG_COMMON Definitions common to all builds
CONFIG_ENV Definitions of EPICS environment variables
CONFIG_FILE_TYPE
CONFIG_FILE_TYPE
CONFIG_SITE Site specific make definitions
CONFIG_SITE_ENV Site defaults for EPICS environment variables
MAKEFILE Installs CONFIG* RULES* creates
@ -206,9 +206,9 @@
RULES_ARCHS Definitions and rules for building architectures
RULES_BUILD Build and install rules and definitions
RULES_DIRS Definitions and rules for building subdirectories
RULES_EXPAND
RULES_FILE_TYPE
RULES_TARGET
RULES_EXPAND
RULES_FILE_TYPE
RULES_TARGET
RULES_TOP Rules specific to a &lt;top&gt; dir (uninstall and tar)
Sample.Makefile Sample makefile with comments
</PRE>
@ -340,7 +340,7 @@ Files in the base/startup directory have been provided to
<H3><A NAME="0_0_13"> Example application and extension</A></H3>
<BLOCKQUOTE>A perl tool, makeBaseApp.pl is included in the distribution
file. This script will create a sample application that can be built
and then executed to try out this release of base.
and then executed to try out this release of base.
<P>
Instructions for building and executing the 3.15 example application
@ -350,8 +350,8 @@ Files in the base/startup directory have been provided to
create and build an example application in a user created &lt;top&gt;
directory. It also explains how to run the example application on a
vxWorks ioc or as a process on the host system.
By running the example application as a host-based IOC, you will be
able to quickly implement a complete EPICS system and be able to run channel
By running the example application as a host-based IOC, you will be
able to quickly implement a complete EPICS system and be able to run channel
access clients on the host system.
<P>

View File

@ -3,14 +3,15 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>EPICS Base R3.16.0.2 Release Notes</title>
<title>EPICS Base R3.16.1 Release Notes</title>
</head>
<body lang="en">
<h1 align="center">EPICS Base Release 3.16.0.2</h1>
<h1 align="center">EPICS Base Release 3.16.1</h1>
<p style="color:red">This version of EPICS Base has not been released yet.</p>
<h2 align="center">Changes made on the 3.16 branch since 3.16.0.1</h2>
<!-- Insert new items immediately below this template ...
@ -138,13 +139,117 @@ callback.h header and removed the need for dbScan.c to reach into the internals
of its CALLBACK objects.</p>
<h2 align="center">Changes from the 3.15 branch since 3.15.4</h2>
<h2 align="center">Changes from the 3.15 branch since 3.15.5</h2>
<!-- Insert inherited items immediately below here ... -->
<h2 align="center">Changes from the 3.14 branch since 3.15.4</h2>
<h2 align="center">Changes from the 3.14 branch since 3.15.5</h2>
<!-- Insert inherited items immediately below here ... -->
<h3>Server bind issue on Windows</h3>
<p>When a National Instruments network variables CA server is already running on
a Windows system and an IOC or PCAS server is started, the IOC's attempt to
bind a TCP socket to the CA server port number fails, but Windows returns a
different error status value than the IOC is expecting in that circumstance
(because the National Instruments code requests exclusive use of that port,
unlike the EPICS code) so the IOC fails to start properly. The relevent EPICS
bind() checks have now been updated so the IOC will request that a dynamic port
number be allocated for this TCP socket instead when this happens.</p>
<h3>Checking Periodic Scan Rates</h3>
<p>Code has been added to the IOC startup to better protect it against bad
periodic scan rates, including against locales where <q><tt>.</tt></q> is not
accepted as a decimal separator character. If the scan period in a menuScan
choice string cannot be parsed, the associated periodic scan thread will no
longer be started by the IOC and a warning message will be displayed at iocInit
time. The <tt>scanppl</tt> command will also flag the faulty menuScan value.</p>
<h2 align="center">Changes made between 3.15.4 and 3.15.5</h2>
<h3>dbStatic Library Speedup and Cleanup</h3>
<p>Loading of database files has been optimized to avoid overproportionally
long loading times for large databases. As a part of this, the alphabetical
ordering of records instances (within a record type) has been dropped. In the
unexpected case that applications were relying on the alphabetic order, setting
<tt>dbRecordsAbcSorted = 1</tt> before loading the databases will retain the
old behavior.</p>
<p>The routine <tt>dbRenameRecord()</tt> has been removed, as it was intended
to be used by database configuration tools linked against a host side version
of the dbStatic library that is not being built anymore.</p>
<h3>Launchpad Bug-fixes</h3>
<p>In addition to the more detailed change descriptions below, the following
Launchpad bugs have also been fixed in this release:</p>
<ul>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1440186">
#1440186</a> Crash due to a too small buffer being provided in
dbContextReadNotifyCache</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1479316">
#1479316</a> Some data races found using Helgrind</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1495833">
#1495833</a> biRecord prompt groups are nonsensical</li>
<li><a href="https://bugs.launchpad.net/epics-base/+bug/1606848">
#1606848</a> WSAIoctl SIO_GET_INTERFACE_LIST failed in Windows</li>
</ul>
<h3>Whole-Program Optimization for MS Visual Studio Targets</h3>
<p>When using the Microsoft compilers a new build system variable is provided
that controls whether whole program optimization is used or not. For static
builds using Visual Studio 2010 this optimization must be disabled. This is
controlled in the files configure/os/CONFIG_SITE.Common.windows-x64-static and
configure/os/CONFIG_SITE.Common.win32-x86-static by setting the variable
<tt>OPT_WHOLE_PROGRAM&nbsp;=&nbsp;NO</tt> to override the default value
<tt>YES</tt> that would otherwise be used.</p>
<p>Note that enabling this optimization slows down the build process. It is not
possible to selectively disable this optimization, when building a particular
module say; Microsoft's linker will restart itself automatically with the
<tt>-LTCG</tt> flag set and display a warning if it is asked to link any object
files that were compiled with the <tt>-GL</tt> flag.</p>
<h3>Add dynamic (variable length) array support to PCAS</h3>
<p>Dynamic array sizing support was added to the IOC server (RSRV) in the
Base-3.14.12 release, but has not until now been supported in the <q>Portable
Channel Access Server</q> (PCAS). Channel Access server applications using the
PCAS may not need to be modified at all; if they already push monitors with
different gdd array lengths, those variable sizes will be forwarded to any CA
clients who have requested variable length updates. The example CAS server
application has been modified to demonstrate this feature.</p>
<p>In implementing the above, the gdd method <tt>gdd::put(const gdd *)</tt> now
copies the full-sized array from the source gdd if the destination gdd is of
type array, has no allocated memory and a boundary size of 0.</p>
<h3>Additional epicsTime conversion</h3>
<p>The EPICS timestamp library (epicsTime) inside libCom's OSI layer has
been extended by routines that convert from <tt>struct tm</tt> to the EPICS
internal <tt>epicsTime</tt> type, assuming UTC - i.e. without going through
the timezone mechanism. This solves issues with converting from the structured
type to the EPICS timestamp at driver level from multiple threads at a high
repetition rate, where the timezone mechanism was blocking on file access.</p>
<h3>MinGW Cross-builds from Linux</h3>
<p>The build configuration files that allow cross-building of the 32-bit
win32-x86-mingw cross-target have been adjusted to default to building shared
libraries (DLLs) as this is now supported by recent MinGW compilers. The 64-bit
windows-x64-mingw cross-target was already being built that way by default. The
configuration options to tell the minGW cross-compiler to link programs with
static versions of the compiler support libraries have now been moved into the
CONFIG_SITE.linux-x86.<i>target</i> files.</p>
<h3>General Time updates</h3>
<p>The <tt>iocInit</tt> code now performs a sanity check of the current time

View File

@ -1146,16 +1146,10 @@ the output.</p>
<td>Wide mode "name timestamp value stat sevr" (read PVs as
DBR_TIME_xxx)</td>
</tr>
<tr>
<td>-n</td>
<td>Print DBF_ENUM values as number (default are enum strings)</td>
</tr>
<tr>
<td>-d &lt;type&gt;</td>
<td>Request specific dbr type; use string (DBR_ prefix may be omitted)
<p>or number of one of the following types:</p>
<td>Request specific dbr type; use string (DBR_ prefix may be omitted)<br>
or number of one of the following types:<br>
<table border="1">
<tbody>
<tr>
@ -1272,6 +1266,14 @@ the output.</p>
</table>
</td>
</tr>
<tr>
<td></td>
<td><strong>Enum format:</strong></td>
</tr>
<tr>
<td>-n</td>
<td>Print DBF_ENUM value as number (default is enum string)</td>
</tr>
<tr>
<td></td>
<td><strong>Arrays:</strong></td>
@ -1303,15 +1305,15 @@ the output.</p>
</tr>
<tr>
<td>-e &lt;nr&gt;</td>
<td>Use %e format, with &lt;nr&gt; digits after the decimal point</td>
<td>Use %e format, with a precision of &lt;nr&gt; digits</td>
</tr>
<tr>
<td>-f &lt;nr&gt;</td>
<td>Use %f format, with &lt;nr&gt; digits after the decimal point</td>
<td>Use %f format, with a precision of &lt;nr&gt; digits</td>
</tr>
<tr>
<td>-g &lt;nr&gt;</td>
<td>Use %g format, with &lt;nr&gt; digits after the decimal point</td>
<td>Use %g format, with a precision of &lt;nr&gt; digits</td>
</tr>
<tr>
<td>-s</td>
@ -1349,6 +1351,14 @@ the output.</p>
<td>-0b</td>
<td>Print as binary number</td>
</tr>
<tr>
<td></td>
<td><strong>Alternate output field separator:</strong></td>
</tr>
<tr>
<td>-F &lt;ofs&gt;</td>
<td>Use &lt;ofs&gt; as an alternate output field separator</td>
</tr>
</tbody>
</table>
@ -1381,9 +1391,10 @@ the output.</p>
<td>Wait time, specifies longer CA timeout, default is 1.0 second</td>
</tr>
<tr>
<td>-m &lt;mask&gt;</td>
<td>Specify CA event mask to use, with &lt;mask&gt; being any combination
of 'v' (value), 'a' (alarm), 'l' (log), 'p' (property). Default: va</td>
<td>-m &lt;msk&gt;</td>
<td>Specify CA event mask to use. &lt;msk&gt; is any combination of<br>
'v' (value), 'a' (alarm), 'l' (log/archive), 'p' (property).<br>
Default event mask is 'va'</td>
</tr>
<tr>
<td>-p &lt;prio&gt;</td>
@ -1405,8 +1416,8 @@ the output.</p>
'n' = no timestamps<br>
'r' = relative timestamps (time elapsed since start of program)<br>
'i' = incremental timestamps (time elapsed since last update)<br>
'I' = incremental timestamps (time elapsed since last update, by
channel)</td>
'I' = incremental timestamps (time since last update, by channel)<br>
'r', 'i' or 'I' require 's' or 'c' to select the time source</td>
</tr>
<tr>
<td></td>
@ -1414,7 +1425,7 @@ the output.</p>
</tr>
<tr>
<td>-n</td>
<td>Print DBF_ENUM values as number (default are enum strings)</td>
<td>Print DBF_ENUM values as number (default is enum string)</td>
</tr>
<tr>
<td></td>
@ -1422,16 +1433,15 @@ the output.</p>
</tr>
<tr>
<td></td>
<td>Value format: Print number of requested values, then list of
values</td>
<td>Array values: Print number of elements, then list of values</td>
</tr>
<tr>
<td>Default:</td>
<td>Print all values</td>
<td>Default: Request and print all elements (dynamic arrays supported)</td>
</tr>
<tr>
<td>-# &lt;count&gt;</td>
<td>Print first &lt;count&gt; elements of an array</td>
<td>-# &lt;num&gt;</td>
<td>Request and print up to &lt;num&gt; elements</td>
</tr>
<tr>
<td>-S</td>
@ -1439,23 +1449,23 @@ the output.</p>
</tr>
<tr>
<td></td>
<td><strong>Floating point type format:</strong></td>
<td><strong>Floating point format:</strong></td>
</tr>
<tr>
<td>Default:</td>
<td>Use %g format</td>
</tr>
<tr>
<td>-e &lt;nr&gt;</td>
<td>Use %e format, with &lt;nr&gt; digits after the decimal point</td>
<td>-e &lt;num&gt;</td>
<td>Use %e format, with a precision of &lt;num&gt; digits</td>
</tr>
<tr>
<td>-f &lt;nr&gt;</td>
<td>Use %f format, with &lt;nr&gt; digits after the decimal point</td>
<td>-f &lt;num&gt;</td>
<td>Use %f format, with a precision of &lt;num&gt; digits</td>
</tr>
<tr>
<td>-g &lt;nr&gt;</td>
<td>Use %g format, with &lt;nr&gt; digits after the decimal point</td>
<td>-g &lt;num&gt;</td>
<td>Use %g format, with a precision of &lt;num&gt; digits</td>
</tr>
<tr>
<td>-s</td>
@ -1497,21 +1507,27 @@ the output.</p>
</table>
<h3><a name="caput">caput</a></h3>
<pre>caput [options] &lt;PV name&gt; &lt;value&gt;
<pre>caput [options] &lt;PV name&gt; &lt;value&gt; ...
caput -a [options] &lt;PV name&gt; &lt;no of elements&gt; &lt;value&gt; ...</pre>
<h4>Description</h4>
<p>Put value to a PV.</p>
<p>The specified value is written to the PV (as a string). The PV value is read
before and after the write operation and printed as "Old" and "new" values on
stdout.</p>
<p>The specified value is written to the PV (as a string). The PV's value is
read before and after the write operation and printed as "Old" and "New" values
on stdout.</p>
<p>The array variant writes an array to the specified PV. The first numeric
argument specifying the number of array elements is kept for compatibility with
the array data format of caget - the actual number of values specified on the
command line is used.</p>
<p>There are two variants to the arguments for this command. For the scalar
variant without the <code>-a</code> flag, all the value arguments provided after
the PV name are concatenated with a single space character between them, and the
resulting string (up to 40 characters long unless the <code>-S</code> flag is
given) is written to the specified PV.</p>
<p>The array variant with the <code>-a</code> flag writes an array of string
values to the specified PV. The numeric argument giving the number of array
elements is actually ignored, the array length to be written is actually
controlled by the number of values provided on the command line.</p>
<table border="1">
<caption></caption>
@ -1550,12 +1566,16 @@ command line is used.</p>
<td>-t</td>
<td>Terse mode - print only successfully written value, without name</td>
</tr>
<tr>
<td>-l</td>
<td>Long mode "name timestamp value stat sevr" (read PVs as DBR_TIME_xxx)</td>
</tr>
<tr>
<td></td>
<td><strong>Enum Format:</strong></td>
</tr>
<tr>
<td></td>
<td>Default:</td>
<td>Auto - try value as ENUM string, then as index number</td>
</tr>
<tr>
@ -1571,17 +1591,24 @@ command line is used.</p>
<td><strong>Arrays:</strong></td>
</tr>
<tr>
<td>-a</td>
<td>Put array data</td>
<td>Default:</td>
<td>Put scalar</td>
</tr>
<tr>
<td></td>
<td>Value format: Print number of requested values, then list of
values</td>
<td>Value format: all value arguments concatenated with spaces</td>
</tr>
<tr>
<td>-S</td>
<td>Put string as an array of char (long string)</td>
<td>Put string as an array of chars (long string)</td>
</tr>
<tr>
<td>-a</td>
<td>Put array</td>
</tr>
<tr>
<td></td>
<td>Value format: number of values, then list of values</td>
</tr>
</tbody>
</table>

View File

@ -149,9 +149,9 @@ cac::cac (
iiuExistenceCount ( 0u ),
cacShutdownInProgress ( false )
{
if ( ! osiSockAttach () ) {
throwWithLocation ( caErrorCode (ECA_INTERNAL) );
}
if ( ! osiSockAttach () ) {
throwWithLocation ( udpiiu :: noSocket () );
}
try {
long status;

View File

@ -61,11 +61,6 @@ static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request
*/
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
class caErrorCode {
public:
caErrorCode ( int ) {};
};
/*
* CA internal functions
*/

View File

@ -504,6 +504,7 @@ void ca_repeater ()
if ( sockerrno == SOCK_EADDRINUSE ) {
osiSockRelease ();
debugPrintf ( ( "CA Repeater: exiting because a repeater is already running\n" ) );
delete [] pBuf;
return;
}
char sockErrBuf[64];

View File

@ -44,12 +44,7 @@
using namespace std;
#if 0
const unsigned mSecPerSec = 1000u;
const unsigned uSecPerSec = 1000u * mSecPerSec;
#endif
tcpSendThread::tcpSendThread (
tcpSendThread::tcpSendThread (
class tcpiiu & iiuIn, const char * pName,
unsigned stackSize, unsigned priority ) :
thread ( *this, pName, stackSize, priority ), iiu ( iiuIn )
@ -807,28 +802,6 @@ tcpiiu::tcpiiu (
}
}
# if 0
//
// windows has a really strange implementation of thess options
// and we can avoid the need for this by using pthread_kill on unix
//
{
struct timeval timeout;
double pollInterval = connectionTimeout / 8.0;
timeout.tv_sec = static_cast < long > ( pollInterval );
timeout.tv_usec = static_cast < long >
( ( pollInterval - timeout.tv_sec ) * uSecPerSec );
// intentionally ignore status as we dont expect that all systems
// will accept this request
setsockopt ( this->sock, SOL_SOCKET, SO_SNDTIMEO,
( char * ) & timeout, sizeof ( timeout ) );
// intentionally ignore status as we dont expect that all systems
// will accept this request
setsockopt ( this->sock, SOL_SOCKET, SO_RCVTIMEO,
( char * ) & timeout, sizeof ( timeout ) );
}
# endif
if ( isNameService() ) {
pSearchDest->setCircuit ( this );
}

View File

@ -56,7 +56,7 @@ static epicsEventId epId;
void usage (void)
{
fprintf (stderr, "\nUsage: caput [options] <PV name> <PV value>\n"
fprintf (stderr, "\nUsage: caput [options] <PV name> <PV value> ...\n"
" caput -a [options] <PV name> <no of values> <PV value> ...\n\n"
" -h: Help: Print this message\n"
"Channel Access options:\n"
@ -71,9 +71,11 @@ void usage (void)
" -n: Force interpretation of values as numbers\n"
" -s: Force interpretation of values as strings\n"
"Arrays:\n"
" Default: Put scalar\n"
" Value format: all value arguments concatenated with spaces\n"
" -S: Put string as an array of chars (long string)\n"
" -a: Put array\n"
" Value format: number of requested values, then list of values\n"
" -S: Put string as an array of char (long string)\n"
" Value format: number of values, then list of values\n"
"Alternate output field separator:\n"
" -F <ofs>: Use <ofs> as an alternate output field separator\n"
"\nExample: caput my_channel 1.2\n"

View File

@ -930,10 +930,12 @@ bool udpiiu::pushDatagramMsg ( epicsGuard < epicsMutex > & guard,
caHdr * pbufmsg = ( caHdr * ) &this->xmitBuf[this->nBytesInXmitBuf];
*pbufmsg = msg;
memcpy ( pbufmsg + 1, pExt, extsize );
if ( extsize != alignedExtSize ) {
char *pDest = (char *) ( pbufmsg + 1 );
memset ( pDest + extsize, '\0', alignedExtSize - extsize );
if ( extsize ) {
memcpy ( pbufmsg + 1, pExt, extsize );
if ( extsize != alignedExtSize ) {
char *pDest = (char *) ( pbufmsg + 1 );
memset ( pDest + extsize, '\0', alignedExtSize - extsize );
}
}
AlignedWireRef < epicsUInt16 > ( pbufmsg->m_postsize ) = alignedExtSize;
this->nBytesInXmitBuf += msgsize;

View File

@ -1355,8 +1355,9 @@ gddStatus gdd::put ( const gdd * dd )
}
aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow;
if ( srcAvailSize > this->getBounds()->size() ) {
srcCopySize = this->getBounds()->size();
aitUint32 destSize = this->getBounds()->size();
if ( destSize > 0 && srcAvailSize > destSize ) {
srcCopySize = destSize;
}
else {
srcCopySize = srcAvailSize;

View File

@ -418,8 +418,10 @@ gddStatus gddApplicationTypeTable::freeDD(gdd* dd)
}
// fprintf(stderr,"Adding DD to free_list %d\n",app);
attr_table[group][app].sem.lock ();
dd->setNext(attr_table[group][app].free_list);
attr_table[group][app].free_list=dd;
attr_table[group][app].sem.unlock ();
}
else if (attr_table[group][app].type==gddApplicationTypeNormal)
{

View File

@ -308,7 +308,7 @@ void gdd::test()
pdd->convertOffsetsToAddress();
pdd->dump();
pdd->unreference();
delete buf;
delete [] buf;
}
#endif
@ -510,7 +510,7 @@ void gddContainer::test(void)
fprintf(stderr,"=====RE-DUMP OF ORIGINAL CONTAINER:\n");
dump();
cdd1->unreference();
delete buf;
delete [] buf;
// test copy(), Dup(), copyInfo()
fprintf(stderr,"=======CREATING TEST CONTAINER FOR *COPY* TEST:\n");

View File

@ -170,7 +170,7 @@ static int parseDirectoryFP (FILE *pf, const char *pFileName)
status = aToIPAddr (hostNameStr, 0u, &ipa);
if (status) {
fprintf (pf, "Unknown host name=\"%s\" (or bad dotted ip addr) in \"%s\" with PV=\"%s\"?\n",
fprintf (stderr, "Unknown host name=\"%s\" (or bad dotted ip addr) in \"%s\" with PV=\"%s\"?\n",
hostNameStr, pFileName, pvNameStr);
return -1;
}

View File

@ -30,7 +30,7 @@
# include "shareLib.h"
#endif
static const unsigned char CA_MINOR_PROTOCOL_REVISION = 12;
static const unsigned char CA_MINOR_PROTOCOL_REVISION = 13;
typedef ca_uint32_t caResId;

View File

@ -40,8 +40,13 @@ class casIntfOS;
class casMonitor;
class casChannelI;
caStatus convertContainerMemberToAtomic ( class gdd & dd,
aitUint32 appType, aitUint32 elemCount );
caStatus convertContainerMemberToAtomic (class gdd & dd,
aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount);
// Keep the old signature for backward compatibility
inline caStatus convertContainerMemberToAtomic (class gdd & dd,
aitUint32 appType, aitUint32 elemCount)
{ return convertContainerMemberToAtomic(dd, appType, elemCount, elemCount); }
class caServerI :
public caServerIO,

View File

@ -21,6 +21,7 @@ casChannelI::casChannelI ( casCoreClient & clientIn,
casChannel & chanIn, casPVI & pvIn, ca_uint32_t cidIn ) :
privateForPV ( clientIn, *this ),
pv ( pvIn ),
maxElem( pvIn.nativeCount() ),
chan ( chanIn ),
cid ( cidIn ),
serverDeletePending ( false ),
@ -29,7 +30,7 @@ casChannelI::casChannelI ( casCoreClient & clientIn,
}
casChannelI::~casChannelI ()
{
{
this->privateForPV.client().removeFromEventQueue (
*this, this->accessRightsEvPending );
@ -48,7 +49,7 @@ void casChannelI::uninstallFromPV ( casEventSys & eventSys )
this->privateForPV.removeSelfFromPV ( this->pv, dest );
while ( casMonitor * pMon = dest.get () ) {
eventSys.prepareMonitorForDestroy ( *pMon );
}
}
}
void casChannelI::show ( unsigned level ) const
@ -68,13 +69,13 @@ caStatus casChannelI::cbFunc (
{
caStatus stat = S_cas_success;
{
stat = this->privateForPV.client().accessRightsResponse (
stat = this->privateForPV.client().accessRightsResponse (
clientGuard, this );
}
if ( stat == S_cas_success ) {
this->accessRightsEvPending = false;
}
return stat;
if ( stat == S_cas_success ) {
this->accessRightsEvPending = false;
}
return stat;
}
caStatus casChannelI::read ( const casCtx & ctx, gdd & prototype )

View File

@ -1,4 +1,3 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
@ -31,55 +30,62 @@ class casChannelI : public tsDLNode < casChannelI >,
public:
casChannelI ( casCoreClient & clientIn, casChannel & chanIn,
casPVI & pvIn, ca_uint32_t cidIn );
~casChannelI ();
~casChannelI ();
void casChannelDestroyFromInterfaceNotify ();
const caResId getCID ();
const caResId getSID ();
const caResId getCID ();
const caResId getSID ();
void uninstallFromPV ( casEventSys & eventSys );
void installIntoPV ();
void installIO ( casAsyncIOI & );
void uninstallIO ( casAsyncIOI & );
void installMonitor ( casMonitor & mon );
casMonitor * removeMonitor ( ca_uint32_t clientIdIn );
casPVI & getPVI () const;
void clearOutstandingReads ();
void postAccessRightsEvent ();
casPVI & getPVI () const;
void clearOutstandingReads ();
void postAccessRightsEvent ();
const gddEnumStringTable & enumStringTable () const;
void setOwner ( const char * const pUserName,
const char * const pHostName );
bool readAccess () const;
ca_uint32_t getMaxElem () const;
void setOwner ( const char * const pUserName,
const char * const pHostName );
bool readAccess () const;
bool writeAccess () const;
bool confirmationRequested () const;
bool confirmationRequested () const;
caStatus read ( const casCtx & ctx, gdd & prototype );
caStatus write ( const casCtx & ctx, const gdd & value );
caStatus writeNotify ( const casCtx & ctx, const gdd & value );
void show ( unsigned level ) const;
void show ( unsigned level ) const;
private:
chanIntfForPV privateForPV;
tsDLList < casAsyncIOI > ioList;
casPVI & pv;
tsDLList < casAsyncIOI > ioList;
casPVI & pv;
ca_uint32_t maxElem;
casChannel & chan;
caResId cid; // client id
caResId cid; // client id
bool serverDeletePending;
bool accessRightsEvPending;
//epicsShareFunc virtual void destroy ();
caStatus cbFunc (
bool accessRightsEvPending;
//epicsShareFunc virtual void destroy ();
caStatus cbFunc (
casCoreClient &,
epicsGuard < casClientMutex > &,
epicsGuard < evSysMutex > & );
void postDestroyEvent ();
casChannelI ( const casChannelI & );
casChannelI & operator = ( const casChannelI & );
casChannelI ( const casChannelI & );
casChannelI & operator = ( const casChannelI & );
};
inline casPVI & casChannelI::getPVI () const
{
return this->pv;
return this->pv;
}
inline ca_uint32_t casChannelI::getMaxElem () const
{
return this->maxElem;
}
inline const caResId casChannelI::getCID ()
{
return this->cid;
return this->cid;
}
inline const caResId casChannelI::getSID ()
@ -89,7 +95,7 @@ inline const caResId casChannelI::getSID ()
inline void casChannelI::postAccessRightsEvent ()
{
this->privateForPV.client().addToEventQueue ( *this, this->accessRightsEvPending );
this->privateForPV.client().addToEventQueue ( *this, this->accessRightsEvPending );
}
inline const gddEnumStringTable & casChannelI::enumStringTable () const
@ -108,7 +114,7 @@ inline void casChannelI::clearOutstandingReads ()
}
inline void casChannelI::setOwner ( const char * const pUserName,
const char * const pHostName )
const char * const pHostName )
{
this->chan.setOwner ( pUserName, pHostName );
}

View File

@ -18,6 +18,8 @@
#include "caHdrLargeArray.h"
class casStrmClient;
class casCtx {
public:
casCtx();
@ -41,6 +43,7 @@ private:
casChannelI * pChannel;
casPVI * pPV;
unsigned nAsyncIO; // checks for improper use of async io
friend class casStrmClient;
};
inline const caHdrLargeArray * casCtx::getMsg() const

View File

@ -5,7 +5,7 @@
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
@ -30,9 +30,9 @@ casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
& casDGClient::uknownMessageAction,
& casDGClient::uknownMessageAction,
& casDGClient::uknownMessageAction,
& casDGClient::searchAction,
& casDGClient::uknownMessageAction,
& casDGClient::uknownMessageAction,
& casDGClient::searchAction,
& casDGClient::uknownMessageAction,
& casDGClient::uknownMessageAction,
& casDGClient::uknownMessageAction,
@ -64,9 +64,9 @@ casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
//
casDGClient::casDGClient ( caServerI & serverIn, clientBufMemoryManager & mgrIn ) :
casCoreClient ( serverIn ),
in ( *this, mgrIn, MAX_UDP_RECV + sizeof ( cadg ) ),
in ( *this, mgrIn, MAX_UDP_RECV + sizeof ( cadg ) ),
out ( *this, mgrIn ),
seqNoOfReq ( 0 ),
seqNoOfReq ( 0 ),
minor_version_number ( 0 )
{
}
@ -92,15 +92,15 @@ void casDGClient::destroy()
//
void casDGClient::show (unsigned level) const
{
printf ( "casDGClient at %p\n",
printf ( "casDGClient at %p\n",
static_cast <const void *> ( this ) );
if (level>=1u) {
char buf[64];
this->hostName (buf, sizeof(buf));
printf ("Client Host=%s\n", buf);
this->casCoreClient::show ( level - 1u );
this->in.show ( level - 1u );
this->out.show ( level - 1u );
this->casCoreClient::show ( level - 1u );
this->in.show ( level - 1u );
this->out.show ( level - 1u );
}
}
@ -114,7 +114,7 @@ caStatus casDGClient::uknownMessageAction ()
char pHostName[64u];
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
"bad request code=%u in DG\n", mp->m_cmmd );
return S_cas_badProtocol;
@ -135,7 +135,7 @@ caStatus casDGClient::searchAction()
if ( mp->m_postsize <= 1 ) {
char pHostName[64u];
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
"empty PV name extension in UDP search request?\n" );
return S_cas_success;
}
@ -143,19 +143,19 @@ caStatus casDGClient::searchAction()
if ( pChanName[0] == '\0' ) {
char pHostName[64u];
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
"zero length PV name in UDP search request?\n" );
return S_cas_success;
}
// check for an unterminated string before calling server tool
// by searching backwards through the string (some early versions
// by searching backwards through the string (some early versions
// of the client library might not be setting the pad bytes to nill)
for ( unsigned i = mp->m_postsize-1; pChanName[i] != '\0'; i-- ) {
if ( i <= 1 ) {
char pHostName[64u];
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
"unterminated PV name in UDP search request?\n" );
return S_cas_success;
}
@ -183,7 +183,7 @@ caStatus casDGClient::searchAction()
// ask the server tool if this PV exists
//
this->userStartedAsyncIO = false;
pvExistReturn pver =
pvExistReturn pver =
this->getCAS()->pvExistTest ( this->ctx, this->lastRecvAddr, pChanName );
//
@ -193,7 +193,7 @@ caStatus casDGClient::searchAction()
//
if ( this->userStartedAsyncIO ) {
if ( pver.getStatus() != pverAsyncCompletion ) {
errMessage (S_cas_badParameter,
errMessage (S_cas_badParameter,
"- assuming asynch IO status from caServer::pvExistTest()");
}
status = S_cas_success;
@ -212,13 +212,13 @@ caStatus casDGClient::searchAction()
break;
case pverAsyncCompletion:
errMessage (S_cas_badParameter,
errMessage (S_cas_badParameter,
"- unexpected asynch IO status from caServer::pvExistTest() ignored");
status = S_cas_success;
break;
default:
errMessage (S_cas_badParameter,
errMessage (S_cas_badParameter,
"- invalid return from caServer::pvExistTest() ignored");
status = S_cas_success;
break;
@ -234,14 +234,14 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
const pvExistReturn & retVal )
{
caStatus status;
if ( retVal.getStatus() != pverExistsHere ) {
return S_cas_success;
}
//
// starting with V4.1 the count field is used (abused)
// by the client to store the minor version number of
// by the client to store the minor version number of
// the client.
//
// Old versions expect alloc of channel in response
@ -250,8 +250,8 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
if ( !CA_V44(msg.m_count) ) {
char pName[64u];
this->hostName (pName, sizeof (pName));
errlogPrintf (
"client \"%s\" using EPICS R3.11 CA connect protocol was ignored\n",
errlogPrintf (
"client \"%s\" using EPICS R3.11 CA connect protocol was ignored\n",
pName);
//
// old connect protocol was dropped when the
@ -264,19 +264,19 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
}
//
// cid field is abused to carry the IP
// cid field is abused to carry the IP
// address in CA_V48 or higher
// (this allows a CA servers to serve
// as a directory service)
//
// data type field is abused to carry the IP
// data type field is abused to carry the IP
// port number here CA_V44 or higher
// (this allows multiple CA servers on one
// host)
//
ca_uint32_t serverAddr;
ca_uint16_t serverPort;
if ( CA_V48( msg.m_count ) ) {
if ( CA_V48( msg.m_count ) ) {
struct sockaddr_in ina;
if ( retVal.addrIsValid() ) {
caNetAddr addr = retVal.getAddr();
@ -296,7 +296,7 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
ina = addr.getSockIP();
//
// We dont fill in the servers address here
// because the server was not bound to a particular
// because the server was not bound to a particular
// interface, and we would need to waste CPU performing
// the following steps to determine the interface that
// will be used:
@ -318,24 +318,24 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
serverAddr = ~0U;
serverPort = ntohs ( inetAddr.sin_port );
}
ca_uint16_t * pMinorVersion;
epicsGuard < epicsMutex > guard ( this->mutex );
status = this->out.copyInHeader ( CA_PROTO_SEARCH,
sizeof ( *pMinorVersion ), serverPort, 0,
serverAddr, msg.m_available,
status = this->out.copyInHeader ( CA_PROTO_SEARCH,
sizeof ( *pMinorVersion ), serverPort, 0,
serverAddr, msg.m_available,
reinterpret_cast <void **> ( &pMinorVersion ) );
//
// Starting with CA V4.1 the minor version number
// is appended to the end of each search reply.
// This value is ignored by earlier clients.
// This value is ignored by earlier clients.
//
if ( status == S_cas_success ) {
AlignedWireRef < epicsUInt16 > tmp ( *pMinorVersion );
tmp = CA_MINOR_PROTOCOL_REVISION;
this->out.commitMsg ();
}
return status;
}
@ -346,15 +346,11 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
//
caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
{
caStatus 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 );
if ( status == S_cas_success ) {
this->out.commitMsg ();
}
this->out.commitMsg ();
return S_cas_success;
}
@ -408,8 +404,8 @@ void casDGClient::sendBeacon ( ca_uint32_t beaconNumber )
//
// casDGClient::xSend()
//
outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
bufSizeT nBytesToSend, bufSizeT & nBytesSent )
outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
bufSizeT nBytesToSend, bufSizeT & nBytesSent )
{
bufSizeT totalBytes = 0;
while ( totalBytes < nBytesToSend ) {
@ -422,7 +418,7 @@ outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
unsigned sizeDG = pHdr->cadg_nBytes - sizeof ( *pHdr );
if ( pHdr->cadg_addr.isValid() ) {
outBufClient::flushCondition stat =
outBufClient::flushCondition stat =
this->osdSend ( pDG, sizeDG, pHdr->cadg_addr );
if ( stat != outBufClient::flushProgress ) {
break;
@ -459,7 +455,7 @@ inBufClient::fillCondition casDGClient::xRecv (char *pBufIn, bufSizeT nBytesToRe
while (pAfter-pCurBuf >= static_cast<int>(MAX_UDP_RECV+sizeof(cadg))) {
pHdr = reinterpret_cast < cadg * > ( pCurBuf );
stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
MAX_UDP_RECV, parm, nDGBytesRecv, pHdr->cadg_addr);
if (stat==casFillProgress) {
pHdr->cadg_nBytes = nDGBytesRecv + sizeof(*pHdr);
@ -491,7 +487,7 @@ inBufClient::fillCondition casDGClient::xRecv (char *pBufIn, bufSizeT nBytesToRe
// this results in many small UDP frames which unfortunately
// isnt particularly efficient
//
caStatus casDGClient::asyncSearchResponse (
caStatus casDGClient::asyncSearchResponse (
epicsGuard < casClientMutex > &, const caNetAddr & outAddr,
const caHdrLargeArray & msg, const pvExistReturn & retVal,
ca_uint16_t protocolRevision, ca_uint32_t sequenceNumber )
@ -501,7 +497,7 @@ caStatus casDGClient::asyncSearchResponse (
}
void * pRaw;
const outBufCtx outctx = this->out.pushCtx
const outBufCtx outctx = this->out.pushCtx
( sizeof(cadg), MAX_UDP_SEND, pRaw );
if ( outctx.pushResult() != outBufCtx::pushCtxSuccess ) {
return S_cas_sendBlocked;
@ -565,9 +561,9 @@ caStatus casDGClient::processDG ()
// insert version header at the start of the reply message
this->sendVersion ();
cadg * pRespHdr = static_cast < cadg * > ( pRaw );
//
// select the next DG in the input stream and start processing it
//
@ -597,7 +593,7 @@ caStatus casDGClient::processDG ()
// a) it used all of the incoming DG or
// b) it used all of the outgoing DG
//
// In either case commit the DG to the protocol stream and
// In either case commit the DG to the protocol stream and
// release the send lock
//
// if there are not additional messages passed the version header
@ -688,7 +684,7 @@ void casDGClient::hostName ( char *pBufIn, unsigned bufSizeIn ) const
void casDGClient::sendVersion ()
{
epicsGuard < epicsMutex > guard ( this->mutex );
caStatus status = this->out.copyInHeader ( CA_PROTO_VERSION, 0,
caStatus status = this->out.copyInHeader ( CA_PROTO_VERSION, 0,
0, CA_MINOR_PROTOCOL_REVISION, 0, 0, 0 );
if ( ! status ) {
this->out.commitMsg ();
@ -783,8 +779,8 @@ caStatus casDGClient::processMsg ()
msgTmp.m_available = AlignedWireRef < epicsUInt32 > ( smallHdr.m_available );
if ( payloadSize & 0x7 ) {
status = this->sendErr (
& msgTmp, invalidResID, ECA_INTERNAL,
status = this->sendErr (
& msgTmp, invalidResID, ECA_INTERNAL,
"CAS: Datagram request wasn't 8 byte aligned" );
this->in.removeMsg ( bytesLeft );
break;
@ -793,7 +789,7 @@ caStatus casDGClient::processMsg ()
msgSize = hdrSize + payloadSize;
if ( bytesLeft < msgSize ) {
if ( msgSize > this->in.bufferSize() ) {
status = this->sendErr ( & msgTmp, invalidResID, ECA_TOLARGE,
status = this->sendErr ( & msgTmp, invalidResID, ECA_TOLARGE,
"client's request didnt fit within the CA server's message buffer" );
this->in.removeMsg ( bytesLeft );
}
@ -805,7 +801,7 @@ caStatus casDGClient::processMsg ()
if ( this->getCAS().getDebugLevel() > 5u ) {
char pHostName[64u];
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
caServerI::dumpMsg ( pHostName, "?",
caServerI::dumpMsg ( pHostName, "?",
& msgTmp, rawMP + hdrSize, 0 );
}
@ -813,7 +809,7 @@ caStatus casDGClient::processMsg ()
//
// Reset the context to the default
// (guarantees that previous message does not get mixed
// (guarantees that previous message does not get mixed
// up with the current message)
//
this->ctx.setChannel ( NULL );
@ -840,16 +836,16 @@ caStatus casDGClient::processMsg ()
}
catch ( std::exception & except ) {
this->in.removeMsg ( this->in.bytesPresent() );
status = this->sendErr (
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
this->sendErr (
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
"C++ exception \"%s\" in CA circuit server",
except.what () );
status = S_cas_internal;
}
catch (...) {
this->in.removeMsg ( this->in.bytesPresent() );
status = this->sendErr (
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
this->sendErr (
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
"unexpected C++ exception in CA datagram server" );
status = S_cas_internal;
}
@ -860,37 +856,38 @@ caStatus casDGClient::processMsg ()
//
// casDGClient::sendErr()
//
caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
ca_uint32_t cid, const int reportedStatus, const char *pformat, ... )
{
unsigned stringSize;
char msgBuf[1024]; /* allocate plenty of space for the message string */
if ( pformat ) {
va_list args;
va_start ( args, pformat );
int status = vsprintf ( msgBuf, pformat, args );
if ( status < 0 ) {
errPrintf (S_cas_internal, __FILE__, __LINE__,
"bad sendErr(%s)", pformat);
stringSize = 0u;
}
else {
stringSize = 1u + (unsigned) status;
}
}
else {
unsigned stringSize;
char msgBuf[1024]; /* allocate plenty of space for the message string */
if ( pformat ) {
va_list args;
va_start ( args, pformat );
int status = vsprintf ( msgBuf, pformat, args );
if ( status < 0 ) {
errPrintf (S_cas_internal, __FILE__, __LINE__,
"bad sendErr(%s)", pformat);
stringSize = 0u;
}
else {
stringSize = 1u + (unsigned) status;
}
va_end ( args );
}
else {
stringSize = 0u;
}
unsigned hdrSize = sizeof ( caHdr );
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
CA_V49( this->minor_version_number ) ) {
hdrSize += 2 * sizeof ( ca_uint32_t );
}
caHdr * pReqOut;
epicsGuard < epicsMutex > guard ( this->mutex );
caStatus status = this->out.copyInHeader ( CA_PROTO_ERROR,
caStatus status = this->out.copyInHeader ( CA_PROTO_ERROR,
hdrSize + stringSize, 0, 0, cid, reportedStatus,
reinterpret_cast <void **> ( & pReqOut ) );
if ( ! status ) {
@ -900,7 +897,7 @@ caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
* copy back the request protocol
* (in network byte order)
*/
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
CA_V49( this->minor_version_number ) ) {
ca_uint32_t *pLW = ( ca_uint32_t * ) ( pReqOut + 1 );
pReqOut->m_cmmd = htons ( curp->m_cmmd );
@ -945,7 +942,7 @@ caStatus casDGClient::echoAction ()
void * pPayloadOut;
epicsGuard < epicsMutex > guard ( this->mutex );
caStatus status = this->out.copyInHeader ( mp->m_cmmd, mp->m_postsize,
caStatus status = this->out.copyInHeader ( mp->m_cmmd, mp->m_postsize,
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
& pPayloadOut );
if ( ! status ) {

View File

@ -388,14 +388,12 @@ caStatus casStrmClient::echoAction ( epicsGuard < casClientMutex > & )
//
// casStrmClient::verifyRequest()
//
caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn)
{
const caHdrLargeArray * mp = this->ctx.getMsg();
//
// channel exists for this resource id ?
//
chronIntId tmpId ( mp->m_cid );
chronIntId tmpId ( ctx.msg.m_cid );
pChan = this->chanTable.lookup ( tmpId );
if ( ! pChan ) {
return ECA_BADCHID;
@ -404,14 +402,15 @@ caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
//
// data type out of range ?
//
if ( mp->m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
if ( ctx.msg.m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
return ECA_BADTYPE;
}
//
// element count out of range ?
//
if ( mp->m_count > pChan->getPVI().nativeCount() || mp->m_count == 0u ) {
if ( ctx.msg.m_count > pChan->getMaxElem() ||
( !allowdyn && ctx.msg.m_count == 0u ) ) {
return ECA_BADCOUNT;
}
@ -444,7 +443,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard )
casChannelI * pChan;
{
caStatus status = this->verifyRequest ( pChan );
caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pChan ) {
return this->sendErr ( guard, mp, pChan->getCID(),
@ -531,11 +530,15 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
pChan->getCID(), status, ECA_GETFAIL );
}
ca_uint32_t count = (msg.m_count == 0) ?
(ca_uint32_t)desc.getDataSizeElements() :
msg.m_count;
void * pPayload;
{
unsigned payloadSize = dbr_size_n ( msg.m_dataType, msg.m_count );
unsigned payloadSize = dbr_size_n ( msg.m_dataType, count );
caStatus localStatus = this->out.copyInHeader ( msg.m_cmmd, payloadSize,
msg.m_dataType, msg.m_count, pChan->getCID (),
msg.m_dataType, count, pChan->getCID (),
msg.m_available, & pPayload );
if ( localStatus ) {
if ( localStatus==S_cas_hugeRequest ) {
@ -551,21 +554,21 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
// (places the data in network format)
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr(
pPayload, msg.m_count, desc, pChan->enumStringTable() );
pPayload, count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump ();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u",
pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
pChan->getPVI().getName(), msg.m_dataType, count );
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_badBounds, ECA_GETFAIL );
}
int cacStatus = caNetConvert (
msg.m_dataType, pPayload, pPayload, true, msg.m_count );
msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@ -585,7 +588,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard
casChannelI * pChan;
{
caStatus status = this->verifyRequest ( pChan );
caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
return this->readNotifyFailureResponse ( guard, * mp, status );
}
@ -656,11 +659,15 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
return ecaStatus;
}
ca_uint32_t count = (msg.m_count == 0) ?
(ca_uint32_t)desc.getDataSizeElements() :
msg.m_count;
void *pPayload;
{
unsigned size = dbr_size_n ( msg.m_dataType, msg.m_count );
unsigned size = dbr_size_n ( msg.m_dataType, count );
caStatus status = this->out.copyInHeader ( msg.m_cmmd, size,
msg.m_dataType, msg.m_count, ECA_NORMAL,
msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@ -675,23 +682,23 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
// convert gdd to db_access type
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr ( pPayload,
msg.m_count, desc, pChan->enumStringTable() );
count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__,
"- get notify with PV=%s type=%u count=%u",
pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
pChan->getPVI().getName(), msg.m_dataType, count );
return this->readNotifyFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
msg.m_dataType, pPayload, pPayload, true, msg.m_count );
msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@ -727,8 +734,8 @@ caStatus casStrmClient::readNotifyFailureResponse (
// to be more efficent if it discovers that the source has less data
// than the destination)
//
caStatus convertContainerMemberToAtomic ( gdd & dd,
aitUint32 appType, aitUint32 elemCount )
caStatus convertContainerMemberToAtomic ( gdd & dd,
aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount )
{
gdd * pVal;
if ( dd.isContainer() ) {
@ -755,13 +762,13 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
return S_cas_badType;
}
if ( elemCount <= 1 ) {
if ( nativeCount <= 1 ) {
return S_cas_success;
}
// convert to atomic
gddBounds bds;
bds.setSize ( elemCount );
bds.setSize ( requestedCount );
bds.setFirst ( 0u );
pVal->setDimension ( 1u, & bds );
return S_cas_success;
@ -770,9 +777,9 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
//
// createDBRDD ()
//
static caStatus createDBRDD ( unsigned dbrType,
unsigned elemCount, gdd * & pDD )
{
static caStatus createDBRDD ( unsigned dbrType,
unsigned requestedCount, unsigned nativeCount, gdd * & pDD )
{
/*
* DBR type has already been checked, but it is possible
* that "gddDbrToAit" will not track with changes in
@ -799,7 +806,7 @@ static caStatus createDBRDD ( unsigned dbrType,
// fix the value element count
caStatus status = convertContainerMemberToAtomic (
*pDescRet, gddAppType_value, elemCount );
*pDescRet, gddAppType_value, requestedCount, nativeCount );
if ( status != S_cas_success ) {
pDescRet->unreference ();
return status;
@ -849,11 +856,27 @@ caStatus casStrmClient::monitorResponse (
casChannelI & chan, const caHdrLargeArray & msg,
const gdd & desc, const caStatus completionStatus )
{
aitUint32 elementCount = 0;
if (desc.isContainer()) {
aitUint32 index;
int gdds = gddApplicationTypeTable::app_table.mapAppToIndex
( desc.applicationType(), gddAppType_value, index );
if ( gdds ) {
return S_cas_badType;
}
elementCount = desc.getDD(index)->getDataSizeElements();
} else {
elementCount = desc.getDataSizeElements();
}
ca_uint32_t count = (msg.m_count == 0) ?
(ca_uint32_t)elementCount :
msg.m_count;
void * pPayload = 0;
{
ca_uint32_t size = dbr_size_n ( msg.m_dataType, msg.m_count );
ca_uint32_t size = dbr_size_n ( msg.m_dataType, count );
caStatus status = out.copyInHeader ( msg.m_cmmd, size,
msg.m_dataType, msg.m_count, ECA_NORMAL,
msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@ -871,7 +894,8 @@ caStatus casStrmClient::monitorResponse (
gdd * pDBRDD = 0;
if ( completionStatus == S_cas_success ) {
caStatus status = createDBRDD ( msg.m_dataType, msg.m_count, pDBRDD );
caStatus status = createDBRDD ( msg.m_dataType, count,
chan.getMaxElem(), pDBRDD );
if ( status != S_cas_success ) {
caStatus ecaStatus;
if ( status == S_cas_badType ) {
@ -892,7 +916,7 @@ caStatus casStrmClient::monitorResponse (
pDBRDD->unreference ();
errPrintf ( S_cas_noConvert, __FILE__, __LINE__,
"no conversion between event app type=%d and DBR type=%d Element count=%d",
desc.applicationType (), msg.m_dataType, msg.m_count);
desc.applicationType (), msg.m_dataType, count);
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
}
@ -915,14 +939,14 @@ caStatus casStrmClient::monitorResponse (
}
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr (
pPayload, msg.m_count, *pDBRDD, chan.enumStringTable() );
pPayload, count, *pDBRDD, chan.enumStringTable() );
if ( mapDBRStatus < 0 ) {
pDBRDD->unreference ();
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
msg.m_dataType, pPayload, pPayload, true, msg.m_count );
msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
pDBRDD->unreference ();
return this->sendErrWithEpicsStatus (
@ -932,7 +956,7 @@ caStatus casStrmClient::monitorResponse (
//
// force string message size to be the true size
//
if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
if ( msg.m_dataType == DBR_STRING && count == 1u ) {
ca_uint32_t reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@ -1842,7 +1866,7 @@ caStatus casStrmClient::privateCreateChanResponse (
// the protocol buffer.
//
assert ( nativeTypeDBR <= 0xffff );
aitIndex nativeCount = chan.getPVI().nativeCount();
aitIndex nativeCount = chan.getMaxElem();
assert ( nativeCount <= 0xffffffff );
assert ( hdr.m_cid == chan.getCID() );
status = this->out.copyInHeader ( CA_PROTO_CREATE_CHAN, 0,
@ -1940,7 +1964,7 @@ caStatus casStrmClient::eventAddAction (
casChannelI *pciu;
{
caStatus status = casStrmClient::verifyRequest ( pciu );
caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pciu ) {
return this->sendErr ( guard, mp,
@ -2601,8 +2625,8 @@ caStatus casStrmClient::read ()
{
gdd * pDD = 0;
caStatus status = createDBRDD ( pHdr->m_dataType,
pHdr->m_count, pDD );
caStatus status = createDBRDD ( pHdr->m_dataType, pHdr->m_count,
this->ctx.getChannel()->getMaxElem(), pDD );
if ( status != S_cas_success ) {
return status;
}
@ -2749,6 +2773,7 @@ caStatus casStrmClient::sendErr ( epicsGuard <casClientMutex> &,
else {
stringSize = 1u + (unsigned) status;
}
va_end ( args );
}
else {
stringSize = 0u;

View File

@ -69,7 +69,7 @@ private:
bool responseIsPending;
caStatus createChannel ( const char * pName );
caStatus verifyRequest ( casChannelI * & pChan );
caStatus verifyRequest ( casChannelI * & pChan, bool allowdyn = false );
typedef caStatus ( casStrmClient :: * pCASMsgHandler )
( epicsGuard < casClientMutex > & );
static pCASMsgHandler const msgHandlers[CA_PROTO_LAST_CMMD+1u];

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
@ -32,7 +32,7 @@ const unsigned caServerConnectPendQueueSize = 5u;
//
// casIntfIO::casIntfIO()
//
casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
sock ( INVALID_SOCKET ),
addr ( addrIn.getSockIP() )
{
@ -40,80 +40,79 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
osiSocklen_t addrSize;
bool portChange;
if ( ! osiSockAttach () ) {
throw S_cas_internal;
}
if ( ! osiSockAttach () ) {
throw S_cas_internal;
}
/*
* Setup the server socket
*/
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (this->sock==INVALID_SOCKET) {
/*
* Setup the server socket
*/
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (this->sock == INVALID_SOCKET) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
printf ( "No socket error was %s\n", sockErrBuf );
throw S_cas_noFD;
}
printf ( "No socket error was %s\n", sockErrBuf );
throw S_cas_noFD;
}
epicsSocketEnableAddressReuseDuringTimeWaitState ( this->sock );
status = bind ( this->sock,
reinterpret_cast <sockaddr *> (&this->addr),
sizeof(this->addr) );
if (status<0) {
if (SOCKERRNO == SOCK_EADDRINUSE) {
//
// enable assignment of a default port
// (so the getsockname() call below will
// work correctly)
//
this->addr.sin_port = ntohs (0);
status = bind(
status = bind ( this->sock,
reinterpret_cast <sockaddr *> (&this->addr),
sizeof(this->addr) );
if (status < 0) {
if (SOCKERRNO == SOCK_EADDRINUSE ||
SOCKERRNO == SOCK_EACCES) {
//
// enable assignment of a default port
// (so the getsockname() call below will
// work correctly)
//
this->addr.sin_port = ntohs (0);
status = bind(
this->sock,
reinterpret_cast <sockaddr *> (&this->addr),
sizeof(this->addr) );
}
if (status<0) {
}
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
char buf[64];
ipAddrToA (&this->addr, buf, sizeof(buf));
errPrintf ( S_cas_bindFail,
__FILE__, __LINE__,
"- bind TCP IP addr=%s failed because %s",
buf, sockErrBuf );
char buf[64];
ipAddrToA (&this->addr, buf, sizeof(buf));
errlogPrintf ( "CAS: Socket bind TCP to %s failed with %s",
buf, sockErrBuf );
epicsSocketDestroy (this->sock);
throw S_cas_bindFail;
}
throw S_cas_bindFail;
}
portChange = true;
}
}
else {
portChange = false;
}
addrSize = ( osiSocklen_t ) sizeof (this->addr);
status = getsockname (
this->sock,
reinterpret_cast <sockaddr *> ( &this->addr ),
addrSize = ( osiSocklen_t ) sizeof (this->addr);
status = getsockname (
this->sock,
reinterpret_cast <sockaddr *> ( &this->addr ),
&addrSize );
if (status) {
if (status) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: getsockname() error %s\n",
sockErrBuf );
errlogPrintf ( "CAS: getsockname() error %s\n",
sockErrBuf );
epicsSocketDestroy (this->sock);
throw S_cas_internal;
}
throw S_cas_internal;
}
//
// be sure of this now so that we can fetch the IP
// address and port number later
//
//
// be sure of this now so that we can fetch the IP
// address and port number later
//
assert (this->addr.sin_family == AF_INET);
if ( portChange ) {
errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
ntohs (this->addr.sin_port) );
errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
@ -121,12 +120,12 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
}
status = listen(this->sock, caServerConnectPendQueueSize);
if(status < 0) {
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: listen() error %s\n", sockErrBuf );
errlogPrintf ( "CAS: listen() error %s\n", sockErrBuf );
epicsSocketDestroy (this->sock);
throw S_cas_internal;
throw S_cas_internal;
}
}
@ -135,17 +134,17 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
//
casIntfIO::~casIntfIO()
{
if (this->sock != INVALID_SOCKET) {
epicsSocketDestroy (this->sock);
}
if (this->sock != INVALID_SOCKET) {
epicsSocketDestroy (this->sock);
}
osiSockRelease ();
osiSockRelease ();
}
//
// newStreamIO::newStreamClient()
//
casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
clientBufMemoryManager & bufMgr ) const
{
static bool oneMsgFlag = false;
@ -175,14 +174,14 @@ casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
args.sock = newSock;
casStreamOS * pOS = new casStreamOS ( cas, bufMgr, args );
if ( ! pOS ) {
errMessage ( S_cas_noMemory,
errMessage ( S_cas_noMemory,
"unable to create data structures for a new client" );
epicsSocketDestroy ( newSock );
}
else {
if ( cas.getDebugLevel() > 0u ) {
char pName[64u];
pOS->hostName ( pName, sizeof ( pName ) );
errlogPrintf ( "CAS: allocated client object for \"%s\"\n", pName );
}
@ -197,7 +196,7 @@ void casIntfIO::setNonBlocking()
{
int status;
osiSockIoctl_t yes = true;
status = socket_ioctl(this->sock, FIONBIO, &yes);
if ( status < 0 ) {
char sockErrBuf[64];

View File

@ -130,8 +130,8 @@ long dbcar(char *precordname, int level)
precord->name,
pdbFldDes->name,
plink->value.pv_link.pvname,
pca->nDisconnect,
pca->nNoWrite);
pca ? pca->nDisconnect : 0,
pca ? pca->nNoWrite : 0);
}
}
}

View File

@ -3940,10 +3940,9 @@ static long putFloatString(
char *pdest = (char *) paddr->pfield;
long status = 0;
int precision = 6;
struct rset *prset = 0;
struct rset *prset = dbGetRset(paddr);
short size = paddr->field_size;
if (paddr) prset = dbGetRset(paddr);
if (prset && (prset->get_precision))
status = (*prset->get_precision)(paddr,&precision);
if (nRequest==1 && offset==0) {
@ -4154,10 +4153,9 @@ static long putDoubleString(
char *pdest = (char *) paddr->pfield;
long status = 0;
int precision = 6;
struct rset *prset = 0;
struct rset *prset = dbGetRset(paddr);
short size = paddr->field_size;
if (paddr) prset = dbGetRset(paddr);
if (prset && (prset->get_precision))
status = (*prset->get_precision)(paddr,&precision);
if (nRequest==1 && offset==0) {

View File

@ -159,8 +159,11 @@ void scanStop(void)
interruptAccept = FALSE;
for (i = 0; i < nPeriodic; i++) {
papPeriodic[i]->scanCtl = ctlExit;
epicsEventSignal(papPeriodic[i]->loopEvent);
periodic_scan_list *ppsl = papPeriodic[i];
if (!ppsl) continue;
ppsl->scanCtl = ctlExit;
epicsEventSignal(ppsl->loopEvent);
epicsEventWait(startStopEvent);
}
@ -205,16 +208,24 @@ void scanRun(void)
interruptAccept = TRUE;
scanCtl = ctlRun;
for (i = 0; i < nPeriodic; i++)
papPeriodic[i]->scanCtl = ctlRun;
for (i = 0; i < nPeriodic; i++) {
periodic_scan_list *ppsl = papPeriodic[i];
if (!ppsl) continue;
ppsl->scanCtl = ctlRun;
}
}
void scanPause(void)
{
int i;
for (i = nPeriodic - 1; i >= 0; --i)
papPeriodic[i]->scanCtl = ctlPause;
for (i = nPeriodic - 1; i >= 0; --i) {
periodic_scan_list *ppsl = papPeriodic[i];
if (!ppsl) continue;
ppsl->scanCtl = ctlPause;
}
scanCtl = ctlPause;
interruptAccept = FALSE;
@ -286,9 +297,11 @@ void scanAdd(struct dbCommon *precord)
}
addToList(precord, &piosh->iosl[prio].scan_list);
} else if (scan >= SCAN_1ST_PERIODIC) {
addToList(precord, &papPeriodic[scan - SCAN_1ST_PERIODIC]->scan_list);
periodic_scan_list *ppsl = papPeriodic[scan - SCAN_1ST_PERIODIC];
if (ppsl)
addToList(precord, &ppsl->scan_list);
}
return;
}
void scanDelete(struct dbCommon *precord)
@ -352,28 +365,48 @@ void scanDelete(struct dbCommon *precord)
}
deleteFromList(precord, &piosh->iosl[prio].scan_list);
} else if (scan >= SCAN_1ST_PERIODIC) {
deleteFromList(precord, &papPeriodic[scan - SCAN_1ST_PERIODIC]->scan_list);
periodic_scan_list *ppsl = papPeriodic[scan - SCAN_1ST_PERIODIC];
if (ppsl)
deleteFromList(precord, &ppsl->scan_list);
}
return;
}
double scanPeriod(int scan) {
periodic_scan_list *ppsl;
scan -= SCAN_1ST_PERIODIC;
if (scan < 0 || scan >= nPeriodic)
return 0.0;
return papPeriodic[scan]->period;
ppsl = papPeriodic[scan];
return ppsl ? ppsl->period : 0.0;
}
int scanppl(double period) /* print periodic list */
int scanppl(double period) /* print periodic scan list(s) */
{
periodic_scan_list *ppsl;
dbMenu *pmenu = dbFindMenu(pdbbase, "menuScan");
char message[80];
int i;
if (!pmenu || !papPeriodic) {
printf("scanppl: dbScan subsystem not initialized\n");
return -1;
}
for (i = 0; i < nPeriodic; i++) {
ppsl = papPeriodic[i];
if (ppsl == NULL) continue;
if (period > 0.0 && (fabs(period - ppsl->period) >.05)) continue;
periodic_scan_list *ppsl = papPeriodic[i];
if (!ppsl) {
const char *choice = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC];
printf("Periodic scan list for SCAN = '%s' not initialized\n",
choice);
continue;
}
if (period > 0.0 &&
(fabs(period - ppsl->period) > 0.05))
continue;
sprintf(message, "Records with SCAN = '%s' (%lu over-runs):",
ppsl->name, ppsl->overruns);
printList(&ppsl->scan_list, message);
@ -741,7 +774,7 @@ static void periodicTask(void *arg)
if (++overruns >= 10 &&
epicsTimeDiffInSeconds(&now, &reported) > report_delay) {
errlogPrintf("\ndbScan warning from '%s' scan thread:\n"
"\tScan processing averages %.2f seconds (%.2f .. %.2f).\n"
"\tScan processing averages %.3f seconds (%.3f .. %.3f).\n"
"\tOver-runs have now happened %u times in a row.\n"
"\tTo fix this, move some records to a slower scan rate.\n",
ppsl->name, ppsl->period + overtime / overruns,
@ -788,12 +821,8 @@ static void initPeriodic(void)
char *unit;
int status = epicsParseDouble(choice, &number, &unit);
ppsl->scan_list.lock = epicsMutexMustCreate();
ellInit(&ppsl->scan_list.list);
ppsl->name = choice;
if (status || number == 0) {
if (status || number <= 0) {
errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
ppsl->period = i;
}
else if (!*unit ||
!epicsStrCaseCmp(unit, "second") ||
@ -814,16 +843,24 @@ static void initPeriodic(void)
}
else {
errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
ppsl->period = i;
}
if (ppsl->period == 0) {
free(ppsl);
continue;
}
ppsl->scan_list.lock = epicsMutexMustCreate();
ellInit(&ppsl->scan_list.list);
ppsl->name = choice;
ppsl->scanCtl = ctlPause;
ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);
number = ppsl->period / quantum;
if ((ppsl->period < 2 * quantum) ||
(number / floor(number) > 1.1)) {
errlogPrintf("initPeriodic: Scan rate '%s' is not achievable.\n",
choice);
}
ppsl->scanCtl = ctlPause;
ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);
papPeriodic[i] = ppsl;
}
@ -835,6 +872,8 @@ static void deletePeriodic(void)
for (i = 0; i < nPeriodic; i++) {
periodic_scan_list *ppsl = papPeriodic[i];
if (!ppsl) continue;
ellFree(&ppsl->scan_list.list);
epicsEventDestroy(ppsl->loopEvent);
epicsMutexDestroy(ppsl->scan_list.lock);
@ -847,10 +886,11 @@ static void deletePeriodic(void)
static void spawnPeriodic(int ind)
{
periodic_scan_list *ppsl;
periodic_scan_list *ppsl = papPeriodic[ind];
char taskName[20];
ppsl = papPeriodic[ind];
if (!ppsl) return;
sprintf(taskName, "scan-%g", ppsl->period);
periodicTaskId[ind] = epicsThreadCreate(
taskName, epicsThreadPriorityScanLow + ind,
@ -989,13 +1029,13 @@ static void addToList(struct dbCommon *precord, scan_list *psl)
pse->precord = precord;
}
pse->pscan_list = psl;
ptemp = (scan_element *)ellFirst(&psl->list);
ptemp = (scan_element *)ellLast(&psl->list);
while (ptemp) {
if (ptemp->precord->phas > precord->phas) {
ellInsert(&psl->list, ellPrevious(&ptemp->node), &pse->node);
if (ptemp->precord->phas <= precord->phas) {
ellInsert(&psl->list, &ptemp->node, &pse->node);
break;
}
ptemp = (scan_element *)ellNext(&ptemp->node);
ptemp = (scan_element *)ellPrevious(&ptemp->node);
}
if (ptemp == NULL) ellAdd(&psl->list, (void *)pse);
psl->modified = TRUE;

View File

@ -172,6 +172,7 @@ int pft(const char *pname, const char *pvalue)
ca_dump_dbr(DBR_ENUM,1, buffer);
}
printf("\n");
dbChannelDelete(chan);
return (0);
}
@ -231,6 +232,7 @@ int tpn(const char *pname, const char *pvalue)
ppn = calloc(1, sizeof(processNotify));
if (!ppn) {
printf("calloc failed\n");
dbChannelDelete(chan);
return -1;
}
ppn->requestType = putProcessRequest;
@ -241,6 +243,8 @@ int tpn(const char *pname, const char *pvalue)
ptpnInfo = calloc(1, sizeof(tpnInfo));
if (!ptpnInfo) {
printf("calloc failed\n");
free(ppn);
dbChannelDelete(chan);
return -1;
}
ptpnInfo->ppn = ppn;

View File

@ -541,8 +541,11 @@ MAIN(chfPluginTest)
dbChannel *pch;
db_field_log *pfl;
#if defined(WIN32) && (!defined(_MINGW) || __MSVCRT_VERSION__ >= 0x0800)
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
(defined(_MINGW) && defined(_TWO_DIGIT_EXPONENT))
_set_output_format(_TWO_DIGIT_EXPONENT);
#endif
#endif
testPlan(1433);

View File

@ -133,25 +133,25 @@ typedef struct dbVariableDef {
}dbVariableDef;
typedef struct dbRecordType {
ELLNODE node;
ELLLIST attributeList; /*LIST head of attributes*/
ELLLIST recList; /*LIST head of sorted dbRecordNodes*/
ELLLIST devList; /*List of associated device support*/
ELLLIST cdefList; /*LIST of Cdef text items*/
char *name;
short no_fields; /* number of fields defined */
short no_prompt; /* number of fields to configure*/
short no_links; /* number of links */
short no_aliases; /* number of aliases in recList */
short *link_ind; /* addr of array of ind in papFldDes*/
char **papsortFldName;/* ptr to array of ptr to fld names*/
short *sortFldInd; /* addr of array of ind in papFldDes*/
dbFldDes *pvalFldDes; /*pointer dbFldDes for VAL field*/
short indvalFlddes; /*ind in papFldDes*/
dbFldDes **papFldDes; /* ptr to array of ptr to fldDes*/
/*The following are only available on run time system*/
struct rset *prset;
int rec_size; /*record size in bytes */
ELLNODE node;
ELLLIST attributeList; /*LIST head of attributes*/
ELLLIST recList; /*LIST head of sorted dbRecordNodes*/
ELLLIST devList; /*List of associated device support*/
ELLLIST cdefList; /*LIST of Cdef text items*/
char *name;
short no_fields; /* number of fields defined */
short no_prompt; /* number of fields to configure*/
short no_links; /* number of links */
short no_aliases; /* number of aliases in recList */
short *link_ind; /* addr of array of ind in papFldDes*/
char **papsortFldName;/* ptr to array of ptr to fld names*/
short *sortFldInd; /* addr of array of ind in papFldDes*/
dbFldDes *pvalFldDes; /*pointer dbFldDes for VAL field*/
short indvalFlddes; /*ind in papFldDes*/
dbFldDes **papFldDes; /* ptr to array of ptr to fldDes*/
/*The following are only available on run time system*/
struct rset *prset;
int rec_size; /*record size in bytes */
}dbRecordType;
struct dbPvd; /* Contents private to dbPvdLib code */

View File

@ -50,6 +50,9 @@ epicsExportAddress(int,dbBptNotMonotonic);
epicsShareDef int dbQuietMacroWarnings=0;
epicsExportAddress(int,dbQuietMacroWarnings);
epicsShareDef int dbRecordsAbcSorted=0;
epicsExportAddress(int,dbRecordsAbcSorted);
/*private routines */
static void yyerrorAbort(char *str);
static void allocTemp(void *pvoid);
@ -194,7 +197,16 @@ static void freeInputFileList(void)
free((void *)pinputFileNow);
}
}
static
int cmp_dbRecordNode(const ELLNODE *lhs, const ELLNODE *rhs)
{
dbRecordNode *LHS = (dbRecordNode*)lhs,
*RHS = (dbRecordNode*)rhs;
return strcmp(LHS->recordname, RHS->recordname);
}
static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
const char *path,const char *substitutions)
{
@ -239,24 +251,25 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
macSuppressWarning(macHandle,dbQuietMacroWarnings);
}
pinputFile = dbCalloc(1,sizeof(inputFile));
if(filename) {
pinputFile->filename = macEnvExpand(filename);
if (filename) {
pinputFile->filename = macEnvExpand(filename);
}
if(!fp) {
FILE *fp1;
if (!fp) {
FILE *fp1 = 0;
if(pinputFile->filename) pinputFile->path = dbOpenFile(pdbbase,pinputFile->filename,&fp1);
if(!pinputFile->filename || !fp1) {
errPrintf(0,__FILE__, __LINE__,
"dbRead opening file %s",pinputFile->filename);
free((void *)pinputFile->filename);
free((void *)pinputFile);
if (pinputFile->filename)
pinputFile->path = dbOpenFile(pdbbase, pinputFile->filename, &fp1);
if (!pinputFile->filename || !fp1) {
errPrintf(0, __FILE__, __LINE__,
"dbRead opening file %s",pinputFile->filename);
free(pinputFile->filename);
free(pinputFile);
status = -1;
goto cleanup;
}
pinputFile->fp = fp1;
}
pinputFile->fp = fp1;
} else {
pinputFile->fp = fp;
pinputFile->fp = fp;
}
pinputFile->line_num = 0;
pinputFileNow = pinputFile;
@ -294,6 +307,15 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
dbFinishEntry(pdbEntry);
}
cleanup:
if(dbRecordsAbcSorted) {
ELLNODE *cur;
for(cur = ellFirst(&pdbbase->recordTypeList); cur; cur=ellNext(cur))
{
dbRecordType *rtype = CONTAINER(cur, dbRecordType, node);
ellSortStable(&rtype->recList, &cmp_dbRecordNode);
}
}
if(macHandle) macDeleteHandle(macHandle);
macHandle = NULL;
if(mac_input_buffer) free((void *)mac_input_buffer);

View File

@ -1418,7 +1418,6 @@ long dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
dbFldDes *pdbFldDes;
PVDENTRY *ppvd;
ELLLIST *preclist = NULL;
dbRecordNode *precnode = NULL;
dbRecordNode *pNewRecNode = NULL;
long status = 0;
@ -1426,7 +1425,7 @@ long dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
/*Get size of NAME field*/
pdbFldDes = precordType->papFldDes[0];
if(!pdbFldDes || (strcmp(pdbFldDes->name,"NAME")!=0))
return(S_dbLib_nameLength);
return(S_dbLib_nameLength);
if((int)strlen(precordName)>=pdbFldDes->size) return(S_dbLib_nameLength);
/* clear callers entry */
zeroDbentry(pdbentry);
@ -1441,18 +1440,7 @@ long dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
if((status = dbAllocRecord(pdbentry,precordName))) return(status);
pNewRecNode->recordname = dbRecordName(pdbentry);
ellInit(&pNewRecNode->infoList);
/* install record node in list in sorted postion */
status = dbFirstRecord(pdbentry);
while(status==0) {
if(strcmp(precordName,dbGetRecordName(pdbentry)) < 0) break;
status = dbNextRecord(pdbentry);
}
if(status==0) {
precnode = pdbentry->precnode;
ellInsert(preclist,ellPrevious(&precnode->node),&pNewRecNode->node);
} else {
ellAdd(preclist,&pNewRecNode->node);
}
ellAdd(preclist, &pNewRecNode->node);
pdbentry->precnode = pNewRecNode;
ppvd = dbPvdAdd(pdbentry->pdbbase,precordType,pNewRecNode);
if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
@ -1630,52 +1618,6 @@ char * dbGetRecordName(DBENTRY *pdbentry)
return precnode->recordname;
}
long dbRenameRecord(DBENTRY *pdbentry,const char *newName)
{
dbBase *pdbbase = pdbentry->pdbbase;
dbRecordType *precordType = pdbentry->precordType;
dbFldDes *pdbFldDes;
dbRecordNode *precnode = pdbentry->precnode;
PVDENTRY *ppvd;
ELLLIST *preclist;
dbRecordNode *plistnode;
long status;
DBENTRY dbentry;
if(!precordType) return(S_dbLib_recordTypeNotFound);
/*Get size of NAME field*/
pdbFldDes = precordType->papFldDes[0];
if(!pdbFldDes || (strcmp(pdbFldDes->name,"NAME")!=0))
return(S_dbLib_nameLength);
if((int)strlen(newName)>=pdbFldDes->size) return(S_dbLib_nameLength);
if (!precnode || dbIsAlias(pdbentry)) return S_dbLib_recNotFound;
dbInitEntry(pdbentry->pdbbase,&dbentry);
status = dbFindRecord(&dbentry,newName);
dbFinishEntry(&dbentry);
if(!status) return(S_dbLib_recExists);
dbPvdDelete(pdbbase,precnode);
pdbentry->pflddes = precordType->papFldDes[0];
if((status = dbGetFieldAddress(pdbentry))) return(status);
strcpy(pdbentry->pfield,newName);
ppvd = dbPvdAdd(pdbbase,precordType,precnode);
if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
/*remove from record list and reinstall in sorted order*/
preclist = &precordType->recList;
ellDelete(preclist,&precnode->node);
plistnode = (dbRecordNode *)ellFirst(preclist);
while(plistnode) {
pdbentry->precnode = plistnode;
if(strcmp(newName,dbGetRecordName(pdbentry)) >=0) break;
plistnode = (dbRecordNode *)ellNext(&plistnode->node);
}
if(plistnode)
ellInsert(preclist,ellPrevious(&plistnode->node),&precnode->node);
else
ellAdd(preclist,&precnode->node);
/*Leave pdbentry pointing to newly renamed record*/
return(dbFindRecord(pdbentry,newName));
}
long dbVisibleRecord(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
@ -1709,7 +1651,6 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
dbRecordNode *pnewnode;
PVDENTRY *ppvd;
ELLLIST *preclist = NULL;
long status;
if (!precordType) return S_dbLib_recordTypeNotFound;
if (!precnode) return S_dbLib_recNotFound;
@ -1725,18 +1666,7 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
if (!(precnode->flags & DBRN_FLAGS_ISALIAS))
precnode->flags |= DBRN_FLAGS_HASALIAS;
ellInit(&pnewnode->infoList);
/* install record node in list in sorted postion */
status = dbFirstRecord(pdbentry);
while (!status) {
if (strcmp(alias, dbGetRecordName(pdbentry)) < 0) break;
status = dbNextRecord(pdbentry);
}
if (!status) {
precnode = pdbentry->precnode;
ellInsert(preclist, ellPrevious(&precnode->node), &pnewnode->node);
} else {
ellAdd(preclist, &pnewnode->node);
}
ellAdd(preclist, &pnewnode->node);
precordType->no_aliases++;
pdbentry->precnode = pnewnode;
ppvd = dbPvdAdd(pdbentry->pdbbase, precordType, pnewnode);

View File

@ -146,8 +146,6 @@ epicsShareFunc long dbNextRecord(DBENTRY *pdbentry);
epicsShareFunc int dbGetNRecords(DBENTRY *pdbentry);
epicsShareFunc int dbGetNAliases(DBENTRY *pdbentry);
epicsShareFunc char * dbGetRecordName(DBENTRY *pdbentry);
epicsShareFunc long dbRenameRecord(DBENTRY *pdbentry,
const char *newName);
epicsShareFunc long dbCopyRecord(DBENTRY *pdbentry,
const char *newRecordName, int overWriteOK);

View File

@ -11,6 +11,7 @@ variable(asCaDebug,int)
# Static database access variables
variable(dbRecordsOnceOnly,int)
variable(dbRecordsAbcSorted,int)
variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int)

View File

@ -26,6 +26,7 @@
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "errlog.h"
@ -663,7 +664,7 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *pClient )
{
struct channel_in_use *pciu = MPTOPCIU ( mp );
const int readAccess = asCheckGet ( pciu->asClientPVT );
int readAccess;
ca_uint32_t payloadSize;
void *pPayload;
int status;
@ -675,6 +676,7 @@ static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *p
logBadId ( pClient, mp, 0 );
return RSRV_ERROR;
}
readAccess = asCheckGet ( pciu->asClientPVT );
SEND_LOCK ( pClient );
@ -748,7 +750,7 @@ static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *p
*/
if ( mp->m_dataType == DBR_STRING && mp->m_count == 1 ) {
char * pStr = (char *) pPayload;
size_t strcnt = strlen ( pStr );
size_t strcnt = epicsStrnLen( pStr, payloadSize );
if ( strcnt < payloadSize ) {
payloadSize = ( ca_uint32_t ) ( strcnt + 1u );
}
@ -883,7 +885,7 @@ static int write_action ( caHdrLargeArray *mp,
static int host_name_action ( caHdrLargeArray *mp, void *pPayload,
struct client *client )
{
size_t size;
ca_uint32_t size;
char *pName;
char *pMalloc;
int chanCount;
@ -907,9 +909,9 @@ static int host_name_action ( caHdrLargeArray *mp, void *pPayload,
}
pName = (char *) pPayload;
size = strlen(pName)+1;
if (size > 512) {
log_header ( "bad (very long) host name",
size = epicsStrnLen(pName, mp->m_postsize)+1;
if (size > 512 || size > mp->m_postsize) {
log_header ( "bad (very long) host name",
client, mp, pPayload, 0 );
SEND_LOCK(client);
send_err(
@ -962,7 +964,7 @@ static int host_name_action ( caHdrLargeArray *mp, void *pPayload,
static int client_name_action ( caHdrLargeArray *mp, void *pPayload,
struct client *client )
{
size_t size;
ca_uint32_t size;
char *pName;
char *pMalloc;
int chanCount;
@ -986,9 +988,9 @@ static int client_name_action ( caHdrLargeArray *mp, void *pPayload,
}
pName = (char *) pPayload;
size = strlen(pName)+1;
if (size > 512) {
log_header ("a very long user name was specified",
size = epicsStrnLen(pName, mp->m_postsize)+1;
if (size > 512 || size > mp->m_postsize) {
log_header ("a very long user name was specified",
client, mp, pPayload, 0);
SEND_LOCK(client);
send_err(

View File

@ -232,16 +232,17 @@ SOCKET* rsrv_grab_tcp(unsigned short *port)
ok = 0;
break;
}
/* if SOCK_EADDRINUSE then try again with a different port number.
* otherwise, fail hard
/* if SOCK_EADDRINUSE or SOCK_EACCES try again with a different
* port number, otherwise fail hard.
*/
if(errcode!=SOCK_EADDRINUSE) {
if (errcode != SOCK_EADDRINUSE &&
errcode != SOCK_EACCES) {
char name[40];
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToDottedIP(&scratch.ia, name, sizeof(name));
cantProceed( "CAS: Socket bind %s error was \"%s\"\n",
cantProceed( "CAS: Socket bind %s error was %s\n",
name, sockErrBuf );
}
ok = 0;
@ -852,7 +853,7 @@ static void log_one_client (struct client *client, unsigned level)
printf(
"\tUnprocessed request bytes = %u, Undelivered response bytes = %u\n",
client->recv.cnt - client->recv.stk,
client->send.stk );
client->send.stk );
printf(
"\tState = %s%s%s\n",
state[client->disconnect?1:0],

View File

@ -2,7 +2,7 @@
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS startup task for EPICS
@ -287,27 +287,27 @@ initialize_remote_filesystem(char **argv, int hasLocalFilesystem)
mount_point[l] = '\0';
argv[1] = rtems_bsdnet_bootp_cmdline;
/*
* Its probably common to embed the mount point in the server
* Its probably common to embed the mount point in the server
* name so, when this is occurring, dont clobber the mount point
* by appending the first node from the command path. This allows
* the mount point to be a different path then the server's mount
* the mount point to be a different path then the server's mount
* path.
*
* This allows for example a line similar to as follows the DHCP
* This allows for example a line similar to as follows the DHCP
* configuration file.
*
* server-name "159.233@192.168.0.123:/vol/vol0/bootRTEMS";
*/
if ( server_name ) {
const size_t allocSize = strlen ( server_name ) + 2;
char * const pServerName = mustMalloc( allocSize,
char * const pServerName = mustMalloc( allocSize,
"NFS mount paths");
char * const pServerPath = mustMalloc ( allocSize,
char * const pServerPath = mustMalloc ( allocSize,
"NFS mount paths");
const int scanfStatus = sscanf (
server_name,
"%[^:] : / %s",
pServerName,
const int scanfStatus = sscanf (
server_name,
"%[^:] : / %s",
pServerName,
pServerPath + 1u );
if ( scanfStatus == 2 ) {
pServerPath[0u]= '/';
@ -535,7 +535,7 @@ exitHandler(void)
rtems_task
Init (rtems_task_argument ignored)
{
int i;
int result;
char *argv[3] = { NULL, NULL, NULL };
char *cp;
rtems_task_priority newpri;
@ -661,8 +661,8 @@ Init (rtems_task_argument ignored)
atexit(exitHandler);
errlogFlush();
printf ("***** Starting EPICS application *****\n");
i = main ((sizeof argv / sizeof argv[0]) - 1, argv);
result = main ((sizeof argv / sizeof argv[0]) - 1, argv);
printf ("***** IOC application terminating *****\n");
epicsThreadSleep(1.0);
epicsExit(0);
epicsExit(result);
}

View File

@ -68,7 +68,7 @@ INP{link} {
\n { line_num ++;}
. {
char message[20];
char message[40];
YY_BUFFER_STATE *dummy=0;
sprintf(message,"invalid character '%c'",yytext[0]);

View File

@ -10,3 +10,4 @@
SRC_DIRS += $(LIBCOM)/ellLib
INC += ellLib.h
Com_SRCS += ellLib.c
Com_SRCS += ellSort.c

View File

@ -56,6 +56,8 @@ epicsShareFunc void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode);
epicsShareFunc ELLNODE * ellNth (ELLLIST *pList, int nodeNum);
epicsShareFunc ELLNODE * ellNStep (ELLNODE *pNode, int nStep);
epicsShareFunc int ellFind (ELLLIST *pList, ELLNODE *pNode);
typedef int (*pListCmp)(const ELLNODE* A, const ELLNODE* B);
epicsShareFunc void ellSortStable(ELLLIST *pList, pListCmp);
epicsShareFunc void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc);
epicsShareFunc void ellVerify (ELLLIST *pList);

View File

@ -0,0 +1,83 @@
/*************************************************************************\
* Copyright (c) 2014 Brookhaven Science Assoc., as Operator of Argonne
* National Laboratory.
* 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.
\*************************************************************************/
/*
* Use of mergesort algorithm based on analysis by
* http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
*/
#include <stdlib.h>
#define epicsExportSharedSymbols
#include "epicsAssert.h"
#include "ellLib.h"
static void ellMoveN(ELLLIST* pTo, ELLLIST* pFrom, int count )
{
for(;count && ellCount(pFrom); count--) {
ELLNODE *node = ellGet(pFrom);
ellAdd(pTo, node);
}
}
/* Stable (MergeSort) to given list.
* The comparison function cmp(A,B) is expected
* to return -1 for A<B, 0 for A==B, and 1 for A>B.
*/
void ellSortStable(ELLLIST *pList, pListCmp cmp)
{
ELLLIST INP, P, Q;
size_t insize = 1; /* initial sub-list size */
if(ellCount(pList)<=1)
return;
ellInit(&INP);
ellInit(&P);
ellInit(&Q);
/* Process is to iteratively sort
* a sequence of sub-lists of size 'insize'
*/
while(insize < ellCount(pList)) {
assert(ellCount(&INP)==0);
/* shift previous results to inputs */
ellConcat(&INP, pList);
while(ellCount(&INP))
{
ELLNODE *p, *q;
/* Pull out the next pair of sub-lists */
ellMoveN(&Q, &INP, insize);
ellMoveN(&P, &INP, insize);
/* merge these sub-lists */
while((p=ellFirst(&P)) && (q=ellFirst(&Q)))
{
if((*cmp)(p,q) < 0) {
ellAdd(pList, ellGet(&P));
} else {
ellAdd(pList, ellGet(&Q));
}
}
/* concatenate any remaining to result */
if(ellFirst(&P))
ellConcat(pList, &P);
else if(ellFirst(&Q))
ellConcat(pList, &Q);
assert(!ellFirst(&P) && !ellFirst(&Q));
}
insize *= 2;
}
}

View File

@ -559,6 +559,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
if (macros) {
if (macParseDefns(NULL, macros, &defines) < 0) {
free(redirects);
return -1;
}
}
@ -571,6 +572,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
if (handle == NULL) {
if (macCreateHandle(&handle, pairs)) {
errlogMessage("iocsh: macCreateHandle failed.");
free(redirects);
return -1;
}

View File

@ -84,131 +84,132 @@ static int sighupPipe[2];
/*
*
* main()
* main()
*
*/
int main(void)
{
struct sockaddr_in serverAddr; /* server's address */
struct timeval timeout;
int status;
struct ioc_log_server *pserver;
struct sockaddr_in serverAddr; /* server's address */
struct timeval timeout;
int status;
struct ioc_log_server *pserver;
osiSockIoctl_t optval;
osiSockIoctl_t optval;
status = getConfig();
if(status<0){
fprintf(stderr, "iocLogServer: EPICS environment underspecified\n");
fprintf(stderr, "iocLogServer: failed to initialize\n");
return IOCLS_ERROR;
}
status = getConfig();
if (status<0) {
fprintf(stderr, "iocLogServer: EPICS environment underspecified\n");
fprintf(stderr, "iocLogServer: failed to initialize\n");
return IOCLS_ERROR;
}
pserver = (struct ioc_log_server *)
calloc(1, sizeof *pserver);
if(!pserver){
fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
return IOCLS_ERROR;
}
pserver = (struct ioc_log_server *)
calloc(1, sizeof *pserver);
if (!pserver) {
fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
return IOCLS_ERROR;
}
pserver->pfdctx = (void *) fdmgr_init();
if(!pserver->pfdctx){
fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
return IOCLS_ERROR;
}
pserver->pfdctx = (void *) fdmgr_init();
if (!pserver->pfdctx) {
fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
return IOCLS_ERROR;
}
/*
* Open the socket. Use ARPA Internet address format and stream
* sockets. Format described in <sys/socket.h>.
*/
pserver->sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
if (pserver->sock==INVALID_SOCKET) {
/*
* Open the socket. Use ARPA Internet address format and stream
* sockets. Format described in <sys/socket.h>.
*/
pserver->sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
if (pserver->sock == INVALID_SOCKET) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
fprintf(stderr, "iocLogServer: sock create err: %s\n", sockErrBuf);
return IOCLS_ERROR;
}
fprintf(stderr, "iocLogServer: sock create err: %s\n", sockErrBuf);
free(pserver);
return IOCLS_ERROR;
}
epicsSocketEnableAddressReuseDuringTimeWaitState ( pserver->sock );
/* Zero the sock_addr structure */
memset((void *)&serverAddr, 0, sizeof serverAddr);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(ioc_log_port);
/* Zero the sock_addr structure */
memset((void *)&serverAddr, 0, sizeof serverAddr);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(ioc_log_port);
/* get server's Internet address */
status = bind ( pserver->sock,
(struct sockaddr *)&serverAddr,
sizeof (serverAddr) );
if (status<0) {
/* get server's Internet address */
status = bind ( pserver->sock,
(struct sockaddr *)&serverAddr,
sizeof (serverAddr) );
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
fprintf(stderr, "iocLogServer: bind err: %s\n", sockErrBuf );
fprintf (stderr,
"iocLogServer: a server is already installed on port %u?\n",
(unsigned)ioc_log_port);
return IOCLS_ERROR;
}
fprintf(stderr, "iocLogServer: bind err: %s\n", sockErrBuf );
fprintf (stderr,
"iocLogServer: a server is already installed on port %u?\n",
(unsigned)ioc_log_port);
return IOCLS_ERROR;
}
/* listen and accept new connections */
status = listen(pserver->sock, 10);
if (status<0) {
/* listen and accept new connections */
status = listen(pserver->sock, 10);
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
fprintf(stderr, "iocLogServer: listen err %s\n", sockErrBuf);
return IOCLS_ERROR;
}
fprintf(stderr, "iocLogServer: listen err %s\n", sockErrBuf);
return IOCLS_ERROR;
}
/*
* Set non blocking IO
* to prevent dead locks
*/
optval = TRUE;
status = socket_ioctl(
pserver->sock,
FIONBIO,
&optval);
if(status<0){
/*
* Set non blocking IO
* to prevent dead locks
*/
optval = TRUE;
status = socket_ioctl(
pserver->sock,
FIONBIO,
&optval);
if (status < 0){
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
fprintf(stderr, "iocLogServer: ioctl FIONBIO err %s\n", sockErrBuf);
return IOCLS_ERROR;
}
fprintf(stderr, "iocLogServer: ioctl FIONBIO err %s\n", sockErrBuf);
return IOCLS_ERROR;
}
# ifdef UNIX
status = setupSIGHUP(pserver);
if (status<0) {
return IOCLS_ERROR;
}
# endif
# ifdef UNIX
status = setupSIGHUP(pserver);
if (status < 0) {
return IOCLS_ERROR;
}
# endif
status = openLogFile(pserver);
if (status<0) {
fprintf(stderr,
"File access problems to `%s' because `%s'\n",
ioc_log_file_name,
strerror(errno));
return IOCLS_ERROR;
}
status = openLogFile(pserver);
if (status < 0) {
fprintf(stderr,
"File access problems to `%s' because `%s'\n",
ioc_log_file_name,
strerror(errno));
return IOCLS_ERROR;
}
status = fdmgr_add_callback(
pserver->pfdctx,
pserver->sock,
fdi_read,
acceptNewClient,
pserver);
if(status<0){
fprintf(stderr,
"iocLogServer: failed to add read callback\n");
return IOCLS_ERROR;
}
status = fdmgr_add_callback(
pserver->pfdctx,
pserver->sock,
fdi_read,
acceptNewClient,
pserver);
if (status < 0) {
fprintf(stderr,
"iocLogServer: failed to add read callback\n");
return IOCLS_ERROR;
}
while(TRUE){
timeout.tv_sec = 60; /* 1 min */
timeout.tv_usec = 0;
fdmgr_pend_event(pserver->pfdctx, &timeout);
fflush(pserver->poutfile);
}
while (TRUE) {
timeout.tv_sec = 60; /* 1 min */
timeout.tv_usec = 0;
fdmgr_pend_event(pserver->pfdctx, &timeout);
fflush(pserver->poutfile);
}
}
/*
@ -964,6 +965,7 @@ static int getDirectory(void)
"Problem reading o/p from `%s' because `%s'\n",
ioc_log_file_command,
strerror(errno));
(void) pclose(pipe);
return IOCLS_ERROR;
}
(void) pclose(pipe);

View File

@ -256,6 +256,18 @@ int epicsStrPrintEscaped(FILE *fp, const char *s, size_t len)
return nout;
}
/* Until Base requires POSIX 2008 we must provide our own implementation */
size_t epicsStrnLen(const char *s, size_t maxlen)
{
size_t i;
for (i=0; i<maxlen; i++) {
if(s[i]=='\0')
return i;
}
return i;
}
int epicsStrGlobMatch(const char *str, const char *pattern)
{
const char *cp = NULL, *mp = NULL;

View File

@ -33,6 +33,7 @@ epicsShareFunc int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len);
epicsShareFunc char * epicsStrDup(const char *s);
epicsShareFunc int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n);
#define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw
epicsShareFunc size_t epicsStrnLen(const char *s, size_t maxlen);
epicsShareFunc int epicsStrGlobMatch(const char *str, const char *pattern);
epicsShareFunc char * epicsStrtok_r(char *s, const char *delim, char **lasts);
epicsShareFunc unsigned int epicsStrHash(const char *str, unsigned int seed);

View File

@ -380,7 +380,7 @@ static gtProvider * findProvider(ELLLIST *plist, epicsMutexId lock,
for (ptp = (gtProvider *)ellFirst(plist);
ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
if (ptp->priority == ptp->priority &&
if (ptp->priority == priority &&
!strcmp(ptp->name, name))
break;
}

View File

@ -6,15 +6,15 @@
* Copyright (c) 2007 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.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* epicsTime.cpp */
/* Author Jeffrey O. Hill */
// Notes:
// 1) The epicsTime::nSec field is not public and so it could be
// changed to work more like the fractional seconds field in the NTP time
// stamp. That would significantly improve the precision of epicsTime on
// 1) The epicsTime::nSec field is not public and so it could be
// changed to work more like the fractional seconds field in the NTP time
// stamp. That would significantly improve the precision of epicsTime on
// 64 bit architectures.
//
@ -26,7 +26,7 @@
#include <string.h>
#include <limits.h>
#include <float.h>
#include <string> // vxWorks 6.0 requires this include
#include <string> // vxWorks 6.0 requires this include
#define epicsExportSharedSymbols
#include "locationException.h"
@ -37,7 +37,7 @@
#include "osiSock.h" /* pull in struct timeval */
#include "epicsStdio.h"
static const char pEpicsTimeVersion[] =
static const char pEpicsTimeVersion[] =
"@(#) " EPICS_VERSION_STRING ", Common Utilities Library " __DATE__;
//
@ -60,11 +60,13 @@ static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
//
// epicsTime (const unsigned long secIn, const unsigned long nSecIn)
//
inline epicsTime::epicsTime (const unsigned long secIn,
const unsigned long nSecIn) :
secPastEpoch ( nSecIn / nSecPerSec + secIn ),
nSec ( nSecIn % nSecPerSec )
inline epicsTime::epicsTime (const unsigned long secIn, const unsigned long nSecIn) :
secPastEpoch ( secIn ), nSec ( nSecIn )
{
if (nSecIn >= nSecPerSec) {
this->secPastEpoch += nSecIn / nSecPerSec;
this->nSec = nSecIn % nSecPerSec;
}
}
//
@ -93,7 +95,7 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
* the ANSI epoch (1/1/1970 00:00:00UTC)
* Convert this offset into time_t units, however this must not be
* calculated using local time (i.e. using mktime() or similar), since
* in the UK the ANSI Epoch had daylight saving time in effect, and
* in the UK the ANSI Epoch had daylight saving time in effect, and
* the value calculated would be 3600 seconds wrong.*/
this->epicsEpochOffset =
(double) POSIX_TIME_AT_EPICS_EPOCH / this->time_tSecPerTick;
@ -103,7 +105,7 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
this->epicsEpochOffset >= 0) {
// We can use simpler code on Posix-compliant systems
this->useDiffTimeOptimization = true;
this->epicsEpochOffsetAsAnUnsignedLong =
this->epicsEpochOffsetAsAnUnsignedLong =
static_cast<unsigned long>(this->epicsEpochOffset);
} else {
// Forced to use the slower but correct code
@ -113,47 +115,26 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
}
//
// epicsTime::addNanoSec ()
// private epicsTime::addNanoSec ()
//
// The nano-second field of several of the the UNIX time stamp formats
// field is stored in the C type "long".
// Most formats keep the nSec value as an unsigned long, so are +ve.
// struct timeval's tv_usec may be -1, but I think that means error,
// so this private method never needs to handle -ve offsets.
//
void epicsTime :: addNanoSec ( long nSecAdj )
{
//
// After optimizing this function we now have a larger code which
// uses only unsigned integer, and not floating point, arithmetic.
// This change benefits embedded CPU's lacking a floating point
// co-processor at the expense of some additional code to maintain.
//
// We hope that all CPU's we run on provide at least an integer
// divide instruction which should enable this implementation
// to be more efficient than implementations based on branching;
// this is presuming that we will run on pipelined architectures.
//
// Overflow and underflow is expected; in the future we might
// operate close to, the modulo of, the EPICS epic.
//
// We are depending on the normalize operation in the private
// constructor used below.
//
// joh 11-04-2012
//
if ( nSecAdj >= 0 ) {
const unsigned long nSecPlus =
static_cast <unsigned long> ( nSecAdj );
const unsigned long nSecPlusAdj = nSecPlus % nSecPerSec;
const unsigned long secPlusAdj = nSecPlus / nSecPerSec;
*this = epicsTime ( this->secPastEpoch+secPlusAdj,
this->nSec+nSecPlusAdj );
if (nSecAdj <= 0)
return;
if (static_cast<unsigned long>(nSecAdj) >= nSecPerSec) {
this->secPastEpoch += nSecAdj / nSecPerSec;
nSecAdj %= nSecPerSec;
}
else {
const unsigned long nSecMinus =
static_cast <unsigned long> ( -nSecAdj );
const unsigned long nSecMinusAdj = nSecMinus % nSecPerSec;
const unsigned long secMinusAdj = nSecMinus / nSecPerSec;
*this = epicsTime ( this->secPastEpoch - secMinusAdj - 1u,
this->nSec + nSecPerSec - nSecMinusAdj );
this->nSec += nSecAdj; // Can't overflow
if (this->nSec >= nSecPerSec) {
this->secPastEpoch++;
this->nSec -= nSecPerSec;
}
}
@ -166,11 +147,11 @@ epicsTime::epicsTime ( const time_t_wrapper & ansiTimeTicks )
static epicsTimeLoadTimeInit & lti = * new epicsTimeLoadTimeInit ();
//
// try to directly map time_t into an unsigned long integer because this is
// try to directly map time_t into an unsigned long integer because this is
// faster on systems w/o hardware floating point and a simple integer type time_t.
//
if ( lti.useDiffTimeOptimization ) {
// LONG_MAX is used here and not ULONG_MAX because some systems (linux)
// LONG_MAX is used here and not ULONG_MAX because some systems (linux)
// still store time_t as a long.
if ( ansiTimeTicks.ts > 0 && ansiTimeTicks.ts <= LONG_MAX ) {
unsigned long ticks = static_cast < unsigned long > ( ansiTimeTicks.ts );
@ -186,8 +167,8 @@ epicsTime::epicsTime ( const time_t_wrapper & ansiTimeTicks )
}
//
// otherwise map time_t, which ANSI C and POSIX define as any arithmetic type,
// into type double
// otherwise map time_t, which ANSI C and POSIX define as any arithmetic type,
// into type double
//
double sec = ansiTimeTicks.ts * lti.time_tSecPerTick - lti.epicsEpochOffset;
@ -209,14 +190,14 @@ epicsTime::epicsTime ( const time_t_wrapper & ansiTimeTicks )
this->nSec = static_cast <unsigned long> ( ( sec-this->secPastEpoch ) * nSecPerSec );
}
epicsTime::epicsTime (const epicsTimeStamp &ts)
epicsTime::epicsTime (const epicsTimeStamp &ts)
{
if ( ts.nsec < nSecPerSec ) {
this->secPastEpoch = ts.secPastEpoch;
this->nSec = ts.nsec;
}
else {
throw std::logic_error (
throw std::logic_error (
"epicsTimeStamp has overflow in nano-seconds field" );
}
}
@ -262,7 +243,7 @@ epicsTime::operator time_t_wrapper () const
return wrap;
}
}
//
// map type double into time_t which ansi C defines as some arithmetic type
//
@ -317,20 +298,82 @@ epicsTime::operator gm_tm_nano_sec () const
//
epicsTime::epicsTime (const local_tm_nano_sec &tm)
{
static const time_t mktimeFailure = static_cast <time_t> (-1);
time_t_wrapper ansiTimeTicks;
struct tm tmp = tm.ansi_tm;
time_t_wrapper ansiTimeTicks = { mktime (&tmp) };
ansiTimeTicks.ts = mktime (&tmp);
if (ansiTimeTicks.ts == mktimeFailure) {
static const time_t mktimeError = static_cast <time_t> (-1);
if (ansiTimeTicks.ts == mktimeError) {
throwWithLocation ( formatProblemWithStructTM () );
}
*this = epicsTime (ansiTimeTicks);
*this = epicsTime(ansiTimeTicks);
this->addNanoSec(tm.nSec);
}
unsigned long nSecAdj = tm.nSec % nSecPerSec;
unsigned long secAdj = tm.nSec / nSecPerSec;
*this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj );
//
// epicsTime (const gm_tm_nano_sec &tm)
//
// do conversion avoiding the timezone mechanism
static inline int is_leap(int year)
{
if (year % 400 == 0)
return 1;
if (year % 100 == 0)
return 0;
if (year % 4 == 0)
return 1;
return 0;
}
static inline int days_from_0(int year)
{
year--;
return 365 * year + (year / 400) - (year / 100) + (year / 4);
}
static inline int days_from_1970(int year)
{
static const int days_from_0_to_1970 = days_from_0(1970);
return days_from_0(year) - days_from_0_to_1970;
}
static inline int days_from_1jan(int year, int month, int day)
{
static const int days[2][12] =
{
{ 0,31,59,90,120,151,181,212,243,273,304,334},
{ 0,31,60,91,121,152,182,213,244,274,305,335}
};
return days[is_leap(year)][month-1] + day - 1;
}
epicsTime::epicsTime (const gm_tm_nano_sec &tm)
{
int year = tm.ansi_tm.tm_year + 1900;
int month = tm.ansi_tm.tm_mon;
if (month > 11) {
year += month / 12;
month %= 12;
} else if (month < 0) {
int years_diff = (-month + 11) / 12;
year -= years_diff;
month += 12 * years_diff;
}
month++;
int day = tm.ansi_tm.tm_mday;
int day_of_year = days_from_1jan(year, month, day);
int days_since_epoch = days_from_1970(year) + day_of_year;
time_t_wrapper ansiTimeTicks;
ansiTimeTicks.ts = ((days_since_epoch
* 24 + tm.ansi_tm.tm_hour)
* 60 + tm.ansi_tm.tm_min)
* 60 + tm.ansi_tm.tm_sec;
*this = epicsTime(ansiTimeTicks);
this->addNanoSec(tm.nSec);
}
//
@ -372,9 +415,9 @@ epicsTime::operator struct timeval () const
// a direct assignment. On other systems I dont know that we can
// guarantee that time_t and timeval :: tv_sec will have the
// same epoch or have the same scaling factor to discrete seconds.
// For example, on windows time_t changed recently to a 64 bit
// For example, on windows time_t changed recently to a 64 bit
// quantity but timeval is still a long. That can cause problems
// on 32 bit systems. So technically, we should have an os
// on 32 bit systems. So technically, we should have an os
// dependent conversion between time_t and timeval :: tv_sec?
ts.tv_sec = ansiTimeTicks.ts;
ts.tv_usec = static_cast < long > ( this->nSec / nSecPerUSec );
@ -391,9 +434,9 @@ epicsTime::epicsTime (const struct timeval &ts)
// a direct assignment. On other systems I dont know that we can
// guarantee that time_t and timeval :: tv_sec will have the
// same epoch or have the same scaling factor to discrete seconds.
// For example, on windows time_t changed recently to a 64 bit
// For example, on windows time_t changed recently to a 64 bit
// quantity but timeval is still a long. That can cause problems
// on 32 bit systems. So technically, we should have an os
// on 32 bit systems. So technically, we should have an os
// dependent conversion between time_t and timeval :: tv_sec?
ansiTimeTicks.ts = ts.tv_sec;
*this = epicsTime (ansiTimeTicks);
@ -415,7 +458,7 @@ epicsTime::operator l_fp () const
{
l_fp ts;
ts.l_ui = this->secPastEpoch + NTP_TIME_AT_EPICS_EPOCH;
ts.l_uf = static_cast < unsigned long >
ts.l_uf = static_cast < unsigned long >
( ( this->nSec * NTP_FRACTION_DENOMINATOR ) / nSecPerSec );
return ts;
}
@ -426,14 +469,14 @@ epicsTime::operator l_fp () const
epicsTime::epicsTime ( const l_fp & ts )
{
this->secPastEpoch = ts.l_ui - NTP_TIME_AT_EPICS_EPOCH;
this->nSec = static_cast < unsigned long >
this->nSec = static_cast < unsigned long >
( ( ts.l_uf / NTP_FRACTION_DENOMINATOR ) * nSecPerSec );
}
epicsTime::operator epicsTimeStamp () const
{
if ( this->nSec >= nSecPerSec ) {
throw std::logic_error (
throw std::logic_error (
"epicsTimeStamp has overflow in nano-seconds field?" );
}
epicsTimeStamp ts;
@ -444,7 +487,7 @@ epicsTime::operator epicsTimeStamp () const
// on 64 bit hosts than the original epicsTimeStamp::secPastEpoch. The
// epicsTimeStamp::secPastEpoch is based on epicsUInt32 so that it will
// match the original network protocol. Of course one can anticipate
// that eventually, a epicsUInt64 based network time stamp will be
// that eventually, a epicsUInt64 based network time stamp will be
// introduced when 64 bit architectures are more ubiquitous.
//
// Truncation usually works fine here because the routines in this code
@ -458,14 +501,14 @@ epicsTime::operator epicsTimeStamp () const
return ts;
}
// Break up a format string into "<strftime prefix>%0<nnn>f<postfix>"
// (where <nnn> in an unsigned integer)
// Break up a format string into "<strftime prefix>%0<nnn>f<postfix>"
// (where <nnn> in an unsigned integer)
// Result:
// A) Copies a prefix which is valid for ANSI strftime into the supplied
// buffer setting the buffer to an empty string if no prefix is present.
// B) Indicates whether a valid "%0<n>f]" is present or not and if so
// B) Indicates whether a valid "%0<n>f]" is present or not and if so
// specifying its nnnn
// C) returning a pointer to the postfix (which might be passed again
// C) returning a pointer to the postfix (which might be passed again
// to fracFormatFind.
static const char * fracFormatFind (
const char * const pFormat,
@ -529,8 +572,8 @@ static const char * fracFormatFind (
//
// size_t epicsTime::strftime ()
//
size_t epicsTime::strftime (
char * pBuff, size_t bufLength, const char * pFormat ) const
size_t epicsTime::strftime (
char * pBuff, size_t bufLength, const char * pFormat ) const
{
if ( bufLength == 0u ) {
return 0u;
@ -547,15 +590,15 @@ size_t epicsTime::strftime (
const char * pFmt = pFormat;
size_t bufLenLeft = bufLength;
while ( *pFmt != '\0' && bufLenLeft > 1 ) {
// look for "%0<n>f" at the end (used for fractional second formatting)
// look for "%0<n>f" at the end (used for fractional second formatting)
char strftimePrefixBuf [256];
bool fracFmtFound;
unsigned long fracWid = 0;
pFmt = fracFormatFind (
pFmt,
pFmt,
strftimePrefixBuf, sizeof ( strftimePrefixBuf ),
fracFmtFound, fracWid );
// nothing more in the string, then quit
if ( ! ( strftimePrefixBuf[0] != '\0' || fracFmtFound ) ) {
break;
@ -657,7 +700,7 @@ void epicsTime::show ( unsigned level ) const
if ( level > 1 ) {
// this also suppresses the "defined, but not used"
// warning message
printf ( "epicsTime: revision \"%s\"\n",
printf ( "epicsTime: revision \"%s\"\n",
pEpicsTimeVersion );
}
@ -704,10 +747,10 @@ epicsTime epicsTime::operator + (const double &rhs) const
}
//
// operator -
// operator -
//
// To make this code robust during timestamp rollover events
// time stamp differences greater than one half full scale are
// time stamp differences greater than one half full scale are
// interpreted as rollover situations:
//
// when RHS is greater than THIS:
@ -729,7 +772,7 @@ double epicsTime::operator - (const epicsTime &rhs) const
// so the unsigned to signed conversion is ok
//
if (this->nSec>=rhs.nSec) {
nSecRes = this->nSec - rhs.nSec;
nSecRes = this->nSec - rhs.nSec;
}
else {
nSecRes = rhs.nSec - this->nSec;
@ -746,7 +789,7 @@ double epicsTime::operator - (const epicsTime &rhs) const
if (secRes > ULONG_MAX/2) {
//
// In this situation where the difference is more than
// 68 years assume that the seconds counter has rolled
// 68 years assume that the seconds counter has rolled
// over and compute the "wrap around" difference
//
secRes = 1 + (ULONG_MAX-secRes);
@ -761,7 +804,7 @@ double epicsTime::operator - (const epicsTime &rhs) const
if (secRes > ULONG_MAX/2) {
//
// In this situation where the difference is more than
// 68 years assume that the seconds counter has rolled
// 68 years assume that the seconds counter has rolled
// over and compute the "wrap around" difference
//
secRes = 1 + (ULONG_MAX-secRes);
@ -770,7 +813,7 @@ double epicsTime::operator - (const epicsTime &rhs) const
}
}
return secRes + nSecRes/nSecPerSec;
return secRes + nSecRes/nSecPerSec;
}
//
@ -791,7 +834,7 @@ bool epicsTime::operator <= (const epicsTime &rhs) const
else {
//
// In this situation where the difference is more than
// 69 years assume that the seconds counter has rolled
// 69 years assume that the seconds counter has rolled
// over and compute the "wrap around" result
//
rc = false;
@ -808,7 +851,7 @@ bool epicsTime::operator <= (const epicsTime &rhs) const
else {
//
// In this situation where the difference is more than
// 69 years assume that the seconds counter has rolled
// 69 years assume that the seconds counter has rolled
// over and compute the "wrap around" result
//
rc = true;
@ -843,7 +886,7 @@ bool epicsTime::operator < (const epicsTime &rhs) const
else {
//
// In this situation where the difference is more than
// 69 years assume that the seconds counter has rolled
// 69 years assume that the seconds counter has rolled
// over and compute the "wrap around" result
//
rc = false;
@ -860,7 +903,7 @@ bool epicsTime::operator < (const epicsTime &rhs) const
else {
//
// In this situation where the difference is more than
// 69 years assume that the seconds counter has rolled
// 69 years assume that the seconds counter has rolled
// over and compute the "wrap around" result
//
rc = true;
@ -881,7 +924,7 @@ extern "C" {
//
// ANSI C interface
//
// its too bad that these cant be implemented with inline functions
// its too bad that these cant be implemented with inline functions
// at least when running the GNU compiler
//
epicsShareFunc int epicsShareAPI epicsTimeToTime_t (time_t *pDest, const epicsTimeStamp *pSrc)
@ -944,6 +987,19 @@ extern "C" {
}
return epicsTimeOK;
}
epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
{
try {
gm_tm_nano_sec tmns;
tmns.ansi_tm = *pSrc;
tmns.nSec = nSecSrc;
*pDest = epicsTime (tmns);
}
catch (...) {
return S_time_conversion;
}
return epicsTimeOK;
}
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc)
{
try {
@ -1075,4 +1131,3 @@ extern "C" {
}
}
}

View File

@ -106,10 +106,12 @@ public:
epicsTime & operator = ( const local_tm_nano_sec & );
/*
* convert to ANSI Cs "struct tm" (with nano seconds)
* convert to and from ANSI Cs "struct tm" (with nano seconds)
* adjusted for GM time (UTC)
*/
operator gm_tm_nano_sec () const;
epicsTime ( const gm_tm_nano_sec & );
epicsTime & operator = ( const gm_tm_nano_sec & );
/* convert to and from POSIX RTs "struct timespec" */
operator struct timespec () const;
@ -201,13 +203,15 @@ epicsShareFunc int epicsShareAPI epicsTimeToTime_t (
epicsShareFunc int epicsShareAPI epicsTimeFromTime_t (
epicsTimeStamp * pDest, time_t src );
/*convert to and from ANSI C's "struct tm" with nano seconds */
/* convert to and from ANSI C's "struct tm" with nano seconds */
epicsShareFunc int epicsShareAPI epicsTimeToTM (
struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc );
epicsShareFunc int epicsShareAPI epicsTimeToGMTM (
struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc );
epicsShareFunc int epicsShareAPI epicsTimeFromTM (
epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc );
epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (
epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc );
/* convert to and from POSIX RT's "struct timespec" */
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (
@ -319,6 +323,11 @@ inline epicsTime & epicsTime::operator = ( const local_tm_nano_sec & rhs )
return *this = epicsTime ( rhs );
}
inline epicsTime & epicsTime::operator = ( const gm_tm_nano_sec & rhs )
{
return *this = epicsTime ( rhs );
}
inline epicsTime & epicsTime::operator = ( const struct timespec & rhs )
{
*this = epicsTime ( rhs );

View File

@ -1,7 +1,7 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Eric Norum
@ -38,6 +38,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@ -42,6 +42,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
@ -72,4 +73,3 @@ typedef socklen_t osiSocklen_t;
#define ifreq_size(pifreq) (sizeof(pifreq->ifr_name))
#endif /*osdSockH*/

View File

@ -171,7 +171,7 @@ static int receiveMessage(
return -1;
}
rsize = receiveMessage(id, id->localBuf, id->maxSize, wait, delay);
if ((rsize < 0) || (rsize > size))
if (rsize > size)
return -1;
memcpy(buffer, id->localBuf, rsize);
}

View File

@ -1,7 +1,7 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS osdSock.h
@ -35,7 +35,7 @@ int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, str
#ifdef __cplusplus
}
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define SOCKERRNO errno
@ -49,6 +49,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
@ -75,7 +76,7 @@ typedef socklen_t osiSocklen_t;
#ifndef INADDR_NONE
# define INADDR_NONE (0xffffffff)
#endif
#endif
/*
* For shutdown()

View File

@ -427,8 +427,6 @@ void epicsThreadGetName (epicsThreadId id, char *name, size_t size)
struct taskVar *v;
int haveName = 0;
if (size <= 0)
return;
taskVarLock ();
for (v=taskVarHead ; v != NULL ; v=v->forw) {
if (v->id == tid) {
@ -690,6 +688,7 @@ void epicsThreadShow (epicsThreadId id, unsigned int level)
for (v = taskVarHead ; v != NULL ; v = v->forw) {
if ((rtems_id)id == v->id) {
epicsThreadShowInfo (v, level);
taskVarUnlock ();
return;
}
}

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef osdSockH
@ -14,7 +14,7 @@
#include <errno.h>
/*
* winsock2.h changes the structure alignment to 4 if
* winsock2.h changes the structure alignment to 4 if
* WIN32 isnt set which can be a source of confusion
*/
#ifndef WIN32
@ -48,6 +48,7 @@ typedef int osiSocklen_t;
#define SOCK_ENOBUFS WSAENOBUFS
#define SOCK_ECONNRESET WSAECONNRESET
#define SOCK_ETIMEDOUT WSAETIMEDOUT
#define SOCK_EACCES WSAEACCES
#define SOCK_EADDRINUSE WSAEADDRINUSE
#define SOCK_EADDRNOTAVAIL WSAEADDRNOTAVAIL
#define SOCK_ECONNREFUSED WSAECONNREFUSED

View File

@ -523,13 +523,8 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName )
pParmWIN32 = calloc ( 1, sizeof ( *pParmWIN32 ) + strlen ( pName ) + 1 );
if ( pParmWIN32 ) {
if ( pName ) {
pParmWIN32->pName = (char *) ( pParmWIN32 + 1 );
strcpy ( pParmWIN32->pName, pName );
}
else {
pParmWIN32->pName = 0;
}
pParmWIN32->pName = (char *) ( pParmWIN32 + 1 );
strcpy ( pParmWIN32->pName, pName );
pParmWIN32->isSuspended = 0;
}
return pParmWIN32;

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* cygwin32 specific include
@ -49,6 +49,7 @@ typedef int osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
@ -67,4 +68,3 @@ typedef int osiSocklen_t;
#define ifreq_size(pifreq) (sizeof(pifreq->ifr_name))
#endif /*osdSockH*/

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef osdSockH
@ -29,7 +29,7 @@
#define IPPORT_USERRESERVED 5000
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define SOCKERRNO errno
@ -43,6 +43,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
@ -77,4 +78,3 @@ typedef socklen_t osiSocklen_t;
#endif
#endif /*osdSockH*/

View File

@ -39,6 +39,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@ -39,7 +39,7 @@ typedef int osiSockIoctl_t;
#if SOLARIS > 6 || defined ( _SOCKLEN_T )
typedef uint32_t osiSocklen_t;
#else
#else
typedef int osiSocklen_t;
#endif
@ -51,6 +51,7 @@ typedef int osiSockIoctl_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
@ -80,9 +81,8 @@ typedef int osiSockIoctl_t;
#ifndef INADDR_NONE
# define INADDR_NONE (0xffffffff)
#endif
#endif
#define ifreq_size(pifreq) (sizeof(pifreq->ifr_name))
#endif /*osdSockH*/

View File

@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* vxWorks specific socket include
@ -44,7 +44,7 @@ int sysClkRateGet(void);
#ifdef __cplusplus
}
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define SOCKERRNO errno
@ -72,6 +72,7 @@ typedef int osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
@ -93,7 +94,7 @@ typedef int osiSocklen_t;
#ifndef INADDR_NONE
# define INADDR_NONE (0xffffffff)
#endif
#endif
#if defined(_SIZEOF_ADDR_IFREQ)
# define ifreq_size(pifreq) _SIZEOF_ADDR_IFREQ(*pifreq)
@ -104,5 +105,3 @@ typedef int osiSocklen_t;
#endif
#endif /*osdSockH*/

View File

@ -1,4 +1,5 @@
/*************************************************************************\
* Copyright (c) 2016 Michael Davidsaver
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
@ -11,6 +12,7 @@
#include <stdlib.h>
#include "ellLib.h"
#include "dbDefs.h"
#include "epicsUnitTest.h"
#include "testMain.h"
@ -20,15 +22,13 @@ struct myItem {
int num;
};
MAIN(epicsEllTest)
static void testList(void)
{
ELLLIST list1;
ELLLIST list2 = ELLLIST_INIT;
int i1 = 1;
struct myItem *pitem, *pfirst, *pick;
testPlan(70);
list1.count = 27;
list1.node.next = (ELLNODE *) 0x01010101;
list1.node.previous = (ELLNODE *) 0x10101010;
@ -192,6 +192,77 @@ MAIN(epicsEllTest)
ellFree2(&list1, free);
testOk1(ellCount(&list1) == 0);
}
typedef struct { int A, B; } input_t;
static int myItemCmp(const ELLNODE *a, const ELLNODE *b)
{
struct myItem *A = CONTAINER(a, struct myItem, node),
*B = CONTAINER(b, struct myItem, node);
if (A->num < B->num) return -1;
else if(A->num > B->num) return 1;
else if(A->list < B->list) return -1;
else if(A->list > B->list) return 1;
else return 0;
}
static const input_t input[] = {
{-4, 0},
{-5, 0},
{0,0},
{50,0},
{0,1},
{5,0},
{5,1}
};
static
void testSort(const input_t *inp, size_t ninp)
{
unsigned i;
ELLLIST list = ELLLIST_INIT;
struct myItem *alloc = calloc(ninp, sizeof(*alloc));
if(!alloc) testAbort("testSort allocation fails");
for(i=0; i<ninp; i++) {
struct myItem *it = &alloc[i];
it->num = inp[i].A;
it->list= inp[i].B;
ellAdd(&list, &it->node);
}
ellSortStable(&list, &myItemCmp);
testOk(ellCount(&list)==ninp, "output length %u == %u", (unsigned)ellCount(&list), (unsigned)ninp);
if(ellCount(&list)==0) {
testSkip(ninp-1, "all items lost");
}
{
struct myItem *prev = CONTAINER(ellFirst(&list), struct myItem, node),
*next;
for(next = CONTAINER(ellNext(&prev->node), struct myItem, node);
next;
prev = next, next = CONTAINER(ellNext(&next->node), struct myItem, node))
{
int cond = (prev->num<next->num) || (prev->num==next->num && prev->list<next->list);
testOk(cond, "%d:%d < %d:%d", prev->num, prev->list, next->num, next->list);
}
}
}
MAIN(epicsEllTest)
{
testPlan(77);
testList();
testSort(input, NELEMENTS(input));
return testDone();
}

View File

@ -250,5 +250,12 @@ MAIN(epicsEventTest)
eventWaitTest();
eventWakeupTest();
free(name);
free(id);
epicsRingPointerDelete(pinfo->ring);
epicsMutexDestroy(pinfo->lockRing);
epicsEventDestroy(event);
free(pinfo);
return testDone();
}

View File

@ -279,5 +279,11 @@ MAIN(epicsMutexTest)
epicsMutexPerformance ();
free(pinfo);
free(arg);
free(name);
free(id);
epicsMutexDestroy(mutex);
return testDone();
}

View File

@ -37,7 +37,14 @@ static void testEpicsSnprintf(void) {
const char *expected = exbuffer;
int size;
int rtn, rlen;
#ifdef _WIN32
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
(defined(_MINGW) && defined(_TWO_DIGIT_EXPONENT))
_set_output_format(_TWO_DIGIT_EXPONENT);
#endif
#endif
sprintf(exbuffer, format, ivalue, fvalue, svalue);
rlen = strlen(expected)+1;
@ -121,11 +128,7 @@ void testStdoutRedir (const char *report)
MAIN(epicsStdioTest)
{
#ifdef _WIN32
testPlan(166);
#else
testPlan(163);
#endif
testEpicsSnprintf();
#ifdef __rtems__
/* ensure there is a writeable area */

View File

@ -87,7 +87,7 @@ MAIN(epicsStringTest)
char *s;
int status;
testPlan(402);
testPlan(406);
testChars();
@ -122,6 +122,11 @@ MAIN(epicsStringTest)
testOk1(epicsStrHash(abcd, 0) == epicsMemHash(abcde, 4, 0));
testOk1(epicsStrHash(abcd, 0) != epicsMemHash("abcd\0", 5, 0));
testOk1(epicsStrnLen("abcd", 5)==4);
testOk1(epicsStrnLen("abcd", 4)==4);
testOk1(epicsStrnLen("abcd", 3)==3);
testOk1(epicsStrnLen("abcd", 0)==0);
testGlob();
memset(result, 'x', sizeof(result));

View File

@ -43,7 +43,7 @@ MAIN(epicsTimeTest)
const int wasteTime = 100000;
const int nTimes = 10;
testPlan(15 + nTimes * 18);
testPlan(15 + nTimes * 19);
try {
const epicsTimeStamp epochTS = {0, 0};
@ -200,6 +200,11 @@ MAIN(epicsTimeTest)
epicsTime beginANSI = ansiDate;
testOk1(beginANSI + diff == now);
// test struct gmtm round-trip conversion
gm_tm_nano_sec ansiGmDate = begin;
epicsTime beginGMANSI = ansiGmDate;
testOk1(beginGMANSI + diff == now);
// test struct timespec round-trip conversion
struct timespec ts = begin;
epicsTime beginTS = ts;

View File

@ -115,5 +115,9 @@ MAIN(ringBytesTest)
testOk(n==1, "ring get %d", 1);
check(ring, RINGSIZE);
epicsRingBytesDelete(ring);
epicsEventDestroy(consumerEvent);
free(pinfo);
return testDone();
}

View File

@ -36,12 +36,14 @@ recordtype(fanout) {
}
field(OFFS,DBF_SHORT) {
prompt("Offset for Specified")
interest(1)
promptgroup("30 - Action")
interest(1)
initial("0")
}
field(SHFT,DBF_SHORT) {
prompt("Shift for Mask mode")
interest(1)
promptgroup("30 - Action")
interest(1)
initial("-1")
}
field(LNK0,DBF_FWDLINK) {

View File

@ -36,11 +36,13 @@ recordtype(seq) {
}
field(OFFS,DBF_SHORT) {
prompt("Offset for Specified")
promptgroup("30 - Action")
interest(1)
initial("0")
}
field(SHFT,DBF_SHORT) {
prompt("Shift for Mask mode")
promptgroup("30 - Action")
interest(1)
initial("-1")
}

View File

@ -109,6 +109,7 @@ int main(int argc,char **argv)
pmynode[npv] = callocMustSucceed(1, sizeof(MYNODE), "caMonitor");
npv++;
}
fclose(fp);
SEVCHK(ca_context_create(ca_disable_preemptive_callback),"ca_context_create");
SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
"ca_add_exception_event");

View File

@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
@ -30,23 +29,23 @@ exAsyncPV::exAsyncPV ( exServer & cas, pvInfo & setup,
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncReadIO *pIO;
if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
return S_casApp_postponeAsyncIO;
}
exAsyncReadIO *pIO;
pIO = new exAsyncReadIO ( this->cas, ctx,
*this, valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
return S_casApp_postponeAsyncIO;
}
pIO = new exAsyncReadIO ( this->cas, ctx,
*this, valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
return S_casApp_noMemory;
}
}
this->simultAsychReadIOCount++;
}
this->simultAsychReadIOCount++;
return S_casApp_asyncCompletion;
}
@ -54,24 +53,24 @@ caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
// exAsyncPV::writeNotify()
//
caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
{
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
return S_casApp_postponeAsyncIO;
}
{
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
return S_casApp_postponeAsyncIO;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
return S_casApp_noMemory;
}
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
//
@ -79,24 +78,24 @@ caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
// implement the discard intermediate values, but last value
// implement the discard intermediate values, but last value
// sent always applied behavior that IOCs provide excepting
// that we will alow N requests to pend instead of a limit
// of only one imposed in the IOC
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
return S_casApp_success;
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
// Implementing a specialized update for exAsyncPV
@ -150,7 +149,7 @@ void exAsyncPV::removeWriteIO ()
exAsyncWriteIO::exAsyncWriteIO ( exServer & cas,
const casCtx & ctxIn, exAsyncPV & pvIn,
const gdd & valueIn, double asyncDelay ) :
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer () ), pValue(valueIn)
{
this->timer.start ( *this, asyncDelay );
@ -168,7 +167,7 @@ exAsyncWriteIO::~exAsyncWriteIO()
if ( this->pValue.valid () ) {
this->pv.updateFromAsyncWrite ( *this->pValue );
}
this->pv.removeWriteIO();
this->pv.removeWriteIO();
}
//
@ -179,9 +178,9 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::
expire ( const epicsTime & /* currentTime */ )
{
assert ( this->pValue.valid () );
caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
this->pValue.set ( 0 );
this->postIOCompletion ( status );
caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
this->pValue.set ( 0 );
this->postIOCompletion ( status );
return noRestart;
}
@ -191,7 +190,7 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::
exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
exAsyncPV & pvIn, gdd & protoIn,
double asyncDelay ) :
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer() ), pProto ( protoIn )
{
this->timer.start ( *this, asyncDelay );
@ -202,7 +201,7 @@ exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
//
exAsyncReadIO::~exAsyncReadIO()
{
this->pv.removeReadIO ();
this->pv.removeReadIO ();
this->timer.destroy ();
}
@ -213,16 +212,16 @@ exAsyncReadIO::~exAsyncReadIO()
epicsTimerNotify::expireStatus
exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
{
//
// map between the prototype in and the
// current value
//
caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
//
// map between the prototype in and the
// current value
//
caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
//
// post IO completion
//
this->postIOCompletion ( status, *this->pProto );
//
// post IO completion
//
this->postIOCompletion ( status, *this->pProto );
return noRestart;
}

View File

@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
@ -42,7 +41,7 @@ exPV::exPV ( exServer & casIn, pvInfo & setup,
//
// no dataless PV allowed
//
assert (this->info.getElementCount()>=1u);
assert (this->info.getCapacity()>=1u);
//
// start a very slow background scan

View File

@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// fileDescriptorManager.process(delay);
@ -304,7 +303,7 @@ exPV *pvInfo::createPV ( exServer & cas, bool preCreateFlag,
// depending on the io type and the number
// of elements
//
if (this->elementCount==1u) {
if (this->capacity==1u) {
switch (this->ioType){
case excasIoSync:
pNewPV = new exScalarPV ( cas, *this, preCreateFlag, scanOn );

View File

@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
@ -76,8 +75,10 @@ public:
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
unsigned getElementCount () const;
void unlinkPV ();
unsigned getCapacity () const;
unsigned getElementCount () const;
void setElementCount (unsigned);
void unlinkPV ();
exPV *createPV ( exServer & exCAS, bool preCreateFlag,
bool scanOn, double asyncDelay );
void deletePV ();
@ -88,7 +89,8 @@ private:
const double lopr;
aitEnum type;
const excasIoType ioType;
const unsigned elementCount;
const unsigned capacity;
unsigned elementCount;
exPV * pPV;
pvInfo & operator = ( const pvInfo & );
};
@ -441,8 +443,8 @@ inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn,
scanPeriod ( scanPeriodIn ), pName ( pNameIn ),
hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ),
ioType ( ioTypeIn ), elementCount ( countIn ),
pPV ( 0 )
ioType ( ioTypeIn ), capacity ( countIn ),
elementCount ( 0 ), pPV ( 0 )
{
}
@ -454,8 +456,8 @@ inline pvInfo::pvInfo ( const pvInfo & copyIn ) :
scanPeriod ( copyIn.scanPeriod ), pName ( copyIn.pName ),
hopr ( copyIn.hopr ), lopr ( copyIn.lopr ), type ( copyIn.type ),
ioType ( copyIn.ioType ), elementCount ( copyIn.elementCount ),
pPV ( copyIn.pPV )
ioType ( copyIn.ioType ), capacity ( copyIn.capacity ),
elementCount ( copyIn.elementCount ), pPV ( copyIn.pPV )
{
}
@ -509,12 +511,22 @@ inline excasIoType pvInfo::getIOType () const
return this->ioType;
}
inline unsigned pvInfo::getElementCount () const
{
return this->elementCount;
inline unsigned pvInfo::getCapacity () const
{
return this->capacity;
}
inline void pvInfo::unlinkPV ()
inline unsigned pvInfo::getElementCount () const
{
return this->elementCount;
}
inline void pvInfo::setElementCount (unsigned newCount)
{
this->elementCount = newCount;
}
inline void pvInfo::unlinkPV ()
{
this->pPV = NULL;
}

View File

@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "exServer.h"
@ -48,7 +47,7 @@ unsigned exVectorPV::maxDimension() const
aitIndex exVectorPV::maxBound (unsigned dimension) const
{
if (dimension==0u) {
return this->info.getElementCount();
return this->info.getCapacity();
}
else {
return 0u;
@ -60,45 +59,40 @@ aitIndex exVectorPV::maxBound (unsigned dimension) const
//
void exVectorPV::scan()
{
caStatus status;
double radians;
smartGDDPointer pDD;
aitFloat32 *pF, *pFE;
const aitFloat32 *pCF;
float newValue;
float limit;
exVecDestructor *pDest;
int gddStatus;
static epicsTime startTime = epicsTime::getCurrent();
//
// update current time (so we are not required to do
// this every time that we write the PV which impacts
// throughput under sunos4 because gettimeofday() is
// slow)
// update current time
//
this->currentTime = epicsTime::getCurrent();
pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
1u, this->info.getElementCount());
// demonstrate a changing array size
unsigned ramp = 15 & (unsigned) (this->currentTime - startTime);
unsigned newSize = this->info.getCapacity();
if (newSize > ramp) {
newSize -= ramp;
}
smartGDDPointer pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
1u, newSize);
if ( ! pDD.valid () ) {
return;
}
//
// smart pointer class manages reference count after this point
//
gddStatus = pDD->unreference();
assert (!gddStatus);
gddStatus gdds = pDD->unreference();
assert(!gdds);
//
// allocate array buffer
//
pF = new aitFloat32 [this->info.getElementCount()];
aitFloat64 * pF = new aitFloat64 [newSize];
if (!pF) {
return;
}
pDest = new exVecDestructor;
exVecDestructor * pDest = new exVecDestructor;
if (!pDest) {
delete [] pF;
return;
@ -114,37 +108,39 @@ void exVectorPV::scan()
// double check for reasonable bounds on the
// current value
//
pCF=NULL;
if ( this->pValue.valid () ) {
if (this->pValue->dimension()==1u) {
const gddBounds *pB = this->pValue->getBounds();
if (pB[0u].size()==this->info.getElementCount()) {
pCF = *this->pValue;
}
}
const aitFloat64 *pCF = NULL, *pCFE = NULL;
if (this->pValue.valid () &&
this->pValue->dimension() == 1u) {
const gddBounds *pB = this->pValue->getBounds();
pCF = *this->pValue;
pCFE = &pCF[pB->size()];
}
pFE = &pF[this->info.getElementCount()];
while (pF<pFE) {
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (pCF) {
aitFloat64 * pFE = &pF[newSize];
while (pF < pFE) {
double radians = (rand () * 2.0 * myPI)/RAND_MAX;
double newValue;
if (pCF && pCF < pCFE) {
newValue = *pCF++;
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue += (sin (radians) / 10.0);
double limit = this->info.getHopr();
newValue = epicsMin (newValue, limit);
limit = (float) this->info.getLopr();
limit = this->info.getLopr();
newValue = epicsMax (newValue, limit);
*(pF++) = newValue;
*pF++ = newValue;
}
aitTimeStamp gddts = this->currentTime;
pDD->setTimeStamp ( & gddts );
status = this->update ( *pDD );
caStatus status = this->update ( *pDD );
this->info.setElementCount(newSize);
if ( status != S_casApp_success ) {
errMessage (status, "vector scan update failed\n");
}
@ -166,7 +162,7 @@ void exVectorPV::scan()
//
caStatus exVectorPV::updateValue ( const gdd & value )
{
aitUint32 newSize = 0;
//
// Check bounds of incoming request
// (and see if we are replacing all elements -
@ -183,7 +179,9 @@ caStatus exVectorPV::updateValue ( const gdd & value )
if ( pb[0u].first() != 0u ) {
return S_casApp_outOfBounds;
}
else if ( pb[0u].size() > this->info.getElementCount() ) {
newSize = pb[0u].size();
if ( newSize > this->info.getCapacity() ) {
return S_casApp_outOfBounds;
}
}
@ -193,14 +191,14 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
return S_casApp_outOfBounds;
}
//
// Create a new array data descriptor
// (so that old values that may be referenced on the
// event queue are not replaced)
//
smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
1u, this->info.getElementCount() ) );
smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
1u, newSize ) );
if ( ! pNewValue.valid() ) {
return S_casApp_noMemory;
}
@ -211,21 +209,20 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
gddStatus gdds = pNewValue->unreference( );
assert ( ! gdds );
//
// allocate array buffer
//
aitFloat64 * pF = new aitFloat64 [this->info.getElementCount()];
aitFloat64 * pF = new aitFloat64 [newSize];
if (!pF) {
return S_casApp_noMemory;
}
//
// Install (and initialize) array buffer
// if no old values exist
//
unsigned count = this->info.getElementCount();
for ( unsigned i = 0u; i < count; i++ ) {
for ( unsigned i = 0u; i < newSize; i++ ) {
pF[i] = 0.0f;
}
@ -240,7 +237,7 @@ caStatus exVectorPV::updateValue ( const gdd & value )
// (do this before we increment pF)
//
pNewValue->putRef ( pF, pDest );
//
// copy in the values that they are writing
//
@ -248,9 +245,10 @@ caStatus exVectorPV::updateValue ( const gdd & value )
if ( gdds ) {
return S_cas_noConvert;
}
this->pValue = pNewValue;
this->info.setElementCount(newSize);
return S_casApp_success;
}
@ -261,6 +259,6 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
void exVecDestructor::run ( void *pUntyped )
{
aitFloat32 * pf = reinterpret_cast < aitFloat32 * > ( pUntyped );
aitFloat64 * pf = reinterpret_cast < aitFloat64 * > ( pUntyped );
delete [] pf;
}

View File

@ -34,3 +34,10 @@ CHECK_RELEASE = YES
# or CROSS_OPT settings from base/configure/CONFIG_SITE
#HOST_OPT = NO
#CROSS_OPT = NO
# These allow developers to override the CONFIG_SITE variable
# settings without having to modify the configure/CONFIG_SITE
# file itself.
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local

View File

@ -35,3 +35,9 @@ EPICS_BASE = _EPICS_BASE_
# Set RULES here if you want to use build rules from somewhere
# other than EPICS_BASE:
#RULES = $(MODULES)/build-rules
# These allow developers to override the RELEASE variable settings
# without having to modify the configure/RELEASE file itself.
-include $(TOP)/../RELEASE.local
-include $(TOP)/configure/RELEASE.local

View File

@ -101,7 +101,7 @@ sub OutputBreaktables {
my ($out, $breaktables) = @_;
while (my ($name, $breaktable) = each %{$breaktables}) {
printf $out "breaktable(\"%s\") {\n", $name;
printf $out " point(%s, %s)\n", @{$_}
printf $out " %s, %s\n", @{$_}
foreach $breaktable->points;
print $out "}\n";
}

View File

@ -106,7 +106,7 @@ sub equals {
my ($new, $known) = @_;
return 0 if ! $known->fields;
return 1 if ! $new->fields;
dieContext("Duplicate definition of record type '$a->{NAME}'");
dieContext("Duplicate definition of record type '$known->{NAME}'");
}
sub toDeclaration {

View File

@ -5,7 +5,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
#
# Convert configure/RELEASE file(s) into something else.
@ -121,15 +121,16 @@ sub dllPath {
unlink $outfile;
open(OUT, ">$outfile") or die "$! creating $outfile";
print OUT "\@ECHO OFF\n";
print OUT "PATH \%PATH\%;", join(';', binDirs()), "\n";
# This SET syntax is essential for supporting embedded spaces and '&'
# characters in both the PATH variable and the new directory components
print OUT "SET \"PATH=", join(';', binDirs(), '%PATH%'), "\"\n";
close OUT;
}
sub relPaths {
unlink $outfile;
open(OUT, ">$outfile") or die "$! creating $outfile";
print OUT "export PATH=\$PATH:",
join(':', map {m/\s/ ? "\"$_\"" : $_ } binDirs()), "\n";
print OUT "export PATH=\"", join(':', binDirs(), '$PATH'), "\"\n";
close OUT;
}
@ -153,21 +154,21 @@ sub binDirs {
sub cdCommands {
die "Architecture not set (use -a option)" unless ($arch);
my @includes = grep !m/^(RULES | TEMPLATE_TOP)$/x, @apps;
unlink($outfile);
open(OUT,">$outfile") or die "$! creating $outfile";
my $startup = $cwd;
$startup =~ s/^$root/$iocroot/o if ($opt_t);
$startup =~ s/([\\"])/\\$1/g; # escape back-slashes and double-quotes
print OUT "startup = \"$startup\"\n";
my $ioc = $cwd;
$ioc =~ s/^.*\///; # iocname is last component of directory name
print OUT "putenv(\"IOC=$ioc\")\n";
foreach my $app (@includes) {
my $iocpath = my $path = $macros{$app};
$iocpath =~ s/^$root/$iocroot/o if ($opt_t);
@ -189,15 +190,15 @@ sub cdCommands {
#
sub envPaths {
my @includes = grep !m/^ (RULES | TEMPLATE_TOP) $/x, @apps;
unlink($outfile);
open(OUT,">$outfile") or die "$! creating $outfile";
my $ioc = $cwd;
$ioc =~ s/^.*\///; # iocname is last component of directory name
print OUT "epicsEnvSet(\"IOC\",\"$ioc\")\n";
foreach my $app (@includes) {
my $iocpath = my $path = $macros{$app};
$iocpath =~ s/^$root/$iocroot/o if ($opt_t);
@ -224,7 +225,7 @@ sub checkRelease {
expandRelease(\%check);
delete $check{TOP};
delete $check{EPICS_HOST_ARCH};
while (my ($parent, $ppath) = each %check) {
if (exists $macros{$parent} &&
AbsPath($macros{$parent}) ne AbsPath($ppath)) {
@ -269,4 +270,3 @@ sub checkRelease {
print "\n" if $status;
exit $status;
}