Compare commits

...

143 Commits

Author SHA1 Message Date
Janet B. Anderson
7c136fc07d R3.14.11 2009-08-28 18:49:40 +00:00
Andrew Johnson
534ca2c86e Make ellFree() a 1-argument macro, calls ellFree2() with free as freeFunc. 2009-08-28 18:34:38 +00:00
Andrew Johnson
f17ac39f29 Disable divide by zero warnings on MSVC when generating NAN and INF.
Use those values rather than calculating them independently.
2009-08-25 18:19:49 +00:00
Jeff Hill
a4e5e540a9 added \n to printf diagnostic 2009-08-25 15:45:20 +00:00
Jeff Hill
33911cd0af improved failure diagnostic 2009-08-25 14:50:11 +00:00
Andrew Johnson
1607d2a192 ellFree() and Win32 time provider. 2009-08-24 20:55:31 +00:00
Jeff Hill
140b8a468d we dont need tocheck the return from new with assert 2009-08-24 17:09:55 +00:00
Jeff Hill
d84e9cb3ec exp passed to assert must not change the state of the data structures 2009-08-24 17:08:41 +00:00
Jeff Hill
fa24d119dd use verify instead of assert (in tests) 2009-08-24 17:07:03 +00:00
Jeff Hill
4921187178 use verify instead of assert 2009-08-24 17:04:40 +00:00
Jeff Hill
794811b95a exp passed to assert must not change the state of the data structures 2009-08-24 17:03:17 +00:00
Jeff Hill
aa904449c0 we dont need tocheck the return from new with assert 2009-08-24 17:01:21 +00:00
Andrew Johnson
1c95101ae1 Fixed Till's report of non-thread-safe lazy-init. 2009-08-21 17:32:13 +00:00
Janet B. Anderson
0961378465 Revert to -CVS for snapshots. 2009-08-21 15:48:28 +00:00
Janet B. Anderson
7655e7859d R3.14.11-RC1 2009-08-21 15:41:28 +00:00
Andrew Johnson
bbc0899423 RC1 2009-08-21 15:34:02 +00:00
Andrew Johnson
3afade09e6 Fixed epicsCalcTest issue, but epicsMutexTest can still run too long. 2009-08-21 15:32:01 +00:00
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
122 changed files with 2703 additions and 1737 deletions

View File

@@ -33,14 +33,14 @@ EPICS_MODIFICATION = 11
EPICS_PATCH_LEVEL = 0
# This will end in -CVS between official releases
EPICS_CVS_SNAPSHOT=-CVS
#EPICS_CVS_SNAPSHOT=-CVS
#EPICS_CVS_SNAPSHOT=-pre1
#EPICS_CVS_SNAPSHOT=-pre1-CVS
#EPICS_CVS_SNAPSHOT=-RC1
#EPICS_CVS_SNAPSHOT=-RC1-CVS
#EPICS_CVS_SNAPSHOT=-RC2
#EPICS_CVS_SNAPSHOT=-RC2-CVS
#EPICS_CVS_SNAPSHOT=
EPICS_CVS_SNAPSHOT=
# No changes should be needed below here

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,16 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Known Problems R3.14.10-RC1</title>
<title>Known Problems in R3.14.11</title>
</head>
<body>
<h1 style="text-align: center">EPICS Base R3.14.10: Known Problems</h1>
<h1 style="text-align: center">EPICS Base R3.14.11: Known Problems</h1>
<ul>
<li>Parallel make (<tt>make -j</tt>) does not work on cygwin-x86 targets,
probably due to a missing dependency in the EPICS build rules.</li>
<li>Some older Perl versions do not properly install the xsubpp program. This
will prevent the build in src/cap5 from completing &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 epicsMutexTest program sometimes runs an extra test, resulting in
a failure report from 'make -s runtests'. This is harmless.</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,159 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>EPICS Base R3.14.x Release Notes</title>
<title>EPICS Base R3.14.11-RC1 Release Notes</title>
</head>
<body lang="en">
<h1 align="center">EPICS Base Release 3.14.1x</h1>
<h1 align="center">EPICS Base Release 3.14.11</h1>
<h2 align="center">Changes between 3.14.10 and 3.14.11</h2>
<!-- Insert new items below here ... -->
<!-- Insert new items immediately below here ... -->
<h4>Several macros and includes removed from dbDefs.h</h4>
<h4>Extra argument to ellFree()</h4>
<p>To work properly from Windows DLLs we had to add a second argument to the
ellFree() function, which should be passed the free function to be called. In
most cases this will involve just adding <tt><b>, free</b></tt> to the argument
list.</p>
<h4>Time provider on Win32</h4>
<p>A race condition meant that sometimes EPICS programs (including the internal
programs such as flex and antelope) built for Win32 architectures would not
start properly on Windows systems that have multiple CPUs. This race has been
fixed.</p>
<h4>Build system dependency change</h4>
<p>In order to get GNU make parallel execution (-j option) to work proprely for
multiple target architectures, a new dependency had to be added. Now all
cross-compiled builds depend on their host build. This means that when a
<tt>make <i>crosstargetarch</i></tt> command is issued, the EPICS_HOST_ARCH
target build will be executed first, followed by the <i>crosstargetarch</i>
build. Builds done in an O.<i>arch</i> directory will still only build the
<i>arch</i> targets however.</p>
<h4>Channel Access changes</h4>
<p>Mantis 361 fix - ca_add_fd_registration users might not receive select
wakeup</p>
<p>Mantis 359 fix - ca client library flow control mode related issues</p>
<p>Mantis 357 fix - high throughput multithreaded ca client appl thread could
be trapped in lib.</p>
<ul>
<li>Discovered during code review. Not seen in practice, but possible</li>
</ul>
<p>Mantis 285 fix - CA Documentation doesn't distinguish sync groups from
ca_put_callback()</p>
<p>Mantis 346 fix - deleting the chid passed in from within put cb handler
causes failure</p>
<p>Mantis 284 fix - channel clear protocol warning messages from PCAS</p>
<p>Mantis 237 fix - SEGV from simple CA client during context destroy</p>
<p>Mantis 242 fix - invalid DBR type not screened in client library when
doing a put</p>
<h4>Portable Channel Access Server changes</h4>
<p> These changes impact the Gateway (Proxy server) and other servers but not
the IOC.</h4>
<p>Mantis 360 fix - server is unresponsive for one of its clients, when
async io postponed and in flow control mode</p>
<p>Mantis 358 fix - PCAS service snap-in has no way to determine if its a put,
or a put calback.</p>
<p>Mantis 356 fix - medm display sometimes hangs until the motor stops when
controling motor through gw.</p>
<p>Mantis 350 fix - Incoming data corruption under heavy CAS load.</p>
<p>Mantis 340 fix - leak when performing a read and conversion fails.</p>
<p>Mantis 348 fix - A call to 'assert (item.pList == this)'
failed in ../../../../src/cas/generic/st/ioBlocked.cc line 112</p>
<p>Mantis 345 fix - Compilation warning: complaint about missing
gddDestructor</p>
<p>Mantis 343 fix - gddScalar::new() operator is not fully thread safe</p>
<p>Mantis 333 fix - resTable::removeAll() does not reset the item count</p>
<p>Mantis 335 fix - excas fails in clearOutstandingReads - maybe requires an
R3.13 client</p>
<p>Mantis 329 fix - GW hang, pthread_mutex_lock failed: error Invalid
argument message</p>
<p>Mantis 352 fix - gateway hangs temporarily under heavy load on 8-core
64bit RHEL5</p>
<ul>
<li>High throughput performance appears to be much better now for both scalars
and large arrays, but more testing needed in operational gateways</li>
</ul>
<h4>Timer Queue Library</h4>
<p>Mantis 336 fix - timer queue should have try / catch block around call to
user's expiration callback</p>
<p>Mantis 332 fix - epicsTimerTest failure, windows vista 64, dual core
SMP system</p>
<h4>LibCom</h4>
<p>Mantis 328 fixed - orderly shutdown for soft IOC fails</p>
<h4>Application configure files</h4>
<p>The configuration directory files installed by makeBaseApp.pl have been
changing in recent releases to make them work more like the files in the Base
configuration directory. The CONFIG_APP file has gone, and its functionality is
now performed by the CONFIG file which should only be modified in exceptional
circumstances. The variables that used to be set in the CONFIG file now appear
in the new CONFIG_SITE file, and can be overridden for specific combinations of
host and target architectures by creating a file with name matching one of these
patterns:</p>
<ul>
<li>CONFIG_SITE.&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 +164,15 @@ from the menuYesNo.h file where they were used in several record types. The
other macros were not being used anywhere in Base, sncseq or Asyn.</p>
<p>The macro <tt>LOCAL</tt> that was a synonym for <tt>static</tt> is now
deprecated and will be deleted soon, please adjust your code to use the latter
keyword. Any uses of the <tt>READONLY</tt> macro from shareLib.h must now be
replaced by the keyword <tt>const</tt>.</p>
deprecated and will be deleted in R3.15, please adjust your code to use the
latter keyword. All uses of the <tt>READONLY</tt> macro from shareLib.h must
now be replaced by the keyword <tt>const</tt> as the macro has been deleted.</p>
<p>The dbDefs.h file was also unnecessarily including some other libCom header
<p>The dbDefs.h file was unnecessarily including various other libCom header
files which may have to be manually added to out-of-tree source files that
relied on this. The general rule for header files is that a header should only
include other headers that are needed for its own inclusion in any source
file. The <tt>#include</tt> statements that might need to be added are:</p>
include other headers that are needed for its own inclusion in any source file.
The <tt>#include</tt> statements that might need to be added are:</p>
<ul>
<li>#include &lt;stdarg.h&gt;</li>
@@ -39,6 +182,17 @@ file. The <tt>#include</tt> statements that might need to be added are:</p>
<li>#include "epicsTypes.h"</li>
</ul>
<p>A new macro <tt>CONTAINER(pointer, type, member)</tt> has been added which
calculates and returns a pointer to the parent structure when given a pointer to
a member, the structure type and the name of the member in that structure. On
GNU compilers the type of the pointer is checked to ensure that it matches the
member, so code using this macro should be built using gcc for additional
confidence.</p>
<h4>Long-deprecated errSymFind() function deleted</h4>
<p>This functionality was replaced by errSymLookup() many releases ago.</p>
<h4>Perl CA library shutdown</h4>
<p>The Perl CA library has been modified to properly flush the Channel Access
@@ -266,6 +420,16 @@ clients, although by no means all clients support it yet.</p>
now uses _NSGetEnviron() to get the pointer to the environment string
table.</p>
<h4>gpHash argument type changed</h4>
<p>Out-of-tree users of libCom's gpHash routines should change the type of their
pointer to their gpHash table to avoid compiler warnings. The first argument to
all of the <tt>gph...()</tt> routines used to be a <tt>void&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 +629,7 @@ time provider you need to use RTEMS 4.9.1 or newer.</p>
<h4>RTEMS epicsEventWaitWithTimeout</h4>
<p>Correctly return epicsEventWaitTimeout when event is not pending and
timeout value is 0.0 secondsmore agressive.</p>
timeout value is 0.0 seconds.</p>
<h4>epicsRingPointer, epicsRingBytes</h4>

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

@@ -55,6 +55,9 @@ static epicsTimeStamp showProgressBeginTime;
static const double timeoutToPendIO = 1e20;
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
void showProgressBegin ( const char *pTestName, unsigned interestLevel )
{
@@ -133,7 +136,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
epicsThreadSleep ( 0.1 );
ca_poll (); /* emulate typical GUI */
}
assert ( eventCount > 0 );
verify ( eventCount > 0 );
/* clear any knowledge of old gets */
ca_pend_io ( 1e-5 );
@@ -167,7 +170,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
epicsThreadSleep ( 0.1 );
ca_poll (); /* emulate typical GUI */
}
assert ( eventCount > 0 );
verify ( eventCount > 0 );
status = ca_clear_event ( id );
SEVCHK (status, 0);
@@ -193,7 +196,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
epicsThreadSleep ( 0.1 );
ca_poll (); /* emulate typical GUI */
}
assert ( eventCount > 0 );
verify ( eventCount > 0 );
/* verify that a ca_put() produces an update, but */
/* this may fail if there is an unusual deadband */
@@ -224,7 +227,7 @@ void monitorSubscriptionFirstUpdateTest ( const char *pName, chid chan, unsigned
epicsThreadSleep ( 0.1 );
ca_poll (); /* emulate typical GUI */
}
assert ( eventCount > 0 );
verify ( eventCount > 0 );
/* clean up */
status = ca_clear_channel ( chan2 );
@@ -282,7 +285,7 @@ void verifyMonitorSubscriptionFlushIO ( chid chan, unsigned interestLevel )
epicsThreadSleep ( 0.1 );
ca_poll (); /* emulate typical GUI */
}
assert ( eventCount > 0 );
verify ( eventCount > 0 );
status = ca_clear_event ( id );
SEVCHK (status, 0);
@@ -293,9 +296,9 @@ void accessRightsStateChange ( struct access_rights_handler_args args )
{
appChan *pChan = (appChan *) ca_puser ( args.chid );
assert ( pChan->channel == args.chid );
assert ( args.ar.read_access == ca_read_access ( args.chid ) );
assert ( args.ar.write_access == ca_write_access ( args.chid ) );
verify ( pChan->channel == args.chid );
verify ( args.ar.read_access == ca_read_access ( args.chid ) );
verify ( args.ar.write_access == ca_write_access ( args.chid ) );
accessUpdateCount++;
pChan->accessUpdateCount++;
}
@@ -304,12 +307,12 @@ void getCallbackStateChange ( struct event_handler_args args )
{
appChan *pChan = (appChan *) args.usr;
assert ( pChan->channel == args.chid );
assert ( pChan->connected );
verify ( pChan->channel == args.chid );
verify ( pChan->connected );
if ( args.status != ECA_NORMAL ) {
printf ( "getCallbackStateChange abnormal status was \"%s\"\n",
ca_message ( args.status ) );
assert ( args.status == ECA_NORMAL );
verify ( args.status == ECA_NORMAL );
}
getCallbackCount++;
@@ -322,25 +325,25 @@ void connectionStateChange ( struct connection_handler_args args )
appChan *pChan = (appChan *) ca_puser ( args.chid );
assert ( pChan->channel == args.chid );
verify ( pChan->channel == args.chid );
if ( args.op == CA_OP_CONN_UP ) {
if ( pChan->accessRightsHandlerInstalled ) {
assert ( pChan->accessUpdateCount > 0u );
verify ( pChan->accessUpdateCount > 0u );
}
assert ( ! pChan->connected );
verify ( ! pChan->connected );
pChan->connected = 1;
status = ca_get_callback ( DBR_STS_STRING, args.chid, getCallbackStateChange, pChan );
SEVCHK (status, 0);
}
else if ( args.op == CA_OP_CONN_DOWN ) {
assert ( pChan->connected );
verify ( pChan->connected );
pChan->connected = 0u;
assert ( ! ca_read_access ( args.chid ) );
assert ( ! ca_write_access ( args.chid ) );
verify ( ! ca_read_access ( args.chid ) );
verify ( ! ca_write_access ( args.chid ) );
}
else {
assert ( 0 );
verify ( 0 );
}
pChan->connectionUpdateCount++;
connectionUpdateCount++;
@@ -351,11 +354,11 @@ void subscriptionStateChange ( struct event_handler_args args )
struct dbr_sts_string * pdbrgs = ( struct dbr_sts_string * ) args.dbr;
appChan *pChan = (appChan *) args.usr;
assert ( args.status == ECA_NORMAL );
assert ( pChan->channel == args.chid );
assert ( pChan->connected );
assert ( args.type == DBR_STS_STRING );
assert ( strlen ( pdbrgs->value ) <= MAX_STRING_SIZE );
verify ( args.status == ECA_NORMAL );
verify ( pChan->channel == args.chid );
verify ( pChan->connected );
verify ( args.type == DBR_STS_STRING );
verify ( strlen ( pdbrgs->value ) <= MAX_STRING_SIZE );
pChan->subscriptionUpdateCount++;
subscriptionUpdateCount++;
}
@@ -422,7 +425,7 @@ void verifyConnectionHandlerConnect ( appChan *pChans, unsigned chanCount,
subscriptionStateChange, &pChans[j], &pChans[j].subscription );
SEVCHK ( status, NULL );
assert ( ca_test_io () == ECA_IODONE );
verify ( ca_test_io () == ECA_IODONE );
}
ca_flush_io ();
@@ -436,13 +439,13 @@ void verifyConnectionHandlerConnect ( appChan *pChans, unsigned chanCount,
}
for ( j = 0u; j < chanCount; j++ ) {
assert ( pChans[j].getCallbackCount == 1u);
assert ( pChans[j].connectionUpdateCount > 0 );
verify ( pChans[j].getCallbackCount == 1u);
verify ( pChans[j].connectionUpdateCount > 0 );
if ( pChans[j].connectionUpdateCount > 1u ) {
printf ("Unusual connection activity count = %u on channel %s?\n",
pChans[j].connectionUpdateCount, pChans[j].name );
}
assert ( pChans[j].accessUpdateCount > 0 );
verify ( pChans[j].accessUpdateCount > 0 );
if ( pChans[j].accessUpdateCount > 1u ) {
printf ("Unusual access rights activity count = %u on channel %s?\n",
pChans[j].connectionUpdateCount, pChans[j].name );
@@ -515,7 +518,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
i = 0;
while ( backgroundConnCount > 1u ) {
backgroundConnCount = ca_get_ioc_connection_count ();
assert ( i++ < 10 );
verify ( i++ < 10 );
printf ( "Z" );
fflush ( stdout );
epicsThreadSleep ( 1.0 );
@@ -535,11 +538,11 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
SEVCHK ( status, NULL );
if ( ca_state ( pChans[j].channel ) == cs_conn ) {
assert ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
verify ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
}
else {
assert ( INVALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
assert ( ca_test_io () == ECA_IOINPROGRESS );
verify ( INVALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
verify ( ca_test_io () == ECA_IOINPROGRESS );
}
status = ca_replace_access_rights_event (
@@ -577,14 +580,14 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
showProgress ( interestLevel );
assert ( ca_test_io () == ECA_IODONE );
verify ( ca_test_io () == ECA_IODONE );
connections = ca_get_ioc_connection_count ();
assert ( connections == backgroundConnCount );
verify ( connections == backgroundConnCount );
for ( j = 0u; j < chanCount; j++ ) {
assert ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
assert ( ca_state ( pChans[j].channel ) == cs_conn );
verify ( VALID_DB_REQ ( ca_field_type ( pChans[j].channel ) ) );
verify ( ca_state ( pChans[j].channel ) == cs_conn );
SEVCHK ( ca_clear_channel ( pChans[j].channel ), NULL );
}
@@ -605,7 +608,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
while ( ca_get_ioc_connection_count () != backgroundConnCount ) {
epicsThreadSleep ( 0.1 );
ca_poll (); /* emulate typical GUI */
assert ( ++j < 100 );
verify ( ++j < 100 );
}
}
showProgress ( interestLevel );
@@ -621,7 +624,7 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
SEVCHK ( status, NULL );
}
assert ( ca_test_io () == ECA_IODONE );
verify ( ca_test_io () == ECA_IODONE );
/*
* verify ca_pend_io() does not see old search requests
@@ -650,13 +653,13 @@ void verifyBlockingConnect ( appChan *pChans, unsigned chanCount,
SEVCHK ( status, NULL );
status = ca_pend_io ( 1e-16 );
if ( status != ECA_TIMEOUT ) {
assert ( ca_state ( pChans[1].channel ) == cs_conn );
verify ( ca_state ( pChans[1].channel ) == cs_conn );
}
status = ca_clear_channel ( pChans[1].channel );
SEVCHK ( status, NULL );
}
else {
assert ( ca_state( pChans[0].channel ) == cs_conn );
verify ( ca_state( pChans[0].channel ) == cs_conn );
}
}
status = ca_clear_channel( pChans[0].channel );
@@ -721,9 +724,9 @@ void grEnumTest ( chid chan, unsigned interestLevel )
SEVCHK (status, "DBR_GR_ENUM ca_get()");
status = ca_pend_io (timeoutToPendIO);
assert (status == ECA_NORMAL);
verify (status == ECA_NORMAL);
assert ( ge.no_str >= 0 && ge.no_str < NELEMENTS(ge.strs) );
verify ( ge.no_str >= 0 && ge.no_str < NELEMENTS(ge.strs) );
if ( ge.no_str > 0 ) {
printf ("Enum state str = {");
count = (unsigned) ge.no_str;
@@ -763,7 +766,7 @@ void ctrlDoubleTest ( chid chan, unsigned interestLevel )
size = sizeof (*pDbl)*ca_element_count(chan);
pDbl = malloc (size);
assert (pDbl!=NULL);
verify (pDbl!=NULL);
/*
* initialize the array
@@ -782,7 +785,7 @@ void ctrlDoubleTest ( chid chan, unsigned interestLevel )
size = dbr_size_n(DBR_CTRL_DOUBLE, ca_element_count(chan));
pCtrlDbl = (struct dbr_ctrl_double *) malloc (size);
assert (pCtrlDbl!=NULL);
verify (pCtrlDbl!=NULL);
/*
* read the array from the PV
@@ -792,14 +795,14 @@ void ctrlDoubleTest ( chid chan, unsigned interestLevel )
chan, pCtrlDbl);
SEVCHK (status, "ctrlDoubleTest, ca_array_get");
status = ca_pend_io ( timeoutToPendIO );
assert (status==ECA_NORMAL);
verify (status==ECA_NORMAL);
/*
* verify the result
*/
for (i=0; i<nElem; i++) {
double diff = pDbl[i] - sin (i*slice);
assert (fabs(diff) < DBL_EPSILON*4);
verify (fabs(diff) < DBL_EPSILON*4);
}
free (pCtrlDbl);
@@ -830,7 +833,7 @@ void verifyBlockInPendIO ( chid chan, unsigned interestLevel )
"get block test failed - val written %d\n", req );
printf (
"get block test failed - val read %d\n", resp );
assert ( 0 );
verify ( 0 );
}
}
else if ( resp != -100 ) {
@@ -847,7 +850,7 @@ void verifyBlockInPendIO ( chid chan, unsigned interestLevel )
"get block test failed - val written %d\n", req);
printf (
"get block test failed - val read %d\n", resp);
assert(0);
verify (0);
}
showProgressEnd ( interestLevel );
}
@@ -879,7 +882,7 @@ void floatTest ( chid chan, dbr_float_t beginValue, dbr_float_t increment,
if ( fabs ( fval - fretval ) > epsilon ) {
printf ( "float test failed val written %f\n", fval );
printf ( "float test failed val read %f\n", fretval );
assert (0);
verify (0);
}
fval += increment;
}
@@ -909,7 +912,7 @@ void doubleTest ( chid chan, dbr_double_t beginValue,
if ( fabs ( fval - fretval ) > epsilon ) {
printf ( "double test failed val written %f\n", fval );
printf ( "double test failed val read %f\n", fretval );
assert ( 0 );
verify ( 0 );
}
fval += increment;
}
@@ -960,7 +963,7 @@ void verifyAnalogIO ( chid chan, int dataType, double min, double max,
(dbr_double_t) epsil, iter );
}
else {
assert ( 0 );
verify ( 0 );
}
}
base = max;
@@ -981,7 +984,7 @@ void verifyAnalogIO ( chid chan, int dataType, double min, double max,
(dbr_double_t) epsil, iter );
}
else {
assert ( 0 );
verify ( 0 );
}
}
base = - max;
@@ -1002,7 +1005,7 @@ void verifyAnalogIO ( chid chan, int dataType, double min, double max,
(dbr_double_t) epsil, iter );
}
else {
assert ( 0 );
verify ( 0 );
}
}
showProgressEnd ( interestLevel );
@@ -1042,7 +1045,7 @@ void verifyLongIO ( chid chan, unsigned interestLevel )
ca_get ( DBR_LONG, chan, &rdbk );
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "get pend failed\n" );
assert ( iter == rdbk );
verify ( iter == rdbk );
}
showProgressEnd ( interestLevel );
}
@@ -1087,7 +1090,7 @@ void verifyShortIO ( chid chan, unsigned interestLevel )
ca_get ( DBR_SHORT, chan, &rdbk );
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "get pend failed\n" );
assert ( iter == rdbk );
verify ( iter == rdbk );
}
showProgressEnd ( interestLevel );
}
@@ -1198,7 +1201,7 @@ void verifyHighThroughputWriteCallback ( chid chan, unsigned interestLevel )
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status,
"verifyHighThroughputWriteCallback, verification get pend" );
assert ( dval == i );
verify ( dval == i );
showProgressEnd ( interestLevel );
}
else {
@@ -1219,14 +1222,14 @@ void verifyBadString ( chid chan, unsigned interestLevel )
showProgressBegin ( "verifyBadString", interestLevel );
memset (stimStr, 'a', sizeof (stimStr) );
status = ca_array_put ( DBR_STRING, 1u, chan, stimStr );
assert ( status != ECA_NORMAL );
verify ( status != ECA_NORMAL );
sprintf ( stimStr, "%u", 8u );
status = ca_array_put ( DBR_STRING, 1u, chan, stimStr );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_array_get ( DBR_STRING, 1u, chan, respStr );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
if ( strcmp ( stimStr, respStr ) ) {
printf (
"Test fails if stim \"%s\" isnt roughly equiv to resp \"%s\"\n",
@@ -1439,7 +1442,8 @@ void singleSubscriptionDeleteTest ( chid chan, unsigned interestLevel )
unsigned j = 0;
while ( j < i ) {
temp = (float) j++;
SEVCHK ( ca_put (DBR_FLOAT, chan, &temp), NULL);
SEVCHK ( ca_put (DBR_FLOAT, chan, &temp),
"singleSubscriptionDeleteTest - one of multiple puts" );
}
ca_flush_io ();
}
@@ -1472,7 +1476,7 @@ void channelClearWithEventTrafficTest ( const char *pName, unsigned interestLeve
CA_PRIORITY_DEFAULT, &chan );
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "channelClearWithEventTrafficTest: channel connect failed" );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
count = 0u;
SEVCHK ( ca_add_event ( DBR_GR_FLOAT, chan, noopSubscriptionStateChange,
@@ -1515,7 +1519,7 @@ void selfDeleteEvent ( struct event_handler_args args )
{
int status;
status = ca_clear_event ( globalEventID );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
}
void eventClearTest ( chid chan )
@@ -1600,7 +1604,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
SEVCHK ( status, "exception notify install failed" );
pRS = malloc ( ca_element_count (chan) * sizeof (*pRS) );
assert ( pRS );
verify ( pRS );
status = ca_array_get ( DBR_PUT_ACKT,
ca_element_count (chan), chan, pRS );
SEVCHK ( status, "array read request failed" );
@@ -1626,7 +1630,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
status = ca_array_get_callback ( DBR_PUT_ACKT,
ca_element_count (chan), chan, arrayEventExceptionNotify, 0 );
if ( status != ECA_NORMAL ) {
assert ( status == ECA_BADTYPE || status == ECA_GETFAIL );
verify ( status == ECA_BADTYPE || status == ECA_GETFAIL );
arrayEventExceptionNotifyComplete = 1;
}
ca_flush_io ();
@@ -1650,7 +1654,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
status = ca_add_array_event ( DBR_PUT_ACKT, ca_element_count ( chan ),
chan, arrayEventExceptionNotify, 0, 0.0, 0.0, 0.0, &id );
if ( status != ECA_NORMAL ) {
assert ( status == ECA_BADTYPE || status == ECA_GETFAIL );
verify ( status == ECA_BADTYPE || status == ECA_GETFAIL );
arrayEventExceptionNotifyComplete = 1;
}
ca_flush_io ();
@@ -1678,14 +1682,14 @@ void exceptionTest ( chid chan, unsigned interestLevel )
SEVCHK ( status, "exception notify install failed" );
pWS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
assert ( pWS );
verify ( pWS );
for ( i = 0; i < ca_element_count (chan); i++ ) {
strcpy ( pWS[i], "@#$%" );
}
status = ca_array_put ( DBR_STRING,
ca_element_count (chan), chan, pWS );
if ( status != ECA_NORMAL ) {
assert ( status == ECA_BADTYPE || status == ECA_PUTFAIL );
verify ( status == ECA_BADTYPE || status == ECA_PUTFAIL );
acctstExceptionCount++; /* local PV case */
}
ca_flush_io ();
@@ -1710,7 +1714,7 @@ void exceptionTest ( chid chan, unsigned interestLevel )
unsigned i;
pWS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
assert ( pWS );
verify ( pWS );
for ( i = 0; i < ca_element_count (chan); i++ ) {
strcpy ( pWS[i], "@#$%" );
}
@@ -1750,7 +1754,7 @@ void arrayReadNotify ( struct event_handler_args args )
dbr_double_t *pRF = ( dbr_double_t * ) ( args.dbr );
int i;
for ( i = 0; i < args.count; i++ ) {
assert ( pWF[i] == pRF[i] );
verify ( pWF[i] == pRF[i] );
}
arrayReadNotifyComplete = 1;
}
@@ -1780,10 +1784,10 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
showProgressBegin ( "arrayTest", interestLevel );
pRF = (dbr_double_t *) calloc ( ca_element_count (chan), sizeof (*pRF) );
assert ( pRF != NULL );
verify ( pRF != NULL );
pWF = (dbr_double_t *) calloc ( ca_element_count (chan), sizeof (*pWF) );
assert ( pWF != NULL );
verify ( pWF != NULL );
/*
* write some random numbers into the array
@@ -1809,7 +1813,11 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
* verify read response matches values written
*/
for ( i = 0; i < ca_element_count ( chan ); i++ ) {
assert ( pWF[i] == pRF[i] );
if ( pWF[i] != pRF[i] ) {
printf ( "i=%u, pWF[i]=%f, pRF[i]=%f\n",
i, pWF[i], pRF[i]);
}
verify ( pWF[i] == pRF[i] );
}
/*
@@ -1822,7 +1830,7 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
if ( size <= maxArrayBytes ) {
pRS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
assert ( pRS );
verify ( pRS );
status = ca_array_get ( DBR_STRING,
ca_element_count (chan), chan, pRS );
SEVCHK ( status, "array read request failed" );
@@ -1896,7 +1904,7 @@ void arrayTest ( chid chan, unsigned maxArrayBytes, unsigned interestLevel )
}
}
else {
assert ( status == ECA_BADCOUNT );
verify ( status == ECA_BADCOUNT );
}
status = ca_add_exception_event ( 0, 0 );
SEVCHK ( status, "exception notify install failed" );
@@ -1925,54 +1933,54 @@ void unequalServerBufferSizeTest ( const char * pName, unsigned interestLevel )
/* this test must be run when no channels are connected */
connections = ca_get_ioc_connection_count ();
assert ( connections == 0u );
verify ( connections == 0u );
status = ca_create_channel ( pName, 0, 0, 0, & newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
showProgress ( interestLevel );
if ( ! ca_write_access ( newChan ) ) {
printf ( "skipping unequal buffer size test - no write access\n" );
status = ca_clear_channel ( newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
return;
}
pRF = (dbr_double_t *) calloc ( ca_element_count (newChan), sizeof (*pRF) );
assert ( pRF != NULL );
verify ( pRF != NULL );
pWF = (dbr_double_t *) calloc ( ca_element_count (newChan), sizeof (*pWF) );
assert ( pWF != NULL );
verify ( pWF != NULL );
status = ca_array_get ( DBR_DOUBLE, ca_element_count ( newChan ),
newChan, pRF );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_clear_channel ( newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
showProgress ( interestLevel );
status = ca_create_channel ( pName, 0, 0, 0, &newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
showProgress ( interestLevel );
status = ca_array_put ( DBR_DOUBLE, ca_element_count ( newChan ),
newChan, pWF );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_array_get ( DBR_DOUBLE, 1,
newChan, pRF );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_clear_channel ( newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
free ( pRF );
free ( pWF );
@@ -2001,7 +2009,7 @@ void pend_event_delay_test ( dbr_double_t request )
accuracy = 100.0*(delay-request)/request;
printf ( "CA pend event delay = %f sec results in error = %f %%\n",
request, accuracy );
assert ( fabs(accuracy) < 10.0 );
verify ( fabs(accuracy) < 10.0 );
}
void caTaskExitTest ( unsigned interestLevel )
@@ -2021,26 +2029,26 @@ void verifyDataTypeMacros (void)
int type;
type = dbf_type_to_DBR ( DBF_SHORT );
assert ( type == DBR_SHORT );
verify ( type == DBR_SHORT );
type = dbf_type_to_DBR_STS ( DBF_SHORT );
assert ( type == DBR_STS_SHORT );
verify ( type == DBR_STS_SHORT );
type = dbf_type_to_DBR_GR ( DBF_SHORT );
assert ( type == DBR_GR_SHORT );
verify ( type == DBR_GR_SHORT );
type = dbf_type_to_DBR_CTRL ( DBF_SHORT );
assert ( type == DBR_CTRL_SHORT );
verify ( type == DBR_CTRL_SHORT );
type = dbf_type_to_DBR_TIME ( DBF_SHORT );
assert ( type == DBR_TIME_SHORT );
assert ( strcmp ( dbr_type_to_text( DBR_SHORT ), "DBR_SHORT" ) == 0 );
assert ( strcmp ( dbf_type_to_text( DBF_SHORT ), "DBF_SHORT" ) == 0 );
assert ( dbr_type_is_SHORT ( DBR_SHORT ) );
assert ( dbr_type_is_valid ( DBR_SHORT ) );
assert ( dbf_type_is_valid ( DBF_SHORT ) );
verify ( type == DBR_TIME_SHORT );
verify ( strcmp ( dbr_type_to_text( DBR_SHORT ), "DBR_SHORT" ) == 0 );
verify ( strcmp ( dbf_type_to_text( DBF_SHORT ), "DBF_SHORT" ) == 0 );
verify ( dbr_type_is_SHORT ( DBR_SHORT ) );
verify ( dbr_type_is_valid ( DBR_SHORT ) );
verify ( dbf_type_is_valid ( DBF_SHORT ) );
{
int dataType = -1;
dbf_text_to_type ( "DBF_SHORT", dataType );
assert ( dataType == DBF_SHORT );
verify ( dataType == DBF_SHORT );
dbr_text_to_type ( "DBR_CLASS_NAME", dataType );
assert ( dataType == DBR_CLASS_NAME );
verify ( dataType == DBR_CLASS_NAME );
}
}
@@ -2083,7 +2091,7 @@ void clearChannelInGetCallbackTest ( const char *pName, unsigned level )
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
status = ca_create_channel ( pName, 0, 0, 0, & chan );
@@ -2097,7 +2105,7 @@ void clearChannelInGetCallbackTest ( const char *pName, unsigned level )
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
showProgressEnd ( level );
@@ -2114,7 +2122,7 @@ void clearChannelInPutCallbackTest ( const char *pName, unsigned level )
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
status = ca_create_channel ( pName, 0, 0, 0, & chan );
@@ -2129,7 +2137,7 @@ void clearChannelInPutCallbackTest ( const char *pName, unsigned level )
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
showProgressEnd ( level );
@@ -2138,7 +2146,6 @@ void clearChannelInPutCallbackTest ( const char *pName, unsigned level )
void clearChannelInSubscrCallbackTest ( const char *pName, unsigned level )
{
unsigned i;
const dbr_double_t value = 1.1;
chid chan;
int status;
@@ -2146,7 +2153,7 @@ void clearChannelInSubscrCallbackTest ( const char *pName, unsigned level )
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
status = ca_create_channel ( pName, 0, 0, 0, & chan );
@@ -2161,7 +2168,7 @@ void clearChannelInSubscrCallbackTest ( const char *pName, unsigned level )
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
showProgressEnd ( level );
@@ -2172,7 +2179,7 @@ void monitorAddConnectionCallback ( struct connection_handler_args args )
if ( args.op == CA_OP_CONN_UP ) {
unsigned * pEventCount = ( unsigned * ) ca_puser ( args.chid );
int status;
assert ( *pEventCount == 0u );
verify ( *pEventCount == 0u );
(*pEventCount)++;
status = ca_create_subscription ( DBR_DOUBLE, 1,
args.chid, DBE_VALUE, nUpdatesTester, ca_puser ( args.chid ), 0 );
@@ -2201,7 +2208,7 @@ void monitorAddConnectionCallbackTest ( const char *pName, unsigned interestLeve
for ( i = 0; ca_get_ioc_connection_count () > 0 ; i++ ) {
ca_pend_event ( 0.1 );
assert ( i < 100 );
verify ( i < 100 );
}
status = ca_create_channel ( pName,
@@ -2211,15 +2218,15 @@ void monitorAddConnectionCallbackTest ( const char *pName, unsigned interestLeve
while ( eventCount < 2 ) {
ca_pend_event ( 0.1 );
}
assert ( eventCount == 2u );
verify ( eventCount == 2u );
status = ca_get_callback ( DBR_DOUBLE, chan, nUpdatesTester, &getCallbackCount );
SEVCHK ( status, "monitorAddConnectionCallback get callback" );
while ( getCallbackCount == 0 ) {
ca_pend_event ( 0.1 );
}
assert ( eventCount == 2u );
assert ( getCallbackCount == 1u );
verify ( eventCount == 2u );
verify ( getCallbackCount == 1u );
status = ca_clear_channel ( chan );
SEVCHK ( status, "monitorAddConnectionCallbackTest clear channel" );
@@ -2308,7 +2315,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
}
printf ( "-" );
fflush ( stdout );
assert ( tries++ < 50 );
verify ( tries++ < 50 );
}
showProgress ( interestLevel );
@@ -2339,7 +2346,10 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
SEVCHK ( ca_get ( DBR_FLOAT, chan, &getResp ), NULL );
SEVCHK ( ca_pend_io ( timeoutToPendIO ), NULL );
assert ( getResp == temp );
if ( getResp != temp ) {
printf ( "getResp=%f, temp=%f\n", getResp, temp );
verify ( getResp == temp );
}
/*
* wait for all of the monitors to have correct values
@@ -2355,7 +2365,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
* we shouldnt see old monitors because
* we resubscribed
*/
assert ( test[j].count <= i + 2 );
verify ( test[j].count <= i + 2 );
if ( test[j].lastValue == temp ) {
if ( test[j].count < i + 1 ) {
tmpFlowCtrlCount++;
@@ -2368,7 +2378,7 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
break;
}
if ( passCount == prevPassCount ) {
assert ( tries++ < 500 );
verify ( tries++ < 500 );
if ( tries % 50 == 0 ) {
for ( j = 0; j <= i; j++ ) {
dbr_float_t pat = monitorUpdateTestPattern ( j );
@@ -2428,7 +2438,7 @@ void verifyReasonableBeaconPeriod ( chid chan, unsigned interestLevel )
ca_name ( chan ), beaconPeriod );
watchDogDelay = ca_receive_watchdog_delay ( chan );
assert ( watchDogDelay >= 0.0 );
verify ( watchDogDelay >= 0.0 );
printf ( "busy: receive watchdog for \"%s\" expires in %g sec.\n",
ca_name ( chan ), watchDogDelay );
@@ -2446,7 +2456,7 @@ void verifyReasonableBeaconPeriod ( chid chan, unsigned interestLevel )
}
watchDogDelay = ca_receive_watchdog_delay ( chan );
assert ( watchDogDelay >= 0.0 );
verify ( watchDogDelay >= 0.0 );
printf ( "inactive: receive watchdog for \"%s\" expires in %g sec.\n",
ca_name ( chan ), watchDogDelay );
@@ -2465,9 +2475,9 @@ void verifyOldPend ( unsigned interestLevel )
* verify that the old ca_pend() is in the symbol table
*/
status = ca_pend ( 100000.0, 1 );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_pend ( 1e-12, 0 );
assert ( status == ECA_TIMEOUT );
verify ( status == ECA_TIMEOUT );
showProgressEnd ( interestLevel );
}
@@ -2485,21 +2495,21 @@ void verifyTimeStamps ( chid chan, unsigned interestLevel )
showProgressBegin ( "verifyTimeStamps", interestLevel );
status = epicsTimeGetCurrent ( & localTime );
assert ( status >= 0 );
verify ( status >= 0 );
status = ca_get ( DBR_TIME_DOUBLE, chan, & first );
SEVCHK ( status, "fetch of dbr time double failed\n" );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_get ( DBR_TIME_DOUBLE, chan, & last );
SEVCHK ( status, "fetch of dbr time double failed\n" );
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
length = epicsTimeToStrftime ( buf, sizeof ( buf ),
"%a %b %d %Y %H:%M:%S.%f", & first.stamp );
assert ( length );
verify ( length );
printf ("Processing time of channel \"%s\" was \"%s\"\n",
ca_name ( chan ), buf );
@@ -2553,7 +2563,7 @@ void verifyChannelPriorities ( const char *pName, unsigned interestLevel )
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "prioritized channel connect failed" );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
value = i;
status = ca_put ( DBR_DOUBLE, chan0, &value );
@@ -2592,7 +2602,7 @@ void verifyTearDownWhenChannelConnected ( const char * pName,
double * const pValues = (double * const) calloc ( chanCount, sizeof ( *pValues ) );
unsigned i, j;
assert ( pChans && pValues );
verify ( pChans && pValues );
showProgressBegin ( "verifyTearDownWhenChannelConnected", interestLevel );
@@ -2606,7 +2616,7 @@ void verifyTearDownWhenChannelConnected ( const char * pName,
}
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "immediate tear down channel connect failed" );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
for ( j = 0; j < chanCount; j++ ) {
status = ca_get ( DBR_DOUBLE, pChans[j], &pValues[j] );
@@ -2646,7 +2656,7 @@ void verifyImmediateTearDown ( const char * pName,
SEVCHK ( status, "immediate tear down channel create failed" );
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "immediate tear down channel connect failed" );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
/*
* verify that puts pending when we call ca_task_exit()
* get flushed out
@@ -2659,7 +2669,7 @@ void verifyImmediateTearDown ( const char * pName,
SEVCHK ( status, "immediate tear down channel get failed" );
if ( currentValue != ( (i - 1) % 8 ) ) {
printf ( "currentValue = %i, i = %i\n", currentValue, i );
assert ( currentValue == ( (i - 1) % 8 ) );
verify ( currentValue == ( (i - 1) % 8 ) );
}
}
status = ca_put ( DBR_LONG, chan, & value );
@@ -2700,12 +2710,12 @@ void fdRegCB ( void * parg, int fd, int opened )
if ( opened ) {
status = fdmgr_add_callback (
mgrCtx, fd, fdi_read, fdcb, 0 );
assert ( status >= 0 );
verify ( status >= 0 );
}
else {
status = fdmgr_clear_callback (
mgrCtx, fd, fdi_read );
assert ( status >= 0 );
verify ( status >= 0 );
}
}
@@ -2720,42 +2730,46 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
epicsTimeStamp begin, end;
mgrCtx = fdmgr_init ();
assert ( mgrCtx );
verify ( mgrCtx );
showProgressBegin ( "fdManagerVerify", interestLevel );
status = ca_add_fd_registration ( fdRegCB, mgrCtx );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_create_channel ( pName, 0, 0, 0, & newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
while ( ca_state ( newChan ) != cs_conn ) {
tmo.tv_sec = 6000;
tmo.tv_usec = 0;
status = fdmgr_pend_event ( mgrCtx, & tmo );
assert ( status >= 0 );
verify ( status >= 0 );
}
showProgress ( interestLevel );
status = ca_add_event ( DBR_FLOAT, newChan,
nUpdatesTester, & eventCount, & subscription );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_flush_io ();
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
while ( eventCount < 1 ) {
tmo.tv_sec = 6000;
tmo.tv_usec = 0;
status = fdmgr_pend_event ( mgrCtx, & tmo );
assert ( status >= 0 );
verify ( status >= 0 );
}
showProgress ( interestLevel );
status = ca_clear_event ( subscription );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_flush_io ();
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
/* look for infinite loop in fd manager schedualing */
epicsTimeGetCurrent ( & begin );
@@ -2765,23 +2779,25 @@ void fdManagerVerify ( const char * pName, unsigned interestLevel )
tmo.tv_sec = 1;
tmo.tv_usec = 0;
status = fdmgr_pend_event ( mgrCtx, & tmo );
assert ( status >= 0 );
verify ( status >= 0 );
epicsTimeGetCurrent ( & end );
delay = epicsTimeDiffInSeconds ( & end, & begin );
if ( delay >= 1.0 ) {
break;
}
assert ( eventCount++ < 100 );
verify ( eventCount++ < 100 );
}
showProgress ( interestLevel );
status = ca_clear_channel ( newChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_add_fd_registration ( 0, 0 );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = fdmgr_delete ( mgrCtx );
assert ( status >= 0 );
verify ( status >= 0 );
showProgressEnd ( interestLevel );
}
@@ -2798,13 +2814,13 @@ void verifyConnectWithDisconnectedChannels (
for ( i= 0u; i < NELEMENTS ( bogusChan ); i++ ) {
char buf[256];
sprintf ( buf, "aChannelThatShouldNeverNeverNeverExit%u", i );
sprintf ( buf, "aChannelThatShouldNeverNeverNeverExist%u", i );
status = ca_create_channel ( buf, 0, 0, 0, & bogusChan[i] );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
}
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_TIMEOUT );
status = ca_pend_io ( 0.001 );
verify ( status == ECA_TIMEOUT );
/* wait a long time for the search interval to increase */
for ( i= 0u; i < 10; i++ ) {
@@ -2813,7 +2829,7 @@ void verifyConnectWithDisconnectedChannels (
}
status = ca_create_channel ( pName, 0, 0, 0, & validChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
/*
* we should be able to connect to a valid
@@ -2822,14 +2838,14 @@ void verifyConnectWithDisconnectedChannels (
* diasconnected channel
*/
status = ca_pend_io ( timeoutToPendIO );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
status = ca_clear_channel ( validChan );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
for ( i= 0u; i < NELEMENTS ( bogusChan ); i++ ) {
status = ca_clear_channel ( bogusChan[i] );
assert ( status == ECA_NORMAL );
verify ( status == ECA_NORMAL );
}
showProgressEnd ( interestLevel );
@@ -2982,13 +2998,17 @@ void verifyContextRundownFlush ( const char * pName, unsigned interestLevel )
status = ca_pend_io ( timeoutToPendIO );
SEVCHK ( status, "get, pend io failed" );
assert ( stim == resp );
verify ( stim == resp );
status = ca_clear_channel ( chan );
SEVCHK ( status, NULL );
ca_context_destroy ();
}
if ( i % 100 == 0 ) {
showProgress ( interestLevel );
}
}
showProgressEnd ( interestLevel );
@@ -3051,7 +3071,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
verifyDataTypeMacros ();
connections = ca_get_ioc_connection_count ();
assert ( connections == 0u );
verify ( connections == 0u );
unequalServerBufferSizeTest ( pName, interestLevel );
clearChannelInGetCallbackTest ( pName, interestLevel );
clearChannelInPutCallbackTest ( pName, interestLevel );
@@ -3070,7 +3090,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
ca_element_count ( chan ) );
connections = ca_get_ioc_connection_count ();
assert ( connections == 1u || connections == 0u );
verify ( connections == 1u || connections == 0u );
if ( connections == 0u ) {
printf ( "testing with a local channel\n" );
}
@@ -3122,7 +3142,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
/* ca_client_status ( 6u ); info about each channel */
pChans = calloc ( channelCount, sizeof ( *pChans ) );
assert ( pChans );
verify ( pChans );
for ( i = 0; i < channelCount; i++ ) {
strncpy ( pChans[ i ].name, pName, sizeof ( pChans[ i ].name ) );

View File

@@ -66,7 +66,6 @@ void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn )
channelCount = channelCountIn;
pChans = new chid [channelCount];
assert ( pChans );
while ( 1 ) {
connCount = 0u;

View File

@@ -36,7 +36,6 @@ void caEventRate ( const char *pName, unsigned count )
unsigned eventCount = 0u;
chid * pChidTable = new chid [ count ];
assert ( pChidTable );
{
printf ( "Connecting to CA Channel \"%s\" %u times.",

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

@@ -145,7 +145,8 @@ private:
return;
}
pComBuf = newComBuf ();
assert ( pComBuf->push ( val ) );
bool success = pComBuf->push ( val );
assert ( success );
this->pushComBuf ( *pComBuf );
}

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

@@ -79,8 +79,8 @@ void nciu::destroy (
epicsGuard < epicsMutex > & guard )
{
while ( baseNMIU * pNetIO = this->eventq.first () ) {
assert ( this->cacCtx.destroyIO (
guard, pNetIO->getId (), *this ) );
bool success = this->cacCtx.destroyIO ( guard, pNetIO->getId (), *this );
assert ( success );
}
// if the claim reply has not returned yet then we will issue

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

@@ -511,7 +511,10 @@ void ca_repeater ()
pBuf = new char [MAX_UDP_RECV];
assert ( osiSockAttach() );
{
bool success = osiSockAttach();
assert ( success );
}
port = envGetInetPortConfigParam ( & EPICS_CA_REPEATER_PORT,
static_cast <unsigned short> (CA_REPEATER_PORT) );

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

@@ -50,7 +50,6 @@ public:
{
pvInfo::pFirst = this;
this->pName = new char [strlen(pNameIn)+1u];
assert(this->pName);
strcpy(this->pName, pNameIn);
}

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

@@ -21,9 +21,13 @@
#define epicsExportSharedSymbols
#include "casdef.h"
#include "epicsAssert.h"
#include "casEventRegistry.h"
#ifdef TEST
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
main ()
{
casEventRegistry reg;
@@ -49,20 +53,20 @@ main ()
art2.show(10u);
reg.show(10u);
assert (bill1 == bill2);
assert (bill1 == bill3);
assert (jane != bill1);
assert (jane != art1);
assert (bill1 != art1);
assert (art1 == art2);
verify (bill1 == bill2);
verify (bill1 == bill3);
verify (jane != bill1);
verify (jane != art1);
verify (bill1 != art1);
verify (art1 == art2);
artBill = art1 | bill1;
tmp = artBill & art1;
assert (tmp.eventsSelected());
verify (tmp.eventsSelected());
tmp = artBill & bill1;
assert (tmp.eventsSelected());
verify (tmp.eventsSelected());
tmp = artBill&jane;
assert (tmp.noEventsSelected());
verify (tmp.noEventsSelected());
}
#endif
@@ -128,10 +132,8 @@ casEventMaskEntry::casEventMaskEntry (
casEventRegistry & regIn, casEventMask maskIn, const char * pName ) :
casEventMask ( maskIn ), stringId ( pName ), reg ( regIn )
{
int stat;
assert ( this->resourceName() != NULL );
stat = this->reg.add ( *this );
int stat = this->reg.add ( *this );
assert ( stat == 0 );
}

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

@@ -613,7 +613,7 @@ static void dbBkptCont(dbCommon *precord)
--lset_stack_count;
/* free entrypoint queue */
ellFree(&pnode->ep_queue, free);
ellFree(&pnode->ep_queue);
/* remove execution semaphore */
epicsEventDestroy(pnode->ex_sem);

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

@@ -135,7 +135,7 @@ epicsShareFunc long
if (itop)
*ptop = (long) *ptop % itop;
else
*ptop = 0.0 / itop; /* NaN */
*ptop = epicsNAN; /* NaN */
break;
case POWER:

View File

@@ -25,6 +25,9 @@ typedef intId<unsigned,8,16> testIntId;
typedef intId<unsigned,8> testIntId;
#endif
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
static void empty()
{
}
@@ -34,7 +37,7 @@ public:
albert (resTable< albert, testIntId > &atIn, unsigned idIn) :
testIntId(idIn), at(atIn)
{
assert (at.add (*this)==0);
verify (at.add (*this)==0);
}
void show (unsigned /* level */)
{
@@ -125,52 +128,52 @@ int main()
intTbl.setTableSize ( 100000 );
assert (intTbl.add(fred0)==0);
verify (intTbl.add(fred0)==0);
intTbl.verify ();
assert (intTbl.add(fred1)==0);
verify (intTbl.add(fred1)==0);
intTbl.verify ();
assert (intTbl.add(fred2)==0);
verify (intTbl.add(fred2)==0);
intTbl.verify ();
assert (intTbl.add(fred3)==0);
verify (intTbl.add(fred3)==0);
intTbl.verify ();
assert (intTbl.add(fred4)==0);
verify (intTbl.add(fred4)==0);
intTbl.verify ();
intTbl.setTableSize ( 200000 );
assert (intTbl.add(fred5)==0);
verify (intTbl.add(fred5)==0);
intTbl.verify ();
assert (intTbl.add(fred6)==0);
verify (intTbl.add(fred6)==0);
intTbl.verify ();
assert (intTbl.add(fred7)==0);
verify (intTbl.add(fred7)==0);
intTbl.verify ();
assert (intTbl.add(fred8)==0);
verify (intTbl.add(fred8)==0);
intTbl.verify ();
assert (intTbl.add(fred9)==0);
verify (intTbl.add(fred9)==0);
intTbl.verify ();
start = clock();
for (i=0; i<LOOPS; i++) {
pFred = intTbl.lookup(intId1);
assert(pFred==&fred1);
verify(pFred==&fred1);
pFred = intTbl.lookup(intId2);
assert(pFred==&fred2);
verify (pFred==&fred2);
pFred = intTbl.lookup(intId3);
assert(pFred==&fred3);
verify (pFred==&fred3);
pFred = intTbl.lookup(intId4);
assert(pFred==&fred4);
verify (pFred==&fred4);
pFred = intTbl.lookup(intId5);
assert(pFred==&fred5);
verify (pFred==&fred5);
pFred = intTbl.lookup(intId6);
assert(pFred==&fred6);
verify (pFred==&fred6);
pFred = intTbl.lookup(intId7);
assert(pFred==&fred7);
verify (pFred==&fred7);
pFred = intTbl.lookup(intId8);
assert(pFred==&fred8);
verify (pFred==&fred8);
pFred = intTbl.lookup(intId9);
assert(pFred==&fred9);
verify (pFred==&fred9);
pFred = intTbl.lookup(intId0);
assert(pFred==&fred0);
verify (pFred==&fred0);
}
finish = clock();
@@ -187,35 +190,35 @@ int main()
intTbl.remove(intId1);
intTbl.remove(intId2);
pFred = intTbl.lookup(intId1);
assert(pFred==0);
verify (pFred==0);
pFred = intTbl.lookup(intId2);
assert(pFred==0);
verify (pFred==0);
assert (strTbl.add(jane1)==0);
assert (strTbl.add(jane2)==0);
verify (strTbl.add(jane1)==0);
verify (strTbl.add(jane2)==0);
start = clock();
for(i=0; i<LOOPS; i++){
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
verify (pJane==&jane1);
pJane = strTbl.lookup(strId2);
assert(pJane==&jane2);
verify (pJane==&jane2);
}
finish = clock();
@@ -264,7 +267,7 @@ int main()
for (i=0; i<elementCount; i++) {
pAlbert[i] = new albert (alTbl, i);
assert ( pAlbert[i] );
verify ( pAlbert[i] );
}
alTbl.verify ();
alTbl.show (1u);
@@ -276,26 +279,26 @@ int main()
i++;
alTblIter++;
}
assert ( i == elementCount );
verify ( i == elementCount );
alTbl.verify ();
for ( i = 0; i < elementCount; i++ ) {
assert ( pAlbert[i] == alTbl.lookup( pAlbert[i]->getId() ) );
verify ( pAlbert[i] == alTbl.lookup( pAlbert[i]->getId() ) );
}
alTbl.verify ();
for ( i = 0; i < elementCount; i += 2 ) {
assert ( pAlbert[i] == alTbl.remove ( pAlbert[i]->getId() ) );
verify ( pAlbert[i] == alTbl.remove ( pAlbert[i]->getId() ) );
}
alTbl.verify ();
for ( i = 0; i < elementCount; i += 2 ) {
assert ( 0 == alTbl.lookup ( pAlbert[i]->getId() ) );
verify ( 0 == alTbl.lookup ( pAlbert[i]->getId() ) );
}
alTbl.verify ();
for ( i = 1; i < elementCount; i += 2 ) {
assert ( pAlbert[i] == alTbl.lookup ( pAlbert[i]->getId() ) );
verify ( pAlbert[i] == alTbl.lookup ( pAlbert[i]->getId() ) );
}
alTbl.verify ();

View File

@@ -67,7 +67,8 @@ int main ()
clk = clock ();
for (i=0u; i<LOOPCOUNT; i++) {
assert ( tree.verify(a) );
bool success = tree.verify(a);
assert ( success );
}
diff = clock () - clk;
delay = diff;
@@ -77,13 +78,14 @@ int main ()
clk = clock ();
while ( ( pA = list.get () ) ) {
assert (tree.remove(*pA));
bool success = tree.remove(*pA);
assert ( success );
}
diff = clock () - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf ("delay = %15.10f\n", delay);
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf ("delay = %15.10f\n", delay);
tree.traverse (&A::show);

View File

@@ -14,6 +14,9 @@
#include "tsBTree.h"
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
class A : public tsBTreeNode<A> {
public:
A(const char *pNameIn) : pName(pNameIn) {}
@@ -57,30 +60,30 @@ int main ()
tree.traverse (&A::show);
assert (tree.remove(a6)==tsbtrrNotFound);
verify (tree.remove(a6)==tsbtrrNotFound);
tree.insert (a6);
assert (tree.remove(a6)==tsbtrrFound);
assert (tree.remove(a5)==tsbtrrFound);
assert (tree.remove(a5)==tsbtrrNotFound);
assert (!tree.verify(a5));
assert (tree.verify(a4));
assert (tree.remove(a0)==tsbtrrFound);
assert (!tree.verify(a0));
assert (tree.remove(a0)==tsbtrrNotFound);
verify (tree.remove(a6)==tsbtrrFound);
verify (tree.remove(a5)==tsbtrrFound);
verify (tree.remove(a5)==tsbtrrNotFound);
verify (!tree.verify(a5));
verify (tree.verify(a4));
verify (tree.remove(a0)==tsbtrrFound);
verify (!tree.verify(a0));
verify (tree.remove(a0)==tsbtrrNotFound);
tree.insert (a5);
assert (tree.verify(a5));
assert (tree.verify(a2));
assert (tree.remove(a2)==tsbtrrFound);
assert (!tree.verify(a2));
assert (tree.remove(a2)==tsbtrrNotFound);
assert (tree.verify(a5));
assert (tree.remove(a5)==tsbtrrFound);
assert (tree.remove(a5)==tsbtrrNotFound);
assert (tree.remove(a0)==tsbtrrNotFound);
assert (tree.remove(a4)==tsbtrrFound);
assert (tree.remove(a3)==tsbtrrFound);
assert (tree.remove(a4)==tsbtrrNotFound);
assert (tree.remove(a1)==tsbtrrFound);
verify (tree.verify(a5));
verify (tree.verify(a2));
verify (tree.remove(a2)==tsbtrrFound);
verify (!tree.verify(a2));
verify (tree.remove(a2)==tsbtrrNotFound);
verify (tree.verify(a5));
verify (tree.remove(a5)==tsbtrrFound);
verify (tree.remove(a5)==tsbtrrNotFound);
verify (tree.remove(a0)==tsbtrrNotFound);
verify (tree.remove(a4)==tsbtrrFound);
verify (tree.remove(a3)==tsbtrrFound);
verify (tree.remove(a4)==tsbtrrNotFound);
verify (tree.remove(a1)==tsbtrrFound);
tree.traverse (&A::show);

View File

@@ -14,6 +14,9 @@
#include <assert.h>
#include <stdio.h>
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
class fred : public tsDLNode<fred> {
public:
fred(const char * const pNameIn) : pName(pNameIn){}
@@ -46,16 +49,16 @@ int main ()
list.add (*pFred);
list.add (*pFredII);
tsDLIter <fred> iter = list.firstIter();
assert (iter.pointer() == pFred);
verify (iter.pointer() == pFred);
iter++;
assert (iter.pointer() == pFredII);
verify (iter.pointer() == pFredII);
list.remove(*pFred);
list.add(*pFred);
pFredBack = list.get();
assert (pFredBack == pFredII);
verify (pFredBack == pFredII);
pFredBack = list.get();
assert (pFredBack == pFred);
assert (list.count() == 0u);
verify (pFredBack == pFred);
verify (list.count() == 0u);
list.add(*pFred);
list.add(*pFredII);
list.add(* new fred("C"));
@@ -70,9 +73,9 @@ int main ()
pJane = new jane("JA");
janeList.add(*pJane);
pJane = new jane("JB");
assert ( janeList.find ( *pJane ) == -1 );
verify ( janeList.find ( *pJane ) == -1 );
janeList.add(*pJane);
assert ( janeList.find ( *pJane ) == 1 );
verify ( janeList.find ( *pJane ) == 1 );
while ( janeFwdIter.valid() ) {
janeFwdIter->show();
@@ -96,21 +99,21 @@ int main ()
i++;
bdIter++;
}
assert ( i == janeList.count () );
verify ( i == janeList.count () );
iter = list.firstIter();
while ( iter.pointer() ) {
list.remove( * iter.pointer() );
iter++;
}
assert(list.count()==0);
verify (list.count()==0);
janeFwdIter = janeList.firstIter();
while ( janeFwdIter.valid() ) {
janeList.remove( * janeFwdIter.pointer() );
janeFwdIter++;
}
assert(janeList.count()==0);
verify (janeList.count()==0);
pJane = new jane("JA");
janeList.add(*pJane);
@@ -121,7 +124,7 @@ int main ()
janeList.remove( * janeBwdIter.pointer() );
janeBwdIter--;
}
assert(janeList.count()==0);
verify (janeList.count()==0);
return 0;
}

View File

@@ -263,11 +263,10 @@ int ellFind (ELLLIST *pList, ELLNODE *pNode)
*
* NOTE: the nodes in the list are free()'d on the assumption that the node
* structures were malloc()'d one-at-a-time and that the ELLNODE structure is
* the first thing in the "rest of" the node structure.
* In other words, this is a pretty worthless function.
* the first member of the parent structure.
*
*****************************************************************************/
void ellFree (ELLLIST *pList, FREEFUNC freeFunc)
void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc)
{
ELLNODE *nnode = pList->node.next;
ELLNODE *pnode;

View File

@@ -45,6 +45,7 @@ typedef void (*FREEFUNC)(void *);
#define ellLast(PLIST) ((PLIST)->node.previous)
#define ellNext(PNODE) ((PNODE)->next)
#define ellPrevious(PNODE) ((PNODE)->previous)
#define ellFree(PLIST) ellFree2(PLIST, free)
epicsShareFunc void ellAdd (ELLLIST *pList, ELLNODE *pNode);
epicsShareFunc void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList);
@@ -55,8 +56,7 @@ epicsShareFunc void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode);
epicsShareFunc ELLNODE * ellNth (ELLLIST *pList, int nodeNum);
epicsShareFunc ELLNODE * ellNStep (ELLNODE *pNode, int nStep);
epicsShareFunc int ellFind (ELLLIST *pList, ELLNODE *pNode);
/* ellFree has to take a free function to work properly on Windows */
epicsShareFunc void ellFree (ELLLIST *pList, FREEFUNC freeFunc);
epicsShareFunc void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc);
epicsShareFunc void ellVerify (ELLLIST *pList);
#ifdef __cplusplus

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

@@ -3,8 +3,7 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*epicsExit.c*/
@@ -52,7 +51,7 @@ static epicsThreadPrivateId exitPvtPerThread = 0;
static void destroyExitPvt ( exitPvt * pep )
{
ellFree ( &pep->list, free );
ellFree ( &pep->list );
free ( pep );
}

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

@@ -1,27 +1,24 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef epicsInterrupth
#define epicsInterrupth
/*THIS MAY BE A BIG PROBLEM */
#ifdef __cplusplus
extern "C" {
#endif
#include "shareLib.h"
epicsShareFunc int epicsShareAPI epicsInterruptLock(void);
epicsShareFunc void epicsShareAPI epicsInterruptUnlock(int key);
epicsShareFunc int epicsShareAPI epicsInterruptIsInterruptContext(void);
epicsShareFunc void epicsShareAPI epicsInterruptContextMessage(const char *message);
epicsShareFunc int epicsInterruptLock(void);
epicsShareFunc void epicsInterruptUnlock(int key);
epicsShareFunc int epicsInterruptIsInterruptContext(void);
epicsShareFunc void epicsInterruptContextMessage(const char *message);
#ifdef __cplusplus
}

View File

@@ -9,6 +9,11 @@
#define epicsExportSharedSymbols
#include <epicsMath.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4723)
#endif
static float makeNAN ( void )
{
float a = 0, b = 0;
@@ -25,3 +30,8 @@ extern "C" {
epicsShareDef float epicsNAN = makeNAN();
epicsShareDef float epicsINF = makeINF();
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif

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
@@ -110,7 +128,8 @@ void epicsThread::exit ()
void epicsThread::exitWait () throw ()
{
assert ( this->exitWait ( DBL_MAX ) );
bool success = this->exitWait ( DBL_MAX );
assert ( success );
}
bool epicsThread::exitWait ( const double delay ) throw ()
@@ -276,6 +295,27 @@ void epicsThreadPrivateBase::throwUnableToCreateThreadPrivate ()
throw epicsThreadPrivateBase::unableToCreateThreadPrivate ();
}
void epicsThread :: show ( unsigned level ) const throw ()
{
::printf ( "epicsThread at %p\n", this->id );
if ( level > 0u ) {
epicsThreadShow ( this->id, level - 1 );
if ( level > 1u ) {
::printf ( "pWaitReleaseFlag = %p\n", this->pWaitReleaseFlag );
::printf ( "begin = %c, cancel = %c, terminated = %c\n",
this->begin ? 'T' : 'F',
this->cancel ? 'T' : 'F',
this->terminated ? 'T' : 'F' );
this->runable.show ( level - 2u );
this->mutex.show ( level - 2u );
::printf ( "general purpose event\n" );
this->event.show ( level - 2u );
::printf ( "exit event\n" );
this->exitEvent.show ( level - 2u );
}
}
}
extern "C" {
static epicsThreadOnceId okToBlockOnce = EPICS_THREAD_ONCE_INIT;
epicsThreadPrivateId okToBlockPrivate;

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

@@ -1,18 +1,15 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* osi/default/osdInterrupt.c */
/* Author: Marty Kraimer Date: 15JUL99 */
/* This is a version that does not allow osi calls at interrupt level */
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
@@ -21,34 +18,41 @@
#define epicsExportSharedSymbols
#include "epicsMutex.h"
#include "epicsThread.h"
#include "cantProceed.h"
#include "errlog.h"
#include "epicsInterrupt.h"
static epicsMutexId globalLock=0;
static int firstTime = 1;
epicsShareFunc int epicsShareAPI epicsInterruptLock()
static epicsMutexId globalLock = NULL;
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
static void initOnce(void *junk)
{
if(firstTime) {
globalLock = epicsMutexMustCreate();
firstTime = 0;
}
epicsMutexMustLock(globalLock);
return(0);
globalLock = epicsMutexMustCreate();
}
epicsShareFunc void epicsShareAPI epicsInterruptUnlock(int key)
epicsShareFunc int epicsInterruptLock()
{
if(firstTime) cantProceed(
"epicsInterruptUnlock called before epicsInterruptLock\n");
epicsThreadOnce(&onceId, initOnce, NULL);
epicsMutexMustLock(globalLock);
return 0;
}
epicsShareFunc void epicsInterruptUnlock(int key)
{
if (!globalLock)
cantProceed("epicsInterruptUnlock called before epicsInterruptLock\n");
epicsMutexUnlock(globalLock);
}
epicsShareFunc int epicsShareAPI epicsInterruptIsInterruptContext() { return(0);}
epicsShareFunc void epicsShareAPI epicsInterruptContextMessage(const char *message)
epicsShareFunc int epicsInterruptIsInterruptContext()
{
errlogPrintf("%s",message);
return 0;
}
epicsShareFunc void epicsInterruptContextMessage(const char *message)
{
errlogPrintf("%s", message);
}

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

@@ -18,6 +18,9 @@
#include "epicsUnitTest.h"
#include "testMain.h"
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
union address {
struct sockaddr_in ia;
struct sockaddr sa;
@@ -73,7 +76,7 @@ circuit::circuit ( SOCKET sockIn ) :
recvWakeup ( false ),
sendWakeup ( false )
{
assert ( this->sock != INVALID_SOCKET );
verify ( this->sock != INVALID_SOCKET );
}
bool circuit::recvWakeupDetected () const
@@ -89,7 +92,7 @@ bool circuit::sendWakeupDetected () const
void circuit::shutdown ()
{
int status = ::shutdown ( this->sock, SHUT_RDWR );
assert ( status == 0 );
verify ( status == 0 );
}
void circuit::signal ()
@@ -141,14 +144,14 @@ clientCircuit::clientCircuit ( const address & addrIn ) :
address tmpAddr = addrIn;
int status = ::connect (
this->sock, & tmpAddr.sa, sizeof ( tmpAddr ) );
assert ( status == 0 );
verify ( status == 0 );
circuit * pCir = this;
this->id = epicsThreadCreate (
"client circuit", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
socketRecvTest, pCir );
assert ( this->id );
verify ( this->id );
}
@@ -166,7 +169,7 @@ server::server ( const address & addrIn ) :
sock ( epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ),
id ( 0 ), exit ( false )
{
assert ( this->sock != INVALID_SOCKET );
verify ( this->sock != INVALID_SOCKET );
// setup server side
address tmpAddr = addrIn;
@@ -177,7 +180,7 @@ server::server ( const address & addrIn ) :
testAbort ( "Stop all CA servers before running this test." );
}
status = listen ( this->sock, 10 );
assert ( status == 0 );
verify ( status == 0 );
}
void server::start ()
@@ -186,7 +189,7 @@ void server::start ()
"server daemon", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
serverDaemon, this );
assert ( this->id );
verify ( this->id );
}
void server::daemon ()
@@ -197,9 +200,9 @@ void server::daemon ()
osiSocklen_t addressSize = sizeof ( addr );
SOCKET ns = accept ( this->sock,
& addr.sa, & addressSize );
assert ( ns != INVALID_SOCKET );
verify ( ns != INVALID_SOCKET );
circuit * pCir = new serverCircuit ( ns );
assert ( pCir );
verify ( pCir );
}
}
@@ -211,7 +214,7 @@ serverCircuit::serverCircuit ( SOCKET sockIn ) :
"server circuit", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
socketRecvTest, pCir );
assert ( threadId );
verify ( threadId );
}
const char * serverCircuit::pName ()
@@ -253,7 +256,7 @@ MAIN(blockingSockTest)
clientCircuit client ( addr );
epicsThreadSleep ( 1.0 );
assert ( ! client.recvWakeupDetected () );
verify ( ! client.recvWakeupDetected () );
client.shutdown ();
epicsThreadSleep ( 1.0 );

View File

@@ -14,6 +14,9 @@
#include "bucketLib.h"
#include "testMain.h"
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
MAIN(buckTest)
{
unsigned id1;
@@ -36,35 +39,35 @@ MAIN(buckTest)
id1 = 0x1000a432;
pValSave1 = "fred";
s = bucketAddItemUnsignedId(pb, &id1, pValSave1);
assert (s == S_bucket_success);
verify (s == S_bucket_success);
pValSave2 = "jane";
id2 = 0x0000a432;
s = bucketAddItemUnsignedId(pb, &id2, pValSave2);
assert (s == S_bucket_success);
verify (s == S_bucket_success);
start = clock();
for(i=0; i<LOOPS; i++){
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
verify (pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id2);
assert(pVal == pValSave2);
verify (pVal == pValSave2);
}
finish = clock();

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

@@ -161,7 +161,7 @@ MAIN(epicsEllTest)
testOk1(ellFind(&list2, ellNth(&list2, 10)) == 10);
testOk1(ellFind(&list1, ellNth(&list1, 11)) == 11);
ellFree(&list2, free);
ellFree(&list2);
testOk1(ellCount(&list2) == 0);
pick = (struct myItem *)ellFirst(&list1);
@@ -190,7 +190,7 @@ MAIN(epicsEllTest)
pitem = (struct myItem *)ellNStep(&pitem->node, -4);
testOk1(pitem->num == 7);
ellFree(&list1, free);
ellFree2(&list1, free);
testOk1(ellCount(&list1) == 0);
return testDone();

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

@@ -26,6 +26,8 @@
#include "epicsUnitTest.h"
#include "testMain.h"
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
static const double delayVerifyOffset = 1.0; // sec
@@ -368,7 +370,7 @@ epicsTimerNotify::expireStatus periodicVerify::expire ( const epicsTime & )
for ( unsigned i = 0u; i < 1000; i++ ) {
root = sqrt ( root );
}
assert ( ! this->cancelCalled );
verify ( ! this->cancelCalled );
double delay = rand ();
delay = delay / RAND_MAX;
delay /= 10.0;

View File

@@ -15,6 +15,9 @@
#include "epicsAssert.h"
#include "cadef.h"
#define verify(exp) ((exp) ? (void)0 : \
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
static const unsigned uSecPerSec = 1000000;
typedef struct cbStructCreateDestroyFD {
@@ -38,12 +41,12 @@ void fdCreateDestroyHandler (void *pArg, int fd, int open)
if (open) {
printf ("new fd = %d\n", fd);
status = fdmgr_add_callback (pCBFD->pfdm, fd, fdi_read, fdHandler, pArg);
assert (status==0);
verify (status==0);
}
else {
printf ("terminated fd = %d\n", fd);
status = fdmgr_clear_callback (pCBFD->pfdm, fd, fdi_read);
assert (status==0);
verify (status==0);
}
}
@@ -74,13 +77,13 @@ void testTimer (fdctx *pfdm, double delay)
tmo.tv_sec = (unsigned long) delay;
tmo.tv_usec = (unsigned long) ((delay - tmo.tv_sec) * uSecPerSec);
aid = fdmgr_add_timeout (pfdm, &tmo, alarmCB, &cbs);
assert (aid!=fdmgrNoAlarm);
verify (aid!=fdmgrNoAlarm);
while (!cbs.done) {
tmo.tv_sec = (unsigned long) delay;
tmo.tv_usec = (unsigned long) ((delay - tmo.tv_sec) * uSecPerSec);
status = fdmgr_pend_event (pfdm, &tmo);
assert (status==0);
verify (status==0);
}
measuredDelay = epicsTimeDiffInSeconds (&cbs.time, &begin);
@@ -98,7 +101,7 @@ int main (int argc, char **argv)
chid chan;
pfdm = fdmgr_init ();
assert (pfdm);
verify (pfdm);
SEVCHK (ca_task_initialize(), NULL);
cbsfd.pfdm = pfdm;
@@ -121,12 +124,12 @@ int main (int argc, char **argv)
tmo.tv_usec = 100000;
cbsfd.trig = 0;
status = fdmgr_pend_event (pfdm, &tmo);
assert (status==0);
verify (status==0);
ca_poll ();
}
status = fdmgr_delete (pfdm);
assert (status==0);
verify (status==0);
printf ( "Test Complete\n" );

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

Some files were not shown because too many files have changed in this diff Show More