Compare commits
143 Commits
R3.14.11-p
...
R3.14.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c136fc07d | ||
|
|
534ca2c86e | ||
|
|
f17ac39f29 | ||
|
|
a4e5e540a9 | ||
|
|
33911cd0af | ||
|
|
1607d2a192 | ||
|
|
140b8a468d | ||
|
|
d84e9cb3ec | ||
|
|
fa24d119dd | ||
|
|
4921187178 | ||
|
|
794811b95a | ||
|
|
aa904449c0 | ||
|
|
1c95101ae1 | ||
|
|
0961378465 | ||
|
|
7655e7859d | ||
|
|
bbc0899423 | ||
|
|
3afade09e6 | ||
|
|
c28520bea6 | ||
|
|
bd4784a858 | ||
|
|
8c2278784c | ||
|
|
2caf1a4f50 | ||
|
|
1fba8dd866 | ||
|
|
87eace1bd4 | ||
|
|
db3a655374 | ||
|
|
8ae0c8960f | ||
|
|
ec26c0dc52 | ||
|
|
ea539fceb6 | ||
|
|
782ff1b303 | ||
|
|
2fb6b2100f | ||
|
|
0012042a5e | ||
|
|
e0d16659e1 | ||
|
|
8303cf053b | ||
|
|
78fc566dc4 | ||
|
|
3961c81740 | ||
|
|
0fdda3f794 | ||
|
|
9802e6c629 | ||
|
|
547c5d06ea | ||
|
|
50ddd62502 | ||
|
|
9fc48c9a6b | ||
|
|
e4075da4d7 | ||
|
|
8ace886cfe | ||
|
|
6c61c0de34 | ||
|
|
e581e88223 | ||
|
|
f4cbdec5ee | ||
|
|
b344841365 | ||
|
|
b867dabad0 | ||
|
|
0cea525682 | ||
|
|
2df7da052a | ||
|
|
59b820d2f5 | ||
|
|
3fda8dc2b0 | ||
|
|
3a335c88f0 | ||
|
|
44a6e9a005 | ||
|
|
1f129d3739 | ||
|
|
720236ed39 | ||
|
|
57c9f9344f | ||
|
|
64cb41f489 | ||
|
|
6fe047731f | ||
|
|
56c4c92588 | ||
|
|
562db1e24c | ||
|
|
1b70afa54b | ||
|
|
f316b4ca81 | ||
|
|
6d8cfeef01 | ||
|
|
b1b72e8cf0 | ||
|
|
cde59e262b | ||
|
|
40b6d1b0ba | ||
|
|
4464cfedaa | ||
|
|
b9fbf2e45b | ||
|
|
42ce1bd2db | ||
|
|
7de356519d | ||
|
|
ff5ca5e041 | ||
|
|
d1bb71809b | ||
|
|
7a49a17d1b | ||
|
|
7cf77b40e6 | ||
|
|
e387c06f59 | ||
|
|
c035566d7d | ||
|
|
57e5406684 | ||
|
|
b4948b4ff6 | ||
|
|
15f6b8c682 | ||
|
|
4868904839 | ||
|
|
1a2fa1bc86 | ||
|
|
e3a61ce4e4 | ||
|
|
efdee3c31a | ||
|
|
ee44663d89 | ||
|
|
90db5a4ab0 | ||
|
|
72dbaa8a0f | ||
|
|
458689a252 | ||
|
|
0daf347ef3 | ||
|
|
e32d8d77dc | ||
|
|
ffe7823c22 | ||
|
|
913f724ebf | ||
|
|
4e5fa9b6b3 | ||
|
|
a6b0ffebca | ||
|
|
7246366222 | ||
|
|
191668023b | ||
|
|
7a23b74a76 | ||
|
|
511d818d18 | ||
|
|
f8565139c2 | ||
|
|
30a02b365f | ||
|
|
b4bc931c72 | ||
|
|
e5d3815280 | ||
|
|
ebd65e6e34 | ||
|
|
8c45eb4a19 | ||
|
|
e1bb171f44 | ||
|
|
656c2462d3 | ||
|
|
f4ec20c8f0 | ||
|
|
72e1dba496 | ||
|
|
001b947702 | ||
|
|
c0d4317ade | ||
|
|
290ec3e22c | ||
|
|
d6b887b363 | ||
|
|
fbebea304b | ||
|
|
dd1d2c10bd | ||
|
|
d3e3137265 | ||
|
|
d764e7d4df | ||
|
|
49ddec4294 | ||
|
|
ce778819bd | ||
|
|
d5bffdb13d | ||
|
|
ba11940aad | ||
|
|
8725e4a67a | ||
|
|
a6e57ba17a | ||
|
|
7d137254af | ||
|
|
31fb3775fd | ||
|
|
1ba658b452 | ||
|
|
6eb25148c5 | ||
|
|
4ade695a60 | ||
|
|
bea22985b6 | ||
|
|
fd6d1ce69c | ||
|
|
844ed6345a | ||
|
|
7315f02888 | ||
|
|
1ba6da438b | ||
|
|
c986597f1c | ||
|
|
38b81b44be | ||
|
|
8382eee11a | ||
|
|
7d80ab72b0 | ||
|
|
3d86367330 | ||
|
|
16a6357ab4 | ||
|
|
f4bfc3928d | ||
|
|
4282d3e9f4 | ||
|
|
1e68d1f89b | ||
|
|
03b6345fe0 | ||
|
|
055bb953b9 | ||
|
|
01d223fafd | ||
|
|
7665d1340c |
@@ -33,14 +33,14 @@ EPICS_MODIFICATION = 11
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
|
||||
# This will end in -CVS between official releases
|
||||
EPICS_CVS_SNAPSHOT=-CVS
|
||||
#EPICS_CVS_SNAPSHOT=-CVS
|
||||
#EPICS_CVS_SNAPSHOT=-pre1
|
||||
#EPICS_CVS_SNAPSHOT=-pre1-CVS
|
||||
#EPICS_CVS_SNAPSHOT=-RC1
|
||||
#EPICS_CVS_SNAPSHOT=-RC1-CVS
|
||||
#EPICS_CVS_SNAPSHOT=-RC2
|
||||
#EPICS_CVS_SNAPSHOT=-RC2-CVS
|
||||
#EPICS_CVS_SNAPSHOT=
|
||||
EPICS_CVS_SNAPSHOT=
|
||||
|
||||
# No changes should be needed below here
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@ INSTALL_JAVA = $(INSTALL_LOCATION)/javalib
|
||||
#Directory for OS independant build created files
|
||||
COMMON_DIR = ../O.Common
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Make echo output - suppress echoing if make's '-s' flag is set
|
||||
ECHO := $(if $(findstring s,$(MAKEFLAGS)),\#,@echo)
|
||||
|
||||
#-------------------------------------------------------
|
||||
ifdef T_A
|
||||
|
||||
@@ -123,10 +127,6 @@ CMPLR_PREFIX=
|
||||
LIB_PREFIX=
|
||||
SHRLIB_PREFIX= $(LIB_PREFIX)
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Make echo output - suppress echoing if make's '-s' flag is set
|
||||
ECHO := $(if $(findstring s,$(MAKEFLAGS)),\#,@echo)
|
||||
|
||||
#--------------------------------------------------
|
||||
# vpath directories
|
||||
POSIX_YES = os/posix
|
||||
|
||||
@@ -106,6 +106,7 @@ MAKEDBDEPENDS = $(PERL) $(TOOLS)/makeDbDepends.pl
|
||||
|
||||
ifndef T_A
|
||||
|
||||
ECHO := $(if $(findstring s,$(MAKEFLAGS)),\#,@echo)
|
||||
COMMON_DIR = .
|
||||
INSTALL_DBDS =
|
||||
INSTALL_DBS =
|
||||
@@ -192,28 +193,28 @@ $(INSTALL_DB)/%.template: %.template
|
||||
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd
|
||||
@$(RM) $@$(DEP)
|
||||
@$(DBDDEPENDS_CMD)
|
||||
$(ECHO) "$<:../Makefile" >> $@$(DEP)
|
||||
@echo "$<:../Makefile" >> $@$(DEP)
|
||||
@$(RM) $@
|
||||
$(DBTORECORDTYPEH) $(DBDFLAGS) $< $@
|
||||
|
||||
$(COMMON_DIR)/%Record.h: %Record.dbd
|
||||
@$(RM) $@$(DEP)
|
||||
@$(DBDDEPENDS_CMD)
|
||||
$(ECHO) "$<:../Makefile" >> $@$(DEP)
|
||||
@echo "$<:../Makefile" >> $@$(DEP)
|
||||
@$(RM) $@
|
||||
$(DBTORECORDTYPEH) $(DBDFLAGS) $< $@
|
||||
|
||||
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd
|
||||
@$(RM) $@$(DEP)
|
||||
@$(DBDDEPENDS_CMD)
|
||||
$(ECHO) "$<:../Makefile" >> $@$(DEP)
|
||||
@echo "$<:../Makefile" >> $@$(DEP)
|
||||
@$(RM) $@
|
||||
$(DBTOMENUH) $(DBDFLAGS) $< $@
|
||||
|
||||
$(COMMON_DIR)/menu%.h: menu%.dbd
|
||||
@$(RM) $@$(DEP)
|
||||
@$(DBDDEPENDS_CMD)
|
||||
$(ECHO) "$<:../Makefile" >> $@$(DEP)
|
||||
@echo "$<:../Makefile" >> $@$(DEP)
|
||||
@$(RM) $@
|
||||
$(DBTOMENUH) $(DBDFLAGS) $< $@
|
||||
|
||||
@@ -228,7 +229,7 @@ $(COMMON_DIR)/bpt%.dbd: bpt%.data
|
||||
$(COMMON_DIR)/%.dbd: $(COMMON_DIR)/%Include.dbd
|
||||
@$(RM) $@$(DEP)
|
||||
@$(DBDDEPENDS_CMD)
|
||||
$(ECHO) "$<:../Makefile" >> $@$(DEP)
|
||||
@echo "$<:../Makefile" >> $@$(DEP)
|
||||
$(ECHO) "Expanding dbd"
|
||||
@$(RM) $@
|
||||
$(DBEXPAND) $(DBDFLAGS) -o $@ $<
|
||||
@@ -279,7 +280,7 @@ $(COMMON_DIR)/%.db$(RAW): $(COMMON_DIR)/%.edf
|
||||
$(COMMON_DIR)/%.db$(RAW): %.substitutions
|
||||
@$(RM) $@$(DEP)
|
||||
$(MAKEDBDEPENDS) $@ $< $(TEMPLATE_FILENAME) >> $@$(DEP)
|
||||
$(ECHO) "$@:$(TEMPLATE_FILENAME)" >> $@$(DEP)
|
||||
@echo "$@:$(TEMPLATE_FILENAME)" >> $@$(DEP)
|
||||
$(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"
|
||||
@$(RM) $@
|
||||
$(MSI) $(DBFLAGS) -S$< $(TEMPLATE_FILENAME) > msi.tmp
|
||||
|
||||
@@ -31,7 +31,7 @@ endif
|
||||
ifeq ($(wildcard $(INSTALL_LOCATION_LIB)/*),)
|
||||
@$(RMDIR) $(INSTALL_LOCATION_LIB)
|
||||
endif
|
||||
$(ECHO)
|
||||
@echo
|
||||
# The echo above stops a "nothing to be done for cleandirs" message
|
||||
|
||||
distclean: realclean realuninstall
|
||||
@@ -52,32 +52,32 @@ uninstallDirs:
|
||||
@$(RMDIR) $(UNINSTALL_DIRS)
|
||||
|
||||
help:
|
||||
$(ECHO) "Usage: gnumake [options] [target] ..."
|
||||
$(ECHO) "Targets supported by all Makefiles:"
|
||||
$(ECHO) " install - Builds and installs all targets (default rule)"
|
||||
$(ECHO) " all - Same as install"
|
||||
$(ECHO) " buildInstall - Same as install"
|
||||
$(ECHO) " clean - Removes the O.<arch> dirs created by running make"
|
||||
$(ECHO) " In O.<arch> dir, clean removes build created files"
|
||||
$(ECHO) " realclean - Removes ALL O.<arch> dirs"
|
||||
$(ECHO) " Cannot be used within an O.<arch> dir"
|
||||
$(ECHO) " rebuild - Same as clean install"
|
||||
$(ECHO) " inc - Installs header files"
|
||||
$(ECHO) " build - Builds all targets"
|
||||
$(ECHO) " archclean - Removes O.<arch> dirs but not O.Common dir"
|
||||
$(ECHO) "\"Partial\" build targets supported by Makefiles:"
|
||||
$(ECHO) " inc.<arch> - Installs <arch> only header files."
|
||||
$(ECHO) " install.<arch> - Builds and installs <arch> only."
|
||||
$(ECHO) " clean.<arch> - Cleans <arch> binaries in O.<arch> dirs only."
|
||||
$(ECHO) " build.<arch> - Builds <arch> only."
|
||||
$(ECHO) "Targets supported by top level Makefile:"
|
||||
$(ECHO) " uninstall - Cleans directories created by the install."
|
||||
$(ECHO) " realuninstall - Removes ALL install dirs"
|
||||
$(ECHO) " distclean - Same as realclean realuninstall."
|
||||
$(ECHO) " cvsclean - Removes cvs .#* files in all dirs of directory tree"
|
||||
$(ECHO) " help - Prints this list of valid make targets "
|
||||
$(ECHO) "Indiv. object targets are supported by O.<arch> level Makefile .e.g"
|
||||
$(ECHO) " xxxRecord.o"
|
||||
@echo "Usage: gnumake [options] [target] ..."
|
||||
@echo "Targets supported by all Makefiles:"
|
||||
@echo " install - Builds and installs all targets (default rule)"
|
||||
@echo " all - Same as install"
|
||||
@echo " buildInstall - Same as install"
|
||||
@echo " clean - Removes the O.<arch> dirs created by running make"
|
||||
@echo " In O.<arch> dir, clean removes build created files"
|
||||
@echo " realclean - Removes ALL O.<arch> dirs"
|
||||
@echo " Cannot be used within an O.<arch> dir"
|
||||
@echo " rebuild - Same as clean install"
|
||||
@echo " inc - Installs header files"
|
||||
@echo " build - Builds all targets"
|
||||
@echo " archclean - Removes O.<arch> dirs but not O.Common dir"
|
||||
@echo "\"Partial\" build targets supported by Makefiles:"
|
||||
@echo " inc.<arch> - Installs <arch> only header files."
|
||||
@echo " install.<arch> - Builds and installs <arch> only."
|
||||
@echo " clean.<arch> - Cleans <arch> binaries in O.<arch> dirs only."
|
||||
@echo " build.<arch> - Builds <arch> only."
|
||||
@echo "Targets supported by top level Makefile:"
|
||||
@echo " uninstall - Cleans directories created by the install."
|
||||
@echo " realuninstall - Removes ALL install dirs"
|
||||
@echo " distclean - Same as realclean realuninstall."
|
||||
@echo " cvsclean - Removes cvs .#* files in all dirs of directory tree"
|
||||
@echo " help - Prints this list of valid make targets "
|
||||
@echo "Indiv. object targets are supported by O.<arch> level Makefile .e.g"
|
||||
@echo " xxxRecord.o"
|
||||
|
||||
.PHONY : $(uninstallArchTargets)
|
||||
.PHONY : uninstall help cleandirs distclean uninstallDirs realuninstall
|
||||
|
||||
@@ -28,7 +28,7 @@ LOADABLE_SHRLIB_PREFIX = lib
|
||||
# <lib> -> lib<lib>.a
|
||||
LIBNAME = $(BUILD_LIBRARY:%=$(LIB_PREFIX)%$(LIB_SUFFIX))
|
||||
# <lib> -> lib<lib>.so.<version>
|
||||
SHRLIBNAME_YES = $(BUILD_LIBRARY:%=$(LIB_PREFIX)%$(SHRLIB_SUFFIX))
|
||||
SHRLIBNAME_YES = $(BUILD_LIBRARY:%=$(SHRLIB_PREFIX)%$(SHRLIB_SUFFIX))
|
||||
LOADABLE_SHRLIBNAME = $(LOADABLE_BUILD_LIBRARY:%=$(LOADABLE_SHRLIB_PREFIX)%$(LOADABLE_SHRLIB_SUFFIX))
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
@@ -13,7 +13,6 @@ ARCH_CLASS = arm
|
||||
|
||||
# Set a special definition for network order of Netwinder ARM floating point
|
||||
ARCH_DEP_CPPFLAGS += -D_ARM_NWFP_
|
||||
ARCH_DEP_CPPFLAGS += -mcpu=arm9 -marm
|
||||
|
||||
ifeq ($(BUILD_CLASS),CROSS)
|
||||
VALID_BUILDS = Ioc
|
||||
|
||||
@@ -4,34 +4,16 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<title>Known Problems R3.14.10-RC1</title>
|
||||
<title>Known Problems in R3.14.11</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="text-align: center">EPICS Base R3.14.10: Known Problems</h1>
|
||||
<h1 style="text-align: center">EPICS Base R3.14.11: Known Problems</h1>
|
||||
|
||||
<ul>
|
||||
<li>Parallel make (<tt>make -j</tt>) does not work on cygwin-x86 targets,
|
||||
probably due to a missing dependency in the EPICS build rules.</li>
|
||||
|
||||
<li>Some older Perl versions do not properly install the xsubpp program. This
|
||||
will prevent the build in src/cap5 from completing — the build will
|
||||
finish with an error like this:
|
||||
|
||||
<blockquote><pre>/bin/sh: /bin/xsubpp: not found
|
||||
make[3]: *** [Cap5.c] Error 1
|
||||
make[3]: Leaving directory `/home/phoebus3/ANJ/epics/base/3-14-dev/src/cap5/O.solaris-x86'
|
||||
make[2]: *** [install.solaris-x86] Error 2
|
||||
make[2]: Leaving directory `/home/phoebus3/ANJ/epics/base/3-14-dev/src/cap5'
|
||||
make[1]: *** [cap5.install] Error 2
|
||||
make[1]: Leaving directory `/home/phoebus3/ANJ/epics/base/3-14-dev/src'
|
||||
make: *** [src.install] Error 2</pre></blockquote>
|
||||
|
||||
As long as you don't intend to use the Perl5 CA interface this error is
|
||||
harmless, as cap5 is the last directory to be compiled in Base. If you need
|
||||
the Perl5 CA inteface, fix your Perl installation so that the perl binary
|
||||
and the xsubpp program (or soft links to them) are both found in the same
|
||||
directory.</li>
|
||||
<li>The epicsMutexTest program sometimes runs an extra test, resulting in
|
||||
a failure report from 'make -s runtests'. This is harmless.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -169,10 +169,10 @@ Software requirements
|
||||
|
||||
Host system storage requirements
|
||||
|
||||
The GNU zipped tar file is approximately 1.4 MB in size. The unzipped
|
||||
untarred distribution source tree is approximately 7.3 MB. The build created
|
||||
files for each host take approximately 40 MB and the build created files for
|
||||
each target take approximately 10 MB.
|
||||
The GNU zipped tar file is approximately 1.5 MB in size. The unzipped
|
||||
untarred distribution source tree is approximately 7.4 MB. The build created
|
||||
files for each host take approximately 37 MB and the build created files for
|
||||
each cross target take approximately 15 MB.
|
||||
|
||||
Documentation
|
||||
|
||||
|
||||
@@ -177,10 +177,10 @@ RTEMS-uC5282
|
||||
are used.</P>
|
||||
</BLOCKQUOTE>
|
||||
<H3><A NAME="0_0_7"> Host system storage requirements</A></H3>
|
||||
<BLOCKQUOTE>The GNU zipped tar file is approximately 1.4 MB in size. The
|
||||
unzipped untarred distribution source tree is approximately 7.3 MB. The
|
||||
build created files for each host take approximately 40 MB and the
|
||||
build created files for each target take approximately 10 MB.</BLOCKQUOTE>
|
||||
<BLOCKQUOTE>The GNU zipped tar file is approximately 1.5 MB in size. The
|
||||
unzipped untarred distribution source tree is approximately 7.4 MB. The
|
||||
build created files for each host take approximately 37 MB and the
|
||||
build created files for each cross target take approximately 15 MB.</BLOCKQUOTE>
|
||||
<H3><A NAME="0_0_8"> Documentation</A></H3>
|
||||
<BLOCKQUOTE>EPICS documentation is available on the WWW via the EPICS
|
||||
home page at APS: URL<A href="http://www.aps.anl.gov/epics">
|
||||
|
||||
@@ -3,16 +3,159 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<title>EPICS Base R3.14.x Release Notes</title>
|
||||
<title>EPICS Base R3.14.11-RC1 Release Notes</title>
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 align="center">EPICS Base Release 3.14.1x</h1>
|
||||
<h1 align="center">EPICS Base Release 3.14.11</h1>
|
||||
|
||||
<h2 align="center">Changes between 3.14.10 and 3.14.11</h2>
|
||||
<!-- Insert new items below here ... -->
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h4>Several macros and includes removed from dbDefs.h</h4>
|
||||
<h4>Extra argument to ellFree()</h4>
|
||||
|
||||
<p>To work properly from Windows DLLs we had to add a second argument to the
|
||||
ellFree() function, which should be passed the free function to be called. In
|
||||
most cases this will involve just adding <tt><b>, free</b></tt> to the argument
|
||||
list.</p>
|
||||
|
||||
<h4>Time provider on Win32</h4>
|
||||
|
||||
<p>A race condition meant that sometimes EPICS programs (including the internal
|
||||
programs such as flex and antelope) built for Win32 architectures would not
|
||||
start properly on Windows systems that have multiple CPUs. This race has been
|
||||
fixed.</p>
|
||||
|
||||
<h4>Build system dependency change</h4>
|
||||
|
||||
<p>In order to get GNU make parallel execution (-j option) to work proprely for
|
||||
multiple target architectures, a new dependency had to be added. Now all
|
||||
cross-compiled builds depend on their host build. This means that when a
|
||||
<tt>make <i>crosstargetarch</i></tt> command is issued, the EPICS_HOST_ARCH
|
||||
target build will be executed first, followed by the <i>crosstargetarch</i>
|
||||
build. Builds done in an O.<i>arch</i> directory will still only build the
|
||||
<i>arch</i> targets however.</p>
|
||||
|
||||
<h4>Channel Access changes</h4>
|
||||
|
||||
<p>Mantis 361 fix - ca_add_fd_registration users might not receive select
|
||||
wakeup</p>
|
||||
|
||||
<p>Mantis 359 fix - ca client library flow control mode related issues</p>
|
||||
|
||||
<p>Mantis 357 fix - high throughput multithreaded ca client appl thread could
|
||||
be trapped in lib.</p>
|
||||
|
||||
<ul>
|
||||
<li>Discovered during code review. Not seen in practice, but possible</li>
|
||||
</ul>
|
||||
|
||||
<p>Mantis 285 fix - CA Documentation doesn't distinguish sync groups from
|
||||
ca_put_callback()</p>
|
||||
|
||||
<p>Mantis 346 fix - deleting the chid passed in from within put cb handler
|
||||
causes failure</p>
|
||||
|
||||
<p>Mantis 284 fix - channel clear protocol warning messages from PCAS</p>
|
||||
|
||||
<p>Mantis 237 fix - SEGV from simple CA client during context destroy</p>
|
||||
|
||||
<p>Mantis 242 fix - invalid DBR type not screened in client library when
|
||||
doing a put</p>
|
||||
|
||||
<h4>Portable Channel Access Server changes</h4>
|
||||
|
||||
<p> These changes impact the Gateway (Proxy server) and other servers but not
|
||||
the IOC.</h4>
|
||||
|
||||
<p>Mantis 360 fix - server is unresponsive for one of its clients, when
|
||||
async io postponed and in flow control mode</p>
|
||||
|
||||
<p>Mantis 358 fix - PCAS service snap-in has no way to determine if its a put,
|
||||
or a put calback.</p>
|
||||
|
||||
<p>Mantis 356 fix - medm display sometimes hangs until the motor stops when
|
||||
controling motor through gw.</p>
|
||||
|
||||
<p>Mantis 350 fix - Incoming data corruption under heavy CAS load.</p>
|
||||
|
||||
<p>Mantis 340 fix - leak when performing a read and conversion fails.</p>
|
||||
|
||||
<p>Mantis 348 fix - A call to 'assert (item.pList == this)'
|
||||
failed in ../../../../src/cas/generic/st/ioBlocked.cc line 112</p>
|
||||
|
||||
<p>Mantis 345 fix - Compilation warning: complaint about missing
|
||||
gddDestructor</p>
|
||||
|
||||
<p>Mantis 343 fix - gddScalar::new() operator is not fully thread safe</p>
|
||||
|
||||
<p>Mantis 333 fix - resTable::removeAll() does not reset the item count</p>
|
||||
|
||||
<p>Mantis 335 fix - excas fails in clearOutstandingReads - maybe requires an
|
||||
R3.13 client</p>
|
||||
|
||||
<p>Mantis 329 fix - GW hang, pthread_mutex_lock failed: error Invalid
|
||||
argument message</p>
|
||||
|
||||
<p>Mantis 352 fix - gateway hangs temporarily under heavy load on 8-core
|
||||
64bit RHEL5</p>
|
||||
|
||||
<ul>
|
||||
<li>High throughput performance appears to be much better now for both scalars
|
||||
and large arrays, but more testing needed in operational gateways</li>
|
||||
</ul>
|
||||
|
||||
<h4>Timer Queue Library</h4>
|
||||
|
||||
<p>Mantis 336 fix - timer queue should have try / catch block around call to
|
||||
user's expiration callback</p>
|
||||
|
||||
<p>Mantis 332 fix - epicsTimerTest failure, windows vista 64, dual core
|
||||
SMP system</p>
|
||||
|
||||
<h4>LibCom</h4>
|
||||
|
||||
<p>Mantis 328 fixed - orderly shutdown for soft IOC fails</p>
|
||||
|
||||
<h4>Application configure files</h4>
|
||||
|
||||
<p>The configuration directory files installed by makeBaseApp.pl have been
|
||||
changing in recent releases to make them work more like the files in the Base
|
||||
configuration directory. The CONFIG_APP file has gone, and its functionality is
|
||||
now performed by the CONFIG file which should only be modified in exceptional
|
||||
circumstances. The variables that used to be set in the CONFIG file now appear
|
||||
in the new CONFIG_SITE file, and can be overridden for specific combinations of
|
||||
host and target architectures by creating a file with name matching one of these
|
||||
patterns:</p>
|
||||
|
||||
<ul>
|
||||
<li>CONFIG_SITE.<host-arch>.Common</li>
|
||||
<li>CONFIG_SITE.Common.<target-arch></li>
|
||||
<li>CONFIG_SITE.<host-arch>.<target-arch></li>
|
||||
</ul>
|
||||
|
||||
<p>Note that the setting for <tt>CHECK_RELEASE</tt> in the CONFIG_SITE files is
|
||||
not compatible with previous releases of Base; if you are creating an
|
||||
application that has to work with earlier releases, move the
|
||||
<tt>CHECK_RELEASE</tt> setting back to the configure/Makefile where it used to
|
||||
live.</p>
|
||||
|
||||
<p>The RELEASE file(s) can now define the variable <tt>RULES</tt> if you wish
|
||||
the application to use build rules from some module other than EPICS_BASE. The
|
||||
rules must appear in a configure subdirectory just like they do in Base.</p>
|
||||
|
||||
<h4>Compile-time assertions</h4>
|
||||
|
||||
<p>A new macro has been added to epicsAssert.h which performs assertion checks
|
||||
at compile-time. <tt>STATIC_ASSERT(<i>expr</i>)</tt> can only be used when
|
||||
<tt><i>expr</i></tt> can be evaluated by the compiler, and will cause the
|
||||
compilation to fail if it evaluates to false. The resulting compiler error
|
||||
message might appear a little obscure, but it does provide some explanation and
|
||||
contains the line where the failure was discovered. Future versions of the C++
|
||||
standard will probably contain a similar facility <tt>static_assert(<i>expr</i>,
|
||||
<i>message</i>)</tt> but will require compiler support to be implemented.</p>
|
||||
|
||||
<h4>Several changes made to dbDefs.h</h4>
|
||||
|
||||
<p>The definitions for the macros <tt>YES</tt>, <tt>NO</tt>, <tt>NONE</tt>,
|
||||
<tt>min()</tt> and <tt>max()</tt> have been deleted. <tt>YES</tt> and
|
||||
@@ -21,15 +164,15 @@ from the menuYesNo.h file where they were used in several record types. The
|
||||
other macros were not being used anywhere in Base, sncseq or Asyn.</p>
|
||||
|
||||
<p>The macro <tt>LOCAL</tt> that was a synonym for <tt>static</tt> is now
|
||||
deprecated and will be deleted soon, please adjust your code to use the latter
|
||||
keyword. Any uses of the <tt>READONLY</tt> macro from shareLib.h must now be
|
||||
replaced by the keyword <tt>const</tt>.</p>
|
||||
deprecated and will be deleted in R3.15, please adjust your code to use the
|
||||
latter keyword. All uses of the <tt>READONLY</tt> macro from shareLib.h must
|
||||
now be replaced by the keyword <tt>const</tt> as the macro has been deleted.</p>
|
||||
|
||||
<p>The dbDefs.h file was also unnecessarily including some other libCom header
|
||||
<p>The dbDefs.h file was unnecessarily including various other libCom header
|
||||
files which may have to be manually added to out-of-tree source files that
|
||||
relied on this. The general rule for header files is that a header should only
|
||||
include other headers that are needed for its own inclusion in any source
|
||||
file. The <tt>#include</tt> statements that might need to be added are:</p>
|
||||
include other headers that are needed for its own inclusion in any source file.
|
||||
The <tt>#include</tt> statements that might need to be added are:</p>
|
||||
|
||||
<ul>
|
||||
<li>#include <stdarg.h></li>
|
||||
@@ -39,6 +182,17 @@ file. The <tt>#include</tt> statements that might need to be added are:</p>
|
||||
<li>#include "epicsTypes.h"</li>
|
||||
</ul>
|
||||
|
||||
<p>A new macro <tt>CONTAINER(pointer, type, member)</tt> has been added which
|
||||
calculates and returns a pointer to the parent structure when given a pointer to
|
||||
a member, the structure type and the name of the member in that structure. On
|
||||
GNU compilers the type of the pointer is checked to ensure that it matches the
|
||||
member, so code using this macro should be built using gcc for additional
|
||||
confidence.</p>
|
||||
|
||||
<h4>Long-deprecated errSymFind() function deleted</h4>
|
||||
|
||||
<p>This functionality was replaced by errSymLookup() many releases ago.</p>
|
||||
|
||||
<h4>Perl CA library shutdown</h4>
|
||||
|
||||
<p>The Perl CA library has been modified to properly flush the Channel Access
|
||||
@@ -266,6 +420,16 @@ clients, although by no means all clients support it yet.</p>
|
||||
now uses _NSGetEnviron() to get the pointer to the environment string
|
||||
table.</p>
|
||||
|
||||
<h4>gpHash argument type changed</h4>
|
||||
|
||||
<p>Out-of-tree users of libCom's gpHash routines should change the type of their
|
||||
pointer to their gpHash table to avoid compiler warnings. The first argument to
|
||||
all of the <tt>gph...()</tt> routines used to be a <tt>void *</tt> (or a
|
||||
pointer to one for <tt>gphInit()</tt>) but is now a <tt>struct
|
||||
gphPvt *</tt> (<tt>struct gphPvt **</tt> for <tt>gphInit</tt>) for
|
||||
better type safety. The definition of the structure has not been made public,
|
||||
although a declaration is provided in <tt>gpHash.h</tt>.</p>
|
||||
|
||||
<h4>New hash functions in epicsString.h</h4>
|
||||
|
||||
<p>The existing routines used to hash strings have been replaced by a new
|
||||
@@ -465,7 +629,7 @@ time provider you need to use RTEMS 4.9.1 or newer.</p>
|
||||
<h4>RTEMS epicsEventWaitWithTimeout</h4>
|
||||
|
||||
<p>Correctly return epicsEventWaitTimeout when event is not pending and
|
||||
timeout value is 0.0 secondsmore agressive.</p>
|
||||
timeout value is 0.0 seconds.</p>
|
||||
|
||||
<h4>epicsRingPointer, epicsRingBytes</h4>
|
||||
|
||||
|
||||
@@ -19,10 +19,14 @@
|
||||
* RTEMS CONFIGURATION *
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#define CONFIGURE_UNIFIED_WORK_AREAS
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#if __RTEMS_MAJOR__>4 || ( __RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9 )
|
||||
# define CONFIGURE_UNIFIED_WORK_AREAS
|
||||
#else
|
||||
# define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
|
||||
#endif
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
|
||||
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
|
||||
|
||||
@@ -1617,6 +1617,16 @@ the application Developer's Guide.</p>
|
||||
<td>the default, nnn is one, enables synchronous scanning, and if nnn is
|
||||
zero it turns on asynchronous scanning</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-ad <n.n></td>
|
||||
<td>set the delay before asynchronous operations complete (defaults to
|
||||
0.1 seconds)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-an <nnn></td>
|
||||
<td>set the maximum number of simultaneous asynchronous operations
|
||||
(defaults to 1000)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -351,6 +351,13 @@ int epicsShareAPI ca_create_channel (
|
||||
catch ( cacChannel::unsupportedByService & ) {
|
||||
return ECA_UNAVAILINSERV;
|
||||
}
|
||||
catch ( std :: exception & except ) {
|
||||
pcac->printFormated (
|
||||
"ca_create_channel: "
|
||||
"unexpected exception was \"%s\"",
|
||||
except.what () );
|
||||
return ECA_INTERNAL;
|
||||
}
|
||||
catch ( ... ) {
|
||||
return ECA_INTERNAL;
|
||||
}
|
||||
|
||||
336
src/ca/acctst.c
336
src/ca/acctst.c
@@ -55,6 +55,9 @@ static epicsTimeStamp showProgressBeginTime;
|
||||
|
||||
static const double timeoutToPendIO = 1e20;
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
void showProgressBegin ( const char *pTestName, unsigned interestLevel )
|
||||
{
|
||||
|
||||
@@ -133,7 +136,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
}
|
||||
assert ( eventCount > 0 );
|
||||
verify ( eventCount > 0 );
|
||||
|
||||
/* clear any knowledge of old gets */
|
||||
ca_pend_io ( 1e-5 );
|
||||
@@ -167,7 +170,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
}
|
||||
assert ( eventCount > 0 );
|
||||
verify ( eventCount > 0 );
|
||||
|
||||
status = ca_clear_event ( id );
|
||||
SEVCHK (status, 0);
|
||||
@@ -193,7 +196,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
}
|
||||
assert ( eventCount > 0 );
|
||||
verify ( eventCount > 0 );
|
||||
|
||||
/* verify that a ca_put() produces an update, but */
|
||||
/* this may fail if there is an unusual deadband */
|
||||
@@ -224,7 +227,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
}
|
||||
assert ( eventCount > 0 );
|
||||
verify ( eventCount > 0 );
|
||||
|
||||
/* clean up */
|
||||
status = ca_clear_channel ( chan2 );
|
||||
@@ -282,7 +285,7 @@ void verifyMonitorSubscriptionFlushIO ( chid chan, unsigned interestLevel )
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
}
|
||||
assert ( eventCount > 0 );
|
||||
verify ( eventCount > 0 );
|
||||
status = ca_clear_event ( id );
|
||||
SEVCHK (status, 0);
|
||||
|
||||
@@ -293,9 +296,9 @@ void accessRightsStateChange ( struct access_rights_handler_args args )
|
||||
{
|
||||
appChan *pChan = (appChan *) ca_puser ( args.chid );
|
||||
|
||||
assert ( pChan->channel == args.chid );
|
||||
assert ( args.ar.read_access == ca_read_access ( args.chid ) );
|
||||
assert ( args.ar.write_access == ca_write_access ( args.chid ) );
|
||||
verify ( pChan->channel == args.chid );
|
||||
verify ( args.ar.read_access == ca_read_access ( args.chid ) );
|
||||
verify ( args.ar.write_access == ca_write_access ( args.chid ) );
|
||||
accessUpdateCount++;
|
||||
pChan->accessUpdateCount++;
|
||||
}
|
||||
@@ -304,12 +307,12 @@ void getCallbackStateChange ( struct event_handler_args args )
|
||||
{
|
||||
appChan *pChan = (appChan *) args.usr;
|
||||
|
||||
assert ( pChan->channel == args.chid );
|
||||
assert ( pChan->connected );
|
||||
verify ( pChan->channel == args.chid );
|
||||
verify ( pChan->connected );
|
||||
if ( args.status != ECA_NORMAL ) {
|
||||
printf ( "getCallbackStateChange abnormal status was \"%s\"\n",
|
||||
ca_message ( args.status ) );
|
||||
assert ( args.status == ECA_NORMAL );
|
||||
verify ( args.status == ECA_NORMAL );
|
||||
}
|
||||
|
||||
getCallbackCount++;
|
||||
@@ -322,25 +325,25 @@ void connectionStateChange ( struct connection_handler_args args )
|
||||
|
||||
appChan *pChan = (appChan *) ca_puser ( args.chid );
|
||||
|
||||
assert ( pChan->channel == args.chid );
|
||||
verify ( pChan->channel == args.chid );
|
||||
|
||||
if ( args.op == CA_OP_CONN_UP ) {
|
||||
if ( pChan->accessRightsHandlerInstalled ) {
|
||||
assert ( pChan->accessUpdateCount > 0u );
|
||||
verify ( pChan->accessUpdateCount > 0u );
|
||||
}
|
||||
assert ( ! pChan->connected );
|
||||
verify ( ! pChan->connected );
|
||||
pChan->connected = 1;
|
||||
status = ca_get_callback ( DBR_STS_STRING, args.chid, getCallbackStateChange, pChan );
|
||||
SEVCHK (status, 0);
|
||||
}
|
||||
else if ( args.op == CA_OP_CONN_DOWN ) {
|
||||
assert ( pChan->connected );
|
||||
verify ( pChan->connected );
|
||||
pChan->connected = 0u;
|
||||
assert ( ! ca_read_access ( args.chid ) );
|
||||
assert ( ! ca_write_access ( args.chid ) );
|
||||
verify ( ! ca_read_access ( args.chid ) );
|
||||
verify ( ! ca_write_access ( args.chid ) );
|
||||
}
|
||||
else {
|
||||
assert ( 0 );
|
||||
verify ( 0 );
|
||||
}
|
||||
pChan->connectionUpdateCount++;
|
||||
connectionUpdateCount++;
|
||||
@@ -351,11 +354,11 @@ void subscriptionStateChange ( struct event_handler_args args )
|
||||
struct dbr_sts_string * pdbrgs = ( struct dbr_sts_string * ) args.dbr;
|
||||
appChan *pChan = (appChan *) args.usr;
|
||||
|
||||
assert ( args.status == ECA_NORMAL );
|
||||
assert ( pChan->channel == args.chid );
|
||||
assert ( pChan->connected );
|
||||
assert ( args.type == DBR_STS_STRING );
|
||||
assert ( strlen ( pdbrgs->value ) <= MAX_STRING_SIZE );
|
||||
verify ( args.status == ECA_NORMAL );
|
||||
verify ( pChan->channel == args.chid );
|
||||
verify ( pChan->connected );
|
||||
verify ( args.type == DBR_STS_STRING );
|
||||
verify ( strlen ( pdbrgs->value ) <= MAX_STRING_SIZE );
|
||||
pChan->subscriptionUpdateCount++;
|
||||
subscriptionUpdateCount++;
|
||||
}
|
||||
@@ -422,7 +425,7 @@ void verifyConnectionHandlerConnect ( appChan *pChans, unsigned chanCount,
|
||||
subscriptionStateChange, &pChans[j], &pChans[j].subscription );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
assert ( ca_test_io () == ECA_IODONE );
|
||||
verify ( ca_test_io () == ECA_IODONE );
|
||||
}
|
||||
|
||||
ca_flush_io ();
|
||||
@@ -436,13 +439,13 @@ void verifyConnectionHandlerConnect ( appChan *pChans, unsigned chanCount,
|
||||
}
|
||||
|
||||
for ( j = 0u; j < chanCount; j++ ) {
|
||||
assert ( pChans[j].getCallbackCount == 1u);
|
||||
assert ( pChans[j].connectionUpdateCount > 0 );
|
||||
verify ( pChans[j].getCallbackCount == 1u);
|
||||
verify ( pChans[j].connectionUpdateCount > 0 );
|
||||
if ( pChans[j].connectionUpdateCount > 1u ) {
|
||||
printf ("Unusual connection activity count = %u on channel %s?\n",
|
||||
pChans[j].connectionUpdateCount, pChans[j].name );
|
||||
}
|
||||
assert ( pChans[j].accessUpdateCount > 0 );
|
||||
verify ( pChans[j].accessUpdateCount > 0 );
|
||||
if ( pChans[j].accessUpdateCount > 1u ) {
|
||||
printf ("Unusual access rights activity count = %u on channel %s?\n",
|
||||
pChans[j].connectionUpdateCount, pChans[j].name );
|
||||
@@ -515,7 +518,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
i = 0;
|
||||
while ( backgroundConnCount > 1u ) {
|
||||
backgroundConnCount = ca_get_ioc_connection_count ();
|
||||
assert ( i++ < 10 );
|
||||
verify ( i++ < 10 );
|
||||
printf ( "Z" );
|
||||
fflush ( stdout );
|
||||
epicsThreadSleep ( 1.0 );
|
||||
@@ -535,11 +538,11 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
if ( ca_state ( pChans[j].channel ) == cs_conn ) {
|
||||
assert ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
|
||||
verify ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
|
||||
}
|
||||
else {
|
||||
assert ( INVALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
|
||||
assert ( ca_test_io () == ECA_IOINPROGRESS );
|
||||
verify ( INVALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
|
||||
verify ( ca_test_io () == ECA_IOINPROGRESS );
|
||||
}
|
||||
|
||||
status = ca_replace_access_rights_event (
|
||||
@@ -577,14 +580,14 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
assert ( ca_test_io () == ECA_IODONE );
|
||||
verify ( ca_test_io () == ECA_IODONE );
|
||||
|
||||
connections = ca_get_ioc_connection_count ();
|
||||
assert ( connections == backgroundConnCount );
|
||||
verify ( connections == backgroundConnCount );
|
||||
|
||||
for ( j = 0u; j < chanCount; j++ ) {
|
||||
assert ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
|
||||
assert ( ca_state ( pChans[j].channel ) == cs_conn );
|
||||
verify ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
|
||||
verify ( ca_state ( pChans[j].channel ) == cs_conn );
|
||||
SEVCHK ( ca_clear_channel ( pChans[j].channel ), NULL );
|
||||
}
|
||||
|
||||
@@ -605,7 +608,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
while ( ca_get_ioc_connection_count () != backgroundConnCount ) {
|
||||
epicsThreadSleep ( 0.1 );
|
||||
ca_poll (); /* emulate typical GUI */
|
||||
assert ( ++j < 100 );
|
||||
verify ( ++j < 100 );
|
||||
}
|
||||
}
|
||||
showProgress ( interestLevel );
|
||||
@@ -621,7 +624,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
|
||||
assert ( ca_test_io () == ECA_IODONE );
|
||||
verify ( ca_test_io () == ECA_IODONE );
|
||||
|
||||
/*
|
||||
* verify ca_pend_io() does not see old search requests
|
||||
@@ -650,13 +653,13 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
|
||||
SEVCHK ( status, NULL );
|
||||
status = ca_pend_io ( 1e-16 );
|
||||
if ( status != ECA_TIMEOUT ) {
|
||||
assert ( ca_state ( pChans[1].channel ) == cs_conn );
|
||||
verify ( ca_state ( pChans[1].channel ) == cs_conn );
|
||||
}
|
||||
status = ca_clear_channel ( pChans[1].channel );
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
else {
|
||||
assert ( ca_state( pChans[0].channel ) == cs_conn );
|
||||
verify ( ca_state( pChans[0].channel ) == cs_conn );
|
||||
}
|
||||
}
|
||||
status = ca_clear_channel( pChans[0].channel );
|
||||
@@ -721,9 +724,9 @@ void grEnumTest ( chid chan, unsigned interestLevel )
|
||||
SEVCHK (status, "DBR_GR_ENUM ca_get()");
|
||||
|
||||
status = ca_pend_io (timeoutToPendIO);
|
||||
assert (status == ECA_NORMAL);
|
||||
verify (status == ECA_NORMAL);
|
||||
|
||||
assert ( ge.no_str >= 0 && ge.no_str < NELEMENTS(ge.strs) );
|
||||
verify ( ge.no_str >= 0 && ge.no_str < NELEMENTS(ge.strs) );
|
||||
if ( ge.no_str > 0 ) {
|
||||
printf ("Enum state str = {");
|
||||
count = (unsigned) ge.no_str;
|
||||
@@ -763,7 +766,7 @@ void ctrlDoubleTest ( chid chan, unsigned interestLevel )
|
||||
|
||||
size = sizeof (*pDbl)*ca_element_count(chan);
|
||||
pDbl = malloc (size);
|
||||
assert (pDbl!=NULL);
|
||||
verify (pDbl!=NULL);
|
||||
|
||||
/*
|
||||
* initialize the array
|
||||
@@ -782,7 +785,7 @@ void ctrlDoubleTest ( chid chan, unsigned interestLevel )
|
||||
|
||||
size = dbr_size_n(DBR_CTRL_DOUBLE, ca_element_count(chan));
|
||||
pCtrlDbl = (struct dbr_ctrl_double *) malloc (size);
|
||||
assert (pCtrlDbl!=NULL);
|
||||
verify (pCtrlDbl!=NULL);
|
||||
|
||||
/*
|
||||
* read the array from the PV
|
||||
@@ -792,14 +795,14 @@ void ctrlDoubleTest ( chid chan, unsigned interestLevel )
|
||||
chan, pCtrlDbl);
|
||||
SEVCHK (status, "ctrlDoubleTest, ca_array_get");
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert (status==ECA_NORMAL);
|
||||
verify (status==ECA_NORMAL);
|
||||
|
||||
/*
|
||||
* verify the result
|
||||
*/
|
||||
for (i=0; i<nElem; i++) {
|
||||
double diff = pDbl[i] - sin (i*slice);
|
||||
assert (fabs(diff) < DBL_EPSILON*4);
|
||||
verify (fabs(diff) < DBL_EPSILON*4);
|
||||
}
|
||||
|
||||
free (pCtrlDbl);
|
||||
@@ -830,7 +833,7 @@ void verifyBlockInPendIO ( chid chan, unsigned interestLevel )
|
||||
"get block test failed - val written %d\n", req );
|
||||
printf (
|
||||
"get block test failed - val read %d\n", resp );
|
||||
assert ( 0 );
|
||||
verify ( 0 );
|
||||
}
|
||||
}
|
||||
else if ( resp != -100 ) {
|
||||
@@ -847,7 +850,7 @@ void verifyBlockInPendIO ( chid chan, unsigned interestLevel )
|
||||
"get block test failed - val written %d\n", req);
|
||||
printf (
|
||||
"get block test failed - val read %d\n", resp);
|
||||
assert(0);
|
||||
verify (0);
|
||||
}
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
@@ -879,7 +882,7 @@ void floatTest ( chid chan, dbr_float_t beginValue, dbr_float_t increment,
|
||||
if ( fabs ( fval - fretval ) > epsilon ) {
|
||||
printf ( "float test failed val written %f\n", fval );
|
||||
printf ( "float test failed val read %f\n", fretval );
|
||||
assert (0);
|
||||
verify (0);
|
||||
}
|
||||
fval += increment;
|
||||
}
|
||||
@@ -909,7 +912,7 @@ void doubleTest ( chid chan, dbr_double_t beginValue,
|
||||
if ( fabs ( fval - fretval ) > epsilon ) {
|
||||
printf ( "double test failed val written %f\n", fval );
|
||||
printf ( "double test failed val read %f\n", fretval );
|
||||
assert ( 0 );
|
||||
verify ( 0 );
|
||||
}
|
||||
fval += increment;
|
||||
}
|
||||
@@ -960,7 +963,7 @@ void verifyAnalogIO ( chid chan, int dataType, double min, double max,
|
||||
(dbr_double_t) epsil, iter );
|
||||
}
|
||||
else {
|
||||
assert ( 0 );
|
||||
verify ( 0 );
|
||||
}
|
||||
}
|
||||
base = max;
|
||||
@@ -981,7 +984,7 @@ void verifyAnalogIO ( chid chan, int dataType, double min, double max,
|
||||
(dbr_double_t) epsil, iter );
|
||||
}
|
||||
else {
|
||||
assert ( 0 );
|
||||
verify ( 0 );
|
||||
}
|
||||
}
|
||||
base = - max;
|
||||
@@ -1002,7 +1005,7 @@ void verifyAnalogIO ( chid chan, int dataType, double min, double max,
|
||||
(dbr_double_t) epsil, iter );
|
||||
}
|
||||
else {
|
||||
assert ( 0 );
|
||||
verify ( 0 );
|
||||
}
|
||||
}
|
||||
showProgressEnd ( interestLevel );
|
||||
@@ -1042,7 +1045,7 @@ void verifyLongIO ( chid chan, unsigned interestLevel )
|
||||
ca_get ( DBR_LONG, chan, &rdbk );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "get pend failed\n" );
|
||||
assert ( iter == rdbk );
|
||||
verify ( iter == rdbk );
|
||||
}
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
@@ -1087,7 +1090,7 @@ void verifyShortIO ( chid chan, unsigned interestLevel )
|
||||
ca_get ( DBR_SHORT, chan, &rdbk );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "get pend failed\n" );
|
||||
assert ( iter == rdbk );
|
||||
verify ( iter == rdbk );
|
||||
}
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
@@ -1198,7 +1201,7 @@ void verifyHighThroughputWriteCallback ( chid chan, unsigned interestLevel )
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status,
|
||||
"verifyHighThroughputWriteCallback, verification get pend" );
|
||||
assert ( dval == i );
|
||||
verify ( dval == i );
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
else {
|
||||
@@ -1219,14 +1222,14 @@ void verifyBadString ( chid chan, unsigned interestLevel )
|
||||
showProgressBegin ( "verifyBadString", interestLevel );
|
||||
memset (stimStr, 'a', sizeof (stimStr) );
|
||||
status = ca_array_put ( DBR_STRING, 1u, chan, stimStr );
|
||||
assert ( status != ECA_NORMAL );
|
||||
verify ( status != ECA_NORMAL );
|
||||
sprintf ( stimStr, "%u", 8u );
|
||||
status = ca_array_put ( DBR_STRING, 1u, chan, stimStr );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_array_get ( DBR_STRING, 1u, chan, respStr );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
if ( strcmp ( stimStr, respStr ) ) {
|
||||
printf (
|
||||
"Test fails if stim \"%s\" isnt roughly equiv to resp \"%s\"\n",
|
||||
@@ -1439,7 +1442,8 @@ void singleSubscriptionDeleteTest ( chid chan, unsigned interestLevel )
|
||||
unsigned j = 0;
|
||||
while ( j < i ) {
|
||||
temp = (float) j++;
|
||||
SEVCHK ( ca_put (DBR_FLOAT, chan, &temp), NULL);
|
||||
SEVCHK ( ca_put (DBR_FLOAT, chan, &temp),
|
||||
"singleSubscriptionDeleteTest - one of multiple puts" );
|
||||
}
|
||||
ca_flush_io ();
|
||||
}
|
||||
@@ -1472,7 +1476,7 @@ void channelClearWithEventTrafficTest ( const char *pName, unsigned interestLeve
|
||||
CA_PRIORITY_DEFAULT, &chan );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "channelClearWithEventTrafficTest: channel connect failed" );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
count = 0u;
|
||||
SEVCHK ( ca_add_event ( DBR_GR_FLOAT, chan, noopSubscriptionStateChange,
|
||||
@@ -1515,7 +1519,7 @@ void selfDeleteEvent ( struct event_handler_args args )
|
||||
{
|
||||
int status;
|
||||
status = ca_clear_event ( globalEventID );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
}
|
||||
|
||||
void eventClearTest ( chid chan )
|
||||
@@ -1600,7 +1604,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
|
||||
SEVCHK ( status, "exception notify install failed" );
|
||||
|
||||
pRS = malloc ( ca_element_count (chan) * sizeof (*pRS) );
|
||||
assert ( pRS );
|
||||
verify ( pRS );
|
||||
status = ca_array_get ( DBR_PUT_ACKT,
|
||||
ca_element_count (chan), chan, pRS );
|
||||
SEVCHK ( status, "array read request failed" );
|
||||
@@ -1626,7 +1630,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
|
||||
status = ca_array_get_callback ( DBR_PUT_ACKT,
|
||||
ca_element_count (chan), chan, arrayEventExceptionNotify, 0 );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
assert ( status == ECA_BADTYPE || status == ECA_GETFAIL );
|
||||
verify ( status == ECA_BADTYPE || status == ECA_GETFAIL );
|
||||
arrayEventExceptionNotifyComplete = 1;
|
||||
}
|
||||
ca_flush_io ();
|
||||
@@ -1650,7 +1654,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
|
||||
status = ca_add_array_event ( DBR_PUT_ACKT, ca_element_count ( chan ),
|
||||
chan, arrayEventExceptionNotify, 0, 0.0, 0.0, 0.0, &id );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
assert ( status == ECA_BADTYPE || status == ECA_GETFAIL );
|
||||
verify ( status == ECA_BADTYPE || status == ECA_GETFAIL );
|
||||
arrayEventExceptionNotifyComplete = 1;
|
||||
}
|
||||
ca_flush_io ();
|
||||
@@ -1678,14 +1682,14 @@ void exceptionTest ( chid chan, unsigned interestLevel )
|
||||
SEVCHK ( status, "exception notify install failed" );
|
||||
|
||||
pWS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
|
||||
assert ( pWS );
|
||||
verify ( pWS );
|
||||
for ( i = 0; i < ca_element_count (chan); i++ ) {
|
||||
strcpy ( pWS[i], "@#$%" );
|
||||
}
|
||||
status = ca_array_put ( DBR_STRING,
|
||||
ca_element_count (chan), chan, pWS );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
assert ( status == ECA_BADTYPE || status == ECA_PUTFAIL );
|
||||
verify ( status == ECA_BADTYPE || status == ECA_PUTFAIL );
|
||||
acctstExceptionCount++; /* local PV case */
|
||||
}
|
||||
ca_flush_io ();
|
||||
@@ -1710,7 +1714,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
|
||||
unsigned i;
|
||||
|
||||
pWS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
|
||||
assert ( pWS );
|
||||
verify ( pWS );
|
||||
for ( i = 0; i < ca_element_count (chan); i++ ) {
|
||||
strcpy ( pWS[i], "@#$%" );
|
||||
}
|
||||
@@ -1750,7 +1754,7 @@ void arrayReadNotify ( struct event_handler_args args )
|
||||
dbr_double_t *pRF = ( dbr_double_t * ) ( args.dbr );
|
||||
int i;
|
||||
for ( i = 0; i < args.count; i++ ) {
|
||||
assert ( pWF[i] == pRF[i] );
|
||||
verify ( pWF[i] == pRF[i] );
|
||||
}
|
||||
arrayReadNotifyComplete = 1;
|
||||
}
|
||||
@@ -1780,10 +1784,10 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
|
||||
showProgressBegin ( "arrayTest", interestLevel );
|
||||
|
||||
pRF = (dbr_double_t *) calloc ( ca_element_count (chan), sizeof (*pRF) );
|
||||
assert ( pRF != NULL );
|
||||
verify ( pRF != NULL );
|
||||
|
||||
pWF = (dbr_double_t *) calloc ( ca_element_count (chan), sizeof (*pWF) );
|
||||
assert ( pWF != NULL );
|
||||
verify ( pWF != NULL );
|
||||
|
||||
/*
|
||||
* write some random numbers into the array
|
||||
@@ -1809,7 +1813,11 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
|
||||
* verify read response matches values written
|
||||
*/
|
||||
for ( i = 0; i < ca_element_count ( chan ); i++ ) {
|
||||
assert ( pWF[i] == pRF[i] );
|
||||
if ( pWF[i] != pRF[i] ) {
|
||||
printf ( "i=%u, pWF[i]=%f, pRF[i]=%f\n",
|
||||
i, pWF[i], pRF[i]);
|
||||
}
|
||||
verify ( pWF[i] == pRF[i] );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1822,7 +1830,7 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
|
||||
if ( size <= maxArrayBytes ) {
|
||||
|
||||
pRS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
|
||||
assert ( pRS );
|
||||
verify ( pRS );
|
||||
status = ca_array_get ( DBR_STRING,
|
||||
ca_element_count (chan), chan, pRS );
|
||||
SEVCHK ( status, "array read request failed" );
|
||||
@@ -1896,7 +1904,7 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert ( status == ECA_BADCOUNT );
|
||||
verify ( status == ECA_BADCOUNT );
|
||||
}
|
||||
status = ca_add_exception_event ( 0, 0 );
|
||||
SEVCHK ( status, "exception notify install failed" );
|
||||
@@ -1925,54 +1933,54 @@ void unequalServerBufferSizeTest ( const char * pName, unsigned interestLevel )
|
||||
|
||||
/* this test must be run when no channels are connected */
|
||||
connections = ca_get_ioc_connection_count ();
|
||||
assert ( connections == 0u );
|
||||
verify ( connections == 0u );
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
if ( ! ca_write_access ( newChan ) ) {
|
||||
printf ( "skipping unequal buffer size test - no write access\n" );
|
||||
status = ca_clear_channel ( newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
return;
|
||||
}
|
||||
|
||||
pRF = (dbr_double_t *) calloc ( ca_element_count (newChan), sizeof (*pRF) );
|
||||
assert ( pRF != NULL );
|
||||
verify ( pRF != NULL );
|
||||
|
||||
pWF = (dbr_double_t *) calloc ( ca_element_count (newChan), sizeof (*pWF) );
|
||||
assert ( pWF != NULL );
|
||||
verify ( pWF != NULL );
|
||||
|
||||
status = ca_array_get ( DBR_DOUBLE, ca_element_count ( newChan ),
|
||||
newChan, pRF );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_clear_channel ( newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, &newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
status = ca_array_put ( DBR_DOUBLE, ca_element_count ( newChan ),
|
||||
newChan, pWF );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_array_get ( DBR_DOUBLE, 1,
|
||||
newChan, pRF );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_clear_channel ( newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
free ( pRF );
|
||||
free ( pWF );
|
||||
@@ -2001,7 +2009,7 @@ void pend_event_delay_test ( dbr_double_t request )
|
||||
accuracy = 100.0*(delay-request)/request;
|
||||
printf ( "CA pend event delay = %f sec results in error = %f %%\n",
|
||||
request, accuracy );
|
||||
assert ( fabs(accuracy) < 10.0 );
|
||||
verify ( fabs(accuracy) < 10.0 );
|
||||
}
|
||||
|
||||
void caTaskExitTest ( unsigned interestLevel )
|
||||
@@ -2021,26 +2029,26 @@ void verifyDataTypeMacros (void)
|
||||
int type;
|
||||
|
||||
type = dbf_type_to_DBR ( DBF_SHORT );
|
||||
assert ( type == DBR_SHORT );
|
||||
verify ( type == DBR_SHORT );
|
||||
type = dbf_type_to_DBR_STS ( DBF_SHORT );
|
||||
assert ( type == DBR_STS_SHORT );
|
||||
verify ( type == DBR_STS_SHORT );
|
||||
type = dbf_type_to_DBR_GR ( DBF_SHORT );
|
||||
assert ( type == DBR_GR_SHORT );
|
||||
verify ( type == DBR_GR_SHORT );
|
||||
type = dbf_type_to_DBR_CTRL ( DBF_SHORT );
|
||||
assert ( type == DBR_CTRL_SHORT );
|
||||
verify ( type == DBR_CTRL_SHORT );
|
||||
type = dbf_type_to_DBR_TIME ( DBF_SHORT );
|
||||
assert ( type == DBR_TIME_SHORT );
|
||||
assert ( strcmp ( dbr_type_to_text( DBR_SHORT ), "DBR_SHORT" ) == 0 );
|
||||
assert ( strcmp ( dbf_type_to_text( DBF_SHORT ), "DBF_SHORT" ) == 0 );
|
||||
assert ( dbr_type_is_SHORT ( DBR_SHORT ) );
|
||||
assert ( dbr_type_is_valid ( DBR_SHORT ) );
|
||||
assert ( dbf_type_is_valid ( DBF_SHORT ) );
|
||||
verify ( type == DBR_TIME_SHORT );
|
||||
verify ( strcmp ( dbr_type_to_text( DBR_SHORT ), "DBR_SHORT" ) == 0 );
|
||||
verify ( strcmp ( dbf_type_to_text( DBF_SHORT ), "DBF_SHORT" ) == 0 );
|
||||
verify ( dbr_type_is_SHORT ( DBR_SHORT ) );
|
||||
verify ( dbr_type_is_valid ( DBR_SHORT ) );
|
||||
verify ( dbf_type_is_valid ( DBF_SHORT ) );
|
||||
{
|
||||
int dataType = -1;
|
||||
dbf_text_to_type ( "DBF_SHORT", dataType );
|
||||
assert ( dataType == DBF_SHORT );
|
||||
verify ( dataType == DBF_SHORT );
|
||||
dbr_text_to_type ( "DBR_CLASS_NAME", dataType );
|
||||
assert ( dataType == DBR_CLASS_NAME );
|
||||
verify ( dataType == DBR_CLASS_NAME );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2083,7 +2091,7 @@ void clearChannelInGetCallbackTest ( const char *pName, unsigned level )
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & chan );
|
||||
@@ -2097,7 +2105,7 @@ void clearChannelInGetCallbackTest ( const char *pName, unsigned level )
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
showProgressEnd ( level );
|
||||
@@ -2114,7 +2122,7 @@ void clearChannelInPutCallbackTest ( const char *pName, unsigned level )
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & chan );
|
||||
@@ -2129,7 +2137,7 @@ void clearChannelInPutCallbackTest ( const char *pName, unsigned level )
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
showProgressEnd ( level );
|
||||
@@ -2138,7 +2146,6 @@ void clearChannelInPutCallbackTest ( const char *pName, unsigned level )
|
||||
void clearChannelInSubscrCallbackTest ( const char *pName, unsigned level )
|
||||
{
|
||||
unsigned i;
|
||||
const dbr_double_t value = 1.1;
|
||||
chid chan;
|
||||
int status;
|
||||
|
||||
@@ -2146,7 +2153,7 @@ void clearChannelInSubscrCallbackTest ( const char *pName, unsigned level )
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & chan );
|
||||
@@ -2161,7 +2168,7 @@ void clearChannelInSubscrCallbackTest ( const char *pName, unsigned level )
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
showProgressEnd ( level );
|
||||
@@ -2172,7 +2179,7 @@ void monitorAddConnectionCallback ( struct connection_handler_args args )
|
||||
if ( args.op == CA_OP_CONN_UP ) {
|
||||
unsigned * pEventCount = ( unsigned * ) ca_puser ( args.chid );
|
||||
int status;
|
||||
assert ( *pEventCount == 0u );
|
||||
verify ( *pEventCount == 0u );
|
||||
(*pEventCount)++;
|
||||
status = ca_create_subscription ( DBR_DOUBLE, 1,
|
||||
args.chid, DBE_VALUE, nUpdatesTester, ca_puser ( args.chid ), 0 );
|
||||
@@ -2201,7 +2208,7 @@ void monitorAddConnectionCallbackTest ( const char *pName, unsigned interestLeve
|
||||
|
||||
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
assert ( i < 100 );
|
||||
verify ( i < 100 );
|
||||
}
|
||||
|
||||
status = ca_create_channel ( pName,
|
||||
@@ -2211,15 +2218,15 @@ void monitorAddConnectionCallbackTest ( const char *pName, unsigned interestLeve
|
||||
while ( eventCount < 2 ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
}
|
||||
assert ( eventCount == 2u );
|
||||
verify ( eventCount == 2u );
|
||||
|
||||
status = ca_get_callback ( DBR_DOUBLE, chan, nUpdatesTester, &getCallbackCount );
|
||||
SEVCHK ( status, "monitorAddConnectionCallback get callback" );
|
||||
while ( getCallbackCount == 0 ) {
|
||||
ca_pend_event ( 0.1 );
|
||||
}
|
||||
assert ( eventCount == 2u );
|
||||
assert ( getCallbackCount == 1u );
|
||||
verify ( eventCount == 2u );
|
||||
verify ( getCallbackCount == 1u );
|
||||
|
||||
status = ca_clear_channel ( chan );
|
||||
SEVCHK ( status, "monitorAddConnectionCallbackTest clear channel" );
|
||||
@@ -2308,7 +2315,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
}
|
||||
printf ( "-" );
|
||||
fflush ( stdout );
|
||||
assert ( tries++ < 50 );
|
||||
verify ( tries++ < 50 );
|
||||
}
|
||||
|
||||
showProgress ( interestLevel );
|
||||
@@ -2339,7 +2346,10 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
SEVCHK ( ca_get ( DBR_FLOAT, chan, &getResp ), NULL );
|
||||
SEVCHK ( ca_pend_io ( timeoutToPendIO ), NULL );
|
||||
|
||||
assert ( getResp == temp );
|
||||
if ( getResp != temp ) {
|
||||
printf ( "getResp=%f, temp=%f\n", getResp, temp );
|
||||
verify ( getResp == temp );
|
||||
}
|
||||
|
||||
/*
|
||||
* wait for all of the monitors to have correct values
|
||||
@@ -2355,7 +2365,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
* we shouldnt see old monitors because
|
||||
* we resubscribed
|
||||
*/
|
||||
assert ( test[j].count <= i + 2 );
|
||||
verify ( test[j].count <= i + 2 );
|
||||
if ( test[j].lastValue == temp ) {
|
||||
if ( test[j].count < i + 1 ) {
|
||||
tmpFlowCtrlCount++;
|
||||
@@ -2368,7 +2378,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
break;
|
||||
}
|
||||
if ( passCount == prevPassCount ) {
|
||||
assert ( tries++ < 500 );
|
||||
verify ( tries++ < 500 );
|
||||
if ( tries % 50 == 0 ) {
|
||||
for ( j = 0; j <= i; j++ ) {
|
||||
dbr_float_t pat = monitorUpdateTestPattern ( j );
|
||||
@@ -2428,7 +2438,7 @@ void verifyReasonableBeaconPeriod ( chid chan, unsigned interestLevel )
|
||||
ca_name ( chan ), beaconPeriod );
|
||||
|
||||
watchDogDelay = ca_receive_watchdog_delay ( chan );
|
||||
assert ( watchDogDelay >= 0.0 );
|
||||
verify ( watchDogDelay >= 0.0 );
|
||||
|
||||
printf ( "busy: receive watchdog for \"%s\" expires in %g sec.\n",
|
||||
ca_name ( chan ), watchDogDelay );
|
||||
@@ -2446,7 +2456,7 @@ void verifyReasonableBeaconPeriod ( chid chan, unsigned interestLevel )
|
||||
}
|
||||
|
||||
watchDogDelay = ca_receive_watchdog_delay ( chan );
|
||||
assert ( watchDogDelay >= 0.0 );
|
||||
verify ( watchDogDelay >= 0.0 );
|
||||
|
||||
printf ( "inactive: receive watchdog for \"%s\" expires in %g sec.\n",
|
||||
ca_name ( chan ), watchDogDelay );
|
||||
@@ -2465,9 +2475,9 @@ void verifyOldPend ( unsigned interestLevel )
|
||||
* verify that the old ca_pend() is in the symbol table
|
||||
*/
|
||||
status = ca_pend ( 100000.0, 1 );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_pend ( 1e-12, 0 );
|
||||
assert ( status == ECA_TIMEOUT );
|
||||
verify ( status == ECA_TIMEOUT );
|
||||
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
@@ -2485,21 +2495,21 @@ void verifyTimeStamps ( chid chan, unsigned interestLevel )
|
||||
showProgressBegin ( "verifyTimeStamps", interestLevel );
|
||||
|
||||
status = epicsTimeGetCurrent ( & localTime );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
|
||||
status = ca_get ( DBR_TIME_DOUBLE, chan, & first );
|
||||
SEVCHK ( status, "fetch of dbr time double failed\n" );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = ca_get ( DBR_TIME_DOUBLE, chan, & last );
|
||||
SEVCHK ( status, "fetch of dbr time double failed\n" );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
length = epicsTimeToStrftime ( buf, sizeof ( buf ),
|
||||
"%a %b %d %Y %H:%M:%S.%f", & first.stamp );
|
||||
assert ( length );
|
||||
verify ( length );
|
||||
printf ("Processing time of channel \"%s\" was \"%s\"\n",
|
||||
ca_name ( chan ), buf );
|
||||
|
||||
@@ -2553,7 +2563,7 @@ void verifyChannelPriorities ( const char *pName, unsigned interestLevel )
|
||||
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "prioritized channel connect failed" );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
value = i;
|
||||
status = ca_put ( DBR_DOUBLE, chan0, &value );
|
||||
@@ -2592,7 +2602,7 @@ void verifyTearDownWhenChannelConnected ( const char * pName,
|
||||
double * const pValues = (double * const) calloc ( chanCount, sizeof ( *pValues ) );
|
||||
unsigned i, j;
|
||||
|
||||
assert ( pChans && pValues );
|
||||
verify ( pChans && pValues );
|
||||
|
||||
showProgressBegin ( "verifyTearDownWhenChannelConnected", interestLevel );
|
||||
|
||||
@@ -2606,7 +2616,7 @@ void verifyTearDownWhenChannelConnected ( const char * pName,
|
||||
}
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "immediate tear down channel connect failed" );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
for ( j = 0; j < chanCount; j++ ) {
|
||||
status = ca_get ( DBR_DOUBLE, pChans[j], &pValues[j] );
|
||||
@@ -2646,7 +2656,7 @@ void verifyImmediateTearDown ( const char * pName,
|
||||
SEVCHK ( status, "immediate tear down channel create failed" );
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "immediate tear down channel connect failed" );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
/*
|
||||
* verify that puts pending when we call ca_task_exit()
|
||||
* get flushed out
|
||||
@@ -2659,7 +2669,7 @@ void verifyImmediateTearDown ( const char * pName,
|
||||
SEVCHK ( status, "immediate tear down channel get failed" );
|
||||
if ( currentValue != ( (i - 1) % 8 ) ) {
|
||||
printf ( "currentValue = %i, i = %i\n", currentValue, i );
|
||||
assert ( currentValue == ( (i - 1) % 8 ) );
|
||||
verify ( currentValue == ( (i - 1) % 8 ) );
|
||||
}
|
||||
}
|
||||
status = ca_put ( DBR_LONG, chan, & value );
|
||||
@@ -2700,12 +2710,12 @@ void fdRegCB ( void * parg, int fd, int opened )
|
||||
if ( opened ) {
|
||||
status = fdmgr_add_callback (
|
||||
mgrCtx, fd, fdi_read, fdcb, 0 );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
}
|
||||
else {
|
||||
status = fdmgr_clear_callback (
|
||||
mgrCtx, fd, fdi_read );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2720,42 +2730,46 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
|
||||
epicsTimeStamp begin, end;
|
||||
|
||||
mgrCtx = fdmgr_init ();
|
||||
assert ( mgrCtx );
|
||||
verify ( mgrCtx );
|
||||
|
||||
showProgressBegin ( "fdManagerVerify", interestLevel );
|
||||
|
||||
status = ca_add_fd_registration ( fdRegCB, mgrCtx );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
while ( ca_state ( newChan ) != cs_conn ) {
|
||||
tmo.tv_sec = 6000;
|
||||
tmo.tv_usec = 0;
|
||||
status = fdmgr_pend_event ( mgrCtx, & tmo );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
}
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
status = ca_add_event ( DBR_FLOAT, newChan,
|
||||
nUpdatesTester, & eventCount, & subscription );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = ca_flush_io ();
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
while ( eventCount < 1 ) {
|
||||
tmo.tv_sec = 6000;
|
||||
tmo.tv_usec = 0;
|
||||
status = fdmgr_pend_event ( mgrCtx, & tmo );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
}
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
status = ca_clear_event ( subscription );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = ca_flush_io ();
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
/* look for infinite loop in fd manager schedualing */
|
||||
epicsTimeGetCurrent ( & begin );
|
||||
@@ -2765,23 +2779,25 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
|
||||
tmo.tv_sec = 1;
|
||||
tmo.tv_usec = 0;
|
||||
status = fdmgr_pend_event ( mgrCtx, & tmo );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
epicsTimeGetCurrent ( & end );
|
||||
delay = epicsTimeDiffInSeconds ( & end, & begin );
|
||||
if ( delay >= 1.0 ) {
|
||||
break;
|
||||
}
|
||||
assert ( eventCount++ < 100 );
|
||||
verify ( eventCount++ < 100 );
|
||||
}
|
||||
|
||||
showProgress ( interestLevel );
|
||||
|
||||
status = ca_clear_channel ( newChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = ca_add_fd_registration ( 0, 0 );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = fdmgr_delete ( mgrCtx );
|
||||
assert ( status >= 0 );
|
||||
verify ( status >= 0 );
|
||||
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
@@ -2798,13 +2814,13 @@ void verifyConnectWithDisconnectedChannels (
|
||||
|
||||
for ( i= 0u; i < NELEMENTS ( bogusChan ); i++ ) {
|
||||
char buf[256];
|
||||
sprintf ( buf, "aChannelThatShouldNeverNeverNeverExit%u", i );
|
||||
sprintf ( buf, "aChannelThatShouldNeverNeverNeverExist%u", i );
|
||||
status = ca_create_channel ( buf, 0, 0, 0, & bogusChan[i] );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
}
|
||||
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_TIMEOUT );
|
||||
status = ca_pend_io ( 0.001 );
|
||||
verify ( status == ECA_TIMEOUT );
|
||||
|
||||
/* wait a long time for the search interval to increase */
|
||||
for ( i= 0u; i < 10; i++ ) {
|
||||
@@ -2813,7 +2829,7 @@ void verifyConnectWithDisconnectedChannels (
|
||||
}
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & validChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
/*
|
||||
* we should be able to connect to a valid
|
||||
@@ -2822,14 +2838,14 @@ void verifyConnectWithDisconnectedChannels (
|
||||
* diasconnected channel
|
||||
*/
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
status = ca_clear_channel ( validChan );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
for ( i= 0u; i < NELEMENTS ( bogusChan ); i++ ) {
|
||||
status = ca_clear_channel ( bogusChan[i] );
|
||||
assert ( status == ECA_NORMAL );
|
||||
verify ( status == ECA_NORMAL );
|
||||
}
|
||||
|
||||
showProgressEnd ( interestLevel );
|
||||
@@ -2982,13 +2998,17 @@ void verifyContextRundownFlush ( const char * pName, unsigned interestLevel )
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "get, pend io failed" );
|
||||
|
||||
assert ( stim == resp );
|
||||
verify ( stim == resp );
|
||||
|
||||
status = ca_clear_channel ( chan );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
ca_context_destroy ();
|
||||
}
|
||||
|
||||
if ( i % 100 == 0 ) {
|
||||
showProgress ( interestLevel );
|
||||
}
|
||||
}
|
||||
|
||||
showProgressEnd ( interestLevel );
|
||||
@@ -3051,7 +3071,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
|
||||
verifyDataTypeMacros ();
|
||||
|
||||
connections = ca_get_ioc_connection_count ();
|
||||
assert ( connections == 0u );
|
||||
verify ( connections == 0u );
|
||||
unequalServerBufferSizeTest ( pName, interestLevel );
|
||||
clearChannelInGetCallbackTest ( pName, interestLevel );
|
||||
clearChannelInPutCallbackTest ( pName, interestLevel );
|
||||
@@ -3070,7 +3090,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
|
||||
ca_element_count ( chan ) );
|
||||
|
||||
connections = ca_get_ioc_connection_count ();
|
||||
assert ( connections == 1u || connections == 0u );
|
||||
verify ( connections == 1u || connections == 0u );
|
||||
if ( connections == 0u ) {
|
||||
printf ( "testing with a local channel\n" );
|
||||
}
|
||||
@@ -3122,7 +3142,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
|
||||
/* ca_client_status ( 6u ); info about each channel */
|
||||
|
||||
pChans = calloc ( channelCount, sizeof ( *pChans ) );
|
||||
assert ( pChans );
|
||||
verify ( pChans );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
strncpy ( pChans[ i ].name, pName, sizeof ( pChans[ i ].name ) );
|
||||
|
||||
@@ -66,7 +66,6 @@ void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn )
|
||||
channelCount = channelCountIn;
|
||||
|
||||
pChans = new chid [channelCount];
|
||||
assert ( pChans );
|
||||
|
||||
while ( 1 ) {
|
||||
connCount = 0u;
|
||||
|
||||
@@ -36,7 +36,6 @@ void caEventRate ( const char *pName, unsigned count )
|
||||
unsigned eventCount = 0u;
|
||||
|
||||
chid * pChidTable = new chid [ count ];
|
||||
assert ( pChidTable );
|
||||
|
||||
{
|
||||
printf ( "Connecting to CA Channel \"%s\" %u times.",
|
||||
|
||||
@@ -253,6 +253,11 @@ void ca_client_context::registerForFileDescriptorCallBack (
|
||||
this->fdRegFunc = pFunc;
|
||||
this->fdRegArg = pArg;
|
||||
this->fdRegFuncNeedsToBeCalled = true;
|
||||
if ( pFunc ) {
|
||||
// the receive thread might already be blocking
|
||||
// w/o having sent the wakeup message
|
||||
this->_sendWakeupMsg ();
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
@@ -557,11 +562,11 @@ int ca_client_context::pendEvent ( const double & timeout )
|
||||
0, & tmpAddr.sa, & addrSize );
|
||||
} while ( status > 0 );
|
||||
}
|
||||
this->noWakeupSincePend = true;
|
||||
while ( this->callbackThreadsPending > 0 ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->callbackThreadActivityComplete.wait ( 30.0 );
|
||||
}
|
||||
this->noWakeupSincePend = true;
|
||||
}
|
||||
|
||||
double elapsed = epicsTime::getCurrent() - current;
|
||||
@@ -613,19 +618,24 @@ void ca_client_context::callbackProcessingInitiateNotify ()
|
||||
}
|
||||
}
|
||||
if ( sendNeeded ) {
|
||||
// send short udp message to wake up a file descriptor manager
|
||||
// when a message arrives
|
||||
osiSockAddr tmpAddr;
|
||||
tmpAddr.ia.sin_family = AF_INET;
|
||||
tmpAddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
|
||||
tmpAddr.ia.sin_port = htons ( this->localPort );
|
||||
char buf = 0;
|
||||
sendto ( this->sock, & buf, sizeof ( buf ),
|
||||
0, & tmpAddr.sa, sizeof ( tmpAddr.sa ) );
|
||||
_sendWakeupMsg ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context :: _sendWakeupMsg ()
|
||||
{
|
||||
// send short udp message to wake up a file descriptor manager
|
||||
// when a message arrives
|
||||
osiSockAddr tmpAddr;
|
||||
tmpAddr.ia.sin_family = AF_INET;
|
||||
tmpAddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
|
||||
tmpAddr.ia.sin_port = htons ( this->localPort );
|
||||
char buf = 0;
|
||||
sendto ( this->sock, & buf, sizeof ( buf ),
|
||||
0, & tmpAddr.sa, sizeof ( tmpAddr.sa ) );
|
||||
}
|
||||
|
||||
void ca_client_context::callbackProcessingCompleteNotify ()
|
||||
{
|
||||
// if preemptive callback is enabled then this is a noop
|
||||
|
||||
@@ -143,6 +143,7 @@ cac::cac (
|
||||
initializingThreadsId ( epicsThreadGetIdSelf() ),
|
||||
initializingThreadsPriority ( epicsThreadGetPrioritySelf() ),
|
||||
maxRecvBytesTCP ( MAX_TCP ),
|
||||
maxContigFrames ( contiguousMsgCountWhichTriggersFlowControl ),
|
||||
beaconAnomalyCount ( 0u ),
|
||||
iiuExistenceCount ( 0u )
|
||||
{
|
||||
@@ -215,6 +216,11 @@ cac::cac (
|
||||
if ( ! this->tcpLargeRecvBufFreeList ) {
|
||||
throw std::bad_alloc ();
|
||||
}
|
||||
unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes ();
|
||||
if ( bufsPerArray > 1u ) {
|
||||
maxContigFrames = bufsPerArray *
|
||||
contiguousMsgCountWhichTriggersFlowControl;
|
||||
}
|
||||
}
|
||||
catch ( ... ) {
|
||||
osiSockRelease ();
|
||||
@@ -547,12 +553,15 @@ void cac::transferChanToVirtCircuit (
|
||||
piiu = pnewiiu.release ();
|
||||
newIIU = true;
|
||||
}
|
||||
catch ( std::bad_alloc & ) {
|
||||
catch ( std :: exception & except ) {
|
||||
errlogPrintf (
|
||||
"CAC: exception during virtual circuit creation \"%s\"\n",
|
||||
except.what () );
|
||||
return;
|
||||
}
|
||||
catch ( ... ) {
|
||||
errlogPrintf (
|
||||
"CAC: Unexpected exception during virtual circuit creation\n" );
|
||||
"CAC: nonstandard exception during virtual circuit creation\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ public:
|
||||
unsigned largeBufferSizeTCP () const;
|
||||
char * allocateLargeBufferTCP ();
|
||||
void releaseLargeBufferTCP ( char * );
|
||||
unsigned maxContiguousFrames ( epicsGuard < epicsMutex > & ) const;
|
||||
|
||||
// misc
|
||||
const char * userNamePointer () const;
|
||||
@@ -272,6 +273,7 @@ private:
|
||||
epicsThreadId initializingThreadsId;
|
||||
unsigned initializingThreadsPriority;
|
||||
unsigned maxRecvBytesTCP;
|
||||
unsigned maxContigFrames;
|
||||
unsigned beaconAnomalyCount;
|
||||
unsigned iiuExistenceCount;
|
||||
|
||||
@@ -442,5 +444,11 @@ inline const char * cac :: pLocalHostName ()
|
||||
return _refLocalHostName->pointer ();
|
||||
}
|
||||
|
||||
inline unsigned cac ::
|
||||
maxContiguousFrames ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return maxContigFrames;
|
||||
}
|
||||
|
||||
#endif // ifdef cach
|
||||
|
||||
|
||||
273
src/ca/catime.c
273
src/ca/catime.c
@@ -42,15 +42,10 @@
|
||||
|
||||
typedef struct testItem {
|
||||
chid chix;
|
||||
char name[40];
|
||||
char name[128];
|
||||
int type;
|
||||
int count;
|
||||
union {
|
||||
dbr_double_t doubleval;
|
||||
dbr_float_t fltval;
|
||||
dbr_short_t intval;
|
||||
dbr_string_t strval;
|
||||
} val;
|
||||
void * pValue;
|
||||
} ti;
|
||||
|
||||
typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
|
||||
@@ -172,66 +167,66 @@ unsigned *pInlineIter
|
||||
int status;
|
||||
dbr_int_t val;
|
||||
|
||||
for (pi=pItems; pi<&pItems[iterations]; pi++) {
|
||||
for (pi=pItems; pi < &pItems[iterations]; pi++) {
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
#ifdef WAIT_FOR_ACK
|
||||
@@ -243,7 +238,7 @@ unsigned *pInlineIter
|
||||
pItems[0].type,
|
||||
pItems[0].count,
|
||||
pItems[0].chix,
|
||||
&pItems[0].val);
|
||||
pItems[0].pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_flush_io();
|
||||
SEVCHK (status, NULL);
|
||||
@@ -255,7 +250,7 @@ unsigned *pInlineIter
|
||||
* test_get ()
|
||||
*/
|
||||
static void test_get(
|
||||
ti *pItems,
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
@@ -268,64 +263,64 @@ unsigned *pInlineIter
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_pend_io(100.0);
|
||||
status = ca_pend_io(1e20);
|
||||
SEVCHK (status, NULL);
|
||||
|
||||
*pInlineIter = 10;
|
||||
@@ -348,7 +343,7 @@ unsigned *pInlineIter
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
&pi->val);
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_pend_io(100.0);
|
||||
SEVCHK (status, NULL);
|
||||
@@ -377,7 +372,7 @@ static void measure_get_latency (ti *pItems, unsigned iterations)
|
||||
for ( pi = pItems; pi < &pItems[iterations]; pi++ ) {
|
||||
epicsTimeGetCurrent ( &start_time );
|
||||
status = ca_array_get ( pi->type, pi->count,
|
||||
pi->chix, &pi->val );
|
||||
pi->chix, pi->pValue );
|
||||
SEVCHK ( status, NULL );
|
||||
status = ca_pend_io ( 100.0 );
|
||||
SEVCHK ( status, NULL );
|
||||
@@ -400,14 +395,20 @@ static void measure_get_latency (ti *pItems, unsigned iterations)
|
||||
|
||||
mean = X/iterations;
|
||||
stdDev = sqrt ( XX/iterations - mean*mean );
|
||||
printf ( "Round trip get delays - mean=%f sec, std dev=%f sec, min=%f sec max=%f sec\n",
|
||||
mean, stdDev, min, max );
|
||||
printf (
|
||||
"Get Latency - "
|
||||
"mean = %3.1f uS, "
|
||||
"std dev = %3.1f uS, "
|
||||
"min = %3.1f uS "
|
||||
"max = %3.1f uS\n",
|
||||
mean * 1e6, stdDev * 1e6,
|
||||
min * 1e6, max * 1e6 );
|
||||
}
|
||||
|
||||
/*
|
||||
* printSearchStat()
|
||||
*/
|
||||
static void printSearchStat ( const ti *pi, unsigned iterations )
|
||||
static void printSearchStat ( const ti * pi, unsigned iterations )
|
||||
{
|
||||
unsigned i;
|
||||
double X = 0u;
|
||||
@@ -431,40 +432,43 @@ static void printSearchStat ( const ti *pi, unsigned iterations )
|
||||
|
||||
mean = X / iterations;
|
||||
stdDev = sqrt( XX / iterations - mean * mean );
|
||||
printf ( "Search tries per chan - mean=%f std dev=%f min=%f max=%f\n",
|
||||
printf (
|
||||
"Search tries per chan - "
|
||||
"mean = %3.1f "
|
||||
"std dev = %3.1f "
|
||||
"min = %3.1f "
|
||||
"max = %3.1f\n",
|
||||
mean, stdDev, min, max);
|
||||
}
|
||||
|
||||
/*
|
||||
* timeIt ()
|
||||
*/
|
||||
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations, unsigned nBytes )
|
||||
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
|
||||
unsigned nBytesSent, unsigned nBytesRecv )
|
||||
{
|
||||
epicsTimeStamp end_time;
|
||||
epicsTimeStamp start_time;
|
||||
double delay;
|
||||
unsigned inlineIter;
|
||||
|
||||
epicsTimeGetCurrent (&start_time);
|
||||
(*pfunc) (pItems, iterations, &inlineIter);
|
||||
epicsTimeGetCurrent (&end_time);
|
||||
delay = epicsTimeDiffInSeconds (&end_time, &start_time);
|
||||
if (delay>0.0) {
|
||||
epicsTimeGetCurrent ( &start_time );
|
||||
(*pfunc) ( pItems, iterations, &inlineIter );
|
||||
epicsTimeGetCurrent ( &end_time );
|
||||
delay = epicsTimeDiffInSeconds ( &end_time, &start_time );
|
||||
if ( delay > 0.0 ) {
|
||||
double freq = ( iterations * inlineIter ) / delay;
|
||||
printf ( "Elapsed Per Item = %12.8f sec, %10.1f Items per sec",
|
||||
1.0 / freq, freq );
|
||||
printf ( "Per Op, %8.4f uS ( %8.4f MHz )",
|
||||
1e6 / freq, freq / 1e6 );
|
||||
if ( pItems != NULL ) {
|
||||
printf(", %3.1f Mbps\n",
|
||||
(inlineIter*nBytes*CHAR_BIT)/(delay*1e6));
|
||||
printf(", %8.4f snd Mbps, %8.4f rcv Mbps\n",
|
||||
(inlineIter*nBytesSent*CHAR_BIT)/(delay*1e6),
|
||||
(inlineIter*nBytesRecv*CHAR_BIT)/(delay*1e6) );
|
||||
}
|
||||
else {
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf ("Elapsed Per Item = %12.8f sec\n",
|
||||
delay/(iterations*inlineIter));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -472,19 +476,53 @@ void timeIt ( tf *pfunc, ti *pItems, unsigned iterations, unsigned nBytes )
|
||||
*/
|
||||
static void test ( ti *pItems, unsigned iterations )
|
||||
{
|
||||
unsigned nBytes;
|
||||
unsigned payloadSize, dblPayloadSize;
|
||||
unsigned nBytesSent, nBytesRecv;
|
||||
|
||||
printf ( "\tasync put test\n");
|
||||
nBytes = sizeof ( caHdr ) + OCT_ROUND( dbr_size[pItems[0].type] );
|
||||
timeIt ( test_put, pItems, iterations, nBytes * iterations );
|
||||
payloadSize =
|
||||
dbr_size_n ( pItems[0].type, pItems[0].count );
|
||||
payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
|
||||
|
||||
printf ( "\tasync get test\n");
|
||||
nBytes = 2 * sizeof ( caHdr ) + OCT_ROUND ( dbr_size[pItems[0].type] );
|
||||
timeIt ( test_get, pItems, iterations/2, nBytes * ( iterations / 2 ) );
|
||||
dblPayloadSize = dbr_size [ DBR_DOUBLE ];
|
||||
dblPayloadSize = CA_MESSAGE_ALIGN ( dblPayloadSize );
|
||||
|
||||
if ( payloadSize > dblPayloadSize ) {
|
||||
unsigned factor = payloadSize / dblPayloadSize;
|
||||
while ( factor ) {
|
||||
if ( iterations > 10 * factor ) {
|
||||
iterations /= factor;
|
||||
break;
|
||||
}
|
||||
factor /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\tsynch get test\n");
|
||||
nBytes = 2 * sizeof ( caHdr ) + OCT_ROUND ( dbr_size[pItems[0].type] );
|
||||
timeIt ( test_wait, pItems, iterations/100, nBytes * ( iterations / 100 ) );
|
||||
printf ( "\t### async put test ###\n");
|
||||
nBytesSent = sizeof ( caHdr ) + CA_MESSAGE_ALIGN( payloadSize );
|
||||
nBytesRecv = 0u;
|
||||
timeIt ( test_put, pItems, iterations,
|
||||
nBytesSent * iterations,
|
||||
nBytesRecv * iterations );
|
||||
|
||||
printf ( "\t### async get test ###\n");
|
||||
nBytesSent = sizeof ( caHdr );
|
||||
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
|
||||
timeIt ( test_get, pItems, iterations,
|
||||
nBytesSent * ( iterations ),
|
||||
nBytesRecv * ( iterations ) );
|
||||
|
||||
printf ("\t### synch get test ###\n");
|
||||
nBytesSent = sizeof ( caHdr );
|
||||
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
|
||||
if ( iterations > 100 ) {
|
||||
iterations /= 100;
|
||||
}
|
||||
else if ( iterations > 10 ) {
|
||||
iterations /= 10;
|
||||
}
|
||||
timeIt ( test_wait, pItems, iterations,
|
||||
nBytesSent * iterations,
|
||||
nBytesRecv * iterations );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -493,11 +531,12 @@ static void test ( ti *pItems, unsigned iterations )
|
||||
int catime ( const char * channelName,
|
||||
unsigned channelCount, enum appendNumberFlag appNF )
|
||||
{
|
||||
unsigned i;
|
||||
unsigned strsize;
|
||||
unsigned nBytes;
|
||||
ti *pItemList;
|
||||
|
||||
unsigned i;
|
||||
int j;
|
||||
unsigned strsize;
|
||||
unsigned nBytesSent, nBytesRecv;
|
||||
ti *pItemList;
|
||||
|
||||
if ( channelCount == 0 ) {
|
||||
printf ( "channel count was zero\n" );
|
||||
return 0;
|
||||
@@ -521,7 +560,8 @@ int catime ( const char * channelName,
|
||||
}
|
||||
|
||||
strsize = sizeof ( pItemList[0].name ) - 1;
|
||||
nBytes = 0;
|
||||
nBytesSent = 0;
|
||||
nBytesRecv = 0;
|
||||
for ( i=0; i < channelCount; i++ ) {
|
||||
if ( appNF == appendNumber ) {
|
||||
sprintf ( pItemList[i].name,"%.*s%.6u",
|
||||
@@ -531,70 +571,109 @@ int catime ( const char * channelName,
|
||||
strncpy ( pItemList[i].name, channelName, strsize);
|
||||
}
|
||||
pItemList[i].name[strsize]= '\0';
|
||||
pItemList[i].count = 1;
|
||||
nBytes += 2 * ( OCT_ROUND ( strlen ( pItemList[i].name ) ) + 2 * sizeof (caHdr) );
|
||||
pItemList[i].count = 0;
|
||||
pItemList[i].pValue = 0;
|
||||
nBytesSent += 2 * ( CA_MESSAGE_ALIGN ( strlen ( pItemList[i].name ) )
|
||||
+ sizeof (caHdr) );
|
||||
nBytesRecv += 2 * sizeof (caHdr);
|
||||
}
|
||||
|
||||
printf ( "channel connect test\n" );
|
||||
timeIt ( test_search, pItemList, channelCount, nBytes );
|
||||
printf ( "Channel Connect Test\n" );
|
||||
printf ( "--------------------\n" );
|
||||
timeIt ( test_search, pItemList, channelCount, nBytesSent, nBytesRecv );
|
||||
printSearchStat ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
size_t count = ca_element_count ( pItemList[i].chix );
|
||||
size_t size = sizeof ( dbr_string_t ) * count;
|
||||
pItemList[i].count = count;
|
||||
pItemList[i].pValue = malloc ( size );
|
||||
assert ( pItemList[i].pValue );
|
||||
}
|
||||
|
||||
printf (
|
||||
"channel name=%s, native type=%d, native count=%lu\n",
|
||||
"channel name=%s, native type=%d, native count=%u\n",
|
||||
ca_name (pItemList[0].chix),
|
||||
ca_field_type (pItemList[0].chix),
|
||||
ca_element_count (pItemList[0].chix));
|
||||
pItemList[0].count );
|
||||
|
||||
printf ("\tpend event test\n");
|
||||
timeIt (test_pend, NULL, 100, 0);
|
||||
printf ("Pend Event Test\n");
|
||||
printf ( "----------------\n" );
|
||||
timeIt ( test_pend, NULL, 100, 0, 0 );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_float_t * pFltVal = ( dbr_float_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
pItemList[i].val.fltval = (dbr_float_t) val;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pFltVal[j] = (dbr_float_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_FLOAT;
|
||||
}
|
||||
printf ( "float test\n" );
|
||||
printf ( "DBR_FLOAT Test\n" );
|
||||
printf ( "--------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
pItemList[i].val.doubleval = (dbr_double_t) val;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pDblVal[j] = (dbr_double_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_DOUBLE;
|
||||
}
|
||||
printf ( "double test\n" );
|
||||
printf ( "DBR_DOUBLE Test\n" );
|
||||
printf ( "---------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_string_t * pStrVal = ( dbr_string_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
sprintf ( pItemList[i].val.strval, "%f", val );
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
sprintf ( pStrVal[j], "%f", val );
|
||||
}
|
||||
pItemList[i].type = DBR_STRING;
|
||||
}
|
||||
printf ( "string test\n" );
|
||||
printf ( "DBR_STRING Test\n" );
|
||||
printf ( "---------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_int_t * pIntVal = ( dbr_int_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
pItemList[i].val.intval = (dbr_int_t) val;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pIntVal[j] = (dbr_int_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_INT;
|
||||
}
|
||||
printf ( "integer test\n" );
|
||||
printf ( "DBR_INT Test\n" );
|
||||
printf ( "------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
printf ( "round trip jitter test\n" );
|
||||
printf ( "Get Latency Test\n" );
|
||||
printf ( "----------------\n" );
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
pItemList[i].val.fltval = 0.0f;
|
||||
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pDblVal[j] = 0;
|
||||
}
|
||||
pItemList[i].type = DBR_DOUBLE;
|
||||
}
|
||||
measure_get_latency ( pItemList, channelCount );
|
||||
|
||||
printf ("free test\n");
|
||||
timeIt ( test_free, pItemList, channelCount, 0 );
|
||||
printf ( "Free Channel Test\n" );
|
||||
printf ( "-----------------\n" );
|
||||
timeIt ( test_free, pItemList, channelCount, 0, 0 );
|
||||
|
||||
SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
free ( pItemList[i].pValue );
|
||||
}
|
||||
|
||||
free ( pItemList );
|
||||
|
||||
|
||||
@@ -145,7 +145,8 @@ private:
|
||||
return;
|
||||
}
|
||||
pComBuf = newComBuf ();
|
||||
assert ( pComBuf->push ( val ) );
|
||||
bool success = pComBuf->push ( val );
|
||||
assert ( success );
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,14 @@ epicsTimerNotify::expireStatus disconnectGovernorTimer::expire (
|
||||
void disconnectGovernorTimer::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
::printf ( "disconnect governor timer:\n" );
|
||||
tsDLIterConst < nciu > pChan = this->chanList.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 1u );
|
||||
pChan++;
|
||||
::printf ( "disconnect governor timer: with %u channels pending\n",
|
||||
this->chanList.count () );
|
||||
if ( level > 0u ) {
|
||||
tsDLIterConst < nciu > pChan = this->chanList.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 1u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,12 +77,17 @@ void getCallback::exception (
|
||||
args.status = status;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
else {
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
}
|
||||
}
|
||||
|
||||
void * getCallback::operator new ( size_t ) // X aCC 361
|
||||
|
||||
@@ -65,24 +65,30 @@ void getCopy::completion (
|
||||
memcpy ( this->pValue, pDataIn, size );
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
// this object destroyed by preceding function call
|
||||
}
|
||||
else {
|
||||
this->exception ( guard, ECA_INTERNAL,
|
||||
"bad data type match in get copy back response",
|
||||
typeIn, countIn);
|
||||
// this object destroyed by preceding function call
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char *pContext, unsigned /* typeIn */, arrayElementCount /* countIn */ )
|
||||
int status, const char *pContext,
|
||||
unsigned /* typeIn */, arrayElementCount /* countIn */ )
|
||||
{
|
||||
oldChannelNotify & chanTmp ( this->chan );
|
||||
unsigned typeTmp ( this->type );
|
||||
arrayElementCount countTmp ( this->count );
|
||||
ca_client_context & caClientCtx ( this->cacCtx );
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
this->cacCtx.exception ( guard, status, pContext,
|
||||
caClientCtx.exception ( guard, status, pContext,
|
||||
__FILE__, __LINE__, chanTmp, typeTmp,
|
||||
countTmp, CA_OP_GET );
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ extern "C" void epicsShareAPI removeDuplicateAddresses
|
||||
ELLNODE *pRawNode;
|
||||
|
||||
while ( (pRawNode = ellGet ( pSrcList ) ) ) {
|
||||
assert ( offsetof (osiSockAddrNode, node) == 0 );
|
||||
STATIC_ASSERT ( offsetof (osiSockAddrNode, node) == 0 );
|
||||
osiSockAddrNode *pNode = reinterpret_cast <osiSockAddrNode *> ( pRawNode );
|
||||
osiSockAddrNode *pTmpNode;
|
||||
|
||||
|
||||
@@ -79,8 +79,8 @@ void nciu::destroy (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
while ( baseNMIU * pNetIO = this->eventq.first () ) {
|
||||
assert ( this->cacCtx.destroyIO (
|
||||
guard, pNetIO->getId (), *this ) );
|
||||
bool success = this->cacCtx.destroyIO ( guard, pNetIO->getId (), *this );
|
||||
assert ( success );
|
||||
}
|
||||
|
||||
// if the claim reply has not returned yet then we will issue
|
||||
|
||||
@@ -404,6 +404,7 @@ private:
|
||||
void callbackProcessingCompleteNotify ();
|
||||
cacContext & createNetworkContext (
|
||||
epicsMutex & mutualExclusion, epicsMutex & callbackControl );
|
||||
void _sendWakeupMsg ();
|
||||
|
||||
ca_client_context ( const ca_client_context & );
|
||||
ca_client_context & operator = ( const ca_client_context & );
|
||||
|
||||
@@ -54,11 +54,13 @@ void putCallback::completion ( epicsGuard < epicsMutex > & guard )
|
||||
args.status = ECA_NORMAL;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
}
|
||||
|
||||
void putCallback::exception (
|
||||
@@ -75,12 +77,17 @@ void putCallback::exception (
|
||||
args.status = status;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) (args);
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
else {
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
}
|
||||
}
|
||||
|
||||
void * putCallback::operator new ( size_t ) // X aCC 361
|
||||
|
||||
@@ -511,7 +511,10 @@ void ca_repeater ()
|
||||
|
||||
pBuf = new char [MAX_UDP_RECV];
|
||||
|
||||
assert ( osiSockAttach() );
|
||||
{
|
||||
bool success = osiSockAttach();
|
||||
assert ( success );
|
||||
}
|
||||
|
||||
port = envGetInetPortConfigParam ( & EPICS_CA_REPEATER_PORT,
|
||||
static_cast <unsigned short> (CA_REPEATER_PORT) );
|
||||
|
||||
@@ -289,23 +289,31 @@ epicsTimerNotify::expireStatus searchTimer::expire (
|
||||
return expireStatus ( restart, this->period ( guard ) );
|
||||
}
|
||||
|
||||
void searchTimer::show ( unsigned level ) const
|
||||
void searchTimer :: show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
::printf ( "search timer delay %f\n", this->period ( guard ) );
|
||||
::printf ( "%u channels with search request pending\n",
|
||||
this->chanListReqPending.count () );
|
||||
tsDLIterConst < nciu > pChan = this->chanListReqPending.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 1u );
|
||||
pChan++;
|
||||
}
|
||||
::printf ( "%u channels with search response pending\n",
|
||||
this->chanListRespPending.count () );
|
||||
pChan = this->chanListRespPending.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 1u );
|
||||
pChan++;
|
||||
::printf ( "searchTimer with period %f\n", this->period ( guard ) );
|
||||
if ( level > 0 ) {
|
||||
::printf ( "channels with search request pending = %u\n",
|
||||
this->chanListReqPending.count () );
|
||||
if ( level > 1u ) {
|
||||
tsDLIterConst < nciu > pChan =
|
||||
this->chanListReqPending.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 2u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
::printf ( "channels with search response pending = %u\n",
|
||||
this->chanListRespPending.count () );
|
||||
if ( level > 1u ) {
|
||||
tsDLIterConst < nciu > pChan =
|
||||
this->chanListRespPending.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 2u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -42,6 +44,8 @@
|
||||
#include "caerr.h"
|
||||
#include "udpiiu.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const unsigned mSecPerSec = 1000u;
|
||||
const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
|
||||
@@ -468,6 +472,7 @@ void tcpRecvThread::run ()
|
||||
if ( ! pComBuf ) {
|
||||
pComBuf = new ( this->iiu.comBufMemMgr ) comBuf;
|
||||
}
|
||||
|
||||
statusWireIO stat;
|
||||
pComBuf->fillFromWire ( this->iiu, stat );
|
||||
|
||||
@@ -497,7 +502,6 @@ void tcpRecvThread::run ()
|
||||
callbackManager mgr ( this->ctxNotify, this->cbMutex );
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->iiu.mutex );
|
||||
|
||||
|
||||
// route legacy V42 channel connect through the recv thread -
|
||||
// the only thread that should be taking the callback lock
|
||||
@@ -506,19 +510,6 @@ void tcpRecvThread::run ()
|
||||
pChan->connect ( mgr.cbGuard, guard );
|
||||
}
|
||||
|
||||
if ( stat.bytesCopied == pComBuf->capacityBytes () ) {
|
||||
if ( this->iiu.contigRecvMsgCount >=
|
||||
contiguousMsgCountWhichTriggersFlowControl ) {
|
||||
this->iiu.busyStateDetected = true;
|
||||
}
|
||||
else {
|
||||
this->iiu.contigRecvMsgCount++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->iiu.contigRecvMsgCount = 0u;
|
||||
this->iiu.busyStateDetected = false;
|
||||
}
|
||||
this->iiu.unacknowledgedSendBytes = 0u;
|
||||
|
||||
bool protocolOK = false;
|
||||
@@ -542,6 +533,40 @@ void tcpRecvThread::run ()
|
||||
sendWakeupNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// we dont feel comfortable calling this with a lock applied
|
||||
// (it might block for longer than we like)
|
||||
//
|
||||
// we would prefer to improve efficency by trying, first, a
|
||||
// recv with the new MSG_DONTWAIT flag set, but there isnt
|
||||
// universal support
|
||||
//
|
||||
bool bytesArePending = this->iiu.bytesArePendingInOS ();
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->iiu.mutex );
|
||||
if ( bytesArePending ) {
|
||||
if ( ! this->iiu.busyStateDetected ) {
|
||||
this->iiu.contigRecvMsgCount++;
|
||||
if ( this->iiu.contigRecvMsgCount >=
|
||||
this->iiu.cacRef.maxContiguousFrames ( guard ) ) {
|
||||
this->iiu.busyStateDetected = true;
|
||||
sendWakeupNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if no bytes are pending then we must immediately
|
||||
// switch off flow control w/o waiting for more
|
||||
// data to arrive
|
||||
this->iiu.contigRecvMsgCount = 0u;
|
||||
if ( this->iiu.busyStateDetected ) {
|
||||
sendWakeupNeeded = true;
|
||||
this->iiu.busyStateDetected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sendWakeupNeeded ) {
|
||||
this->iiu.sendThreadFlushEvent.signal ();
|
||||
}
|
||||
@@ -673,13 +698,15 @@ tcpiiu::tcpiiu (
|
||||
{
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if ( this->sock == INVALID_SOCKET ) {
|
||||
cac.releaseSmallBufferTCP ( this->pCurData );
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAC: unable to create virtual circuit because \"%s\"\n",
|
||||
sockErrBuf );
|
||||
cac.releaseSmallBufferTCP ( this->pCurData );
|
||||
throw std::bad_alloc ();
|
||||
std :: string reason =
|
||||
"CAC: TCP circuit creation failure because \"";
|
||||
reason += sockErrBuf;
|
||||
reason += "\"";
|
||||
throw runtime_error ( reason );
|
||||
}
|
||||
|
||||
int flag = true;
|
||||
@@ -727,7 +754,7 @@ tcpiiu::tcpiiu (
|
||||
if (status < 0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAC: problems setting socket option SO_SNDBUF = \"%s\"\n",
|
||||
errlogPrintf ( "CAC: problems setting socket option SO_SNDBUF = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
i = MAX_MSG_SIZE;
|
||||
@@ -1694,7 +1721,7 @@ void tcpiiu::decrementBlockingForFlushCount (
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
assert ( this->blockingForFlush > 0u );
|
||||
this->blockingForFlush--;
|
||||
if ( this->blockingForFlush == 0 ) {
|
||||
if ( this->blockingForFlush > 0 ) {
|
||||
this->flushBlockEvent.signal ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ template class tsFreeList < syncGroupWriteNotify, 128, epicsMutexNOOP >;
|
||||
template class tsFreeList < comBuf, 0x20 >;
|
||||
template class tsFreeList < getCallback, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < getCopy, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < hostNameCache, 16 >;
|
||||
template class tsFreeList < msgForMultiplyDefinedPV, 16 >;
|
||||
template class tsFreeList < nciu, 1024, epicsMutexNOOP>;
|
||||
template class tsFreeList < oldChannelNotify, 1024, epicsMutexNOOP >;
|
||||
|
||||
@@ -50,7 +50,6 @@ public:
|
||||
{
|
||||
pvInfo::pFirst = this;
|
||||
this->pName = new char [strlen(pNameIn)+1u];
|
||||
assert(this->pName);
|
||||
strcpy(this->pName, pNameIn);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ caServerI::caServerI ( caServer & tool ) :
|
||||
beaconAnomalyGov ( * new beaconAnomalyGovernor ( *this ) ),
|
||||
debugLevel ( 0u ),
|
||||
nEventsProcessed ( 0u ),
|
||||
nEventsPosted ( 0u )
|
||||
nEventsPosted ( 0u ),
|
||||
ioInProgressCount ( 0u )
|
||||
{
|
||||
assert ( & adapter != NULL );
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ public:
|
||||
const char * pHostName, const char * pUserName,
|
||||
const struct caHdrLargeArray * mp, const void * dp,
|
||||
const char * pFormat, ... );
|
||||
bool ioIsPending () const;
|
||||
void incrementIOInProgCount ();
|
||||
void decrementIOInProgCount ();
|
||||
private:
|
||||
clientBufMemoryManager clientBufMemMgr;
|
||||
tsFreeList < casMonitor, 1024 > casMonitorFreeList;
|
||||
@@ -89,6 +92,7 @@ private:
|
||||
unsigned debugLevel;
|
||||
unsigned nEventsProcessed;
|
||||
unsigned nEventsPosted;
|
||||
unsigned ioInProgressCount;
|
||||
|
||||
casEventMask valueEvent; // DBE_VALUE registerEvent("value")
|
||||
casEventMask logEvent; // DBE_LOG registerEvent("log")
|
||||
@@ -137,4 +141,22 @@ inline casEventMask caServerI::alarmEventMask() const
|
||||
return this->alarmEvent;
|
||||
}
|
||||
|
||||
inline bool caServerI :: ioIsPending () const
|
||||
{
|
||||
return ( ioInProgressCount > 0u );
|
||||
}
|
||||
|
||||
inline void caServerI :: incrementIOInProgCount ()
|
||||
{
|
||||
assert ( ioInProgressCount < UINT_MAX );
|
||||
ioInProgressCount++;
|
||||
}
|
||||
|
||||
inline void caServerI :: decrementIOInProgCount ()
|
||||
{
|
||||
assert ( ioInProgressCount > 0 );
|
||||
ioInProgressCount--;
|
||||
this->ioBlockedList::signal ();
|
||||
}
|
||||
|
||||
#endif // caServerIh
|
||||
|
||||
@@ -100,8 +100,6 @@ caStatus casAsyncIOI::cbFunc (
|
||||
this->ioComplete = true;
|
||||
}
|
||||
|
||||
this->client.getCAS().ioBlockedList::signal ();
|
||||
|
||||
// dont use "this" after destroying the object here
|
||||
delete this;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ casAsyncPVAttachIOI::casAsyncPVAttachIOI (
|
||||
casAsyncIOI ( ctx ), msg ( *ctx.getMsg() ),
|
||||
asyncPVAttachIO ( intf ), retVal ( S_cas_badParameter )
|
||||
{
|
||||
ctx.getServer()->incrementIOInProgCount ();
|
||||
ctx.getClient()->installAsynchIO ( *this );
|
||||
}
|
||||
|
||||
@@ -42,6 +43,7 @@ caStatus casAsyncPVAttachIOI::cbFuncAsyncIO (
|
||||
// uninstall here in case the channel is deleted
|
||||
// further down the call stack
|
||||
this->client.uninstallAsynchIO ( *this );
|
||||
this->client.getCAS().decrementIOInProgCount ();
|
||||
|
||||
if ( this->msg.m_cmmd == CA_PROTO_CREATE_CHAN ) {
|
||||
casCtx tmpCtx;
|
||||
@@ -58,6 +60,7 @@ caStatus casAsyncPVAttachIOI::cbFuncAsyncIO (
|
||||
}
|
||||
|
||||
if ( status == S_cas_sendBlocked ) {
|
||||
this->client.getCAS().incrementIOInProgCount ();
|
||||
this->client.installAsynchIO ( *this );
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ casAsyncPVExistIOI::casAsyncPVExistIOI (
|
||||
protocolRevision ( ctx.getClient()->protocolRevision () ),
|
||||
sequenceNumber ( ctx.getClient()->datagramSequenceNumber () )
|
||||
{
|
||||
ctx.getServer()->incrementIOInProgCount ();
|
||||
ctx.getClient()->installAsynchIO ( *this );
|
||||
}
|
||||
|
||||
@@ -61,6 +62,7 @@ caStatus casAsyncPVExistIOI::cbFuncAsyncIO (
|
||||
|
||||
if ( status != S_cas_sendBlocked ) {
|
||||
this->client.uninstallAsynchIO ( *this );
|
||||
this->client.getCAS().decrementIOInProgCount ();
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
@@ -90,6 +90,11 @@ caStatus casChannel::write ( const casCtx & ctx, const gdd & value )
|
||||
return ctx.getPV()->write ( ctx, value );
|
||||
}
|
||||
|
||||
caStatus casChannel::writeNotify ( const casCtx & ctx, const gdd & value )
|
||||
{
|
||||
return ctx.getPV()->writeNotify ( ctx, value );
|
||||
}
|
||||
|
||||
void casChannel::show ( unsigned level ) const
|
||||
{
|
||||
if ( level > 2u ) {
|
||||
|
||||
@@ -101,6 +101,17 @@ caStatus casChannelI::write ( const casCtx & ctx, const gdd & value )
|
||||
return status;
|
||||
}
|
||||
|
||||
caStatus casChannelI::writeNotify ( const casCtx & ctx, const gdd & value )
|
||||
{
|
||||
caStatus status = this->chan.beginTransaction ();
|
||||
if ( status != S_casApp_success ) {
|
||||
return status;
|
||||
}
|
||||
status = this->chan.writeNotify ( ctx, value );
|
||||
this->chan.endTransaction ();
|
||||
return status;
|
||||
}
|
||||
|
||||
void casChannelI::postDestroyEvent ()
|
||||
{
|
||||
if ( ! this->serverDeletePending ) {
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
bool confirmationRequested () const;
|
||||
caStatus read ( const casCtx & ctx, gdd & prototype );
|
||||
caStatus write ( const casCtx & ctx, const gdd & value );
|
||||
caStatus writeNotify ( const casCtx & ctx, const gdd & value );
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
chanIntfForPV privateForPV;
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
bool okToStartAsynchIO ();
|
||||
void setDestroyPending ();
|
||||
|
||||
casEventSys::processStatus eventSysProcess();
|
||||
casProcCond eventSysProcess();
|
||||
|
||||
caStatus addToEventQueue ( casAsyncIOI &,
|
||||
bool & onTheQueue, bool & posted );
|
||||
@@ -172,7 +172,7 @@ inline void casCoreClient::postEvent (
|
||||
}
|
||||
}
|
||||
|
||||
inline casEventSys::processStatus casCoreClient::eventSysProcess ()
|
||||
inline casProcCond casCoreClient :: eventSysProcess ()
|
||||
{
|
||||
epicsGuard < casClientMutex > guard ( this->mutex );
|
||||
return this->eventSys.process ( guard );
|
||||
|
||||
@@ -408,18 +408,15 @@ void casDGClient::sendBeacon ( ca_uint32_t beaconNumber )
|
||||
//
|
||||
// casDGClient::xSend()
|
||||
//
|
||||
outBufClient::flushCondition casDGClient::xSend ( char *pBufIn, // X aCC 361
|
||||
bufSizeT nBytesAvailableToSend, bufSizeT nBytesNeedToBeSent,
|
||||
bufSizeT &nBytesSent )
|
||||
outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
|
||||
bufSizeT nBytesToSend, bufSizeT & nBytesSent )
|
||||
{
|
||||
assert ( nBytesAvailableToSend >= nBytesNeedToBeSent );
|
||||
|
||||
bufSizeT totalBytes = 0;
|
||||
while ( totalBytes < nBytesNeedToBeSent ) {
|
||||
while ( totalBytes < nBytesToSend ) {
|
||||
cadg *pHdr = reinterpret_cast < cadg * > ( & pBufIn[totalBytes] );
|
||||
|
||||
assert ( totalBytes <= bufSizeT_MAX-pHdr->cadg_nBytes );
|
||||
assert ( totalBytes + pHdr->cadg_nBytes <= nBytesAvailableToSend );
|
||||
assert ( totalBytes <= bufSizeT_MAX - pHdr->cadg_nBytes );
|
||||
assert ( totalBytes + pHdr->cadg_nBytes <= nBytesToSend );
|
||||
|
||||
char * pDG = reinterpret_cast < char * > ( pHdr + 1 );
|
||||
unsigned sizeDG = pHdr->cadg_nBytes - sizeof ( *pHdr );
|
||||
@@ -710,13 +707,15 @@ void casDGClient::inBufFill ( inBufClient::fillParameter parm )
|
||||
this->in.fill ( parm );
|
||||
}
|
||||
|
||||
bufSizeT casDGClient::inBufBytesAvailable () const
|
||||
bufSizeT casDGClient ::
|
||||
inBufBytesPending () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
return this->in.bytesAvailable ();
|
||||
return this->in.bytesPresent ();
|
||||
}
|
||||
|
||||
bufSizeT casDGClient::outBufBytesPresent () const
|
||||
bufSizeT casDGClient ::
|
||||
outBufBytesPending () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
return this->out.bytesPresent ();
|
||||
|
||||
@@ -48,12 +48,12 @@ public:
|
||||
caStatus sendErr ( const caHdrLargeArray * curp,
|
||||
ca_uint32_t cid, const int reportedStatus,
|
||||
const char *pformat, ... );
|
||||
protected:
|
||||
caStatus processDG ();
|
||||
protected:
|
||||
bool inBufFull () const;
|
||||
void inBufFill ( inBufClient::fillParameter );
|
||||
bufSizeT inBufBytesAvailable () const;
|
||||
bufSizeT outBufBytesPresent () const;
|
||||
bufSizeT inBufBytesPending () const;
|
||||
bufSizeT outBufBytesPending () const;
|
||||
outBufClient::flushCondition flush ();
|
||||
private:
|
||||
inBuf in;
|
||||
@@ -80,8 +80,8 @@ private:
|
||||
const caHdrLargeArray &, const pvExistReturn &,
|
||||
ca_uint16_t protocolRevision, ca_uint32_t sequenceNumber );
|
||||
void sendVersion ();
|
||||
outBufClient::flushCondition xSend ( char *pBufIn, bufSizeT nBytesAvailableToSend,
|
||||
bufSizeT nBytesNeedToBeSent, bufSizeT &nBytesSent );
|
||||
outBufClient::flushCondition xSend ( char *pBufIn, bufSizeT nBytesToSend,
|
||||
bufSizeT &nBytesSent );
|
||||
inBufClient::fillCondition xRecv ( char * pBufIn, bufSizeT nBytesToRecv,
|
||||
fillParameter parm, bufSizeT & nByesRecv );
|
||||
virtual outBufClient::flushCondition osdSend (
|
||||
|
||||
@@ -21,9 +21,13 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "casdef.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "casEventRegistry.h"
|
||||
|
||||
#ifdef TEST
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
main ()
|
||||
{
|
||||
casEventRegistry reg;
|
||||
@@ -49,20 +53,20 @@ main ()
|
||||
art2.show(10u);
|
||||
reg.show(10u);
|
||||
|
||||
assert (bill1 == bill2);
|
||||
assert (bill1 == bill3);
|
||||
assert (jane != bill1);
|
||||
assert (jane != art1);
|
||||
assert (bill1 != art1);
|
||||
assert (art1 == art2);
|
||||
verify (bill1 == bill2);
|
||||
verify (bill1 == bill3);
|
||||
verify (jane != bill1);
|
||||
verify (jane != art1);
|
||||
verify (bill1 != art1);
|
||||
verify (art1 == art2);
|
||||
|
||||
artBill = art1 | bill1;
|
||||
tmp = artBill & art1;
|
||||
assert (tmp.eventsSelected());
|
||||
verify (tmp.eventsSelected());
|
||||
tmp = artBill & bill1;
|
||||
assert (tmp.eventsSelected());
|
||||
verify (tmp.eventsSelected());
|
||||
tmp = artBill&jane;
|
||||
assert (tmp.noEventsSelected());
|
||||
verify (tmp.noEventsSelected());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -128,10 +132,8 @@ casEventMaskEntry::casEventMaskEntry (
|
||||
casEventRegistry & regIn, casEventMask maskIn, const char * pName ) :
|
||||
casEventMask ( maskIn ), stringId ( pName ), reg ( regIn )
|
||||
{
|
||||
int stat;
|
||||
|
||||
assert ( this->resourceName() != NULL );
|
||||
stat = this->reg.add ( *this );
|
||||
int stat = this->reg.add ( *this );
|
||||
assert ( stat == 0 );
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,13 @@ void casEventSys::show ( unsigned level ) const
|
||||
if (level>=1u) {
|
||||
printf ( "\numSubscriptions = %u, maxLogEntries = %u\n",
|
||||
this->numSubscriptions, this->maxLogEntries );
|
||||
printf ( "\tthere are %d events in the queue\n",
|
||||
printf ( "\tthere are %d items in the event queue\n",
|
||||
this->eventLogQue.count() );
|
||||
printf ( "Replace events flag = %d, dontProcess flag = %d\n",
|
||||
printf ( "\tthere are %d items in the io queue\n",
|
||||
this->ioQue.count() );
|
||||
printf ( "Replace events flag = %d, dontProcessSubscr flag = %d\n",
|
||||
static_cast < int > ( this->replaceEvents ),
|
||||
static_cast < int > ( this->dontProcess ) );
|
||||
static_cast < int > ( this->dontProcessSubscr ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +51,14 @@ casEventSys::~casEventSys()
|
||||
}
|
||||
|
||||
// at this point:
|
||||
// o all channels delete
|
||||
// o all IO deleted
|
||||
// o all channels have been deleted
|
||||
// o all IO has been deleted
|
||||
// o any subscription events remaining on the queue
|
||||
// are pending destroy
|
||||
|
||||
// verify above assertion is true
|
||||
casVerify ( this->eventLogQue.count() == 0 );
|
||||
casVerify ( this->ioQue.count() == 0 );
|
||||
|
||||
// all active subscriptions should also have been
|
||||
// uninstalled
|
||||
@@ -81,20 +84,18 @@ void casEventSys::removeMonitor ()
|
||||
this->maxLogEntries -= averageEventEntries;
|
||||
}
|
||||
|
||||
casEventSys::processStatus casEventSys::process (
|
||||
casProcCond casEventSys :: process (
|
||||
epicsGuard < casClientMutex > & casClientGuard )
|
||||
{
|
||||
casEventSys::processStatus ps;
|
||||
ps.cond = casProcOk;
|
||||
ps.nAccepted = 0u;
|
||||
casProcCond cond = casProcOk;
|
||||
|
||||
epicsGuard < evSysMutex > evGuard ( this->mutex );
|
||||
|
||||
while ( ! this->dontProcess ) {
|
||||
casEvent * pEvent;
|
||||
|
||||
pEvent = this->eventLogQue.get ();
|
||||
|
||||
// we need two queues, one for io and one for subscriptions,
|
||||
// so that we dont hang up the server when in an IO postponed
|
||||
// state simultaneouly with a flow control active state
|
||||
while ( true ) {
|
||||
casEvent * pEvent = this->ioQue.get ();
|
||||
if ( pEvent == NULL ) {
|
||||
break;
|
||||
}
|
||||
@@ -102,27 +103,59 @@ casEventSys::processStatus casEventSys::process (
|
||||
caStatus status = pEvent->cbFunc (
|
||||
this->client, casClientGuard, evGuard );
|
||||
if ( status == S_cas_success ) {
|
||||
ps.nAccepted++;
|
||||
cond = casProcOk;
|
||||
}
|
||||
else if ( status == S_cas_sendBlocked ) {
|
||||
// not accepted so return to the head of the list
|
||||
// (we will try again later)
|
||||
this->eventLogQue.push ( *pEvent );
|
||||
ps.cond = casProcOk;
|
||||
this->ioQue.push ( *pEvent );
|
||||
cond = casProcOk;
|
||||
break;
|
||||
}
|
||||
else if ( status == S_cas_disconnect ) {
|
||||
ps.cond = casProcDisconnect;
|
||||
cond = casProcDisconnect;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
errMessage ( status,
|
||||
"- unexpected error processing event" );
|
||||
ps.cond = casProcDisconnect;
|
||||
"- unexpected error, processing io queue" );
|
||||
cond = casProcDisconnect;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( cond == casProcOk ) {
|
||||
while ( ! this->dontProcessSubscr ) {
|
||||
casEvent * pEvent = this->eventLogQue.get ();
|
||||
if ( pEvent == NULL ) {
|
||||
break;
|
||||
}
|
||||
|
||||
caStatus status = pEvent->cbFunc (
|
||||
this->client, casClientGuard, evGuard );
|
||||
if ( status == S_cas_success ) {
|
||||
cond = casProcOk;
|
||||
}
|
||||
else if ( status == S_cas_sendBlocked ) {
|
||||
// not accepted so return to the head of the list
|
||||
// (we will try again later)
|
||||
this->eventLogQue.push ( *pEvent );
|
||||
cond = casProcOk;
|
||||
break;
|
||||
}
|
||||
else if ( status == S_cas_disconnect ) {
|
||||
cond = casProcDisconnect;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
errMessage ( status,
|
||||
"- unexpected error, processing event queue" );
|
||||
cond = casProcDisconnect;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// allows the derived class to be informed that it
|
||||
// needs to delete itself via the event system
|
||||
@@ -133,10 +166,10 @@ casEventSys::processStatus casEventSys::process (
|
||||
// pointer.
|
||||
//
|
||||
if ( this->destroyPending ) {
|
||||
ps.cond = casProcDisconnect;
|
||||
cond = casProcDisconnect;
|
||||
}
|
||||
|
||||
return ps;
|
||||
return cond;
|
||||
}
|
||||
|
||||
void casEventSys::eventsOn ()
|
||||
@@ -151,7 +184,7 @@ void casEventSys::eventsOn ()
|
||||
//
|
||||
// allow the event queue to be processed
|
||||
//
|
||||
this->dontProcess = false;
|
||||
this->dontProcessSubscr = false;
|
||||
|
||||
//
|
||||
// remove purge event if it is still pending
|
||||
@@ -188,7 +221,7 @@ bool casEventSys::eventsOff ()
|
||||
// stop processing and sending events to the client
|
||||
// until we exit flow control
|
||||
//
|
||||
this->dontProcess = true;
|
||||
this->dontProcessSubscr = true;
|
||||
}
|
||||
else {
|
||||
if ( this->eventLogQue.count() == 0 ) {
|
||||
@@ -211,7 +244,7 @@ caStatus casEventPurgeEv::cbFunc (
|
||||
epicsGuard < casClientMutex > &,
|
||||
epicsGuard < evSysMutex > & )
|
||||
{
|
||||
this->evSys.dontProcess = true;
|
||||
this->evSys.dontProcessSubscr = true;
|
||||
this->evSys.pPurgeEvent = NULL;
|
||||
delete this;
|
||||
return S_cas_success;
|
||||
@@ -220,60 +253,66 @@ caStatus casEventPurgeEv::cbFunc (
|
||||
caStatus casEventSys::addToEventQueue ( casAsyncIOI & event,
|
||||
bool & onTheQueue, bool & posted, bool & wakeupNeeded )
|
||||
{
|
||||
wakeupNeeded = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
// dont allow them to post completion more than once
|
||||
if ( posted || onTheQueue ) {
|
||||
wakeupNeeded = false;
|
||||
return S_cas_redundantPost;
|
||||
}
|
||||
posted = true;
|
||||
onTheQueue = true;
|
||||
wakeupNeeded = ! this->dontProcess && this->eventLogQue.count() == 0;
|
||||
this->eventLogQue.add ( event );
|
||||
wakeupNeeded =
|
||||
( this->dontProcessSubscr || this->eventLogQue.count() == 0 ) &&
|
||||
this->ioQue.count() == 0;
|
||||
this->ioQue.add ( event );
|
||||
}
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
void casEventSys::removeFromEventQueue ( casAsyncIOI & io, bool & onTheEventQueue )
|
||||
void casEventSys::removeFromEventQueue ( casAsyncIOI & io, bool & onTheIOQueue )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( onTheEventQueue ) {
|
||||
onTheEventQueue = false;
|
||||
this->eventLogQue.remove ( io );
|
||||
if ( onTheIOQueue ) {
|
||||
onTheIOQueue = false;
|
||||
this->ioQue.remove ( io );
|
||||
}
|
||||
}
|
||||
|
||||
bool casEventSys::addToEventQueue ( casChannelI & event,
|
||||
bool & inTheEventQueue )
|
||||
bool & onTheIOQueue )
|
||||
{
|
||||
bool wakeupRequired = false;
|
||||
bool wakeupNeeded = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( ! inTheEventQueue ) {
|
||||
inTheEventQueue = true;
|
||||
wakeupRequired = ! this->dontProcess && this->eventLogQue.count()==0;
|
||||
this->eventLogQue.add ( event );
|
||||
if ( ! onTheIOQueue ) {
|
||||
onTheIOQueue = true;
|
||||
wakeupNeeded =
|
||||
( this->dontProcessSubscr || this->eventLogQue.count() == 0 ) &&
|
||||
this->ioQue.count() == 0;
|
||||
this->ioQue.add ( event );
|
||||
}
|
||||
}
|
||||
return wakeupRequired;
|
||||
return wakeupNeeded;
|
||||
}
|
||||
|
||||
void casEventSys::removeFromEventQueue ( class casChannelI & io,
|
||||
bool & inTheEventQueue )
|
||||
bool & onTheIOQueue )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( inTheEventQueue ) {
|
||||
inTheEventQueue = false;
|
||||
this->eventLogQue.remove ( io );
|
||||
if ( onTheIOQueue ) {
|
||||
onTheIOQueue = false;
|
||||
this->ioQue.remove ( io );
|
||||
}
|
||||
}
|
||||
|
||||
bool casEventSys::addToEventQueue ( channelDestroyEvent & event )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
bool wakeupRequired = ! this->dontProcess && this->eventLogQue.count()==0;
|
||||
this->eventLogQue.add ( event );
|
||||
bool wakeupRequired =
|
||||
( this->dontProcessSubscr || this->eventLogQue.count() == 0 ) &&
|
||||
this->ioQue.count() == 0;
|
||||
this->ioQue.add ( event );
|
||||
return wakeupRequired;
|
||||
}
|
||||
|
||||
@@ -283,14 +322,10 @@ void casEventSys::setDestroyPending ()
|
||||
this->destroyPending = true;
|
||||
}
|
||||
|
||||
inline bool casEventSys::full () const // X aCC 361
|
||||
inline bool casEventSys::full () const
|
||||
{
|
||||
if ( this->replaceEvents || this->eventLogQue.count() >= this->maxLogEntries ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return this->replaceEvents ||
|
||||
this->eventLogQue.count() >= this->maxLogEntries;
|
||||
}
|
||||
|
||||
bool casEventSys::postEvent ( tsDLList < casMonitor > & monitorList,
|
||||
@@ -323,9 +358,11 @@ bool casEventSys::postEvent ( tsDLList < casMonitor > & monitorList,
|
||||
pLog = 0;
|
||||
}
|
||||
|
||||
if ( this->eventLogQue.count() == 0 ) {
|
||||
signalNeeded = true;
|
||||
}
|
||||
signalNeeded |=
|
||||
!this->dontProcessSubscr &&
|
||||
this->eventLogQue.count() == 0 &&
|
||||
this->ioQue.count() == 0;
|
||||
|
||||
iter->installNewEventLog (
|
||||
this->eventLogQue, pLog, event );
|
||||
}
|
||||
|
||||
@@ -68,12 +68,7 @@ public:
|
||||
casEventSys ( casCoreClient & );
|
||||
~casEventSys ();
|
||||
void show ( unsigned level ) const;
|
||||
struct processStatus {
|
||||
casProcCond cond;
|
||||
unsigned nAccepted;
|
||||
};
|
||||
processStatus process (
|
||||
epicsGuard < casClientMutex > & guard );
|
||||
casProcCond process ( epicsGuard < casClientMutex > & guard );
|
||||
void installMonitor ();
|
||||
void removeMonitor ();
|
||||
void prepareMonitorForDestroy ( casMonitor & mon );
|
||||
@@ -97,6 +92,7 @@ public:
|
||||
private:
|
||||
mutable evSysMutex mutex;
|
||||
tsDLList < casEvent > eventLogQue;
|
||||
tsDLList < casEvent > ioQue;
|
||||
tsFreeList < casMonEvent, 1024, epicsMutexNOOP > casMonEventFreeList;
|
||||
casCoreClient & client;
|
||||
class casEventPurgeEv * pPurgeEvent; // flow control purge complete event
|
||||
@@ -104,7 +100,7 @@ private:
|
||||
unsigned maxLogEntries; // max log entries
|
||||
bool destroyPending;
|
||||
bool replaceEvents; // replace last existing event on queue
|
||||
bool dontProcess; // flow ctl is on - dont process event queue
|
||||
bool dontProcessSubscr; // flow ctl is on - dont process subscr event queue
|
||||
|
||||
bool full () const;
|
||||
casEventSys ( const casEventSys & );
|
||||
@@ -141,7 +137,7 @@ inline casEventSys::casEventSys ( casCoreClient & clientIn ) :
|
||||
maxLogEntries ( individualEventEntries ),
|
||||
destroyPending ( false ),
|
||||
replaceEvents ( false ),
|
||||
dontProcess ( false )
|
||||
dontProcessSubscr ( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +111,18 @@ caStatus casPV::write (const casCtx &, const gdd &)
|
||||
return S_casApp_noSupport;
|
||||
}
|
||||
|
||||
//
|
||||
// casPV::writeNotify()
|
||||
//
|
||||
caStatus casPV :: writeNotify (
|
||||
const casCtx & ctx, const gdd & val )
|
||||
{
|
||||
// plumbed this way to preserve backwards
|
||||
// compatibility with the old interface which
|
||||
// did not include a writeNotify interface
|
||||
return this->write ( ctx, val );
|
||||
}
|
||||
|
||||
//
|
||||
// casPV::bestExternalType()
|
||||
//
|
||||
|
||||
@@ -464,6 +464,23 @@ caStatus casPVI::write ( const casCtx & ctx, const gdd & value )
|
||||
}
|
||||
}
|
||||
|
||||
caStatus casPVI::writeNotify ( const casCtx & ctx, const gdd & value )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( this->pPV ) {
|
||||
caStatus status = this->pPV->beginTransaction ();
|
||||
if ( status != S_casApp_success ) {
|
||||
return status;
|
||||
}
|
||||
status = this->pPV->writeNotify ( ctx, value );
|
||||
this->pPV->endTransaction ();
|
||||
return status;
|
||||
}
|
||||
else {
|
||||
return S_cas_disconnect;
|
||||
}
|
||||
}
|
||||
|
||||
casChannel * casPVI::createChannel ( const casCtx & ctx,
|
||||
const char * const pUserName, const char * const pHostName )
|
||||
{
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
caServerI * getPCAS () const;
|
||||
caStatus attachToServer ( caServerI & cas );
|
||||
aitIndex nativeCount ();
|
||||
bool ioIsPending () const;
|
||||
void clearOutstandingReads ( tsDLList < class casAsyncIOI > &);
|
||||
void destroyAllIO (
|
||||
tsDLList < casAsyncIOI > & );
|
||||
@@ -77,6 +78,7 @@ public:
|
||||
void show ( unsigned level ) const;
|
||||
caStatus read ( const casCtx & ctx, gdd & prototype );
|
||||
caStatus write ( const casCtx & ctx, const gdd & value );
|
||||
caStatus writeNotify ( const casCtx & ctx, const gdd & value );
|
||||
casChannel * createChannel ( const casCtx & ctx,
|
||||
const char * const pUserName, const char * const pHostName );
|
||||
aitEnum bestExternalType () const;
|
||||
@@ -112,5 +114,10 @@ inline casPV * casPVI::apiPointer ()
|
||||
return this->pPV;
|
||||
}
|
||||
|
||||
inline bool casPVI :: ioIsPending () const
|
||||
{
|
||||
return this->nIOAttached > 0u;
|
||||
}
|
||||
|
||||
#endif // casPVIh
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,9 +49,9 @@ public:
|
||||
protected:
|
||||
caStatus processMsg ();
|
||||
bool inBufFull () const;
|
||||
bufSizeT inBufBytesAvailable () const;
|
||||
inBufClient::fillCondition inBufFill ();
|
||||
bufSizeT outBufBytesPresent () const;
|
||||
bufSizeT inBufBytesPending () const;
|
||||
bufSizeT outBufBytesPending () const;
|
||||
private:
|
||||
char hostNameStr [32];
|
||||
inBuf in;
|
||||
@@ -62,10 +62,11 @@ private:
|
||||
epicsTime lastRecvTS;
|
||||
char * pUserName;
|
||||
char * pHostName;
|
||||
smartGDDPointer pValueRead;
|
||||
unsigned incommingBytesToDrain;
|
||||
int pendingResponseStatus;
|
||||
caStatus pendingResponseStatus;
|
||||
ca_uint16_t minor_version_number;
|
||||
bool payloadNeedsByteSwap;
|
||||
bool reqPayloadNeedsByteSwap;
|
||||
bool responseIsPending;
|
||||
|
||||
caStatus createChannel ( const char * pName );
|
||||
@@ -142,15 +143,16 @@ private:
|
||||
caStatus accessRightsResponse (
|
||||
epicsGuard < casClientMutex > &, casChannelI * pciu );
|
||||
|
||||
caStatus read ( const gdd * & pDesc );
|
||||
caStatus write ();
|
||||
|
||||
caStatus writeArrayData();
|
||||
caStatus writeScalarData();
|
||||
caStatus writeString();
|
||||
typedef caStatus ( casChannelI :: * PWriteMethod ) (
|
||||
const casCtx &, const gdd & );
|
||||
caStatus read ();
|
||||
caStatus write ( PWriteMethod );
|
||||
caStatus writeArrayData( PWriteMethod );
|
||||
caStatus writeScalarData( PWriteMethod );
|
||||
|
||||
outBufClient::flushCondition xSend ( char * pBuf, bufSizeT nBytesAvailableToSend,
|
||||
bufSizeT nBytesNeedToBeSent, bufSizeT & nBytesSent );
|
||||
outBufClient::flushCondition xSend ( char * pBuf, bufSizeT nBytesToSend,
|
||||
bufSizeT & nBytesSent );
|
||||
inBufClient::fillCondition xRecv ( char * pBuf, bufSizeT nBytesToRecv,
|
||||
inBufClient::fillParameter parm, bufSizeT & nByesRecv );
|
||||
|
||||
@@ -169,6 +171,7 @@ private:
|
||||
const unsigned lineno, const unsigned idIn );
|
||||
void casChannelDestroyFromInterfaceNotify ( casChannelI & chan,
|
||||
bool immediatedSestroyNeeded );
|
||||
static void issuePosponeWhenNonePendingWarning ( const char * pReqTypeStr );
|
||||
|
||||
casStrmClient ( const casStrmClient & );
|
||||
casStrmClient & operator = ( const casStrmClient & );
|
||||
|
||||
@@ -78,6 +78,7 @@ typedef aitUint32 caStatus;
|
||||
#define S_cas_pvAlreadyAttached (M_cas | 31) /*PV attached to another server*/
|
||||
#define S_cas_badRequest (M_cas | 32) /*client's request was invalid*/
|
||||
#define S_cas_invalidAsynchIO (M_cas | 33) /*inappropriate asynchronous IO type*/
|
||||
#define S_cas_posponeWhenNonePending (M_cas | 34) /*request postponement, none pending*/
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
@@ -392,16 +393,31 @@ public:
|
||||
// asynchronous IO operation (read or write) completes
|
||||
// against the PV.
|
||||
//
|
||||
// NOTE:
|
||||
// NOTES:
|
||||
// o The incoming GDD with application type "value" is always
|
||||
// converted to the PV.bestExternalType() primitive type.
|
||||
// o The time stamp in the incoming GDD is set to the time that
|
||||
// the last message was received from the client.
|
||||
// o Currently, no container type GDD's are passed here and
|
||||
// the application type is always "value". This may change.
|
||||
// o The write interface is called when the server receives
|
||||
// ca_put request and the writeNotify interface is called
|
||||
// when the server receives ca_put_callback request.
|
||||
// o A writeNotify request is considered complete and therefore
|
||||
// ready for asynchronous completion notification when any
|
||||
// action that it initiates, and any cascaded actions, complete.
|
||||
// o In an IOC context intermediate write requets can be discarded
|
||||
// as long as the final writeRequest is always executed. In an
|
||||
// IOC context intermediate writeNotify requests are never discarded.
|
||||
// o If the service does not implement writeNotify then
|
||||
// the base implementation of casPV :: writeNotify calls
|
||||
// casPV :: write thereby preserving backwards compatibility
|
||||
// with the original interface which included a virtual write
|
||||
// method but not a virtual writeNotify method.
|
||||
//
|
||||
epicsShareFunc virtual caStatus write (const casCtx &ctx, const gdd &value);
|
||||
|
||||
epicsShareFunc virtual caStatus writeNotify (const casCtx &ctx, const gdd &value);
|
||||
|
||||
//
|
||||
// chCreate() is called each time that a PV is attached to
|
||||
// by a client. The server tool may choose not to
|
||||
@@ -600,6 +616,14 @@ public:
|
||||
//
|
||||
epicsShareFunc virtual caStatus write (const casCtx &ctx, const gdd &value);
|
||||
|
||||
//
|
||||
// writeNotify
|
||||
//
|
||||
// If this function is not provided in the derived class then casPV::writeNotify()
|
||||
// is called - see casPV::writeNotify() for additional comments.
|
||||
//
|
||||
epicsShareFunc virtual caStatus writeNotify (const casCtx &ctx, const gdd &value);
|
||||
|
||||
//
|
||||
// This is called for each channel in the server if
|
||||
// caServer::show() is called and the level is high
|
||||
|
||||
@@ -51,12 +51,12 @@ inBuf::~inBuf ()
|
||||
//
|
||||
// inBuf::show()
|
||||
//
|
||||
void inBuf::show (unsigned level) const
|
||||
void inBuf :: show (unsigned level) const
|
||||
{
|
||||
if ( level > 1u ) {
|
||||
printf (
|
||||
"\tUnprocessed request bytes = %d\n",
|
||||
this->bytesAvailable());
|
||||
this->bytesPresent () );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,9 @@ inBufClient::fillCondition inBuf::fill ( inBufClient::fillParameter parm )
|
||||
// move back any prexisting data to the start of the buffer
|
||||
//
|
||||
if ( this->nextReadIndex > 0 ) {
|
||||
bufSizeT unprocessedBytes;
|
||||
unprocessedBytes = this->bytesInBuffer - this->nextReadIndex;
|
||||
assert ( this->bytesInBuffer >= this->nextReadIndex );
|
||||
bufSizeT unprocessedBytes =
|
||||
this->bytesInBuffer - this->nextReadIndex;
|
||||
//
|
||||
// memmove() handles overlapping buffers
|
||||
//
|
||||
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
// this is a hack for a Solaris IP kernel feature
|
||||
enum fillParameter { fpNone, fpUseBroadcastInterface };
|
||||
virtual unsigned getDebugLevel () const = 0;
|
||||
virtual bufSizeT incomingBytesPresent () const = 0;
|
||||
virtual fillCondition xRecv ( char *pBuf, bufSizeT nBytesToRecv,
|
||||
enum fillParameter parm, bufSizeT &nByesRecv ) = 0;
|
||||
virtual void hostName ( char *pBuf, unsigned bufSize ) const = 0;
|
||||
@@ -66,7 +65,6 @@ public:
|
||||
bufSizeT ioMinSizeIn );
|
||||
virtual ~inBuf ();
|
||||
bufSizeT bytesPresent () const;
|
||||
bufSizeT bytesAvailable () const;
|
||||
bool full () const;
|
||||
inBufClient::fillCondition fill (
|
||||
inBufClient::fillParameter parm = inBufClient::fpNone );
|
||||
@@ -107,17 +105,6 @@ inline bufSizeT inBuf::bytesPresent () const
|
||||
return this->bytesInBuffer - this->nextReadIndex;
|
||||
}
|
||||
|
||||
//
|
||||
// inBuf::bytesAvailable()
|
||||
//
|
||||
inline bufSizeT inBuf::bytesAvailable () const
|
||||
{
|
||||
bufSizeT bp;
|
||||
bp = this->bytesPresent ();
|
||||
bp += this->client.incomingBytesPresent ();
|
||||
return bp;
|
||||
}
|
||||
|
||||
//
|
||||
// inBuf::full()
|
||||
//
|
||||
|
||||
@@ -15,11 +15,19 @@
|
||||
*/
|
||||
|
||||
#include "errlog.h"
|
||||
#include "epicsTime.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "outBuf.h"
|
||||
#include "osiWireFormat.h"
|
||||
|
||||
const char * outBufClient :: ppFlushCondText[3] =
|
||||
{
|
||||
"flushNone",
|
||||
"flushProgress",
|
||||
"flushDisconnect"
|
||||
};
|
||||
|
||||
//
|
||||
// outBuf::outBuf()
|
||||
//
|
||||
@@ -62,11 +70,10 @@ caStatus outBuf::allocRawMsg ( bufSizeT msgsize, void **ppMsg )
|
||||
stackNeeded = this->bufSize - msgsize;
|
||||
|
||||
if ( this->stack > stackNeeded ) {
|
||||
|
||||
//
|
||||
// Try to flush the output queue
|
||||
//
|
||||
this->flush ( this->stack - stackNeeded );
|
||||
this->flush ();
|
||||
|
||||
//
|
||||
// If this failed then the fd is nonblocking
|
||||
@@ -216,45 +223,32 @@ void outBuf::commitMsg ( ca_uint32_t reducedPayloadSize )
|
||||
//
|
||||
// outBuf::flush ()
|
||||
//
|
||||
outBufClient::flushCondition outBuf::flush ( bufSizeT spaceRequired )
|
||||
outBufClient::flushCondition outBuf :: flush ()
|
||||
{
|
||||
bufSizeT nBytes;
|
||||
bufSizeT nBytesRequired;
|
||||
outBufClient::flushCondition cond;
|
||||
|
||||
if ( this->ctxRecursCount > 0 ) {
|
||||
return outBufClient::flushNone;
|
||||
}
|
||||
|
||||
if ( spaceRequired > this->bufSize ) {
|
||||
nBytesRequired = this->stack;
|
||||
}
|
||||
else {
|
||||
bufSizeT stackPermitted;
|
||||
|
||||
stackPermitted = this->bufSize - spaceRequired;
|
||||
if ( this->stack > stackPermitted ) {
|
||||
nBytesRequired = this->stack - stackPermitted;
|
||||
}
|
||||
else {
|
||||
nBytesRequired = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
cond = this->client.xSend ( this->pBuf, this->stack,
|
||||
nBytesRequired, nBytes );
|
||||
bufSizeT nBytesSent;
|
||||
//epicsTime beg = epicsTime::getCurrent ();
|
||||
outBufClient :: flushCondition cond =
|
||||
this->client.xSend ( this->pBuf, this->stack, nBytesSent );
|
||||
//epicsTime end = epicsTime::getCurrent ();
|
||||
//printf ( "send of %u bytes, stat =%s, cost us %f u sec\n",
|
||||
// this->stack, this->client.ppFlushCondText[cond], ( end - beg ) * 1e6 );
|
||||
if ( cond == outBufClient::flushProgress ) {
|
||||
bufSizeT len;
|
||||
|
||||
if ( nBytes >= this->stack ) {
|
||||
if ( nBytesSent >= this->stack ) {
|
||||
this->stack = 0u;
|
||||
}
|
||||
else {
|
||||
len = this->stack-nBytes;
|
||||
bufSizeT len = this->stack - nBytesSent;
|
||||
//
|
||||
// memmove() is ok with overlapping buffers
|
||||
//
|
||||
memmove ( this->pBuf, &this->pBuf[nBytes], len );
|
||||
//epicsTime beg = epicsTime::getCurrent ();
|
||||
memmove ( this->pBuf, &this->pBuf[nBytesSent], len );
|
||||
//epicsTime end = epicsTime::getCurrent ();
|
||||
//printf ( "mem move cost us %f nano sec\n", ( end - beg ) * 1e9 );
|
||||
this->stack = len;
|
||||
}
|
||||
|
||||
@@ -262,7 +256,7 @@ outBufClient::flushCondition outBuf::flush ( bufSizeT spaceRequired )
|
||||
char buf[64];
|
||||
this->client.hostName ( buf, sizeof ( buf ) );
|
||||
fprintf ( stderr, "CAS outgoing: %u byte reply to %s\n",
|
||||
nBytes, buf );
|
||||
nBytesSent, buf );
|
||||
}
|
||||
}
|
||||
return cond;
|
||||
|
||||
@@ -47,12 +47,18 @@ private:
|
||||
|
||||
class outBufClient { // X aCC 655
|
||||
public:
|
||||
enum flushCondition { flushNone, flushProgress, flushDisconnect };
|
||||
enum flushCondition {
|
||||
flushNone = 0,
|
||||
flushProgress = 1,
|
||||
flushDisconnect = 2
|
||||
};
|
||||
static const char * ppFlushCondText[3];
|
||||
virtual unsigned getDebugLevel () const = 0;
|
||||
virtual void sendBlockSignal () = 0;
|
||||
virtual flushCondition xSend ( char *pBuf, bufSizeT nBytesAvailableToSend,
|
||||
bufSizeT nBytesNeedToBeSent, bufSizeT &nBytesSent ) = 0;
|
||||
virtual flushCondition xSend ( char *pBuf, bufSizeT nBytesToSend,
|
||||
bufSizeT & nBytesSent ) = 0;
|
||||
virtual void hostName ( char *pBuf, unsigned bufSize ) const = 0;
|
||||
virtual bufSizeT osSendBufferSize () const = 0;
|
||||
protected:
|
||||
virtual ~outBufClient() {}
|
||||
};
|
||||
@@ -72,7 +78,7 @@ public:
|
||||
// flush output queue
|
||||
// (returns the number of bytes sent)
|
||||
//
|
||||
outBufClient::flushCondition flush ( bufSizeT spaceRequired=bufSizeT_MAX );
|
||||
outBufClient::flushCondition flush ();
|
||||
|
||||
void show (unsigned level) const;
|
||||
|
||||
@@ -128,13 +134,7 @@ private:
|
||||
//
|
||||
inline bufSizeT outBuf::bytesPresent () const
|
||||
{
|
||||
//
|
||||
// Note on use of lock here:
|
||||
// This guarantees that any pushCtx() operation
|
||||
// in progress completes before another thread checks.
|
||||
//
|
||||
bufSizeT result = this->stack;
|
||||
return result;
|
||||
return this->stack;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// $Id$
|
||||
//
|
||||
|
||||
|
||||
#include "fdManager.h"
|
||||
#include "errlog.h"
|
||||
|
||||
@@ -27,7 +26,6 @@ public:
|
||||
casDGReadReg ( casDGIntfOS & osIn ) :
|
||||
fdReg (osIn.getFD(), fdrRead), os (osIn) {}
|
||||
~casDGReadReg ();
|
||||
|
||||
void show (unsigned level) const;
|
||||
private:
|
||||
casDGIntfOS &os;
|
||||
@@ -81,8 +79,7 @@ casDGIntfOS::casDGIntfOS (
|
||||
autoBeaconAddr, addConfigBeaconAddr ),
|
||||
pRdReg ( 0 ),
|
||||
pBCastRdReg ( 0 ),
|
||||
pWtReg ( 0 ),
|
||||
sendBlocked ( false )
|
||||
pWtReg ( 0 )
|
||||
{
|
||||
this->xSetNonBlocking();
|
||||
this->armRecv();
|
||||
@@ -140,10 +137,18 @@ void casDGEvWakeup::show ( unsigned level ) const
|
||||
//
|
||||
epicsTimerNotify::expireStatus casDGEvWakeup::expire ( const epicsTime & /* currentTime */ )
|
||||
{
|
||||
casEventSys::processStatus ps = this->pOS->eventSysProcess ();
|
||||
if ( ps.nAccepted > 0u ) {
|
||||
this->pOS->eventFlush ();
|
||||
}
|
||||
this->pOS->eventSysProcess ();
|
||||
// We do not wait for any impartial, or complete,
|
||||
// messages in the input queue to be processed
|
||||
// because.
|
||||
// A) IO postponement might be preventing the
|
||||
// input queue processing from proceeding.
|
||||
// B) Since both reads and events get processed
|
||||
// before going back to select to find out if we
|
||||
// can do a write then we naturally tend to
|
||||
// combine get responses and subscription responses
|
||||
// into one write.
|
||||
this->pOS->armSend ();
|
||||
this->pOS = 0;
|
||||
return noRestart;
|
||||
}
|
||||
@@ -168,21 +173,22 @@ casDGIOWakeup::~casDGIOWakeup()
|
||||
// casDGIOWakeup::expire()
|
||||
//
|
||||
// Running this indirectly off of the timer queue
|
||||
// guarantees that we will not call processInput()
|
||||
// guarantees that we will not call processDG()
|
||||
// recursively
|
||||
//
|
||||
epicsTimerNotify::expireStatus casDGIOWakeup::expire( const epicsTime & /* currentTime */ )
|
||||
epicsTimerNotify :: expireStatus
|
||||
casDGIOWakeup :: expire( const epicsTime & /* currentTime */ )
|
||||
{
|
||||
//
|
||||
// in case there is something in the input buffer
|
||||
// and currently nothing to be read from UDP
|
||||
//
|
||||
// processInput() does an armRecv() so
|
||||
// if recv is not armed, there is space in
|
||||
// the input buffer, and there eventually will
|
||||
// be something to read from TCP this works
|
||||
//
|
||||
this->pOS->processInput ();
|
||||
caStatus status = this->pOS->processDG ();
|
||||
if ( status != S_cas_success &&
|
||||
status != S_cas_sendBlocked ) {
|
||||
char pName[64u];
|
||||
this->pOS->hostName (pName, sizeof (pName));
|
||||
errPrintf (status, __FILE__, __LINE__,
|
||||
"unexpected problem with UDP input from \"%s\"", pName);
|
||||
}
|
||||
this->pOS->armRecv ();
|
||||
this->pOS->armSend ();
|
||||
this->pOS = 0;
|
||||
return noRestart;
|
||||
}
|
||||
@@ -243,7 +249,7 @@ void casDGIntfOS::disarmRecv()
|
||||
//
|
||||
void casDGIntfOS::armSend()
|
||||
{
|
||||
if ( this->outBufBytesPresent () == 0u ) {
|
||||
if ( this->outBufBytesPending () == 0u ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -277,20 +283,6 @@ void casDGIntfOS::eventSignal()
|
||||
this->evWk.start ( *this );
|
||||
}
|
||||
|
||||
//
|
||||
// casDGIntfOS::eventFlush()
|
||||
//
|
||||
void casDGIntfOS::eventFlush()
|
||||
{
|
||||
//
|
||||
// if there is nothing pending in the input
|
||||
// queue, then flush the output queue
|
||||
//
|
||||
if ( this->inBufBytesAvailable() == 0u ) {
|
||||
this->armSend ();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// casDGIntfOS::show()
|
||||
//
|
||||
@@ -396,7 +388,6 @@ void casDGWriteReg::show(unsigned level) const
|
||||
//
|
||||
void casDGIntfOS::sendBlockSignal()
|
||||
{
|
||||
this->sendBlocked = true;
|
||||
this->armSend();
|
||||
}
|
||||
|
||||
@@ -412,47 +403,53 @@ void casDGIntfOS::sendCB()
|
||||
// attempt to flush the output buffer
|
||||
//
|
||||
outBufClient::flushCondition flushCond = this->flush ();
|
||||
if ( flushCond != flushProgress ) {
|
||||
return;
|
||||
}
|
||||
if ( flushCond == flushProgress ) {
|
||||
//
|
||||
// If we are unable to flush out all of the events
|
||||
// in casDgEvWakeup::expire() because the
|
||||
// client is slow then we must check again here when
|
||||
// we _are_ able to write to see if additional events
|
||||
// can be sent to the slow client.
|
||||
//
|
||||
this->eventSysProcess ();
|
||||
|
||||
if ( this->sendBlocked ) {
|
||||
this->sendBlocked = false;
|
||||
}
|
||||
//
|
||||
// If we were able to send something then we need
|
||||
// to process the input queue in case we were send
|
||||
// blocked.
|
||||
//
|
||||
caStatus status = this->processDG ();
|
||||
if ( status != S_cas_success &&
|
||||
status != S_cas_sendBlocked ) {
|
||||
char pName[64u];
|
||||
this->hostName (pName, sizeof (pName));
|
||||
errPrintf ( status, __FILE__, __LINE__,
|
||||
"unexpected problem with UDP input from \"%s\"", pName);
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(DEBUG)
|
||||
printf ("write attempted on %d result was %d\n", this->getFD(), flushCond);
|
||||
printf ("write attempted on %d result was %d\n", this->getFD(), flushCond );
|
||||
printf ("Recv backlog %u\n", this->inBuf::bytesPresent());
|
||||
printf ("Send backlog %u\n", this->outBuf::bytesPresent());
|
||||
# endif
|
||||
|
||||
//
|
||||
// If we are unable to flush out all of the events
|
||||
// in casDgEvWakeup::expire() because the
|
||||
// client is slow then we must check again here when
|
||||
// we _are_ able to write to see if additional events
|
||||
// can be sent to the slow client.
|
||||
//
|
||||
this->eventSysProcess ();
|
||||
|
||||
//
|
||||
// If we were able to send something then we need
|
||||
// to process the input queue in case we were send
|
||||
// blocked.
|
||||
//
|
||||
this->processInput ();
|
||||
|
||||
//
|
||||
// this reenables receipt of incoming frames once
|
||||
// the output has been flushed
|
||||
// the output has been flushed in case the receive
|
||||
// side is blocked due to lack of buffer space
|
||||
//
|
||||
this->armRecv ();
|
||||
|
||||
|
||||
// once we start sending we continue until done
|
||||
this->armSend ();
|
||||
}
|
||||
|
||||
//
|
||||
// casDGIntfOS::recvCB()
|
||||
//
|
||||
void casDGIntfOS::recvCB ( inBufClient::fillParameter parm )
|
||||
void casDGIntfOS :: recvCB ( inBufClient::fillParameter parm )
|
||||
{
|
||||
assert ( this->pRdReg );
|
||||
|
||||
@@ -460,7 +457,16 @@ void casDGIntfOS::recvCB ( inBufClient::fillParameter parm )
|
||||
// copy in new messages
|
||||
//
|
||||
this->inBufFill ( parm );
|
||||
this->processInput ();
|
||||
caStatus status = this->processDG ();
|
||||
if ( status != S_cas_success &&
|
||||
status != S_cas_sendBlocked ) {
|
||||
char pName[64u];
|
||||
this->hostName (pName, sizeof (pName));
|
||||
errPrintf (status, __FILE__, __LINE__,
|
||||
"unexpected problem with UDP input from \"%s\"", pName);
|
||||
}
|
||||
|
||||
this->armSend ();
|
||||
|
||||
//
|
||||
// If there isnt any space then temporarily
|
||||
@@ -477,38 +483,3 @@ void casDGIntfOS::recvCB ( inBufClient::fillParameter parm )
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// casDGIntfOS::processInput()
|
||||
//
|
||||
void casDGIntfOS::processInput()
|
||||
{
|
||||
caStatus status;
|
||||
|
||||
//
|
||||
// attempt to process the datagram in the input
|
||||
// buffer
|
||||
//
|
||||
status = this->processDG ();
|
||||
if (status!=S_cas_success &&
|
||||
status!=S_cas_sendBlocked &&
|
||||
status!=S_casApp_postponeAsyncIO) {
|
||||
char pName[64u];
|
||||
|
||||
this->hostName (pName, sizeof (pName));
|
||||
errPrintf (status, __FILE__, __LINE__,
|
||||
"unexpected problem with UDP input from \"%s\"", pName);
|
||||
}
|
||||
|
||||
//
|
||||
// if anything is in the send buffer
|
||||
// and there are not requests pending in the
|
||||
// input buffer then keep sending the output
|
||||
// buffer until it is empty
|
||||
//
|
||||
if ( this->outBufBytesPresent() > 0u ) {
|
||||
if ( this->inBufBytesAvailable () == 0 ) {
|
||||
this->armSend ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,26 +23,21 @@ class casDGIntfOS : public casDGIntfIO {
|
||||
friend class casDGReadReg;
|
||||
friend class casDGBCastReadReg;
|
||||
friend class casDGWriteReg;
|
||||
friend class casDGEvWakeup;
|
||||
friend class casDGIOWakeup;
|
||||
friend class casStreamEvWakeup;
|
||||
public:
|
||||
casDGIntfOS ( caServerI &, clientBufMemoryManager &,
|
||||
const caNetAddr & addr, bool autoBeaconAddr = true,
|
||||
bool addConfigBeaconAddr = false);
|
||||
|
||||
virtual ~casDGIntfOS ();
|
||||
|
||||
virtual void show (unsigned level) const;
|
||||
|
||||
void processInput();
|
||||
|
||||
void eventFlush ();
|
||||
|
||||
private:
|
||||
casDGIOWakeup ioWk;
|
||||
casDGEvWakeup evWk;
|
||||
class casDGReadReg * pRdReg;
|
||||
class casDGBCastReadReg * pBCastRdReg; // fix for solaris bug
|
||||
class casDGWriteReg * pWtReg;
|
||||
bool sendBlocked;
|
||||
|
||||
void armRecv ();
|
||||
void armSend ();
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
// casStreamOS.cc
|
||||
// $Id$
|
||||
//
|
||||
//
|
||||
//
|
||||
// TO DO:
|
||||
// o armRecv() and armSend() should return bad status when
|
||||
// there isnt enough memory
|
||||
@@ -23,6 +21,34 @@
|
||||
#define epicsExportSharedFunc
|
||||
#include "casStreamOS.h"
|
||||
|
||||
#if 0
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
//
|
||||
// printStatus ()
|
||||
//
|
||||
#if defined(DEBUG)
|
||||
void casStreamOS :: printStatus ( const char * pCtx ) const
|
||||
{
|
||||
static epicsTime beginTime = epicsTime :: getCurrent ();
|
||||
epicsTime current = epicsTime :: getCurrent ();
|
||||
printf (
|
||||
"%03.3f, "
|
||||
"Sock %d, %s, "
|
||||
"RecvBuf %u, "
|
||||
"SendBuf %u\n",
|
||||
current - beginTime,
|
||||
this->getFD(),
|
||||
pCtx,
|
||||
this->inBufBytesPending (),
|
||||
this->outBufBytesPending () );
|
||||
fflush ( stdout );
|
||||
}
|
||||
#else
|
||||
inline void casStreamOS :: printStatus ( const char * ) const {}
|
||||
#endif
|
||||
|
||||
//
|
||||
// casStreamReadReg
|
||||
//
|
||||
@@ -44,13 +70,7 @@ private:
|
||||
inline casStreamReadReg::casStreamReadReg (casStreamOS &osIn) :
|
||||
fdReg (osIn.getFD(), fdrRead), os (osIn)
|
||||
{
|
||||
# if defined(DEBUG)
|
||||
printf ("Read on %d\n", this->os.getFD());
|
||||
printf ("Recv backlog %u\n",
|
||||
this->os.in.bytesPresent());
|
||||
printf ("Send backlog %u\n",
|
||||
this->os.out.bytesPresent());
|
||||
# endif
|
||||
this->os.printStatus ( "read schedualed" );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -58,13 +78,7 @@ inline casStreamReadReg::casStreamReadReg (casStreamOS &osIn) :
|
||||
//
|
||||
inline casStreamReadReg::~casStreamReadReg ()
|
||||
{
|
||||
# if defined(DEBUG)
|
||||
printf ("Read off %d\n", this->os.getFD());
|
||||
printf ("Recv backlog %u\n",
|
||||
this->os.in.bytesPresent());
|
||||
printf ("Send backlog %u\n",
|
||||
this->os.out.bytesPresent());
|
||||
# endif
|
||||
this->os.printStatus ( "read unschedualed" );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -89,13 +103,7 @@ private:
|
||||
inline casStreamWriteReg::casStreamWriteReg (casStreamOS &osIn) :
|
||||
fdReg (osIn.getFD(), fdrWrite, true), os (osIn)
|
||||
{
|
||||
# if defined(DEBUG)
|
||||
printf ("Write on %d\n", this->os.getFD());
|
||||
printf ("Recv backlog %u\n",
|
||||
this->os.in.bytesPresent());
|
||||
printf ("Send backlog %u\n",
|
||||
this->os.out.bytesPresent());
|
||||
# endif
|
||||
this->os.printStatus ( "write schedualed" );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -103,13 +111,7 @@ inline casStreamWriteReg::casStreamWriteReg (casStreamOS &osIn) :
|
||||
//
|
||||
inline casStreamWriteReg::~casStreamWriteReg ()
|
||||
{
|
||||
# if defined(DEBUG)
|
||||
printf ("Write off %d\n", this->os.getFD());
|
||||
printf ("Recv backlog %u\n",
|
||||
this->os.in.bytesPresent());
|
||||
printf ("Send backlog %u\n",
|
||||
this->os.out.bytesPresent());
|
||||
# endif
|
||||
this->os.printStatus ( "write unschedualed" );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -142,13 +144,31 @@ void casStreamEvWakeup::show(unsigned level) const
|
||||
//
|
||||
// casStreamEvWakeup::expire()
|
||||
//
|
||||
epicsTimerNotify::expireStatus casStreamEvWakeup::expire ( const epicsTime & /* currentTime */ )
|
||||
epicsTimerNotify::expireStatus casStreamEvWakeup::
|
||||
expire ( const epicsTime & /* currentTime */ )
|
||||
{
|
||||
casEventSys::processStatus ps = os.eventSysProcess ();
|
||||
if ( ps.nAccepted > 0u ) {
|
||||
this->os.eventFlush ();
|
||||
this->os.printStatus ( "casStreamEvWakeup tmr expire" );
|
||||
casProcCond pc = os.eventSysProcess ();
|
||||
if ( pc == casProcOk ) {
|
||||
// We do not wait for any impartial, or complete,
|
||||
// messages in the input queue to be processed
|
||||
// because.
|
||||
// A) IO postponement might be preventing the
|
||||
// input queue processing from proceeding.
|
||||
// B) We dont want to interrupt subscription
|
||||
// updates while waiting for very large arrays
|
||||
// to be read in a packet at a time.
|
||||
// C) Since both reads and events get processed
|
||||
// before going back to select to find out if we
|
||||
// can do a write then we naturally tend to
|
||||
// combine get responses and subscription responses
|
||||
// into one write.
|
||||
// D) Its probably questionable to hold up event
|
||||
// traffic (introduce latency) because a partial
|
||||
// message is pending in the input queue.
|
||||
this->os.armSend ();
|
||||
}
|
||||
if ( ps.cond != casProcOk ) {
|
||||
else {
|
||||
//
|
||||
// ok to delete the client here
|
||||
// because casStreamEvWakeup::expire()
|
||||
@@ -170,14 +190,16 @@ epicsTimerNotify::expireStatus casStreamEvWakeup::expire ( const epicsTime & /*
|
||||
//
|
||||
// casStreamEvWakeup::start()
|
||||
//
|
||||
// care is needed here because this is called
|
||||
// asynchronously by postEvent
|
||||
//
|
||||
// there is some overhead here but care is taken
|
||||
// in the caller of this routine to call this
|
||||
// only when its the 2nd event on the queue
|
||||
//
|
||||
void casStreamEvWakeup::start( casStreamOS & )
|
||||
{
|
||||
// care is needed here because this is called
|
||||
// asynchronously by postEvent
|
||||
//
|
||||
// there is some overhead here but care is taken
|
||||
// in the caller of this routine to call this
|
||||
// only when its the 2nd event on the queue
|
||||
this->os.printStatus ( "casStreamEvWakeup tmr start" );
|
||||
this->timer.start ( *this, 0.0 );
|
||||
}
|
||||
|
||||
@@ -211,16 +233,52 @@ void casStreamIOWakeup::show ( unsigned level ) const
|
||||
//
|
||||
// casStreamIOWakeup::expire()
|
||||
//
|
||||
// This is called whenever asynchronous IO completes
|
||||
//
|
||||
// Running this indirectly off of the timer queue
|
||||
// guarantees that we will not call processInput()
|
||||
// guarantees that we will not call processMsg()
|
||||
// recursively
|
||||
//
|
||||
epicsTimerNotify::expireStatus casStreamIOWakeup::expire ( const epicsTime & /* currentTime */ )
|
||||
epicsTimerNotify::expireStatus casStreamIOWakeup ::
|
||||
expire ( const epicsTime & /* currentTime */ )
|
||||
{
|
||||
assert ( this->pOS );
|
||||
this->pOS->printStatus ( "casStreamIOWakeup tmr expire" );
|
||||
casStreamOS & tmpOS = *this->pOS;
|
||||
this->pOS = 0;
|
||||
tmpOS.processInput();
|
||||
caStatus status = tmpOS.processMsg ();
|
||||
if ( status == S_cas_success ) {
|
||||
tmpOS.armRecv ();
|
||||
if ( tmpOS._sendNeeded () ) {
|
||||
tmpOS.armSend ();
|
||||
}
|
||||
}
|
||||
else if ( status == S_cas_sendBlocked ) {
|
||||
tmpOS.armSend ();
|
||||
// always activate receives if space is available
|
||||
// in the in buf
|
||||
tmpOS.armRecv ();
|
||||
}
|
||||
else if ( status == S_casApp_postponeAsyncIO ) {
|
||||
// we should be back on the IO blocked list
|
||||
// if S_casApp_postponeAsyncIO was returned
|
||||
// so this function will be called again when
|
||||
// another asynchronous request completes
|
||||
tmpOS.armSend ();
|
||||
// always activate receives if space is available
|
||||
// in the in buf
|
||||
tmpOS.armRecv ();
|
||||
}
|
||||
else {
|
||||
errMessage ( status,
|
||||
"- unexpected problem with client's input - forcing disconnect");
|
||||
tmpOS.getCAS().destroyClient ( tmpOS );
|
||||
//
|
||||
// must _not_ touch "tmpOS" ref
|
||||
// after the destroy
|
||||
//
|
||||
return noRestart;
|
||||
}
|
||||
return noRestart;
|
||||
}
|
||||
|
||||
@@ -236,6 +294,7 @@ void casStreamIOWakeup::start ( casStreamOS &os )
|
||||
this->pOS = &os;
|
||||
this->timer.start ( *this, 0.0 );
|
||||
}
|
||||
this->pOS->printStatus ( "casStreamIOWakeup tmr start" );
|
||||
}
|
||||
|
||||
//
|
||||
@@ -264,7 +323,7 @@ inline void casStreamOS::disarmRecv ()
|
||||
//
|
||||
inline void casStreamOS::armSend()
|
||||
{
|
||||
if ( this->outBufBytesPresent() == 0u ) {
|
||||
if ( this->outBufBytesPending() == 0u ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -284,6 +343,7 @@ inline void casStreamOS::disarmSend ()
|
||||
|
||||
//
|
||||
// casStreamOS::ioBlockedSignal()
|
||||
// (called by main thread when lock is applied)
|
||||
//
|
||||
void casStreamOS::ioBlockedSignal()
|
||||
{
|
||||
@@ -292,26 +352,14 @@ void casStreamOS::ioBlockedSignal()
|
||||
|
||||
//
|
||||
// casStreamOS::eventSignal()
|
||||
// (called by any thread asynchronously
|
||||
// when an event is posted)
|
||||
//
|
||||
void casStreamOS::eventSignal()
|
||||
{
|
||||
this->evWk.start ( *this );
|
||||
}
|
||||
|
||||
//
|
||||
// casStreamOS::eventFlush()
|
||||
//
|
||||
void casStreamOS::eventFlush()
|
||||
{
|
||||
//
|
||||
// if there is nothing pending in the input
|
||||
// queue, then flush the output queue
|
||||
//
|
||||
if ( this->inBufBytesAvailable() == 0u ) {
|
||||
this->armSend ();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// casStreamOS::casStreamOS()
|
||||
//
|
||||
@@ -319,9 +367,14 @@ casStreamOS::casStreamOS (
|
||||
caServerI & cas, clientBufMemoryManager & bufMgrIn,
|
||||
const ioArgsToNewStreamIO & ioArgs ) :
|
||||
casStreamIO ( cas, bufMgrIn, ioArgs ),
|
||||
evWk ( *this ), pWtReg ( 0 ), pRdReg ( 0 ),
|
||||
sendBlocked ( false )
|
||||
evWk ( *this ),
|
||||
pWtReg ( 0 ),
|
||||
pRdReg ( 0 ),
|
||||
_sendBacklogThresh ( osSendBufferSize () / 2u )
|
||||
{
|
||||
if ( _sendBacklogThresh < MAX_TCP / 2 ) {
|
||||
_sendBacklogThresh = MAX_TCP / 2;
|
||||
}
|
||||
this->xSetNonBlocking ();
|
||||
this->armRecv ();
|
||||
}
|
||||
@@ -348,7 +401,6 @@ void casStreamOS::show ( unsigned level ) const
|
||||
this->casStrmClient::show ( level );
|
||||
printf ( "casStreamOS at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
printf ( "\tsendBlocked = %d\n", this->sendBlocked );
|
||||
if ( this->pWtReg ) {
|
||||
this->pWtReg->show ( level );
|
||||
}
|
||||
@@ -384,9 +436,11 @@ void casStreamReadReg::callBack ()
|
||||
//
|
||||
// casStreamOS::recvCB()
|
||||
//
|
||||
void casStreamOS::recvCB ()
|
||||
void casStreamOS :: recvCB ()
|
||||
{
|
||||
assert ( this->pRdReg );
|
||||
|
||||
printStatus ( "receiving" );
|
||||
|
||||
//
|
||||
// copy in new messages
|
||||
@@ -394,38 +448,50 @@ void casStreamOS::recvCB ()
|
||||
inBufClient::fillCondition fillCond = this->inBufFill ();
|
||||
if ( fillCond == casFillDisconnect ) {
|
||||
this->getCAS().destroyClient ( *this );
|
||||
//
|
||||
// must _not_ touch "this" pointer
|
||||
// after the destroy
|
||||
//
|
||||
return;
|
||||
}
|
||||
else {
|
||||
casProcCond procCond = this->processInput ();
|
||||
if ( procCond == casProcDisconnect ) {
|
||||
this->getCAS().destroyClient ( *this );
|
||||
}
|
||||
else if ( this->inBufFull() ) {
|
||||
//
|
||||
// If there isnt any space then temporarily
|
||||
// stop calling this routine until problem is resolved
|
||||
// either by:
|
||||
// (1) sending or
|
||||
// (2) a blocked IO op unblocks
|
||||
//
|
||||
// (casStreamReadReg is _not_ a onceOnly fdReg -
|
||||
// therefore an explicit delete is required here)
|
||||
//
|
||||
this->disarmRecv (); // this deletes the casStreamReadReg object
|
||||
}
|
||||
else if ( fillCond == casFillNone ) {
|
||||
if ( this->inBufFull() ) {
|
||||
this->disarmRecv ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
printStatus ( "recv CB req proc" );
|
||||
caStatus status = this->processMsg ();
|
||||
if ( status == S_cas_success ) {
|
||||
this->armRecv ();
|
||||
if ( _sendNeeded () ) {
|
||||
this->armSend ();
|
||||
}
|
||||
}
|
||||
else if ( status == S_cas_sendBlocked ) {
|
||||
this->armSend ();
|
||||
}
|
||||
else if ( status == S_casApp_postponeAsyncIO ) {
|
||||
this->armSend ();
|
||||
}
|
||||
else {
|
||||
errMessage ( status,
|
||||
"- unexpected problem with client's input - forcing disconnect");
|
||||
this->getCAS().destroyClient ( *this );
|
||||
//
|
||||
// must _not_ touch "this" pointer
|
||||
// after the destroy
|
||||
//
|
||||
return;
|
||||
}
|
||||
}
|
||||
//
|
||||
// NO CODE HERE
|
||||
// (see delete above)
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
// casStreamOS::sendBlockSignal()
|
||||
// casStreamOS :: sendBlockSignal()
|
||||
//
|
||||
void casStreamOS::sendBlockSignal ()
|
||||
void casStreamOS :: sendBlockSignal ()
|
||||
{
|
||||
this->sendBlocked = true;
|
||||
this->armSend ();
|
||||
}
|
||||
|
||||
@@ -456,18 +522,21 @@ void casStreamWriteReg::callBack()
|
||||
//
|
||||
void casStreamOS::sendCB ()
|
||||
{
|
||||
// we know that the fdManager will destroy the write
|
||||
// registration after this function returns, and that
|
||||
// it is robust in situations where the callback
|
||||
// deletes its fdReg derived object so delete it now,
|
||||
// because we can now reschedule a send as needed
|
||||
//
|
||||
this->disarmSend ();
|
||||
|
||||
printStatus ( "writing" );
|
||||
|
||||
//
|
||||
// attempt to flush the output buffer
|
||||
//
|
||||
outBufClient::flushCondition flushCond = this->flush ();
|
||||
if ( flushCond == flushProgress ) {
|
||||
if ( this->sendBlocked ) {
|
||||
this->sendBlocked = false;
|
||||
}
|
||||
}
|
||||
else if ( flushCond == outBufClient::flushDisconnect ) {
|
||||
if ( flushCond == outBufClient::flushDisconnect ) {
|
||||
//
|
||||
// ok to delete the client here
|
||||
// because casStreamWriteReg::callBack()
|
||||
@@ -491,8 +560,8 @@ void casStreamOS::sendCB ()
|
||||
// we _are_ able to write to see if additional events
|
||||
// can be sent to the slow client.
|
||||
//
|
||||
casEventSys::processStatus ps = this->eventSysProcess ();
|
||||
if ( ps.cond != casProcOk ) {
|
||||
casProcCond pc = this->eventSysProcess ();
|
||||
if ( pc != casProcOk ) {
|
||||
//
|
||||
// ok to delete the client here
|
||||
// because casStreamWriteReg::callBack()
|
||||
@@ -508,80 +577,57 @@ void casStreamOS::sendCB ()
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
# if defined(DEBUG)
|
||||
printf ( "write attempted on %d result was %d\n",
|
||||
this->getFD(), flushCond );
|
||||
printf ( "Recv backlog %u\n", this->in.bytesPresent() );
|
||||
printf ( "Send backlog %u\n", this->out.bytesPresent() );
|
||||
# endif
|
||||
|
||||
printStatus ( ppFlushCondText [ flushCond ] );
|
||||
|
||||
//
|
||||
// If we were able to send something then we need
|
||||
// to process the input queue in case we were send
|
||||
// blocked.
|
||||
//
|
||||
casProcCond procCond = this->processInput ();
|
||||
if ( procCond == casProcDisconnect ) {
|
||||
this->getCAS().destroyClient ( *this );
|
||||
}
|
||||
else {
|
||||
//
|
||||
// if anything is left in the send buffer that
|
||||
// still needs to be sent and there are not
|
||||
// requests pending in the input buffer then
|
||||
// keep sending the output buffer until it is
|
||||
// empty
|
||||
//
|
||||
// do not test for this with flushCond since
|
||||
// additional bytes may have been added since
|
||||
// we flushed the out buffer
|
||||
//
|
||||
if ( this->outBufBytesPresent() > 0u &&
|
||||
this->inBufBytesAvailable() == 0u ) {
|
||||
this->armSend();
|
||||
}
|
||||
}
|
||||
//
|
||||
// NO CODE HERE
|
||||
// (see deletes above)
|
||||
//
|
||||
|
||||
bufSizeT inBufBytesPend = this->inBufBytesPending ();
|
||||
if ( flushCond == flushProgress && inBufBytesPend ) {
|
||||
printStatus ( "send CB req proc" );
|
||||
caStatus status = this->processMsg ();
|
||||
if ( status == S_cas_success ) {
|
||||
this->armRecv ();
|
||||
}
|
||||
else if ( status == S_cas_sendBlocked
|
||||
|| status == S_casApp_postponeAsyncIO ) {
|
||||
bufSizeT inBufBytesPendNew = this->inBufBytesPending ();
|
||||
if ( inBufBytesPendNew < inBufBytesPend ) {
|
||||
this->armRecv ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMessage ( status,
|
||||
"- unexpected problem with client's input - forcing disconnect");
|
||||
this->getCAS().destroyClient ( *this );
|
||||
//
|
||||
// must _not_ touch "this" pointer
|
||||
// after the destroy
|
||||
//
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Once a send starts we will keep going with it until
|
||||
// it flushes all of the way out. Its important to
|
||||
// perform this step only after processMsg so that we
|
||||
// flush out any send blocks detected by processMsg.
|
||||
this->armSend ();
|
||||
}
|
||||
|
||||
//
|
||||
// casStreamOS::processInput()
|
||||
// casStreamOS :: sendNeeded ()
|
||||
//
|
||||
casProcCond casStreamOS::processInput() // X aCC 361
|
||||
bool casStreamOS ::
|
||||
_sendNeeded () const
|
||||
{
|
||||
caStatus status;
|
||||
|
||||
# ifdef DEBUG
|
||||
printf(
|
||||
"Resp bytes to send=%d, Req bytes pending %d\n",
|
||||
this->out.bytesPresent(),
|
||||
this->in.bytesPresent());
|
||||
# endif
|
||||
|
||||
status = this->processMsg();
|
||||
if (status==S_cas_success ||
|
||||
status==S_cas_sendBlocked ||
|
||||
status==S_casApp_postponeAsyncIO) {
|
||||
|
||||
//
|
||||
// if there is nothing pending in the input
|
||||
// queue, then flush the output queue
|
||||
//
|
||||
if ( this->inBufBytesAvailable() == 0u ) {
|
||||
this->armSend ();
|
||||
}
|
||||
this->armRecv ();
|
||||
|
||||
return casProcOk;
|
||||
}
|
||||
else {
|
||||
errMessage ( status,
|
||||
"- unexpected problem with client's input - forcing disconnect");
|
||||
return casProcDisconnect;
|
||||
}
|
||||
}
|
||||
bool sn = this->outBufBytesPending() >= this->_sendBacklogThresh;
|
||||
bufSizeT inBytesPending = this->inBufBytesPending ();
|
||||
return sn || ( inBytesPending == 0u );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,14 +66,13 @@ public:
|
||||
const ioArgsToNewStreamIO & );
|
||||
~casStreamOS ();
|
||||
void show ( unsigned level ) const;
|
||||
casProcCond processInput ();
|
||||
void eventFlush ();
|
||||
void printStatus ( const char * pCtx ) const;
|
||||
private:
|
||||
casStreamEvWakeup evWk;
|
||||
casStreamIOWakeup ioWk;
|
||||
class casStreamWriteReg * pWtReg;
|
||||
class casStreamReadReg * pRdReg;
|
||||
bool sendBlocked;
|
||||
bufSizeT _sendBacklogThresh;
|
||||
void armSend ();
|
||||
void armRecv ();
|
||||
void disarmSend();
|
||||
@@ -83,10 +82,13 @@ private:
|
||||
void sendBlockSignal ();
|
||||
void ioBlockedSignal ();
|
||||
void eventSignal ();
|
||||
bool _sendNeeded () const;
|
||||
casStreamOS ( const casStreamOS & );
|
||||
casStreamOS & operator = ( const casStreamOS & );
|
||||
friend class casStreamWriteReg;
|
||||
friend class casStreamReadReg;
|
||||
friend class casStreamIOWakeup;
|
||||
friend class casStreamEvWakeup;
|
||||
};
|
||||
|
||||
#endif // casStreamOSh
|
||||
|
||||
@@ -181,7 +181,7 @@ casDGIntfIO::casDGIntfIO ( caServerI & serverIn, clientBufMemoryManager & memMgr
|
||||
removeDuplicateAddresses ( & filtered, & parsed, true );
|
||||
|
||||
while ( ELLNODE * pRawNode = ellGet ( & filtered ) ) {
|
||||
assert ( offsetof (osiSockAddrNode, node) == 0 );
|
||||
STATIC_ASSERT ( offsetof (osiSockAddrNode, node) == 0 );
|
||||
osiSockAddrNode * pNode = reinterpret_cast < osiSockAddrNode * > ( pRawNode );
|
||||
if ( pNode->addr.sa.sa_family == AF_INET ) {
|
||||
ipIgnoreEntry * pIPI = new ( this->ipIgnoreEntryFreeList )
|
||||
@@ -394,13 +394,14 @@ casDGIntfIO::osdSend ( const char * pBufIn, bufSizeT size, // X aCC 361
|
||||
return outBufClient::flushNone;
|
||||
}
|
||||
}
|
||||
|
||||
bufSizeT casDGIntfIO::incomingBytesPresent () const // X aCC 361
|
||||
|
||||
bufSizeT casDGIntfIO ::
|
||||
dgInBytesPending () const
|
||||
{
|
||||
int status;
|
||||
osiSockIoctl_t nchars = 0;
|
||||
|
||||
status = socket_ioctl ( this->sock, FIONREAD, & nchars ); // X aCC 392
|
||||
status = socket_ioctl ( this->sock, FIONREAD, & nchars );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
@@ -500,38 +501,21 @@ bufSizeT casDGIntfIO::optimumInBufferSize ()
|
||||
#endif
|
||||
}
|
||||
|
||||
bufSizeT casDGIntfIO::optimumOutBufferSize ()
|
||||
bufSizeT casDGIntfIO ::
|
||||
osSendBufferSize () const
|
||||
{
|
||||
|
||||
#if 1
|
||||
//
|
||||
// must update client before the message size can be
|
||||
// increased here
|
||||
//
|
||||
return MAX_UDP_SEND;
|
||||
#else
|
||||
int n;
|
||||
int size;
|
||||
int status;
|
||||
|
||||
|
||||
/* fetch the TCP send buffer size */
|
||||
n = sizeof(size);
|
||||
status = getsockopt(
|
||||
this->sock,
|
||||
SOL_SOCKET,
|
||||
SO_SNDBUF,
|
||||
(char *)&size,
|
||||
&n);
|
||||
if(status < 0 || n != sizeof(size)){
|
||||
int size = MAX_UDP_SEND;
|
||||
osiSocklen_t n = sizeof ( size );
|
||||
int status = getsockopt( this->sock, SOL_SOCKET, SO_SNDBUF,
|
||||
reinterpret_cast < char * > ( & size ), & n );
|
||||
if ( status < 0 || n != sizeof(size) ) {
|
||||
size = MAX_UDP_SEND;
|
||||
}
|
||||
|
||||
if (size<=0) {
|
||||
if ( size <= MAX_UDP_SEND ) {
|
||||
size = MAX_UDP_SEND;
|
||||
}
|
||||
return (bufSizeT) size;
|
||||
#endif
|
||||
return static_cast < bufSizeT > ( size );
|
||||
}
|
||||
|
||||
SOCKET casDGIntfIO::makeSockDG ()
|
||||
|
||||
@@ -39,10 +39,10 @@ public:
|
||||
inBufClient::fillParameter parm, bufSizeT & nBytesActual, caNetAddr & addr );
|
||||
virtual void show ( unsigned level ) const;
|
||||
|
||||
static bufSizeT optimumOutBufferSize ();
|
||||
static bufSizeT optimumInBufferSize ();
|
||||
|
||||
bufSizeT incomingBytesPresent () const;
|
||||
bufSizeT dgInBytesPending () const;
|
||||
bufSizeT osSendBufferSize () const ;
|
||||
|
||||
private:
|
||||
tsFreeList < ipIgnoreEntry, 128 > ipIgnoreEntryFreeList;
|
||||
|
||||
@@ -236,4 +236,3 @@ caNetAddr casIntfIO::serverAddress () const
|
||||
{
|
||||
return caNetAddr (this->addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
clientBufMemoryManager & ) const;
|
||||
|
||||
caNetAddr serverAddress () const;
|
||||
|
||||
|
||||
private:
|
||||
SOCKET sock;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
casStreamIO::casStreamIO ( caServerI & cas, clientBufMemoryManager & bufMgr,
|
||||
const ioArgsToNewStreamIO & args ) :
|
||||
casStrmClient ( cas, bufMgr ), sock ( args.sock ), addr ( args.addr),
|
||||
blockingFlag ( xIsBlocking ), sockHasBeenShutdown ( false )
|
||||
_osSendBufferSize ( MAX_TCP ), blockingFlag ( xIsBlocking ),
|
||||
sockHasBeenShutdown ( false )
|
||||
{
|
||||
assert ( sock >= 0 );
|
||||
int yes = true;
|
||||
@@ -91,7 +92,19 @@ casStreamIO::casStreamIO ( caServerI & cas, clientBufMemoryManager & bufMgr,
|
||||
throw S_cas_internal;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* cache the TCP send buffer size */
|
||||
int size = MAX_TCP;
|
||||
osiSocklen_t n = sizeof ( size ) ;
|
||||
status = getsockopt ( this->sock, SOL_SOCKET,
|
||||
SO_SNDBUF, reinterpret_cast < char * > ( & size ), & n );
|
||||
if ( status < 0 || n != sizeof ( size ) ) {
|
||||
size = MAX_TCP;
|
||||
}
|
||||
if ( size <= MAX_TCP ) {
|
||||
size = MAX_TCP;
|
||||
}
|
||||
_osSendBufferSize = static_cast < bufSizeT > ( size );
|
||||
}
|
||||
|
||||
// casStreamIO::~casStreamIO()
|
||||
@@ -254,14 +267,14 @@ xBlockingStatus casStreamIO::blockingState() const
|
||||
{
|
||||
return this->blockingFlag;
|
||||
}
|
||||
|
||||
// casStreamIO::incomingBytesPresent()
|
||||
bufSizeT casStreamIO::incomingBytesPresent () const // X aCC 361
|
||||
|
||||
// casStreamIO :: inCircuitBytesPending()
|
||||
bufSizeT casStreamIO :: inCircuitBytesPending () const
|
||||
{
|
||||
int status;
|
||||
osiSockIoctl_t nchars = 0;
|
||||
|
||||
status = socket_ioctl ( this->sock, FIONREAD, &nchars ); // X aCC 392
|
||||
status = socket_ioctl ( this->sock, FIONREAD, &nchars );
|
||||
if ( status < 0 ) {
|
||||
int localError = SOCKERRNO;
|
||||
if (
|
||||
@@ -293,32 +306,10 @@ void casStreamIO::hostName ( char * pInBuf, unsigned bufSizeIn ) const
|
||||
ipAddrToA ( & this->addr, pInBuf, bufSizeIn );
|
||||
}
|
||||
|
||||
// casStreamIO:::optimumBufferSize()
|
||||
bufSizeT casStreamIO::optimumBufferSize ()
|
||||
// casStreamIO :: osSendBufferSize ()
|
||||
bufSizeT casStreamIO :: osSendBufferSize () const
|
||||
{
|
||||
|
||||
#if 0
|
||||
int n;
|
||||
int size;
|
||||
int status;
|
||||
|
||||
/* fetch the TCP send buffer size */
|
||||
n = sizeof ( size) ;
|
||||
status = getsockopt ( this->sock, SOL_SOCKET,
|
||||
SO_SNDBUF, (char *) & size, & n );
|
||||
if ( status < 0 || n != sizeof ( size ) ) {
|
||||
size = 0x400;
|
||||
}
|
||||
|
||||
if (size<=0) {
|
||||
size = 0x400;
|
||||
}
|
||||
printf("the tcp buf size is %d\n", size);
|
||||
return (bufSizeT) size;
|
||||
#else
|
||||
// this needs to be MAX_TCP (until we fix the array problem)
|
||||
return (bufSizeT) MAX_TCP; // X aCC 392
|
||||
#endif
|
||||
return _osSendBufferSize;
|
||||
}
|
||||
|
||||
// casStreamIO::getFD()
|
||||
|
||||
@@ -31,16 +31,16 @@ public:
|
||||
void xSetNonBlocking ();
|
||||
const caNetAddr getAddr() const;
|
||||
void hostName ( char *pBuf, unsigned bufSize ) const;
|
||||
|
||||
bufSizeT inCircuitBytesPending () const;
|
||||
bufSizeT osSendBufferSize () const;
|
||||
private:
|
||||
SOCKET sock;
|
||||
struct sockaddr_in addr;
|
||||
bufSizeT _osSendBufferSize;
|
||||
xBlockingStatus blockingFlag;
|
||||
|
||||
bool sockHasBeenShutdown;
|
||||
xBlockingStatus blockingState() const;
|
||||
bufSizeT incomingBytesPresent() const;
|
||||
static bufSizeT optimumBufferSize ();
|
||||
void osdShow ( unsigned level ) const;
|
||||
outBufClient::flushCondition osdSend ( const char *pBuf, bufSizeT nBytesReq,
|
||||
bufSizeT & nBytesActual );
|
||||
|
||||
@@ -613,7 +613,7 @@ static void dbBkptCont(dbCommon *precord)
|
||||
--lset_stack_count;
|
||||
|
||||
/* free entrypoint queue */
|
||||
ellFree(&pnode->ep_queue, free);
|
||||
ellFree(&pnode->ep_queue);
|
||||
|
||||
/* remove execution semaphore */
|
||||
epicsEventDestroy(pnode->ex_sem);
|
||||
|
||||
@@ -872,10 +872,14 @@ static void dbBreakBody(void)
|
||||
double slope =
|
||||
(paBrkInt[i+1].eng - paBrkInt[i].eng)/
|
||||
(paBrkInt[i+1].raw - paBrkInt[i].raw);
|
||||
if (!dbBptNotMonotonic && slope == 0) {
|
||||
yyerrorAbort("breaktable slope is zero");
|
||||
return;
|
||||
}
|
||||
if (i == 0) {
|
||||
down = (slope < 0);
|
||||
} else if (!dbBptNotMonotonic && down != (slope < 0)) {
|
||||
yyerrorAbort("breaktable: curve slope changes sign");
|
||||
yyerrorAbort("breaktable slope changes sign");
|
||||
return;
|
||||
}
|
||||
paBrkInt[i].slope = slope;
|
||||
|
||||
@@ -235,53 +235,55 @@ static long setLinkType(DBENTRY *pdbentry)
|
||||
DBLINK *plink;
|
||||
long status=0;
|
||||
int link_type,ind,type;
|
||||
int isSoftLink;
|
||||
|
||||
dbCopyEntryContents(pdbentry,&dbEntry);
|
||||
status = dbFindField(&dbEntry,"DTYP");
|
||||
if(status) {
|
||||
dbCopyEntryContents(pdbentry, &dbEntry);
|
||||
status = dbFindField(&dbEntry, "DTYP");
|
||||
if (status) {
|
||||
epicsPrintf("field DTYP does not exist for recordtype %s\n",
|
||||
dbGetRecordTypeName(&dbEntry));
|
||||
status = S_dbLib_fieldNotFound;
|
||||
goto done;
|
||||
}
|
||||
|
||||
precordType = dbEntry.precordType;
|
||||
if(!precordType) {
|
||||
if (!precordType) {
|
||||
status = S_dbLib_badField;
|
||||
goto done;
|
||||
}
|
||||
if(ellCount(&precordType->devList)==0) goto done;
|
||||
|
||||
if (ellCount(&precordType->devList) == 0) goto done;
|
||||
|
||||
ind = dbGetMenuIndex(&dbEntry);
|
||||
if(ind==-1) {
|
||||
if (ind == -1) {
|
||||
char *pstring;
|
||||
|
||||
pstring = dbGetString(&dbEntry);
|
||||
if(strstr(pstring,"$(") || strstr(pstring,"${")) {
|
||||
if (strstr(pstring, "$(") || strstr(pstring, "${")) {
|
||||
link_type = MACRO_LINK;
|
||||
} else {
|
||||
status = S_dbLib_badField;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
pdevSup = (devSup *)ellNth(&precordType->devList,ind+1);
|
||||
if(!pdevSup) {
|
||||
pdevSup = (devSup *)ellNth(&precordType->devList, ind + 1);
|
||||
if (!pdevSup) {
|
||||
status = S_dbLib_badField;
|
||||
goto done;
|
||||
}
|
||||
link_type = pdevSup->link_type;
|
||||
}
|
||||
|
||||
pflddes = pdbentry->pflddes;
|
||||
plink = (DBLINK *)(pdbentry->pfield);
|
||||
if(plink->type == link_type) goto done;
|
||||
plink = (DBLINK *)pdbentry->pfield;
|
||||
if (plink->type == link_type) goto done;
|
||||
|
||||
type = plink->type;
|
||||
if(type==CONSTANT || type==PV_LINK || type==DB_LINK || type==CA_LINK)
|
||||
isSoftLink = TRUE;
|
||||
else
|
||||
isSoftLink = FALSE;
|
||||
if(isSoftLink && (link_type==CONSTANT || link_type==PV_LINK)) goto done;
|
||||
if ((type == CONSTANT || type == PV_LINK || type == DB_LINK || type == CA_LINK) &&
|
||||
(link_type == CONSTANT || link_type == PV_LINK)) goto done;
|
||||
|
||||
dbFreeLinkContents(plink);
|
||||
plink->type = link_type;
|
||||
switch(plink->type) {
|
||||
switch (plink->type) {
|
||||
case VME_IO: plink->value.vmeio.parm = pNullString; break;
|
||||
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
|
||||
case AB_IO: plink->value.abio.parm = pNullString; break;
|
||||
@@ -2164,8 +2166,9 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
}
|
||||
if((short)strlen(pstring) >= pflddes->size) status = S_dbLib_strLen;
|
||||
break;
|
||||
case DBF_CHAR :
|
||||
case DBF_SHORT :
|
||||
|
||||
case DBF_CHAR:
|
||||
case DBF_SHORT:
|
||||
case DBF_LONG:
|
||||
case DBF_UCHAR:
|
||||
case DBF_USHORT:
|
||||
@@ -2176,68 +2179,75 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
case DBF_MENU:
|
||||
status = dbPutStringNum(pdbentry,pstring);
|
||||
break;
|
||||
|
||||
case DBF_DEVICE: {
|
||||
DBENTRY dbEntry;
|
||||
char *name;
|
||||
|
||||
status = dbPutStringNum(pdbentry,pstring);
|
||||
if(status) return(status);
|
||||
status = dbPutStringNum(pdbentry, pstring);
|
||||
if (status) return status;
|
||||
|
||||
name = dbGetRelatedField(pdbentry);
|
||||
if(!name) return(0);
|
||||
dbCopyEntryContents(pdbentry,&dbEntry);
|
||||
status = dbFindField(&dbEntry,name);
|
||||
if(!status) status = setLinkType(&dbEntry);
|
||||
if (!name) return 0;
|
||||
|
||||
dbCopyEntryContents(pdbentry, &dbEntry);
|
||||
status = dbFindField(&dbEntry, name);
|
||||
if (!status)
|
||||
status = setLinkType(&dbEntry);
|
||||
dbFinishEntry(&dbEntry);
|
||||
return(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
case DBF_INLINK:
|
||||
case DBF_OUTLINK:
|
||||
case DBF_FWDLINK: {
|
||||
DBLINK *plink;
|
||||
char string[80];
|
||||
char *pstr=&string[0];
|
||||
char *pstr = string;
|
||||
int ind;
|
||||
|
||||
if(!pfield) return(S_dbLib_fieldNotFound);
|
||||
if (!pfield)
|
||||
return S_dbLib_fieldNotFound;
|
||||
|
||||
plink = (DBLINK *)pfield;
|
||||
dbFreeLinkContents(plink);
|
||||
if(!stringHasMacro &&(strcmp(pflddes->name,"INP")==0
|
||||
|| strcmp(pflddes->name,"OUT")==0)){
|
||||
status = setLinkType(pdbentry);
|
||||
if(status) {
|
||||
errMessage(status,"in dbPutString from setLinkType");
|
||||
return(status);
|
||||
}
|
||||
}
|
||||
if(stringHasMacro) {
|
||||
if (stringHasMacro) {
|
||||
plink->type = MACRO_LINK;
|
||||
plink->value.macro_link.macroStr =
|
||||
dbCalloc(strlen(pstring)+1,sizeof(char));
|
||||
strcpy(plink->value.macro_link.macroStr,pstring);
|
||||
plink->value.macro_link.macroStr = epicsStrDup(pstring);
|
||||
goto done;
|
||||
}
|
||||
if(strlen(pstring)>=sizeof(string)) {
|
||||
|
||||
if (strcmp(pflddes->name, "INP") == 0 ||
|
||||
strcmp(pflddes->name, "OUT") == 0) {
|
||||
status = setLinkType(pdbentry); /* This uses DTYP to look up and set plink->type, necessary for default DTYP */
|
||||
if (status) {
|
||||
errMessage(status,"in dbPutString from setLinkType");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (strlen(pstring) >= sizeof(string)) {
|
||||
status = S_dbLib_badField;
|
||||
errMessage(status,
|
||||
"dbPutString received a string that is too long");
|
||||
return(status);
|
||||
return status;
|
||||
}
|
||||
strcpy(pstr,pstring);
|
||||
/*strip off leading blanks and tabs*/
|
||||
while(*pstr && (*pstr==' ' || *pstr=='\t')) pstr++;
|
||||
/*strip off trailing blanks and tabs*/
|
||||
if(pstr) for(ind = strlen(pstr)-1; ind>=0; ind--) {
|
||||
if(pstr[ind]!=' ' && pstr[ind]!='\t') break;
|
||||
pstr[ind] = '\0';
|
||||
}
|
||||
if(!pstr || (int)strlen(pstr)<=0 ) {
|
||||
if(plink->type==PV_LINK) dbCvtLinkToConstant(pdbentry);
|
||||
if(plink->type!=CONSTANT) return(S_dbLib_badField);
|
||||
strcpy(pstr, pstring);
|
||||
/* Strip leading blanks and tabs */
|
||||
while (*pstr && (*pstr == ' ' || *pstr == '\t')) pstr++;
|
||||
/* Strip trailing blanks and tabs */
|
||||
if (pstr)
|
||||
for (ind = strlen(pstr) - 1; ind >= 0; ind--) {
|
||||
if (pstr[ind] != ' ' && pstr[ind] != '\t') break;
|
||||
pstr[ind] = '\0';
|
||||
}
|
||||
if (!pstr || !*pstr) {
|
||||
if (plink->type == PV_LINK) dbCvtLinkToConstant(pdbentry);
|
||||
if (plink->type != CONSTANT) return S_dbLib_badField;
|
||||
free((void *)plink->value.constantStr);
|
||||
plink->value.constantStr = NULL;
|
||||
goto done;
|
||||
}
|
||||
switch(plink->type) {
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
case PV_LINK: {
|
||||
short ppOpt = 0;
|
||||
@@ -2251,60 +2261,64 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
/* Check first to see if string is a constant*/
|
||||
/*It is a string if epicsStrtod or strtol eats entire string*/
|
||||
/*leading and trailing blanks have already been stripped*/
|
||||
tempdouble = epicsStrtod(pstr,&enddouble);
|
||||
templong = strtol(pstr,&endlong,0);
|
||||
if((*enddouble == 0) || (*endlong == 0)) {
|
||||
if(plink->type==PV_LINK) dbCvtLinkToConstant(pdbentry);
|
||||
if((!plink->value.constantStr) ||
|
||||
((int)strlen(plink->value.constantStr)<(int)strlen(pstr)
|
||||
)) {
|
||||
tempdouble = epicsStrtod(pstr, &enddouble);
|
||||
templong = strtol(pstr, &endlong, 0);
|
||||
|
||||
if (*enddouble == 0 || *endlong == 0) {
|
||||
if (plink->type == PV_LINK) dbCvtLinkToConstant(pdbentry);
|
||||
if (!plink->value.constantStr ||
|
||||
strlen(plink->value.constantStr) < strlen(pstr)) {
|
||||
free(plink->value.constantStr);
|
||||
plink->value.constantStr =
|
||||
dbCalloc(strlen(pstr)+1,sizeof(char));
|
||||
dbCalloc(strlen(pstr) + 1, sizeof(char));
|
||||
}
|
||||
strcpy(plink->value.constantStr,pstr);
|
||||
strcpy(plink->value.constantStr, pstr);
|
||||
goto done;
|
||||
}
|
||||
if(plink->type==CONSTANT) dbCvtLinkToPvlink(pdbentry);
|
||||
|
||||
if (plink->type==CONSTANT) dbCvtLinkToPvlink(pdbentry);
|
||||
end = strchr(pstr,' ');
|
||||
if(end) {
|
||||
if (end) {
|
||||
switch (pflddes->field_type) {
|
||||
case DBF_INLINK: {
|
||||
if(strstr(end,"NPP")) ppOpt = 0;
|
||||
else if(strstr(end,"CPP")) ppOpt = pvlOptCPP;
|
||||
else if(strstr(end,"PP")) ppOpt = pvlOptPP;
|
||||
else if(strstr(end,"CA")) ppOpt = pvlOptCA;
|
||||
else if(strstr(end,"CP")) ppOpt = pvlOptCP;
|
||||
if (strstr(end, "NPP")) ppOpt = 0;
|
||||
else if (strstr(end, "CPP")) ppOpt = pvlOptCPP;
|
||||
else if (strstr(end, "PP")) ppOpt = pvlOptPP;
|
||||
else if (strstr(end, "CA")) ppOpt = pvlOptCA;
|
||||
else if (strstr(end, "CP")) ppOpt = pvlOptCP;
|
||||
else ppOpt = 0;
|
||||
if(strstr(end,"NMS")) msOpt = pvlOptNMS;
|
||||
else if(strstr(end,"MSI")) msOpt = pvlOptMSI;
|
||||
else if(strstr(end,"MSS")) msOpt = pvlOptMSS;
|
||||
/*must be the last one:*/ else if(strstr(end,"MS")) msOpt = pvlOptMS;
|
||||
if (strstr(end, "NMS")) msOpt = pvlOptNMS;
|
||||
else if (strstr(end, "MSI")) msOpt = pvlOptMSI;
|
||||
else if (strstr(end, "MSS")) msOpt = pvlOptMSS;
|
||||
/*must be the last one:*/ else if (strstr(end, "MS")) msOpt = pvlOptMS;
|
||||
else msOpt = 0;
|
||||
*end = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DBF_OUTLINK: {
|
||||
if(strstr(end,"NPP")) ppOpt = 0;
|
||||
else if(strstr(end,"PP")) ppOpt = pvlOptPP;
|
||||
else if(strstr(end,"CA")) ppOpt = pvlOptCA;
|
||||
if (strstr(end, "NPP")) ppOpt = 0;
|
||||
else if(strstr(end, "PP")) ppOpt = pvlOptPP;
|
||||
else if(strstr(end, "CA")) ppOpt = pvlOptCA;
|
||||
else ppOpt = 0;
|
||||
if(strstr(end,"NMS")) msOpt = pvlOptNMS;
|
||||
else if(strstr(end,"MSI")) msOpt = pvlOptMSI;
|
||||
else if(strstr(end,"MSS")) msOpt = pvlOptMSS;
|
||||
/*must be the last one:*/ else if(strstr(end,"MS")) msOpt = pvlOptMS;
|
||||
if (strstr(end, "NMS")) msOpt = pvlOptNMS;
|
||||
else if(strstr(end, "MSI")) msOpt = pvlOptMSI;
|
||||
else if(strstr(end, "MSS")) msOpt = pvlOptMSS;
|
||||
/*must be the last one:*/ else if(strstr(end, "MS")) msOpt = pvlOptMS;
|
||||
else msOpt = 0;
|
||||
*end = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DBF_FWDLINK: {
|
||||
if(strstr(end,"NPP")) ppOpt = 0;
|
||||
else if(strstr(end,"CA")) ppOpt = pvlOptCA;
|
||||
if (strstr(end, "NPP")) ppOpt = 0;
|
||||
else if (strstr(end, "CA")) ppOpt = pvlOptCA;
|
||||
else ppOpt = 0;
|
||||
msOpt = 0;
|
||||
*end = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
epicsPrintf("dbPutString: Logic Error\n");
|
||||
}
|
||||
@@ -2316,38 +2330,39 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
case VME_IO: {
|
||||
char *end;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'#'))) return S_dbLib_badField;
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'C'))) return S_dbLib_badField;
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vmeio.card);
|
||||
if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'S'))) return S_dbLib_badField;
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.vmeio.signal);
|
||||
status = putParmString(&plink->value.vmeio.parm,pstr);
|
||||
cvtDecimalOrHexToShort(pstr, &plink->value.vmeio.signal);
|
||||
status = putParmString(&plink->value.vmeio.parm, pstr);
|
||||
}
|
||||
break;
|
||||
|
||||
case CAMAC_IO: {
|
||||
char *end;
|
||||
|
||||
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
if(!(end = strchr(pstr,'B'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'B'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.b);
|
||||
if(!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.c);
|
||||
if(!(end = strchr(pstr,'N'))) return (S_dbLib_badField);
|
||||
if (!(end = strchr(pstr,'N'))) return (S_dbLib_badField);
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.n);
|
||||
if(!(end = strchr(pstr,'A'))) {
|
||||
if (!(end = strchr(pstr,'A'))) {
|
||||
plink->value.camacio.a = 0;
|
||||
} else {
|
||||
pstr = end + 1;
|
||||
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.a);
|
||||
}
|
||||
if(!(end = strchr(pstr,'F'))) {
|
||||
if (!(end = strchr(pstr,'F'))) {
|
||||
plink->value.camacio.f = 0;
|
||||
} else {
|
||||
pstr = end + 1;
|
||||
@@ -2356,6 +2371,7 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
status = putParmString(&plink->value.camacio.parm,pstr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RF_IO: {
|
||||
char *end;
|
||||
|
||||
@@ -2492,22 +2508,22 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,const char *pstring)
|
||||
}
|
||||
break;
|
||||
case INST_IO: {
|
||||
status = putParmString(&plink->value.instio.string,pstr);
|
||||
status = putParmString(&plink->value.instio.string, pstr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return (S_dbLib_badField);
|
||||
return S_dbLib_badField;
|
||||
}
|
||||
done:
|
||||
if(!status && strcmp(pflddes->name,"VAL")==0) {
|
||||
if (!status && strcmp(pflddes->name, "VAL") == 0) {
|
||||
DBENTRY dbentry;
|
||||
|
||||
dbCopyEntryContents(pdbentry,&dbentry);
|
||||
if(!dbFindField(&dbentry,"UDF")) {
|
||||
dbPutString(&dbentry,"0");
|
||||
dbCopyEntryContents(pdbentry, &dbentry);
|
||||
if (!dbFindField(&dbentry, "UDF")) {
|
||||
dbPutString(&dbentry, "0");
|
||||
}
|
||||
dbFinishEntry(&dbentry);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <epicsStdlib.h>
|
||||
#include <limits.h>
|
||||
#include "epicsStdio.h"
|
||||
#include "cvtFast.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "aitConvert.h"
|
||||
|
||||
@@ -69,7 +71,7 @@ bool putDoubleToString (
|
||||
const double in, const gddEnumStringTable * pEST,
|
||||
char * pString, size_t strSize )
|
||||
{
|
||||
if ( strSize == 0u ) {
|
||||
if ( strSize <= 1u ) {
|
||||
return false;
|
||||
}
|
||||
if ( pEST && in >= 0 && in <= UINT_MAX ) {
|
||||
@@ -79,11 +81,33 @@ bool putDoubleToString (
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
bool cvtDoubleToStringInRange =
|
||||
( in < 1.e4 && in > 1.e-4 ) ||
|
||||
( in > -1.e4 && in < -1.e-4 ) ||
|
||||
in == 0.0;
|
||||
// conservative
|
||||
static const unsigned cvtDoubleToStringSizeMax = 15;
|
||||
int nChar;
|
||||
if ( cvtDoubleToStringInRange &&
|
||||
strSize > cvtDoubleToStringSizeMax ) {
|
||||
nChar = cvtDoubleToString ( in, pString, 4 );
|
||||
}
|
||||
else {
|
||||
nChar = epicsSnprintf (
|
||||
pString, strSize-1, "%g", in );
|
||||
}
|
||||
if ( nChar < 1 ) {
|
||||
return false;
|
||||
}
|
||||
assert ( nChar < strSize );
|
||||
#else
|
||||
int nChar = epicsSnprintf (
|
||||
pString, strSize-1, "%g", in );
|
||||
if ( nChar <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
size_t nCharU = static_cast < size_t > ( nChar );
|
||||
nChar = epicsMin ( nCharU, strSize-1 ) + 1;
|
||||
memset ( &pString[nChar], '\0', strSize - nChar );
|
||||
|
||||
@@ -70,76 +70,6 @@ static void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId);
|
||||
*/
|
||||
#define BUCKET_MAX_WIDTH 12
|
||||
|
||||
#ifdef DEBUG
|
||||
main()
|
||||
{
|
||||
unsigned id1;
|
||||
unsigned id2;
|
||||
char *pValSave1;
|
||||
char *pValSave2;
|
||||
int s;
|
||||
BUCKET *pb;
|
||||
char *pVal;
|
||||
unsigned i;
|
||||
clock_t start, finish;
|
||||
double duration;
|
||||
const int LOOPS = 500000;
|
||||
|
||||
pb = bucketCreate(8);
|
||||
if(!pb){
|
||||
return -1;
|
||||
}
|
||||
|
||||
id1 = 0x1000a432;
|
||||
pValSave1 = "fred";
|
||||
s = bucketAddItemUnsignedId(pb, &id1, pValSave1);
|
||||
assert (s == S_bucket_success);
|
||||
|
||||
pValSave2 = "jane";
|
||||
id2 = 0x0000a432;
|
||||
s = bucketAddItemUnsignedId(pb, &id2, pValSave2);
|
||||
assert (s == S_bucket_success);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id2);
|
||||
assert(pVal == pValSave2);
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
duration = finish-start;
|
||||
duration = duration/CLOCKS_PER_SEC;
|
||||
printf("It took %15.10f total sec\n", duration);
|
||||
duration = duration/LOOPS;
|
||||
duration = duration/10;
|
||||
duration = duration * 1e6;
|
||||
printf("It took %15.10f u sec per hash lookup\n", duration);
|
||||
|
||||
bucketShow(pb);
|
||||
|
||||
return S_bucket_success;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedCompare()
|
||||
|
||||
@@ -135,7 +135,7 @@ epicsShareFunc long
|
||||
if (itop)
|
||||
*ptop = (long) *ptop % itop;
|
||||
else
|
||||
*ptop = 0.0 / itop; /* NaN */
|
||||
*ptop = epicsNAN; /* NaN */
|
||||
break;
|
||||
|
||||
case POWER:
|
||||
|
||||
@@ -25,6 +25,9 @@ typedef intId<unsigned,8,16> testIntId;
|
||||
typedef intId<unsigned,8> testIntId;
|
||||
#endif
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
static void empty()
|
||||
{
|
||||
}
|
||||
@@ -34,7 +37,7 @@ public:
|
||||
albert (resTable< albert, testIntId > &atIn, unsigned idIn) :
|
||||
testIntId(idIn), at(atIn)
|
||||
{
|
||||
assert (at.add (*this)==0);
|
||||
verify (at.add (*this)==0);
|
||||
}
|
||||
void show (unsigned /* level */)
|
||||
{
|
||||
@@ -125,52 +128,52 @@ int main()
|
||||
|
||||
intTbl.setTableSize ( 100000 );
|
||||
|
||||
assert (intTbl.add(fred0)==0);
|
||||
verify (intTbl.add(fred0)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred1)==0);
|
||||
verify (intTbl.add(fred1)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred2)==0);
|
||||
verify (intTbl.add(fred2)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred3)==0);
|
||||
verify (intTbl.add(fred3)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred4)==0);
|
||||
verify (intTbl.add(fred4)==0);
|
||||
intTbl.verify ();
|
||||
|
||||
intTbl.setTableSize ( 200000 );
|
||||
|
||||
assert (intTbl.add(fred5)==0);
|
||||
verify (intTbl.add(fred5)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred6)==0);
|
||||
verify (intTbl.add(fred6)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred7)==0);
|
||||
verify (intTbl.add(fred7)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred8)==0);
|
||||
verify (intTbl.add(fred8)==0);
|
||||
intTbl.verify ();
|
||||
assert (intTbl.add(fred9)==0);
|
||||
verify (intTbl.add(fred9)==0);
|
||||
intTbl.verify ();
|
||||
|
||||
start = clock();
|
||||
for (i=0; i<LOOPS; i++) {
|
||||
pFred = intTbl.lookup(intId1);
|
||||
assert(pFred==&fred1);
|
||||
verify(pFred==&fred1);
|
||||
pFred = intTbl.lookup(intId2);
|
||||
assert(pFred==&fred2);
|
||||
verify (pFred==&fred2);
|
||||
pFred = intTbl.lookup(intId3);
|
||||
assert(pFred==&fred3);
|
||||
verify (pFred==&fred3);
|
||||
pFred = intTbl.lookup(intId4);
|
||||
assert(pFred==&fred4);
|
||||
verify (pFred==&fred4);
|
||||
pFred = intTbl.lookup(intId5);
|
||||
assert(pFred==&fred5);
|
||||
verify (pFred==&fred5);
|
||||
pFred = intTbl.lookup(intId6);
|
||||
assert(pFred==&fred6);
|
||||
verify (pFred==&fred6);
|
||||
pFred = intTbl.lookup(intId7);
|
||||
assert(pFred==&fred7);
|
||||
verify (pFred==&fred7);
|
||||
pFred = intTbl.lookup(intId8);
|
||||
assert(pFred==&fred8);
|
||||
verify (pFred==&fred8);
|
||||
pFred = intTbl.lookup(intId9);
|
||||
assert(pFred==&fred9);
|
||||
verify (pFred==&fred9);
|
||||
pFred = intTbl.lookup(intId0);
|
||||
assert(pFred==&fred0);
|
||||
verify (pFred==&fred0);
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
@@ -187,35 +190,35 @@ int main()
|
||||
intTbl.remove(intId1);
|
||||
intTbl.remove(intId2);
|
||||
pFred = intTbl.lookup(intId1);
|
||||
assert(pFred==0);
|
||||
verify (pFred==0);
|
||||
pFred = intTbl.lookup(intId2);
|
||||
assert(pFred==0);
|
||||
verify (pFred==0);
|
||||
|
||||
assert (strTbl.add(jane1)==0);
|
||||
assert (strTbl.add(jane2)==0);
|
||||
verify (strTbl.add(jane1)==0);
|
||||
verify (strTbl.add(jane2)==0);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
assert(pJane==&jane1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId2);
|
||||
assert(pJane==&jane2);
|
||||
verify (pJane==&jane2);
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
@@ -264,7 +267,7 @@ int main()
|
||||
|
||||
for (i=0; i<elementCount; i++) {
|
||||
pAlbert[i] = new albert (alTbl, i);
|
||||
assert ( pAlbert[i] );
|
||||
verify ( pAlbert[i] );
|
||||
}
|
||||
alTbl.verify ();
|
||||
alTbl.show (1u);
|
||||
@@ -276,26 +279,26 @@ int main()
|
||||
i++;
|
||||
alTblIter++;
|
||||
}
|
||||
assert ( i == elementCount );
|
||||
verify ( i == elementCount );
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 0; i < elementCount; i++ ) {
|
||||
assert ( pAlbert[i] == alTbl.lookup( pAlbert[i]->getId() ) );
|
||||
verify ( pAlbert[i] == alTbl.lookup( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 0; i < elementCount; i += 2 ) {
|
||||
assert ( pAlbert[i] == alTbl.remove ( pAlbert[i]->getId() ) );
|
||||
verify ( pAlbert[i] == alTbl.remove ( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 0; i < elementCount; i += 2 ) {
|
||||
assert ( 0 == alTbl.lookup ( pAlbert[i]->getId() ) );
|
||||
verify ( 0 == alTbl.lookup ( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 1; i < elementCount; i += 2 ) {
|
||||
assert ( pAlbert[i] == alTbl.lookup ( pAlbert[i]->getId() ) );
|
||||
verify ( pAlbert[i] == alTbl.lookup ( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ int main ()
|
||||
|
||||
clk = clock ();
|
||||
for (i=0u; i<LOOPCOUNT; i++) {
|
||||
assert ( tree.verify(a) );
|
||||
bool success = tree.verify(a);
|
||||
assert ( success );
|
||||
}
|
||||
diff = clock () - clk;
|
||||
delay = diff;
|
||||
@@ -77,13 +78,14 @@ int main ()
|
||||
|
||||
clk = clock ();
|
||||
while ( ( pA = list.get () ) ) {
|
||||
assert (tree.remove(*pA));
|
||||
bool success = tree.remove(*pA);
|
||||
assert ( success );
|
||||
}
|
||||
diff = clock () - clk;
|
||||
delay = diff;
|
||||
delay = delay/CLOCKS_PER_SEC;
|
||||
delay = delay/LOOPCOUNT;
|
||||
printf ("delay = %15.10f\n", delay);
|
||||
delay = diff;
|
||||
delay = delay/CLOCKS_PER_SEC;
|
||||
delay = delay/LOOPCOUNT;
|
||||
printf ("delay = %15.10f\n", delay);
|
||||
|
||||
tree.traverse (&A::show);
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
|
||||
#include "tsBTree.h"
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
class A : public tsBTreeNode<A> {
|
||||
public:
|
||||
A(const char *pNameIn) : pName(pNameIn) {}
|
||||
@@ -57,30 +60,30 @@ int main ()
|
||||
|
||||
tree.traverse (&A::show);
|
||||
|
||||
assert (tree.remove(a6)==tsbtrrNotFound);
|
||||
verify (tree.remove(a6)==tsbtrrNotFound);
|
||||
tree.insert (a6);
|
||||
assert (tree.remove(a6)==tsbtrrFound);
|
||||
assert (tree.remove(a5)==tsbtrrFound);
|
||||
assert (tree.remove(a5)==tsbtrrNotFound);
|
||||
assert (!tree.verify(a5));
|
||||
assert (tree.verify(a4));
|
||||
assert (tree.remove(a0)==tsbtrrFound);
|
||||
assert (!tree.verify(a0));
|
||||
assert (tree.remove(a0)==tsbtrrNotFound);
|
||||
verify (tree.remove(a6)==tsbtrrFound);
|
||||
verify (tree.remove(a5)==tsbtrrFound);
|
||||
verify (tree.remove(a5)==tsbtrrNotFound);
|
||||
verify (!tree.verify(a5));
|
||||
verify (tree.verify(a4));
|
||||
verify (tree.remove(a0)==tsbtrrFound);
|
||||
verify (!tree.verify(a0));
|
||||
verify (tree.remove(a0)==tsbtrrNotFound);
|
||||
tree.insert (a5);
|
||||
assert (tree.verify(a5));
|
||||
assert (tree.verify(a2));
|
||||
assert (tree.remove(a2)==tsbtrrFound);
|
||||
assert (!tree.verify(a2));
|
||||
assert (tree.remove(a2)==tsbtrrNotFound);
|
||||
assert (tree.verify(a5));
|
||||
assert (tree.remove(a5)==tsbtrrFound);
|
||||
assert (tree.remove(a5)==tsbtrrNotFound);
|
||||
assert (tree.remove(a0)==tsbtrrNotFound);
|
||||
assert (tree.remove(a4)==tsbtrrFound);
|
||||
assert (tree.remove(a3)==tsbtrrFound);
|
||||
assert (tree.remove(a4)==tsbtrrNotFound);
|
||||
assert (tree.remove(a1)==tsbtrrFound);
|
||||
verify (tree.verify(a5));
|
||||
verify (tree.verify(a2));
|
||||
verify (tree.remove(a2)==tsbtrrFound);
|
||||
verify (!tree.verify(a2));
|
||||
verify (tree.remove(a2)==tsbtrrNotFound);
|
||||
verify (tree.verify(a5));
|
||||
verify (tree.remove(a5)==tsbtrrFound);
|
||||
verify (tree.remove(a5)==tsbtrrNotFound);
|
||||
verify (tree.remove(a0)==tsbtrrNotFound);
|
||||
verify (tree.remove(a4)==tsbtrrFound);
|
||||
verify (tree.remove(a3)==tsbtrrFound);
|
||||
verify (tree.remove(a4)==tsbtrrNotFound);
|
||||
verify (tree.remove(a1)==tsbtrrFound);
|
||||
|
||||
tree.traverse (&A::show);
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
class fred : public tsDLNode<fred> {
|
||||
public:
|
||||
fred(const char * const pNameIn) : pName(pNameIn){}
|
||||
@@ -46,16 +49,16 @@ int main ()
|
||||
list.add (*pFred);
|
||||
list.add (*pFredII);
|
||||
tsDLIter <fred> iter = list.firstIter();
|
||||
assert (iter.pointer() == pFred);
|
||||
verify (iter.pointer() == pFred);
|
||||
iter++;
|
||||
assert (iter.pointer() == pFredII);
|
||||
verify (iter.pointer() == pFredII);
|
||||
list.remove(*pFred);
|
||||
list.add(*pFred);
|
||||
pFredBack = list.get();
|
||||
assert (pFredBack == pFredII);
|
||||
verify (pFredBack == pFredII);
|
||||
pFredBack = list.get();
|
||||
assert (pFredBack == pFred);
|
||||
assert (list.count() == 0u);
|
||||
verify (pFredBack == pFred);
|
||||
verify (list.count() == 0u);
|
||||
list.add(*pFred);
|
||||
list.add(*pFredII);
|
||||
list.add(* new fred("C"));
|
||||
@@ -70,9 +73,9 @@ int main ()
|
||||
pJane = new jane("JA");
|
||||
janeList.add(*pJane);
|
||||
pJane = new jane("JB");
|
||||
assert ( janeList.find ( *pJane ) == -1 );
|
||||
verify ( janeList.find ( *pJane ) == -1 );
|
||||
janeList.add(*pJane);
|
||||
assert ( janeList.find ( *pJane ) == 1 );
|
||||
verify ( janeList.find ( *pJane ) == 1 );
|
||||
|
||||
while ( janeFwdIter.valid() ) {
|
||||
janeFwdIter->show();
|
||||
@@ -96,21 +99,21 @@ int main ()
|
||||
i++;
|
||||
bdIter++;
|
||||
}
|
||||
assert ( i == janeList.count () );
|
||||
verify ( i == janeList.count () );
|
||||
|
||||
iter = list.firstIter();
|
||||
while ( iter.pointer() ) {
|
||||
list.remove( * iter.pointer() );
|
||||
iter++;
|
||||
}
|
||||
assert(list.count()==0);
|
||||
verify (list.count()==0);
|
||||
|
||||
janeFwdIter = janeList.firstIter();
|
||||
while ( janeFwdIter.valid() ) {
|
||||
janeList.remove( * janeFwdIter.pointer() );
|
||||
janeFwdIter++;
|
||||
}
|
||||
assert(janeList.count()==0);
|
||||
verify (janeList.count()==0);
|
||||
|
||||
pJane = new jane("JA");
|
||||
janeList.add(*pJane);
|
||||
@@ -121,7 +124,7 @@ int main ()
|
||||
janeList.remove( * janeBwdIter.pointer() );
|
||||
janeBwdIter--;
|
||||
}
|
||||
assert(janeList.count()==0);
|
||||
verify (janeList.count()==0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -263,11 +263,10 @@ int ellFind (ELLLIST *pList, ELLNODE *pNode)
|
||||
*
|
||||
* NOTE: the nodes in the list are free()'d on the assumption that the node
|
||||
* structures were malloc()'d one-at-a-time and that the ELLNODE structure is
|
||||
* the first thing in the "rest of" the node structure.
|
||||
* In other words, this is a pretty worthless function.
|
||||
* the first member of the parent structure.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellFree (ELLLIST *pList, FREEFUNC freeFunc)
|
||||
void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc)
|
||||
{
|
||||
ELLNODE *nnode = pList->node.next;
|
||||
ELLNODE *pnode;
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef void (*FREEFUNC)(void *);
|
||||
#define ellLast(PLIST) ((PLIST)->node.previous)
|
||||
#define ellNext(PNODE) ((PNODE)->next)
|
||||
#define ellPrevious(PNODE) ((PNODE)->previous)
|
||||
#define ellFree(PLIST) ellFree2(PLIST, free)
|
||||
|
||||
epicsShareFunc void ellAdd (ELLLIST *pList, ELLNODE *pNode);
|
||||
epicsShareFunc void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList);
|
||||
@@ -55,8 +56,7 @@ epicsShareFunc void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode);
|
||||
epicsShareFunc ELLNODE * ellNth (ELLLIST *pList, int nodeNum);
|
||||
epicsShareFunc ELLNODE * ellNStep (ELLNODE *pNode, int nStep);
|
||||
epicsShareFunc int ellFind (ELLLIST *pList, ELLNODE *pNode);
|
||||
/* ellFree has to take a free function to work properly on Windows */
|
||||
epicsShareFunc void ellFree (ELLLIST *pList, FREEFUNC freeFunc);
|
||||
epicsShareFunc void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc);
|
||||
epicsShareFunc void ellVerify (ELLLIST *pList);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
// 1) This library is not thread safe
|
||||
//
|
||||
|
||||
#undef FD_SETSIZE
|
||||
#define FD_SETSIZE 4096
|
||||
|
||||
//
|
||||
@@ -51,15 +50,15 @@ const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
//
|
||||
epicsShareFunc fdManager::fdManager () :
|
||||
sleepQuantum ( epicsThreadSleepQuantum () ),
|
||||
fdSetsPtr ( new fd_set [fdrNEnums+1] ),
|
||||
fdSetsPtr ( new fd_set [fdrNEnums] ),
|
||||
pTimerQueue ( 0 ), maxFD ( 0 ), processInProg ( false ),
|
||||
pCBReg ( 0 )
|
||||
{
|
||||
int status = osiSockAttach ();
|
||||
assert (status);
|
||||
|
||||
for ( size_t i = 0u; i <= fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] ); // X aCC 392
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +123,10 @@ epicsShareFunc void fdManager::process (double delay)
|
||||
tv.tv_sec = static_cast<long> ( minDelay );
|
||||
tv.tv_usec = static_cast<long> ( (minDelay-tv.tv_sec) * uSecPerSec );
|
||||
|
||||
int status = select (this->maxFD, &this->fdSetsPtr[fdrRead],
|
||||
&this->fdSetsPtr[fdrWrite], &this->fdSetsPtr[fdrException], &tv);
|
||||
fd_set * pReadSet = & this->fdSetsPtr[fdrRead];
|
||||
fd_set * pWriteSet = & this->fdSetsPtr[fdrWrite];
|
||||
fd_set * pExceptSet = & this->fdSetsPtr[fdrException];
|
||||
int status = select (this->maxFD, pReadSet, pWriteSet, pExceptSet, &tv);
|
||||
|
||||
this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
|
||||
@@ -135,16 +136,17 @@ epicsShareFunc void fdManager::process (double delay)
|
||||
// Look for activity
|
||||
//
|
||||
iter=this->regList.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
tsDLIter<fdReg> tmp = iter;
|
||||
while ( iter.valid () && status > 0 ) {
|
||||
tsDLIter < fdReg > tmp = iter;
|
||||
tmp++;
|
||||
if (FD_ISSET(iter->getFD(), &this->fdSetsPtr[iter->getType()])) {
|
||||
FD_CLR(iter->getFD(), &this->fdSetsPtr[iter->getType()]);
|
||||
this->regList.remove(*iter);
|
||||
this->activeList.add(*iter);
|
||||
iter->state = fdReg::active;
|
||||
status--;
|
||||
}
|
||||
iter=tmp;
|
||||
iter = tmp;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -182,6 +184,12 @@ epicsShareFunc void fdManager::process (double delay)
|
||||
}
|
||||
else if ( status < 0 ) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
|
||||
// dont depend on flags being properly set if
|
||||
// an error is retuned from select
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
}
|
||||
|
||||
//
|
||||
// print a message if its an unexpected error
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
#endif
|
||||
#define FALSE 0
|
||||
|
||||
#ifndef LOCAL
|
||||
/* deprecated, use static */
|
||||
#ifndef LOCAL
|
||||
# define LOCAL static
|
||||
#endif
|
||||
|
||||
@@ -36,11 +37,24 @@
|
||||
# define NELEMENTS(array) (sizeof (array) / sizeof ((array) [0]))
|
||||
#endif
|
||||
|
||||
/* byte offset of member in structure*/
|
||||
/* byte offset of member in structure - deprecated, use offsetof */
|
||||
#ifndef OFFSET
|
||||
# define OFFSET(structure, member) offsetof(structure, member)
|
||||
#endif
|
||||
|
||||
/* Subtract member byte offset, returning pointer to parent object */
|
||||
#ifndef CONTAINER
|
||||
# ifdef __GNUC__
|
||||
# define CONTAINER(ptr, structure, member) ({ \
|
||||
const __typeof(((structure*)0)->member) *_ptr = (ptr); \
|
||||
(structure*)((char*)_ptr - offsetof(structure, member)); \
|
||||
})
|
||||
# else
|
||||
# define CONTAINER(ptr, structure, member) \
|
||||
((structure*)((char*)(ptr) - offsetof(structure, member)))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*Process Variable Name Size */
|
||||
/* PVNAME_STRINGSZ includes the nil terminator */
|
||||
#define PVNAME_STRINGSZ 61
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*epicsExit.c*/
|
||||
@@ -52,7 +51,7 @@ static epicsThreadPrivateId exitPvtPerThread = 0;
|
||||
|
||||
static void destroyExitPvt ( exitPvt * pep )
|
||||
{
|
||||
ellFree ( &pep->list, free );
|
||||
ellFree ( &pep->list );
|
||||
free ( pep );
|
||||
}
|
||||
|
||||
|
||||
@@ -31,25 +31,26 @@ extern "C" {
|
||||
#undef assert
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define assert(ignore) ((void) 0)
|
||||
# define assert(ignore) ((void) 0)
|
||||
#else /* NDEBUG */
|
||||
|
||||
epicsShareFunc void epicsAssert (const char *pFile, const unsigned line,
|
||||
const char *pExp, const char *pAuthorName);
|
||||
|
||||
#if (defined(__STDC__) || defined(__cplusplus)) && !defined(VAXC)
|
||||
# define assert(exp) \
|
||||
( (exp) ? (void) 0 : \
|
||||
epicsAssert( __FILE__, __LINE__, #exp, epicsAssertAuthor ) )
|
||||
#else /* __STDC__ or __cplusplus */
|
||||
# define assert(exp) \
|
||||
( (exp) ? (void) 0 : \
|
||||
epicsAssert( __FILE__, __LINE__, "", epicsAssertAuthor ) )
|
||||
#endif /* (__STDC__ or __cplusplus) and not VAXC */
|
||||
# define assert(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
|
||||
/* Compile-time checks */
|
||||
#define STATIC_JOIN(x, y) STATIC_JOIN2(x, y)
|
||||
#define STATIC_JOIN2(x, y) x ## y
|
||||
#define STATIC_ASSERT(expr) \
|
||||
typedef int STATIC_JOIN(static_assert_failed_at_line_, __LINE__) \
|
||||
[ (expr) ? 1 : -1 ]
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2009 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 Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
#ifndef epicsInterrupth
|
||||
#define epicsInterrupth
|
||||
|
||||
/*THIS MAY BE A BIG PROBLEM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsInterruptLock(void);
|
||||
epicsShareFunc void epicsShareAPI epicsInterruptUnlock(int key);
|
||||
epicsShareFunc int epicsShareAPI epicsInterruptIsInterruptContext(void);
|
||||
epicsShareFunc void epicsShareAPI epicsInterruptContextMessage(const char *message);
|
||||
epicsShareFunc int epicsInterruptLock(void);
|
||||
epicsShareFunc void epicsInterruptUnlock(int key);
|
||||
epicsShareFunc int epicsInterruptIsInterruptContext(void);
|
||||
epicsShareFunc void epicsInterruptContextMessage(const char *message);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include <epicsMath.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4723)
|
||||
#endif
|
||||
|
||||
static float makeNAN ( void )
|
||||
{
|
||||
float a = 0, b = 0;
|
||||
@@ -25,3 +30,8 @@ extern "C" {
|
||||
epicsShareDef float epicsNAN = makeNAN();
|
||||
epicsShareDef float epicsINF = makeINF();
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
|
||||
// The following is required for Solaris builds
|
||||
#undef __EXTENSIONS__
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAlgorithm.h"
|
||||
#include "epicsTime.h"
|
||||
@@ -28,10 +31,24 @@
|
||||
#include "epicsGuard.h"
|
||||
#include "errlog.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
epicsThreadRunable::~epicsThreadRunable () {}
|
||||
void epicsThreadRunable::run () {}
|
||||
void epicsThreadRunable::show ( unsigned int ) const {}
|
||||
|
||||
|
||||
class epicsThread :: unableToCreateThread :
|
||||
public exception {
|
||||
public:
|
||||
const char * what () const throw ();
|
||||
};
|
||||
|
||||
const char * epicsThread ::
|
||||
unableToCreateThread :: what () const throw ()
|
||||
{
|
||||
return "unable to create thread";
|
||||
}
|
||||
|
||||
void epicsThread :: printLastChanceExceptionMessage (
|
||||
const char * pExceptionTypeName,
|
||||
const char * pExceptionContext )
|
||||
@@ -47,7 +64,8 @@ void epicsThread :: printLastChanceExceptionMessage (
|
||||
char name [128];
|
||||
epicsThreadGetName ( this->id, name, sizeof ( name ) );
|
||||
errlogPrintf (
|
||||
"epicsThread: Unexpected C++ exception \"%s\" with type \"%s\" in thread \"%s\" at %s\n",
|
||||
"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
|
||||
@@ -110,7 +128,8 @@ void epicsThread::exit ()
|
||||
|
||||
void epicsThread::exitWait () throw ()
|
||||
{
|
||||
assert ( this->exitWait ( DBL_MAX ) );
|
||||
bool success = this->exitWait ( DBL_MAX );
|
||||
assert ( success );
|
||||
}
|
||||
|
||||
bool epicsThread::exitWait ( const double delay ) throw ()
|
||||
@@ -276,6 +295,27 @@ void epicsThreadPrivateBase::throwUnableToCreateThreadPrivate ()
|
||||
throw epicsThreadPrivateBase::unableToCreateThreadPrivate ();
|
||||
}
|
||||
|
||||
void epicsThread :: show ( unsigned level ) const throw ()
|
||||
{
|
||||
::printf ( "epicsThread at %p\n", this->id );
|
||||
if ( level > 0u ) {
|
||||
epicsThreadShow ( this->id, level - 1 );
|
||||
if ( level > 1u ) {
|
||||
::printf ( "pWaitReleaseFlag = %p\n", this->pWaitReleaseFlag );
|
||||
::printf ( "begin = %c, cancel = %c, terminated = %c\n",
|
||||
this->begin ? 'T' : 'F',
|
||||
this->cancel ? 'T' : 'F',
|
||||
this->terminated ? 'T' : 'F' );
|
||||
this->runable.show ( level - 2u );
|
||||
this->mutex.show ( level - 2u );
|
||||
::printf ( "general purpose event\n" );
|
||||
this->event.show ( level - 2u );
|
||||
::printf ( "exit event\n" );
|
||||
this->exitEvent.show ( level - 2u );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static epicsThreadOnceId okToBlockOnce = EPICS_THREAD_ONCE_INIT;
|
||||
epicsThreadPrivateId okToBlockPrivate;
|
||||
|
||||
@@ -149,6 +149,7 @@ public:
|
||||
bool isSuspended () const throw ();
|
||||
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 ();
|
||||
@@ -158,7 +159,7 @@ public:
|
||||
static void setOkToBlock ( bool isOkToBlock ) throw ();
|
||||
|
||||
/* exceptions */
|
||||
class unableToCreateThread {};
|
||||
class unableToCreateThread;
|
||||
private:
|
||||
epicsThreadRunable & runable;
|
||||
epicsThreadId id;
|
||||
|
||||
@@ -59,7 +59,7 @@ static struct taskVar *taskVarHead;
|
||||
/*
|
||||
* Support for `once-only' execution
|
||||
*/
|
||||
static int initialized;
|
||||
static int initialized = 0;
|
||||
static epicsMutexId onceMutex;
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2009 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 Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* osi/default/osdInterrupt.c */
|
||||
|
||||
/* Author: Marty Kraimer Date: 15JUL99 */
|
||||
|
||||
/* This is a version that does not allow osi calls at interrupt level */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -21,34 +18,41 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsThread.h"
|
||||
#include "cantProceed.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsInterrupt.h"
|
||||
|
||||
static epicsMutexId globalLock=0;
|
||||
static int firstTime = 1;
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsInterruptLock()
|
||||
static epicsMutexId globalLock = NULL;
|
||||
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
static void initOnce(void *junk)
|
||||
{
|
||||
if(firstTime) {
|
||||
globalLock = epicsMutexMustCreate();
|
||||
firstTime = 0;
|
||||
}
|
||||
epicsMutexMustLock(globalLock);
|
||||
return(0);
|
||||
globalLock = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsInterruptUnlock(int key)
|
||||
epicsShareFunc int epicsInterruptLock()
|
||||
{
|
||||
if(firstTime) cantProceed(
|
||||
"epicsInterruptUnlock called before epicsInterruptLock\n");
|
||||
epicsThreadOnce(&onceId, initOnce, NULL);
|
||||
epicsMutexMustLock(globalLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsInterruptUnlock(int key)
|
||||
{
|
||||
if (!globalLock)
|
||||
cantProceed("epicsInterruptUnlock called before epicsInterruptLock\n");
|
||||
epicsMutexUnlock(globalLock);
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsInterruptIsInterruptContext() { return(0);}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsInterruptContextMessage(const char *message)
|
||||
epicsShareFunc int epicsInterruptIsInterruptContext()
|
||||
{
|
||||
errlogPrintf("%s",message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsInterruptContextMessage(const char *message)
|
||||
{
|
||||
errlogPrintf("%s", message);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,9 @@ fdmgrTest_SRCS += fdmgrTest.c
|
||||
fdmgrTest_LIBS += ca
|
||||
# FIXME: program never exits.
|
||||
|
||||
TESTPROD_HOST += cvtFastPerform
|
||||
cvtFastPerform_SRCS += cvtFastPerform.cpp
|
||||
testHarness_SRCS += cvtFastPerform.cpp
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
union address {
|
||||
struct sockaddr_in ia;
|
||||
struct sockaddr sa;
|
||||
@@ -73,7 +76,7 @@ circuit::circuit ( SOCKET sockIn ) :
|
||||
recvWakeup ( false ),
|
||||
sendWakeup ( false )
|
||||
{
|
||||
assert ( this->sock != INVALID_SOCKET );
|
||||
verify ( this->sock != INVALID_SOCKET );
|
||||
}
|
||||
|
||||
bool circuit::recvWakeupDetected () const
|
||||
@@ -89,7 +92,7 @@ bool circuit::sendWakeupDetected () const
|
||||
void circuit::shutdown ()
|
||||
{
|
||||
int status = ::shutdown ( this->sock, SHUT_RDWR );
|
||||
assert ( status == 0 );
|
||||
verify ( status == 0 );
|
||||
}
|
||||
|
||||
void circuit::signal ()
|
||||
@@ -141,14 +144,14 @@ clientCircuit::clientCircuit ( const address & addrIn ) :
|
||||
address tmpAddr = addrIn;
|
||||
int status = ::connect (
|
||||
this->sock, & tmpAddr.sa, sizeof ( tmpAddr ) );
|
||||
assert ( status == 0 );
|
||||
verify ( status == 0 );
|
||||
|
||||
circuit * pCir = this;
|
||||
this->id = epicsThreadCreate (
|
||||
"client circuit", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
socketRecvTest, pCir );
|
||||
assert ( this->id );
|
||||
verify ( this->id );
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +169,7 @@ server::server ( const address & addrIn ) :
|
||||
sock ( epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ),
|
||||
id ( 0 ), exit ( false )
|
||||
{
|
||||
assert ( this->sock != INVALID_SOCKET );
|
||||
verify ( this->sock != INVALID_SOCKET );
|
||||
|
||||
// setup server side
|
||||
address tmpAddr = addrIn;
|
||||
@@ -177,7 +180,7 @@ server::server ( const address & addrIn ) :
|
||||
testAbort ( "Stop all CA servers before running this test." );
|
||||
}
|
||||
status = listen ( this->sock, 10 );
|
||||
assert ( status == 0 );
|
||||
verify ( status == 0 );
|
||||
}
|
||||
|
||||
void server::start ()
|
||||
@@ -186,7 +189,7 @@ void server::start ()
|
||||
"server daemon", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
serverDaemon, this );
|
||||
assert ( this->id );
|
||||
verify ( this->id );
|
||||
}
|
||||
|
||||
void server::daemon ()
|
||||
@@ -197,9 +200,9 @@ void server::daemon ()
|
||||
osiSocklen_t addressSize = sizeof ( addr );
|
||||
SOCKET ns = accept ( this->sock,
|
||||
& addr.sa, & addressSize );
|
||||
assert ( ns != INVALID_SOCKET );
|
||||
verify ( ns != INVALID_SOCKET );
|
||||
circuit * pCir = new serverCircuit ( ns );
|
||||
assert ( pCir );
|
||||
verify ( pCir );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +214,7 @@ serverCircuit::serverCircuit ( SOCKET sockIn ) :
|
||||
"server circuit", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
socketRecvTest, pCir );
|
||||
assert ( threadId );
|
||||
verify ( threadId );
|
||||
}
|
||||
|
||||
const char * serverCircuit::pName ()
|
||||
@@ -253,7 +256,7 @@ MAIN(blockingSockTest)
|
||||
clientCircuit client ( addr );
|
||||
|
||||
epicsThreadSleep ( 1.0 );
|
||||
assert ( ! client.recvWakeupDetected () );
|
||||
verify ( ! client.recvWakeupDetected () );
|
||||
|
||||
client.shutdown ();
|
||||
epicsThreadSleep ( 1.0 );
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include "bucketLib.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
MAIN(buckTest)
|
||||
{
|
||||
unsigned id1;
|
||||
@@ -36,35 +39,35 @@ MAIN(buckTest)
|
||||
id1 = 0x1000a432;
|
||||
pValSave1 = "fred";
|
||||
s = bucketAddItemUnsignedId(pb, &id1, pValSave1);
|
||||
assert (s == S_bucket_success);
|
||||
verify (s == S_bucket_success);
|
||||
|
||||
pValSave2 = "jane";
|
||||
id2 = 0x0000a432;
|
||||
s = bucketAddItemUnsignedId(pb, &id2, pValSave2);
|
||||
assert (s == S_bucket_success);
|
||||
verify (s == S_bucket_success);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id1);
|
||||
assert(pVal == pValSave1);
|
||||
verify (pVal == pValSave1);
|
||||
pVal = bucketLookupItemUnsignedId(pb, &id2);
|
||||
assert(pVal == pValSave2);
|
||||
verify (pVal == pValSave2);
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
|
||||
143
src/libCom/test/cvtFastPerform.cpp
Normal file
143
src/libCom/test/cvtFastPerform.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
// Author: Jeff Hill, LANL
|
||||
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <cstdlib>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "epicsStdio.h"
|
||||
#include "cvtFast.h"
|
||||
#include "epicsTime.h"
|
||||
#include "testMain.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef void ( * PTestFunc ) ( const double &, char * pBug, size_t bufSize );
|
||||
|
||||
class Test {
|
||||
public:
|
||||
Test ();
|
||||
void execute ();
|
||||
protected:
|
||||
char _pDst[128];
|
||||
double _srcVal;
|
||||
unsigned short _prec;
|
||||
static unsigned const _nUnrolled = 10;
|
||||
static const unsigned _uSecPerSec = 1000000;
|
||||
static unsigned const _nIterations = 10000;
|
||||
virtual void _target () = 0;
|
||||
void _measure ();
|
||||
Test ( const Test & );
|
||||
Test & operator = ( Test & );
|
||||
};
|
||||
|
||||
class TestCvtFastDouble : public Test {
|
||||
protected:
|
||||
void _target ();
|
||||
};
|
||||
|
||||
class TestSNPrintf : public Test {
|
||||
protected:
|
||||
void _target ();
|
||||
};
|
||||
|
||||
Test ::
|
||||
Test () :
|
||||
_srcVal ( 0.0 ), _prec ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void Test :: execute ()
|
||||
{
|
||||
static const unsigned lowPrecision = 2;
|
||||
static const unsigned highPrecision = DBL_MANT_DIG;
|
||||
|
||||
for ( unsigned i = 0; i < 3; i++ ) {
|
||||
double mVal = rand ();
|
||||
mVal /= (RAND_MAX + 1);
|
||||
double fEVal = rand ();
|
||||
fEVal /= (RAND_MAX + 1);
|
||||
fEVal *= DBL_MAX_EXP - DBL_MIN_EXP;
|
||||
fEVal += DBL_MIN_EXP;
|
||||
int eVal = static_cast < int > ( fEVal + 0.5 );
|
||||
_srcVal = ldexp ( mVal, eVal );
|
||||
for ( _prec = lowPrecision;
|
||||
_prec <= highPrecision; _prec += 4u ) {
|
||||
_measure ();
|
||||
}
|
||||
_srcVal = rand ();
|
||||
_srcVal /= (RAND_MAX + 1);
|
||||
_srcVal *= 10.0;
|
||||
_srcVal -= 5.0;
|
||||
for ( _prec = lowPrecision;
|
||||
_prec <= highPrecision; _prec += 4u ) {
|
||||
_measure ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Test :: _measure ()
|
||||
{
|
||||
epicsTime beg = epicsTime :: getCurrent ();
|
||||
for ( unsigned i = 0; i < _nIterations; i++ ) {
|
||||
_target ();
|
||||
}
|
||||
epicsTime end = epicsTime :: getCurrent ();
|
||||
double elapsed = end - beg;
|
||||
elapsed /= _nIterations * _nUnrolled;
|
||||
elapsed *= _uSecPerSec;
|
||||
printf ( " %4.4f usec, prec=%i, val=%4.4g, for %s\n",
|
||||
elapsed, _prec, _srcVal, typeid ( *this ).name () );
|
||||
}
|
||||
|
||||
void TestCvtFastDouble :: _target ()
|
||||
{
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
cvtDoubleToString ( _srcVal, _pDst, _prec );
|
||||
}
|
||||
|
||||
void TestSNPrintf :: _target ()
|
||||
{
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g",
|
||||
static_cast < int > ( _prec ), _srcVal );
|
||||
}
|
||||
|
||||
MAIN(cvtFastPerform)
|
||||
{
|
||||
TestCvtFastDouble testCvtFastDouble;
|
||||
TestSNPrintf testSNPrintf;
|
||||
|
||||
testCvtFastDouble.execute ();
|
||||
testSNPrintf.execute ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -281,7 +281,7 @@ MAIN(epicsCalcTest)
|
||||
testCalc("finite(-Inf,1,2)", 0);
|
||||
testExpr(isinf(0));
|
||||
testExpr(isinf(Inf));
|
||||
testExpr(isinf(-Inf));
|
||||
testExpr(!!isinf(-Inf)); // Some GCCs return -1/0/+1 rather than 0/+1
|
||||
testExpr(isinf(NaN));
|
||||
testExpr(isnan(0));
|
||||
testExpr(isnan(Inf));
|
||||
|
||||
@@ -161,7 +161,7 @@ MAIN(epicsEllTest)
|
||||
testOk1(ellFind(&list2, ellNth(&list2, 10)) == 10);
|
||||
testOk1(ellFind(&list1, ellNth(&list1, 11)) == 11);
|
||||
|
||||
ellFree(&list2, free);
|
||||
ellFree(&list2);
|
||||
testOk1(ellCount(&list2) == 0);
|
||||
|
||||
pick = (struct myItem *)ellFirst(&list1);
|
||||
@@ -190,7 +190,7 @@ MAIN(epicsEllTest)
|
||||
pitem = (struct myItem *)ellNStep(&pitem->node, -4);
|
||||
testOk1(pitem->num == 7);
|
||||
|
||||
ellFree(&list1, free);
|
||||
ellFree2(&list1, free);
|
||||
testOk1(ellCount(&list1) == 0);
|
||||
|
||||
return testDone();
|
||||
|
||||
@@ -36,6 +36,7 @@ int ringPointerTest(void);
|
||||
int ringBytesTest(void);
|
||||
int blockingSockTest(void);
|
||||
int taskwdTest(void);
|
||||
int cvtFastPerform(void);
|
||||
int epicsExitTest(void);
|
||||
|
||||
void epicsRunLibComTests(void)
|
||||
@@ -90,6 +91,8 @@ void epicsRunLibComTests(void)
|
||||
|
||||
runTest(taskwdTest);
|
||||
|
||||
runTest(cvtFastPerform);
|
||||
|
||||
/*
|
||||
* Exit must come last as it never returns
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
static const double delayVerifyOffset = 1.0; // sec
|
||||
|
||||
@@ -368,7 +370,7 @@ epicsTimerNotify::expireStatus periodicVerify::expire ( const epicsTime & )
|
||||
for ( unsigned i = 0u; i < 1000; i++ ) {
|
||||
root = sqrt ( root );
|
||||
}
|
||||
assert ( ! this->cancelCalled );
|
||||
verify ( ! this->cancelCalled );
|
||||
double delay = rand ();
|
||||
delay = delay / RAND_MAX;
|
||||
delay /= 10.0;
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include "epicsAssert.h"
|
||||
#include "cadef.h"
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
static const unsigned uSecPerSec = 1000000;
|
||||
|
||||
typedef struct cbStructCreateDestroyFD {
|
||||
@@ -38,12 +41,12 @@ void fdCreateDestroyHandler (void *pArg, int fd, int open)
|
||||
if (open) {
|
||||
printf ("new fd = %d\n", fd);
|
||||
status = fdmgr_add_callback (pCBFD->pfdm, fd, fdi_read, fdHandler, pArg);
|
||||
assert (status==0);
|
||||
verify (status==0);
|
||||
}
|
||||
else {
|
||||
printf ("terminated fd = %d\n", fd);
|
||||
status = fdmgr_clear_callback (pCBFD->pfdm, fd, fdi_read);
|
||||
assert (status==0);
|
||||
verify (status==0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,13 +77,13 @@ void testTimer (fdctx *pfdm, double delay)
|
||||
tmo.tv_sec = (unsigned long) delay;
|
||||
tmo.tv_usec = (unsigned long) ((delay - tmo.tv_sec) * uSecPerSec);
|
||||
aid = fdmgr_add_timeout (pfdm, &tmo, alarmCB, &cbs);
|
||||
assert (aid!=fdmgrNoAlarm);
|
||||
verify (aid!=fdmgrNoAlarm);
|
||||
|
||||
while (!cbs.done) {
|
||||
tmo.tv_sec = (unsigned long) delay;
|
||||
tmo.tv_usec = (unsigned long) ((delay - tmo.tv_sec) * uSecPerSec);
|
||||
status = fdmgr_pend_event (pfdm, &tmo);
|
||||
assert (status==0);
|
||||
verify (status==0);
|
||||
}
|
||||
|
||||
measuredDelay = epicsTimeDiffInSeconds (&cbs.time, &begin);
|
||||
@@ -98,7 +101,7 @@ int main (int argc, char **argv)
|
||||
chid chan;
|
||||
|
||||
pfdm = fdmgr_init ();
|
||||
assert (pfdm);
|
||||
verify (pfdm);
|
||||
|
||||
SEVCHK (ca_task_initialize(), NULL);
|
||||
cbsfd.pfdm = pfdm;
|
||||
@@ -121,12 +124,12 @@ int main (int argc, char **argv)
|
||||
tmo.tv_usec = 100000;
|
||||
cbsfd.trig = 0;
|
||||
status = fdmgr_pend_event (pfdm, &tmo);
|
||||
assert (status==0);
|
||||
verify (status==0);
|
||||
ca_poll ();
|
||||
}
|
||||
|
||||
status = fdmgr_delete (pfdm);
|
||||
assert (status==0);
|
||||
verify (status==0);
|
||||
|
||||
printf ( "Test Complete\n" );
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
\*************************************************************************/
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "epicsGeneralTime.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
extern void epicsRunLibComTests(void);
|
||||
generalTimeReport(1);
|
||||
epicsRunLibComTests();
|
||||
epicsExit(0);
|
||||
return 0;
|
||||
|
||||
@@ -189,12 +189,6 @@ epicsTimer::expireInfo timer::getExpireInfo () const
|
||||
void timer::show ( unsigned int level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->queue.mutex );
|
||||
const char * pName = "<no notify attached>";
|
||||
const char *pStateName;
|
||||
|
||||
if ( this->pNotify ) {
|
||||
pName = typeid ( *this->pNotify ).name ();
|
||||
}
|
||||
double delay;
|
||||
if ( this->curState == statePending || this->curState == stateActive ) {
|
||||
try {
|
||||
@@ -207,6 +201,7 @@ void timer::show ( unsigned int level ) const
|
||||
else {
|
||||
delay = -DBL_MAX;
|
||||
}
|
||||
const char *pStateName;
|
||||
if ( this->curState == statePending ) {
|
||||
pStateName = "pending";
|
||||
}
|
||||
@@ -219,8 +214,8 @@ void timer::show ( unsigned int level ) const
|
||||
else {
|
||||
pStateName = "corrupt";
|
||||
}
|
||||
printf ( "%s, state = %s, delay = %f\n",
|
||||
pName, pStateName, delay );
|
||||
printf ( "timer, state = %s, delay = %f\n",
|
||||
pStateName, delay );
|
||||
if ( level >= 1u && this->pNotify ) {
|
||||
this->pNotify->show ( level - 1u );
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user