Compare commits
168 Commits
R3.15.3-rc
...
R3.15.4-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe887b4f83 | ||
|
|
7be7ad2768 | ||
|
|
6c9555310a | ||
|
|
4ccc2e9d3a | ||
|
|
122fb6c731 | ||
|
|
3b8fd13152 | ||
|
|
04a9fdb4e3 | ||
|
|
3c61880d79 | ||
|
|
8081d3ada4 | ||
|
|
6d35ee9c3c | ||
|
|
b5a0657adc | ||
|
|
b87f3eaaee | ||
|
|
6db0e13809 | ||
|
|
0f6c997288 | ||
|
|
704c748fbd | ||
|
|
82456f83ee | ||
|
|
e98a6bbafa | ||
|
|
9b51444fb7 | ||
|
|
3be97865b3 | ||
|
|
67097456e3 | ||
|
|
3c8af4c571 | ||
|
|
26c04844cf | ||
|
|
a3d981ad0a | ||
|
|
924aa2f93b | ||
|
|
457fb8fa13 | ||
|
|
b8b259de6f | ||
|
|
7ce8e5ea01 | ||
|
|
496414c88c | ||
|
|
2acde8bac7 | ||
|
|
2c69ddbee5 | ||
|
|
ba0d5f9443 | ||
|
|
08fd987c60 | ||
|
|
5a605fa0c3 | ||
|
|
0e5dc2a21c | ||
|
|
230603f4ac | ||
|
|
396ff3c484 | ||
|
|
09fbeaf6d3 | ||
|
|
b4a8a1ac98 | ||
|
|
ee87aecd6e | ||
|
|
054a234c70 | ||
|
|
24ddcd2524 | ||
|
|
2226f3acb9 | ||
|
|
f0f89b4b1c | ||
|
|
fdda079b8f | ||
|
|
1f36670175 | ||
|
|
1ede873200 | ||
|
|
51dd371784 | ||
|
|
72745d7b0c | ||
|
|
c933d77963 | ||
|
|
93597e20d5 | ||
|
|
f0453faf36 | ||
|
|
473992cfb9 | ||
|
|
6a362f467d | ||
|
|
af07e0fd51 | ||
|
|
de38b80795 | ||
|
|
7bb27ad3e7 | ||
|
|
1e1799c30e | ||
|
|
8358580190 | ||
|
|
24e39b252d | ||
|
|
ce7044c711 | ||
|
|
177090e35e | ||
|
|
430da57a35 | ||
|
|
d2d637d0c2 | ||
|
|
106fae3b26 | ||
|
|
3179e65791 | ||
|
|
6b9bfb09a5 | ||
|
|
4e312b9f64 | ||
|
|
59fea64390 | ||
|
|
f260124733 | ||
|
|
bd2ada3f8c | ||
|
|
113076a009 | ||
|
|
9502841b55 | ||
|
|
b4404c8266 | ||
|
|
f73f3332fa | ||
|
|
3f4c6abb31 | ||
|
|
76c422c5fd | ||
|
|
fee62836cd | ||
|
|
2c48bcc26b | ||
|
|
a3ab342833 | ||
|
|
3304470323 | ||
|
|
4f2f910d09 | ||
|
|
217f515985 | ||
|
|
ebc59a4223 | ||
|
|
58285501de | ||
|
|
fa07bc3efe | ||
|
|
bfa8e324f7 | ||
|
|
51a69862e7 | ||
|
|
4b8c11aeef | ||
|
|
62efa2e96a | ||
|
|
c7bcb09540 | ||
|
|
5ee778b0c2 | ||
|
|
7b3a040b34 | ||
|
|
e721be4ff5 | ||
|
|
88b47c021c | ||
|
|
d0a316f7ca | ||
|
|
ba307ba6e7 | ||
|
|
d943f6966f | ||
|
|
76d7ce1f76 | ||
|
|
66b0acbe3e | ||
|
|
822c6815c5 | ||
|
|
684ae7b35c | ||
|
|
e18eca80db | ||
|
|
b45622ac5e | ||
|
|
89e6fdbca0 | ||
|
|
599e6635fb | ||
|
|
4241b4e6cb | ||
|
|
9eedf0581e | ||
|
|
ffb23a3480 | ||
|
|
61e61aab24 | ||
|
|
d3e046a466 | ||
|
|
99d331e50a | ||
|
|
9d95528eba | ||
|
|
95a1998e0b | ||
|
|
5769db3862 | ||
|
|
00a74fbb4e | ||
|
|
03fde89dd4 | ||
|
|
8421b46398 | ||
|
|
650aaea203 | ||
|
|
fcfe7ed312 | ||
|
|
f2c4b2c81e | ||
|
|
167dea3735 | ||
|
|
1c1eb030a9 | ||
|
|
43cf5af621 | ||
|
|
235e4bd835 | ||
|
|
601d6d9fe8 | ||
|
|
b961b25151 | ||
|
|
eb9246e4c9 | ||
|
|
d729006908 | ||
|
|
0aeba281be | ||
|
|
04fee51795 | ||
|
|
cba449d53b | ||
|
|
cdffcbfbae | ||
|
|
ba5ea5da93 | ||
|
|
c884175a86 | ||
|
|
a4e9dcff00 | ||
|
|
c9323da5e3 | ||
|
|
ffe441d032 | ||
|
|
45c8a173f3 | ||
|
|
98504d1cdc | ||
|
|
568ece9c27 | ||
|
|
f876bdb42c | ||
|
|
605074a580 | ||
|
|
64da181e6f | ||
|
|
823613fb4f | ||
|
|
f837add8c4 | ||
|
|
15307c4db6 | ||
|
|
8d5815ac95 | ||
|
|
25d7d46e08 | ||
|
|
5f31d9d2b1 | ||
|
|
bb67c9db2f | ||
|
|
cb965611ce | ||
|
|
e805abe971 | ||
|
|
c80f71e294 | ||
|
|
692bbafffe | ||
|
|
fd863738be | ||
|
|
2052062324 | ||
|
|
5d74216017 | ||
|
|
991ff308e0 | ||
|
|
77a5f0db77 | ||
|
|
8d6469957e | ||
|
|
ef90d2d3c7 | ||
|
|
2d9c529f5e | ||
|
|
05d3dbf453 | ||
|
|
695f516cbf | ||
|
|
fda3824ab4 | ||
|
|
42a67524e0 | ||
|
|
d4ed70154b | ||
|
|
f776f6b422 |
@@ -29,7 +29,7 @@ EPICS_VERSION = 3
|
||||
EPICS_REVISION = 15
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 3
|
||||
EPICS_MODIFICATION = 4
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included if zero
|
||||
|
||||
@@ -118,6 +118,13 @@ CROSS_COMPILER_TARGET_ARCHS=
|
||||
# configure/os/CONFIG_SITE.<host>.Common files instead.
|
||||
CROSS_COMPILER_HOST_ARCHS=
|
||||
|
||||
# The 'make runtests' and 'make tapfiles' build targets normally only run
|
||||
# self-tests for the EPICS_HOST_ARCH architecture. If the host can execute
|
||||
# the self-test programs for any other cross-built architectures such as
|
||||
# a -debug architecture, those architectures can be named here.
|
||||
#
|
||||
CROSS_COMPILER_RUNTEST_ARCHS=
|
||||
|
||||
# Build shared libraries (DLLs on Windows).
|
||||
# Must be either YES or NO. Definitions in the target-specific
|
||||
# os/CONFIG.Common.<target> and os/CONFIG_SITE.Common.<target> files may
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
# local timezone info for vxWorks and RTEMS IOCs. The format is
|
||||
# <name>::<minutesWest>:<start daylight>:<end daylight>
|
||||
# where the start and end are mmddhh - that is month,day,hour
|
||||
# e.g. for ANL in 2015: EPICS_TIMEZONE=CST/CDT::360:030802:110102
|
||||
# e.g. for ANL in 2016: EPICS_TIMEZONE=CST/CDT::360:031302:110602
|
||||
#
|
||||
# DST for 2015 US: Mar 08 - Nov 01
|
||||
# EU: Mar 29 - Oct 25
|
||||
# DST for 2016 US: Mar 13 - Nov 06
|
||||
# EU: Mar 27 - Oct 30
|
||||
# DST for 2017 US: Mar 12 - Nov 05
|
||||
@@ -42,11 +40,15 @@
|
||||
# EU: Mar 25 - Oct 28
|
||||
# DST for 2019 US: Mar 10 - Nov 03
|
||||
# EU: Mar 31 - Oct 27
|
||||
# (see: http://www.timeanddate.com/time/map/)
|
||||
# DST for 2020 US: Mar 08 - Nov 01
|
||||
# EU: Mar 29 - Oct 25
|
||||
# DST for 2021 US: Mar 14 - Nov 07
|
||||
# EU: Mar 28 - Oct 31
|
||||
# (see: http://www.timeanddate.com/time/dst/2016.html etc. )
|
||||
#
|
||||
# These values are for 2015:
|
||||
EPICS_TIMEZONE=CST/CDT::360:030802:110102
|
||||
#EPICS_TIMEZONE=CET/CEST::-60:032902:102502
|
||||
# These values are for 2016:
|
||||
EPICS_TIMEZONE=CST/CDT::360:031302:110602
|
||||
#EPICS_TIMEZONE=CET/CEST::-60:032702:103002
|
||||
|
||||
# EPICS_TS_NTP_INET
|
||||
# NTP time server ip address. Uses boot host if not set.
|
||||
|
||||
@@ -24,11 +24,15 @@ else
|
||||
clean$(DIVIDER)$(ARCH) clean:
|
||||
endif
|
||||
|
||||
cdCommands envPaths dllPath.bat relPaths.sh: \
|
||||
cdCommands dllPath.bat relPaths.sh: \
|
||||
$(wildcard $(TOP)/configure/RELEASE*) \
|
||||
$(wildcard $(TOP)/configure/CONFIG_SITE*) $(INSTALL_BIN)
|
||||
$(wildcard $(TOP)/configure/CONFIG_SITE*) | $(INSTALL_BIN)
|
||||
$(CONVERTRELEASE) -a $(ARCH) -t $(IOCS_APPL_TOP) $@
|
||||
|
||||
envPaths: $(wildcard $(TOP)/configure/RELEASE*) \
|
||||
$(wildcard $(TOP)/configure/CONFIG_SITE*) | $(INSTALL_BIN)
|
||||
$(CONVERTRELEASE) -t $(IOCS_APPL_TOP) $@
|
||||
|
||||
realclean:
|
||||
$(RM) cdCommands envPaths dllPath.bat relPaths.sh
|
||||
|
||||
|
||||
@@ -170,7 +170,13 @@ endif
|
||||
$(DIRECTORY_TARGETS) :
|
||||
$(MKDIR) -p $@
|
||||
|
||||
$(PRODNAME): $(INSTALL_LIB_INSTALLS)
|
||||
# Install LIB_INSTALLS libraries before linking executables
|
||||
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS)
|
||||
|
||||
# Install built libraries too, unless Makefile says to wait
|
||||
ifneq ($(DELAY_INSTALL_LIBS),YES)
|
||||
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIBS) $(INSTALL_DLLSTUB_LIBS)
|
||||
endif
|
||||
|
||||
# RELEASE file consistency checking
|
||||
checkRelease:
|
||||
@@ -319,7 +325,9 @@ $(MODNAME): %$(MODEXT): %$(EXE)
|
||||
# Automated testing
|
||||
|
||||
runtests: $(TESTSCRIPTS)
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
|
||||
endif
|
||||
|
||||
testspec: $(TESTSCRIPTS)
|
||||
@$(RM) $@
|
||||
@@ -333,7 +341,9 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
||||
|
||||
# A .tap file is the output from running the associated test script
|
||||
%.tap: %.t
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
-$(PERL) $< -tap > $@
|
||||
endif
|
||||
|
||||
# If there's a perl test script (.plt) available, use it
|
||||
%.t: ../%.plt
|
||||
|
||||
@@ -57,7 +57,7 @@ SHRLIB_LDLIBS = $(addprefix -l, $($*_LDLIBS) $(LIB_LIBS) $(USR_LIBS)) \
|
||||
$(LDLIBS)
|
||||
|
||||
SHRLIB_DEPLIB_DIRS = $(foreach word, \
|
||||
$(sort $(dir $($*_DEPLIBS) $(SHRLIB_DEPLIBS))), \
|
||||
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(SHRLIB_DEPLIBS))), \
|
||||
$(shell $(FULLPATHNAME) $(word)))
|
||||
|
||||
SHRLIBDIR_LDFLAGS += $(SHRLIB_DEPLIB_DIRS:%=-L%)
|
||||
@@ -86,7 +86,7 @@ PROD_LDLIBS += $($(firstword $(LDLIBS_STATIC_$(STATIC_BUILD)) \
|
||||
$(LDLIBS_SHARED_$(SHARED_LIBRARIES))))
|
||||
|
||||
PROD_DEPLIB_DIRS = $(foreach word, \
|
||||
$(sort $(dir $($*_DEPLIBS) $(PROD_DEPLIBS))), \
|
||||
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(PROD_DEPLIBS))), \
|
||||
$(shell $(FULLPATHNAME) $(word)))
|
||||
|
||||
PRODDIR_LDFLAGS += $(PROD_DEPLIB_DIRS:%=-L%)
|
||||
|
||||
@@ -26,14 +26,14 @@ POSIX_LDLIBS += -lpthread
|
||||
ARCH_DEP_CFLAGS += -m32
|
||||
ARCH_DEP_LDFLAGS += -m32
|
||||
|
||||
# Compiler defines _X86_ 1
|
||||
# Compiler defines __MSVCRT__ 1
|
||||
# 32-bit compiler defines _X86_ 1
|
||||
# Compiler defines __CYGWIN__ 1
|
||||
# Compiler defines __CYGWIN32__ 1
|
||||
# 32-bit compiler defines __CYGWIN32__ 1
|
||||
# Compiler defines __unix__ 1
|
||||
# Compiler defines __unix 1
|
||||
# Compiler defines unix 1
|
||||
|
||||
# This macro now deprecated, use __CYGWIN__ in the future
|
||||
OP_SYS_CPPFLAGS += -DCYGWIN32
|
||||
|
||||
EXE = .exe
|
||||
|
||||
33
configure/os/CONFIG.cygwin-x86.linux-arm
Normal file
33
configure/os/CONFIG.cygwin-x86.linux-arm
Normal file
@@ -0,0 +1,33 @@
|
||||
# CONFIG.cygwin-x86.linux-arm
|
||||
#
|
||||
# Definitions for cywgin-x86 host - linux-arm target builds
|
||||
# Override these settings in CONFIG_SITE.cygwin-x86.linux-arm
|
||||
#-------------------------------------------------------
|
||||
|
||||
VALID_BUILDS = Ioc
|
||||
GNU_TARGET = arm-linux
|
||||
|
||||
# prefix of compiler tools
|
||||
CMPLR_SUFFIX =
|
||||
CMPLR_PREFIX = $(addsuffix -,$(GNU_TARGET))
|
||||
|
||||
# Provide a link-time path for shared libraries
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES += $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath-link,%)
|
||||
SHRLIBDIR_LDFLAGS += $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
# Provide a link-time path for products
|
||||
PRODDIR_RPATH_LDFLAGS_YES += $(PROD_DEPLIB_DIRS:%=-Wl,-rpath-link,%)
|
||||
PRODDIR_LDFLAGS += $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
# Provide a link-time path for readline
|
||||
RUNTIME_LDFLAGS_READLINE_YES = -Wl,-rpath-link,$(GNU_DIR)/lib
|
||||
RUNTIME_LDFLAGS_READLINE = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
|
||||
RUNTIME_LDFLAGS_READLINE_CURSES = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
|
||||
RUNTIME_LDFLAGS_READLINE_NCURSES = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
|
||||
|
||||
# Library flags
|
||||
STATIC_LDFLAGS_YES= -Wl,-Bstatic
|
||||
STATIC_LDFLAGS_NO=
|
||||
STATIC_LDLIBS_YES= -Wl,-Bdynamic
|
||||
STATIC_LDLIBS_NO=
|
||||
|
||||
7
configure/os/CONFIG.cygwin-x86_64.linux-arm
Normal file
7
configure/os/CONFIG.cygwin-x86_64.linux-arm
Normal file
@@ -0,0 +1,7 @@
|
||||
# CONFIG.cygwin-x86_64.linux-arm
|
||||
#
|
||||
# Definitions for cygwin-x86_64 host - linux-arkm targets
|
||||
# Override these settings in CONFIG_SITE.cygwin-x86_64.linux-arm
|
||||
#-------------------------------------------------------
|
||||
|
||||
include $(CONFIG)/os/CONFIG.cygwin-x86.linux-arm
|
||||
28
configure/os/CONFIG.linux-x86.windows-x64-mingw
Normal file
28
configure/os/CONFIG.linux-x86.windows-x64-mingw
Normal file
@@ -0,0 +1,28 @@
|
||||
# CONFIG.linux-x86.windows-x64-mingw
|
||||
#
|
||||
# Definitions for linux-x86 host windows-x64-mingw target builds
|
||||
# Override these definitions in CONFIG_SITE.linux-x86.windows-x64-mingw
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Include common gnu compiler definitions
|
||||
include $(CONFIG)/CONFIG.gnuCommon
|
||||
|
||||
# Add resource compiler
|
||||
RCCMD = $(GNU_BIN)/$(CMPLR_PREFIX)windres$(CMPLR_SUFFIX) $(INCLUDES) $< $@
|
||||
|
||||
# Remove -fPIC flags, add out-implib
|
||||
SHRLIB_CFLAGS =
|
||||
SHRLIB_LDFLAGS = -shared \
|
||||
-Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX)
|
||||
LOADABLE_SHRLIB_LDFLAGS = -shared \
|
||||
-Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX)
|
||||
|
||||
# No need to explicitly link with gcc library
|
||||
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
|
||||
9
configure/os/CONFIG.linux-x86_64.windows-x64-mingw
Normal file
9
configure/os/CONFIG.linux-x86_64.windows-x64-mingw
Normal file
@@ -0,0 +1,9 @@
|
||||
# CONFIG.linux-x86_64.windows-x64-mingw
|
||||
#
|
||||
# Definitions for linux-x86_64 host windows-x64-mingw target builds
|
||||
# Override these definitions in CONFIG_SITE.linux-x86_64.windows-x64-mingw
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Settings as for the linux-x86 host architecture
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.windows-x64-mingw
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
# Site override definitions for cygwin-x86 host builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
#CROSS_COMPILER_TARGET_ARCHS =
|
||||
#CROSS_COMPILER_TARGET_ARCHS = linux-arm
|
||||
|
||||
|
||||
16
configure/os/CONFIG_SITE.cygwin-x86.linux-arm
Normal file
16
configure/os/CONFIG_SITE.cygwin-x86.linux-arm
Normal file
@@ -0,0 +1,16 @@
|
||||
# CONFIG_SITE.cygwin-x86.linux-arm
|
||||
#
|
||||
# $Revision-Id$
|
||||
#
|
||||
# Site specific definitions for cygwin-x86 host - linux-arm target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Tools install path
|
||||
GNU_DIR = /usr/local/arm-linux
|
||||
|
||||
# GNU crosscompiler target name
|
||||
GNU_TARGET = arm-linux
|
||||
|
||||
STATIC_BUILD = YES
|
||||
SHARED_LIBRARIES = NO
|
||||
|
||||
16
configure/os/CONFIG_SITE.cygwin-x86_64.linux-arm
Normal file
16
configure/os/CONFIG_SITE.cygwin-x86_64.linux-arm
Normal file
@@ -0,0 +1,16 @@
|
||||
# CONFIG_SITE.cygwin-x86_64.linux-arm
|
||||
#
|
||||
# $Revision-Id$
|
||||
#
|
||||
# Site specific definitions for cygwin-x86_64 host - linux-arm target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Tools install path
|
||||
GNU_DIR = /usr/local/arm-linux
|
||||
|
||||
# GNU crosscompiler target name
|
||||
GNU_TARGET = arm-linux
|
||||
|
||||
STATIC_BUILD = YES
|
||||
SHARED_LIBRARIES = NO
|
||||
|
||||
20
configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
Normal file
20
configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
Normal file
@@ -0,0 +1,20 @@
|
||||
# CONFIG_SITE.linux-x86.windows-x64-mingw
|
||||
#
|
||||
# Configuration for linux-x86 host windows-x64-mingw target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# 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
|
||||
|
||||
# The cross-build tools are in $(GNU_DIR)/bin
|
||||
# Default is /usr
|
||||
#GNU_DIR = /usr/local
|
||||
|
||||
# Different distribution cross-build packages use different prefixes:
|
||||
# Ubuntu:
|
||||
#CMPLR_PREFIX = i686-w64-mingw32-
|
||||
# RHEL:
|
||||
CMPLR_PREFIX = x86_64-w64-mingw32-
|
||||
8
configure/os/CONFIG_SITE.linux-x86_64.windows-x64-mingw
Normal file
8
configure/os/CONFIG_SITE.linux-x86_64.windows-x64-mingw
Normal file
@@ -0,0 +1,8 @@
|
||||
# CONFIG_SITE.linux-x86_64.windows-x64-mingw
|
||||
#
|
||||
# Configuration for linux-x86_64 host windows-x64-mingw target builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Inherit from the linux-x86 host architecture
|
||||
include $(CONFIG)/os/CONFIG_SITE.linux-x86.windows-x64-mingw
|
||||
|
||||
@@ -22,6 +22,13 @@ version of EPICS Base:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>See LaunchPad bug
|
||||
<a href="https://bugs.launchpad.net/epics-base/+bug/1466129">#1466129</a>:
|
||||
The feature that allows an IOC to bind to a single network interface is not
|
||||
working correctly. The bug mentioned above contains a patch that has been
|
||||
tested on Linux-64, a complete fix is expected for 3.15.4. Note that Windows
|
||||
systems are not affected by this bug.</li>
|
||||
|
||||
<li>Parallel builds ("make -j") on native Windows are not working properly.
|
||||
Builds tend to hang (saturating one core); interrupting and running make
|
||||
again usually finishes the build. Limiting the number of parallel jobs using
|
||||
|
||||
@@ -3,17 +3,227 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<title>EPICS Base R3.15.3 Release Notes</title>
|
||||
<title>EPICS Base R3.15.4 Release Notes</title>
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 align="center">EPICS Base Release 3.15.3</h1>
|
||||
<h1 align="center">EPICS Base Release 3.15.4</h1>
|
||||
|
||||
<p style="color:red">This version of EPICS Base has not been released yet.</p>
|
||||
|
||||
<h2 align="center">Changes between 3.15.2 and 3.15.3</h2>
|
||||
|
||||
<h2 align="center">Changes made on the 3.15 branch since 3.15.3</h2>
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>New string input device support "getenv"</h3>
|
||||
|
||||
<p>A new "getenv" device support for both the stringin and lsi (long string
|
||||
input) record types can be used to read the value of an environment variable
|
||||
from the IOC at runtime. See base/db/softIocExit.db for sample usage.</p>
|
||||
|
||||
<h3>Build rules and DELAY_INSTALL_LIBS</h3>
|
||||
|
||||
<p>A new order-only prerequisite build rule has been added to ensure that
|
||||
library files (and DLL stubs on Windows) get installed before linking any
|
||||
executables, which resolves parallel build problems on high-powered CPUs. There
|
||||
are some (rare) cases though where a Makefile has to build an executable and run
|
||||
it to be able to compile code for a library built by the same Makefile. With
|
||||
this new build rule GNUmake will complain about a circular dependency and the
|
||||
build will probably fail in those cases. To avoid this problem the failing
|
||||
Makefile should set <tt>DELAY_INSTALL_LIBS = YES</tt> before including the
|
||||
<tt>$(TOP)/configure/RULES</tt> file, disabling the new build rule.</p>
|
||||
|
||||
<h3>IOC environment variables and build parameters</h3>
|
||||
|
||||
<p>The IOC now sets a number of environment variables at startup that provide
|
||||
the version of EPICS Base it was built against (EPICS_VERSION_...) and its build
|
||||
architecture (ARCH). In some cases this allows a single iocBoot/ioc directory to
|
||||
be used to run the same IOC on several different architectures without any
|
||||
changes.</p>
|
||||
|
||||
<p>There are also 3 new environment parameters (EPICS_BUILD_...) available that
|
||||
C/C++ code can use to find out the target architecture, OS class and compiler
|
||||
class it was built with. These may be useful when writing interfaces to other
|
||||
languages.</p>
|
||||
|
||||
<h3>New implementation of promptgroup/gui_group field property</h3>
|
||||
|
||||
<p>The mechanism behind the "promptgroup()" field property inside a record type
|
||||
definition has been changed. Instead of using a fixed set of choices,
|
||||
the static database access library now collects the used gui group names
|
||||
while parsing DBD information. Group names should start with a two-digit number
|
||||
plus space-dash-space to allow proper sorting of groups.</p>
|
||||
|
||||
<p>The include file <tt>guigroup.h</tt> that defined the fixed set of choices
|
||||
has been deprecated. Instead, use the conversion functions between index number
|
||||
and group string that have been added to dbStaticLib.</p>
|
||||
|
||||
<h3>CA server configuration changes</h3>
|
||||
|
||||
<p>RSRV now honors EPICS_CAS_INTF_ADDR_LIST and binds only to the provided list
|
||||
of network interfaces. Name searches (UDP and TCP) on other network interfaces
|
||||
are ignored. For example on a computer with interfaces 10.5.1.1/24, 10.5.2.1/24,
|
||||
and 10.5.3.1/24, setting "EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'" will
|
||||
accept traffic on the .1.1 and .2.1, but ignore from .3.1</p>
|
||||
|
||||
<p>RSRV now honors EPICS_CAS_IGNORE_ADDR_LIST and ignores UDP messages received
|
||||
from addresses in this list.</p>
|
||||
|
||||
<p>Previously, CA servers (RSRV and PCAS) would build the beacon address list
|
||||
using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set. This is no
|
||||
longer done. Sites depending on this should set both envronment variables to the
|
||||
same value.</p>
|
||||
|
||||
<h3>IPv4 multicast for name search and beacons</h3>
|
||||
|
||||
<p>libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name
|
||||
search and beacons). This is disabled by default. To enable multicast address(s)
|
||||
must be listed in EPICS_CA_ADDR_LIST for clients and EPICS_CAS_INTF_ADDR_LIST
|
||||
for servers (IOCs should set both). For example:
|
||||
"EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9".</p>
|
||||
|
||||
<p>Please note that no IPv4 multicast address is officially assigned for Channel
|
||||
Access by IANA. The example 224.0.2.9 is taken from the AD-HOC Block I range.<p>
|
||||
|
||||
<h3>Moved <tt>mlockall()</tt> into its own epicsThread routine</h3>
|
||||
|
||||
<p>Since EPICS Base 3.15.0.2 on Posix OSs the initialization of the epicsThread
|
||||
subsystem has called <tt>mlockall()</tt> when the OS supports it and thread
|
||||
priority scheduling is enabled. Doing so has caused problems in third-party
|
||||
applications that call the CA client library, so the functionality has been
|
||||
moved to a separate routine <tt>epicsThreadRealtimeLock()</tt> which will be
|
||||
called by the IOC at iocInit (unless disabled by setting the global variable
|
||||
<tt>dbThreadRealtimeLock</tt> to zero).</p>
|
||||
|
||||
<h3>Added dbQuietMacroWarnings control</h3>
|
||||
|
||||
<p>When loading database files, macros get expanded even on comment lines. If a
|
||||
comment contains an undefined macro, the load still continues but an error
|
||||
message gets printed. For this release the error message has been changed to a
|
||||
warning, but even this warning can be made less verbose by setting this new
|
||||
variable to a non-zero value before loading the file, like this:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
var dbQuietMacroWarnings 1 <i>iocsh</i>
|
||||
dbQuietMacroWarnings=1 <i>VxWorks</i>
|
||||
</pre></blockquote>
|
||||
|
||||
<p>This was <a href="https://bugs.launchpad.net/bugs/541119">Launchpad bug
|
||||
541119</a>.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes pulled from the 3.14 branch since 3.15.3</h2>
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Making IOC ca_get operations atomic</h3>
|
||||
|
||||
<p>When a CA client gets data from an IOC record using a compound data type such
|
||||
as <tt>DBR_TIME_DOUBLE</tt> the value field is fetched from the database in a
|
||||
separate call than the other metadata, without keeping the record locked. This
|
||||
allows some other thread such as a periodic scan thread a chance to interrupt
|
||||
the get operation and process the record in between. CA monitors have always
|
||||
been atomic as long as the value data isn't a string or an array, but this race
|
||||
condition in the CA get path has now been fixed so the record will stay locked
|
||||
between the two fetch operations.</p>
|
||||
|
||||
<p>This fixes <a href="https://bugs.launchpad.net/epics-base/+bug/1581212">
|
||||
Launchpad bug #1581212</a>, thanks to Till Strauman and Dehong Zhang.</p>
|
||||
|
||||
<h3>New CONFIG_SITE variable for running self-tests</h3>
|
||||
|
||||
<p>The 'make runtests' and 'make tapfiles' build targets normally only run the
|
||||
self-tests for the main <tt>EPICS_HOST_ARCH</tt> architecture. If the host is
|
||||
able to execute self-test programs for other target architectures that are being
|
||||
built by the host, such as when building a <tt>-debug</tt> version of the host
|
||||
architecture for example, the names of those other architectures can be added to
|
||||
the new <tt>CROSS_COMPILER_RUNTEST_ARCHS</tt> variable in either the
|
||||
<tt>configure/CONFIG_SITE</tt> file or in an appropriate
|
||||
<tt>configure/os/CONFIG_SITE.<host>.Common</tt> file to have the test
|
||||
programs for those targets be run as well.</p>
|
||||
|
||||
<h3>Additional RELEASE file checks</h3>
|
||||
|
||||
<p>An additional check has been added at build-time for the contents of the
|
||||
configure/RELEASE file(s), which will mostly only affect users of the Debian
|
||||
EPICS packages published by NSLS-2. Support modules may share an install path,
|
||||
but all such modules must be listed adjacent to each other in any RELEASE files
|
||||
that point to them. For example the following will fail the new checks:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
AUTOSAVE = /usr/lib/epics
|
||||
ASYN = /home/mdavidsaver/asyn
|
||||
EPICS_BASE = /usr/lib/epics
|
||||
</pre></blockquote>
|
||||
|
||||
<p>giving the compile-time error</p>
|
||||
|
||||
<blockquote><pre>
|
||||
This application's RELEASE file(s) define
|
||||
EPICS_BASE = /usr/lib/epics
|
||||
after but not adjacent to
|
||||
AUTOSAVE = /usr/lib/epics
|
||||
Module definitions that share paths must be grouped together.
|
||||
Either remove a definition, or move it to a line immediately
|
||||
above or below the other(s).
|
||||
Any non-module definitions belong in configure/CONFIG_SITE.
|
||||
</pre></blockquote>
|
||||
|
||||
|
||||
<p>In many cases such as the one above the order of the <tt>AUTOSAVE</tt> and
|
||||
<tt>ASYN</tt> lines can be swapped to let the checks pass, but if the
|
||||
<tt>AUTOSAVE</tt> module depended on <tt>ASYN</tt> and hence had to appear
|
||||
before it in the list this error indicates that <tt>AUTOSAVE</tt> should also be
|
||||
built in its own private area; a shared copy would likely be incompatible with
|
||||
the version of <tt>ASYN</tt> built in the home directory.</p>
|
||||
|
||||
<h3>String field buffer overflows</h3>
|
||||
|
||||
<p>Two buffer overflow bugs that can crash the IOC have been fixed, caused by
|
||||
initializing a string field with a value larger than the field size
|
||||
(<a href="https://bugs.launchpad.net/bugs/1563191">Launchpad bug
|
||||
#1563191</a>).</p>
|
||||
|
||||
<h3>Fixed stack corruption bug in epicsThread C++ API</h3>
|
||||
|
||||
<p>The C++ interface to the epicsThread API could corrupt the stack on thread
|
||||
exit in some rare circumstances, usually at program exit. This bug has been
|
||||
fixed (<a href="https://bugs.launchpad.net/bugs/1558206">Launchpad bug
|
||||
#1558206</a>).</p>
|
||||
|
||||
<h3>RTEMS NTP Support Issue</h3>
|
||||
|
||||
<p>On RTEMS the NTP Time Provider could in some circumstances get out of sync
|
||||
with the server because the osdNTPGet() code wasn't clearing its input socket
|
||||
before sending out a new request. This
|
||||
(<a href="https://bugs.launchpad.net/bugs/1549908">Launchpad bug 1549908</a>)
|
||||
has now been fixed.</p>
|
||||
|
||||
<h3>CALC engine bitwise operator fixes</h3>
|
||||
|
||||
<p>The bitwise operators in the CALC engine have been modified to work properly
|
||||
with values that have bit 31 (0x80000000) set. This modification involved
|
||||
back-porting some earlier changes from the 3.15 branch, and fixes
|
||||
<a href="https://code.launchpad.net/bugs/1514520">Launchpad bug
|
||||
#1514520</a>.</p>
|
||||
|
||||
<h3>Fix <tt>ipAddrToAsciiAsync()</tt>: Don't try to join the daemon thread</h3>
|
||||
|
||||
<p>On process exit, don't try to stop the worker thread that makes DNS lookups
|
||||
asynchronous. Previously this would wait for any lookups still in progress,
|
||||
delaying the exit unnecessarily. This was most obvious with catools (eg.
|
||||
cainfo).
|
||||
<a href="https://bugs.launchpad.net/bugs/1527636">lp:1527636</a></p>
|
||||
|
||||
<h3>Fix <tt>epicsTime_localtime()</tt> on Windows</h3>
|
||||
|
||||
<p>Simpler versions of the epicsTime_gmtime() and epicsTime_localtime()
|
||||
routines have been included in the Windows implementations, and a new test
|
||||
program added. The original versions do not report DST status properly. Fixes
|
||||
<a href="https://bugs.launchpad.net/bugs/1528284">Launchpad bug 1528284</a>.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes between 3.15.2 and 3.15.3</h2>
|
||||
|
||||
<h3>Make the NTP Time provider optional on VxWorks</h3>
|
||||
|
||||
<p>Recent versions of VxWorks (sometime after VxWorks 6) provide facilities for
|
||||
@@ -52,6 +262,7 @@ time, but there was still one implementation left in the event record support
|
||||
code, and a structure definition for one of the original arguments to that
|
||||
routine was defined in recGbl.h. Both of these have now been removed.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes between 3.15.1 and 3.15.2</h2>
|
||||
|
||||
<h3>Raised limit on link field length in database files</h3>
|
||||
@@ -170,6 +381,7 @@ use a modified version of msi must provide support for both the <tt>-D</tt> and
|
||||
<tt>-o outfile</tt> options, and should then point the MSI3_15 variable in
|
||||
their applications' CONFIG_SITE files to that updated executable.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes between 3.15.0.2 and 3.15.1</h2>
|
||||
|
||||
<h3>epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()</h3>
|
||||
|
||||
@@ -841,23 +841,18 @@ seconds. See also <a href="#Disconnect">EPICS_CA_CONN_TMO</a> and
|
||||
Interval</a>.</p>
|
||||
|
||||
<p>CA servers build a list of addresses to send beacons to during
|
||||
initialization. If EPICS_CAS_AUTO_BEACON_ADDR_LIST has the value "YES" then the
|
||||
beacon address list will be automatically configured to contain the broadcast
|
||||
addresses of all LAN interfaces found in the host and the destination address
|
||||
of all point-to-point interfaces found in the host. However, if the user also
|
||||
initialization. If EPICS_CAS_AUTO_BEACON_ADDR_LIST has the value "YES"
|
||||
(the default) this list will be automatically populated with the broadcast
|
||||
addresses of all network interfaces. However, if the user also
|
||||
defines EPICS_CAS_INTF_ADDR_LIST then beacon address list automatic
|
||||
configuration is constrained to the network interfaces specified therein, and
|
||||
therefore only the broadcast addresses of the specified LAN interfaces, and the
|
||||
destination addresses of all specified point-to-point links, will be
|
||||
therefore only the broadcast addresses of the specified LAN interfaces, will be
|
||||
automatically configured.</p>
|
||||
|
||||
<p>If EPICS_CAS_BEACON_ADDR_LIST is defined then its contents will be used to
|
||||
augment any automatic configuration of the beacon address list. Individual
|
||||
entries in EPICS_CAS_BEACON_ADDR_LIST may override the destination port number
|
||||
if ":nnn" follows the host name or IP address there. Alternatively, when both
|
||||
EPICS_CAS_BEACON_ADDR_LIST and EPICS_CAS_INTF_ADDR_LIST are not defined then
|
||||
the contents of EPICS_CA_ADDR_LIST is used to augment the list. Otherwise, the
|
||||
list is not augmented.</p>
|
||||
if ":nnn" follows the host name or IP address there.</p>
|
||||
|
||||
<p>The EPICS_CAS_BEACON_PORT parameter specifies the destination port for
|
||||
server beacons. The only exception to this occurs when ports are specified in
|
||||
@@ -868,20 +863,18 @@ specified in EPICS_CA_REPEATER_PORT.</p>
|
||||
<h4>Binding a Server to a Limited Set of Network Interfaces</h4>
|
||||
|
||||
<p>The parameter EPICS_CAS_INTF_ADDR_LIST allows a ca server to bind itself to,
|
||||
and therefore accept messages only over, a limited set of the local host's
|
||||
and therefore accept messages received by, a limited set of the local host's
|
||||
network interfaces (each specified by its IP address). On UNIX systems type
|
||||
"netstat -i" (type "ipconfig" on windows) to see a list of the local host's
|
||||
network interfaces. Specifically, UDP search messages addressed to both the IP
|
||||
addresses in EPICS_CAS_INTF_ADDR_LIST and also to the broadcast addresses of
|
||||
the corresponding LAN interfaces will be accepted by the server. By default,
|
||||
"netstat -ie" (type "ipconfig" on windows) to see a list of the local host's
|
||||
network interfaces. By default,
|
||||
the CA server is accessible from all network interfaces configured into its
|
||||
host.</p>
|
||||
|
||||
<p>In R3.14 and previous releases the CA server employed by iocCore did not
|
||||
implement the EPICS_CAS_INTF_ADDR_LIST feature. In this release the iocCore
|
||||
server will read the first IP address from the parameter variable and use that
|
||||
to select which interface to bind to. Any additional IP addresses will be
|
||||
ignored and a warning message displayed during IOC initialization.</p>
|
||||
<p>Until R3.15.4 the CA server employed by iocCore did not
|
||||
implement the EPICS_CAS_INTF_ADDR_LIST feature.</p>
|
||||
|
||||
<p>Prior to R3.15.4 CA servers would build the beacon address list
|
||||
using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set.</p>
|
||||
|
||||
<h4>Ignoring Process Variable Name Resolution Requests From Certain Hosts</h4>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ extern "C" {
|
||||
epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
|
||||
( struct ELLLIST *pList, SOCKET sock, unsigned short port );
|
||||
|
||||
epicsShareFunc void epicsShareAPI addAddrToChannelAccessAddressList
|
||||
epicsShareFunc int epicsShareAPI addAddrToChannelAccessAddressList
|
||||
( struct ELLLIST *pList, const ENV_PARAM *pEnv,
|
||||
unsigned short port, int ignoreNonDefaultPort );
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
|
||||
/*
|
||||
* addAddrToChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
|
||||
extern "C" int epicsShareAPI addAddrToChannelAccessAddressList
|
||||
( ELLLIST *pList, const ENV_PARAM *pEnv,
|
||||
unsigned short port, int ignoreNonDefaultPort )
|
||||
{
|
||||
@@ -82,11 +82,11 @@ extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[32u]; /* large enough to hold an IP address */
|
||||
int status;
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
if (!pStr) {
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
|
||||
@@ -104,7 +104,7 @@ extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
@@ -113,9 +113,10 @@ extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
}
|
||||
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1138,6 +1138,20 @@ void CA_add_exception_event(const char *class, SV *sub) {
|
||||
static
|
||||
SV * printf_sub = NULL;
|
||||
|
||||
#ifndef va_copy
|
||||
# ifdef __GNUC__
|
||||
# define va_copy(d, s) __va_copy(d, s)
|
||||
# else
|
||||
# define va_copy(d, s) ((d) = (s))
|
||||
/* The above macro is NOT PORTABLE but works on Windows when
|
||||
* stdarg.h doesn't provide va_copy(). Some architectures need
|
||||
* define va_copy(d, s) ((*d) = (*s))
|
||||
* while others may be even more complicated, but hopefully the
|
||||
* system stdarg.h header defines va_copy() in those cases.
|
||||
*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static
|
||||
int printf_handler(const char *format, va_list args) {
|
||||
if (! printf_sub)
|
||||
@@ -1152,11 +1166,7 @@ int printf_handler(const char *format, va_list args) {
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__va_copy(argcopy, args);
|
||||
#else
|
||||
va_copy(argcopy, args);
|
||||
#endif
|
||||
|
||||
printf_str = NEWSV(0, strlen(format) + 32);
|
||||
sv_vsetpvf(printf_str, format, &argcopy);
|
||||
|
||||
@@ -20,10 +20,19 @@ ifeq ($(OS_CLASS),Darwin)
|
||||
LOADABLE_SHRLIB_SUFFIX = .$(shell $(PERL) ../perlConfig.pl dlext)
|
||||
endif
|
||||
|
||||
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
|
||||
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
|
||||
PERL_ARCHPATH = $(PERL_VERSION)/$(PERL_ARCHNAME)
|
||||
ifdef T_A
|
||||
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
|
||||
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
|
||||
PERL_ARCHPATH := $(PERL_VERSION)/$(PERL_ARCHNAME)
|
||||
|
||||
EXTUTILS := $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
|
||||
PERLBIN := $(shell $(PERL) ../perlConfig.pl bin)
|
||||
XSUBPP := $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
|
||||
|
||||
ifeq ($(strip $(XSUBPP)),)
|
||||
$(warning Perl's xsubpp program was not found.)
|
||||
$(warning The Perl CA module will not be built.)
|
||||
else
|
||||
ifeq ($(T_A),$(EPICS_HOST_ARCH)) # No cross-builds (wrong Perl!)
|
||||
ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
|
||||
LOADABLE_LIBRARY_HOST = Cap5
|
||||
@@ -41,6 +50,8 @@ ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
|
||||
HTMLS = CA.html
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
Cap5_SRCS = Cap5.xs
|
||||
Cap5_LIBS = ca Com
|
||||
@@ -52,10 +63,6 @@ CLEANS += Cap5.c pod2htmd.tmp pod2htmi.tmp
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
ifdef T_A
|
||||
EXTUTILS = $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
|
||||
PERLBIN = $(shell $(PERL) ../perlConfig.pl bin)
|
||||
XSUBPP = $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
|
||||
|
||||
%.c: ../%.xs
|
||||
$(RM) $@ $@_new
|
||||
$(PERL) $(XSUBPP) -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
# This script is used to extract information about the Perl build
|
||||
# configuration, so the EPICS build system uses the same settings.
|
||||
|
||||
use strict;
|
||||
use Config;
|
||||
|
||||
my $arg = shift;
|
||||
print $Config{$arg};
|
||||
my $val = $Config{$arg};
|
||||
|
||||
$val =~ s{\\}{/}go
|
||||
if $^O eq 'MSWin32';
|
||||
|
||||
print $val;
|
||||
|
||||
@@ -163,6 +163,19 @@ udpiiu::udpiiu (
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
|
||||
#ifdef IP_ADD_MEMBERSHIP
|
||||
{
|
||||
int flag = 1;
|
||||
if ( setsockopt ( this->sock, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
(char *) &flag, sizeof ( flag ) ) == -1 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf("CAC: failed to set mcast loopback\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int boolValue = true;
|
||||
int status = setsockopt ( this->sock, SOL_SOCKET, SO_BROADCAST,
|
||||
(char *) &boolValue, sizeof ( boolValue ) );
|
||||
|
||||
@@ -69,6 +69,11 @@ CLEANS += $(COMMON_DIR)/aitConvertGenerated.cc
|
||||
USR_CXXFLAGS_Linux = -fno-strict-aliasing
|
||||
USR_CXXFLAGS_RTEMS = -fno-strict-aliasing
|
||||
|
||||
ifeq ($(T_A),$(EPICS_HOST_ARCH))
|
||||
# genApps and aitGen are needed to finish libgdd
|
||||
DELAY_INSTALL_LIBS = YES
|
||||
endif
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
# Manual dependencies
|
||||
|
||||
@@ -141,6 +141,39 @@ caStatus caServerI::attachInterface ( const caNetAddr & addrIn,
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
void caServerI::addMCast(const osiSockAddr& addr)
|
||||
{
|
||||
#ifdef IP_ADD_MEMBERSHIP
|
||||
epicsGuard < epicsMutex > locker ( this->mutex );
|
||||
tsDLIter < casIntfOS > iter = this->intfList.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
struct ip_mreq mreq;
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.imr_interface = iter->serverAddress().getSockIP().sin_addr;
|
||||
mreq.imr_multiaddr = addr.ia.sin_addr;
|
||||
|
||||
if ( setsockopt ( iter->casDGIntfIO::getFD (), IPPROTO_IP,
|
||||
IP_ADD_MEMBERSHIP, (char *) &mreq,
|
||||
sizeof ( mreq ) ) < 0) {
|
||||
struct sockaddr_in temp;
|
||||
char name[40];
|
||||
char sockErrBuf[64];
|
||||
temp.sin_family = AF_INET;
|
||||
temp.sin_addr = mreq.imr_multiaddr;
|
||||
temp.sin_port = addr.ia.sin_port;
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToDottedIP (&temp, name, sizeof(name));
|
||||
fprintf(stderr, "CAS: Socket mcast join %s failed with \"%s\"\n",
|
||||
name, sockErrBuf );
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void caServerI::sendBeacon ( ca_uint32_t beaconNo )
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->mutex );
|
||||
|
||||
@@ -103,6 +103,8 @@ private:
|
||||
caStatus attachInterface ( const caNetAddr & addr, bool autoBeaconAddr,
|
||||
bool addConfigAddr );
|
||||
|
||||
virtual void addMCast(const osiSockAddr&);
|
||||
|
||||
void sendBeacon ( ca_uint32_t beaconNo );
|
||||
|
||||
caServerI ( const caServerI & );
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
//
|
||||
|
||||
#include <ctype.h>
|
||||
#include <list>
|
||||
|
||||
#include "epicsSignal.h"
|
||||
#include "envDefs.h"
|
||||
@@ -92,6 +93,9 @@ void caServerIO::locateInterfaces ()
|
||||
autoBeaconAddr = true;
|
||||
}
|
||||
|
||||
typedef std::list<osiSockAddr> mcastAddrs_t;
|
||||
mcastAddrs_t mcastAddrs;
|
||||
|
||||
//
|
||||
// bind to the the interfaces specified - otherwise wildcard
|
||||
// with INADDR_ANY and allow clients to attach from any interface
|
||||
@@ -114,6 +118,15 @@ void caServerIO::locateInterfaces ()
|
||||
pToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
epicsUInt32 top = ntohl(saddr.sin_addr.s_addr)>>24;
|
||||
if (saddr.sin_family==AF_INET && top>=224 && top<=239) {
|
||||
osiSockAddr oaddr;
|
||||
oaddr.ia = saddr;
|
||||
mcastAddrs.push_back(oaddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
stat = this->attachInterface (caNetAddr(saddr), autoBeaconAddr, configAddrOnceFlag);
|
||||
if (stat) {
|
||||
errMessage(stat, "unable to attach explicit interface");
|
||||
@@ -131,6 +144,10 @@ void caServerIO::locateInterfaces ()
|
||||
errMessage(stat, "unable to attach any interface");
|
||||
}
|
||||
}
|
||||
|
||||
for (mcastAddrs_t::const_iterator it = mcastAddrs.begin(); it!=mcastAddrs.end(); ++it) {
|
||||
this->addMCast(*it);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -47,6 +47,8 @@ private:
|
||||
virtual caStatus attachInterface (
|
||||
const caNetAddr & addr, bool autoBeaconAddr,
|
||||
bool addConfigAddr ) = 0;
|
||||
|
||||
virtual void addMCast(const osiSockAddr&) = 0;
|
||||
};
|
||||
|
||||
#endif // caServerIOh
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
#include "addrList.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "casDGIntfIO.h"
|
||||
#include "ipIgnoreEntry.h"
|
||||
@@ -148,26 +153,8 @@ casDGIntfIO::casDGIntfIO ( caServerI & serverIn, clientBufMemoryManager & memMgr
|
||||
}
|
||||
|
||||
if ( addConfigBeaconAddr ) {
|
||||
|
||||
//
|
||||
// by default use EPICS_CA_ADDR_LIST for the
|
||||
// beacon address list
|
||||
//
|
||||
const ENV_PARAM *pParam;
|
||||
|
||||
if ( envGetConfigParamPtr ( & EPICS_CAS_INTF_ADDR_LIST ) ||
|
||||
envGetConfigParamPtr ( & EPICS_CAS_BEACON_ADDR_LIST ) ) {
|
||||
pParam = & EPICS_CAS_BEACON_ADDR_LIST;
|
||||
}
|
||||
else {
|
||||
pParam = & EPICS_CA_ADDR_LIST;
|
||||
}
|
||||
|
||||
//
|
||||
// add in the configured addresses
|
||||
//
|
||||
addAddrToChannelAccessAddressList (
|
||||
& BCastAddrList, pParam, beaconPort, pParam == & EPICS_CA_ADDR_LIST );
|
||||
& BCastAddrList, &EPICS_CAS_BEACON_ADDR_LIST, beaconPort, 0 );
|
||||
}
|
||||
|
||||
removeDuplicateAddresses ( & this->beaconAddrList, & BCastAddrList, 0 );
|
||||
@@ -267,7 +254,7 @@ casDGIntfIO::~casDGIntfIO()
|
||||
|
||||
// avoid use of ellFree because problems on windows occur if the
|
||||
// free is in a different DLL than the malloc
|
||||
ELLNODE * nnode = this->beaconAddrList.node.next;
|
||||
ELLNODE * nnode = ellFirst(&this->beaconAddrList);
|
||||
while ( nnode )
|
||||
{
|
||||
ELLNODE * pnode = nnode;
|
||||
@@ -418,52 +405,24 @@ bufSizeT casDGIntfIO ::
|
||||
}
|
||||
|
||||
void casDGIntfIO::sendBeaconIO ( char & msg, unsigned length,
|
||||
aitUint16 & portField, aitUint32 & addrField )
|
||||
aitUint16 & portField, aitUint32 & )
|
||||
{
|
||||
caNetAddr addr = this->serverAddress ();
|
||||
struct sockaddr_in inetAddr = addr.getSockIP();
|
||||
osiSockAddrNode *pAddr;
|
||||
int status;
|
||||
char buf[64];
|
||||
|
||||
portField = inetAddr.sin_port; // the TCP port
|
||||
|
||||
for (pAddr = reinterpret_cast <osiSockAddrNode *> ( ellFirst ( & this->beaconAddrList ) );
|
||||
pAddr; pAddr = reinterpret_cast <osiSockAddrNode *> ( ellNext ( & pAddr->node ) ) ) {
|
||||
status = connect ( this->beaconSock, &pAddr->addr.sa, sizeof ( pAddr->addr.sa ) );
|
||||
if (status<0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToDottedIP ( & pAddr->addr.ia, buf, sizeof ( buf ) );
|
||||
errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n",
|
||||
__FILE__, buf, sockErrBuf );
|
||||
}
|
||||
else {
|
||||
osiSockAddr sockAddr;
|
||||
osiSocklen_t size = ( osiSocklen_t ) sizeof ( sockAddr.sa );
|
||||
status = getsockname ( this->beaconSock, &sockAddr.sa, &size );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n",
|
||||
__FILE__, sockErrBuf );
|
||||
}
|
||||
else if ( sockAddr.sa.sa_family == AF_INET ) {
|
||||
addrField = sockAddr.ia.sin_addr.s_addr;
|
||||
for (ELLNODE *pNode = ellFirst(&this->beaconAddrList); pNode; pNode = ellNext(pNode))
|
||||
{
|
||||
osiSockAddrNode *pAddr = reinterpret_cast<osiSockAddrNode *>(pNode);
|
||||
|
||||
status = send ( this->beaconSock, &msg, length, 0 );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToA ( &pAddr->addr.ia, buf, sizeof(buf) );
|
||||
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
|
||||
__FILE__, buf, sockErrBuf );
|
||||
}
|
||||
else {
|
||||
unsigned statusAsLength = static_cast < unsigned > ( status );
|
||||
assert ( statusAsLength == length );
|
||||
}
|
||||
}
|
||||
ssize_t status = sendto(this->beaconSock, &msg, length, 0, &pAddr->addr.sa, sizeof(pAddr->addr.ia));
|
||||
if ( status != length ) {
|
||||
char sockErrBuf[64], buf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToA ( &pAddr->addr.ia, buf, sizeof(buf) );
|
||||
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\" (%u)\n",
|
||||
__FILE__, buf, sockErrBuf, (unsigned)status );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,19 +402,29 @@ struct rset * dbGetRset(const struct dbAddr *paddr)
|
||||
}
|
||||
|
||||
long dbPutAttribute(
|
||||
const char *recordTypename,const char *name,const char*value)
|
||||
const char *recordTypename, const char *name, const char *value)
|
||||
{
|
||||
DBENTRY dbEntry;
|
||||
DBENTRY *pdbEntry = &dbEntry;
|
||||
long status=0;
|
||||
DBENTRY dbEntry;
|
||||
DBENTRY *pdbEntry = &dbEntry;
|
||||
long status = 0;
|
||||
|
||||
if(!pdbbase) return(S_db_notFound);
|
||||
dbInitEntry(pdbbase,pdbEntry);
|
||||
status = dbFindRecordType(pdbEntry,recordTypename);
|
||||
if(!status) status = dbPutRecordAttribute(pdbEntry,name,value);
|
||||
dbFinishEntry(pdbEntry);
|
||||
if(status) errMessage(status,"dbPutAttribute failure");
|
||||
return(status);
|
||||
if (!pdbbase)
|
||||
return S_db_notFound;
|
||||
if (!name) {
|
||||
status = S_db_badField;
|
||||
goto done;
|
||||
}
|
||||
if (!value)
|
||||
value = "";
|
||||
dbInitEntry(pdbbase, pdbEntry);
|
||||
status = dbFindRecordType(pdbEntry, recordTypename);
|
||||
if (!status)
|
||||
status = dbPutRecordAttribute(pdbEntry, name, value);
|
||||
dbFinishEntry(pdbEntry);
|
||||
done:
|
||||
if (status)
|
||||
errMessage(status, "dbPutAttribute failure");
|
||||
return status;
|
||||
}
|
||||
|
||||
int dbIsValueField(const struct dbFldDes *pdbFldDes)
|
||||
@@ -812,11 +822,10 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
void *pbuffer, long *options, long *nRequest, void *pflin)
|
||||
{
|
||||
char *pbuf = pbuffer;
|
||||
void *pfieldsave;
|
||||
void *pfieldsave = paddr->pfield;
|
||||
db_field_log *pfl = (db_field_log *)pflin;
|
||||
short field_type;
|
||||
long no_elements;
|
||||
long offset;
|
||||
long capacity, no_elements, offset;
|
||||
struct rset *prset;
|
||||
long status = 0;
|
||||
|
||||
@@ -826,18 +835,33 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
return 0;
|
||||
|
||||
if (!pfl || pfl->type == dbfl_type_rec) {
|
||||
field_type = paddr->field_type;
|
||||
no_elements = paddr->no_elements;
|
||||
field_type = paddr->field_type;
|
||||
no_elements = capacity = paddr->no_elements;
|
||||
|
||||
/* Update field info from record
|
||||
* may modify paddr->pfield
|
||||
*/
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
(prset = dbGetRset(paddr)) &&
|
||||
prset->get_array_info) {
|
||||
status = prset->get_array_info(paddr, &no_elements, &offset);
|
||||
} else
|
||||
offset = 0;
|
||||
} else {
|
||||
field_type = pfl->field_type;
|
||||
no_elements = pfl->no_elements;
|
||||
field_type = pfl->field_type;
|
||||
no_elements = capacity = pfl->no_elements;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK)
|
||||
return getLinkValue(paddr, dbrType, pbuf, nRequest);
|
||||
if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) {
|
||||
status = getLinkValue(paddr, dbrType, pbuf, nRequest);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (paddr->special == SPC_ATTRIBUTE)
|
||||
return getAttrValue(paddr, dbrType, pbuf, nRequest);
|
||||
if (paddr->special == SPC_ATTRIBUTE) {
|
||||
status = getAttrValue(paddr, dbrType, pbuf, nRequest);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check for valid request */
|
||||
if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
|
||||
@@ -845,26 +869,13 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
|
||||
sprintf(message, "dbGet: Request type is %d\n", dbrType);
|
||||
recGblDbaddrError(S_db_badDbrtype, paddr, message);
|
||||
return S_db_badDbrtype;
|
||||
status = S_db_badDbrtype;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* For SPC_DBADDR fields, the rset function
|
||||
* get_array_info() is allowed to modify
|
||||
* paddr->pfield. So we store the original
|
||||
* value and restore it later.
|
||||
*/
|
||||
pfieldsave = paddr->pfield;
|
||||
|
||||
/* Update field info */
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
(prset = dbGetRset(paddr)) &&
|
||||
prset->get_array_info) {
|
||||
status = prset->get_array_info(paddr, &no_elements, &offset);
|
||||
} else
|
||||
offset = 0;
|
||||
|
||||
if (offset == 0 && (!nRequest || no_elements == 1)) {
|
||||
if (nRequest) *nRequest = 1;
|
||||
if (nRequest)
|
||||
*nRequest = 1;
|
||||
if (!pfl || pfl->type == dbfl_type_rec) {
|
||||
status = dbFastGetConvertRoutine[field_type][dbrType]
|
||||
(paddr->pfield, pbuf, paddr);
|
||||
@@ -883,10 +894,11 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
}
|
||||
} else {
|
||||
long n;
|
||||
long (*convert)();
|
||||
GETCONVERTFUNC convert;
|
||||
|
||||
if (nRequest) {
|
||||
if (no_elements<(*nRequest)) *nRequest = no_elements;
|
||||
if (no_elements < *nRequest)
|
||||
*nRequest = no_elements;
|
||||
n = *nRequest;
|
||||
} else {
|
||||
n = 1;
|
||||
@@ -901,11 +913,11 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
status = S_db_badDbrtype;
|
||||
goto done;
|
||||
}
|
||||
/* convert database field and place it in the buffer */
|
||||
/* convert data into the caller's buffer */
|
||||
if (n <= 0) {
|
||||
;/*do nothing*/
|
||||
} else if (!pfl || pfl->type == dbfl_type_rec) {
|
||||
status = convert(paddr, pbuf, n, no_elements, offset);
|
||||
status = convert(paddr, pbuf, n, capacity, offset);
|
||||
} else {
|
||||
DBADDR localAddr = *paddr; /* Structure copy */
|
||||
|
||||
@@ -916,7 +928,7 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
localAddr.pfield = (char *) &pfl->u.v.field;
|
||||
else
|
||||
localAddr.pfield = (char *) pfl->u.r.field;
|
||||
status = convert(&localAddr, pbuf, n, no_elements, offset);
|
||||
status = convert(&localAddr, pbuf, n, capacity, offset);
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
@@ -704,21 +704,27 @@ void dbChannelShow(dbChannel *chan, int level, const unsigned short indent)
|
||||
int pre = ellCount(&chan->pre_chain);
|
||||
int post = ellCount(&chan->post_chain);
|
||||
|
||||
printf("%*schannel name: %s\n", indent, "", chan->name);
|
||||
printf("%*s field_type=%s (%d bytes), dbr_type=%s, %ld element%s, %d filter%s", indent, "",
|
||||
dbGetFieldTypeString(chan->addr.field_type), chan->addr.field_size,
|
||||
dbGetFieldTypeString(chan->addr.dbr_field_type), elems, elems == 1 ? "" : "s",
|
||||
count, count == 1 ? "" : "s");
|
||||
if (count)
|
||||
printf(" (%d pre eventq, %d post eventq)\n", pre, post);
|
||||
else
|
||||
printf("\n");
|
||||
if (level > 0)
|
||||
dbChannelFilterShow(chan, level - 1, indent + 2);
|
||||
if (count) {
|
||||
printf("%*s final field_type=%s (%dB), %ld element%s\n", indent, "",
|
||||
dbGetFieldTypeString(chan->final_type), chan->final_field_size,
|
||||
felems, felems == 1 ? "" : "s");
|
||||
printf("%*sChannel: '%s'\n", indent, "", chan->name);
|
||||
if (level > 0) {
|
||||
printf("%*sfield_type=%s (%d bytes), dbr_type=%s, %ld element%s",
|
||||
indent + 4, "",
|
||||
dbGetFieldTypeString(chan->addr.field_type),
|
||||
chan->addr.field_size,
|
||||
dbGetFieldTypeString(chan->addr.dbr_field_type),
|
||||
elems, elems == 1 ? "" : "s");
|
||||
if (count)
|
||||
printf("\n%*s%d filter%s (%d pre eventq, %d post eventq)\n",
|
||||
indent + 4, "", count, count == 1 ? "" : "s", pre, post);
|
||||
else
|
||||
printf(", no filters\n");
|
||||
if (level > 1)
|
||||
dbChannelFilterShow(chan, level - 2, indent + 8);
|
||||
if (count) {
|
||||
printf("%*sfinal field_type=%s (%dB), %ld element%s\n", indent + 4, "",
|
||||
dbGetFieldTypeString(chan->final_type),
|
||||
chan->final_field_size,
|
||||
felems, felems == 1 ? "" : "s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
#*************************************************************************
|
||||
%#include "epicsTypes.h"
|
||||
%#include "link.h"
|
||||
@@ -15,59 +15,59 @@
|
||||
}
|
||||
field(DESC,DBF_STRING) {
|
||||
prompt("Descriptor")
|
||||
promptgroup(GUI_COMMON)
|
||||
promptgroup("10 - Common")
|
||||
size(41)
|
||||
}
|
||||
field(ASG,DBF_STRING) {
|
||||
prompt("Access Security Group")
|
||||
promptgroup(GUI_COMMON)
|
||||
promptgroup("10 - Common")
|
||||
special(SPC_AS)
|
||||
size(29)
|
||||
}
|
||||
field(SCAN,DBF_MENU) {
|
||||
prompt("Scan Mechanism")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
special(SPC_SCAN)
|
||||
interest(1)
|
||||
menu(menuScan)
|
||||
}
|
||||
field(PINI,DBF_MENU) {
|
||||
prompt("Process at iocInit")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
interest(1)
|
||||
menu(menuPini)
|
||||
}
|
||||
field(PHAS,DBF_SHORT) {
|
||||
prompt("Scan Phase")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
special(SPC_SCAN)
|
||||
interest(1)
|
||||
}
|
||||
field(EVNT,DBF_STRING) {
|
||||
prompt("Event Name")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
special(SPC_SCAN)
|
||||
size(40)
|
||||
interest(1)
|
||||
}
|
||||
field(TSE,DBF_SHORT) {
|
||||
prompt("Time Stamp Event")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
interest(1)
|
||||
}
|
||||
field(TSEL,DBF_INLINK) {
|
||||
prompt("Time Stamp Link")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
interest(1)
|
||||
}
|
||||
field(DTYP,DBF_DEVICE) {
|
||||
prompt("Device Type")
|
||||
promptgroup(GUI_LINKS)
|
||||
promptgroup("10 - Common")
|
||||
interest(1)
|
||||
}
|
||||
field(DISV,DBF_SHORT) {
|
||||
prompt("Disable Value")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
initial("1")
|
||||
}
|
||||
field(DISA,DBF_SHORT) {
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
field(SDIS,DBF_INLINK) {
|
||||
prompt("Scanning Disable")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
interest(1)
|
||||
}
|
||||
%#include "epicsMutex.h"
|
||||
@@ -131,7 +131,7 @@
|
||||
}
|
||||
field(ACKT,DBF_MENU) {
|
||||
prompt("Alarm Ack Transient")
|
||||
promptgroup(GUI_ALARMS)
|
||||
promptgroup("70 - Alarm")
|
||||
special(SPC_NOMOD)
|
||||
interest(2)
|
||||
menu(menuYesNo)
|
||||
@@ -139,7 +139,7 @@
|
||||
}
|
||||
field(DISS,DBF_MENU) {
|
||||
prompt("Disable Alarm Sevrty")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("70 - Alarm")
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
}
|
||||
@@ -219,7 +219,7 @@
|
||||
}
|
||||
field(PRIO,DBF_MENU) {
|
||||
prompt("Scheduling Priority")
|
||||
promptgroup(GUI_SCAN)
|
||||
promptgroup("20 - Scan")
|
||||
special(SPC_SCAN)
|
||||
interest(1)
|
||||
menu(menuPriority)
|
||||
@@ -235,14 +235,14 @@
|
||||
}
|
||||
field(UDF,DBF_UCHAR) {
|
||||
prompt("Undefined")
|
||||
promptgroup(GUI_COMMON)
|
||||
promptgroup("10 - Common")
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
initial("1")
|
||||
}
|
||||
field(UDFS,DBF_MENU) {
|
||||
prompt("Undefined Alarm Sevrty")
|
||||
promptgroup(GUI_COMMON)
|
||||
promptgroup("70 - Alarm")
|
||||
interest(1)
|
||||
menu(menuAlarmSevr)
|
||||
initial("INVALID")
|
||||
@@ -256,6 +256,6 @@
|
||||
}
|
||||
field(FLNK,DBF_FWDLINK) {
|
||||
prompt("Forward Process Link")
|
||||
promptgroup(GUI_LINKS)
|
||||
promptgroup("20 - Scan")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -224,6 +224,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
return S_db_badDbrtype;
|
||||
|
||||
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
|
||||
&& paddr->special != SPC_DBADDR
|
||||
&& paddr->special != SPC_ATTRIBUTE) {
|
||||
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "dbChannel.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbNotify.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "recSup.h"
|
||||
@@ -153,28 +154,30 @@ int dbChannel_get_count(
|
||||
* in the dbAccess.c dbGet() and getOptions() routines.
|
||||
*/
|
||||
|
||||
dbScanLock(dbChannelRecord(chan));
|
||||
|
||||
switch(buffer_type) {
|
||||
case(oldDBR_STRING):
|
||||
status = dbChannelGetField(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
/* case(oldDBR_INT): */
|
||||
case(oldDBR_SHORT):
|
||||
status = dbChannelGetField(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_FLOAT):
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_ENUM):
|
||||
status = dbChannelGetField(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_CHAR):
|
||||
status = dbChannelGetField(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_LONG):
|
||||
status = dbChannelGetField(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
case(oldDBR_DOUBLE):
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
|
||||
break;
|
||||
|
||||
case(oldDBR_STS_STRING):
|
||||
@@ -187,10 +190,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_STRING, pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_STRING, pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -203,10 +206,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -218,10 +221,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -233,10 +236,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -248,10 +251,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -263,10 +266,10 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &zero,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &zero,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -278,11 +281,11 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -296,12 +299,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_STRING, pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_STRING, pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -315,12 +318,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -333,12 +336,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -351,12 +354,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -369,12 +372,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_CHAR, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_CHAR, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -387,12 +390,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -405,12 +408,12 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_TIME;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->stamp = newSt.time; /* structure copy */
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -428,7 +431,7 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -440,7 +443,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -457,7 +460,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -470,7 +473,7 @@ int dbChannel_get_count(
|
||||
pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
|
||||
pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -486,7 +489,7 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -498,7 +501,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -513,7 +516,7 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -525,7 +528,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -542,7 +545,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -555,7 +558,7 @@ int dbChannel_get_count(
|
||||
pold->lower_warning_limit = newSt.lower_warning_limit;
|
||||
pold->lower_alarm_limit = newSt.lower_alarm_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -574,7 +577,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
|
||||
DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -588,7 +591,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -606,7 +609,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -621,7 +624,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
|
||||
pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit);
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -638,7 +641,7 @@ int dbChannel_get_count(
|
||||
memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
|
||||
/* first get status and severity */
|
||||
options = DBR_STATUS | DBR_ENUM_STRS;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
no_str = newSt.no_str;
|
||||
@@ -648,7 +651,7 @@ int dbChannel_get_count(
|
||||
strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i]));
|
||||
/*now get values*/
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -665,7 +668,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
|
||||
DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -679,7 +682,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -696,7 +699,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
|
||||
DBR_AL_LONG;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
|
||||
@@ -710,7 +713,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -728,7 +731,7 @@ int dbChannel_get_count(
|
||||
|
||||
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
|
||||
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->precision = (dbr_short_t) newSt.precision.dp;
|
||||
@@ -743,7 +746,7 @@ int dbChannel_get_count(
|
||||
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
|
||||
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
|
||||
nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -756,13 +759,13 @@ int dbChannel_get_count(
|
||||
} newSt;
|
||||
|
||||
options = DBR_STATUS;
|
||||
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
|
||||
pold->status = newSt.status;
|
||||
pold->severity = newSt.severity;
|
||||
pold->ackt = newSt.ackt;
|
||||
pold->acks = newSt.acks;
|
||||
options = 0;
|
||||
status = dbChannelGetField(chan, DBR_STRING, pold->value,
|
||||
status = dbChannelGet(chan, DBR_STRING, pold->value,
|
||||
&options, nRequest, pfl);
|
||||
}
|
||||
break;
|
||||
@@ -791,8 +794,12 @@ int dbChannel_get_count(
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
dbScanUnlock(dbChannelRecord(chan));
|
||||
|
||||
if (status) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
#ifndef INCLdb_field_logh
|
||||
#define INCLdb_field_logh
|
||||
|
||||
#include "epicsTime.h"
|
||||
#include <epicsTime.h>
|
||||
#include <epicsTypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -32,18 +33,20 @@ extern "C" {
|
||||
* priority task pending on the event queue wakes up). Strings would slow down
|
||||
* events for more reasonable size values. DB fields of native type string
|
||||
* will most likely change infrequently.
|
||||
*
|
||||
*
|
||||
* Strings can be added to the set of types for which updates will be queued
|
||||
* by defining the macro DB_EVENT_LOG_STRINGS. The code in db_add_event()
|
||||
* will adjust automatically, it just compares field sizes.
|
||||
*/
|
||||
union native_value {
|
||||
short dbf_int;
|
||||
short dbf_short;
|
||||
float dbf_float;
|
||||
short dbf_enum;
|
||||
char dbf_char;
|
||||
long dbf_long;
|
||||
double dbf_double;
|
||||
epicsInt8 dbf_char;
|
||||
epicsInt16 dbf_short;
|
||||
epicsEnum16 dbf_enum;
|
||||
epicsInt32 dbf_long;
|
||||
epicsFloat32 dbf_float;
|
||||
epicsFloat64 dbf_double;
|
||||
#ifdef DB_EVENT_LOG_STRINGS
|
||||
char dbf_string[MAX_STRING_SIZE];
|
||||
char dbf_string[MAX_STRING_SIZE];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -12,14 +12,17 @@ include $(TOP)/configure/CONFIG
|
||||
|
||||
TESTLIBRARY = dbTestIoc
|
||||
|
||||
dbTestIoc_SRCS += arrRecord.c
|
||||
dbTestIoc_SRCS += xRecord.c
|
||||
dbTestIoc_SRCS += dbLinkdset.c
|
||||
dbTestIoc_LIBS = dbCore ca Com
|
||||
|
||||
TARGETS += $(COMMON_DIR)/dbTestIoc.dbd
|
||||
DBDDEPENDS_FILES += dbTestIoc.dbd$(DEP)
|
||||
dbTestIoc_DBD += menuGlobal.dbd
|
||||
dbTestIoc_DBD += menuConvert.dbd
|
||||
dbTestIoc_DBD += menuScan.dbd
|
||||
#dbTestIoc_DBD += arrRecord.dbd
|
||||
dbTestIoc_DBD += xRecord.dbd
|
||||
dbTestIoc_DBD += dbLinkdset.dbd
|
||||
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
|
||||
@@ -76,6 +79,7 @@ TESTS += dbCaStatsTest
|
||||
TESTFILES += ../dbCaStatsTest.db
|
||||
|
||||
TARGETS += $(COMMON_DIR)/scanIoTest.dbd
|
||||
DBDDEPENDS_FILES += scanIoTest.dbd$(DEP)
|
||||
scanIoTest_DBD += menuGlobal.dbd
|
||||
scanIoTest_DBD += menuConvert.dbd
|
||||
scanIoTest_DBD += menuScan.dbd
|
||||
@@ -95,6 +99,17 @@ dbChannelTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbChannelTest.c
|
||||
TESTS += dbChannelTest
|
||||
|
||||
TARGETS += $(COMMON_DIR)/dbChArrTest.dbd
|
||||
DBDDEPENDS_FILES += dbChArrTest.dbd$(DEP)
|
||||
dbChArrTest_DBD += arrRecord.dbd
|
||||
TESTPROD_HOST += dbChArrTest
|
||||
dbChArrTest_SRCS += dbChArrTest.cpp
|
||||
dbChArrTest_SRCS += dbChArrTest_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbChArrTest.cpp
|
||||
testHarness_SRCS += dbChArrTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/dbChArrTest.dbd ../dbChArrTest.db
|
||||
TESTS += dbChArrTest
|
||||
|
||||
TESTPROD_HOST += chfPluginTest
|
||||
chfPluginTest_SRCS += chfPluginTest.c
|
||||
chfPluginTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
@@ -132,7 +147,7 @@ TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h
|
||||
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
dbPutLinkTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
scanIoTest$(DEP): $(COMMON_DIR)/yRecord.h
|
||||
|
||||
|
||||
135
src/ioc/db/test/arrRecord.c
Normal file
135
src/ioc/db/test/arrRecord.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/* arrRecord.c - minimal array record for test purposes: no processing */
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*
|
||||
* vaguely implemented like parts of recWaveform.c by Bob Dalesio
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "cantProceed.h"
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "arrRecord.h"
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
#define initialize NULL
|
||||
static long init_record(arrRecord *, int);
|
||||
static long process(arrRecord *);
|
||||
#define special NULL
|
||||
#define get_value NULL
|
||||
static long cvt_dbaddr(DBADDR *);
|
||||
static long get_array_info(DBADDR *, long *, long *);
|
||||
static long put_array_info(DBADDR *, long);
|
||||
#define get_units NULL
|
||||
#define get_precision NULL
|
||||
#define get_enum_str NULL
|
||||
#define get_enum_strs NULL
|
||||
#define put_enum_str NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
#define get_alarm_double NULL
|
||||
|
||||
rset arrRSET = {
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_units,
|
||||
get_precision,
|
||||
get_enum_str,
|
||||
get_enum_strs,
|
||||
put_enum_str,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_alarm_double
|
||||
};
|
||||
epicsExportAddress(rset, arrRSET);
|
||||
|
||||
static long init_record(arrRecord *prec, int pass)
|
||||
{
|
||||
if (pass == 0) {
|
||||
if (prec->nelm <= 0)
|
||||
prec->nelm = 1;
|
||||
if (prec->ftvl > DBF_ENUM)
|
||||
prec->ftvl = DBF_UCHAR;
|
||||
prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl),
|
||||
"arr calloc failed");
|
||||
|
||||
if (prec->nelm == 1) {
|
||||
prec->nord = 1;
|
||||
} else {
|
||||
prec->nord = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long process(arrRecord *prec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long cvt_dbaddr(DBADDR *paddr)
|
||||
{
|
||||
arrRecord *prec = (arrRecord *) paddr->precord;
|
||||
|
||||
paddr->pfield = prec->bptr;
|
||||
paddr->no_elements = prec->nelm;
|
||||
paddr->field_type = prec->ftvl;
|
||||
paddr->field_size = dbValueSize(prec->ftvl);
|
||||
paddr->dbr_field_type = prec->ftvl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
|
||||
{
|
||||
arrRecord *prec = (arrRecord *) paddr->precord;
|
||||
|
||||
*no_elements = prec->nord;
|
||||
*offset = prec->off;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long put_array_info(DBADDR *paddr, long nNew)
|
||||
{
|
||||
arrRecord *prec = (arrRecord *) paddr->precord;
|
||||
|
||||
prec->nord = nNew;
|
||||
if (prec->nord > prec->nelm)
|
||||
prec->nord = prec->nelm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
34
src/ioc/db/test/arrRecord.dbd
Normal file
34
src/ioc/db/test/arrRecord.dbd
Normal file
@@ -0,0 +1,34 @@
|
||||
include "menuGlobal.dbd"
|
||||
include "menuConvert.dbd"
|
||||
include "menuScan.dbd"
|
||||
recordtype(arr) {
|
||||
include "dbCommon.dbd"
|
||||
field(VAL, DBF_NOACCESS) {
|
||||
prompt("Value")
|
||||
special(SPC_DBADDR)
|
||||
pp(TRUE)
|
||||
extra("void *val")
|
||||
}
|
||||
field(NELM, DBF_ULONG) {
|
||||
prompt("Number of Elements")
|
||||
special(SPC_NOMOD)
|
||||
initial("1")
|
||||
}
|
||||
field(FTVL, DBF_MENU) {
|
||||
prompt("Field Type of Value")
|
||||
special(SPC_NOMOD)
|
||||
menu(menuFtype)
|
||||
}
|
||||
field(NORD, DBF_ULONG) {
|
||||
prompt("Number elements read")
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
field(OFF, DBF_ULONG) {
|
||||
prompt("Offset into array")
|
||||
}
|
||||
field(BPTR, DBF_NOACCESS) {
|
||||
prompt("Buffer Pointer")
|
||||
special(SPC_NOMOD)
|
||||
extra("void *bptr")
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ MAIN(callbackParallelTest)
|
||||
myPvt *pcbt[NCALLBACKS];
|
||||
epicsTimeStamp start;
|
||||
int noCpus = epicsThreadGetCPUs();
|
||||
int i, j;
|
||||
int i, j, slowups, faults;
|
||||
/* Statistics: min/max/sum/sum^2/n for each priority */
|
||||
double setupError[NUM_CALLBACK_PRIORITIES][5];
|
||||
double timeError[NUM_CALLBACK_PRIORITIES][5];
|
||||
@@ -109,7 +109,7 @@ MAIN(callbackParallelTest)
|
||||
for (j = 0; j < 5; j++)
|
||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||
|
||||
testPlan(NCALLBACKS * 2 + 1);
|
||||
testPlan(4);
|
||||
|
||||
testDiag("Starting %d parallel callback threads", noCpus);
|
||||
|
||||
@@ -138,7 +138,7 @@ MAIN(callbackParallelTest)
|
||||
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
|
||||
pcbt[NCALLBACKS-1]->pass = 0;
|
||||
|
||||
testOk1(epicsTimeGetCurrent(&start)==epicsTimeOK);
|
||||
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
callbackRequest(&pcbt[i]->cb1);
|
||||
@@ -147,28 +147,43 @@ MAIN(callbackParallelTest)
|
||||
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
|
||||
|
||||
epicsEventWait(finished);
|
||||
|
||||
slowups = 0;
|
||||
faults = 0;
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
testFail("pass = %d for delay = %f", pcbt[i]->pass, pcbt[i]->delay);
|
||||
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
|
||||
++faults, pcbt[i]->pass, pcbt[i]->delay);
|
||||
else {
|
||||
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
|
||||
testOk(fabs(delta) < 0.05, "callback %.02f setup time |%f| < 0.05",
|
||||
|
||||
if (fabs(delta) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
|
||||
pcbt[i]->delay, delta);
|
||||
}
|
||||
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
|
||||
}
|
||||
}
|
||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
||||
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
|
||||
|
||||
slowups = 0;
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
double delta, error;
|
||||
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
continue;
|
||||
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
|
||||
error = delta - pcbt[i]->delay;
|
||||
testOk(fabs(error) < 0.05, "delay %.02f seconds, callback time error |%.04f| < 0.05",
|
||||
if (fabs(error) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
|
||||
pcbt[i]->delay, error);
|
||||
}
|
||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
||||
}
|
||||
testOk(slowups < 5, "%d slowups during callbacks", slowups);
|
||||
|
||||
testDiag("Setup time statistics");
|
||||
printStats(setupError[0], "LOW");
|
||||
|
||||
@@ -99,7 +99,7 @@ MAIN(callbackTest)
|
||||
{
|
||||
myPvt *pcbt[NCALLBACKS];
|
||||
epicsTimeStamp start;
|
||||
int i, j;
|
||||
int i, j, slowups, faults;
|
||||
/* Statistics: min/max/sum/sum^2/n for each priority */
|
||||
double setupError[NUM_CALLBACK_PRIORITIES][5];
|
||||
double timeError[NUM_CALLBACK_PRIORITIES][5];
|
||||
@@ -109,7 +109,7 @@ MAIN(callbackTest)
|
||||
for (j = 0; j < 5; j++)
|
||||
setupError[i][j] = timeError[i][j] = defaultError[j];
|
||||
|
||||
testPlan(NCALLBACKS * 2 + 1);
|
||||
testPlan(4);
|
||||
|
||||
callbackInit();
|
||||
epicsThreadSleep(1.0);
|
||||
@@ -135,7 +135,7 @@ MAIN(callbackTest)
|
||||
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
|
||||
pcbt[NCALLBACKS-1]->pass = 0;
|
||||
|
||||
testOk1(epicsTimeGetCurrent(&start)==epicsTimeOK);
|
||||
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
callbackRequest(&pcbt[i]->cb1);
|
||||
@@ -144,28 +144,43 @@ MAIN(callbackTest)
|
||||
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
|
||||
|
||||
epicsEventWait(finished);
|
||||
|
||||
slowups = 0;
|
||||
faults = 0;
|
||||
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
testFail("pass = %d for delay = %f", pcbt[i]->pass, pcbt[i]->delay);
|
||||
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
|
||||
++faults, pcbt[i]->pass, pcbt[i]->delay);
|
||||
else {
|
||||
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
|
||||
testOk(fabs(delta) < 0.05, "callback %.02f setup time |%f| < 0.05",
|
||||
|
||||
if (fabs(delta) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
|
||||
pcbt[i]->delay, delta);
|
||||
}
|
||||
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
|
||||
}
|
||||
}
|
||||
testOk(faults == 0, "%d faults during callback setup", faults);
|
||||
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
|
||||
|
||||
slowups = 0;
|
||||
for (i = 0; i < NCALLBACKS ; i++) {
|
||||
double delta, error;
|
||||
|
||||
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
|
||||
continue;
|
||||
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
|
||||
error = delta - pcbt[i]->delay;
|
||||
testOk(fabs(error) < 0.05, "delay %.02f seconds, callback time error |%.04f| < 0.05",
|
||||
if (fabs(error) >= 0.05) {
|
||||
slowups++;
|
||||
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
|
||||
pcbt[i]->delay, error);
|
||||
}
|
||||
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
|
||||
}
|
||||
testOk(slowups < 5, "%d slowups during callbacks", slowups);
|
||||
|
||||
testDiag("Setup time statistics");
|
||||
printStats(setupError[0], "LOW");
|
||||
|
||||
@@ -418,7 +418,7 @@ static void channelRegisterPost(dbChannel *chan, void *user,
|
||||
static void channel_report(dbChannel *chan, void *user, int level,
|
||||
const unsigned short indent)
|
||||
{
|
||||
testOk(level == R_LEVEL - 1, "channel_report: level correct");
|
||||
testOk(level == R_LEVEL - 2, "channel_report: level correct %u == %u", level, R_LEVEL-2);
|
||||
if (user == puser1) {
|
||||
testOk(e1 & e_report, "channel_report (1) called");
|
||||
c1 |= e_report;
|
||||
|
||||
246
src/ioc/db/test/dbChArrTest.cpp
Normal file
246
src/ioc/db/test/dbChArrTest.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2003 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to the Software License Agreement
|
||||
* found in the file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Authors: Ralph Lange <ralph.lange@gmx.de>,
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "registryFunction.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "envDefs.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbmf.h"
|
||||
#include "registry.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbAccess.h"
|
||||
#include "asDbLib.h"
|
||||
#include "iocInit.h"
|
||||
#include "iocsh.h"
|
||||
#include "dbChannel.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
#include "osiFileName.h"
|
||||
|
||||
extern "C" {
|
||||
int dbChArrTest_registerRecordDeviceDriver(struct dbBase *pdbbase);
|
||||
}
|
||||
|
||||
#define CA_SERVER_PORT "65535"
|
||||
|
||||
const char *server_port = CA_SERVER_PORT;
|
||||
|
||||
static void createAndOpen(const char *name, dbChannel**pch)
|
||||
{
|
||||
testOk(!!(*pch = dbChannelCreate(name)), "dbChannel %s created", name);
|
||||
testOk(!(dbChannelOpen(*pch)), "dbChannel opened");
|
||||
testOk((ellCount(&(*pch)->pre_chain) == 0), "no filters in pre chain");
|
||||
testOk((ellCount(&(*pch)->post_chain) == 0), "no filters in post chain");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static void freeArray(db_field_log *pfl) {
|
||||
if (pfl->type == dbfl_type_ref) {
|
||||
free(pfl->u.r.field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testHead (const char *title, const char *typ = "") {
|
||||
const char *line = "------------------------------------------------------------------------------";
|
||||
testDiag("%s", line);
|
||||
testDiag(title, typ);
|
||||
testDiag("%s", line);
|
||||
}
|
||||
|
||||
static void check(short dbr_type) {
|
||||
dbChannel *pch;
|
||||
db_field_log *pfl;
|
||||
dbAddr valaddr;
|
||||
dbAddr offaddr;
|
||||
const char *offname = NULL, *valname = NULL, *typname = NULL;
|
||||
epicsInt32 buf[26];
|
||||
long off, req;
|
||||
int i;
|
||||
|
||||
switch (dbr_type) {
|
||||
case DBR_LONG:
|
||||
offname = "i32.OFF";
|
||||
valname = "i32.VAL";
|
||||
typname = "long";
|
||||
break;
|
||||
case DBR_DOUBLE:
|
||||
offname = "f64.OFF";
|
||||
valname = "f64.VAL";
|
||||
typname = "double";
|
||||
break;
|
||||
case DBR_STRING:
|
||||
offname = "c40.OFF";
|
||||
valname = "c40.VAL";
|
||||
typname = "string";
|
||||
break;
|
||||
default:
|
||||
testDiag("Invalid data type %d", dbr_type);
|
||||
}
|
||||
|
||||
(void) dbNameToAddr(offname, &offaddr);
|
||||
(void) dbNameToAddr(valname, &valaddr);
|
||||
|
||||
testHead("Ten %s elements", typname);
|
||||
|
||||
/* Fill the record's array field with data, 10..19 */
|
||||
|
||||
epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19};
|
||||
(void) dbPutField(&valaddr, DBR_LONG, ar, 10);
|
||||
|
||||
/* Open a channel to it, make sure no filters present */
|
||||
|
||||
createAndOpen(valname, &pch);
|
||||
testOk(pch->final_type == valaddr.field_type,
|
||||
"final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
|
||||
testOk(pch->final_no_elements == valaddr.no_elements,
|
||||
"final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
|
||||
|
||||
/* TEST1 sets the record's OFF field, then requests 10 elements from the channel,
|
||||
* passing in a transparent db_field_log and converting the data to LONG on the way in.
|
||||
* It checks that it got back the expected data and the right number of elements.
|
||||
*/
|
||||
|
||||
#define TEST1(Size, Offset, Text, Expected) \
|
||||
testDiag("Reading from offset = %d (%s)", Offset, Text); \
|
||||
off = Offset; req = 10; \
|
||||
memset(buf, 0, sizeof(buf)); \
|
||||
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
|
||||
pfl = db_create_read_log(pch); \
|
||||
testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \
|
||||
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
|
||||
testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
|
||||
if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
|
||||
for (i=0; i<Size; i++) \
|
||||
testDiag("Element %d expected %d got %d", i, Expected[i], buf[i]); \
|
||||
db_delete_field_log(pfl);
|
||||
|
||||
const epicsInt32 res_10_0[] = {10,11,12,13,14,15,16,17,18,19};
|
||||
TEST1(10, 0, "no offset", res_10_0);
|
||||
|
||||
const epicsInt32 res_10_4[] = {14,15,16,17,18,19,10,11,12,13};
|
||||
TEST1(10, 4, "wrapped", res_10_4);
|
||||
|
||||
/* Partial array */
|
||||
|
||||
testHead("Five %s elements", typname);
|
||||
off = 0; /* Reset offset for writing the next buffer */
|
||||
(void) dbPutField(&offaddr, DBR_LONG, &off, 1);
|
||||
(void) dbPutField(&valaddr, DBR_LONG, &ar[5], 5);
|
||||
|
||||
createAndOpen(valname, &pch);
|
||||
testOk(pch->final_type == valaddr.field_type,
|
||||
"final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
|
||||
testOk(pch->final_no_elements == valaddr.no_elements,
|
||||
"final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
|
||||
|
||||
const epicsInt32 res_5_0[] = {15,16,17,18,19};
|
||||
TEST1(5, 0, "no offset", res_5_0);
|
||||
|
||||
const epicsInt32 res_5_3[] = {18,19,15,16,17};
|
||||
TEST1(5, 3, "wrapped", res_5_3);
|
||||
|
||||
/* TEST2 sets the record's OFF field, then requests 15 elements from the channel
|
||||
* but passes in a db_field_log with alternate data, converting that data to LONG.
|
||||
* It checks that it got back the expected data and the right number of elements.
|
||||
*/
|
||||
|
||||
#define TEST2(Size, Offset, Text, Expected) \
|
||||
testDiag("Reading from offset = %d (%s)", Offset, Text); \
|
||||
off = Offset; req = 15; \
|
||||
memset(buf, 0, sizeof(buf)); \
|
||||
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
|
||||
pfl = db_create_read_log(pch); \
|
||||
pfl->type = dbfl_type_ref; \
|
||||
pfl->field_type = DBF_CHAR; \
|
||||
pfl->field_size = 1; \
|
||||
pfl->no_elements = 26; \
|
||||
pfl->u.r.dtor = freeArray; \
|
||||
pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \
|
||||
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
|
||||
testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
|
||||
if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
|
||||
for (i=0; i<Size; i++) \
|
||||
testDiag("Element %d expected '%c' got '%c'", i, Expected[i], buf[i]); \
|
||||
db_delete_field_log(pfl);
|
||||
|
||||
testHead("Fifteen letters from field-log instead of %s", typname);
|
||||
|
||||
const epicsInt32 res_15[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o'};
|
||||
TEST2(15, 0, "no offset", res_15);
|
||||
TEST2(15, 10, "ignored", res_15);
|
||||
|
||||
dbChannelDelete(pch);
|
||||
}
|
||||
|
||||
static dbEventCtx evtctx;
|
||||
|
||||
extern "C" {
|
||||
static void dbChArrTestCleanup(void* junk)
|
||||
{
|
||||
dbFreeBase(pdbbase);
|
||||
registryFree();
|
||||
pdbbase=0;
|
||||
|
||||
db_close_events(evtctx);
|
||||
|
||||
dbmfFreeChunks();
|
||||
}
|
||||
}
|
||||
|
||||
MAIN(dbChArrTest)
|
||||
{
|
||||
testPlan(102);
|
||||
|
||||
/* Prepare the IOC */
|
||||
|
||||
epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "dbChArrTest.dbd",
|
||||
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL))
|
||||
testAbort("Database description not loaded");
|
||||
|
||||
dbChArrTest_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
if (dbReadDatabase(&pdbbase, "dbChArrTest.db",
|
||||
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
|
||||
testAbort("Test database not loaded");
|
||||
|
||||
epicsAtExit(&dbChArrTestCleanup,NULL);
|
||||
|
||||
/* Start the IOC */
|
||||
|
||||
iocInit();
|
||||
evtctx = db_init_events();
|
||||
|
||||
check(DBR_LONG);
|
||||
check(DBR_DOUBLE);
|
||||
check(DBR_STRING);
|
||||
|
||||
return testDone();
|
||||
}
|
||||
15
src/ioc/db/test/dbChArrTest.db
Normal file
15
src/ioc/db/test/dbChArrTest.db
Normal file
@@ -0,0 +1,15 @@
|
||||
record(arr, "i32") {
|
||||
field(DESC, "test array record")
|
||||
field(NELM, "10")
|
||||
field(FTVL, "LONG")
|
||||
}
|
||||
record(arr, "f64") {
|
||||
field(DESC, "test array record")
|
||||
field(NELM, "10")
|
||||
field(FTVL, "DOUBLE")
|
||||
}
|
||||
record(arr, "c40") {
|
||||
field(DESC, "test array record")
|
||||
field(NELM, "10")
|
||||
field(FTVL, "STRING")
|
||||
}
|
||||
@@ -242,7 +242,7 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
|
||||
testOk1(!!(pch = dbChannelCreate("x.{\"scalar\":null}")));
|
||||
|
||||
e = e_report;
|
||||
dbChannelShow(pch, 1, 2);
|
||||
dbChannelShow(pch, 2, 2);
|
||||
|
||||
e = e_close;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
@@ -165,8 +165,9 @@ typedef struct dbBase {
|
||||
ELLLIST functionList;
|
||||
ELLLIST variableList;
|
||||
ELLLIST bptList;
|
||||
ELLLIST filterList;
|
||||
void *pathPvt;
|
||||
ELLLIST filterList;
|
||||
ELLLIST guiGroupList;
|
||||
void *pathPvt;
|
||||
struct dbPvd *ppvd;
|
||||
struct gphPvt *pgpHash;
|
||||
short ignoreMissingMenus;
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
#include "epicsExport.h"
|
||||
#include "guigroup.h"
|
||||
#include "link.h"
|
||||
#include "special.h"
|
||||
|
||||
@@ -49,6 +48,9 @@ epicsExportAddress(int,dbRecordsOnceOnly);
|
||||
epicsShareDef int dbBptNotMonotonic=0;
|
||||
epicsExportAddress(int,dbBptNotMonotonic);
|
||||
|
||||
epicsShareDef int dbQuietMacroWarnings=0;
|
||||
epicsExportAddress(int,dbQuietMacroWarnings);
|
||||
|
||||
/*private routines */
|
||||
static void yyerrorAbort(char *str);
|
||||
static void allocTemp(void *pvoid);
|
||||
@@ -68,6 +70,7 @@ static void dbRecordtypeEmpty(void);
|
||||
static void dbRecordtypeBody(void);
|
||||
static void dbRecordtypeFieldHead(char *name,char *type);
|
||||
static void dbRecordtypeFieldItem(char *name,char *value);
|
||||
static short findOrAddGuiGroup(const char *name);
|
||||
|
||||
static void dbDevice(char *recordtype,char *linktype,
|
||||
char *dsetname,char *choicestring);
|
||||
@@ -230,6 +233,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
free((void *)macPairs);
|
||||
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
}
|
||||
macSuppressWarning(macHandle,dbQuietMacroWarnings);
|
||||
}
|
||||
pinputFile = dbCalloc(1,sizeof(inputFile));
|
||||
if(filename) {
|
||||
@@ -320,10 +324,9 @@ static int db_yyinput(char *buf, int max_size)
|
||||
if(fgetsRtn) {
|
||||
int exp = macExpandString(macHandle,mac_input_buffer,
|
||||
my_buffer,MY_BUFFER_SIZE);
|
||||
if(exp < 0) {
|
||||
errPrintf(0,__FILE__, __LINE__,
|
||||
"macExpandString failed for file %s",
|
||||
pinputFileNow->filename);
|
||||
if (exp < 0) {
|
||||
fprintf(stderr, "Warning: '%s' line %d has undefined macros\n",
|
||||
pinputFileNow->filename, pinputFileNow->line_num+1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -492,7 +495,23 @@ static void dbRecordtypeFieldHead(char *name,char *type)
|
||||
yyerrorAbort("Illegal Field Type");
|
||||
pdbFldDes->field_type = i;
|
||||
}
|
||||
|
||||
|
||||
static short findOrAddGuiGroup(const char *name)
|
||||
{
|
||||
dbGuiGroup *pdbGuiGroup;
|
||||
GPHENTRY *pgphentry;
|
||||
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
|
||||
if (!pgphentry) {
|
||||
pdbGuiGroup = dbCalloc(1,sizeof(dbGuiGroup));
|
||||
pdbGuiGroup->name = epicsStrDup(name);
|
||||
ellAdd(&pdbbase->guiGroupList, &pdbGuiGroup->node);
|
||||
pdbGuiGroup->key = ellCount(&pdbbase->guiGroupList);
|
||||
pgphentry = gphAdd(pdbbase->pgpHash, pdbGuiGroup->name, &pdbbase->guiGroupList);
|
||||
pgphentry->userPvt = pdbGuiGroup;
|
||||
}
|
||||
return ((dbGuiGroup *)pgphentry->userPvt)->key;
|
||||
}
|
||||
|
||||
static void dbRecordtypeFieldItem(char *name,char *value)
|
||||
{
|
||||
dbFldDes *pdbFldDes;
|
||||
@@ -514,14 +533,7 @@ static void dbRecordtypeFieldItem(char *name,char *value)
|
||||
return;
|
||||
}
|
||||
if(strcmp(name,"promptgroup")==0) {
|
||||
int i;
|
||||
for(i=0; i<GUI_NTYPES; i++) {
|
||||
if(strcmp(value,pamapguiGroup[i].strvalue)==0) {
|
||||
pdbFldDes->promptgroup = pamapguiGroup[i].value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
yyerror("Illegal promptgroup. See guigroup.h for legal values");
|
||||
pdbFldDes->promptgroup = findOrAddGuiGroup(value);
|
||||
return;
|
||||
}
|
||||
if(strcmp(name,"prompt")==0) {
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "postfix.h"
|
||||
|
||||
#define DBFLDTYPES_GBLSOURCE
|
||||
#define GUIGROUPS_GBLSOURCE
|
||||
#define SPECIAL_GBLSOURCE
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -41,7 +40,6 @@
|
||||
#include "dbStaticPvt.h"
|
||||
#include "devSup.h"
|
||||
#include "drvSup.h"
|
||||
#include "guigroup.h"
|
||||
#include "link.h"
|
||||
#include "special.h"
|
||||
|
||||
@@ -417,6 +415,7 @@ dbBase * dbAllocBase(void)
|
||||
ellInit(&pdbbase->variableList);
|
||||
ellInit(&pdbbase->bptList);
|
||||
ellInit(&pdbbase->filterList);
|
||||
ellInit(&pdbbase->guiGroupList);
|
||||
gphInitPvt(&pdbbase->pgpHash,256);
|
||||
dbPvdInitPvt(pdbbase);
|
||||
return (pdbbase);
|
||||
@@ -442,8 +441,10 @@ void dbFreeBase(dbBase *pdbbase)
|
||||
drvSup *pdrvSupNext;
|
||||
brkTable *pbrkTable;
|
||||
brkTable *pbrkTableNext;
|
||||
chFilterPlugin *pfilt;
|
||||
chFilterPlugin *pfiltNext;
|
||||
chFilterPlugin *pfilt;
|
||||
chFilterPlugin *pfiltNext;
|
||||
dbGuiGroup *pguiGroup;
|
||||
dbGuiGroup *pguiGroupNext;
|
||||
int i;
|
||||
DBENTRY dbentry;
|
||||
|
||||
@@ -584,6 +585,15 @@ void dbFreeBase(dbBase *pdbbase)
|
||||
free(pfilt);
|
||||
pfilt = pfiltNext;
|
||||
}
|
||||
pguiGroup = (dbGuiGroup *)ellFirst(&pdbbase->guiGroupList);
|
||||
while (pguiGroup) {
|
||||
pguiGroupNext = (dbGuiGroup *)ellNext(&pguiGroup->node);
|
||||
gphDelete(pdbbase->pgpHash, pguiGroup->name, &pdbbase->guiGroupList);
|
||||
ellDelete(&pdbbase->guiGroupList, &pguiGroup->node);
|
||||
free(pguiGroup->name);
|
||||
free((void *)pguiGroup);
|
||||
pguiGroup = pguiGroupNext;
|
||||
}
|
||||
gphFreeMem(pdbbase->pgpHash);
|
||||
dbPvdFreeMem(pdbbase);
|
||||
dbFreePath(pdbbase);
|
||||
@@ -738,6 +748,31 @@ static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *dbGetPromptGroupNameFromKey(DBBASE *pdbbase, const short key)
|
||||
{
|
||||
dbGuiGroup *pdbGuiGroup;
|
||||
|
||||
if (!pdbbase) return NULL;
|
||||
for (pdbGuiGroup = (dbGuiGroup *)ellFirst(&pdbbase->guiGroupList);
|
||||
pdbGuiGroup; pdbGuiGroup = (dbGuiGroup *)ellNext(&pdbGuiGroup->node)) {
|
||||
if (pdbGuiGroup->key == key) return pdbGuiGroup->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
short dbGetPromptGroupKeyFromName(DBBASE *pdbbase, const char *name)
|
||||
{
|
||||
GPHENTRY *pgphentry;
|
||||
|
||||
if (!pdbbase) return 0;
|
||||
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
|
||||
if (!pgphentry) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((dbGuiGroup*)pgphentry->userPvt)->key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long dbWriteRecord(DBBASE *ppdbbase,const char *filename,
|
||||
const char *precordTypename,int level)
|
||||
@@ -937,16 +972,11 @@ long dbWriteRecordTypeFP(
|
||||
fprintf(fp,"\t\tprompt(\"%s\")\n",pdbFldDes->prompt);
|
||||
if(pdbFldDes->initial)
|
||||
fprintf(fp,"\t\tinitial(\"%s\")\n",pdbFldDes->initial);
|
||||
if(pdbFldDes->promptgroup) {
|
||||
for(j=0; j<GUI_NTYPES; j++) {
|
||||
if(pamapguiGroup[j].value == pdbFldDes->promptgroup) {
|
||||
fprintf(fp,"\t\tpromptgroup(%s)\n",
|
||||
pamapguiGroup[j].strvalue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pdbFldDes->special) {
|
||||
if (pdbFldDes->promptgroup) {
|
||||
fprintf(fp,"\t\tpromptgroup(\"%s\")\n",
|
||||
dbGetPromptGroupNameFromKey(pdbbase, pdbFldDes->promptgroup));
|
||||
}
|
||||
if(pdbFldDes->special) {
|
||||
if(pdbFldDes->special >= SPC_NTYPES) {
|
||||
fprintf(fp,"\t\tspecial(%d)\n",pdbFldDes->special);
|
||||
} else for(j=0; j<SPC_NTYPES; j++) {
|
||||
@@ -2051,7 +2081,10 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
switch (pflddes->field_type) {
|
||||
case DBF_STRING:
|
||||
if(!pfield) return(S_dbLib_fieldNotFound);
|
||||
strncpy((char *)pfield, pstring,pflddes->size);
|
||||
if(strlen(pstring) >= (size_t)pflddes->size) return S_dbLib_strLen;
|
||||
strncpy((char *)pfield, pstring, pflddes->size-1);
|
||||
((char *)pfield)[pflddes->size-1] = 0;
|
||||
|
||||
if((pflddes->special == SPC_CALC) && !stringHasMacro) {
|
||||
char rpcl[RPCL_LEN];
|
||||
short err;
|
||||
@@ -2062,7 +2095,6 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
calcErrorStr(err), pstring);
|
||||
}
|
||||
}
|
||||
if((short)strlen(pstring) >= pflddes->size) status = S_dbLib_strLen;
|
||||
break;
|
||||
|
||||
case DBF_CHAR:
|
||||
@@ -3181,14 +3213,9 @@ void dbDumpField(
|
||||
if(!pdbFldDes->promptgroup) {
|
||||
printf("\t promptgroup: %d\n",pdbFldDes->promptgroup);
|
||||
} else {
|
||||
for(j=0; j<GUI_NTYPES; j++) {
|
||||
if(pamapguiGroup[j].value == pdbFldDes->promptgroup) {
|
||||
printf("\t promptgroup: %s\n",
|
||||
pamapguiGroup[j].strvalue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\t promptgroup: %s\n",
|
||||
dbGetPromptGroupNameFromKey(pdbbase, pdbFldDes->promptgroup));
|
||||
}
|
||||
printf("\t interest: %hd\n", pdbFldDes->interest);
|
||||
printf("\t as_level: %d\n",pdbFldDes->as_level);
|
||||
printf("\t initial: %s\n",
|
||||
|
||||
@@ -81,6 +81,10 @@ epicsShareFunc long dbReadDatabaseFP(DBBASE **ppdbbase,
|
||||
FILE *fp, const char *path, const char *substitutions);
|
||||
epicsShareFunc long dbPath(DBBASE *pdbbase, const char *path);
|
||||
epicsShareFunc long dbAddPath(DBBASE *pdbbase, const char *path);
|
||||
epicsShareFunc char * dbGetPromptGroupNameFromKey(DBBASE *pdbbase,
|
||||
const short key);
|
||||
epicsShareFunc short dbGetPromptGroupKeyFromName(DBBASE *pdbbase,
|
||||
const char *name);
|
||||
epicsShareFunc long dbWriteRecord(DBBASE *ppdbbase,
|
||||
const char *filename, const char *precordTypename, int level);
|
||||
epicsShareFunc long dbWriteRecordFP(DBBASE *ppdbbase,
|
||||
|
||||
@@ -42,6 +42,13 @@ typedef struct dbPathNode {
|
||||
char *directory;
|
||||
} dbPathNode;
|
||||
|
||||
/* Element of the global gui group list */
|
||||
typedef struct dbGuiGroup {
|
||||
ELLNODE node;
|
||||
short key;
|
||||
char *name;
|
||||
} dbGuiGroup;
|
||||
|
||||
/*The following are in dbPvdLib.c*/
|
||||
/*directory*/
|
||||
typedef struct{
|
||||
|
||||
@@ -16,68 +16,11 @@
|
||||
#ifndef __gui_group_h__
|
||||
#define __gui_group_h__
|
||||
|
||||
#define GUI_COMMON 1
|
||||
#define GUI_ALARMS 2
|
||||
#define GUI_BITS1 3
|
||||
#define GUI_BITS2 4
|
||||
#define GUI_CALC 5
|
||||
#define GUI_CLOCK 6
|
||||
#define GUI_COMPRESS 7
|
||||
#define GUI_CONVERT 8
|
||||
#define GUI_DISPLAY 9
|
||||
#define GUI_HIST 10
|
||||
#define GUI_INPUTS 11
|
||||
#define GUI_LINKS 12
|
||||
#define GUI_MBB 13
|
||||
#define GUI_MOTOR 14
|
||||
#define GUI_OUTPUT 15
|
||||
#define GUI_PID 16
|
||||
#define GUI_PULSE 17
|
||||
#define GUI_SELECT 18
|
||||
#define GUI_SEQ1 19
|
||||
#define GUI_SEQ2 20
|
||||
#define GUI_SEQ3 21
|
||||
#define GUI_SUB 22
|
||||
#define GUI_TIMER 23
|
||||
#define GUI_WAVE 24
|
||||
#define GUI_SCAN 25
|
||||
#define GUI_NTYPES 25
|
||||
|
||||
typedef struct mapguiGroup{
|
||||
char *strvalue;
|
||||
int value;
|
||||
}mapguiGroup;
|
||||
|
||||
#ifndef GUIGROUPS_GBLSOURCE
|
||||
extern mapguiGroup pamapguiGroup[];
|
||||
#else
|
||||
mapguiGroup pamapguiGroup[GUI_NTYPES] = {
|
||||
{"GUI_COMMON",GUI_COMMON},
|
||||
{"GUI_ALARMS",GUI_ALARMS},
|
||||
{"GUI_BITS1",GUI_BITS1},
|
||||
{"GUI_BITS2",GUI_BITS2},
|
||||
{"GUI_CALC",GUI_CALC},
|
||||
{"GUI_CLOCK",GUI_CLOCK},
|
||||
{"GUI_COMPRESS",GUI_COMPRESS},
|
||||
{"GUI_CONVERT",GUI_CONVERT},
|
||||
{"GUI_DISPLAY",GUI_DISPLAY},
|
||||
{"GUI_HIST",GUI_HIST},
|
||||
{"GUI_INPUTS",GUI_INPUTS},
|
||||
{"GUI_LINKS",GUI_LINKS},
|
||||
{"GUI_MBB",GUI_MBB},
|
||||
{"GUI_MOTOR",GUI_MOTOR},
|
||||
{"GUI_OUTPUT",GUI_OUTPUT},
|
||||
{"GUI_PID",GUI_PID},
|
||||
{"GUI_PULSE",GUI_PULSE},
|
||||
{"GUI_SELECT",GUI_SELECT},
|
||||
{"GUI_SEQ1",GUI_SEQ1},
|
||||
{"GUI_SEQ2",GUI_SEQ2},
|
||||
{"GUI_SEQ3",GUI_SEQ3},
|
||||
{"GUI_SUB",GUI_SUB},
|
||||
{"GUI_TIMER",GUI_TIMER},
|
||||
{"GUI_WAVE",GUI_WAVE},
|
||||
{"GUI_SCAN",GUI_SCAN}
|
||||
};
|
||||
#endif /*GUIGROUPS_GBLSOURCE*/
|
||||
#error As of Base 3.15.4, the promptgroup implementation has changed. \
|
||||
This header file (guigroup.h) is invalid and will be removed shortly. \
|
||||
Instead, you should include dbStaticLib.h, parse the DBD, \
|
||||
and use dbGetPromptGroupNameFromKey() and dbGetPromptGroupKeyFromName() \
|
||||
that have been added to dbStaticLib. \
|
||||
More details in the 3.15.4 release notes and the AppDev Guide.
|
||||
|
||||
#endif /*__gui_group_h__*/
|
||||
|
||||
@@ -14,8 +14,12 @@ variable(asCaDebug,int)
|
||||
# Static database access variables
|
||||
variable(dbRecordsOnceOnly,int)
|
||||
variable(dbBptNotMonotonic,int)
|
||||
variable(dbQuietMacroWarnings,int)
|
||||
|
||||
# dbLoadTemplate settings
|
||||
variable(dbTemplateMaxVars,int)
|
||||
# Default number of parallel callback threads
|
||||
variable(callbackParallelThreadsDefault,int)
|
||||
|
||||
# Real-time operation
|
||||
variable(dbThreadRealtimeLock,int)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
#include "caeventmask.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsExport.h" /* defines epicsExportSharedSymbols */
|
||||
#include "alarm.h"
|
||||
#include "asDbLib.h"
|
||||
#include "callback.h"
|
||||
@@ -86,7 +86,9 @@ static void initDatabase(void);
|
||||
static void initialProcess(void);
|
||||
static void exitDatabase(void *dummy);
|
||||
|
||||
|
||||
int dbThreadRealtimeLock = 1;
|
||||
epicsExportAddress(int, dbThreadRealtimeLock);
|
||||
|
||||
/*
|
||||
* Initialize EPICS on the IOC.
|
||||
*/
|
||||
@@ -186,6 +188,10 @@ int iocBuild(void)
|
||||
rsrv_init();
|
||||
|
||||
status = iocBuild_3();
|
||||
|
||||
if (dbThreadRealtimeLock)
|
||||
epicsThreadRealtimeLock();
|
||||
|
||||
if (!status) iocBuildMode = buildRSRV;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "epicsVersion.h"
|
||||
#include "iocsh.h"
|
||||
#include "libComRegister.h"
|
||||
|
||||
@@ -21,10 +23,29 @@
|
||||
#include "registryIocRegister.h"
|
||||
#include "rsrvIocRegister.h"
|
||||
|
||||
#define quote(v) #v
|
||||
#define str(v) quote(v)
|
||||
|
||||
void iocshRegisterCommon(void)
|
||||
{
|
||||
const char *targetArch = envGetConfigParamPtr(&EPICS_BUILD_TARGET_ARCH);
|
||||
iocshPpdbbase = &pdbbase;
|
||||
|
||||
/* This uses a config param so the user can override it */
|
||||
if (targetArch) {
|
||||
epicsEnvSet("ARCH", targetArch);
|
||||
}
|
||||
|
||||
/* Base build version variables */
|
||||
epicsEnvSet("EPICS_VERSION_MAJOR", str(EPICS_VERSION));
|
||||
epicsEnvSet("EPICS_VERSION_MIDDLE", str(EPICS_REVISION));
|
||||
epicsEnvSet("EPICS_VERSION_MINOR", str(EPICS_MODIFICATION));
|
||||
epicsEnvSet("EPICS_VERSION_PATCH", str(EPICS_PATCH_LEVEL));
|
||||
epicsEnvSet("EPICS_VERSION_SNAPSHOT", EPICS_DEV_SNAPSHOT);
|
||||
epicsEnvSet("EPICS_VERSION_SITE", EPICS_SITE_VERSION);
|
||||
epicsEnvSet("EPICS_VERSION_SHORT", EPICS_VERSION_SHORT);
|
||||
epicsEnvSet("EPICS_VERSION_FULL", EPICS_VERSION_FULL);
|
||||
|
||||
dbStaticIocRegister();
|
||||
registryIocRegister();
|
||||
dbIocRegister();
|
||||
|
||||
@@ -1112,7 +1112,7 @@ unsigned cid
|
||||
* casAccessRightsCB()
|
||||
*
|
||||
* If access right state changes then inform the client.
|
||||
*
|
||||
* asLock is held
|
||||
*/
|
||||
static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
|
||||
{
|
||||
@@ -1126,7 +1126,7 @@ static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
|
||||
pclient = pciu->client;
|
||||
assert(pclient);
|
||||
|
||||
if(pclient == prsrv_cast_client){
|
||||
if(pclient->proto==IPPROTO_UDP){
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1193,7 +1193,7 @@ static void access_rights_reply ( struct channel_in_use * pciu )
|
||||
int v41;
|
||||
int status;
|
||||
|
||||
assert ( pciu->client != prsrv_cast_client );
|
||||
assert ( pciu->client->proto!=IPPROTO_UDP );
|
||||
|
||||
/*
|
||||
* noop if this is an old client
|
||||
@@ -1321,7 +1321,7 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsMutexMustLock(prsrv_cast_client->chanListLock);
|
||||
epicsMutexMustLock(client->chanListLock);
|
||||
/*
|
||||
* clients which dont claim their
|
||||
* channel in use block prior to
|
||||
@@ -1331,7 +1331,7 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
if(!pciu){
|
||||
errlogPrintf("CAS: client timeout disconnect id=%d\n",
|
||||
mp->m_cid);
|
||||
epicsMutexUnlock(prsrv_cast_client->chanListLock);
|
||||
epicsMutexUnlock(client->chanListLock);
|
||||
SEND_LOCK(client);
|
||||
send_err(
|
||||
mp,
|
||||
@@ -1342,24 +1342,6 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* duplicate claim message are unacceptable
|
||||
* (so we disconnect the client)
|
||||
*/
|
||||
if (pciu->client!=prsrv_cast_client) {
|
||||
errlogPrintf("CAS: duplicate claim disconnect id=%d\n",
|
||||
mp->m_cid);
|
||||
epicsMutexUnlock(prsrv_cast_client->chanListLock);
|
||||
SEND_LOCK(client);
|
||||
send_err(
|
||||
mp,
|
||||
ECA_INTERNAL,
|
||||
client,
|
||||
"duplicate claim in old connect protocol");
|
||||
SEND_UNLOCK(client);
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove channel in use block from
|
||||
* the UDP client where it could time
|
||||
@@ -1367,9 +1349,9 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
* who is claiming it
|
||||
*/
|
||||
ellDelete(
|
||||
&prsrv_cast_client->chanList,
|
||||
&client->chanList,
|
||||
&pciu->node);
|
||||
epicsMutexUnlock(prsrv_cast_client->chanListLock);
|
||||
epicsMutexUnlock(client->chanListLock);
|
||||
|
||||
epicsMutexMustLock(client->chanListLock);
|
||||
pciu->state = rsrvCS_pendConnectResp;
|
||||
@@ -1586,6 +1568,9 @@ static void sendAllUpdateAS ( struct client *client )
|
||||
else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ) {
|
||||
access_rights_reply ( pciu );
|
||||
}
|
||||
else if ( pciu->state == rsrvCS_shutdown ) {
|
||||
/* no-op */
|
||||
}
|
||||
else {
|
||||
errlogPrintf (
|
||||
"%s at %d: corrupt channel state detected durring AR update\n",
|
||||
@@ -2065,10 +2050,15 @@ static int clear_channel_reply ( caHdrLargeArray *mp,
|
||||
if ( pciu->state == rsrvCS_inService ||
|
||||
pciu->state == rsrvCS_pendConnectResp ) {
|
||||
ellDelete ( &client->chanList, &pciu->node );
|
||||
pciu->state = rsrvCS_shutdown;
|
||||
}
|
||||
else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ||
|
||||
pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) {
|
||||
ellDelete ( &client->chanPendingUpdateARList, &pciu->node );
|
||||
pciu->state = rsrvCS_shutdown;
|
||||
}
|
||||
else if ( pciu->state == rsrvCS_shutdown ) {
|
||||
/* no-op */
|
||||
}
|
||||
else {
|
||||
epicsMutexUnlock( client->chanListLock );
|
||||
@@ -2515,12 +2505,7 @@ int camessage ( struct client *client )
|
||||
unsigned bytes_left;
|
||||
int status = RSRV_ERROR;
|
||||
|
||||
if ( ! pCaBucket ) {
|
||||
pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE);
|
||||
if(!pCaBucket){
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
}
|
||||
assert(pCaBucket);
|
||||
|
||||
/* drain remnents of large messages that will not fit */
|
||||
if ( client->recvBytesToDrain ) {
|
||||
@@ -2623,7 +2608,7 @@ int camessage ( struct client *client )
|
||||
if ( CASDEBUG > 2 )
|
||||
log_header (NULL, client, &msg, pBody, nmsg);
|
||||
|
||||
if ( client == prsrv_cast_client ) {
|
||||
if ( client->proto==IPPROTO_UDP ) {
|
||||
if ( msg.m_cmmd < NELEMENTS ( udpJumpTable ) ) {
|
||||
status = ( *udpJumpTable[msg.m_cmmd] )( &msg, pBody, client );
|
||||
if (status!=RSRV_OK) {
|
||||
|
||||
@@ -222,7 +222,7 @@ void cas_send_dg_msg ( struct client * pclient )
|
||||
/*
|
||||
* add placeholder for the first version message should it be needed
|
||||
*/
|
||||
rsrv_version_reply ( prsrv_cast_client );
|
||||
rsrv_version_reply ( pclient );
|
||||
|
||||
SEND_UNLOCK(pclient);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -54,7 +54,7 @@
|
||||
/*
|
||||
* clean_addrq
|
||||
*/
|
||||
static void clean_addrq(void)
|
||||
static void clean_addrq(struct client *client)
|
||||
{
|
||||
struct channel_in_use * pciu;
|
||||
struct channel_in_use * pnextciu;
|
||||
@@ -67,9 +67,9 @@ static void clean_addrq(void)
|
||||
|
||||
epicsTimeGetCurrent ( ¤t );
|
||||
|
||||
epicsMutexMustLock ( prsrv_cast_client->chanListLock );
|
||||
epicsMutexMustLock ( client->chanListLock );
|
||||
pnextciu = (struct channel_in_use *)
|
||||
prsrv_cast_client->chanList.node.next;
|
||||
client->chanList.node.next;
|
||||
|
||||
while( (pciu = pnextciu) ) {
|
||||
pnextciu = (struct channel_in_use *)pciu->node.next;
|
||||
@@ -77,7 +77,7 @@ static void clean_addrq(void)
|
||||
delay = epicsTimeDiffInSeconds(¤t,&pciu->time_at_creation);
|
||||
if (delay > timeout) {
|
||||
|
||||
ellDelete(&prsrv_cast_client->chanList, &pciu->node);
|
||||
ellDelete(&client->chanList, &pciu->node);
|
||||
LOCK_CLIENTQ;
|
||||
s = bucketRemoveItemUnsignedId (
|
||||
pCaBucket,
|
||||
@@ -96,7 +96,7 @@ static void clean_addrq(void)
|
||||
if(delay>maxdelay) maxdelay = delay;
|
||||
}
|
||||
}
|
||||
epicsMutexUnlock ( prsrv_cast_client->chanListLock );
|
||||
epicsMutexUnlock ( client->chanListLock );
|
||||
|
||||
# ifdef DEBUG
|
||||
if(ndelete){
|
||||
@@ -115,70 +115,19 @@ static void clean_addrq(void)
|
||||
*/
|
||||
void cast_server(void *pParm)
|
||||
{
|
||||
osiSockAddrNode *paddrNode;
|
||||
struct sockaddr_in sin;
|
||||
rsrv_iface_config *conf = pParm;
|
||||
int status;
|
||||
int count=0;
|
||||
int mysocket=0;
|
||||
struct sockaddr_in new_recv_addr;
|
||||
osiSocklen_t recv_addr_size;
|
||||
osiSockIoctl_t nchars;
|
||||
SOCKET recv_sock, reply_sock;
|
||||
struct client *client;
|
||||
|
||||
recv_addr_size = sizeof(new_recv_addr);
|
||||
|
||||
if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) {
|
||||
epicsSocketDestroy ( IOC_cast_sock );
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the socket.
|
||||
* Use ARPA Internet address format and datagram socket.
|
||||
*/
|
||||
|
||||
if ( ( IOC_cast_sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0) ) == INVALID_SOCKET ) {
|
||||
epicsPrintf ("CAS: cast socket creation error\n");
|
||||
epicsThreadSuspendSelf ();
|
||||
}
|
||||
|
||||
/*
|
||||
* some concern that vxWorks will run out of mBuf's
|
||||
* if this change is made
|
||||
*
|
||||
* joh 11-10-98
|
||||
*/
|
||||
#if 0
|
||||
{
|
||||
/*
|
||||
*
|
||||
* this allows for faster connects by queuing
|
||||
* additional incomming UDP search frames
|
||||
*
|
||||
* this allocates a 32k buffer
|
||||
* (uses a power of two)
|
||||
*/
|
||||
int size = 1u<<15u;
|
||||
status = setsockopt (IOC_cast_sock, SOL_SOCKET,
|
||||
SO_RCVBUF, (char *)&size, sizeof(size));
|
||||
if (status<0) {
|
||||
epicsPrintf ("CAS: unable to set cast socket size\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock );
|
||||
|
||||
paddrNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList );
|
||||
|
||||
memcpy(&sin, &paddrNode->addr.ia, sizeof (sin));
|
||||
|
||||
/* get server's Internet address */
|
||||
if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsPrintf ("CAS: UDP server port bind error was \"%s\"\n", sockErrBuf );
|
||||
epicsSocketDestroy ( IOC_cast_sock );
|
||||
epicsThreadSuspendSelf ();
|
||||
}
|
||||
reply_sock = conf->udp;
|
||||
|
||||
/*
|
||||
* setup new client structure but reuse old structure if
|
||||
@@ -186,27 +135,39 @@ void cast_server(void *pParm)
|
||||
*
|
||||
*/
|
||||
while ( TRUE ) {
|
||||
prsrv_cast_client = create_client ( IOC_cast_sock, IPPROTO_UDP );
|
||||
if ( prsrv_cast_client ) {
|
||||
client = create_client ( reply_sock, IPPROTO_UDP );
|
||||
if ( client ) {
|
||||
break;
|
||||
}
|
||||
epicsThreadSleep(300.0);
|
||||
}
|
||||
if (conf->startbcast) {
|
||||
recv_sock = conf->udpbcast;
|
||||
conf->bclient = client;
|
||||
}
|
||||
else {
|
||||
recv_sock = conf->udp;
|
||||
conf->client = client;
|
||||
}
|
||||
client->udpRecv = recv_sock;
|
||||
|
||||
casAttachThreadToClient ( prsrv_cast_client );
|
||||
casAttachThreadToClient ( client );
|
||||
|
||||
/*
|
||||
* add placeholder for the first version message should it be needed
|
||||
*/
|
||||
rsrv_version_reply ( prsrv_cast_client );
|
||||
rsrv_version_reply ( client );
|
||||
|
||||
/* these pointers become invalid after signaling casudp_startStopEvent */
|
||||
conf = NULL;
|
||||
|
||||
epicsEventSignal(casudp_startStopEvent);
|
||||
|
||||
while (TRUE) {
|
||||
status = recvfrom (
|
||||
IOC_cast_sock,
|
||||
prsrv_cast_client->recv.buf,
|
||||
prsrv_cast_client->recv.maxstk,
|
||||
recv_sock,
|
||||
client->recv.buf,
|
||||
client->recv.maxstk,
|
||||
0,
|
||||
(struct sockaddr *)&new_recv_addr,
|
||||
&recv_addr_size);
|
||||
@@ -219,71 +180,90 @@ void cast_server(void *pParm)
|
||||
sockErrBuf);
|
||||
epicsThreadSleep(1.0);
|
||||
}
|
||||
}
|
||||
else if (casudp_ctl == ctlRun) {
|
||||
prsrv_cast_client->recv.cnt = (unsigned) status;
|
||||
prsrv_cast_client->recv.stk = 0ul;
|
||||
epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv);
|
||||
|
||||
prsrv_cast_client->minor_version_number = 0;
|
||||
prsrv_cast_client->seqNoOfReq = 0;
|
||||
} else {
|
||||
size_t idx;
|
||||
for(idx=0; casIgnoreAddrs[idx]; idx++)
|
||||
{
|
||||
if(new_recv_addr.sin_addr.s_addr==casIgnoreAddrs[idx]) {
|
||||
status = -1; /* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status >= 0 && casudp_ctl == ctlRun) {
|
||||
client->recv.cnt = (unsigned) status;
|
||||
client->recv.stk = 0ul;
|
||||
epicsTimeGetCurrent(&client->time_at_last_recv);
|
||||
|
||||
client->minor_version_number = 0;
|
||||
client->seqNoOfReq = 0;
|
||||
|
||||
/*
|
||||
* If we are talking to a new client flush to the old one
|
||||
* in case we are holding UDP messages waiting to
|
||||
* see if the next message is for this same client.
|
||||
*/
|
||||
if (prsrv_cast_client->send.stk>sizeof(caHdr)) {
|
||||
status = memcmp(&prsrv_cast_client->addr,
|
||||
if (client->send.stk>sizeof(caHdr)) {
|
||||
status = memcmp(&client->addr,
|
||||
&new_recv_addr, recv_addr_size);
|
||||
if(status){
|
||||
/*
|
||||
* if the address is different
|
||||
*/
|
||||
cas_send_dg_msg(prsrv_cast_client);
|
||||
prsrv_cast_client->addr = new_recv_addr;
|
||||
cas_send_dg_msg(client);
|
||||
client->addr = new_recv_addr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prsrv_cast_client->addr = new_recv_addr;
|
||||
client->addr = new_recv_addr;
|
||||
}
|
||||
|
||||
if (CASDEBUG>1) {
|
||||
char buf[40];
|
||||
|
||||
ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
|
||||
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
|
||||
errlogPrintf ("CAS: cast server msg of %d bytes from addr %s\n",
|
||||
prsrv_cast_client->recv.cnt, buf);
|
||||
client->recv.cnt, buf);
|
||||
}
|
||||
|
||||
if (CASDEBUG>2)
|
||||
count = ellCount (&prsrv_cast_client->chanList);
|
||||
count = ellCount (&client->chanList);
|
||||
|
||||
status = camessage ( prsrv_cast_client );
|
||||
status = camessage ( client );
|
||||
if(status == RSRV_OK){
|
||||
if(prsrv_cast_client->recv.cnt !=
|
||||
prsrv_cast_client->recv.stk){
|
||||
if(client->recv.cnt !=
|
||||
client->recv.stk){
|
||||
char buf[40];
|
||||
|
||||
ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
|
||||
|
||||
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
|
||||
|
||||
epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n",
|
||||
prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf);
|
||||
client->recv.cnt - client->recv.stk, buf);
|
||||
|
||||
epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
|
||||
&client->time_at_last_recv);
|
||||
epicsPrintf ("CAS: message received at %s\n", buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
char buf[40];
|
||||
|
||||
ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
|
||||
|
||||
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
|
||||
|
||||
epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf);
|
||||
|
||||
epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
|
||||
&client->time_at_last_recv);
|
||||
epicsPrintf ("CAS: message received at %s\n", buf);
|
||||
}
|
||||
|
||||
if (CASDEBUG>2) {
|
||||
if ( ellCount (&prsrv_cast_client->chanList) ) {
|
||||
if ( ellCount (&client->chanList) ) {
|
||||
errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n",
|
||||
ellCount(&prsrv_cast_client->chanList)-count,
|
||||
ellCount(&prsrv_cast_client->chanList));
|
||||
ellCount(&client->chanList)-count,
|
||||
ellCount(&client->chanList));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,15 +272,22 @@ void cast_server(void *pParm)
|
||||
* allow messages to batch up if more are comming
|
||||
*/
|
||||
nchars = 0; /* supress purify warning */
|
||||
status = socket_ioctl(IOC_cast_sock, FIONREAD, &nchars);
|
||||
status = socket_ioctl(recv_sock, FIONREAD, &nchars);
|
||||
if (status<0) {
|
||||
errlogPrintf ("CA cast server: Unable to fetch N characters pending\n");
|
||||
cas_send_dg_msg (prsrv_cast_client);
|
||||
clean_addrq ();
|
||||
cas_send_dg_msg (client);
|
||||
clean_addrq (client);
|
||||
}
|
||||
else if (nchars == 0) {
|
||||
cas_send_dg_msg (prsrv_cast_client);
|
||||
clean_addrq ();
|
||||
cas_send_dg_msg (client);
|
||||
clean_addrq (client);
|
||||
}
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
|
||||
if(!mysocket)
|
||||
client->sock = INVALID_SOCKET; /* only one cast_server should destroy the reply socket */
|
||||
destroy_client(client);
|
||||
epicsSocketDestroy(recv_sock);
|
||||
}
|
||||
|
||||
@@ -35,46 +35,19 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include "server.h"
|
||||
|
||||
/*
|
||||
* forcePort ()
|
||||
*/
|
||||
static void forcePort (ELLLIST *pList, unsigned short port)
|
||||
{
|
||||
osiSockAddrNode *pNode;
|
||||
|
||||
pNode = (osiSockAddrNode *) ellFirst ( pList );
|
||||
while ( pNode ) {
|
||||
if ( pNode->addr.sa.sa_family == AF_INET ) {
|
||||
pNode->addr.ia.sin_port = htons ( port );
|
||||
}
|
||||
pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RSRV_ONLINE_NOTIFY_TASK
|
||||
*/
|
||||
void rsrv_online_notify_task(void *pParm)
|
||||
{
|
||||
unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
|
||||
osiSockAddrNode *pNode;
|
||||
double delay;
|
||||
double maxdelay;
|
||||
long longStatus;
|
||||
double maxPeriod;
|
||||
caHdr msg;
|
||||
int status;
|
||||
SOCKET sock;
|
||||
int intTrue = TRUE;
|
||||
unsigned short port;
|
||||
ca_uint32_t beaconCounter = 0;
|
||||
char * pStr;
|
||||
int autoBeaconAddr;
|
||||
ELLLIST autoAddrList;
|
||||
char buf[16];
|
||||
unsigned priorityOfUDP;
|
||||
epicsThreadBooleanStatus tbs;
|
||||
epicsThreadId tid;
|
||||
|
||||
taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL);
|
||||
|
||||
@@ -94,189 +67,34 @@ void rsrv_online_notify_task(void *pParm)
|
||||
|
||||
delay = 0.02; /* initial beacon period in sec */
|
||||
maxdelay = maxPeriod;
|
||||
|
||||
/*
|
||||
* Open the socket.
|
||||
* Use ARPA Internet address format and datagram socket.
|
||||
* Format described in <sys/socket.h>.
|
||||
*/
|
||||
if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
|
||||
errlogPrintf ("CAS: online socket creation error\n");
|
||||
epicsThreadSuspendSelf ();
|
||||
}
|
||||
|
||||
status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST,
|
||||
(char *)&intTrue, sizeof(intTrue));
|
||||
if (status<0) {
|
||||
errlogPrintf ("CAS: online socket set up error\n");
|
||||
epicsThreadSuspendSelf ();
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* this connect is to supress a warning message on Linux
|
||||
* when we shutdown the read side of the socket. If it
|
||||
* fails (and it will on old ip kernels) we just ignore
|
||||
* the failure.
|
||||
*/
|
||||
osiSockAddr sockAddr;
|
||||
sockAddr.ia.sin_family = AF_UNSPEC;
|
||||
sockAddr.ia.sin_port = htons ( 0 );
|
||||
sockAddr.ia.sin_addr.s_addr = htonl (0);
|
||||
connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) );
|
||||
shutdown ( sock, SHUT_RD );
|
||||
}
|
||||
|
||||
memset((char *)&msg, 0, sizeof msg);
|
||||
msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP);
|
||||
msg.m_count = htons (ca_server_port);
|
||||
msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION);
|
||||
|
||||
ellInit ( & beaconAddrList );
|
||||
ellInit ( & autoAddrList );
|
||||
|
||||
pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf);
|
||||
if ( ! pStr ) {
|
||||
pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf);
|
||||
}
|
||||
if (pStr) {
|
||||
if (strstr(pStr,"no")||strstr(pStr,"NO")) {
|
||||
autoBeaconAddr = FALSE;
|
||||
}
|
||||
else if (strstr(pStr,"yes")||strstr(pStr,"YES")) {
|
||||
autoBeaconAddr = TRUE;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr);
|
||||
autoBeaconAddr = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
autoBeaconAddr = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* load user and auto configured
|
||||
* broadcast address list
|
||||
*/
|
||||
if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) {
|
||||
port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT,
|
||||
(unsigned short) CA_REPEATER_PORT );
|
||||
}
|
||||
else {
|
||||
port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT,
|
||||
(unsigned short) CA_REPEATER_PORT );
|
||||
}
|
||||
|
||||
/*
|
||||
* discover beacon addresses associated with this interface
|
||||
*/
|
||||
if ( autoBeaconAddr ) {
|
||||
osiSockAddr addr;
|
||||
ELLLIST tmpList;
|
||||
|
||||
ellInit ( &tmpList );
|
||||
addr.ia.sin_family = AF_UNSPEC;
|
||||
osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr);
|
||||
forcePort ( &tmpList, port );
|
||||
removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
* by default use EPICS_CA_ADDR_LIST for the
|
||||
* beacon address list
|
||||
*/
|
||||
{
|
||||
const ENV_PARAM *pParam;
|
||||
|
||||
if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) ||
|
||||
envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) {
|
||||
pParam = &EPICS_CAS_BEACON_ADDR_LIST;
|
||||
}
|
||||
else {
|
||||
pParam = &EPICS_CA_ADDR_LIST;
|
||||
}
|
||||
|
||||
/*
|
||||
* add in the configured addresses
|
||||
*/
|
||||
addAddrToChannelAccessAddressList (
|
||||
&autoAddrList, pParam, port, pParam == &EPICS_CA_ADDR_LIST );
|
||||
}
|
||||
|
||||
removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 );
|
||||
|
||||
if ( ellCount ( &beaconAddrList ) == 0 ) {
|
||||
errlogPrintf ("The CA server's beacon address list was empty after initialization?\n");
|
||||
}
|
||||
|
||||
# ifdef DEBUG
|
||||
printChannelAccessAddressList (&beaconAddrList);
|
||||
# endif
|
||||
|
||||
tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP );
|
||||
if ( tbs != epicsThreadBooleanStatusSuccess ) {
|
||||
priorityOfUDP = priorityOfSelf;
|
||||
}
|
||||
|
||||
casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
casudp_ctl = ctlPause;
|
||||
|
||||
tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP,
|
||||
epicsThreadGetStackSize (epicsThreadStackMedium),
|
||||
cast_server, 0 );
|
||||
if ( tid == 0 ) {
|
||||
epicsPrintf ( "CAS: unable to start UDP daemon thread\n" );
|
||||
}
|
||||
|
||||
epicsEventMustWait(casudp_startStopEvent);
|
||||
epicsEventSignal(beacon_startStopEvent);
|
||||
|
||||
while (TRUE) {
|
||||
pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList);
|
||||
while (pNode) {
|
||||
char buf[64];
|
||||
ELLNODE *cur;
|
||||
|
||||
status = connect (sock, &pNode->addr.sa,
|
||||
sizeof(pNode->addr.sa));
|
||||
if (status<0) {
|
||||
/* send beacon to each interface */
|
||||
for(cur=ellFirst(&beaconAddrList); cur; cur=ellNext(cur))
|
||||
{
|
||||
osiSockAddrNode *pAddr = CONTAINER(cur, osiSockAddrNode, node);
|
||||
status = sendto (beaconSocket, (char *)&msg, sizeof(msg), 0,
|
||||
&pAddr->addr.sa, sizeof(pAddr->addr));
|
||||
if (status < 0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
|
||||
errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n",
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf));
|
||||
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
|
||||
__FILE__, buf, sockErrBuf);
|
||||
}
|
||||
else {
|
||||
struct sockaddr_in if_addr;
|
||||
|
||||
osiSocklen_t size = sizeof (if_addr);
|
||||
status = getsockname (sock, (struct sockaddr *) &if_addr, &size);
|
||||
if (status<0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n",
|
||||
__FILE__, sockErrBuf);
|
||||
}
|
||||
else if (if_addr.sin_family==AF_INET) {
|
||||
msg.m_available = if_addr.sin_addr.s_addr;
|
||||
msg.m_cid = htonl ( beaconCounter );
|
||||
|
||||
status = send (sock, (char *)&msg, sizeof(msg), 0);
|
||||
if (status < 0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
|
||||
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
|
||||
__FILE__, buf, sockErrBuf);
|
||||
}
|
||||
else {
|
||||
assert (status == sizeof(msg));
|
||||
}
|
||||
}
|
||||
assert (status == sizeof(msg));
|
||||
}
|
||||
pNode = (osiSockAddrNode *) pNode->node.next;
|
||||
}
|
||||
|
||||
epicsThreadSleep(delay);
|
||||
@@ -287,7 +105,7 @@ void rsrv_online_notify_task(void *pParm)
|
||||
}
|
||||
}
|
||||
|
||||
beaconCounter++; /* expected to overflow */
|
||||
msg.m_cid = htonl ( beaconCounter++ ); /* expected to overflow */
|
||||
|
||||
while (beacon_ctl == ctlPause) {
|
||||
epicsThreadSleep(0.1);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "ellLib.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "osiSock.h"
|
||||
|
||||
#ifdef rsrvRestore_epicsExportSharedSymbols
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -88,7 +89,7 @@ typedef struct client {
|
||||
char *pUserName;
|
||||
char *pHostName;
|
||||
epicsEventId blockSem; /* used whenever the client blocks */
|
||||
SOCKET sock;
|
||||
SOCKET sock, udpRecv;
|
||||
int proto;
|
||||
epicsThreadId tid;
|
||||
unsigned minor_version_number;
|
||||
@@ -98,12 +99,25 @@ typedef struct client {
|
||||
char disconnect; /* disconnect detected */
|
||||
} client;
|
||||
|
||||
/* Channel state shows which struct client list a
|
||||
* channel_in_us::node is in.
|
||||
*
|
||||
* client::chanList
|
||||
* rsrvCS_pendConnectResp, rsrvCS_inService
|
||||
* client::chanPendingUpdateARList
|
||||
* rsrvCS_pendConnectRespUpdatePendAR, rsrvCS_inServiceUpdatePendAR
|
||||
* Not in any list
|
||||
* rsrvCS_shutdown
|
||||
*
|
||||
* rsrvCS_invalid is not used
|
||||
*/
|
||||
enum rsrvChanState {
|
||||
rsrvCS_invalid,
|
||||
rsrvCS_pendConnectResp,
|
||||
rsrvCS_inService,
|
||||
rsrvCS_pendConnectRespUpdatePendAR,
|
||||
rsrvCS_inServiceUpdatePendAR
|
||||
rsrvCS_inServiceUpdatePendAR,
|
||||
rsrvCS_shutdown
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -137,6 +151,16 @@ struct event_ext {
|
||||
char modified; /* mod & ev flw ctrl enbl */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ELLNODE node;
|
||||
osiSockAddr tcpAddr, /* TCP listener endpoint */
|
||||
udpAddr, /* UDP name unicast receiver endpoint */
|
||||
udpbcastAddr; /* UDP name broadcast receiver endpoint */
|
||||
SOCKET tcp, udp, udpbcast;
|
||||
struct client *client, *bclient;
|
||||
|
||||
unsigned int startbcast:1;
|
||||
} rsrv_iface_config;
|
||||
|
||||
enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
|
||||
|
||||
@@ -160,15 +184,16 @@ enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
|
||||
#endif
|
||||
|
||||
GLBLTYPE int CASDEBUG;
|
||||
GLBLTYPE SOCKET IOC_sock;
|
||||
GLBLTYPE SOCKET IOC_cast_sock;
|
||||
GLBLTYPE unsigned short ca_server_port;
|
||||
GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */
|
||||
GLBLTYPE unsigned short ca_server_port, ca_udp_port, ca_beacon_port;
|
||||
GLBLTYPE ELLLIST clientQ; /* (TCP clients) locked by clientQlock */
|
||||
GLBLTYPE ELLLIST clientQudp; /* locked by clientQlock */
|
||||
GLBLTYPE ELLLIST servers; /* rsrv_iface_config::node, read-only after rsrv_init() */
|
||||
GLBLTYPE ELLLIST beaconAddrList;
|
||||
GLBLTYPE ELLLIST casIntfAddrList;
|
||||
GLBLTYPE SOCKET beaconSocket;
|
||||
GLBLTYPE ELLLIST casIntfAddrList, casMCastAddrList;
|
||||
GLBLTYPE epicsUInt32 *casIgnoreAddrs;
|
||||
GLBLTYPE epicsMutexId clientQlock;
|
||||
GLBLTYPE struct client *prsrv_cast_client;
|
||||
GLBLTYPE BUCKET *pCaBucket;
|
||||
GLBLTYPE BUCKET *pCaBucket; /* locked by clientQlock */
|
||||
GLBLTYPE void *rsrvClientFreeList;
|
||||
GLBLTYPE void *rsrvChanFreeList;
|
||||
GLBLTYPE void *rsrvEventFreeList;
|
||||
@@ -176,7 +201,7 @@ GLBLTYPE void *rsrvSmallBufFreeListTCP;
|
||||
GLBLTYPE void *rsrvLargeBufFreeListTCP;
|
||||
GLBLTYPE unsigned rsrvSizeofLargeBufTCP;
|
||||
GLBLTYPE void *rsrvPutNotifyFreeList;
|
||||
GLBLTYPE unsigned rsrvChannelCount;
|
||||
GLBLTYPE unsigned rsrvChannelCount; /* locked by clientQlock */
|
||||
|
||||
GLBLTYPE epicsEventId casudp_startStopEvent;
|
||||
GLBLTYPE epicsEventId beacon_startStopEvent;
|
||||
@@ -185,6 +210,7 @@ GLBLTYPE volatile enum ctl casudp_ctl;
|
||||
GLBLTYPE volatile enum ctl beacon_ctl;
|
||||
GLBLTYPE volatile enum ctl castcp_ctl;
|
||||
|
||||
GLBLTYPE unsigned int threadPrios[5];
|
||||
|
||||
#define CAS_HASH_TABLE_SIZE 4096
|
||||
|
||||
|
||||
@@ -45,6 +45,11 @@ Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
Com_RCS = Com.rc
|
||||
|
||||
ifeq ($(T_A),$(EPICS_HOST_ARCH))
|
||||
# Antelope & flex are needed to finish libCom
|
||||
DELAY_INSTALL_LIBS = YES
|
||||
endif
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
include $(LIBCOM)/as/RULES
|
||||
|
||||
@@ -529,6 +529,12 @@ Init (rtems_task_argument ignored)
|
||||
putenv ("TERM=xterm");
|
||||
putenv ("IOCSH_HISTSIZE=20");
|
||||
|
||||
/*
|
||||
* Display some OS information
|
||||
*/
|
||||
printf("\n***** RTEMS Version: %s *****\n",
|
||||
rtems_get_version_string());
|
||||
|
||||
/*
|
||||
* Start network
|
||||
*/
|
||||
|
||||
@@ -486,7 +486,7 @@ epicsShareFunc int epicsShareAPI bucketShow(BUCKET *pb)
|
||||
unsigned count;
|
||||
unsigned maxEntries;
|
||||
|
||||
printf( "Bucket entries in use = %d bytes in use = %ld\n",
|
||||
printf( " Bucket entries in use = %d bytes in use = %ld\n",
|
||||
pb->nInUse,
|
||||
(long) (sizeof(*pb)+(pb->hashIdMask+1)*
|
||||
sizeof(ITEM *)+pb->nInUse*sizeof(ITEM)));
|
||||
@@ -511,7 +511,7 @@ epicsShareFunc int epicsShareAPI bucketShow(BUCKET *pb)
|
||||
|
||||
mean = X/nElem;
|
||||
stdDev = sqrt(XX/nElem - mean*mean);
|
||||
printf( "Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
|
||||
printf( " Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
|
||||
mean,
|
||||
stdDev,
|
||||
maxEntries);
|
||||
|
||||
@@ -33,6 +33,10 @@ static int cond_search(const char **ppinst, int match);
|
||||
#define PI 3.14159265358979323
|
||||
#endif
|
||||
|
||||
/* Turn off global optimization for 64-bit MSVC builds */
|
||||
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
|
||||
# pragma optimize("g", off)
|
||||
#endif
|
||||
|
||||
/* calcPerform
|
||||
*
|
||||
@@ -45,6 +49,7 @@ epicsShareFunc long
|
||||
double *ptop; /* stack pointer */
|
||||
double top; /* value from top of stack */
|
||||
epicsInt32 itop; /* integer from top of stack */
|
||||
epicsUInt32 utop; /* unsigned integer from top of stack */
|
||||
int op;
|
||||
int nargs;
|
||||
|
||||
@@ -262,7 +267,7 @@ epicsShareFunc long
|
||||
|
||||
case NINT:
|
||||
top = *ptop;
|
||||
*ptop = (double)(epicsInt32)(top >= 0 ? top + 0.5 : top - 0.5);
|
||||
*ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5);
|
||||
break;
|
||||
|
||||
case RANDOM:
|
||||
@@ -283,34 +288,45 @@ epicsShareFunc long
|
||||
*ptop = ! *ptop;
|
||||
break;
|
||||
|
||||
/* For bitwise operations on values with bit 31 set, double values
|
||||
* must first be cast to unsigned to correctly set that bit; the
|
||||
* double value must be negative in that case. The result must be
|
||||
* cast to a signed integer before converting to the double result.
|
||||
*/
|
||||
|
||||
case BIT_OR:
|
||||
itop = (epicsInt32) *ptop--;
|
||||
*ptop = (epicsInt32) *ptop | itop;
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
|
||||
break;
|
||||
|
||||
case BIT_AND:
|
||||
itop = (epicsInt32) *ptop--;
|
||||
*ptop = (epicsInt32) *ptop & itop;
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
|
||||
break;
|
||||
|
||||
case BIT_EXCL_OR:
|
||||
itop = (epicsInt32) *ptop--;
|
||||
*ptop = (epicsInt32) *ptop ^ itop;
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
|
||||
break;
|
||||
|
||||
case BIT_NOT:
|
||||
itop = (epicsInt32) *ptop;
|
||||
*ptop = ~itop;
|
||||
utop = *ptop;
|
||||
*ptop = (epicsInt32) ~utop;
|
||||
break;
|
||||
|
||||
/* The shift operators use signed integers, so a right-shift will
|
||||
* extend the sign bit into the left-hand end of the value. The
|
||||
* double-casting through unsigned here is important, see above.
|
||||
*/
|
||||
|
||||
case RIGHT_SHIFT:
|
||||
itop = (epicsInt32) *ptop--;
|
||||
*ptop = (epicsInt32) *ptop >> itop;
|
||||
utop = *ptop--;
|
||||
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
|
||||
break;
|
||||
|
||||
case LEFT_SHIFT:
|
||||
itop = (epicsInt32) *ptop--;
|
||||
*ptop = (epicsInt32) *ptop << itop;
|
||||
utop = *ptop--;
|
||||
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
|
||||
break;
|
||||
|
||||
case NOT_EQ:
|
||||
@@ -367,6 +383,9 @@ epicsShareFunc long
|
||||
*presult = *ptop;
|
||||
return 0;
|
||||
}
|
||||
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
|
||||
# pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
|
||||
epicsShareFunc long
|
||||
|
||||
@@ -251,7 +251,7 @@ epicsShareFunc long
|
||||
goto bad;
|
||||
}
|
||||
psrc = pnext;
|
||||
lit_i = (int) lit_d;
|
||||
lit_i = (epicsInt32) lit_d;
|
||||
if (lit_d != (double) lit_i) {
|
||||
*pout++ = pel->code;
|
||||
memcpy(pout, &lit_d, sizeof(double));
|
||||
@@ -272,8 +272,8 @@ epicsShareFunc long
|
||||
}
|
||||
psrc = pnext;
|
||||
*pout++ = LITERAL_INT;
|
||||
memcpy(pout, &lit_ui, sizeof(epicsInt32));
|
||||
pout += sizeof(epicsInt32);
|
||||
memcpy(pout, &lit_ui, sizeof(epicsUInt32));
|
||||
pout += sizeof(epicsUInt32);
|
||||
}
|
||||
|
||||
operand_needed = FALSE;
|
||||
|
||||
6
src/libCom/env/RULES
vendored
6
src/libCom/env/RULES
vendored
@@ -8,5 +8,7 @@
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
envData.c: $(LIBCOM)/env/envDefs.h $(LIBCOM)/env/bldEnvData.pl \
|
||||
$(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV
|
||||
$(PERL) $(LIBCOM)/env/bldEnvData.pl $(INSTALL_QUIETLY) $(CONFIG)
|
||||
$(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV \
|
||||
$(wildcard $(CONFIG)/os/CONFIG_SITE_ENV.$(T_A))
|
||||
$(PERL) $(LIBCOM)/env/bldEnvData.pl $(INSTALL_QUIETLY) -t $(T_A) \
|
||||
-c $(CMPLR_CLASS) -s $(OS_CLASS) $(CONFIG)
|
||||
|
||||
57
src/libCom/env/bldEnvData.pl
vendored
57
src/libCom/env/bldEnvData.pl
vendored
@@ -26,13 +26,13 @@ use Text::Wrap;
|
||||
|
||||
my $tool = basename($0);
|
||||
|
||||
our ($opt_h, $opt_q);
|
||||
our ($opt_h, $opt_q, $opt_t, $opt_s, $opt_c);
|
||||
our $opt_o = 'envData.c';
|
||||
|
||||
$Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
$Text::Wrap::columns = 75;
|
||||
|
||||
&HELP_MESSAGE unless getopts('ho:q') && @ARGV == 1;
|
||||
&HELP_MESSAGE unless getopts('ho:qt:s:c:') && @ARGV == 1;
|
||||
&HELP_MESSAGE if $opt_h;
|
||||
|
||||
my $config = AbsPath(shift);
|
||||
@@ -52,16 +52,31 @@ while (<SRC>) {
|
||||
}
|
||||
close SRC;
|
||||
|
||||
# Read the values from the CONFIG_ENV and CONFIG_SITE_ENV files
|
||||
# A list of configure/CONFIG_* files to read
|
||||
#
|
||||
my $config_env = "$config/CONFIG_ENV";
|
||||
my $config_site_env = "$config/CONFIG_SITE_ENV";
|
||||
my @configs = ("$config/CONFIG_ENV", "$config/CONFIG_SITE_ENV");
|
||||
|
||||
my %values;
|
||||
readReleaseFiles($config_env, \%values);
|
||||
readReleaseFiles($config_site_env, \%values);
|
||||
if ($opt_t) {
|
||||
my $config_arch_env = "$config/os/CONFIG_SITE_ENV.$opt_t";
|
||||
push @configs, $config_arch_env
|
||||
if -f $config_arch_env;
|
||||
}
|
||||
|
||||
# Warn about any vars with no value
|
||||
my @sources = ($env_defs, @configs);
|
||||
|
||||
# Get values from the config files
|
||||
#
|
||||
my (%values, @dummy);
|
||||
readRelease($_, \%values, \@dummy) foreach @configs;
|
||||
expandRelease(\%values);
|
||||
|
||||
# Get values from the command-line
|
||||
#
|
||||
$values{EPICS_BUILD_COMPILER_CLASS} = $opt_c if $opt_c;
|
||||
$values{EPICS_BUILD_OS_CLASS} = $opt_s if $opt_s;
|
||||
$values{EPICS_BUILD_TARGET_ARCH} = $opt_t if $opt_t;
|
||||
|
||||
# Warn about vars with no configured value
|
||||
#
|
||||
my @undefs = grep {!exists $values{$_}} @vars;
|
||||
warn "$tool: No value given for $_\n" foreach @undefs;
|
||||
@@ -73,13 +88,13 @@ print "Generating $opt_o\n" unless $opt_q;
|
||||
open OUT, '>', $opt_o
|
||||
or die "$tool: Cannot create $opt_o: $!\n";
|
||||
|
||||
my $sources = join "\n", map {" * $_"} @sources;
|
||||
|
||||
print OUT << "END";
|
||||
/* Generated file $opt_o
|
||||
*
|
||||
* Created from
|
||||
* $env_defs
|
||||
* $config_env
|
||||
* $config_site_env
|
||||
$sources
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -88,18 +103,23 @@ print OUT << "END";
|
||||
|
||||
END
|
||||
|
||||
# Define all parameters, giving variable name and default value
|
||||
# Define a default value for each named parameter
|
||||
#
|
||||
foreach my $var (@vars) {
|
||||
my $default = $values{$var} || '';
|
||||
$default =~ s/^"//;
|
||||
$default =~ s/"$//;
|
||||
my $default = $values{$var};
|
||||
if (defined $default) {
|
||||
$default =~ s/^"//;
|
||||
$default =~ s/"$//;
|
||||
}
|
||||
else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
print OUT "epicsShareDef const ENV_PARAM $var =\n",
|
||||
" {\"$var\", \"$default\"};\n";
|
||||
}
|
||||
|
||||
# Now create a list of all those parameters
|
||||
# Also provide a list of all defined parameters
|
||||
#
|
||||
print OUT "\n",
|
||||
"epicsShareDef const ENV_PARAM* env_param_list[] = {\n",
|
||||
@@ -112,6 +132,9 @@ sub HELP_MESSAGE {
|
||||
" -h Help: Print this message\n",
|
||||
" -q Quiet: Only print errors\n",
|
||||
" -o file Output filename, default is $opt_o\n",
|
||||
" -t arch Target architecture \$(T_A) name\n",
|
||||
" -s os Operating system \$(OS_CLASS)\n",
|
||||
" -c comp Compiler class \$(CMPLR_CLASS)\n",
|
||||
"\n";
|
||||
|
||||
exit 1;
|
||||
|
||||
7
src/libCom/env/envDefs.h
vendored
7
src/libCom/env/envDefs.h
vendored
@@ -40,7 +40,7 @@ typedef struct envParam {
|
||||
} ENV_PARAM;
|
||||
|
||||
/*
|
||||
* bldEnvData looks for "epicsShareExtern const ENV_PARAM"
|
||||
* bldEnvData.pl looks for "epicsShareExtern const ENV_PARAM <name>;"
|
||||
*/
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_CONN_TMO;
|
||||
@@ -58,6 +58,9 @@ epicsShareExtern const ENV_PARAM EPICS_CAS_SERVER_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_BEACON_PERIOD; /* deprecated */
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PERIOD;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_COMPILER_CLASS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH;
|
||||
epicsShareExtern const ENV_PARAM EPICS_TIMEZONE;
|
||||
epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT;
|
||||
@@ -88,6 +91,8 @@ epicsShareFunc long epicsShareAPI
|
||||
envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong);
|
||||
epicsShareFunc unsigned short epicsShareAPI envGetInetPortConfigParam
|
||||
(const ENV_PARAM *pEnv, unsigned short defaultPort);
|
||||
epicsShareFunc long epicsShareAPI
|
||||
envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool);
|
||||
epicsShareFunc long epicsShareAPI epicsPrtEnvParams(void);
|
||||
epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value);
|
||||
epicsShareFunc void epicsShareAPI epicsEnvShow (const char *name);
|
||||
|
||||
15
src/libCom/env/envSubr.c
vendored
15
src/libCom/env/envSubr.c
vendored
@@ -43,6 +43,7 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "errMdef.h"
|
||||
#include "errlog.h"
|
||||
#include "envDefs.h"
|
||||
@@ -319,7 +320,19 @@ long *pLong /* O pointer to place to store value */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
long epicsShareAPI
|
||||
envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool)
|
||||
{
|
||||
char text[20];
|
||||
|
||||
if(!envGetConfigParam(pParam, sizeof(text), text))
|
||||
return -1;
|
||||
*pBool = epicsStrCaseCmp(text, "yes")==0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envPrtConfigParam - print value of a configuration parameter
|
||||
*
|
||||
|
||||
@@ -70,12 +70,12 @@ epicsShareFunc int
|
||||
/* These macros return 1 if successful, 0 on failure.
|
||||
* This is analagous to the return value from sscanf()
|
||||
*/
|
||||
#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base, NULL)
|
||||
#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base, NULL)
|
||||
#define epicsScanLLong(str, to, base) !epicsParseLLong(str, to, base, NULL)
|
||||
#define epicsScanULLong(str, to, base) !epicsParseULLong(str, to, base, NULL)
|
||||
#define epicsScanFloat(str, to) !epicsParseFloat(str, to, NULL)
|
||||
#define epicsScanDouble(str, to) !epicsParseDouble(str, to, NULL)
|
||||
#define epicsScanLong(str, to, base) (!epicsParseLong(str, to, base, NULL))
|
||||
#define epicsScanULong(str, to, base) (!epicsParseULong(str, to, base, NULL))
|
||||
#define epicsScanLLong(str, to, base) (!epicsParseLLong(str, to, base, NULL))
|
||||
#define epicsScanULLong(str, to, base) (!epicsParseULLong(str, to, base, NULL))
|
||||
#define epicsScanFloat(str, to) (!epicsParseFloat(str, to, NULL))
|
||||
#define epicsScanDouble(str, to) (!epicsParseDouble(str, to, NULL))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ template class tsFreeList
|
||||
|
||||
extern "C" {
|
||||
static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * );
|
||||
static void ipAddrToAsciiEngineShutdownRequest ( void * );
|
||||
}
|
||||
|
||||
// - this class executes the synchronous DNS query
|
||||
@@ -107,10 +106,7 @@ private:
|
||||
unsigned cancelPendingCount;
|
||||
bool exitFlag;
|
||||
bool callbackInProgress;
|
||||
static epicsMutex * pGlobalMutex;
|
||||
static ipAddrToAsciiEnginePrivate * pEngine;
|
||||
static unsigned numberOfReferences;
|
||||
static bool shutdownRequest;
|
||||
ipAddrToAsciiTransaction & createTransaction ();
|
||||
void release ();
|
||||
void run ();
|
||||
@@ -118,15 +114,11 @@ private:
|
||||
ipAddrToAsciiEnginePrivate & operator = ( const ipAddrToAsciiEngine & );
|
||||
friend class ipAddrToAsciiEngine;
|
||||
friend class ipAddrToAsciiTransactionPrivate;
|
||||
friend void ipAddrToAsciiEngineShutdownRequest ( void * );
|
||||
friend void ipAddrToAsciiEngineGlobalMutexConstruct ( void * );
|
||||
};
|
||||
|
||||
epicsMutex * ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0;
|
||||
ipAddrToAsciiEnginePrivate * ipAddrToAsciiEnginePrivate :: pEngine = 0;
|
||||
unsigned ipAddrToAsciiEnginePrivate :: numberOfReferences = 0u;
|
||||
bool ipAddrToAsciiEnginePrivate :: shutdownRequest = false;
|
||||
static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = 0;
|
||||
static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
// the users are not required to supply a show routine
|
||||
// for there transaction callback class
|
||||
@@ -137,26 +129,13 @@ ipAddrToAsciiCallBack::~ipAddrToAsciiCallBack () {}
|
||||
ipAddrToAsciiTransaction::~ipAddrToAsciiTransaction () {}
|
||||
ipAddrToAsciiEngine::~ipAddrToAsciiEngine () {}
|
||||
|
||||
static void ipAddrToAsciiEngineShutdownRequest ( void * )
|
||||
{
|
||||
bool deleteGlobalMutexCondDetected = false;
|
||||
{
|
||||
epicsGuard < epicsMutex >
|
||||
guard ( * ipAddrToAsciiEnginePrivate :: pGlobalMutex );
|
||||
ipAddrToAsciiEnginePrivate :: shutdownRequest = true;
|
||||
deleteGlobalMutexCondDetected =
|
||||
( ipAddrToAsciiEnginePrivate :: numberOfReferences == 0 );
|
||||
}
|
||||
if ( deleteGlobalMutexCondDetected ) {
|
||||
delete ipAddrToAsciiEnginePrivate :: pGlobalMutex;
|
||||
ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * )
|
||||
{
|
||||
ipAddrToAsciiEnginePrivate :: pGlobalMutex = newEpicsMutex;
|
||||
epicsAtExit ( ipAddrToAsciiEngineShutdownRequest, 0 );
|
||||
try {
|
||||
ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate ();
|
||||
} catch (std::exception& e) {
|
||||
errlogPrintf("ipAddrToAsciiEnginePrivate ctor fails with: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
// for now its probably sufficent to allocate one
|
||||
@@ -168,21 +147,8 @@ ipAddrToAsciiEngine & ipAddrToAsciiEngine::allocate ()
|
||||
epicsThreadOnce (
|
||||
& ipAddrToAsciiEngineGlobalMutexOnceFlag,
|
||||
ipAddrToAsciiEngineGlobalMutexConstruct, 0 );
|
||||
// since we must not own lock when checking this flag
|
||||
// this diagnostic has imperfect detection, but never
|
||||
// incorrect detection
|
||||
if ( ipAddrToAsciiEnginePrivate :: shutdownRequest ) {
|
||||
throw std :: runtime_error (
|
||||
"ipAddrToAsciiEngine::allocate (): "
|
||||
"attempts to create an "
|
||||
"ipAddrToAsciiEngine while the exit "
|
||||
"handlers are running are rejected");
|
||||
}
|
||||
epicsGuard < epicsMutex > guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex );
|
||||
if ( ! ipAddrToAsciiEnginePrivate::pEngine ) {
|
||||
ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate ();
|
||||
}
|
||||
ipAddrToAsciiEnginePrivate::numberOfReferences++;
|
||||
if(!ipAddrToAsciiEnginePrivate::pEngine)
|
||||
throw std::runtime_error("ipAddrToAsciiEngine::allocate fails");
|
||||
return * ipAddrToAsciiEnginePrivate::pEngine;
|
||||
}
|
||||
|
||||
@@ -206,32 +172,8 @@ ipAddrToAsciiEnginePrivate::~ipAddrToAsciiEnginePrivate ()
|
||||
this->thread.exitWait ();
|
||||
}
|
||||
|
||||
// for now its probably sufficient to allocate one
|
||||
// DNS transaction thread for all codes sharing
|
||||
// the same process that need DNS services but we
|
||||
// leave our options open for the future
|
||||
void ipAddrToAsciiEnginePrivate::release ()
|
||||
{
|
||||
bool deleteGlobalMutexCondDetected = false;
|
||||
epicsThreadOnce (
|
||||
& ipAddrToAsciiEngineGlobalMutexOnceFlag,
|
||||
ipAddrToAsciiEngineGlobalMutexConstruct, 0 );
|
||||
{
|
||||
epicsGuard < epicsMutex >
|
||||
guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex );
|
||||
assert ( ipAddrToAsciiEnginePrivate::numberOfReferences > 0u );
|
||||
ipAddrToAsciiEnginePrivate::numberOfReferences--;
|
||||
if ( ipAddrToAsciiEnginePrivate::numberOfReferences == 0u ) {
|
||||
deleteGlobalMutexCondDetected =
|
||||
ipAddrToAsciiEnginePrivate :: shutdownRequest;
|
||||
delete ipAddrToAsciiEnginePrivate :: pEngine;
|
||||
ipAddrToAsciiEnginePrivate :: pEngine = 0;
|
||||
}
|
||||
}
|
||||
if ( deleteGlobalMutexCondDetected ) {
|
||||
delete ipAddrToAsciiEnginePrivate :: pGlobalMutex;
|
||||
ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ipAddrToAsciiEnginePrivate::show ( unsigned level ) const
|
||||
@@ -365,6 +307,8 @@ ipAddrToAsciiTransactionPrivate::~ipAddrToAsciiTransactionPrivate ()
|
||||
if ( this->engine.pCurrent == this &&
|
||||
this->engine.callbackInProgress &&
|
||||
! this->engine.thread.isCurrentThread() ) {
|
||||
// cancel from another thread while callback in progress
|
||||
// waits for callback to complete
|
||||
assert ( this->engine.cancelPendingCount < UINT_MAX );
|
||||
this->engine.cancelPendingCount++;
|
||||
{
|
||||
@@ -382,9 +326,11 @@ ipAddrToAsciiTransactionPrivate::~ipAddrToAsciiTransactionPrivate ()
|
||||
}
|
||||
else {
|
||||
if ( this->engine.pCurrent == this ) {
|
||||
// cancel from callback, or while lookup in progress
|
||||
this->engine.pCurrent = 0;
|
||||
}
|
||||
else {
|
||||
// cancel before lookup starts
|
||||
this->engine.labor.remove ( *this );
|
||||
}
|
||||
this->pending = false;
|
||||
|
||||
@@ -47,8 +47,11 @@ map {
|
||||
die "$tool: Variable missing from $infile" unless defined $_;
|
||||
} $ver, $rev, $mod, $patch, $snapshot, $commit_date;
|
||||
|
||||
$commit_date =~ s/^\$\$Date$\$$/\1/;
|
||||
|
||||
my $ver_str = "$ver.$rev.$mod";
|
||||
$ver_str .= ".$patch" if $patch > 0;
|
||||
my $ver_short = $ver_str;
|
||||
$ver_str .= $snapshot if $snapshot ne '';
|
||||
$ver_str .= "-$opt_v" if $opt_v;
|
||||
|
||||
@@ -71,10 +74,15 @@ print $OUT <<"END";
|
||||
#define EPICS_PATCH_LEVEL $patch
|
||||
#define EPICS_DEV_SNAPSHOT "$snapshot"
|
||||
#define EPICS_SITE_VERSION "$opt_v"
|
||||
|
||||
#define EPICS_VERSION_SHORT "$ver_short"
|
||||
#define EPICS_VERSION_FULL "$ver_str"
|
||||
#define EPICS_VERSION_STRING "EPICS $ver_str"
|
||||
#define epicsReleaseVersion "EPICS R$ver_str $commit_date"
|
||||
|
||||
#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
|
||||
#ifndef VERSION_INT
|
||||
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
|
||||
#endif
|
||||
#define EPICS_VERSION_INT VERSION_INT($ver, $rev, $mod, $patch)
|
||||
|
||||
#endif /* INC_${obase}_H */
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
#undef epicsShareAPI
|
||||
#undef READONLY
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN32__)
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
/*
|
||||
* Check if EPICS_BUILD_DLL or EPICS_CALL_DLL defined and use the dllimport/
|
||||
* dllexport keywords if this is a shared library build of base under WIN32.
|
||||
|
||||
@@ -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.
|
||||
\*************************************************************************/
|
||||
//
|
||||
// $Revision-Id$
|
||||
@@ -37,22 +37,22 @@ epicsThreadRunable::~epicsThreadRunable () {}
|
||||
void epicsThreadRunable::run () {}
|
||||
void epicsThreadRunable::show ( unsigned int ) const {}
|
||||
|
||||
class epicsThread :: unableToCreateThread :
|
||||
class epicsThread :: unableToCreateThread :
|
||||
public std :: exception {
|
||||
public:
|
||||
const char * what () const throw ();
|
||||
};
|
||||
|
||||
const char * epicsThread ::
|
||||
const char * epicsThread ::
|
||||
unableToCreateThread :: what () const throw ()
|
||||
{
|
||||
return "unable to create thread";
|
||||
}
|
||||
|
||||
void epicsThread :: printLastChanceExceptionMessage (
|
||||
void epicsThread :: printLastChanceExceptionMessage (
|
||||
const char * pExceptionTypeName,
|
||||
const char * pExceptionContext )
|
||||
{
|
||||
{
|
||||
char date[64];
|
||||
try {
|
||||
epicsTime cur = epicsTime :: getCurrent ();
|
||||
@@ -63,51 +63,52 @@ void epicsThread :: printLastChanceExceptionMessage (
|
||||
}
|
||||
char name [128];
|
||||
epicsThreadGetName ( this->id, name, sizeof ( name ) );
|
||||
errlogPrintf (
|
||||
errlogPrintf (
|
||||
"epicsThread: Unexpected C++ exception \"%s\" "
|
||||
"with type \"%s\" in thread \"%s\" at %s\n",
|
||||
pExceptionContext, pExceptionTypeName, name, date );
|
||||
errlogFlush ();
|
||||
// this should behave as the C++ implementation intends when an
|
||||
// exception isnt handled. If users dont like this behavior, they
|
||||
// can install an application specific unexpected handler.
|
||||
// This behavior matches the C++ implementation when an exception
|
||||
// isn't handled by the thread code. Users can install their own
|
||||
// application-specific unexpected handler if preferred.
|
||||
std::unexpected ();
|
||||
}
|
||||
|
||||
extern "C" void epicsThreadCallEntryPoint ( void * pPvt )
|
||||
{
|
||||
epicsThread * pThread =
|
||||
epicsThread * pThread =
|
||||
static_cast <epicsThread *> ( pPvt );
|
||||
bool waitRelease = false;
|
||||
bool threadDestroyed = false;
|
||||
try {
|
||||
pThread->pWaitReleaseFlag = & waitRelease;
|
||||
pThread->pThreadDestroyed = & threadDestroyed;
|
||||
if ( pThread->beginWait () ) {
|
||||
pThread->runable.run ();
|
||||
// current thread may have run the destructor
|
||||
// so must not touch the this pointer from
|
||||
// here on down if waitRelease is true
|
||||
// The run() routine may have destroyed the epicsThread
|
||||
// object by now; pThread can only be used below here
|
||||
// when the threadDestroyed flag is false.
|
||||
}
|
||||
}
|
||||
catch ( const epicsThread::exitException & ) {
|
||||
}
|
||||
catch ( std :: exception & except ) {
|
||||
if ( ! waitRelease ) {
|
||||
pThread->printLastChanceExceptionMessage (
|
||||
if ( ! threadDestroyed ) {
|
||||
pThread->printLastChanceExceptionMessage (
|
||||
typeid ( except ).name (), except.what () );
|
||||
}
|
||||
}
|
||||
catch ( ... ) {
|
||||
if ( ! waitRelease ) {
|
||||
pThread->printLastChanceExceptionMessage (
|
||||
if ( ! threadDestroyed ) {
|
||||
pThread->printLastChanceExceptionMessage (
|
||||
"catch ( ... )", "Non-standard C++ exception" );
|
||||
}
|
||||
}
|
||||
if ( ! waitRelease ) {
|
||||
if ( ! threadDestroyed ) {
|
||||
epicsGuard < epicsMutex > guard ( pThread->mutex );
|
||||
pThread->pThreadDestroyed = NULL;
|
||||
pThread->terminated = true;
|
||||
pThread->exitEvent.signal ();
|
||||
// once the terminated flag is set and we release the lock
|
||||
// then the "this" pointer must not be touched again
|
||||
// After the terminated flag is set and guard's destructor
|
||||
// releases the lock, pThread must never be used again.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,12 +136,12 @@ void epicsThread::exitWait () throw ()
|
||||
bool epicsThread::exitWait ( const double delay ) throw ()
|
||||
{
|
||||
try {
|
||||
// if destructor is running in managed thread then of
|
||||
// course we will not wait for the managed thread to
|
||||
// exit
|
||||
// When called (usually by a destructor) in the context of
|
||||
// the managed thread we can't wait for the thread to exit.
|
||||
// Set the threadDestroyed flag and return success.
|
||||
if ( this->isCurrentThread() ) {
|
||||
if ( this->pWaitReleaseFlag ) {
|
||||
*this->pWaitReleaseFlag = true;
|
||||
if ( this->pThreadDestroyed ) {
|
||||
*this->pThreadDestroyed = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -157,14 +158,14 @@ bool epicsThread::exitWait ( const double delay ) throw ()
|
||||
}
|
||||
}
|
||||
catch ( std :: exception & except ) {
|
||||
errlogPrintf (
|
||||
errlogPrintf (
|
||||
"epicsThread::exitWait(): Unexpected exception "
|
||||
" \"%s\"\n",
|
||||
" \"%s\"\n",
|
||||
except.what () );
|
||||
epicsThreadSleep ( epicsMin ( delay, 5.0 ) );
|
||||
}
|
||||
catch ( ... ) {
|
||||
errlogPrintf (
|
||||
errlogPrintf (
|
||||
"Non-standard unexpected exception in "
|
||||
"epicsThread::exitWait()\n" );
|
||||
epicsThreadSleep ( epicsMin ( delay, 5.0 ) );
|
||||
@@ -174,14 +175,14 @@ bool epicsThread::exitWait ( const double delay ) throw ()
|
||||
return this->terminated;
|
||||
}
|
||||
|
||||
epicsThread::epicsThread (
|
||||
epicsThread::epicsThread (
|
||||
epicsThreadRunable & runableIn, const char * pName,
|
||||
unsigned stackSize, unsigned priority ) :
|
||||
runable ( runableIn ), id ( 0 ), pWaitReleaseFlag ( 0 ),
|
||||
runable ( runableIn ), id ( 0 ), pThreadDestroyed ( 0 ),
|
||||
begin ( false ), cancel ( false ), terminated ( false )
|
||||
{
|
||||
this->id = epicsThreadCreate (
|
||||
pName, priority, stackSize, epicsThreadCallEntryPoint,
|
||||
this->id = epicsThreadCreate (
|
||||
pName, priority, stackSize, epicsThreadCallEntryPoint,
|
||||
static_cast < void * > ( this ) );
|
||||
if ( ! this->id ) {
|
||||
throw unableToCreateThread ();
|
||||
@@ -193,11 +194,11 @@ epicsThread::~epicsThread () throw ()
|
||||
while ( ! this->exitWait ( 10.0 ) ) {
|
||||
char nameBuf [256];
|
||||
this->getName ( nameBuf, sizeof ( nameBuf ) );
|
||||
fprintf ( stderr,
|
||||
fprintf ( stderr,
|
||||
"epicsThread::~epicsThread(): "
|
||||
"blocking for thread \"%s\" to exit\n",
|
||||
"blocking for thread \"%s\" to exit\n",
|
||||
nameBuf );
|
||||
fprintf ( stderr,
|
||||
fprintf ( stderr,
|
||||
"was epicsThread object destroyed before thread exit ?\n");
|
||||
}
|
||||
}
|
||||
@@ -272,11 +273,6 @@ void epicsThread::sleep (double seconds) throw ()
|
||||
epicsThreadSleep (seconds);
|
||||
}
|
||||
|
||||
//epicsThread & epicsThread::getSelf ()
|
||||
//{
|
||||
// return * static_cast<epicsThread *> ( epicsThreadGetIdSelf () );
|
||||
//}
|
||||
|
||||
const char *epicsThread::getNameSelf () throw ()
|
||||
{
|
||||
return epicsThreadGetNameSelf ();
|
||||
@@ -303,7 +299,7 @@ void epicsThread :: show ( unsigned level ) const throw ()
|
||||
if ( level > 0u ) {
|
||||
epicsThreadShow ( this->id, level - 1 );
|
||||
if ( level > 1u ) {
|
||||
::printf ( "pWaitReleaseFlag = %p\n", this->pWaitReleaseFlag );
|
||||
::printf ( "pThreadDestroyed = %p\n", this->pThreadDestroyed );
|
||||
::printf ( "begin = %c, cancel = %c, terminated = %c\n",
|
||||
this->begin ? 'T' : 'F',
|
||||
this->cancel ? 'T' : 'F',
|
||||
@@ -323,12 +319,12 @@ extern "C" {
|
||||
epicsThreadPrivateId okToBlockPrivate;
|
||||
static const int okToBlockNo = 0;
|
||||
static const int okToBlockYes = 1;
|
||||
|
||||
|
||||
static void epicsThreadOnceIdInit(void *)
|
||||
{
|
||||
okToBlockPrivate = epicsThreadPrivateCreate();
|
||||
}
|
||||
|
||||
|
||||
int epicsShareAPI epicsThreadIsOkToBlock(void)
|
||||
{
|
||||
const int *pokToBlock;
|
||||
@@ -336,7 +332,7 @@ extern "C" {
|
||||
pokToBlock = (int *) epicsThreadPrivateGet(okToBlockPrivate);
|
||||
return (pokToBlock ? *pokToBlock : 0);
|
||||
}
|
||||
|
||||
|
||||
void epicsShareAPI epicsThreadSetOkToBlock(int isOkToBlock)
|
||||
{
|
||||
const int *pokToBlock;
|
||||
@@ -344,12 +340,12 @@ extern "C" {
|
||||
pokToBlock = (isOkToBlock) ? &okToBlockYes : &okToBlockNo;
|
||||
epicsThreadPrivateSet(okToBlockPrivate, (void *)pokToBlock);
|
||||
}
|
||||
|
||||
|
||||
epicsThreadId epicsShareAPI epicsThreadMustCreate (
|
||||
const char *name, unsigned int priority, unsigned int stackSize,
|
||||
EPICSTHREADFUNC funptr,void *parm)
|
||||
EPICSTHREADFUNC funptr,void *parm)
|
||||
{
|
||||
epicsThreadId id = epicsThreadCreate (
|
||||
epicsThreadId id = epicsThreadCreate (
|
||||
name, priority, stackSize, funptr, parm );
|
||||
assert ( id );
|
||||
return id;
|
||||
|
||||
@@ -57,6 +57,12 @@ typedef epicsThreadId epicsThreadOnceId;
|
||||
epicsShareFunc void epicsShareAPI epicsThreadOnce(
|
||||
epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg);
|
||||
|
||||
/* When real-time scheduling is active, attempt any post-init operations
|
||||
* that preserve real-time performance. For POSIX targets this locks the
|
||||
* process into RAM, preventing swap-related VM faults.
|
||||
*/
|
||||
epicsShareFunc void epicsThreadRealtimeLock(void);
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadExitMain(void);
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (
|
||||
@@ -152,10 +158,10 @@ public:
|
||||
bool isCurrentThread () const throw ();
|
||||
bool operator == ( const epicsThread & ) const throw ();
|
||||
void show ( unsigned level ) const throw ();
|
||||
|
||||
/* these operate on the current thread */
|
||||
static void suspendSelf () throw ();
|
||||
static void sleep (double seconds) throw ();
|
||||
/* static epicsThread & getSelf (); */
|
||||
static const char * getNameSelf () throw ();
|
||||
static bool isOkToBlock () throw ();
|
||||
static void setOkToBlock ( bool isOkToBlock ) throw ();
|
||||
@@ -168,7 +174,7 @@ private:
|
||||
epicsMutex mutex;
|
||||
epicsEvent event;
|
||||
epicsEvent exitEvent;
|
||||
bool * pWaitReleaseFlag;
|
||||
bool * pThreadDestroyed;
|
||||
bool begin;
|
||||
bool cancel;
|
||||
bool terminated;
|
||||
|
||||
@@ -41,6 +41,7 @@ typedef socklen_t osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef socklen_t osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef socklen_t osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -248,6 +248,9 @@ epicsThreadInit (void)
|
||||
}
|
||||
}
|
||||
|
||||
void epicsThreadRealtimeLock(void)
|
||||
{}
|
||||
|
||||
/*
|
||||
* Create and start a new thread
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
*
|
||||
* Author: W. Eric Norum
|
||||
*/
|
||||
#define __BSD_VISIBLE 1
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <epicsStdio.h>
|
||||
#include <rtems.h>
|
||||
@@ -40,8 +43,37 @@ void osdTimeRegister(void)
|
||||
|
||||
int osdNTPGet(struct timespec *ts)
|
||||
{
|
||||
static unsigned bequiet;
|
||||
ssize_t ret;
|
||||
|
||||
if (ntpSocket < 0)
|
||||
return -1;
|
||||
|
||||
/* rtems_bsdnet_get_ntp() will send an NTP request, then
|
||||
* call recvfrom() exactly once to process the expected reply.
|
||||
* Any leftovers in the socket buffer (ie. duplicates of
|
||||
* previous replies) will cause problems.
|
||||
* So flush out the socket buffer first.
|
||||
*/
|
||||
do {
|
||||
char junk[16];
|
||||
|
||||
ret = recvfrom(ntpSocket, junk, sizeof(junk), MSG_DONTWAIT, NULL, NULL);
|
||||
if (ret == -1 && errno == EAGAIN) {
|
||||
break;
|
||||
}
|
||||
else if (ret == -1) {
|
||||
if (!bequiet) {
|
||||
printf("osdNTPGet cleaner error: %s\n", strerror(errno));
|
||||
bequiet = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
bequiet = 0;
|
||||
}
|
||||
} while (ret > 0);
|
||||
|
||||
return rtems_bsdnet_get_ntp(ntpSocket, NULL, ts);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# define WIN32
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#define SOCKERRNO WSAGetLastError()
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef int osiSocklen_t;
|
||||
#define SOCK_ECONNRESET WSAECONNRESET
|
||||
#define SOCK_ETIMEDOUT WSAETIMEDOUT
|
||||
#define SOCK_EADDRINUSE WSAEADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED WSAECONNREFUSED
|
||||
#define SOCK_ECONNABORTED WSAECONNABORTED
|
||||
#define SOCK_EINPROGRESS WSAEINPROGRESS
|
||||
|
||||
@@ -23,7 +23,7 @@ epicsShareFunc double epicsStrtod(const char *str, char **endp);
|
||||
* Older compilers have these equivalents though
|
||||
*/
|
||||
|
||||
#ifndef _MINGW
|
||||
#if !defined(_MINGW) && (_MSC_VER < 1800)
|
||||
# define strtoll _strtoi64
|
||||
# define strtoull _strtoui64
|
||||
#endif
|
||||
|
||||
@@ -303,6 +303,10 @@ static unsigned osdPriorityMagFromPriorityOSI ( unsigned osiPriority, unsigned p
|
||||
return magnitude;
|
||||
}
|
||||
|
||||
epicsShareFunc
|
||||
void epicsThreadRealtimeLock(void)
|
||||
{}
|
||||
|
||||
/*
|
||||
* epicsThreadGetOsdPriorityValue ()
|
||||
*/
|
||||
|
||||
@@ -124,148 +124,31 @@ static int osdTimeGetCurrent ( epicsTimeStamp *pDest )
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
inline void UnixTimeToFileTime ( const time_t * pAnsiTime, LPFILETIME pft )
|
||||
{
|
||||
LONGLONG ll = Int32x32To64 ( *pAnsiTime, 10000000 ) + 116444736000000000LL;
|
||||
pft->dwLowDateTime = static_cast < DWORD > ( ll );
|
||||
pft->dwHighDateTime = static_cast < DWORD > ( ll >>32 );
|
||||
}
|
||||
|
||||
static int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31,
|
||||
31, 30, 31, 30, 31 };
|
||||
|
||||
static bool isLeapYear ( DWORD year )
|
||||
{
|
||||
if ( (year % 4) == 0 ) {
|
||||
return ( ( year % 100 ) != 0 || ( year % 400 ) == 0 );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int dayOfYear ( DWORD day, DWORD month, DWORD year )
|
||||
{
|
||||
DWORD nDays = 0;
|
||||
for ( unsigned m = 1; m < month; m++ ) {
|
||||
nDays += daysInMonth[m-1];
|
||||
if ( m == 2 && isLeapYear(year) ) {
|
||||
nDays++;
|
||||
}
|
||||
}
|
||||
return nDays + day;
|
||||
}
|
||||
|
||||
// synthesize a reentrant gmtime on WIN32
|
||||
int epicsShareAPI epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
|
||||
{
|
||||
FILETIME ft;
|
||||
UnixTimeToFileTime ( pAnsiTime, &ft );
|
||||
|
||||
SYSTEMTIME st;
|
||||
BOOL status = FileTimeToSystemTime ( &ft, &st );
|
||||
if ( ! status ) {
|
||||
return epicsTimeERROR;
|
||||
struct tm * pRet = gmtime ( pAnsiTime );
|
||||
if ( pRet ) {
|
||||
*pTM = *pRet;
|
||||
return epicsTimeOK;
|
||||
}
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
|
||||
pTM->tm_sec = st.wSecond; // seconds after the minute - [0,59]
|
||||
pTM->tm_min = st.wMinute; // minutes after the hour - [0,59]
|
||||
pTM->tm_hour = st.wHour; // hours since midnight - [0,23]
|
||||
assert ( st.wDay >= 1 && st.wDay <= 31 );
|
||||
pTM->tm_mday = st.wDay; // day of the month - [1,31]
|
||||
assert ( st.wMonth >= 1 && st.wMonth <= 12 );
|
||||
pTM->tm_mon = st.wMonth - 1; // months since January - [0,11]
|
||||
assert ( st.wYear >= 1900 );
|
||||
pTM->tm_year = st.wYear - 1900; // years since 1900
|
||||
pTM->tm_wday = st.wDayOfWeek; // days since Sunday - [0,6]
|
||||
pTM->tm_yday = dayOfYear ( st.wDay, st.wMonth, st.wYear ) - 1;
|
||||
pTM->tm_isdst = 0;
|
||||
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
// synthesize a reentrant localtime on WIN32
|
||||
int epicsShareAPI epicsTime_localtime (
|
||||
const time_t * pAnsiTime, struct tm * pTM )
|
||||
{
|
||||
FILETIME ft;
|
||||
UnixTimeToFileTime ( pAnsiTime, & ft );
|
||||
|
||||
TIME_ZONE_INFORMATION tzInfo;
|
||||
DWORD tzStatus = GetTimeZoneInformation ( & tzInfo );
|
||||
if ( tzStatus == TIME_ZONE_ID_INVALID ) {
|
||||
return epicsTimeERROR;
|
||||
struct tm * pRet = localtime ( pAnsiTime );
|
||||
if ( pRet ) {
|
||||
*pTM = *pRet;
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
//
|
||||
// There are remarkable weaknesses in the FileTimeToLocalFileTime
|
||||
// interface so we don't use it here. Unfortunately, there is no
|
||||
// corresponding function that works on file time.
|
||||
//
|
||||
SYSTEMTIME st;
|
||||
BOOL success = FileTimeToSystemTime ( & ft, & st );
|
||||
if ( ! success ) {
|
||||
return epicsTimeERROR;
|
||||
else {
|
||||
return errno;
|
||||
}
|
||||
SYSTEMTIME lst;
|
||||
success = SystemTimeToTzSpecificLocalTime (
|
||||
& tzInfo, & st, & lst );
|
||||
if ( ! success ) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// We must convert back to file time so that we can determine if DST
|
||||
// is active...
|
||||
//
|
||||
FILETIME lft;
|
||||
success = SystemTimeToFileTime ( & lst, & lft );
|
||||
if ( ! success ) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
|
||||
int is_dst = -1; // unknown state of dst
|
||||
if ( tzStatus != TIME_ZONE_ID_UNKNOWN &&
|
||||
tzInfo.StandardDate.wMonth != 0 &&
|
||||
tzInfo.DaylightDate.wMonth != 0) {
|
||||
// determine if the specified date is
|
||||
// in daylight savings time
|
||||
tzInfo.StandardDate.wYear = st.wYear;
|
||||
FILETIME StandardDateFT;
|
||||
success = SystemTimeToFileTime (
|
||||
& tzInfo.StandardDate, & StandardDateFT );
|
||||
if ( ! success ) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
tzInfo.DaylightDate.wYear = st.wYear;
|
||||
FILETIME DaylightDateFT;
|
||||
success = SystemTimeToFileTime (
|
||||
& tzInfo.DaylightDate, & DaylightDateFT );
|
||||
if ( ! success ) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
if ( CompareFileTime ( & lft, & DaylightDateFT ) >= 0
|
||||
&& CompareFileTime ( & lft, & StandardDateFT ) < 0 ) {
|
||||
is_dst = 1;
|
||||
}
|
||||
else {
|
||||
is_dst = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pTM->tm_sec = lst.wSecond; // seconds after the minute - [0,59]
|
||||
pTM->tm_min = lst.wMinute; // minutes after the hour - [0,59]
|
||||
pTM->tm_hour = lst.wHour; // hours since midnight - [0,23]
|
||||
assert ( lst.wDay >= 1 && lst.wDay <= 31 );
|
||||
pTM->tm_mday = lst.wDay; // day of the month - [1,31]
|
||||
assert ( lst.wMonth >= 1 && lst.wMonth <= 12 );
|
||||
pTM->tm_mon = lst.wMonth - 1; // months since January - [0,11]
|
||||
assert ( lst.wYear >= 1900 );
|
||||
pTM->tm_year = lst.wYear - 1900; // years since 1900
|
||||
pTM->tm_wday = lst.wDayOfWeek; // days since Sunday - [0,6]
|
||||
pTM->tm_yday = dayOfYear ( lst.wDay, lst.wMonth, lst.wYear ) - 1;
|
||||
pTM->tm_isdst = is_dst;
|
||||
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
currentTime::currentTime () :
|
||||
|
||||
@@ -16,11 +16,17 @@
|
||||
#ifndef INC_osdTime_H
|
||||
#define INC_osdTime_H
|
||||
|
||||
/* MinGW only has a snippet time.h not protected against multiple inclusion */
|
||||
#if defined(__struct_timespec_defined)
|
||||
#define _TIMESPEC_DEFINED 1
|
||||
#endif
|
||||
|
||||
#if ! defined(_MINGW) || ! defined(_TIMESPEC_DEFINED)
|
||||
# if _MSC_VER >= 1900
|
||||
# include <time.h>
|
||||
# else
|
||||
|
||||
#define __struct_timespec_defined 1
|
||||
#define _TIMESPEC_DEFINED 1
|
||||
struct timespec {
|
||||
time_t tv_sec; /* seconds since some epoch */
|
||||
|
||||
@@ -50,6 +50,7 @@ typedef int osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <epicsTypes.h>
|
||||
#include <epicsEndian.h>
|
||||
#include <compilerSpecific.h>
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -27,7 +28,7 @@
|
||||
|
||||
/** @brief Read a single byte.
|
||||
*/
|
||||
INLINE
|
||||
static EPICS_ALWAYS_INLINE
|
||||
epicsUInt8
|
||||
ioread8(volatile void* addr)
|
||||
{
|
||||
@@ -36,7 +37,7 @@ ioread8(volatile void* addr)
|
||||
|
||||
/** @brief Write a single byte.
|
||||
*/
|
||||
INLINE
|
||||
static EPICS_ALWAYS_INLINE
|
||||
void
|
||||
iowrite8(volatile void* addr, epicsUInt8 val)
|
||||
{
|
||||
@@ -46,7 +47,7 @@ iowrite8(volatile void* addr, epicsUInt8 val)
|
||||
/** @brief Read two bytes in host order.
|
||||
* Not byte swapping
|
||||
*/
|
||||
INLINE
|
||||
static EPICS_ALWAYS_INLINE
|
||||
epicsUInt16
|
||||
nat_ioread16(volatile void* addr)
|
||||
{
|
||||
@@ -56,7 +57,7 @@ nat_ioread16(volatile void* addr)
|
||||
/** @brief Write two byte in host order.
|
||||
* Not byte swapping
|
||||
*/
|
||||
INLINE
|
||||
static EPICS_ALWAYS_INLINE
|
||||
void
|
||||
nat_iowrite16(volatile void* addr, epicsUInt16 val)
|
||||
{
|
||||
@@ -66,7 +67,7 @@ nat_iowrite16(volatile void* addr, epicsUInt16 val)
|
||||
/** @brief Read four bytes in host order.
|
||||
* Not byte swapping
|
||||
*/
|
||||
INLINE
|
||||
static EPICS_ALWAYS_INLINE
|
||||
epicsUInt32
|
||||
nat_ioread32(volatile void* addr)
|
||||
{
|
||||
@@ -76,7 +77,7 @@ nat_ioread32(volatile void* addr)
|
||||
/** @brief Write four byte in host order.
|
||||
* Not byte swapping
|
||||
*/
|
||||
INLINE
|
||||
static EPICS_ALWAYS_INLINE
|
||||
void
|
||||
nat_iowrite32(volatile void* addr, epicsUInt32 val)
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ static struct ifreq * ifreqNext ( struct ifreq *pifreq )
|
||||
struct ifreq *ifr;
|
||||
|
||||
ifr = ( struct ifreq * )( ifreqSize (pifreq) + ( char * ) pifreq );
|
||||
ifDepenDebugPrintf( ("ifreqNext() pifreq 0x%08x, size 0x%08x, ifr 0x%08x\n", pifreq, ifreqSize (pifreq), ifr) );
|
||||
ifDepenDebugPrintf( ("ifreqNext() pifreq %p, size 0x%x, ifr 0x%p\n", pifreq, (unsigned)ifreqSize (pifreq), ifr) );
|
||||
return ifr;
|
||||
}
|
||||
|
||||
@@ -105,8 +105,7 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
ifconf.ifc_req = pIfreqList;
|
||||
status = socket_ioctl (socket, SIOCGIFCONF, &ifconf);
|
||||
if (status < 0 || ifconf.ifc_len == 0) {
|
||||
ifDepenDebugPrintf(("osiSockDiscoverBroadcastAddresses(): status: 0x08x, ifconf.ifc_len: %d\n", status, ifconf.ifc_len));
|
||||
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration\n");
|
||||
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration (%d)\n", status);
|
||||
free (pIfreqList);
|
||||
return;
|
||||
}
|
||||
@@ -129,8 +128,8 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
|
||||
ifDepenDebugPrintf (("osiSockDiscoverBroadcastAddresses(): found IFACE: %s len: 0x%x current_ifreqsize: 0x%x \n",
|
||||
pIfreqList->ifr_name,
|
||||
ifreq_size(pifreq),
|
||||
current_ifreqsize));
|
||||
(unsigned)ifreq_size(pifreq),
|
||||
(unsigned)current_ifreqsize));
|
||||
|
||||
/*
|
||||
* If its not an internet interface then dont use it
|
||||
@@ -197,14 +196,22 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
|
||||
* interface.
|
||||
*/
|
||||
if ( pIfreqList->ifr_flags & IFF_BROADCAST ) {
|
||||
osiSockAddr baddr;
|
||||
status = socket_ioctl (socket, SIOCGIFBRDADDR, pIfreqList);
|
||||
if ( status ) {
|
||||
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": bcast addr fetch fail\n", pIfreqList->ifr_name);
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
|
||||
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( pNewNode->addr.ia.sin_addr.s_addr ) ) );
|
||||
baddr.sa = pIfreqList->ifr_broadaddr;
|
||||
if (baddr.ia.sin_family==AF_INET && baddr.ia.sin_addr.s_addr != INADDR_ANY) {
|
||||
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
|
||||
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
|
||||
} else {
|
||||
ifDepenDebugPrintf ( ( "Ignoring broadcast addr = \n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#if defined (IFF_POINTOPOINT)
|
||||
else if ( pIfreqList->ifr_flags & IFF_POINTOPOINT ) {
|
||||
|
||||
@@ -44,6 +44,7 @@ typedef socklen_t osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef socklen_t osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
|
||||
#ifdef isfinite
|
||||
# undef finite
|
||||
# define finite(x) isfinite(x)
|
||||
# define finite(x) isfinite((double)(x))
|
||||
#endif
|
||||
|
||||
epicsShareExtern float epicsNAN;
|
||||
|
||||
@@ -357,21 +357,10 @@ static void once(void)
|
||||
pcommonAttr->maxPriority);
|
||||
}
|
||||
|
||||
#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
|
||||
if(errVerbose) {
|
||||
fprintf(stderr, "LRT: min priority: %d max priority %d\n",
|
||||
if (errVerbose) {
|
||||
fprintf(stderr, "LRT: min priority: %d max priority %d\n",
|
||||
pcommonAttr->minPriority, pcommonAttr->maxPriority);
|
||||
}
|
||||
if (pcommonAttr->maxPriority > pcommonAttr->minPriority) {
|
||||
status = mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
if(status) {
|
||||
fprintf(stderr, "Unable to lock the virtual address space using mlockall\n");
|
||||
} else {
|
||||
fprintf(stderr,"Successfully locked memory using mlockAll\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
if(errVerbose) fprintf(stderr,"task priorities are not implemented\n");
|
||||
@@ -425,7 +414,22 @@ static void epicsThreadInit(void)
|
||||
checkStatusQuit(status,"pthread_once","epicsThreadInit");
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc
|
||||
void epicsThreadRealtimeLock(void)
|
||||
{
|
||||
#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
|
||||
if (pcommonAttr->maxPriority > pcommonAttr->minPriority) {
|
||||
int status = mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
|
||||
if (status) {
|
||||
fprintf(stderr, "epicsThreadRealtimeLock "
|
||||
"Warning: Unable to lock the virtual address space.\n"
|
||||
"VM page faults may harm real-time performance.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
|
||||
{
|
||||
#if defined (OSITHREAD_USE_DEFAULT_STACK)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef CYGWIN32
|
||||
#ifdef __CYGWIN__
|
||||
int clock_settime(clockid_t clock, const timespec *tp)
|
||||
{
|
||||
return -EFAULT;
|
||||
|
||||
@@ -52,6 +52,7 @@ typedef int osiSockIoctl_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -83,13 +83,18 @@
|
||||
* They do *not* all implement the sys{In/Out}{Byte/Word/Long}
|
||||
* functions to do the same thing though, so we can't use them.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
UINT8 sysPciInByte(UINT8 *addr);
|
||||
void sysPciOutByte(UINT8 *addr, UINT8 data);
|
||||
UINT16 sysPciInWord(UINT16 *addr);
|
||||
void sysPciOutWord(UINT16 *addr, UINT16 data);
|
||||
UINT32 sysPciInLong (UINT32 *addr);
|
||||
void sysPciOutLong (UINT32 *addr, UINT32 data);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ioread8(address) sysPciInByte((UINT8 *)(address))
|
||||
#define iowrite8(address,data) sysPciOutByte((UINT8 *)(address), (epicsUInt8)(data))
|
||||
|
||||
@@ -73,6 +73,7 @@ typedef int osiSocklen_t;
|
||||
#define SOCK_ECONNRESET ECONNRESET
|
||||
#define SOCK_ETIMEDOUT ETIMEDOUT
|
||||
#define SOCK_EADDRINUSE EADDRINUSE
|
||||
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
|
||||
#define SOCK_ECONNREFUSED ECONNREFUSED
|
||||
#define SOCK_ECONNABORTED ECONNABORTED
|
||||
#define SOCK_EINPROGRESS EINPROGRESS
|
||||
|
||||
@@ -114,6 +114,9 @@ static void epicsThreadInit(void)
|
||||
lock = 0;
|
||||
}
|
||||
|
||||
void epicsThreadRealtimeLock(void)
|
||||
{}
|
||||
|
||||
unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
|
||||
{
|
||||
|
||||
|
||||
@@ -96,6 +96,11 @@ epicsTimeTest_SRCS += epicsTimeTest.cpp
|
||||
testHarness_SRCS += epicsTimeTest.cpp
|
||||
TESTS += epicsTimeTest
|
||||
|
||||
TESTPROD_HOST += epicsTimeZoneTest
|
||||
epicsTimeZoneTest_SRCS += epicsTimeZoneTest.c
|
||||
libComTestHarness_SRCS_RTEMS += epicsTimeZoneTest.c
|
||||
TESTS += epicsTimeZoneTest
|
||||
|
||||
TESTPROD_HOST += epicsThreadTest
|
||||
epicsThreadTest_SRCS += epicsThreadTest.cpp
|
||||
testHarness_SRCS += epicsThreadTest.cpp
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// Author: Andrew Johnson
|
||||
|
||||
#include "epicsUnitTest.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsAlgorithm.h"
|
||||
#include "postfix.h"
|
||||
@@ -38,32 +39,59 @@ void testCalc(const char *expr, double expected) {
|
||||
/* Evaluate expression, test against expected result */
|
||||
bool pass = false;
|
||||
double args[CALCPERFORM_NARGS] = {
|
||||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0
|
||||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0
|
||||
};
|
||||
char rpn[MAX_POSTFIX_SIZE];
|
||||
short err;
|
||||
double result = 0.0;
|
||||
result /= result; /* Start as NaN */
|
||||
|
||||
|
||||
if (postfix(expr, rpn, &err)) {
|
||||
testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr);
|
||||
testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr);
|
||||
} else
|
||||
if (calcPerform(args, &result, rpn) && finite(result)) {
|
||||
testDiag("calcPerform: error evaluating '%s'", expr);
|
||||
}
|
||||
|
||||
if (calcPerform(args, &result, rpn) && finite(result)) {
|
||||
testDiag("calcPerform: error evaluating '%s'", expr);
|
||||
}
|
||||
|
||||
if (finite(expected) && finite(result)) {
|
||||
pass = fabs(expected - result) < 1e-8;
|
||||
pass = fabs(expected - result) < 1e-8;
|
||||
} else if (isnan(expected)) {
|
||||
pass = (bool) isnan(result);
|
||||
pass = (bool) isnan(result);
|
||||
} else {
|
||||
pass = (result == expected);
|
||||
pass = (result == expected);
|
||||
}
|
||||
if (!testOk(pass, "%s", expr)) {
|
||||
testDiag("Expected result is %g, actually got %g", expected, result);
|
||||
calcExprDump(rpn);
|
||||
testDiag("Expected result is %g, actually got %g", expected, result);
|
||||
calcExprDump(rpn);
|
||||
}
|
||||
}
|
||||
|
||||
void testUInt32Calc(const char *expr, epicsUInt32 expected) {
|
||||
/* Evaluate expression, test against expected result */
|
||||
bool pass = false;
|
||||
double args[CALCPERFORM_NARGS] = {
|
||||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0
|
||||
};
|
||||
char rpn[MAX_POSTFIX_SIZE];
|
||||
short err;
|
||||
epicsUInt32 uresult;
|
||||
double result = 0.0;
|
||||
result /= result; /* Start as NaN */
|
||||
|
||||
if (postfix(expr, rpn, &err)) {
|
||||
testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr);
|
||||
} else
|
||||
if (calcPerform(args, &result, rpn) && finite(result)) {
|
||||
testDiag("calcPerform: error evaluating '%s'", expr);
|
||||
}
|
||||
|
||||
uresult = (epicsUInt32) result;
|
||||
pass = (uresult == expected);
|
||||
if (!testOk(pass, "%s", expr)) {
|
||||
testDiag("Expected result is 0x%x (%u), actually got 0x%x (%u)",
|
||||
expected, expected, uresult, uresult);
|
||||
calcExprDump(rpn);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void testArgs(const char *expr, unsigned long einp, unsigned long eout) {
|
||||
@@ -238,8 +266,8 @@ MAIN(epicsCalcTest)
|
||||
const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0,
|
||||
g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0;
|
||||
|
||||
testPlan(577);
|
||||
|
||||
testPlan(613);
|
||||
|
||||
/* LITERAL_OPERAND elements */
|
||||
testExpr(0);
|
||||
testExpr(1);
|
||||
@@ -883,7 +911,51 @@ MAIN(epicsCalcTest)
|
||||
testBadExpr("1?", CALC_ERR_CONDITIONAL);
|
||||
testBadExpr("1?1", CALC_ERR_CONDITIONAL);
|
||||
testBadExpr(":1", CALC_ERR_SYNTAX);
|
||||
|
||||
|
||||
// Bit manipulations wrt bit 31 (bug lp:1514520)
|
||||
// using integer literals
|
||||
testUInt32Calc("0xaaaaaaaa AND 0xffff0000", 0xaaaa0000u);
|
||||
testUInt32Calc("0xaaaaaaaa OR 0xffff0000", 0xffffaaaau);
|
||||
testUInt32Calc("0xaaaaaaaa XOR 0xffff0000", 0x5555aaaau);
|
||||
testUInt32Calc("~0xaaaaaaaa", 0x55555555u);
|
||||
testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau);
|
||||
testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau);
|
||||
testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u);
|
||||
// using integer literals assigned to variables
|
||||
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a XOR b", 0x5555aaaau);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; ~a", 0x55555555u);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau);
|
||||
testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u);
|
||||
|
||||
// Test proper conversion of double values (+ 0.1 enforces double literal)
|
||||
// when used as inputs to the bitwise operations.
|
||||
// 0xaaaaaaaa = -1431655766 or 2863311530u
|
||||
testUInt32Calc("-1431655766.1 OR 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 OR 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("0 OR -1431655766.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("0 OR 2863311530.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("-1431655766.1 XOR 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 XOR 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("0 XOR -1431655766.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("0 XOR 2863311530.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("-1431655766.1 AND 0xffffffff", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 AND 0xffffffff", 0xaaaaaaaau);
|
||||
testUInt32Calc("0xffffffff AND -1431655766.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("0xffffffff AND 2863311530.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("~ -1431655766.1", 0x55555555u);
|
||||
testUInt32Calc("~ 2863311530.1", 0x55555555u);
|
||||
testUInt32Calc("-1431655766.1 >> 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 >> 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("-1431655766.1 >> 0.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 >> 0.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("-1431655766.1 << 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 << 0", 0xaaaaaaaau);
|
||||
testUInt32Calc("-1431655766.1 << 0.1", 0xaaaaaaaau);
|
||||
testUInt32Calc("2863311530.1 << 0.1", 0xaaaaaaaau);
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user