Compare commits

...

126 Commits

Author SHA1 Message Date
Andrew Johnson
c28520bea6 Adjust test 66 so it doesn't fail if the gcc optimizer result gives -1 but
glibc returns +1.  Both are correct, gcc is following a newer standard.
2009-08-21 14:49:01 +00:00
Andrew Johnson
bd4784a858 Added Mantis 361. 2009-08-21 14:38:01 +00:00
Jeff Hill
8c2278784c fixed mantis 361 2009-08-21 00:53:55 +00:00
Andrew Johnson
2caf1a4f50 Janet's Build Dependency note. 2009-08-20 22:59:10 +00:00
Jeff Hill
1fba8dd866 improved fdManagerVerify progress diagnostics 2009-08-20 22:29:53 +00:00
Andrew Johnson
87eace1bd4 Fix for solaris compiler complaint about ambiguity of 'exception'. 2009-08-18 19:26:37 +00:00
Jeff Hill
db3a655374 fixed improper calculation of signal needed state in postEvent
(this is an issue I introduced when writing the patch where IO
and subscription update events are maintained on seperate
and independent queues). The issue does not exist in an
EPICS base release.
2009-08-18 00:40:00 +00:00
Jeff Hill
8ae0c8960f corrected spelling in message 2009-08-18 00:36:22 +00:00
Jeff Hill
ec26c0dc52 o track number of async read and writes independently
o when the last async write occurs, check to see if a value
is cached and write it immediately (instead of waiting for
aync io object's ctor to run. This allows the regression
tests to pass.
2009-08-18 00:32:48 +00:00
Andrew Johnson
ea539fceb6 Corrected Mantis bug number. 2009-08-17 17:51:43 +00:00
Jeff Hill
782ff1b303 improved create channel unexpected exception diagnostic 2009-08-14 19:12:50 +00:00
Jeff Hill
2fb6b2100f improved test diagnostic 2009-08-14 17:44:33 +00:00
Jeff Hill
0012042a5e accomodate archaic vxWorks gnu compiler 2009-08-14 17:31:34 +00:00
Jeff Hill
e0d16659e1 improved TCP circuit creation failure exception diagnostics 2009-08-14 16:57:48 +00:00
Jeff Hill
8303cf053b improved VC creation failure exception diagnostics 2009-08-14 16:56:31 +00:00
Jeff Hill
78fc566dc4 improved thread creation failure exception diagnostics 2009-08-14 16:54:45 +00:00
Jeff Hill
3961c81740 added additional R3.14.11 ca fixes 2009-08-14 00:56:08 +00:00
Jeff Hill
0fdda3f794 back out prev change 2009-08-14 00:29:56 +00:00
Jeff Hill
9802e6c629 cosmetic 2009-08-14 00:24:32 +00:00
Jeff Hill
547c5d06ea improved the maint of the asych io count in off normal situations 2009-08-14 00:24:09 +00:00
Jeff Hill
50ddd62502 o always arm the send independent of how many messages are placed
in the out buf. The send will not arm if the out buf is empty
o when receiving the io blocked state notify callback always reactivate the
receive if space is available
2009-08-13 23:55:03 +00:00
Jeff Hill
9fc48c9a6b always arm the send independent of how many messages are placed
in the out buf. The send will not arm if the out buf is empty.
2009-08-13 23:51:40 +00:00
Jeff Hill
e4075da4d7 o added new ioQue so the server will not wedge one of its clients
when simultaneouly in flow control mode and also asynchronous io
postponed mode.
o simplified the status from the process func because callers should
not need to know how many messages have been sent
2009-08-13 23:49:59 +00:00
Jeff Hill
8ace886cfe o added new ioQue so the server will not wedge one of its clients
when simultaneouly in flow control mode and also asynchronous io
postponed mode.
o simplified the status from the process func because callers should
not need to know how many messages have been sent
2009-08-13 23:42:37 +00:00
Jeff Hill
6c61c0de34 signal the io blocked list each time that server centric async io completes 2009-08-13 23:38:41 +00:00
Jeff Hill
e581e88223 simplified the return from eventSysProcess because callers should not need to
know how many messages were sent
2009-08-13 23:37:30 +00:00
Jeff Hill
f4cbdec5ee removed io blocked list signal because the base class does not
know if the blocked list is with the pv or the server
2009-08-13 23:32:18 +00:00
Jeff Hill
b344841365 fixed the following issues with detection of flow control mode
o the flow control contig frame thresh should be based on max array size
o it appears that the wakeup mechanism for the send thread, who sends
the flow control on/off messages was broken
o looking at full buffers isnt a perfect detection scheme compared to
the simpler approach of just checking to see if bytes are pending in
the socket before calling recv
2009-08-13 23:29:02 +00:00
Jeff Hill
b867dabad0 cache the client ctx ref prior to calling callback in case they delete the
channel in the callback
2009-08-13 22:46:47 +00:00
Jeff Hill
0cea525682 destroy putCallback prior to calling callback in case they delete the
channel in the callback
2009-08-13 22:44:30 +00:00
Jeff Hill
2df7da052a destroy getCallback prior to calling callback in case they delete the
channel in the callback
2009-08-13 22:43:21 +00:00
Jeff Hill
59b820d2f5 added missing epicsShareExtern 2009-08-13 22:42:05 +00:00
Jeff Hill
3fda8dc2b0 added test failure diagnostic 2009-08-13 22:40:02 +00:00
Andrew Johnson
3a335c88f0 Move Jeff's notes to the top. 2009-08-13 16:06:59 +00:00
Jeff Hill
44a6e9a005 added SEVCHK string 2009-08-12 00:37:10 +00:00
Jeff Hill
1f129d3739 added bullet under mantis 329 for R3.14.11 2009-08-10 23:20:59 +00:00
Jeff Hill
720236ed39 added CA, PCA, and some libCom fixes for R3.14.11 2009-08-10 22:51:09 +00:00
Jeff Hill
57c9f9344f improved show function 2009-08-10 21:51:07 +00:00
Andrew Johnson
64cb41f489 $(SHRLIB_PREFIX) $(LIB_PREFIX) mismatch 2009-08-10 21:50:11 +00:00
Jeff Hill
6fe047731f added shjow func to epicsThread class 2009-08-10 21:48:50 +00:00
Jeff Hill
56c4c92588 improved show diagnostic 2009-08-10 21:41:59 +00:00
Andrew Johnson
562db1e24c Application configure files. 2009-08-10 21:15:27 +00:00
Janet B. Anderson
1b70afa54b Moved ECHO definition to preceed 'ifdef T_A' defines. 2009-08-10 16:49:55 +00:00
Janet B. Anderson
f316b4ca81 Change echo macro back to @echo. We never want to comment help messages. 2009-08-10 16:41:28 +00:00
Andrew Johnson
6d8cfeef01 Explain the epicsCalcTest #66 failure on Linux. 2009-08-07 21:26:47 +00:00
Andrew Johnson
b1b72e8cf0 updated comment text 2009-08-07 20:24:53 +00:00
Andrew Johnson
cde59e262b gpHash argument change. 2009-08-07 15:53:28 +00:00
Jeff Hill
40b6d1b0ba moved IO pending count to caServer 2009-08-06 02:24:00 +00:00
Jeff Hill
4464cfedaa fixed warning message 2009-08-06 01:36:56 +00:00
Jeff Hill
b9fbf2e45b fixed error code numbering 2009-08-06 01:36:30 +00:00
Jeff Hill
42ce1bd2db o reset pendingResponseStatus, reqPayloadNeedsByteSwap,
responseIsPending, and pValueRead whenever removing a
message from the stream
o eliminated error prone reuse of status variables
o dont allow service to postpone IO when no IO is pending against the target
o be extra careful not to do things twice when send blocked or IO postponed
2009-08-06 00:06:59 +00:00
Jeff Hill
7de356519d o added pValueRead gdd snart pointer
o payloadNeedsByteSwap renamed to reqPayloadNeedsByteSwap
o added issuePosponeWhenNonePendingWarning static func
2009-08-05 23:58:40 +00:00
Jeff Hill
ff5ca5e041 added ioIsPending func 2009-08-05 23:56:26 +00:00
Jeff Hill
d1bb71809b added S_cas_posponeWhenNonePending status 2009-08-05 23:56:01 +00:00
Jeff Hill
7a49a17d1b removed unused template instantiation 2009-08-04 23:32:32 +00:00
Jeff Hill
7cf77b40e6 updated the example to implement casPV::writeNotify implementing similar semantics to an IOC 2009-08-04 23:31:13 +00:00
Andrew Johnson
e387c06f59 STATIC_ASSERT(). 2009-08-04 19:51:19 +00:00
Andrew Johnson
c035566d7d Use compile-time assertions, from Micheal Davidsaver. 2009-08-04 19:10:30 +00:00
Andrew Johnson
57e5406684 Added STATIC_ASSERT macro.
Removed assert() definition for pre-ANSI C compilers.
2009-08-04 19:07:07 +00:00
Jeff Hill
b4948b4ff6 fixed missing space in command line help string 2009-08-04 17:50:56 +00:00
Andrew Johnson
15f6b8c682 Update dbDefs.h changes. 2009-08-04 17:11:02 +00:00
Andrew Johnson
4868904839 Added CONTAINER macro, from Micheal Davidsaver (BNL). 2009-08-04 16:31:06 +00:00
Andrew Johnson
1a2fa1bc86 Some cleanup, mostly spacing. 2009-08-03 22:22:45 +00:00
Jeff Hill
e3a61ce4e4 fix for mantis 358 2009-08-03 22:09:52 +00:00
Andrew Johnson
efdee3c31a Escaping doesn't work on all Win32 platform combinations.
Removed -e option again.
2009-08-03 22:03:33 +00:00
Andrew Johnson
ee44663d89 errSymFind() removal. 2009-08-03 17:14:25 +00:00
Andrew Johnson
90db5a4ab0 Deleted test code which was moved to libCom/test some time ago. 2009-08-03 17:13:04 +00:00
Jeff Hill
72dbaa8a0f auto-adjust iterations for payload size 2009-07-31 23:26:16 +00:00
Jeff Hill
458689a252 fixed formating 2009-07-31 22:12:32 +00:00
Jeff Hill
0daf347ef3 fixed incorrect Mbps calc based on rounded payload size 2009-07-31 22:01:53 +00:00
Jeff Hill
e32d8d77dc fixed gnu compiler issues 2009-07-31 21:43:03 +00:00
Jeff Hill
ffe7823c22 report send and recv Mbps independently to better understand fullduplex ethernet bw 2009-07-31 21:23:26 +00:00
Jeff Hill
913f724ebf fix for mantis 357 2009-07-31 19:47:46 +00:00
Andrew Johnson
4e5fa9b6b3 Reverted patch that added architecture-specific compiler flags,
Micheal Abbott didn't like it.
2009-07-31 17:38:27 +00:00
Andrew Johnson
a6b0ffebca Fixed build issue. 2009-07-31 16:46:12 +00:00
Jeff Hill
7246366222 fixed gnu warning 2009-07-31 15:52:32 +00:00
Jeff Hill
191668023b independent of whether receive bytes are pending or not. This improves
event latency, and allows events to flow if we are blocked due to the
service postponing an IO operation. This was a bug fix.

o call processMessage directly from the IO completion callback
that restarts when in an IO postponement state. This makes the logic easier
to understand and maintain, but isnt a functional change
o call processMessage directly from the receive callback.
This makes the logic easier to understand and maintain, but isnt
a functional change
o call processMessage directly from the send callback.
This makes the logic easier to understand and maintain, but isnt
a functional change
o removed the eventFlush function
2009-07-31 00:47:56 +00:00
Jeff Hill
7a23b74a76 o when processing subscription update events, always activate the send
independent of whether receive bytes are pending or not. This improves
event latency, and allows events to flow if we are blocked due to the
service postponing an IO operation. This was a bug fix.
o when finishing processing input activate a send if more than one half
of the TCP buffering would be used. In the past the send was not activated
until either the send buffer was full or the receive buffer (including any
bytes waiting in the socket) was empty. This could cause latency and
performance issues because send receive piplining would not occur if they
have very large buffers due to a large EPICS_CA_MAX_ARRAY_SIZE.
o always activate a send if we enter a service is postponing IO state. Users
would probably prefer to receive past responses and not wait until the
postponed IO initiates.

o casStrmClient::inBufBytesAvailable renamed to
casStrmClient:: inBufBytesPending reflecting the fact that we nlonger use
a socket ioctl to check how many bytes are pending in the sockets
input queue
o casStrmClient::outBufBytesPresent renamed to
casStrmClient::outBufBytesPending for consistency with inBufBytesPending
o removed the eventFlush function
o removed sendBlocked flag
o call processMessage directly from the IO completion callback
that restarts when in an IO postponement state. This makes the logic easier
to understand and maintain, but isnt a functional change
o call processMessage directly from the receive callback.
This makes the logic easier to understand and maintain, but isnt
a functional change
o call processMessage directly from the send callback.
This makes the logic easier to understand and maintain, but isnt
a functional change
2009-07-31 00:41:34 +00:00
Jeff Hill
511d818d18 o removed sendBlocked flag
o removed processInput function
o removed eventFlush function
o made casStreamIOWakeup and casStreamEvWakeup friends
2009-07-31 00:00:42 +00:00
Jeff Hill
f8565139c2 o removed sendBlocked flag
o removed processInput function
o removed eventFlush function
o made casDGEvWakeup, casDGIOWakeup, and
casStreamEvWakeup friends
2009-07-30 23:54:18 +00:00
Jeff Hill
30a02b365f incomingBytesPresent renamed to inCircuitBytesPending but this
function isnt currently used
2009-07-30 23:51:48 +00:00
Jeff Hill
b4bc931c72 incomingBytesPresent renamed to dgInBytesPending, but this function
is not currently used
2009-07-30 23:50:45 +00:00
Jeff Hill
e5d3815280 o removed bytesAvailable member function from inBuf because
we nolonger check the bytes in the socket  with an ioctl
o removed incomingBytesPresent virtual function from inBufClient interface
because we nolonger check the bytes in the socket  with an ioctl
2009-07-30 23:48:43 +00:00
Jeff Hill
ebd65e6e34 added an assert test 2009-07-30 23:45:14 +00:00
Jeff Hill
8c45eb4a19 o casStrmClient::inBufBytesAvailable renamed to
casStrmClient:: inBufBytesPending reflecting the fact that we nlonger use
a socket ioctl to check how many bytes are pending in the sockets
input queue
o  casStrmClient::outBufBytesPresent renamed to
casStrmClient::outBufBytesPending for consistency with inBufBytesPending
2009-07-30 23:43:21 +00:00
Jeff Hill
e1bb171f44 o casStrmClient::inBufBytesAvailable renamed to
casStrmClient:: inBufBytesPending reflecting the fact that we nlonger use
a socket ioctl to check how many bytes are pending in the sockets
input queue
o  casStrmClient::outBufBytesPresent renamed to
casStrmClient::outBufBytesPending for consistency with inBufBytesPending
o in casStrmClient :: processMsg () I forced status to S_cas_success at a couple
of loop exits. There is probably not a bug because the variable is initialized to
this value and the loop termintaes if the status isnt this value nevertheless
the corrected code is more robust to future changes.
o fixed a benign issue in casStrmClient :: processMsg () where if the user
sends a message to big for EPICS_MAX_ARRAY_SIZE and there is
currently no room in the output buffer then the user will not receive
a diagnostic message. With the patch the message will be sent later once
there is space.
2009-07-30 23:42:15 +00:00
Jeff Hill
656c2462d3 o casDGClient::inBufBytesAvailable renamed to
casDGClient :: inBufBytesPending reflecting the fact that we nlonger use
a socket ioctl to check how many bytes are pending in the sockets
input queue
o  casDGClient::outBufBytesPresent renamed to
casDGClient::outBufBytesPending for consistency with inBufBytesPending
2009-07-30 23:31:32 +00:00
Jeff Hill
f4ec20c8f0 casDGClient::inBufBytesAvailable renamed to
casDGClient :: inBufBytesPending reflecting the fact that we nlonger use
a socket ioctl to check how many bytes are pending in the sockets
input queue
2009-07-30 23:29:43 +00:00
Jeff Hill
72e1dba496 o no need to allocate or initialize one more fd_set than is used
(not a bug but messy)
o added optimization where we only check as many registered fd's
on the list as select tells us are active in its status
o added code to clear all of the  fd_set if select returns an error
(in practice this would not cause a bug other than some extra activity
that would immediately self terminate when it clear the flag in the fd_set,
and also we dont see the error message printed when select returns an error)
2009-07-30 23:21:19 +00:00
Jeff Hill
001b947702 added more excas options 2009-07-30 23:09:54 +00:00
Jeff Hill
c0d4317ade fixed broken test 2009-07-30 23:08:34 +00:00
Jeff Hill
290ec3e22c adjustable asyn delay, adjustable max simult io, added variables 2009-07-30 22:53:51 +00:00
Jeff Hill
d6b887b363 adjustable asyn delay 2009-07-30 22:51:03 +00:00
W. Eric Norum
fbebea304b Adapt to older versions of RTEMS. 2009-07-29 20:58:37 +00:00
Janet B. Anderson
dd1d2c10bd Part 2 for Fix of echo problem. 2009-07-29 20:53:02 +00:00
Janet B. Anderson
d3e3137265 Fixed echo problem when using RULES.Db when T_A is not defined. 2009-07-29 19:06:32 +00:00
Jeff Hill
d764e7d4df added "using namespace std" 2009-07-29 15:10:24 +00:00
W. Eric Norum
49ddec4294 Add cvtFastPerform to test harness. 2009-07-29 14:29:54 +00:00
Andrew Johnson
ce778819bd Update comment; can't deprecate a published API! 2009-07-28 21:11:02 +00:00
Andrew Johnson
d5bffdb13d Can't portably pass filesystem paths as command-line macros to C.
Generate a header file instead and include that.
2009-07-28 21:08:37 +00:00
Jeff Hill
ba11940aad removed debug printf 2009-07-25 01:24:50 +00:00
Jeff Hill
8725e4a67a removed debug printf 2009-07-25 01:23:18 +00:00
Jeff Hill
a6e57ba17a proper data type for socklen_t 2009-07-25 01:16:20 +00:00
Jeff Hill
7d137254af proper data type for socklen_t 2009-07-25 01:14:55 +00:00
Jeff Hill
31fb3775fd improved knowledge of the circuit's buffer size 2009-07-25 01:04:14 +00:00
Jeff Hill
1ba658b452 improved diagnostics 2009-07-25 00:44:21 +00:00
Jeff Hill
6eb25148c5 simplified tcp send interactions 2009-07-25 00:43:28 +00:00
Jeff Hill
4ade695a60 upgraded to properly test array performance 2009-07-23 23:59:04 +00:00
Andrew Johnson
bea22985b6 Generate code to abort if no DBD file loaded yet. 2009-07-23 22:13:29 +00:00
W. Eric Norum
fd6d1ce69c As reported by Michael Davidsaver.
Apparently the GeSys dynamic linker doesn't maintain C semantics.
I'm afraid that this behaviour is likely to cause lots of other problems,
but for now I'll apply the patch since it's harmless.
2009-07-23 21:04:27 +00:00
Jeff Hill
844ed6345a test also numbers in -5 to 5 range 2009-07-23 17:32:33 +00:00
Jeff Hill
7315f02888 added cvtFastPerfotm test 2009-07-23 17:25:51 +00:00
Jeff Hill
1ba6da438b partial fix for mantis 352 2009-07-23 00:23:17 +00:00
Andrew Johnson
c986597f1c Reject breaktables with slope of zero. 2009-07-22 22:58:09 +00:00
Janet B. Anderson
38b81b44be Fixed quoted string problem. 2009-07-22 20:41:09 +00:00
Andrew Johnson
8382eee11a Need quotes here too for this to work on Windows. 2009-07-22 20:34:47 +00:00
Andrew Johnson
7d80ab72b0 Escape backslashes in fullPathName output. 2009-07-22 16:43:47 +00:00
Andrew Johnson
3d86367330 Added -e option to escape back-slashes in output. 2009-07-22 16:40:30 +00:00
Janet B. Anderson
16a6357ab4 Initial version. 2009-07-22 14:12:24 +00:00
Janet B. Anderson
f4bfc3928d Fixed XDK definition for Exceed 12.0. 2009-07-21 17:56:55 +00:00
Janet B. Anderson
4282d3e9f4 Commented out XRTGRAPH definitions. 2009-07-21 17:26:34 +00:00
Janet B. Anderson
1e68d1f89b Modified EPICS_EXTENSIONS and add OAG_APPS comments. 2009-07-21 17:12:15 +00:00
Janet B. Anderson
03b6345fe0 Fixed definitions of X11_LIB and X11_INC. 2009-07-21 17:11:02 +00:00
Janet B. Anderson
055bb953b9 Fixed definition of X11_INC. 2009-07-21 17:10:26 +00:00
Janet B. Anderson
01d223fafd Updated file and directory sizes for R3.14.11. 2009-07-21 16:26:58 +00:00
Andrew Johnson
7665d1340c Clean out old stuff. 2009-07-20 23:03:53 +00:00
96 changed files with 2320 additions and 1397 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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))
#-------------------------------------------------------

View File

@@ -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

View File

@@ -4,34 +4,21 @@
<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 &mdash; 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 libCom test suite program epicsCalcTest test #66 fails on some linux
systems. This is not a bug in EPICS and will not be fixed; it actually
demonstrates that the GCC optimizer is not generating the same result for
the expression <tt>isinf(-Inf)</tt> that the glibc function returns at
runtime. Both versions return a non-zero result for infinite arguments, but
the GCC optimized version applies the sign of its infinite argument to its
return value, whereas glibc always returns +1.</li>
</ul>

View File

@@ -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

View File

@@ -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">

View File

@@ -3,16 +3,145 @@
<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-CVS 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-CVS</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>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.&lt;host-arch&gt;.Common</li>
<li>CONFIG_SITE.Common.&lt;target-arch&gt;</li>
<li>CONFIG_SITE.&lt;host-arch&gt;.&lt;target-arch&gt;</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 +150,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 &lt;stdarg.h&gt;</li>
@@ -39,6 +168,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 +406,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&nbsp;*</tt> (or a
pointer to one for <tt>gphInit()</tt>) but is now a <tt>struct
gphPvt&nbsp;*</tt> (<tt>struct gphPvt&nbsp;**</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 +615,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>

View File

@@ -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)

View File

@@ -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 &lt;n.n&gt;</td>
<td>set the delay before asynchronous operations complete (defaults to
0.1 seconds)</td>
</tr>
<tr>
<td>-an &lt;nnn&gt;</td>
<td>set the maximum number of simultaneous asynchronous operations
(defaults to 1000)</td>
</tr>
</tbody>
</table>

View File

@@ -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;
}

View File

@@ -1439,7 +1439,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 ();
}
@@ -2138,7 +2139,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;
@@ -2339,7 +2339,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 );
assert ( getResp == temp );
}
/*
* wait for all of the monitors to have correct values
@@ -2737,6 +2740,8 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
assert ( status >= 0 );
}
showProgress ( interestLevel );
status = ca_add_event ( DBR_FLOAT, newChan,
nUpdatesTester, & eventCount, & subscription );
assert ( status == ECA_NORMAL );
@@ -2751,6 +2756,8 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
assert ( status >= 0 );
}
showProgress ( interestLevel );
status = ca_clear_event ( subscription );
assert ( status == ECA_NORMAL );
@@ -2774,6 +2781,8 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
assert ( eventCount++ < 100 );
}
showProgress ( interestLevel );
status = ca_clear_channel ( newChan );
assert ( status == ECA_NORMAL );
@@ -2798,12 +2807,12 @@ 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 );
}
status = ca_pend_io ( timeoutToPendIO );
status = ca_pend_io ( 0.001 );
assert ( status == ECA_TIMEOUT );
/* wait a long time for the search interval to increase */
@@ -2989,6 +2998,10 @@ void verifyContextRundownFlush ( const char * pName, unsigned interestLevel )
ca_context_destroy ();
}
if ( i % 100 == 0 ) {
showProgress ( interestLevel );
}
}
showProgressEnd ( interestLevel );

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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 );

View File

@@ -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++;
}
}
}

View File

@@ -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

View File

@@ -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 );
}

View File

@@ -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;

View File

@@ -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 & );

View File

@@ -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

View File

@@ -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++;
}
}
}
}

View File

@@ -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 ();
}
}

View File

@@ -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 >;

View File

@@ -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 );

View File

@@ -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

View File

@@ -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;

View File

@@ -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 );
}

View File

@@ -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;

View File

@@ -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 ) {

View File

@@ -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 ) {

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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 ();

View File

@@ -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 (

View File

@@ -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 );
}

View File

@@ -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 )
{
}

View File

@@ -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()
//

View File

@@ -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 )
{

View File

@@ -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

View File

@@ -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 & );

View File

@@ -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

View File

@@ -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
//

View File

@@ -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()
//

View File

@@ -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;

View File

@@ -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;
}
//

View File

@@ -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 ();
}
}
}

View File

@@ -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 ();

View File

@@ -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 );
}

View File

@@ -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

View File

@@ -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 ()

View File

@@ -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;

View File

@@ -236,4 +236,3 @@ caNetAddr casIntfIO::serverAddress () const
{
return caNetAddr (this->addr);
}

View File

@@ -53,7 +53,7 @@ public:
clientBufMemoryManager & ) const;
caNetAddr serverAddress () const;
private:
SOCKET sock;
struct sockaddr_in addr;

View File

@@ -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()

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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 );

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -276,6 +294,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;

View File

@@ -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;

View File

@@ -59,7 +59,7 @@ static struct taskVar *taskVarHead;
/*
* Support for `once-only' execution
*/
static int initialized;
static int initialized = 0;
static epicsMutexId onceMutex;
/*

View File

@@ -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

View 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;
}

View File

@@ -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));

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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 );
}

View File

@@ -131,7 +131,10 @@ void timerQueueActive::show ( unsigned int level ) const
{
printf ( "EPICS threaded timer queue at %p\n",
static_cast <const void *> ( this ) );
if ( level >=1u ) {
if ( level > 0u ) {
// specifying level one here avoids recursive
// show callback
this->thread.show ( 1u );
this->queue.show ( level - 1u );
printf ( "reschedule event\n" );
this->rescheduleEvent.show ( level - 1u );

View File

@@ -15,59 +15,145 @@
#include "exServer.h"
exAsyncPV::exAsyncPV ( exServer & cas, pvInfo & setup,
bool preCreateFlag, bool scanOnIn,
double asyncDelayIn ) :
exScalarPV ( cas, setup, preCreateFlag, scanOnIn ),
asyncDelay ( asyncDelayIn ),
simultAsychReadIOCount ( 0u ),
simultAsychWriteIOCount ( 0u )
{
}
//
// exAsyncPV::read()
// (virtual replacement for the default)
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncReadIO *pIO;
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
pIO = new exAsyncReadIO ( this->cas, ctx, *this, valueIn );
if (!pIO) {
return S_casApp_noMemory;
pIO = new exAsyncReadIO ( this->cas, ctx,
*this, valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
}
}
this->simultAsychReadIOCount++;
return S_casApp_asyncCompletion;
}
//
// exAsyncPV::write()
// (virtual replacement for the default)
// exAsyncPV::writeNotify()
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
exAsyncWriteIO *pIO;
if ( this->simultAsychIOCount >= maxSimultAsyncIO ) {
caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
{
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
pIO = new exAsyncWriteIO ( this->cas, ctx, *this, valueIn );
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
return S_casApp_noMemory;
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
}
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
//
// exAsyncPV::write()
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
// implement the discard intermediate values, but last value
// sent always applied behavior that IOCs provide excepting
// that we will alow N requests to pend instead of a limit
// of only one imposed in the IOC
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
// Implementing a specialized update for exAsyncPV
// allows standby value to update when we update
// the PV from an asynchronous write timer expiration
// which is a better time compared to removeIO below
// which, if used, gets the reads and writes out of
// order. This type of reordering can cause the
// regression tests to fail.
caStatus exAsyncPV :: updateFromAsyncWrite ( const gdd & src )
{
caStatus stat = this->update ( src );
if ( this->simultAsychWriteIOCount <=1 &&
pStandbyValue.valid () ) {
//printf("updateFromAsyncWrite: write standby\n");
stat = this->update ( *this->pStandbyValue );
this->pStandbyValue.set ( 0 );
}
return stat;
}
void exAsyncPV::removeReadIO ()
{
if ( this->simultAsychReadIOCount > 0u ) {
this->simultAsychReadIOCount--;
}
else {
fprintf ( stderr, "inconsistent simultAsychReadIOCount?\n" );
}
}
void exAsyncPV::removeWriteIO ()
{
if ( this->simultAsychWriteIOCount > 0u ) {
this->simultAsychWriteIOCount--;
if ( this->simultAsychWriteIOCount == 0 &&
pStandbyValue.valid () ) {
//printf("removeIO: write standby\n");
this->update ( *this->pStandbyValue );
this->pStandbyValue.set ( 0 );
}
}
else {
fprintf ( stderr, "inconsistent simultAsychWriteIOCount?\n" );
}
}
//
// exAsyncWriteIO::exAsyncWriteIO()
//
exAsyncWriteIO::exAsyncWriteIO ( exServer & cas,
const casCtx & ctxIn, exAsyncPV & pvIn, const gdd & valueIn ) :
const casCtx & ctxIn, exAsyncPV & pvIn,
const gdd & valueIn, double asyncDelay ) :
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer () ), pValue(valueIn)
{
this->timer.start ( *this, 0.1 );
this->timer.start ( *this, asyncDelay );
}
//
@@ -75,23 +161,25 @@ exAsyncWriteIO::exAsyncWriteIO ( exServer & cas,
//
exAsyncWriteIO::~exAsyncWriteIO()
{
this->pv.removeIO();
this->timer.destroy ();
// if the timer hasnt expired, and the value
// hasnt been written then force it to happen
// now so that regression testing works
if ( this->pValue.valid () ) {
this->pv.update ( *this->pValue );
this->pv.updateFromAsyncWrite ( *this->pValue );
}
this->pv.removeWriteIO();
}
//
// exAsyncWriteIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncWriteIO::expire ( const epicsTime & /* currentTime */ )
epicsTimerNotify::expireStatus exAsyncWriteIO::
expire ( const epicsTime & /* currentTime */ )
{
caStatus status = this->pv.update ( *this->pValue );
assert ( this->pValue.valid () );
caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
this->pValue.set ( 0 );
this->postIOCompletion ( status );
return noRestart;
@@ -101,11 +189,12 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::expire ( const epicsTime & /* cur
// exAsyncReadIO::exAsyncReadIO()
//
exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
exAsyncPV & pvIn, gdd & protoIn ) :
exAsyncPV & pvIn, gdd & protoIn,
double asyncDelay ) :
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer() ), pProto ( protoIn )
{
this->timer.start ( *this, 0.1 );
this->timer.start ( *this, asyncDelay );
}
//
@@ -113,24 +202,22 @@ exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
//
exAsyncReadIO::~exAsyncReadIO()
{
this->pv.removeIO ();
this->pv.removeReadIO ();
this->timer.destroy ();
}
//
// exAsyncReadIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
epicsTimerNotify::expireStatus
exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
{
caStatus status;
//
// map between the prototype in and the
// current value
//
status = this->pv.exPV::readNoCtx ( this->pProto );
caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
//
// post IO completion

View File

@@ -39,16 +39,20 @@ const unsigned exServer::pvListNElem = NELEMENTS (exServer::pvList);
// static on-the-fly PVs
//
pvInfo exServer::billy (-1.0, "billybob", 10.0f, -10.0f, aitEnumFloat64, excasIoAsync, 1u);
pvInfo exServer::bloaty (-1.0, "bloaty", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 100000u);
pvInfo exServer::bloater (.010, "bloater", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 10000u);
pvInfo exServer::bloaty (.010, "bloaty", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 100000u);
//
// exServer::exServer()
//
exServer::exServer ( const char * const pvPrefix,
unsigned aliasCount, bool scanOnIn,
bool asyncScan ) :
pTimerQueue ( 0 ), simultAsychIOCount ( 0u ),
scanOn ( scanOnIn )
bool asyncScan, double asyncDelayIn,
unsigned maxSimultAsyncIOIn ) :
pTimerQueue ( 0 ), simultAsychIOCount ( 0u ),
_maxSimultAsyncIO ( maxSimultAsyncIOIn ),
asyncDelay ( asyncDelayIn ), scanOn ( scanOnIn )
{
unsigned i;
exPV *pPV;
@@ -74,7 +78,7 @@ exServer::exServer ( const char * const pvPrefix,
// pre-create all of the simple PVs that this server will export
//
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
pPV = pPVI->createPV (*this, true, scanOnIn);
pPV = pPVI->createPV (*this, true, scanOnIn, this->asyncDelay );
if (!pPV) {
fprintf(stderr, "Unable to create new PV \"%s\"\n",
pPVI->getName());
@@ -103,6 +107,8 @@ exServer::exServer ( const char * const pvPrefix,
//
sprintf ( pvAlias, pNameFmtStr, pvPrefix, billy.getName() );
this->installAliasName ( billy, pvAlias );
sprintf ( pvAlias, pNameFmtStr, pvPrefix, bloater.getName() );
this->installAliasName ( bloater, pvAlias );
sprintf ( pvAlias, pNameFmtStr, pvPrefix, bloaty.getName() );
this->installAliasName ( bloaty, pvAlias );
}
@@ -187,18 +193,19 @@ pvExistReturn exServer::pvExistTest // X aCC 361
return pverExistsHere;
}
else {
if ( this->simultAsychIOCount >= maxSimultAsyncIO ) {
if ( this->simultAsychIOCount >= this->_maxSimultAsyncIO ) {
return pverDoesNotExistHere;
}
this->simultAsychIOCount++;
exAsyncExistIO *pIO;
pIO = new exAsyncExistIO ( pvi, ctxIn, *this );
if (pIO) {
exAsyncExistIO * pIO =
new exAsyncExistIO ( pvi, ctxIn, *this );
if ( pIO ) {
return pverAsyncCompletion;
}
else {
this->simultAsychIOCount--;
return pverDoesNotExistHere;
}
}
@@ -228,7 +235,7 @@ pvAttachReturn exServer::pvAttach // X aCC 361
// If this is a synchronous PV create the PV now
//
if (pvi.getIOType() == excasIoSync) {
pPV = pvi.createPV(*this, false, this->scanOn);
pPV = pvi.createPV(*this, false, this->scanOn, this->asyncDelay );
if (pPV) {
return *pPV;
}
@@ -240,18 +247,20 @@ pvAttachReturn exServer::pvAttach // X aCC 361
// Initiate async IO if this is an async PV
//
else {
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
if (this->simultAsychIOCount>=this->_maxSimultAsyncIO) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
exAsyncCreateIO *pIO =
new exAsyncCreateIO(pvi, *this, ctx, this->scanOn);
new exAsyncCreateIO ( pvi, *this, ctx,
this->scanOn, this->asyncDelay );
if (pIO) {
return S_casApp_asyncCompletion;
}
else {
this->simultAsychIOCount--;
return S_casApp_noMemory;
}
}
@@ -281,8 +290,8 @@ class epicsTimer & exServer::createTimer ()
//
// pvInfo::createPV()
//
exPV *pvInfo::createPV ( exServer & cas,
bool preCreateFlag, bool scanOn )
exPV *pvInfo::createPV ( exServer & cas, bool preCreateFlag,
bool scanOn, double asyncDelay )
{
if (this->pPV) {
return this->pPV;
@@ -301,7 +310,8 @@ exPV *pvInfo::createPV ( exServer & cas,
pNewPV = new exScalarPV ( cas, *this, preCreateFlag, scanOn );
break;
case excasIoAsync:
pNewPV = new exAsyncPV ( cas, *this, preCreateFlag, scanOn );
pNewPV = new exAsyncPV ( cas, *this,
preCreateFlag, scanOn, asyncDelay );
break;
default:
pNewPV = NULL;
@@ -388,11 +398,12 @@ epicsTimerNotify::expireStatus exAsyncExistIO::expire ( const epicsTime & /*curr
//
// exAsyncCreateIO::exAsyncCreateIO()
//
exAsyncCreateIO::exAsyncCreateIO ( pvInfo &pviIn, exServer &casIn,
const casCtx &ctxIn, bool scanOnIn ) :
exAsyncCreateIO ::
exAsyncCreateIO ( pvInfo &pviIn, exServer &casIn,
const casCtx &ctxIn, bool scanOnIn, double asyncDelayIn ) :
casAsyncPVAttachIO ( ctxIn ), pvi ( pviIn ),
timer ( casIn.createTimer () ),
cas ( casIn ), scanOn ( scanOnIn )
cas ( casIn ), asyncDelay ( asyncDelayIn ), scanOn ( scanOnIn )
{
this->timer.start ( *this, 0.00001 );
}
@@ -412,9 +423,8 @@ exAsyncCreateIO::~exAsyncCreateIO()
//
epicsTimerNotify::expireStatus exAsyncCreateIO::expire ( const epicsTime & /*currentTime*/ )
{
exPV *pPV;
pPV = this->pvi.createPV ( this->cas, false, this->scanOn );
exPV * pPV = this->pvi.createPV ( this->cas, false,
this->scanOn, this->asyncDelay );
if ( pPV ) {
this->postIOCompletion ( pvAttachReturn ( *pPV ) );
}

View File

@@ -51,8 +51,6 @@
# define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif
#define maxSimultAsyncIO 1000u
//
// info about all pv in this server
//
@@ -62,28 +60,27 @@ class exPV;
class exServer;
//
// pvInfo
//
// pvInfo
//
class pvInfo {
public:
pvInfo ( double scanPeriodIn, const char *pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn,
aitEnum typeIn, excasIoType ioTypeIn,
unsigned countIn );
pvInfo ( const pvInfo & copyIn );
public:
pvInfo ( double scanPeriodIn, const char * pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn, aitEnum typeIn,
excasIoType ioTypeIn, unsigned countIn );
pvInfo ( const pvInfo & copyIn );
~pvInfo ();
double getScanPeriod () const;
const char *getName () const;
double getHopr () const;
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
unsigned getElementCount () const;
void unlinkPV ();
exPV *createPV ( exServer & exCAS,
bool preCreateFlag, bool scanOn );
double getScanPeriod () const;
const char * getName ()
const; double getHopr () const;
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
unsigned getElementCount () const;
void unlinkPV ();
exPV *createPV ( exServer & exCAS, bool preCreateFlag,
bool scanOn, double asyncDelay );
void deletePV ();
private:
const double scanPeriod;
const char * pName;
@@ -277,7 +274,8 @@ class exServer : private caServer {
public:
exServer ( const char * const pvPrefix,
unsigned aliasCount, bool scanOn,
bool asyncScan );
bool asyncScan, double asyncDelay,
unsigned maxSimultAsyncIO );
~exServer ();
void show ( unsigned level ) const;
void removeIO ();
@@ -287,11 +285,15 @@ public:
void setDebugLevel ( unsigned level );
void destroyAllPV ();
unsigned maxSimultAsyncIO () const;
private:
resTable < pvEntry, stringId > stringResTbl;
epicsTimerQueueActive * pTimerQueue;
unsigned simultAsychIOCount;
const unsigned _maxSimultAsyncIO;
double asyncDelay;
bool scanOn;
void installAliasName ( pvInfo & info, const char * pAliasName );
@@ -310,12 +312,13 @@ private:
//
static pvInfo pvList[];
static const unsigned pvListNElem;
//
// on-the-fly PVs
//
static pvInfo bill;
static pvInfo billy;
static pvInfo bloater;
static pvInfo bloaty;
static pvInfo boot;
static pvInfo booty;
@@ -327,12 +330,18 @@ private:
class exAsyncPV : public exScalarPV {
public:
exAsyncPV ( exServer & cas, pvInfo &setup,
bool preCreateFlag, bool scanOnIn );
bool preCreateFlag, bool scanOnIn, double asyncDelay );
caStatus read ( const casCtx & ctxIn, gdd & protoIn );
caStatus write ( const casCtx & ctxIn, const gdd & value );
void removeIO();
caStatus writeNotify ( const casCtx & ctxIn, const gdd & value );
void removeReadIO();
void removeWriteIO();
caStatus updateFromAsyncWrite ( const gdd & );
private:
unsigned simultAsychIOCount;
double asyncDelay;
smartConstGDDPointer pStandbyValue;
unsigned simultAsychReadIOCount;
unsigned simultAsychWriteIOCount;
exAsyncPV & operator = ( const exAsyncPV & );
exAsyncPV ( const exAsyncPV & );
};
@@ -357,7 +366,8 @@ private:
//
class exAsyncWriteIO : public casAsyncWriteIO, public epicsTimerNotify {
public:
exAsyncWriteIO ( exServer &, const casCtx & ctxIn, exAsyncPV &, const gdd & );
exAsyncWriteIO ( exServer &, const casCtx & ctxIn,
exAsyncPV &, const gdd &, double asyncDelay );
~exAsyncWriteIO ();
private:
exAsyncPV & pv;
@@ -373,7 +383,8 @@ private:
//
class exAsyncReadIO : public casAsyncReadIO, public epicsTimerNotify {
public:
exAsyncReadIO ( exServer &, const casCtx &, exAsyncPV &, gdd & );
exAsyncReadIO ( exServer &, const casCtx &,
exAsyncPV &, gdd &, double asyncDelay );
virtual ~exAsyncReadIO ();
private:
exAsyncPV & pv;
@@ -410,12 +421,13 @@ private:
class exAsyncCreateIO : public casAsyncPVAttachIO, public epicsTimerNotify {
public:
exAsyncCreateIO ( pvInfo & pviIn, exServer & casIn,
const casCtx & ctxIn, bool scanOnIn );
const casCtx & ctxIn, bool scanOnIn, double asyncDelay );
virtual ~exAsyncCreateIO ();
private:
pvInfo & pvi;
epicsTimer & timer;
exServer & cas;
double asyncDelay;
bool scanOn;
expireStatus expire ( const epicsTime & currentTime );
exAsyncCreateIO & operator = ( const exAsyncCreateIO & );
@@ -562,25 +574,13 @@ inline void exServer::removeIO()
}
else {
fprintf ( stderr,
"simultAsychIOCount underflow?\n" );
"simultAsychIOCount underflow?\n" );
}
}
inline exAsyncPV::exAsyncPV ( exServer & cas, pvInfo & setup,
bool preCreateFlag, bool scanOnIn ) :
exScalarPV ( cas, setup, preCreateFlag, scanOnIn ),
simultAsychIOCount ( 0u )
inline unsigned exServer :: maxSimultAsyncIO () const
{
}
inline void exAsyncPV::removeIO ()
{
if ( this->simultAsychIOCount > 0u ) {
this->simultAsychIOCount--;
}
else {
fprintf ( stderr, "inconsistent simultAsychIOCount?\n" );
}
return this->_maxSimultAsyncIO;
}
inline exChannel::exChannel ( const casCtx & ctxIn ) :

View File

@@ -24,12 +24,14 @@ extern int main ( int argc, const char **argv )
exServer *pCAS;
unsigned debugLevel = 0u;
double executionTime = 0.0;
double asyncDelay = 0.1;
char pvPrefix[128] = "";
unsigned aliasCount = 1u;
unsigned scanOn = true;
unsigned syncScan = true;
char arraySize[64] = "";
bool forever = true;
unsigned maxSimultAsyncIO = 1000u;
int i;
i = 1;
@@ -77,6 +79,18 @@ extern int main ( int argc, const char **argv )
continue;
}
}
if ( strcmp ( argv[i],"-ad" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%lf", & asyncDelay ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i],"-an" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%u", & maxSimultAsyncIO ) == 1 ) {
i += 2;
continue;
}
}
printf ( "\"%s\"?\n", argv[i] );
if ( i + 1 < argc ) {
printf ( "\"%s\"?\n", argv[i+1] );
@@ -85,7 +99,8 @@ extern int main ( int argc, const char **argv )
"usage: %s [-d <debug level> -t <execution time> -p <PV name prefix> "
"-c <numbered alias count> -s <1=scan on (default), 0=scan off> "
"-ss <1=synchronous scan (default), 0=asynchronous scan> "
"-a <max array size>\n",
"-a <max array size> -ad <async delay> "
"-an <max simultaneous async>\n",
argv[0]);
return (1);
@@ -97,7 +112,8 @@ extern int main ( int argc, const char **argv )
try {
pCAS = new exServer ( pvPrefix, aliasCount,
scanOn != 0, syncScan == 0 );
scanOn != 0, syncScan == 0, asyncDelay,
maxSimultAsyncIO );
}
catch ( ... ) {
errlogPrintf ( "Server initialization error\n" );

View File

@@ -1,10 +1,13 @@
# CONFIG
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
@@ -13,11 +16,12 @@ endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override for definition in base
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)

View File

@@ -1,20 +1,23 @@
#RELEASE Location of external support modules
# RELEASE - Location of external support modules
#
# IF YOU MAKE ANY CHANGES to this file you MUST at least run
# "gnumake" in this directory afterwards; you usually need
# to run "gnumake rebuild" in the application's top level
# directory each time this file is changed.
# IF YOU MAKE ANY CHANGES to this file you must subsequently
# do a "gnumake rebuild" in this application's top level
# directory.
#
# NOTE: The build does not check dependencies against files
# that are outside this application, thus you should run
# "gnumake distclean install" in the top directory each time
# EPICS_BASE, SNCSEQ, or any other external module defined
# in the RELEASE file is rebuilt.
# The build process does not check dependencies against files
# that are outside this application, thus you should do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
#
# Host/target specific settings can be specified in files named
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
#
# This file should ONLY define paths to other support modules,
# or include statements that pull in similar RELEASE files.
# Build settings that are NOT module paths should appear in a
# CONFIG_SITE file.
TEMPLATE_TOP=_TEMPLATE_TOP_
@@ -24,5 +27,6 @@ TEMPLATE_TOP=_TEMPLATE_TOP_
# EPICS_BASE usually appears last so other apps can override stuff:
EPICS_BASE=_EPICS_BASE_
# Set RULES to use build rules from somewhere other than EPICS_BASE:
# Set RULES here if you want to take build rules from somewhere
# other than EPICS_BASE:
#RULES=/path/to/epics/support/module/rules/x-y

View File

@@ -15,5 +15,8 @@
# Location of external products
EPICS_BASE=_EPICS_BASE_
EPICS_EXTENSIONS = $(EPICS_BASE)/../extensions
EPICS_EXTENSIONS = $(TOP)
# OAG_APPS may be needed by extension SDDS
#OAG_APPS=$(TOP)/../../oag/apps

View File

@@ -29,8 +29,8 @@ IDL = /usr/local/idl
# IDL=$(IDL)/external/rpc is the sun4 version
IDLRPC = $(IDL)/external/rpc.solaris
X11_LIB = d:/cygwin/usr/X11R6/lib
X11_INC = d:/cygwin/usr/X11R6/include
X11_LIB = c:/cygwin/lib
X11_INC = c:/cygwin/include
MOTIF_LIB = $(X11_LIB)
MOTIF_INC = $(X11_INC)

View File

@@ -12,7 +12,7 @@
-include $(TOP)/configure/os/CONFIG_SITE.linux-x86.linux-x86
X11_LIB=/usr/lib64
X11_INC=/usr/include/X11
X11_INC=/usr/include
# OpenMotif location
MOTIF_LIB=/usr/lib64

View File

@@ -11,8 +11,8 @@
-include $(TOP)/configure/os/CONFIG_SITE.solaris-sparc.solaris-sparc
XRTGRAPH_EXTENSIONS=
XRTGRAPH=
#XRTGRAPH_EXTENSIONS=
#XRTGRAPH=
SCIPLOT=YES
X11_LIB = /usr/lib

View File

@@ -0,0 +1,16 @@
#
# $Id$
#
# Site Specific Configuration Information
# Only the local epics system manager should modify this file
# Where to find utilities/libraries
# If you do not have a certain product,
# leave the line empty.
#
-include $(TOP)/configure/os/CONFIG_SITE.solaris-x86.solaris-x86
XRTGRAPH=
SCIPLOT=YES

View File

@@ -181,7 +181,7 @@ ifeq ($(EXCEED),Exceed10.0)
EXCEED_CFLAGS=/DXMSTATIC /DMOTIFAPP
endif
ifeq ($(EXCEED),Exceed12.0)
XDK=C:/Exceed10.0/XDK
XDK=C:/Exceed12.0/XDK
X11_LIB = $(XDK)/lib
X11_INC = $(XDK)/include
EXCEED_XLIBS=XmStatic XmStatXt Xlib HCLXmu

View File

@@ -146,7 +146,7 @@ static long process(subRecord *prec)
if (!pact && prec->pact) return 0;
prec->pact = TRUE;
/* Old async signal, deprecated */
/* Asynchronous function (documented API!) */
if (status == 1) return 0;
recGblGetTimeStamp(prec);

View File

@@ -1,12 +1,11 @@
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
if $running_under_some_shell; # registerRecordDeviceDriver
#*************************************************************************
# 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.
#*************************************************************************
@@ -152,7 +151,14 @@ if (@variables) {
#Now actual registration code.
print "int $subname(DBBASE *pbase)\n{\n";
print << "END" ;
int $subname(DBBASE *pbase)
{
if (!pbase) {
printf("pdbbase is NULL; you must load a DBD file first.\\n");
return -1;
}
END
if($numberRecordType>0) {
print " registerRecordTypes(pbase, $numberRecordType, ",

View File

@@ -1,8 +1,6 @@
##########################################################################
# Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2003 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
##########################################################################
@@ -13,14 +11,13 @@ include $(TOP)/configure/CONFIG
PROD_IOC = softIoc
INC += epicsInstallDir.h
DBD += softIoc.dbd
softIoc_DBD += base.dbd
softIoc_DBD += dlload.dbd
softIoc_DBD += system.dbd
ABS_INSTALL_DIR = $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
USR_CXXFLAGS += -DEPICS_BASE=$(ABS_INSTALL_DIR)
softIoc_SRCS += softIoc_registerRecordDeviceDriver.cpp
softIoc_SRCS_DEFAULT += softMain.cpp
softIoc_SRCS_vxWorks = -nil-
@@ -30,3 +27,6 @@ softIoc_LIBS = $(EPICS_BASE_IOC_LIBS)
DB += softIocExit.db
include $(TOP)/configure/RULES
$(COMMON_DIR)/epicsInstallDir.h:
$(PERL) ../makeInstallDir.pl $(INSTALL_LOCATION) > $@

View File

@@ -0,0 +1,31 @@
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
if $running_under_some_shell; # registerRecordDeviceDriver
#*************************************************************************
# Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
use strict;
use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use EPICS::Path;
die "Path to INSTALL_LOCATION missing\n" unless @ARGV == 1;
my $path = AbsPath(shift);
$path =~ s/\\/\\\\/gx;
print "/* THIS IS A GENERATED FILE. DO NOT EDIT! */\n",
"\n",
"#ifndef INC_epicsInstallDir_H\n",
"#define INC_epicsInstallDir_H\n",
"\n",
"#define EPICS_BASE \"$path\"\n",
"\n",
"#endif /* INC_epicsInstallDir_H */\n";

View File

@@ -70,16 +70,16 @@
#include "asDbLib.h"
#include "iocInit.h"
#include "iocsh.h"
#include "epicsInstallDir.h"
extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase);
#define QUOTE(x) #x
#define DBD_FILE(top) QUOTE(top) "/dbd/softIoc.dbd"
#define EXIT_FILE(top) QUOTE(top) "/db/softIocExit.db"
#define DBD_FILE EPICS_BASE "/dbd/softIoc.dbd"
#define EXIT_FILE EPICS_BASE "/db/softIocExit.db"
const char *arg0;
const char *base_dbd = DBD_FILE(EPICS_BASE);
const char *exit_db = EXIT_FILE(EPICS_BASE);
const char *base_dbd = DBD_FILE;
const char *exit_db = EXIT_FILE;
static void exitSubroutine(subRecord *precord) {

View File

@@ -1,7 +1,7 @@
eval 'exec perl -S -w $0 ${1+"$@"}' # -*- Mode: perl -*-
if 0;
#*************************************************************************
# Copyright (c) 2008 The University of Chicago, as Operator of Argonne
# Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
@@ -11,14 +11,27 @@ eval 'exec perl -S -w $0 ${1+"$@"}' # -*- Mode: perl -*-
# Determines an absolute pathname for its argument,
# which may be either a relative or absolute path and
# might have trailing parts that don't exist yet.
# might have trailing directory names that don't exist yet.
use strict;
use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use Getopt::Std;
use EPICS::Path;
print AbsPath(shift), "\n";
our ($opt_h);
$Getopt::Std::OUTPUT_HELP_VERSION = 1;
&HELP_MESSAGE if !getopts('h') || $opt_h || @ARGV != 1;
my $path = AbsPath(shift);
print "$path\n";
sub HELP_MESSAGE {
print STDERR "Usage: fullPathName.pl [-h] pathname\n";
exit 2;
}

View File

@@ -17,7 +17,7 @@ YACCOPT = -l -d
SKELETON_FILE = include/flex.skel.static
USR_CPPFLAGS = -DDEFAULT_SKELETON_FILE="\"$(SKELETON_FILE)\""
USR_CPPFLAGS = -DDEFAULT_SKELETON_FILE=$(SKELETON_FILE)
INC += flex.skel.static

View File

@@ -34,6 +34,8 @@
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define ENQUOTE(path) #path
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
@@ -294,7 +296,7 @@ void flexend(int status)
if ( usemecs )
putc( 'm', stderr );
if ( strcmp( skelname, DEFAULT_SKELETON_FILE ) )
if ( strcmp( skelname, ENQUOTE(DEFAULT_SKELETON_FILE) ) )
fprintf( stderr, " -S%s", skelname );
putc( '\n', stderr );
@@ -557,7 +559,7 @@ get_next_arg: /* used by -C and -S flags in lieu of a "continue 2" control */
static char skeleton_name_storage[400];
skelname = skeleton_name_storage;
(void) strcpy( skelname, DEFAULT_SKELETON_FILE );
(void) strcpy( skelname, ENQUOTE(DEFAULT_SKELETON_FILE) );
}
if ( ! use_stdout )