diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION
index dd6ae0358..e9f632391 100644
--- a/configure/CONFIG_BASE_VERSION
+++ b/configure/CONFIG_BASE_VERSION
@@ -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)
diff --git a/configure/RULES.ioc b/configure/RULES.ioc
index da314a406..fa0482ec0 100644
--- a/configure/RULES.ioc
+++ b/configure/RULES.ioc
@@ -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
-
diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD
index b0f109669..a665de3a1 100644
--- a/configure/RULES_BUILD
+++ b/configure/RULES_BUILD
@@ -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
diff --git a/configure/os/CONFIG.linux-x86.windows-x64-mingw b/configure/os/CONFIG.linux-x86.windows-x64-mingw
index 3b5ba18b4..3becd0045 100644
--- a/configure/os/CONFIG.linux-x86.windows-x64-mingw
+++ b/configure/os/CONFIG.linux-x86.windows-x64-mingw
@@ -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
diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86
index f9bb0b9cb..505798a8a 100644
--- a/configure/os/CONFIG.win32-x86.win32-x86
+++ b/configure/os/CONFIG.win32-x86.win32-x86
@@ -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:. - 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))
-
diff --git a/configure/os/CONFIG.windows-x64.windows-x64 b/configure/os/CONFIG.windows-x64.windows-x64
index d0e59bd7c..dcb6e82de 100644
--- a/configure/os/CONFIG.windows-x64.windows-x64
+++ b/configure/os/CONFIG.windows-x64.windows-x64
@@ -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
diff --git a/configure/os/CONFIG_SITE.Common.win32-x86-static b/configure/os/CONFIG_SITE.Common.win32-x86-static
new file mode 100644
index 000000000..de4e61760
--- /dev/null
+++ b/configure/os/CONFIG_SITE.Common.win32-x86-static
@@ -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
diff --git a/configure/os/CONFIG_SITE.Common.windows-x64-static b/configure/os/CONFIG_SITE.Common.windows-x64-static
index f2f059751..5db619b11 100644
--- a/configure/os/CONFIG_SITE.Common.windows-x64-static
+++ b/configure/os/CONFIG_SITE.Common.windows-x64-static
@@ -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
diff --git a/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw b/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
index db87a3357..363664f26 100644
--- a/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
+++ b/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
@@ -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++
diff --git a/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw b/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
index 42cdc353b..026410cfe 100644
--- a/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
+++ b/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
@@ -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++
diff --git a/documentation/KnownProblems.html b/documentation/KnownProblems.html
index 2f8a61883..fe9045d03 100644
--- a/documentation/KnownProblems.html
+++ b/documentation/KnownProblems.html
@@ -4,17 +4,17 @@
- Known Problems in R3.16.0.1
+ Known Problems in R3.16.1
-EPICS Base R3.16.0.1: Known Problems
+EPICS Base R3.16.1: Known Problems
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:
-% cd /path/to/base-3.16.0.1
+% cd /path/to/base-3.16.1
% patch -p0 < /path/to/file.patch
The following problems were known by the developers at the time of this
diff --git a/documentation/README.1st b/documentation/README.1st
index b74f6ae92..ee56e542f 100644
--- a/documentation/README.1st
+++ b/documentation/README.1st
@@ -1,24 +1,24 @@
Installation Instructions
- EPICS Base Release 3.16.0
+ EPICS Base Release 3.16.1
--------------------------------------------------------------------------
Table of Contents
- * What is EPICS base?
- * What is new in this release?
- * Copyright
- * Supported platforms
- * Supported compilers
- * Software requirements
- * Host system storage requirements
- * Documentation
- * Directory Structure
- * Build related components
- * Building EPICS base (Unix and Win32)
- * Example application and extension
- * Multiple host platforms
+ *�What is EPICS base?
+ *�What is new in this release?
+ *�Copyright
+ *�Supported platforms
+ *�Supported compilers
+ *�Software requirements
+ *�Host system storage requirements
+ *�Documentation
+ *�Directory Structure
+ *�Build related components
+ *�Building EPICS base (Unix and Win32)
+ *�Example application and extension
+ *�Multiple host platforms
--------------------------------------------------------------------------
diff --git a/documentation/README.html b/documentation/README.html
index f717c3d47..8917fa2e7 100644
--- a/documentation/README.html
+++ b/documentation/README.html
@@ -9,7 +9,7 @@
Installation Instructions
-EPICS Base Release 3.16.0
+EPICS Base Release 3.16.1
Table of Contents
@@ -190,12 +190,12 @@
CONFIG.CrossCommon Cross build definitions
CONFIG.gnuCommon Gnu compiler build definitions for all archs
CONFIG_ADDONS Definitions for <osclass> 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 <top> dir (uninstall and tar)
Sample.Makefile Sample makefile with comments
@@ -340,7 +340,7 @@ Files in the base/startup directory have been provided to
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.
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 <top>
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.
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 4a4804672..372f32d7d 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -3,14 +3,15 @@
- EPICS Base R3.16.0.2 Release Notes
+ EPICS Base R3.16.1 Release Notes
-EPICS Base Release 3.16.0.2
+EPICS Base Release 3.16.1
This version of EPICS Base has not been released yet.
+
Changes made on the 3.16 branch since 3.16.0.1
-Changes from the 3.14 branch since 3.15.4
+Changes from the 3.14 branch since 3.15.5
+
+Server bind issue on Windows
+
+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.
+
+Checking Periodic Scan Rates
+
+Code has been added to the IOC startup to better protect it against bad
+periodic scan rates, including against locales where .
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 scanppl command will also flag the faulty menuScan value.
+
+
+Changes made between 3.15.4 and 3.15.5
+
+dbStatic Library Speedup and Cleanup
+
+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
+dbRecordsAbcSorted = 1 before loading the databases will retain the
+old behavior.
+
+The routine dbRenameRecord() 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.
+
+Launchpad Bug-fixes
+
+In addition to the more detailed change descriptions below, the following
+Launchpad bugs have also been fixed in this release:
+
+
+ -
+ #1440186 Crash due to a too small buffer being provided in
+ dbContextReadNotifyCache
+ -
+ #1479316 Some data races found using Helgrind
+ -
+ #1495833 biRecord prompt groups are nonsensical
+ -
+ #1606848 WSAIoctl SIO_GET_INTERFACE_LIST failed in Windows
+
+
+Whole-Program Optimization for MS Visual Studio Targets
+
+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
+OPT_WHOLE_PROGRAM = NO to override the default value
+YES that would otherwise be used.
+
+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
+-LTCG flag set and display a warning if it is asked to link any object
+files that were compiled with the -GL flag.
+
+Add dynamic (variable length) array support to PCAS
+
+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 Portable
+Channel Access Server
(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.
+
+In implementing the above, the gdd method gdd::put(const gdd *) 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.
+
+Additional epicsTime conversion
+
+The EPICS timestamp library (epicsTime) inside libCom's OSI layer has
+been extended by routines that convert from struct tm to the EPICS
+internal epicsTime 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.
+
+MinGW Cross-builds from Linux
+
+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.target files.
+
General Time updates
The iocInit code now performs a sanity check of the current time
diff --git a/src/ca/client/CAref.html b/src/ca/client/CAref.html
index 87ad469a6..2bdd0b452 100644
--- a/src/ca/client/CAref.html
+++ b/src/ca/client/CAref.html
@@ -1146,16 +1146,10 @@ the output.
Wide mode "name timestamp value stat sevr" (read PVs as
DBR_TIME_xxx) |
-
- | -n |
- Print DBF_ENUM values as number (default are enum strings) |
-
| -d <type> |
- Request specific dbr type; use string (DBR_ prefix may be omitted)
-
- or number of one of the following types:
-
+ | Request specific dbr type; use string (DBR_ prefix may be omitted)
+ or number of one of the following types:
@@ -1272,6 +1266,14 @@ the output.
|
+
+ |
+ Enum format: |
+
+
+ | -n |
+ Print DBF_ENUM value as number (default is enum string) |
+
|
Arrays: |
@@ -1303,15 +1305,15 @@ the output.
| -e <nr> |
- Use %e format, with <nr> digits after the decimal point |
+ Use %e format, with a precision of <nr> digits |
| -f <nr> |
- Use %f format, with <nr> digits after the decimal point |
+ Use %f format, with a precision of <nr> digits |
| -g <nr> |
- Use %g format, with <nr> digits after the decimal point |
+ Use %g format, with a precision of <nr> digits |
| -s |
@@ -1349,6 +1351,14 @@ the output.
-0b |
Print as binary number |
+
+ |
+ Alternate output field separator: |
+
+
+ | -F <ofs> |
+ Use <ofs> as an alternate output field separator |
+
@@ -1381,9 +1391,10 @@ the output.
Wait time, specifies longer CA timeout, default is 1.0 second |
- | -m <mask> |
- Specify CA event mask to use, with <mask> being any combination
- of 'v' (value), 'a' (alarm), 'l' (log), 'p' (property). Default: va |
+ -m <msk> |
+ Specify CA event mask to use. <msk> is any combination of
+ 'v' (value), 'a' (alarm), 'l' (log/archive), 'p' (property).
+ Default event mask is 'va' |
| -p <prio> |
@@ -1405,8 +1416,8 @@ the output.
'n' = no timestamps
'r' = relative timestamps (time elapsed since start of program)
'i' = incremental timestamps (time elapsed since last update)
- 'I' = incremental timestamps (time elapsed since last update, by
- channel)
+ 'I' = incremental timestamps (time since last update, by channel)
+ 'r', 'i' or 'I' require 's' or 'c' to select the time source
|
@@ -1414,7 +1425,7 @@ the output.
| -n |
- Print DBF_ENUM values as number (default are enum strings) |
+ Print DBF_ENUM values as number (default is enum string) |
|
@@ -1422,16 +1433,15 @@ the output.
|
- Value format: Print number of requested values, then list of
- values |
+ Array values: Print number of elements, then list of values |
| Default: |
- Print all values |
+ Default: Request and print all elements (dynamic arrays supported) |
- | -# <count> |
- Print first <count> elements of an array |
+ -# <num> |
+ Request and print up to <num> elements |
| -S |
@@ -1439,23 +1449,23 @@ the output.
|
- Floating point type format: |
+ Floating point format: |
| Default: |
Use %g format |
- | -e <nr> |
- Use %e format, with <nr> digits after the decimal point |
+ -e <num> |
+ Use %e format, with a precision of <num> digits |
- | -f <nr> |
- Use %f format, with <nr> digits after the decimal point |
+ -f <num> |
+ Use %f format, with a precision of <num> digits |
- | -g <nr> |
- Use %g format, with <nr> digits after the decimal point |
+ -g <num> |
+ Use %g format, with a precision of <num> digits |
| -s |
@@ -1497,21 +1507,27 @@ the output.
-caput [options] <PV name> <value>
+caput [options] <PV name> <value> ...
caput -a [options] <PV name> <no of elements> <value> ...
Description
Put value to a PV.
-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.
+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.
-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.
+There are two variants to the arguments for this command. For the scalar
+variant without the -a 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 -S flag is
+given) is written to the specified PV.
+
+The array variant with the -a 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.
@@ -1550,12 +1566,16 @@ command line is used.
| -t |
Terse mode - print only successfully written value, without name |
+
+ | -l |
+ Long mode "name timestamp value stat sevr" (read PVs as DBR_TIME_xxx) |
+
|
Enum Format: |
- |
+ Default: |
Auto - try value as ENUM string, then as index number |
@@ -1571,17 +1591,24 @@ command line is used.
| Arrays: |
- | -a |
- Put array data |
+ Default: |
+ Put scalar |
|
- Value format: Print number of requested values, then list of
- values |
+ Value format: all value arguments concatenated with spaces |
| -S |
- Put string as an array of char (long string) |
+ Put string as an array of chars (long string) |
+
+
+ | -a |
+ Put array |
+
+
+ |
+ Value format: number of values, then list of values |
diff --git a/src/ca/client/cac.cpp b/src/ca/client/cac.cpp
index d66cf9dad..d1afe6785 100644
--- a/src/ca/client/cac.cpp
+++ b/src/ca/client/cac.cpp
@@ -149,9 +149,9 @@ cac::cac (
iiuExistenceCount ( 0u ),
cacShutdownInProgress ( false )
{
- if ( ! osiSockAttach () ) {
- throwWithLocation ( caErrorCode (ECA_INTERNAL) );
- }
+ if ( ! osiSockAttach () ) {
+ throwWithLocation ( udpiiu :: noSocket () );
+ }
try {
long status;
diff --git a/src/ca/client/iocinf.h b/src/ca/client/iocinf.h
index c0c33d6c2..0d3b57db1 100644
--- a/src/ca/client/iocinf.h
+++ b/src/ca/client/iocinf.h
@@ -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
*/
diff --git a/src/ca/client/repeater.cpp b/src/ca/client/repeater.cpp
index 5e123ee2d..61ba33fc5 100644
--- a/src/ca/client/repeater.cpp
+++ b/src/ca/client/repeater.cpp
@@ -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];
diff --git a/src/ca/client/tcpiiu.cpp b/src/ca/client/tcpiiu.cpp
index 58b1b0c0f..7fd848b20 100644
--- a/src/ca/client/tcpiiu.cpp
+++ b/src/ca/client/tcpiiu.cpp
@@ -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 );
}
diff --git a/src/ca/client/tools/caput.c b/src/ca/client/tools/caput.c
index f6dcc21cd..9c50cd9df 100644
--- a/src/ca/client/tools/caput.c
+++ b/src/ca/client/tools/caput.c
@@ -56,7 +56,7 @@ static epicsEventId epId;
void usage (void)
{
- fprintf (stderr, "\nUsage: caput [options] \n"
+ fprintf (stderr, "\nUsage: caput [options] ...\n"
" caput -a [options] ...\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 : Use as an alternate output field separator\n"
"\nExample: caput my_channel 1.2\n"
diff --git a/src/ca/client/udpiiu.cpp b/src/ca/client/udpiiu.cpp
index 837a836d9..8bd3b5831 100644
--- a/src/ca/client/udpiiu.cpp
+++ b/src/ca/client/udpiiu.cpp
@@ -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;
diff --git a/src/ca/legacy/gdd/gdd.cc b/src/ca/legacy/gdd/gdd.cc
index fd2b662c9..acb53da4e 100644
--- a/src/ca/legacy/gdd/gdd.cc
+++ b/src/ca/legacy/gdd/gdd.cc
@@ -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;
diff --git a/src/ca/legacy/gdd/gddAppTable.cc b/src/ca/legacy/gdd/gddAppTable.cc
index ee3b82a7b..2315516fe 100644
--- a/src/ca/legacy/gdd/gddAppTable.cc
+++ b/src/ca/legacy/gdd/gddAppTable.cc
@@ -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)
{
diff --git a/src/ca/legacy/gdd/gddTest.cc b/src/ca/legacy/gdd/gddTest.cc
index d36014018..881a55df9 100644
--- a/src/ca/legacy/gdd/gddTest.cc
+++ b/src/ca/legacy/gdd/gddTest.cc
@@ -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");
diff --git a/src/ca/legacy/pcas/example/directoryService/main.cc b/src/ca/legacy/pcas/example/directoryService/main.cc
index cb8c43901..76f27e75d 100644
--- a/src/ca/legacy/pcas/example/directoryService/main.cc
+++ b/src/ca/legacy/pcas/example/directoryService/main.cc
@@ -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;
}
diff --git a/src/ca/legacy/pcas/generic/caHdrLargeArray.h b/src/ca/legacy/pcas/generic/caHdrLargeArray.h
index 89b0d6d4b..7bda002e9 100644
--- a/src/ca/legacy/pcas/generic/caHdrLargeArray.h
+++ b/src/ca/legacy/pcas/generic/caHdrLargeArray.h
@@ -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;
diff --git a/src/ca/legacy/pcas/generic/caServerI.h b/src/ca/legacy/pcas/generic/caServerI.h
index 344f6393b..012233693 100644
--- a/src/ca/legacy/pcas/generic/caServerI.h
+++ b/src/ca/legacy/pcas/generic/caServerI.h
@@ -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,
diff --git a/src/ca/legacy/pcas/generic/casChannelI.cc b/src/ca/legacy/pcas/generic/casChannelI.cc
index 588f67d78..376f62f8c 100644
--- a/src/ca/legacy/pcas/generic/casChannelI.cc
+++ b/src/ca/legacy/pcas/generic/casChannelI.cc
@@ -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 )
diff --git a/src/ca/legacy/pcas/generic/casChannelI.h b/src/ca/legacy/pcas/generic/casChannelI.h
index 2c72e88e4..a0f74a1df 100644
--- a/src/ca/legacy/pcas/generic/casChannelI.h
+++ b/src/ca/legacy/pcas/generic/casChannelI.h
@@ -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 );
}
diff --git a/src/ca/legacy/pcas/generic/casCtx.h b/src/ca/legacy/pcas/generic/casCtx.h
index 706376e77..eab644685 100644
--- a/src/ca/legacy/pcas/generic/casCtx.h
+++ b/src/ca/legacy/pcas/generic/casCtx.h
@@ -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
diff --git a/src/ca/legacy/pcas/generic/casDGClient.cc b/src/ca/legacy/pcas/generic/casDGClient.cc
index 4f1f41ecb..4fca74dbd 100644
--- a/src/ca/legacy/pcas/generic/casDGClient.cc
+++ b/src/ca/legacy/pcas/generic/casDGClient.cc
@@ -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 ( 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 ( &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(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 ( & 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 ) {
diff --git a/src/ca/legacy/pcas/generic/casStrmClient.cc b/src/ca/legacy/pcas/generic/casStrmClient.cc
index 6b1de3629..ff12e889e 100644
--- a/src/ca/legacy/pcas/generic/casStrmClient.cc
+++ b/src/ca/legacy/pcas/generic/casStrmClient.cc
@@ -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 &,
else {
stringSize = 1u + (unsigned) status;
}
+ va_end ( args );
}
else {
stringSize = 0u;
diff --git a/src/ca/legacy/pcas/generic/casStrmClient.h b/src/ca/legacy/pcas/generic/casStrmClient.h
index 3f6c0a51b..0fdd36bb4 100644
--- a/src/ca/legacy/pcas/generic/casStrmClient.h
+++ b/src/ca/legacy/pcas/generic/casStrmClient.h
@@ -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];
diff --git a/src/ca/legacy/pcas/io/bsdSocket/casIntfIO.cc b/src/ca/legacy/pcas/io/bsdSocket/casIntfIO.cc
index 41ce6de8d..2c2cb5bef 100644
--- a/src/ca/legacy/pcas/io/bsdSocket/casIntfIO.cc
+++ b/src/ca/legacy/pcas/io/bsdSocket/casIntfIO.cc
@@ -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 (&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 (&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 (&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 ( &this->addr ),
+ addrSize = ( osiSocklen_t ) sizeof (this->addr);
+ status = getsockname (
+ this->sock,
+ reinterpret_cast ( &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];
diff --git a/src/ioc/db/dbCaTest.c b/src/ioc/db/dbCaTest.c
index 450eb9463..18ef393ca 100644
--- a/src/ioc/db/dbCaTest.c
+++ b/src/ioc/db/dbCaTest.c
@@ -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);
}
}
}
diff --git a/src/ioc/db/dbConvert.c b/src/ioc/db/dbConvert.c
index 8d3a54c82..0fad81d5a 100644
--- a/src/ioc/db/dbConvert.c
+++ b/src/ioc/db/dbConvert.c
@@ -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) {
diff --git a/src/ioc/db/dbScan.c b/src/ioc/db/dbScan.c
index 180118091..9f7df4c17 100644
--- a/src/ioc/db/dbScan.c
+++ b/src/ioc/db/dbScan.c
@@ -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;
diff --git a/src/ioc/db/db_test.c b/src/ioc/db/db_test.c
index b011c6819..8d7ad31b1 100644
--- a/src/ioc/db/db_test.c
+++ b/src/ioc/db/db_test.c
@@ -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;
diff --git a/src/ioc/db/test/chfPluginTest.c b/src/ioc/db/test/chfPluginTest.c
index 4b12644ea..becd876e8 100644
--- a/src/ioc/db/test/chfPluginTest.c
+++ b/src/ioc/db/test/chfPluginTest.c
@@ -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);
diff --git a/src/ioc/dbStatic/dbBase.h b/src/ioc/dbStatic/dbBase.h
index 55a06ebb8..e58afd8ad 100644
--- a/src/ioc/dbStatic/dbBase.h
+++ b/src/ioc/dbStatic/dbBase.h
@@ -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 */
diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c
index c1444269c..12038a6ec 100644
--- a/src/ioc/dbStatic/dbLexRoutines.c
+++ b/src/ioc/dbStatic/dbLexRoutines.c
@@ -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);
diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c
index f4e5b6317..91c82b702 100644
--- a/src/ioc/dbStatic/dbStaticLib.c
+++ b/src/ioc/dbStatic/dbStaticLib.c
@@ -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);
diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h
index de94dc674..1619a9090 100644
--- a/src/ioc/dbStatic/dbStaticLib.h
+++ b/src/ioc/dbStatic/dbStaticLib.h
@@ -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);
diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd
index 4b515141b..a2ce45806 100644
--- a/src/ioc/misc/dbCore.dbd
+++ b/src/ioc/misc/dbCore.dbd
@@ -11,6 +11,7 @@ variable(asCaDebug,int)
# Static database access variables
variable(dbRecordsOnceOnly,int)
+variable(dbRecordsAbcSorted,int)
variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int)
diff --git a/src/ioc/rsrv/camessage.c b/src/ioc/rsrv/camessage.c
index b5c265ca6..b13883b5a 100644
--- a/src/ioc/rsrv/camessage.c
+++ b/src/ioc/rsrv/camessage.c
@@ -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(
diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c
index a8c590452..a18abafe2 100644
--- a/src/ioc/rsrv/caservertask.c
+++ b/src/ioc/rsrv/caservertask.c
@@ -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],
diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c
index 84634672b..82871da0d 100644
--- a/src/libCom/RTEMS/rtems_init.c
+++ b/src/libCom/RTEMS/rtems_init.c
@@ -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);
}
diff --git a/src/libCom/as/asLib_lex.l b/src/libCom/as/asLib_lex.l
index 90e1b55bb..5e0451925 100644
--- a/src/libCom/as/asLib_lex.l
+++ b/src/libCom/as/asLib_lex.l
@@ -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]);
diff --git a/src/libCom/ellLib/Makefile b/src/libCom/ellLib/Makefile
index b325a453e..9a5cb3e67 100644
--- a/src/libCom/ellLib/Makefile
+++ b/src/libCom/ellLib/Makefile
@@ -10,3 +10,4 @@
SRC_DIRS += $(LIBCOM)/ellLib
INC += ellLib.h
Com_SRCS += ellLib.c
+Com_SRCS += ellSort.c
diff --git a/src/libCom/ellLib/ellLib.h b/src/libCom/ellLib/ellLib.h
index f99859f3d..52b58d169 100644
--- a/src/libCom/ellLib/ellLib.h
+++ b/src/libCom/ellLib/ellLib.h
@@ -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);
diff --git a/src/libCom/ellLib/ellSort.c b/src/libCom/ellLib/ellSort.c
new file mode 100644
index 000000000..2f8f2748b
--- /dev/null
+++ b/src/libCom/ellLib/ellSort.c
@@ -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
+
+#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 AB.
+ */
+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;
+ }
+
+}
diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp
index c5b629ba6..e2e3aaf41 100644
--- a/src/libCom/iocsh/iocsh.cpp
+++ b/src/libCom/iocsh/iocsh.cpp
@@ -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;
}
diff --git a/src/libCom/log/iocLogServer.c b/src/libCom/log/iocLogServer.c
index f9deb06e5..f5694fc0f 100644
--- a/src/libCom/log/iocLogServer.c
+++ b/src/libCom/log/iocLogServer.c
@@ -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 .
- */
- 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 .
+ */
+ 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);
diff --git a/src/libCom/misc/epicsString.c b/src/libCom/misc/epicsString.c
index f3cf828f4..a8098336c 100644
--- a/src/libCom/misc/epicsString.c
+++ b/src/libCom/misc/epicsString.c
@@ -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; inode)) {
- if (ptp->priority == ptp->priority &&
+ if (ptp->priority == priority &&
!strcmp(ptp->name, name))
break;
}
diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp
index 59514c2f7..6dd1d3f97 100644
--- a/src/libCom/osi/epicsTime.cpp
+++ b/src/libCom/osi/epicsTime.cpp
@@ -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
#include
#include
-#include // vxWorks 6.0 requires this include
+#include // 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(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 ( 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(nSecAdj) >= nSecPerSec) {
+ this->secPastEpoch += nSecAdj / nSecPerSec;
+ nSecAdj %= nSecPerSec;
}
- else {
- const unsigned long nSecMinus =
- static_cast ( -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 ( ( 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 (-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 (-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 "%0f"
-// (where in an unsigned integer)
+// Break up a format string into "%0f"
+// (where 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 "%0f]" is present or not and if so
+// B) Indicates whether a valid "%0f]" 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 "%0f" at the end (used for fractional second formatting)
+ // look for "%0f" 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" {
}
}
}
-
diff --git a/src/libCom/osi/epicsTime.h b/src/libCom/osi/epicsTime.h
index bf8f77c87..149f6f2d3 100644
--- a/src/libCom/osi/epicsTime.h
+++ b/src/libCom/osi/epicsTime.h
@@ -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 );
diff --git a/src/libCom/osi/os/Darwin/osdSock.h b/src/libCom/osi/os/Darwin/osdSock.h
index e9426a79f..1d4556eee 100644
--- a/src/libCom/osi/os/Darwin/osdSock.h
+++ b/src/libCom/osi/os/Darwin/osdSock.h
@@ -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
diff --git a/src/libCom/osi/os/Linux/osdSock.h b/src/libCom/osi/os/Linux/osdSock.h
index b32a16044..614f3f98d 100644
--- a/src/libCom/osi/os/Linux/osdSock.h
+++ b/src/libCom/osi/os/Linux/osdSock.h
@@ -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*/
-
diff --git a/src/libCom/osi/os/RTEMS/osdMessageQueue.c b/src/libCom/osi/os/RTEMS/osdMessageQueue.c
index ff7728fb2..a566de6f6 100644
--- a/src/libCom/osi/os/RTEMS/osdMessageQueue.c
+++ b/src/libCom/osi/os/RTEMS/osdMessageQueue.c
@@ -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);
}
diff --git a/src/libCom/osi/os/RTEMS/osdSock.h b/src/libCom/osi/os/RTEMS/osdSock.h
index dce24645f..930ed0e72 100644
--- a/src/libCom/osi/os/RTEMS/osdSock.h
+++ b/src/libCom/osi/os/RTEMS/osdSock.h
@@ -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()
diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c
index d177cf3f2..769e95820 100644
--- a/src/libCom/osi/os/RTEMS/osdThread.c
+++ b/src/libCom/osi/os/RTEMS/osdThread.c
@@ -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;
}
}
diff --git a/src/libCom/osi/os/WIN32/osdSock.h b/src/libCom/osi/os/WIN32/osdSock.h
index e685f6564..d92e18755 100644
--- a/src/libCom/osi/os/WIN32/osdSock.h
+++ b/src/libCom/osi/os/WIN32/osdSock.h
@@ -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
/*
- * 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
diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c
index b8590086a..8cdb4a3f4 100644
--- a/src/libCom/osi/os/WIN32/osdThread.c
+++ b/src/libCom/osi/os/WIN32/osdThread.c
@@ -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;
diff --git a/src/libCom/osi/os/cygwin32/osdSock.h b/src/libCom/osi/os/cygwin32/osdSock.h
index 324e75c3f..d642cad44 100644
--- a/src/libCom/osi/os/cygwin32/osdSock.h
+++ b/src/libCom/osi/os/cygwin32/osdSock.h
@@ -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*/
-
diff --git a/src/libCom/osi/os/freebsd/osdSock.h b/src/libCom/osi/os/freebsd/osdSock.h
index a950b996c..fe28d4cd5 100644
--- a/src/libCom/osi/os/freebsd/osdSock.h
+++ b/src/libCom/osi/os/freebsd/osdSock.h
@@ -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*/
-
diff --git a/src/libCom/osi/os/iOS/osdSock.h b/src/libCom/osi/os/iOS/osdSock.h
index f3a15c88d..0b3b3f6c1 100644
--- a/src/libCom/osi/os/iOS/osdSock.h
+++ b/src/libCom/osi/os/iOS/osdSock.h
@@ -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
diff --git a/src/libCom/osi/os/solaris/osdSock.h b/src/libCom/osi/os/solaris/osdSock.h
index 1ea493680..a39c6c3d3 100644
--- a/src/libCom/osi/os/solaris/osdSock.h
+++ b/src/libCom/osi/os/solaris/osdSock.h
@@ -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*/
-
diff --git a/src/libCom/osi/os/vxWorks/osdSock.h b/src/libCom/osi/os/vxWorks/osdSock.h
index f0260c5a8..80464ef87 100644
--- a/src/libCom/osi/os/vxWorks/osdSock.h
+++ b/src/libCom/osi/os/vxWorks/osdSock.h
@@ -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*/
-
-
diff --git a/src/libCom/test/epicsEllTest.c b/src/libCom/test/epicsEllTest.c
index b608d1cc3..62ee14e39 100644
--- a/src/libCom/test/epicsEllTest.c
+++ b/src/libCom/test/epicsEllTest.c
@@ -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
#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; inum = 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->numnum) || (prev->num==next->num && prev->listlist);
+ 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();
}
diff --git a/src/libCom/test/epicsEventTest.cpp b/src/libCom/test/epicsEventTest.cpp
index b0d79613f..7c1a24141 100644
--- a/src/libCom/test/epicsEventTest.cpp
+++ b/src/libCom/test/epicsEventTest.cpp
@@ -250,5 +250,12 @@ MAIN(epicsEventTest)
eventWaitTest();
eventWakeupTest();
+ free(name);
+ free(id);
+ epicsRingPointerDelete(pinfo->ring);
+ epicsMutexDestroy(pinfo->lockRing);
+ epicsEventDestroy(event);
+ free(pinfo);
+
return testDone();
}
diff --git a/src/libCom/test/epicsMutexTest.cpp b/src/libCom/test/epicsMutexTest.cpp
index 87cf0a460..d44e5c0f1 100644
--- a/src/libCom/test/epicsMutexTest.cpp
+++ b/src/libCom/test/epicsMutexTest.cpp
@@ -279,5 +279,11 @@ MAIN(epicsMutexTest)
epicsMutexPerformance ();
+ free(pinfo);
+ free(arg);
+ free(name);
+ free(id);
+ epicsMutexDestroy(mutex);
+
return testDone();
}
diff --git a/src/libCom/test/epicsStdioTest.c b/src/libCom/test/epicsStdioTest.c
index c2d7eb58a..bf25784a5 100644
--- a/src/libCom/test/epicsStdioTest.c
+++ b/src/libCom/test/epicsStdioTest.c
@@ -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 */
diff --git a/src/libCom/test/epicsStringTest.c b/src/libCom/test/epicsStringTest.c
index 9c50d3c82..3e4aed7e7 100644
--- a/src/libCom/test/epicsStringTest.c
+++ b/src/libCom/test/epicsStringTest.c
@@ -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));
diff --git a/src/libCom/test/epicsTimeTest.cpp b/src/libCom/test/epicsTimeTest.cpp
index 970258801..ec5da4c78 100644
--- a/src/libCom/test/epicsTimeTest.cpp
+++ b/src/libCom/test/epicsTimeTest.cpp
@@ -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;
diff --git a/src/libCom/test/ringBytesTest.c b/src/libCom/test/ringBytesTest.c
index ecfd991be..6cef93334 100644
--- a/src/libCom/test/ringBytesTest.c
+++ b/src/libCom/test/ringBytesTest.c
@@ -115,5 +115,9 @@ MAIN(ringBytesTest)
testOk(n==1, "ring get %d", 1);
check(ring, RINGSIZE);
+ epicsRingBytesDelete(ring);
+ epicsEventDestroy(consumerEvent);
+ free(pinfo);
+
return testDone();
}
diff --git a/src/std/rec/fanoutRecord.dbd b/src/std/rec/fanoutRecord.dbd
index 40968945c..251d63a11 100644
--- a/src/std/rec/fanoutRecord.dbd
+++ b/src/std/rec/fanoutRecord.dbd
@@ -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) {
diff --git a/src/std/rec/seqRecord.dbd b/src/std/rec/seqRecord.dbd
index c40d17c38..826f3ecf6 100644
--- a/src/std/rec/seqRecord.dbd
+++ b/src/std/rec/seqRecord.dbd
@@ -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")
}
diff --git a/src/template/base/top/caClientApp/caMonitor.c b/src/template/base/top/caClientApp/caMonitor.c
index 059fefb5e..9554cc744 100644
--- a/src/template/base/top/caClientApp/caMonitor.c
+++ b/src/template/base/top/caClientApp/caMonitor.c
@@ -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");
diff --git a/src/template/base/top/caServerApp/exAsyncPV.cc b/src/template/base/top/caServerApp/exAsyncPV.cc
index 7e0758c13..b5bff9181 100644
--- a/src/template/base/top/caServerApp/exAsyncPV.cc
+++ b/src/template/base/top/caServerApp/exAsyncPV.cc
@@ -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;
}
diff --git a/src/template/base/top/caServerApp/exPV.cc b/src/template/base/top/caServerApp/exPV.cc
index af99c4e6a..97430c000 100644
--- a/src/template/base/top/caServerApp/exPV.cc
+++ b/src/template/base/top/caServerApp/exPV.cc
@@ -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
diff --git a/src/template/base/top/caServerApp/exServer.cc b/src/template/base/top/caServerApp/exServer.cc
index 49ea802dc..f934f3608 100644
--- a/src/template/base/top/caServerApp/exServer.cc
+++ b/src/template/base/top/caServerApp/exServer.cc
@@ -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 );
diff --git a/src/template/base/top/caServerApp/exServer.h b/src/template/base/top/caServerApp/exServer.h
index e0615c804..cd9a897d3 100644
--- a/src/template/base/top/caServerApp/exServer.h
+++ b/src/template/base/top/caServerApp/exServer.h
@@ -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;
}
diff --git a/src/template/base/top/caServerApp/exVectorPV.cc b/src/template/base/top/caServerApp/exVectorPV.cc
index 22e642fab..932188806 100644
--- a/src/template/base/top/caServerApp/exVectorPV.cc
+++ b/src/template/base/top/caServerApp/exVectorPV.cc
@@ -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 (pFinfo.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;
}
diff --git a/src/template/base/top/configure/CONFIG_SITE b/src/template/base/top/configure/CONFIG_SITE
index 208aa7e68..212485ebe 100644
--- a/src/template/base/top/configure/CONFIG_SITE
+++ b/src/template/base/top/configure/CONFIG_SITE
@@ -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
+
diff --git a/src/template/base/top/configure/RELEASE b/src/template/base/top/configure/RELEASE
index ba28bcb26..dbd742b45 100644
--- a/src/template/base/top/configure/RELEASE
+++ b/src/template/base/top/configure/RELEASE
@@ -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
+
diff --git a/src/tools/DBD/Output.pm b/src/tools/DBD/Output.pm
index 6e9d67b3c..77386f0bd 100644
--- a/src/tools/DBD/Output.pm
+++ b/src/tools/DBD/Output.pm
@@ -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";
}
diff --git a/src/tools/DBD/Recordtype.pm b/src/tools/DBD/Recordtype.pm
index 8c8fabbae..e4b0d5481 100644
--- a/src/tools/DBD/Recordtype.pm
+++ b/src/tools/DBD/Recordtype.pm
@@ -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 {
diff --git a/src/tools/convertRelease.pl b/src/tools/convertRelease.pl
index 919e3a54d..e2f13a556 100644
--- a/src/tools/convertRelease.pl
+++ b/src/tools/convertRelease.pl
@@ -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;
}
-