Compare commits

...

174 Commits

Author SHA1 Message Date
Ralph Lange
65574b5971 Update CONFIG_BASE_VERSION for 3.15.4, remove "not released" from RELEASE_NOTES 2016-05-27 08:54:04 +02:00
Andrew Johnson
4284222b54 Convert GUI_ promptgroup strings to new-style 2016-05-26 16:15:48 +02:00
Ralph Lange
54bab1e2f0 pcas: fix compiler warning (gcc 5.3.1) 2016-05-26 14:14:56 +02:00
Andrew Johnson
df200de27f Fix lsi/lso puts with DBF_STRING data 2016-05-26 13:49:18 +02:00
Ralph Lange
22d6ebe7e1 Merge changes from 3.14 branch up to rev 12642 2016-05-26 13:18:38 +02:00
Ralph Lange
9c3ed1bfe2 catools: fix escape handling when sending long strings 2016-05-26 13:13:29 +02:00
Ralph Lange
23fd4e202b ca: Fix client bug (race condition) in ipAddrToAsciiEngine 2016-05-25 12:26:32 +02:00
Andrew Johnson
a5b8b0b890 Use fabs() in calcPerform 2016-05-24 11:12:25 +02:00
Andrew Johnson
988614ae8a Reset SNAPSHOT after -rc1 tagged 2016-05-22 06:06:53 +02:00
Ralph Lange
fe887b4f83 Update CONFIG_BASE_VERSION for 3.15.4-rc1 2016-05-20 16:37:06 +02:00
Andrew Johnson
7be7ad2768 Merge changes from 3.14 branch, to revno 12640 2016-05-18 10:44:16 -05:00
Andrew Johnson
6c9555310a Update EPICS_TIMEZONE with info for 2016-2021 2016-05-18 10:26:04 -05:00
Andrew Johnson
4ccc2e9d3a Merged my devEnviron branch 2016-05-18 09:48:22 -05:00
Andrew Johnson
122fb6c731 New "getenv" device support for string input types 2016-05-17 19:09:48 -05:00
Andrew Johnson
3b8fd13152 libCom: NTP Time Provider adjusts to OS tick rate changes
Allow the NTP Time provider (used on VxWorks and RTEMS only)
to adapt to changes in the OS clock tick rate after the provider
has been initialized.

Changing the tick rate after iocInit() is not advisable,
other software might still misbehave if initialized before
an OS tick rate change.

Back-ported from the 3.15 branch (commit 12468).
2016-05-17 16:03:27 -05:00
Andrew Johnson
04a9fdb4e3 Clean up warnings from gcc 5.2 2016-05-16 17:02:34 -05:00
Andrew Johnson
3c61880d79 Allow some callback slow-ups before failing tests
The tests occasionally fail on Windows because the server
is busy; this will accept up to 4 slow callbacks without
them causing the build to fail.
2016-05-16 16:55:50 -05:00
Andrew Johnson
8081d3ada4 Merged Till's fix for lp:1581212, modified 2016-05-13 14:48:08 -05:00
Andrew Johnson
6d35ee9c3c Move dbLock.h *after* epicsExportSharedSymbols 2016-05-13 13:40:37 -05:00
Andrew Johnson
b5a0657adc Applied Till's fix for lp:1581212 2016-05-13 13:30:55 -05:00
Andrew Johnson
b87f3eaaee Merged changes from 3.14 branch to revno 12636 2016-05-13 13:12:08 -05:00
Andrew Johnson
6db0e13809 Added CROSS_COMPILER_RUNTEST_ARCHS 2016-05-13 13:00:48 -05:00
Michael Davidsaver
0f6c997288 osdNetIntf: ignore 0.0.0.0 as a broadcast address
It seems in some situations Linux (at least)
sets IFF_BROADCAST bug leaves the bcast address
set to 0.0.0.0.

Fixes lp:1581505
2016-05-13 09:31:26 -04:00
Michael Davidsaver
704c748fbd Revert "libCom/osi: osiSockDiscoverBroadcastAddresses() finds 127.255.255.255"
This reverts commit e805abe971.
2016-05-13 09:14:20 -04:00
Andrew Johnson
82456f83ee Fix Menu declaration test 2016-05-12 16:35:54 -05:00
Andrew Johnson
e98a6bbafa Make <menu>_NUM_CHOICES not an enum tag
Fixes lp:1580972
2016-05-12 15:05:18 -05:00
Andrew Johnson
9b51444fb7 Fix data types and macro name 2016-05-04 18:15:54 -05:00
Andrew Johnson
3be97865b3 Warn instead of building cap5 if xsubpp is missing 2016-05-04 14:41:51 -05:00
Andrew Johnson
67097456e3 Add additional RELEASE file checks
These checks are important for mixing Debian modules with
privately-built applications.
2016-05-03 12:26:40 -05:00
Andrew Johnson
3c8af4c571 Catch bad attribute names/values to prevent a segfault 2016-05-02 11:38:51 -05:00
Michael Davidsaver
26c04844cf add test for lp:1577108 2016-05-01 13:30:45 -04:00
Michael Davidsaver
a3d981ad0a dbLink.c: fix dbGetLink for array of length 1 2016-05-01 13:30:45 -04:00
Ralph Lange
924aa2f93b Set Base version to -pre1-DEV 2016-04-29 12:20:35 +02:00
Ralph Lange
457fb8fa13 Update CONFIG_BASE_VERSION for 3.15.4-pre1 2016-04-29 11:34:05 +02:00
Ralph Lange
b8b259de6f Merge Andrew's libs-prereq branch 2016-04-29 10:42:03 +02:00
Andrew Johnson
7ce8e5ea01 Fix RTEMS Makefile issue 2016-04-28 23:59:39 -05:00
Andrew Johnson
496414c88c Fix for VxWorks 5.5 compiler 2016-04-28 23:28:39 -05:00
Andrew Johnson
2acde8bac7 Merged changes from 3.14 branch to revno 12630 2016-04-28 21:39:55 -05:00
Andrew Johnson
2c69ddbee5 Merged my ioc-arch branch, manually re-based 2016-04-28 19:26:11 -05:00
Andrew Johnson
ba0d5f9443 Disallow single-quoted strings in Perl DBD parser 2016-04-28 19:03:17 -05:00
Andrew Johnson
08fd987c60 Perl script clean-up 2016-04-28 19:00:37 -05:00
Andrew Johnson
5a605fa0c3 Set various EPICS_VERSION_* environment variables
These are set at the same time as the ARCH variable.
Had to add EPICS_VERSION_SHORT and EPICS_VERSION_FULL to epicsVersion.h.

This uses more uniform names, should we change epicsVersion.h names?
We would continue to support the old names in parallel for some time.
2016-04-28 18:58:07 -05:00
Andrew Johnson
0e5dc2a21c More build parameters.
Renamed EPICS_TARGET_ARCH to EPICS_BUILD_TARGET_ARCH
Added EPICS_BUILD_OS_CLASS and EPICS_BUILD_COMPILER_CLASS
2016-04-28 18:56:03 -05:00
Andrew Johnson
230603f4ac Remove ARCH from cdCommands and envPaths files
Set it in iocshRegisterCommon() instead.
Remove ARCH from iocBoot/ioc/Makefile@Common templates.
2016-04-28 18:50:41 -05:00
Andrew Johnson
396ff3c484 Add EPICS_TARGET_ARCH parameter
Set its default value automatically in the generated envData.c
2016-04-28 18:49:10 -05:00
Andrew Johnson
09fbeaf6d3 Merged Ralph's new-promptgroups branch 2016-04-28 18:27:15 -05:00
Andrew Johnson
b4a8a1ac98 Fix dbFreeBase() issue causing segfaults 2016-04-28 18:10:26 -05:00
Andrew Johnson
ee87aecd6e Always have linker search INSTALL_LIB 2016-04-28 14:32:21 -05:00
Andrew Johnson
054a234c70 Parentheses in macro 2016-04-28 13:27:47 -05:00
Andrew Johnson
24ddcd2524 Fix epicsTimeZoneTest.cpp => .c and remove conditional 2016-04-27 12:09:10 -05:00
Michael Davidsaver
2226f3acb9 libCom/test: don't include epicsTimeZoneTest for vxWorks 2016-04-27 12:45:18 -04:00
Andrew Johnson
f0f89b4b1c Fix file paths in comments 2016-04-27 10:28:57 -05:00
Andrew Johnson
fdda079b8f BSD's finite expects a double; make glibc 2.23 happy 2016-04-27 10:28:01 -05:00
Ralph Lange
1f36670175 dbStatic: remove obsolete GUIGROUPS_GBLSOURCE definition 2016-04-27 09:14:51 +02:00
Andrew Johnson
1ede873200 Fixed some space/tab issues in DBD files 2016-04-26 16:20:12 -05:00
Michael Davidsaver
51dd371784 rsrv: add rsrvCS_shutdown to avoid race in destroyAllChannels()
A race can occur between rsrv and cac by way of asLib
whereby casAccessRightsCB() is called after
a channel_in_use has been removed from
chanList/chanPendingUpdateARList.
casAccessRightsCB() would then attempt to remove
the node again, causing corruption.

Create a new rsrvCS_shutdown state when the
channel is not in either list.

Attempt to resolve lp:1571224
2016-04-26 17:06:22 -04:00
Andrew Johnson
72745d7b0c Only make runtests and tapfiles if T_A = EPICS_HOST_ARCH 2016-04-29 16:20:25 -05:00
Andrew Johnson
c933d77963 Add rule to install libraries before linking executables
The rule must be disabled for building libCom and gdd though.
2016-04-26 15:18:31 -05:00
Michael Davidsaver
93597e20d5 add epicsTimeZoneTest to libCom test harness 2016-04-26 09:59:22 -04:00
Michael Davidsaver
f0453faf36 libCom/test: add test for HST time zone
Test US/Hawaii zone which does not observe daylight saving time.
2016-04-26 09:28:09 -04:00
Ralph Lange
473992cfb9 Update release notes 2016-04-26 13:47:12 +02:00
Ralph Lange
6a362f467d rec: implement new promptgroup (gui_group) choices 2016-04-26 13:28:28 +02:00
Andrew Johnson
af07e0fd51 Fix oops in last commit 2016-04-25 12:24:05 -05:00
Andrew Johnson
de38b80795 Apply partial solution for Windows builds of Cap5 2016-04-25 11:54:17 -05:00
Ralph Lange
7bb27ad3e7 dbStatic: deprecate guigroup.h; remove from includes 2016-04-22 17:02:21 +02:00
Ralph Lange
1e1799c30e tools: change RE to allow any value for promptgroup in the Perl DBD parser 2016-04-18 09:56:41 +02:00
Andrew Johnson
8358580190 Merged commit 12623 from 3.14 branch. 2016-04-15 17:38:41 -05:00
Andrew Johnson
24e39b252d Print RTEMS version at startup 2016-04-15 17:37:07 -05:00
Ralph Lange
ce7044c711 dbStatic: collect promptgroup enum choices when reading dbd 2016-04-06 15:38:35 +02:00
Andrew Johnson
177090e35e Merged fixes for lp:1558206 and lp:1563191 from 3.14 branch, revno 12622 2016-03-30 11:26:53 -05:00
Andrew Johnson
430da57a35 Release notes for lp:1563191 2016-03-30 11:00:48 -05:00
Andrew Johnson
d2d637d0c2 Prevent string overflow in recGblInitConstantLink() 2016-03-29 12:04:08 -05:00
Michael Davidsaver
106fae3b26 dbStatic: prevent overflow in dbPutString()
The bounds check should be before the string
copy.  Also zero the last element out of
paranoia (should already be zero).

Fix lp:1563191
2016-03-29 17:36:39 +09:00
Andrew Johnson
3179e65791 Clean-up after lp:1558206 fix 2016-03-16 18:15:14 -05:00
Michael Davidsaver
6b9bfb09a5 pWaitRelease in wrong place
waitRelease==false indicates that pThread
has not be delete'd
2016-03-16 17:43:52 -04:00
Michael Davidsaver
4e312b9f64 libCom: exitWait() from thread exit handler corrupts stack
The epicsThreadCallEntryPoint() function stores a pointer
to a local variable in epicsThread::pWaitReleaseFlag.
Calling epicsAtThreadExit::exitWait() from that thread's
epicsAtThreadExit() handler writes to this pointer
after epicsThreadCallEntryPoint() has returned.
Thus corrupting the stack.

Set pWaitReleaseFlag=NULL before return to prevent this.

fixes lp:1558206
2016-03-16 14:40:37 -04:00
Andrew Johnson
59fea64390 Add missing dependencies for Test.dbd files 2016-03-16 13:10:17 -05:00
Andrew Johnson
f260124733 Ensure mbb* MASK calculated properly 2016-03-10 13:05:00 -06:00
Andrew Johnson
bd2ada3f8c Reformat Release Notes slightly 2016-03-03 16:02:46 -06:00
Andrew Johnson
113076a009 Allow quotes in DBD argument strings 2016-03-03 11:19:22 -06:00
Andrew Johnson
9502841b55 Silence unused variable warning 2016-03-02 10:41:34 -06:00
Andrew Johnson
b4404c8266 Clean up Release Notes merge 2016-02-29 17:53:59 -06:00
Andrew Johnson
f73f3332fa Merge RTEMS NTP fix from 3.14 branch, to revno 12615 2016-02-29 17:49:08 -06:00
Andrew Johnson
3f4c6abb31 Fix for RTEMS NTP sync issue 2016-02-29 17:07:03 -06:00
Andrew Johnson
76c422c5fd Merge Cygwin fix from 3.14, fix in rsrv too 2016-02-26 17:10:35 -06:00
Andrew Johnson
fee62836cd Use OS __CYGWIN__ macro, deprecate our CYGWIN32 2016-02-26 16:27:13 -06:00
Michael Davidsaver
2c48bcc26b dbChannelShow reporting detail level changed 2016-02-26 16:07:47 -05:00
Andrew Johnson
a3ab342833 Fix Release Notes for last commit 2016-02-26 14:22:00 -06:00
Andrew Johnson
3304470323 Merged the rsrvbindiface branch 2016-02-26 14:15:22 -06:00
Andrew Johnson
4f2f910d09 Added extern "C" wrappers to clean up some Solaris warnings 2016-02-26 13:50:39 -06:00
Andrew Johnson
217f515985 Merged fix-dbGet-arrays branch 2016-02-26 12:29:20 -06:00
Andrew Johnson
ebc59a4223 Add epicsAtomicTest to epicsRunLibComTests 2016-02-26 12:27:33 -06:00
Andrew Johnson
58285501de Revert, test programs may be included in harness without being run 2016-02-26 12:25:59 -06:00
Andrew Johnson
fa07bc3efe Added build files for cygwin to cross-compile linux-arm targets
Slightly strange combination and not actually tested, but could
be useful for some developers -- some FPGA tool-sets come with a
Cygwin cross-build environment for their target devices.
2016-02-26 11:19:37 -06:00
Michael Davidsaver
bfa8e324f7 remove dbChArrTest from testHarness
dbChArrTest calls iocInit() and so can't
be in the shared test harness
2016-02-25 21:10:42 -05:00
Michael Davidsaver
51a69862e7 ioc/db: single return for dbGet()
Single return path after call to prset->get_array_info
to ensure that paddr->pfield is restored.
2016-02-25 20:59:10 -05:00
Michael Davidsaver
4b8c11aeef memset transposed arguments 2016-02-25 20:08:44 -05:00
Andrew Johnson
62efa2e96a Fix the dbGet() array with field-log bug.
This also fixes a problem where the array is used in circular buffer
mode and the request has an offset, but the array is not actually
full at the time; to copy the data out of the array the convert()
routine needs to know the capacity of the array to know when to wrap
around, but we were passing it the current length instead.
2016-02-25 17:50:33 -06:00
Andrew Johnson
c7bcb09540 Add tests for dbGet() with db_field_log
Regression testing for a bug where an array field with a sub-array
channel filter can read past the end of the db_field_log array,
because in dbGet() the call to prset->get_array_info() occurs even
when pfl is supposed to be overriding the record's array.
2016-02-25 17:44:45 -06:00
Andrew Johnson
5ee778b0c2 Merged changes from Base-3.14, to revno 12613 2016-02-25 14:13:40 -06:00
Michael Davidsaver
7b3a040b34 rsrv: use SOCKERRNO
Must use OSI SOCKERRNO for correct handling
of errors w/ winsock
2016-02-25 11:32:56 -05:00
Andrew Johnson
e721be4ff5 Merged the posix-mlockall branch 2016-02-25 10:20:56 -06:00
Michael Davidsaver
88b47c021c cygwin inherits winsock broadcast behavior 2016-02-25 11:10:28 -05:00
Michael Davidsaver
d0a316f7ca win32: include ws2tcpip.h from osdSock.h
Needed to get some additional definitions
including IP_ADD_MEMBERSHIP
2016-02-25 11:02:09 -05:00
Ralph Lange
ba307ba6e7 rsrv: populate the server list - also on Windows builds 2016-02-25 09:36:31 +01:00
Andrew Johnson
d943f6966f Minor updates to the extensions/configure template 2016-02-24 17:39:29 -06:00
Andrew Johnson
76d7ce1f76 Fix MSVC (de)-optimizer issue 2016-02-24 15:06:59 -06:00
Andrew Johnson
66b0acbe3e Report UDP client status on Windows 2016-02-24 11:07:33 -06:00
Ralph Lange
822c6815c5 pcas: fix compilation on MSC Windows 2016-02-24 11:24:17 +01:00
Andrew Johnson
684ae7b35c Merged the fix-calc-bit-manipulation branch 2016-02-23 16:21:38 -06:00
Andrew Johnson
e18eca80db Changes from patch in lp:1539791 2016-02-23 15:43:26 -06:00
Andrew Johnson
b45622ac5e Test each bitwise cast individually for overflow 2016-02-23 12:42:00 -06:00
Andrew Johnson
89e6fdbca0 Fixed conversion overflows in tests
Minor tidying-up, added comments about casting for bitwise operations.
2016-02-19 15:57:44 -06:00
Ralph Lange
599e6635fb libCom/calc: fix bit31 bit manipulations 2016-02-18 15:19:01 +01:00
Ralph Lange
4241b4e6cb libCom/test: add calc tests for bit31 operators (lp:1514520) 2016-02-18 15:17:52 +01:00
Ralph Lange
9eedf0581e libCom/calc: Use epics(U)Int32 for all integer calculations
Adapted backport of 3.15 revision 12308
2016-02-18 14:44:43 +01:00
Michael Davidsaver
ffb23a3480 pcas: don't send beacons w/ connect()d socket
use sendto() and leave the origin field to 0.0.0.0
so it will be filled in by the receiving repeater
2016-02-16 16:28:04 -05:00
Andrew Johnson
61e61aab24 Use MS' strto[u]ll() if present 2016-02-12 15:15:19 -06:00
Andrew Johnson
d3e046a466 Document [s:e] and [s] filter usage 2016-02-12 14:20:33 -06:00
Andrew Johnson
99d331e50a Print timestamp with bad UDP msg errors 2016-02-11 14:36:48 -06:00
Andrew Johnson
9d95528eba Show UDP name server status in casr 2+ output 2016-02-08 16:34:37 -06:00
Michael Davidsaver
95a1998e0b update release notes 2016-02-04 19:09:44 -05:00
Michael Davidsaver
5769db3862 rsrv: "casr 1" shows ignore list 2016-02-04 18:57:02 -05:00
Michael Davidsaver
00a74fbb4e libCom: fix debug print formats in osiSockDiscoverBroadcastAddresses() 2016-02-04 18:45:18 -05:00
Michael Davidsaver
03fde89dd4 rsrv: EPICS_CAS_IGNORE_ADDR_LIST 2016-02-04 18:44:33 -05:00
Michael Davidsaver
8421b46398 update release notes 2016-02-04 17:59:08 -05:00
Michael Davidsaver
650aaea203 ca: update CAref.html with changes to beacon address list
Note that server beacon address list will no longer
consider client address list as a fallback.
2016-02-04 17:56:31 -05:00
Michael Davidsaver
fcfe7ed312 pcas: no fallbacks for beacon address list
Don't mix client and server configuration
by defaulting the server beacon list to use
the client address list.
2016-02-04 17:39:28 -05:00
Andrew Johnson
f2c4b2c81e Add config for linux cross-compile to windows-x64-mingw 2016-02-04 15:57:23 -06:00
Michael Davidsaver
167dea3735 rsrv: decouple some client/server config
the automatic beacon address list should follow
the server interface address list, and not be
effected by any client config.

Also, don't populate the interface address list
from EPICS_CAS_BEACON_ADDR_LIST as this will
almost never contain local interface addresses.
2016-01-29 08:33:41 -05:00
Andrew Johnson
1c1eb030a9 Improve casr() output 2016-01-27 17:59:38 -06:00
Andrew Johnson
43cf5af621 dbQuietMacroWarnings control 2016-01-26 12:28:00 -06:00
Michael Davidsaver
235e4bd835 rsrv: more beacon address fixups
should really be based on *server* config
as beacons should be sent to clients attempting
to connect to the server.

By default send beacons to bcast addresses
from the interface address list.
2016-01-23 16:15:17 -05:00
Michael Davidsaver
601d6d9fe8 rsrv: oops
improper rebase
2016-01-23 13:53:44 -05:00
Michael Davidsaver
b961b25151 rsrv: fix wildcard check ordering
filter out mcast addresses before wildcard uniqueness check.
2016-01-23 13:53:44 -05:00
Michael Davidsaver
eb9246e4c9 rsrv: beaconCounter not updated 2016-01-21 17:14:23 -05:00
Andrew Johnson
d729006908 Fix build for vxWorks 5.5.2 (again) 2016-01-21 12:27:01 -06:00
Michael Davidsaver
0aeba281be update release notes 2016-01-21 13:05:56 -05:00
Michael Davidsaver
04fee51795 ipAddrToAsciiAsync.: don't try to join the daemon thread
This isn't really necessary and may unnecessarily delay
things (~10 sec. on Linux) if a query to an unreachable
DNS server is in progress.
2016-01-21 13:00:50 -05:00
Michael Davidsaver
cba449d53b pcas: listen for mcast search request 2016-01-21 12:17:02 -05:00
Michael Davidsaver
cdffcbfbae update release notes 2016-01-21 12:17:02 -05:00
Michael Davidsaver
ba5ea5da93 don't use EPICS_CA_ADDR_LIST for server interface list
keep existing behavior, and server binds wildcard
when only client address list is specified.
2016-01-21 12:17:02 -05:00
Michael Davidsaver
c884175a86 rsrv: loopback mcast beacons 2016-01-21 12:17:02 -05:00
Michael Davidsaver
a4e9dcff00 rsrv: fixup beacon address list handling
should be based on client interface list,
not server.
2016-01-21 12:17:02 -05:00
Michael Davidsaver
c9323da5e3 minor
fix typo
expand error message
skip redundant (and misleading) print of beacon address list
2016-01-21 12:17:02 -05:00
Andrew Johnson
ffe441d032 Fix build for vxWorks 5.5.2 2016-01-21 10:34:32 -06:00
Ralph Lange
45c8a173f3 libCom/osi: fix timespec definition for MinGW 2016-01-13 17:28:23 +01:00
Michael Davidsaver
98504d1cdc libca: enable mcast loopback 2016-01-11 20:59:08 -05:00
Michael Davidsaver
568ece9c27 rsrv: multicast name lookup 2016-01-11 20:59:08 -05:00
Michael Davidsaver
f876bdb42c rsrv: don't leak sockets when building tcp set 2016-01-11 20:59:08 -05:00
Michael Davidsaver
605074a580 rsrv: additional fallback for interface list 2016-01-11 20:59:08 -05:00
Michael Davidsaver
64da181e6f expand beacon address list when binding to wildcard 2016-01-11 20:59:08 -05:00
Michael Davidsaver
823613fb4f libca: addAddrToChannelAccessAddressList report success 2016-01-11 20:59:08 -05:00
Michael Davidsaver
f837add8c4 envDefs: add envGetBoolConfigParam 2016-01-11 20:59:08 -05:00
Michael Davidsaver
15307c4db6 rsrv: redo initialization to support bind multiple interfaces.
consolidate most setup tasks in rsrv_init(),
which now spawns threads directly.
For each interface create 3-4 sockets,

* TCP listener
* UDP receiver (unicast)
* UDP receiver (broadcast optional)
* UDP beacon sender
2016-01-11 20:59:07 -05:00
Michael Davidsaver
8d5815ac95 rsrv: move some from req_server to rsrv_init 2016-01-11 20:59:07 -05:00
Michael Davidsaver
25d7d46e08 rsrv: no lazy init of BUCKET 2016-01-11 20:59:07 -05:00
Michael Davidsaver
5f31d9d2b1 rsrv: unglobalize IOC_sock 2016-01-11 20:59:07 -05:00
Michael Davidsaver
bb67c9db2f rsrv: UDP listener on more than one iface 2016-01-11 20:59:07 -05:00
Michael Davidsaver
cb965611ce rsrv: casr show multiple UDP clients 2016-01-11 20:59:07 -05:00
Michael Davidsaver
e805abe971 libCom/osi: osiSockDiscoverBroadcastAddresses() finds 127.255.255.255
For the default implementation of osiSockDiscoverBroadcastAddresses()
allow the loopback interface to have IFF_BROADCAST set (usually isn't)
and on Linux assume that the loopback broadcast address is usable
even if IFF_BROADCAST isn't set.
2016-01-11 20:59:07 -05:00
Michael Davidsaver
c80f71e294 rsrv: more renaming 2016-01-11 20:59:07 -05:00
Michael Davidsaver
692bbafffe rsrv: placeholder for cast_server thread shutdown 2016-01-11 20:59:07 -05:00
Michael Davidsaver
fd863738be rename prsrv_cast_client in cast_server() 2016-01-11 20:59:07 -05:00
Michael Davidsaver
2052062324 remove global prsrv_cast_client 2016-01-11 20:59:07 -05:00
Michael Davidsaver
5d74216017 rsrv: unnecessary use of global 2016-01-11 20:59:07 -05:00
Michael Davidsaver
991ff308e0 rsrv: when binding to a specific interface also bind to iface bcast
An oddness of BSD sockets (not winsock) is that binding to
INADDR_ANY will receive unicast and broadcast, but binding to
a specific interface address receives only unicast.  The trick
is to bind a second socket to the interface broadcast address,
which will then receive only broadcasts.
2016-01-11 20:59:07 -05:00
Michael Davidsaver
77a5f0db77 epicsMMIODef.h use static inline
'static inline' is necessary for consistent behavior with C and C++.
Plain 'inline' in C can result in multiply defined symbol
errors when linking.
2016-01-05 21:31:51 -05:00
Bjorklund, Eric A
8d6469957e vxWorks: missing extern "C" around sysPci* prototypes 2016-01-05 21:16:04 -05:00
Andrew Johnson
ef90d2d3c7 Merged Michael's tzwin32 branch 2016-01-05 17:17:58 -06:00
Michael Davidsaver
2d9c529f5e osdTime: win32 use C89 localtime/gmtime
as recommended by Freddie Akeroyd
2015-12-21 11:15:04 -05:00
Michael Davidsaver
05d3dbf453 add epicsTimeZoneTest 2015-12-21 11:13:36 -05:00
Andrew Johnson
695f516cbf Fix softIoc build with space in path to Base
Also improved error messages from makeInstallDir.pl.
2015-12-10 13:26:21 -06:00
Ralph Lange
fda3824ab4 Set version back to -DEV, add "not released" to RELEASE_NOTES 2015-11-22 18:10:40 +01:00
175 changed files with 4134 additions and 2379 deletions

View File

@@ -29,7 +29,7 @@ EPICS_VERSION = 3
EPICS_REVISION = 15
# EPICS_MODIFICATION must be a number >=0 and <256
EPICS_MODIFICATION = 3
EPICS_MODIFICATION = 4
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included if zero

View File

@@ -118,6 +118,13 @@ CROSS_COMPILER_TARGET_ARCHS=
# configure/os/CONFIG_SITE.<host>.Common files instead.
CROSS_COMPILER_HOST_ARCHS=
# The 'make runtests' and 'make tapfiles' build targets normally only run
# self-tests for the EPICS_HOST_ARCH architecture. If the host can execute
# the self-test programs for any other cross-built architectures such as
# a -debug architecture, those architectures can be named here.
#
CROSS_COMPILER_RUNTEST_ARCHS=
# Build shared libraries (DLLs on Windows).
# Must be either YES or NO. Definitions in the target-specific
# os/CONFIG.Common.<target> and os/CONFIG_SITE.Common.<target> files may

View File

@@ -30,10 +30,8 @@
# local timezone info for vxWorks and RTEMS IOCs. The format is
# <name>::<minutesWest>:<start daylight>:<end daylight>
# where the start and end are mmddhh - that is month,day,hour
# e.g. for ANL in 2015: EPICS_TIMEZONE=CST/CDT::360:030802:110102
# e.g. for ANL in 2016: EPICS_TIMEZONE=CST/CDT::360:031302:110602
#
# DST for 2015 US: Mar 08 - Nov 01
# EU: Mar 29 - Oct 25
# DST for 2016 US: Mar 13 - Nov 06
# EU: Mar 27 - Oct 30
# DST for 2017 US: Mar 12 - Nov 05
@@ -42,11 +40,15 @@
# EU: Mar 25 - Oct 28
# DST for 2019 US: Mar 10 - Nov 03
# EU: Mar 31 - Oct 27
# (see: http://www.timeanddate.com/time/map/)
# DST for 2020 US: Mar 08 - Nov 01
# EU: Mar 29 - Oct 25
# DST for 2021 US: Mar 14 - Nov 07
# EU: Mar 28 - Oct 31
# (see: http://www.timeanddate.com/time/dst/2016.html etc. )
#
# These values are for 2015:
EPICS_TIMEZONE=CST/CDT::360:030802:110102
#EPICS_TIMEZONE=CET/CEST::-60:032902:102502
# These values are for 2016:
EPICS_TIMEZONE=CST/CDT::360:031302:110602
#EPICS_TIMEZONE=CET/CEST::-60:032702:103002
# EPICS_TS_NTP_INET
# NTP time server ip address. Uses boot host if not set.

View File

@@ -24,11 +24,15 @@ else
clean$(DIVIDER)$(ARCH) clean:
endif
cdCommands envPaths dllPath.bat relPaths.sh: \
cdCommands dllPath.bat relPaths.sh: \
$(wildcard $(TOP)/configure/RELEASE*) \
$(wildcard $(TOP)/configure/CONFIG_SITE*) $(INSTALL_BIN)
$(wildcard $(TOP)/configure/CONFIG_SITE*) | $(INSTALL_BIN)
$(CONVERTRELEASE) -a $(ARCH) -t $(IOCS_APPL_TOP) $@
envPaths: $(wildcard $(TOP)/configure/RELEASE*) \
$(wildcard $(TOP)/configure/CONFIG_SITE*) | $(INSTALL_BIN)
$(CONVERTRELEASE) -t $(IOCS_APPL_TOP) $@
realclean:
$(RM) cdCommands envPaths dllPath.bat relPaths.sh

View File

@@ -170,7 +170,13 @@ endif
$(DIRECTORY_TARGETS) :
$(MKDIR) -p $@
$(PRODNAME): $(INSTALL_LIB_INSTALLS)
# Install LIB_INSTALLS libraries before linking executables
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS)
# Install built libraries too, unless Makefile says to wait
ifneq ($(DELAY_INSTALL_LIBS),YES)
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIBS) $(INSTALL_DLLSTUB_LIBS)
endif
# RELEASE file consistency checking
checkRelease:
@@ -319,7 +325,9 @@ $(MODNAME): %$(MODEXT): %$(EXE)
# Automated testing
runtests: $(TESTSCRIPTS)
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
endif
testspec: $(TESTSCRIPTS)
@$(RM) $@
@@ -333,7 +341,9 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
# A .tap file is the output from running the associated test script
%.tap: %.t
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
-$(PERL) $< -tap > $@
endif
# If there's a perl test script (.plt) available, use it
%.t: ../%.plt

View File

@@ -57,7 +57,7 @@ SHRLIB_LDLIBS = $(addprefix -l, $($*_LDLIBS) $(LIB_LIBS) $(USR_LIBS)) \
$(LDLIBS)
SHRLIB_DEPLIB_DIRS = $(foreach word, \
$(sort $(dir $($*_DEPLIBS) $(SHRLIB_DEPLIBS))), \
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(SHRLIB_DEPLIBS))), \
$(shell $(FULLPATHNAME) $(word)))
SHRLIBDIR_LDFLAGS += $(SHRLIB_DEPLIB_DIRS:%=-L%)
@@ -86,7 +86,7 @@ PROD_LDLIBS += $($(firstword $(LDLIBS_STATIC_$(STATIC_BUILD)) \
$(LDLIBS_SHARED_$(SHARED_LIBRARIES))))
PROD_DEPLIB_DIRS = $(foreach word, \
$(sort $(dir $($*_DEPLIBS) $(PROD_DEPLIBS))), \
$(sort $(INSTALL_LIB)/ $(dir $($*_DEPLIBS) $(PROD_DEPLIBS))), \
$(shell $(FULLPATHNAME) $(word)))
PRODDIR_LDFLAGS += $(PROD_DEPLIB_DIRS:%=-L%)

View File

@@ -26,14 +26,14 @@ POSIX_LDLIBS += -lpthread
ARCH_DEP_CFLAGS += -m32
ARCH_DEP_LDFLAGS += -m32
# Compiler defines _X86_ 1
# Compiler defines __MSVCRT__ 1
# 32-bit compiler defines _X86_ 1
# Compiler defines __CYGWIN__ 1
# Compiler defines __CYGWIN32__ 1
# 32-bit compiler defines __CYGWIN32__ 1
# Compiler defines __unix__ 1
# Compiler defines __unix 1
# Compiler defines unix 1
# This macro now deprecated, use __CYGWIN__ in the future
OP_SYS_CPPFLAGS += -DCYGWIN32
EXE = .exe

View File

@@ -0,0 +1,33 @@
# CONFIG.cygwin-x86.linux-arm
#
# Definitions for cywgin-x86 host - linux-arm target builds
# Override these settings in CONFIG_SITE.cygwin-x86.linux-arm
#-------------------------------------------------------
VALID_BUILDS = Ioc
GNU_TARGET = arm-linux
# prefix of compiler tools
CMPLR_SUFFIX =
CMPLR_PREFIX = $(addsuffix -,$(GNU_TARGET))
# Provide a link-time path for shared libraries
SHRLIBDIR_RPATH_LDFLAGS_YES += $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath-link,%)
SHRLIBDIR_LDFLAGS += $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
# Provide a link-time path for products
PRODDIR_RPATH_LDFLAGS_YES += $(PROD_DEPLIB_DIRS:%=-Wl,-rpath-link,%)
PRODDIR_LDFLAGS += $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
# Provide a link-time path for readline
RUNTIME_LDFLAGS_READLINE_YES = -Wl,-rpath-link,$(GNU_DIR)/lib
RUNTIME_LDFLAGS_READLINE = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
RUNTIME_LDFLAGS_READLINE_CURSES = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
RUNTIME_LDFLAGS_READLINE_NCURSES = $(RUNTIME_LDFLAGS_READLINE_$(LINKER_USE_RPATH))
# Library flags
STATIC_LDFLAGS_YES= -Wl,-Bstatic
STATIC_LDFLAGS_NO=
STATIC_LDLIBS_YES= -Wl,-Bdynamic
STATIC_LDLIBS_NO=

View File

@@ -0,0 +1,7 @@
# CONFIG.cygwin-x86_64.linux-arm
#
# Definitions for cygwin-x86_64 host - linux-arkm targets
# Override these settings in CONFIG_SITE.cygwin-x86_64.linux-arm
#-------------------------------------------------------
include $(CONFIG)/os/CONFIG.cygwin-x86.linux-arm

View File

@@ -0,0 +1,28 @@
# CONFIG.linux-x86.windows-x64-mingw
#
# Definitions for linux-x86 host windows-x64-mingw target builds
# Override these definitions in CONFIG_SITE.linux-x86.windows-x64-mingw
#-------------------------------------------------------
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon
# Add resource compiler
RCCMD = $(GNU_BIN)/$(CMPLR_PREFIX)windres$(CMPLR_SUFFIX) $(INCLUDES) $< $@
# Remove -fPIC flags, add out-implib
SHRLIB_CFLAGS =
SHRLIB_LDFLAGS = -shared \
-Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX)
LOADABLE_SHRLIB_LDFLAGS = -shared \
-Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX)
# No need to explicitly link with gcc library
GNU_LDLIBS_YES =
# Link with winsock2
OP_SYS_LDLIBS = -lws2_32
# Use static compiler-support libraries
OP_SYS_LDFLAGS += -static-libgcc -static-libstdc++
# There is no compiler flag for static libwinpthread

View File

@@ -0,0 +1,9 @@
# CONFIG.linux-x86_64.windows-x64-mingw
#
# Definitions for linux-x86_64 host windows-x64-mingw target builds
# Override these definitions in CONFIG_SITE.linux-x86_64.windows-x64-mingw
#-------------------------------------------------------
# Settings as for the linux-x86 host architecture
include $(CONFIG)/os/CONFIG.linux-x86.windows-x64-mingw

View File

@@ -1,22 +1,22 @@
# CONFIG_SITE.Common.cygwin-x86_64
#
# $Revision-Id$
#
# Site Specific definitions for cygwin-x86_64 target
# Only the local epics system manager should modify this file
# If readline is installed uncomment the following line
# to add command-line editing and history support
#COMMANDLINE_LIBRARY = READLINE
# Uncomment the following line if readline has problems
#LDLIBS_READLINE = -lreadline -lcurses
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
# CONFIG_SITE.Common.cygwin-x86_64
#
# $Revision-Id$
#
# Site Specific definitions for cygwin-x86_64 target
# Only the local epics system manager should modify this file
# If readline is installed uncomment the following line
# to add command-line editing and history support
#COMMANDLINE_LIBRARY = READLINE
# Uncomment the following line if readline has problems
#LDLIBS_READLINE = -lreadline -lcurses
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@@ -6,5 +6,5 @@
# Site override definitions for cygwin-x86 host builds
#-------------------------------------------------------
#CROSS_COMPILER_TARGET_ARCHS =
#CROSS_COMPILER_TARGET_ARCHS = linux-arm

View File

@@ -0,0 +1,16 @@
# CONFIG_SITE.cygwin-x86.linux-arm
#
# $Revision-Id$
#
# Site specific definitions for cygwin-x86 host - linux-arm target builds
#-------------------------------------------------------
# Tools install path
GNU_DIR = /usr/local/arm-linux
# GNU crosscompiler target name
GNU_TARGET = arm-linux
STATIC_BUILD = YES
SHARED_LIBRARIES = NO

View File

@@ -0,0 +1,16 @@
# CONFIG_SITE.cygwin-x86_64.linux-arm
#
# $Revision-Id$
#
# Site specific definitions for cygwin-x86_64 host - linux-arm target builds
#-------------------------------------------------------
# Tools install path
GNU_DIR = /usr/local/arm-linux
# GNU crosscompiler target name
GNU_TARGET = arm-linux
STATIC_BUILD = YES
SHARED_LIBRARIES = NO

View File

@@ -0,0 +1,20 @@
# CONFIG_SITE.linux-x86.windows-x64-mingw
#
# Configuration for linux-x86 host windows-x64-mingw target builds
#-------------------------------------------------------
# Early versions of the MinGW cross-build tools can only build
# static (non-DLL) libraries. For example RHEL's cross-gcc 4.4.6
# needs these uncommented, cross-gcc 4.6.3 for Ubuntu does not:
#SHARED_LIBRARIES = NO
#STATIC_BUILD = YES
# The cross-build tools are in $(GNU_DIR)/bin
# Default is /usr
#GNU_DIR = /usr/local
# Different distribution cross-build packages use different prefixes:
# Ubuntu:
#CMPLR_PREFIX = i686-w64-mingw32-
# RHEL:
CMPLR_PREFIX = x86_64-w64-mingw32-

View File

@@ -0,0 +1,8 @@
# CONFIG_SITE.linux-x86_64.windows-x64-mingw
#
# Configuration for linux-x86_64 host windows-x64-mingw target builds
#-------------------------------------------------------
# Inherit from the linux-x86 host architecture
include $(CONFIG)/os/CONFIG_SITE.linux-x86.windows-x64-mingw

View File

@@ -3,14 +3,229 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>EPICS Base R3.15.3 Release Notes</title>
<title>EPICS Base R3.15.4 Release Notes</title>
</head>
<body lang="en">
<h1 align="center">EPICS Base Release 3.15.3</h1>
<h1 align="center">EPICS Base Release 3.15.4</h1>
<h2 align="center">Changes made on the 3.15 branch since 3.15.3</h2>
<!-- Insert new items immediately below here ... -->
<h3>New string input device support "getenv"</h3>
<p>A new "getenv" device support for both the stringin and lsi (long string
input) record types can be used to read the value of an environment variable
from the IOC at runtime. See base/db/softIocExit.db for sample usage.</p>
<h3>Build rules and DELAY_INSTALL_LIBS</h3>
<p>A new order-only prerequisite build rule has been added to ensure that
library files (and DLL stubs on Windows) get installed before linking any
executables, which resolves parallel build problems on high-powered CPUs. There
are some (rare) cases though where a Makefile has to build an executable and run
it to be able to compile code for a library built by the same Makefile. With
this new build rule GNUmake will complain about a circular dependency and the
build will probably fail in those cases. To avoid this problem the failing
Makefile should set <tt>DELAY_INSTALL_LIBS = YES</tt> before including the
<tt>$(TOP)/configure/RULES</tt> file, disabling the new build rule.</p>
<h3>IOC environment variables and build parameters</h3>
<p>The IOC now sets a number of environment variables at startup that provide
the version of EPICS Base it was built against (EPICS_VERSION_...) and its build
architecture (ARCH). In some cases this allows a single iocBoot/ioc directory to
be used to run the same IOC on several different architectures without any
changes.</p>
<p>There are also 3 new environment parameters (EPICS_BUILD_...) available that
C/C++ code can use to find out the target architecture, OS class and compiler
class it was built with. These may be useful when writing interfaces to other
languages.</p>
<h3>New implementation of promptgroup/gui_group field property</h3>
<p>The mechanism behind the "promptgroup()" field property inside a record type
definition has been changed. Instead of using a fixed set of choices,
the static database access library now collects the used gui group names
while parsing DBD information. Group names should start with a two-digit number
plus space-dash-space to allow proper sorting of groups.</p>
<p>The include file <tt>guigroup.h</tt> that defined the fixed set of choices
has been deprecated. Instead, use the conversion functions between index number
and group string that have been added to dbStaticLib.</p>
<p>When a DBD file containing record-type descriptions is expanded, any
old-style <tt>GUI_xxx</tt> group names will be replaced by a new-style
string for use by the IOC. This permits an older record type to be used with
the 3.15.4 release, although eventually record types should be converted by
hand with better group names used.</p>
<h3>CA server configuration changes</h3>
<p>RSRV now honors EPICS_CAS_INTF_ADDR_LIST and binds only to the provided list
of network interfaces. Name searches (UDP and TCP) on other network interfaces
are ignored. For example on a computer with interfaces 10.5.1.1/24, 10.5.2.1/24,
and 10.5.3.1/24, setting "EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'" will
accept traffic on the .1.1 and .2.1, but ignore from .3.1</p>
<p>RSRV now honors EPICS_CAS_IGNORE_ADDR_LIST and ignores UDP messages received
from addresses in this list.</p>
<p>Previously, CA servers (RSRV and PCAS) would build the beacon address list
using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set. This is no
longer done. Sites depending on this should set both envronment variables to the
same value.</p>
<h3>IPv4 multicast for name search and beacons</h3>
<p>libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name
search and beacons). This is disabled by default. To enable multicast address(s)
must be listed in EPICS_CA_ADDR_LIST for clients and EPICS_CAS_INTF_ADDR_LIST
for servers (IOCs should set both). For example:
"EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9".</p>
<p>Please note that no IPv4 multicast address is officially assigned for Channel
Access by IANA. The example 224.0.2.9 is taken from the AD-HOC Block I range.<p>
<h3>Moved <tt>mlockall()</tt> into its own epicsThread routine</h3>
<p>Since EPICS Base 3.15.0.2 on Posix OSs the initialization of the epicsThread
subsystem has called <tt>mlockall()</tt> when the OS supports it and thread
priority scheduling is enabled. Doing so has caused problems in third-party
applications that call the CA client library, so the functionality has been
moved to a separate routine <tt>epicsThreadRealtimeLock()</tt> which will be
called by the IOC at iocInit (unless disabled by setting the global variable
<tt>dbThreadRealtimeLock</tt> to zero).</p>
<h3>Added dbQuietMacroWarnings control</h3>
<p>When loading database files, macros get expanded even on comment lines. If a
comment contains an undefined macro, the load still continues but an error
message gets printed. For this release the error message has been changed to a
warning, but even this warning can be made less verbose by setting this new
variable to a non-zero value before loading the file, like this:</p>
<blockquote><pre>
var dbQuietMacroWarnings 1 <i>iocsh</i>
dbQuietMacroWarnings=1 <i>VxWorks</i>
</pre></blockquote>
<p>This was <a href="https://bugs.launchpad.net/bugs/541119">Launchpad bug
541119</a>.</p>
<h2 align="center">Changes pulled from the 3.14 branch since 3.15.3</h2>
<!-- Insert inherited items immediately below here ... -->
<h3>Making IOC ca_get operations atomic</h3>
<p>When a CA client gets data from an IOC record using a compound data type such
as <tt>DBR_TIME_DOUBLE</tt> the value field is fetched from the database in a
separate call than the other metadata, without keeping the record locked. This
allows some other thread such as a periodic scan thread a chance to interrupt
the get operation and process the record in between. CA monitors have always
been atomic as long as the value data isn't a string or an array, but this race
condition in the CA get path has now been fixed so the record will stay locked
between the two fetch operations.</p>
<p>This fixes <a href="https://bugs.launchpad.net/epics-base/+bug/1581212">
Launchpad bug #1581212</a>, thanks to Till Strauman and Dehong Zhang.</p>
<h3>New CONFIG_SITE variable for running self-tests</h3>
<p>The 'make runtests' and 'make tapfiles' build targets normally only run the
self-tests for the main <tt>EPICS_HOST_ARCH</tt> architecture. If the host is
able to execute self-test programs for other target architectures that are being
built by the host, such as when building a <tt>-debug</tt> version of the host
architecture for example, the names of those other architectures can be added to
the new <tt>CROSS_COMPILER_RUNTEST_ARCHS</tt> variable in either the
<tt>configure/CONFIG_SITE</tt> file or in an appropriate
<tt>configure/os/CONFIG_SITE.&lt;host&gt;.Common</tt> file to have the test
programs for those targets be run as well.</p>
<h3>Additional RELEASE file checks</h3>
<p>An additional check has been added at build-time for the contents of the
configure/RELEASE file(s), which will mostly only affect users of the Debian
EPICS packages published by NSLS-2. Support modules may share an install path,
but all such modules must be listed adjacent to each other in any RELEASE files
that point to them. For example the following will fail the new checks:</p>
<blockquote><pre>
AUTOSAVE = /usr/lib/epics
ASYN = /home/mdavidsaver/asyn
EPICS_BASE = /usr/lib/epics
</pre></blockquote>
<p>giving the compile-time error</p>
<blockquote><pre>
This application's RELEASE file(s) define
EPICS_BASE = /usr/lib/epics
after but not adjacent to
AUTOSAVE = /usr/lib/epics
Module definitions that share paths must be grouped together.
Either remove a definition, or move it to a line immediately
above or below the other(s).
Any non-module definitions belong in configure/CONFIG_SITE.
</pre></blockquote>
<p>In many cases such as the one above the order of the <tt>AUTOSAVE</tt> and
<tt>ASYN</tt> lines can be swapped to let the checks pass, but if the
<tt>AUTOSAVE</tt> module depended on <tt>ASYN</tt> and hence had to appear
before it in the list this error indicates that <tt>AUTOSAVE</tt> should also be
built in its own private area; a shared copy would likely be incompatible with
the version of <tt>ASYN</tt> built in the home directory.</p>
<h3>String field buffer overflows</h3>
<p>Two buffer overflow bugs that can crash the IOC have been fixed, caused by
initializing a string field with a value larger than the field size
(<a href="https://bugs.launchpad.net/bugs/1563191">Launchpad bug
#1563191</a>).</p>
<h3>Fixed stack corruption bug in epicsThread C++ API</h3>
<p>The C++ interface to the epicsThread API could corrupt the stack on thread
exit in some rare circumstances, usually at program exit. This bug has been
fixed (<a href="https://bugs.launchpad.net/bugs/1558206">Launchpad bug
#1558206</a>).</p>
<h3>RTEMS NTP Support Issue</h3>
<p>On RTEMS the NTP Time Provider could in some circumstances get out of sync
with the server because the osdNTPGet() code wasn't clearing its input socket
before sending out a new request. This
(<a href="https://bugs.launchpad.net/bugs/1549908">Launchpad bug 1549908</a>)
has now been fixed.</p>
<h3>CALC engine bitwise operator fixes</h3>
<p>The bitwise operators in the CALC engine have been modified to work properly
with values that have bit 31 (0x80000000) set. This modification involved
back-porting some earlier changes from the 3.15 branch, and fixes
<a href="https://code.launchpad.net/bugs/1514520">Launchpad bug
#1514520</a>.</p>
<h3>Fix <tt>ipAddrToAsciiAsync()</tt>: Don't try to join the daemon thread</h3>
<p>On process exit, don't try to stop the worker thread that makes DNS lookups
asynchronous. Previously this would wait for any lookups still in progress,
delaying the exit unnecessarily. This was most obvious with catools (eg.
cainfo).
<a href="https://bugs.launchpad.net/bugs/1527636">lp:1527636</a></p>
<h3>Fix <tt>epicsTime_localtime()</tt> on Windows</h3>
<p>Simpler versions of the epicsTime_gmtime() and epicsTime_localtime()
routines have been included in the Windows implementations, and a new test
program added. The original versions do not report DST status properly. Fixes
<a href="https://bugs.launchpad.net/bugs/1528284">Launchpad bug 1528284</a>.</p>
<h2 align="center">Changes between 3.15.2 and 3.15.3</h2>
<!-- Insert new items immediately below here ... -->
<h3>Make the NTP Time provider optional on VxWorks</h3>
@@ -50,6 +265,7 @@ time, but there was still one implementation left in the event record support
code, and a structure definition for one of the original arguments to that
routine was defined in recGbl.h. Both of these have now been removed.</p>
<h2 align="center">Changes between 3.15.1 and 3.15.2</h2>
<h3>Raised limit on link field length in database files</h3>
@@ -168,6 +384,7 @@ use a modified version of msi must provide support for both the <tt>-D</tt> and
<tt>-o&nbsp;outfile</tt> options, and should then point the MSI3_15 variable in
their applications' CONFIG_SITE files to that updated executable.</p>
<h2 align="center">Changes between 3.15.0.2 and 3.15.1</h2>
<h3>epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()</h3>

View File

@@ -841,23 +841,18 @@ seconds. See also <a href="#Disconnect">EPICS_CA_CONN_TMO</a> and
Interval</a>.</p>
<p>CA servers build a list of addresses to send beacons to during
initialization. If EPICS_CAS_AUTO_BEACON_ADDR_LIST has the value "YES" then the
beacon address list will be automatically configured to contain the broadcast
addresses of all LAN interfaces found in the host and the destination address
of all point-to-point interfaces found in the host. However, if the user also
initialization. If EPICS_CAS_AUTO_BEACON_ADDR_LIST has the value "YES"
(the default) this list will be automatically populated with the broadcast
addresses of all network interfaces. However, if the user also
defines EPICS_CAS_INTF_ADDR_LIST then beacon address list automatic
configuration is constrained to the network interfaces specified therein, and
therefore only the broadcast addresses of the specified LAN interfaces, and the
destination addresses of all specified point-to-point links, will be
therefore only the broadcast addresses of the specified LAN interfaces, will be
automatically configured.</p>
<p>If EPICS_CAS_BEACON_ADDR_LIST is defined then its contents will be used to
augment any automatic configuration of the beacon address list. Individual
entries in EPICS_CAS_BEACON_ADDR_LIST may override the destination port number
if ":nnn" follows the host name or IP address there. Alternatively, when both
EPICS_CAS_BEACON_ADDR_LIST and EPICS_CAS_INTF_ADDR_LIST are not defined then
the contents of EPICS_CA_ADDR_LIST is used to augment the list. Otherwise, the
list is not augmented.</p>
if ":nnn" follows the host name or IP address there.</p>
<p>The EPICS_CAS_BEACON_PORT parameter specifies the destination port for
server beacons. The only exception to this occurs when ports are specified in
@@ -868,20 +863,18 @@ specified in EPICS_CA_REPEATER_PORT.</p>
<h4>Binding a Server to a Limited Set of Network Interfaces</h4>
<p>The parameter EPICS_CAS_INTF_ADDR_LIST allows a ca server to bind itself to,
and therefore accept messages only over, a limited set of the local host's
and therefore accept messages received by, a limited set of the local host's
network interfaces (each specified by its IP address). On UNIX systems type
"netstat -i" (type "ipconfig" on windows) to see a list of the local host's
network interfaces. Specifically, UDP search messages addressed to both the IP
addresses in EPICS_CAS_INTF_ADDR_LIST and also to the broadcast addresses of
the corresponding LAN interfaces will be accepted by the server. By default,
"netstat -ie" (type "ipconfig" on windows) to see a list of the local host's
network interfaces. By default,
the CA server is accessible from all network interfaces configured into its
host.</p>
<p>In R3.14 and previous releases the CA server employed by iocCore did not
implement the EPICS_CAS_INTF_ADDR_LIST feature. In this release the iocCore
server will read the first IP address from the parameter variable and use that
to select which interface to bind to. Any additional IP addresses will be
ignored and a warning message displayed during IOC initialization.</p>
<p>Until R3.15.4 the CA server employed by iocCore did not
implement the EPICS_CAS_INTF_ADDR_LIST feature.</p>
<p>Prior to R3.15.4 CA servers would build the beacon address list
using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set.</p>
<h4>Ignoring Process Variable Name Resolution Requests From Certain Hosts</h4>

View File

@@ -22,7 +22,7 @@ extern "C" {
epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
( struct ELLLIST *pList, SOCKET sock, unsigned short port );
epicsShareFunc void epicsShareAPI addAddrToChannelAccessAddressList
epicsShareFunc int epicsShareAPI addAddrToChannelAccessAddressList
( struct ELLLIST *pList, const ENV_PARAM *pEnv,
unsigned short port, int ignoreNonDefaultPort );

View File

@@ -333,6 +333,12 @@ cac::~cac ()
this->ipToAEngine.release ();
// clean-up the list of un-notified msg objects
while ( msgForMultiplyDefinedPV * msg = this->msgMultiPVList.get() ) {
msg->~msgForMultiplyDefinedPV ();
this->mdpvFreeList.release ( msg );
}
errlogFlush ();
osiSockRelease ();
@@ -606,6 +612,8 @@ void cac::transferChanToVirtCircuit (
msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList )
msgForMultiplyDefinedPV ( this->ipToAEngine,
*this, pChan->pName ( guard ), acc );
// cac keeps a list of these objects for proper clean-up in ~cac
this->msgMultiPVList.add ( *pMsg );
// It is possible for the ioInitiate call below to
// call the callback directly if queue quota is exceeded.
// This callback takes the callback lock and therefore we
@@ -1297,6 +1305,8 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
epicsGuard < epicsMutex > guard ( this->mutex );
this->exception ( mgr.cbGuard, guard, ECA_DBLCHNL, buf, __FILE__, __LINE__ );
}
// remove from the list and delete msg object
this->msgMultiPVList.remove ( mfmdpv );
mfmdpv.~msgForMultiplyDefinedPV ();
this->mdpvFreeList.release ( & mfmdpv );
}

View File

@@ -237,6 +237,7 @@ private:
resTable < tcpiiu, caServerID > serverTable;
tsDLList < tcpiiu > circuitList;
tsDLList < SearchDest > searchDestList;
tsDLList < msgForMultiplyDefinedPV > msgMultiPVList;
tsFreeList
< class tcpiiu, 32, epicsMutexNOOP >
freeListVirtualCircuit;

View File

@@ -73,7 +73,7 @@ static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
/*
* addAddrToChannelAccessAddressList ()
*/
extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
extern "C" int epicsShareAPI addAddrToChannelAccessAddressList
( ELLLIST *pList, const ENV_PARAM *pEnv,
unsigned short port, int ignoreNonDefaultPort )
{
@@ -82,11 +82,11 @@ extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
const char *pToken;
struct sockaddr_in addr;
char buf[32u]; /* large enough to hold an IP address */
int status;
int status, ret = -1;
pStr = envGetConfigParamPtr (pEnv);
if (!pStr) {
return;
return ret;
}
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
@@ -104,7 +104,7 @@ extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
if (pNewNode==NULL) {
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
return;
break;
}
pNewNode->addr.ia = addr;
@@ -113,9 +113,10 @@ extern "C" void epicsShareAPI addAddrToChannelAccessAddressList
* LOCK applied externally
*/
ellAdd (pList, &pNewNode->node);
ret = 0; /* success if anything is added to the list */
}
return;
return ret;
}
/*

View File

@@ -55,8 +55,10 @@ msgForMultiplyDefinedPV::~msgForMultiplyDefinedPV ()
void msgForMultiplyDefinedPV::transactionComplete ( const char * pHostNameRej )
{
// calls into cac for the notification
// the msg object (= this) is being deleted as part of the notification
this->cb.pvMultiplyDefinedNotify ( *this, this->channel, this->acc, pHostNameRej );
// !! dont touch this pointer after this point because object has been deleted !!
// !! dont touch 'this' pointer after this point because object has been deleted !!
}
void * msgForMultiplyDefinedPV::operator new ( size_t size,

View File

@@ -33,6 +33,7 @@
#include "ipAddrToAsciiAsynchronous.h"
#include "tsFreeList.h"
#include "tsDLList.h"
#include "compilerDependencies.h"
#ifdef msgForMultiplyDefinedPVh_epicsExportSharedSymbols
@@ -47,7 +48,9 @@ public:
const char * pAcc, const char * pRej ) = 0;
};
class msgForMultiplyDefinedPV : public ipAddrToAsciiCallBack {
class msgForMultiplyDefinedPV :
public ipAddrToAsciiCallBack,
public tsDLNode < msgForMultiplyDefinedPV > {
public:
msgForMultiplyDefinedPV ( ipAddrToAsciiEngine & engine,
callbackForMultiplyDefinedPV &, const char * pChannelName,
@@ -62,8 +65,8 @@ private:
ipAddrToAsciiTransaction & dnsTransaction;
callbackForMultiplyDefinedPV & cb;
void transactionComplete ( const char * pHostName );
msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & );
msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & );
msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & );
msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & );
void operator delete ( void * );
};

View File

@@ -1138,6 +1138,20 @@ void CA_add_exception_event(const char *class, SV *sub) {
static
SV * printf_sub = NULL;
#ifndef va_copy
# ifdef __GNUC__
# define va_copy(d, s) __va_copy(d, s)
# else
# define va_copy(d, s) ((d) = (s))
/* The above macro is NOT PORTABLE but works on Windows when
* stdarg.h doesn't provide va_copy(). Some architectures need
* define va_copy(d, s) ((*d) = (*s))
* while others may be even more complicated, but hopefully the
* system stdarg.h header defines va_copy() in those cases.
*/
# endif
#endif
static
int printf_handler(const char *format, va_list args) {
if (! printf_sub)
@@ -1152,11 +1166,7 @@ int printf_handler(const char *format, va_list args) {
ENTER;
SAVETMPS;
#ifdef __GNUC__
__va_copy(argcopy, args);
#else
va_copy(argcopy, args);
#endif
printf_str = NEWSV(0, strlen(format) + 32);
sv_vsetpvf(printf_str, format, &argcopy);

View File

@@ -20,10 +20,19 @@ ifeq ($(OS_CLASS),Darwin)
LOADABLE_SHRLIB_SUFFIX = .$(shell $(PERL) ../perlConfig.pl dlext)
endif
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
PERL_ARCHPATH = $(PERL_VERSION)/$(PERL_ARCHNAME)
ifdef T_A
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
PERL_ARCHPATH := $(PERL_VERSION)/$(PERL_ARCHNAME)
EXTUTILS := $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
PERLBIN := $(shell $(PERL) ../perlConfig.pl bin)
XSUBPP := $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
ifeq ($(strip $(XSUBPP)),)
$(warning Perl's xsubpp program was not found.)
$(warning The Perl CA module will not be built.)
else
ifeq ($(T_A),$(EPICS_HOST_ARCH)) # No cross-builds (wrong Perl!)
ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
LOADABLE_LIBRARY_HOST = Cap5
@@ -41,6 +50,8 @@ ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32
HTMLS = CA.html
endif
endif
endif
endif
Cap5_SRCS = Cap5.xs
Cap5_LIBS = ca Com
@@ -52,10 +63,6 @@ CLEANS += Cap5.c pod2htmd.tmp pod2htmi.tmp
include $(TOP)/configure/RULES
ifdef T_A
EXTUTILS = $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
PERLBIN = $(shell $(PERL) ../perlConfig.pl bin)
XSUBPP = $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
%.c: ../%.xs
$(RM) $@ $@_new
$(PERL) $(XSUBPP) -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@

View File

@@ -3,7 +3,13 @@
# This script is used to extract information about the Perl build
# configuration, so the EPICS build system uses the same settings.
use strict;
use Config;
my $arg = shift;
print $Config{$arg};
my $val = $Config{$arg};
$val =~ s{\\}{/}go
if $^O eq 'MSWin32';
print $val;

View File

@@ -492,14 +492,13 @@ int main (int argc, char *argv[])
} else { /* Not an ENUM */
if (charArrAsStr) {
count = len;
dbrType = DBR_CHAR;
ebuf = calloc(strlen(cbuf)+1, sizeof(char));
ebuf = calloc(len, sizeof(char));
if(!ebuf) {
fprintf(stderr, "Memory allocation failed\n");
return 1;
}
epicsStrnRawFromEscaped(ebuf, strlen(cbuf)+1, cbuf, strlen(cbuf));
count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1;
} else {
for (i = 0; i < count; ++i) {
epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr));

View File

@@ -163,6 +163,19 @@ udpiiu::udpiiu (
throwWithLocation ( noSocket () );
}
#ifdef IP_ADD_MEMBERSHIP
{
int flag = 1;
if ( setsockopt ( this->sock, IPPROTO_IP, IP_MULTICAST_LOOP,
(char *) &flag, sizeof ( flag ) ) == -1 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf("CAC: failed to set mcast loopback\n");
}
}
#endif
int boolValue = true;
int status = setsockopt ( this->sock, SOL_SOCKET, SO_BROADCAST,
(char *) &boolValue, sizeof ( boolValue ) );

View File

@@ -69,6 +69,11 @@ CLEANS += $(COMMON_DIR)/aitConvertGenerated.cc
USR_CXXFLAGS_Linux = -fno-strict-aliasing
USR_CXXFLAGS_RTEMS = -fno-strict-aliasing
ifeq ($(T_A),$(EPICS_HOST_ARCH))
# genApps and aitGen are needed to finish libgdd
DELAY_INSTALL_LIBS = YES
endif
include $(TOP)/configure/RULES
# Manual dependencies

View File

@@ -141,6 +141,39 @@ caStatus caServerI::attachInterface ( const caNetAddr & addrIn,
return S_cas_success;
}
void caServerI::addMCast(const osiSockAddr& addr)
{
#ifdef IP_ADD_MEMBERSHIP
epicsGuard < epicsMutex > locker ( this->mutex );
tsDLIter < casIntfOS > iter = this->intfList.firstIter ();
while ( iter.valid () ) {
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.imr_interface = iter->serverAddress().getSockIP().sin_addr;
mreq.imr_multiaddr = addr.ia.sin_addr;
if ( setsockopt ( iter->casDGIntfIO::getFD (), IPPROTO_IP,
IP_ADD_MEMBERSHIP, (char *) &mreq,
sizeof ( mreq ) ) < 0) {
struct sockaddr_in temp;
char name[40];
char sockErrBuf[64];
temp.sin_family = AF_INET;
temp.sin_addr = mreq.imr_multiaddr;
temp.sin_port = addr.ia.sin_port;
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToDottedIP (&temp, name, sizeof(name));
fprintf(stderr, "CAS: Socket mcast join %s failed with \"%s\"\n",
name, sockErrBuf );
}
iter++;
}
#endif
}
void caServerI::sendBeacon ( ca_uint32_t beaconNo )
{
epicsGuard < epicsMutex > locker ( this->mutex );

View File

@@ -103,6 +103,8 @@ private:
caStatus attachInterface ( const caNetAddr & addr, bool autoBeaconAddr,
bool addConfigAddr );
virtual void addMCast(const osiSockAddr&);
void sendBeacon ( ca_uint32_t beaconNo );
caServerI ( const caServerI & );

View File

@@ -348,10 +348,8 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
//
caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
{
int status;
epicsGuard < epicsMutex > guard ( this->mutex );
status = this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available, 0 );
this->out.commitMsg ();

View File

@@ -14,6 +14,7 @@
//
#include <ctype.h>
#include <list>
#include "epicsSignal.h"
#include "envDefs.h"
@@ -92,6 +93,9 @@ void caServerIO::locateInterfaces ()
autoBeaconAddr = true;
}
typedef std::list<osiSockAddr> mcastAddrs_t;
mcastAddrs_t mcastAddrs;
//
// bind to the the interfaces specified - otherwise wildcard
// with INADDR_ANY and allow clients to attach from any interface
@@ -114,6 +118,15 @@ void caServerIO::locateInterfaces ()
pToken);
continue;
}
epicsUInt32 top = ntohl(saddr.sin_addr.s_addr)>>24;
if (saddr.sin_family==AF_INET && top>=224 && top<=239) {
osiSockAddr oaddr;
oaddr.ia = saddr;
mcastAddrs.push_back(oaddr);
continue;
}
stat = this->attachInterface (caNetAddr(saddr), autoBeaconAddr, configAddrOnceFlag);
if (stat) {
errMessage(stat, "unable to attach explicit interface");
@@ -131,6 +144,10 @@ void caServerIO::locateInterfaces ()
errMessage(stat, "unable to attach any interface");
}
}
for (mcastAddrs_t::const_iterator it = mcastAddrs.begin(); it!=mcastAddrs.end(); ++it) {
this->addMCast(*it);
}
}
//

View File

@@ -47,6 +47,8 @@ private:
virtual caStatus attachInterface (
const caNetAddr & addr, bool autoBeaconAddr,
bool addConfigAddr ) = 0;
virtual void addMCast(const osiSockAddr&) = 0;
};
#endif // caServerIOh

View File

@@ -19,6 +19,11 @@
#include "addrList.h"
#include "errlog.h"
#if defined(_MSC_VER)
# include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#define epicsExportSharedSymbols
#include "casDGIntfIO.h"
#include "ipIgnoreEntry.h"
@@ -148,26 +153,8 @@ casDGIntfIO::casDGIntfIO ( caServerI & serverIn, clientBufMemoryManager & memMgr
}
if ( addConfigBeaconAddr ) {
//
// by default use EPICS_CA_ADDR_LIST for the
// beacon address list
//
const ENV_PARAM *pParam;
if ( envGetConfigParamPtr ( & EPICS_CAS_INTF_ADDR_LIST ) ||
envGetConfigParamPtr ( & EPICS_CAS_BEACON_ADDR_LIST ) ) {
pParam = & EPICS_CAS_BEACON_ADDR_LIST;
}
else {
pParam = & EPICS_CA_ADDR_LIST;
}
//
// add in the configured addresses
//
addAddrToChannelAccessAddressList (
& BCastAddrList, pParam, beaconPort, pParam == & EPICS_CA_ADDR_LIST );
& BCastAddrList, &EPICS_CAS_BEACON_ADDR_LIST, beaconPort, 0 );
}
removeDuplicateAddresses ( & this->beaconAddrList, & BCastAddrList, 0 );
@@ -267,7 +254,7 @@ casDGIntfIO::~casDGIntfIO()
// avoid use of ellFree because problems on windows occur if the
// free is in a different DLL than the malloc
ELLNODE * nnode = this->beaconAddrList.node.next;
ELLNODE * nnode = ellFirst(&this->beaconAddrList);
while ( nnode )
{
ELLNODE * pnode = nnode;
@@ -418,52 +405,24 @@ bufSizeT casDGIntfIO ::
}
void casDGIntfIO::sendBeaconIO ( char & msg, unsigned length,
aitUint16 & portField, aitUint32 & addrField )
aitUint16 & portField, aitUint32 & )
{
caNetAddr addr = this->serverAddress ();
struct sockaddr_in inetAddr = addr.getSockIP();
osiSockAddrNode *pAddr;
int status;
char buf[64];
portField = inetAddr.sin_port; // the TCP port
for (pAddr = reinterpret_cast <osiSockAddrNode *> ( ellFirst ( & this->beaconAddrList ) );
pAddr; pAddr = reinterpret_cast <osiSockAddrNode *> ( ellNext ( & pAddr->node ) ) ) {
status = connect ( this->beaconSock, &pAddr->addr.sa, sizeof ( pAddr->addr.sa ) );
if (status<0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToDottedIP ( & pAddr->addr.ia, buf, sizeof ( buf ) );
errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n",
__FILE__, buf, sockErrBuf );
}
else {
osiSockAddr sockAddr;
osiSocklen_t size = ( osiSocklen_t ) sizeof ( sockAddr.sa );
status = getsockname ( this->beaconSock, &sockAddr.sa, &size );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n",
__FILE__, sockErrBuf );
}
else if ( sockAddr.sa.sa_family == AF_INET ) {
addrField = sockAddr.ia.sin_addr.s_addr;
for (ELLNODE *pNode = ellFirst(&this->beaconAddrList); pNode; pNode = ellNext(pNode))
{
osiSockAddrNode *pAddr = reinterpret_cast<osiSockAddrNode *>(pNode);
status = send ( this->beaconSock, &msg, length, 0 );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToA ( &pAddr->addr.ia, buf, sizeof(buf) );
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
__FILE__, buf, sockErrBuf );
}
else {
unsigned statusAsLength = static_cast < unsigned > ( status );
assert ( statusAsLength == length );
}
}
ssize_t status = sendto(this->beaconSock, &msg, length, 0, &pAddr->addr.sa, sizeof(pAddr->addr.ia));
if ( status != length ) {
char sockErrBuf[64], buf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToA ( &pAddr->addr.ia, buf, sizeof(buf) );
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\" (%u)\n",
__FILE__, buf, sockErrBuf, (unsigned)status );
}
}
}

View File

@@ -402,19 +402,29 @@ struct rset * dbGetRset(const struct dbAddr *paddr)
}
long dbPutAttribute(
const char *recordTypename,const char *name,const char*value)
const char *recordTypename, const char *name, const char *value)
{
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
long status=0;
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
long status = 0;
if(!pdbbase) return(S_db_notFound);
dbInitEntry(pdbbase,pdbEntry);
status = dbFindRecordType(pdbEntry,recordTypename);
if(!status) status = dbPutRecordAttribute(pdbEntry,name,value);
dbFinishEntry(pdbEntry);
if(status) errMessage(status,"dbPutAttribute failure");
return(status);
if (!pdbbase)
return S_db_notFound;
if (!name) {
status = S_db_badField;
goto done;
}
if (!value)
value = "";
dbInitEntry(pdbbase, pdbEntry);
status = dbFindRecordType(pdbEntry, recordTypename);
if (!status)
status = dbPutRecordAttribute(pdbEntry, name, value);
dbFinishEntry(pdbEntry);
done:
if (status)
errMessage(status, "dbPutAttribute failure");
return status;
}
int dbIsValueField(const struct dbFldDes *pdbFldDes)
@@ -812,11 +822,10 @@ long dbGet(DBADDR *paddr, short dbrType,
void *pbuffer, long *options, long *nRequest, void *pflin)
{
char *pbuf = pbuffer;
void *pfieldsave;
void *pfieldsave = paddr->pfield;
db_field_log *pfl = (db_field_log *)pflin;
short field_type;
long no_elements;
long offset;
long capacity, no_elements, offset;
struct rset *prset;
long status = 0;
@@ -826,18 +835,33 @@ long dbGet(DBADDR *paddr, short dbrType,
return 0;
if (!pfl || pfl->type == dbfl_type_rec) {
field_type = paddr->field_type;
no_elements = paddr->no_elements;
field_type = paddr->field_type;
no_elements = capacity = paddr->no_elements;
/* Update field info from record
* may modify paddr->pfield
*/
if (paddr->pfldDes->special == SPC_DBADDR &&
(prset = dbGetRset(paddr)) &&
prset->get_array_info) {
status = prset->get_array_info(paddr, &no_elements, &offset);
} else
offset = 0;
} else {
field_type = pfl->field_type;
no_elements = pfl->no_elements;
field_type = pfl->field_type;
no_elements = capacity = pfl->no_elements;
offset = 0;
}
if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK)
return getLinkValue(paddr, dbrType, pbuf, nRequest);
if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) {
status = getLinkValue(paddr, dbrType, pbuf, nRequest);
goto done;
}
if (paddr->special == SPC_ATTRIBUTE)
return getAttrValue(paddr, dbrType, pbuf, nRequest);
if (paddr->special == SPC_ATTRIBUTE) {
status = getAttrValue(paddr, dbrType, pbuf, nRequest);
goto done;
}
/* Check for valid request */
if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
@@ -845,26 +869,13 @@ long dbGet(DBADDR *paddr, short dbrType,
sprintf(message, "dbGet: Request type is %d\n", dbrType);
recGblDbaddrError(S_db_badDbrtype, paddr, message);
return S_db_badDbrtype;
status = S_db_badDbrtype;
goto done;
}
/* For SPC_DBADDR fields, the rset function
* get_array_info() is allowed to modify
* paddr->pfield. So we store the original
* value and restore it later.
*/
pfieldsave = paddr->pfield;
/* Update field info */
if (paddr->pfldDes->special == SPC_DBADDR &&
(prset = dbGetRset(paddr)) &&
prset->get_array_info) {
status = prset->get_array_info(paddr, &no_elements, &offset);
} else
offset = 0;
if (offset == 0 && (!nRequest || no_elements == 1)) {
if (nRequest) *nRequest = 1;
if (nRequest)
*nRequest = 1;
if (!pfl || pfl->type == dbfl_type_rec) {
status = dbFastGetConvertRoutine[field_type][dbrType]
(paddr->pfield, pbuf, paddr);
@@ -883,10 +894,11 @@ long dbGet(DBADDR *paddr, short dbrType,
}
} else {
long n;
long (*convert)();
GETCONVERTFUNC convert;
if (nRequest) {
if (no_elements<(*nRequest)) *nRequest = no_elements;
if (no_elements < *nRequest)
*nRequest = no_elements;
n = *nRequest;
} else {
n = 1;
@@ -901,11 +913,11 @@ long dbGet(DBADDR *paddr, short dbrType,
status = S_db_badDbrtype;
goto done;
}
/* convert database field and place it in the buffer */
/* convert data into the caller's buffer */
if (n <= 0) {
;/*do nothing*/
} else if (!pfl || pfl->type == dbfl_type_rec) {
status = convert(paddr, pbuf, n, no_elements, offset);
status = convert(paddr, pbuf, n, capacity, offset);
} else {
DBADDR localAddr = *paddr; /* Structure copy */
@@ -916,7 +928,7 @@ long dbGet(DBADDR *paddr, short dbrType,
localAddr.pfield = (char *) &pfl->u.v.field;
else
localAddr.pfield = (char *) pfl->u.r.field;
status = convert(&localAddr, pbuf, n, no_elements, offset);
status = convert(&localAddr, pbuf, n, capacity, offset);
}
}
done:

View File

@@ -704,21 +704,27 @@ void dbChannelShow(dbChannel *chan, int level, const unsigned short indent)
int pre = ellCount(&chan->pre_chain);
int post = ellCount(&chan->post_chain);
printf("%*schannel name: %s\n", indent, "", chan->name);
printf("%*s field_type=%s (%d bytes), dbr_type=%s, %ld element%s, %d filter%s", indent, "",
dbGetFieldTypeString(chan->addr.field_type), chan->addr.field_size,
dbGetFieldTypeString(chan->addr.dbr_field_type), elems, elems == 1 ? "" : "s",
count, count == 1 ? "" : "s");
if (count)
printf(" (%d pre eventq, %d post eventq)\n", pre, post);
else
printf("\n");
if (level > 0)
dbChannelFilterShow(chan, level - 1, indent + 2);
if (count) {
printf("%*s final field_type=%s (%dB), %ld element%s\n", indent, "",
dbGetFieldTypeString(chan->final_type), chan->final_field_size,
felems, felems == 1 ? "" : "s");
printf("%*sChannel: '%s'\n", indent, "", chan->name);
if (level > 0) {
printf("%*sfield_type=%s (%d bytes), dbr_type=%s, %ld element%s",
indent + 4, "",
dbGetFieldTypeString(chan->addr.field_type),
chan->addr.field_size,
dbGetFieldTypeString(chan->addr.dbr_field_type),
elems, elems == 1 ? "" : "s");
if (count)
printf("\n%*s%d filter%s (%d pre eventq, %d post eventq)\n",
indent + 4, "", count, count == 1 ? "" : "s", pre, post);
else
printf(", no filters\n");
if (level > 1)
dbChannelFilterShow(chan, level - 2, indent + 8);
if (count) {
printf("%*sfinal field_type=%s (%dB), %ld element%s\n", indent + 4, "",
dbGetFieldTypeString(chan->final_type),
chan->final_field_size,
felems, felems == 1 ? "" : "s");
}
}
}

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
%#include "epicsTypes.h"
%#include "link.h"
@@ -15,59 +15,59 @@
}
field(DESC,DBF_STRING) {
prompt("Descriptor")
promptgroup(GUI_COMMON)
promptgroup("10 - Common")
size(41)
}
field(ASG,DBF_STRING) {
prompt("Access Security Group")
promptgroup(GUI_COMMON)
promptgroup("10 - Common")
special(SPC_AS)
size(29)
}
field(SCAN,DBF_MENU) {
prompt("Scan Mechanism")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuScan)
}
field(PINI,DBF_MENU) {
prompt("Process at iocInit")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
interest(1)
menu(menuPini)
}
field(PHAS,DBF_SHORT) {
prompt("Scan Phase")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {
prompt("Time Stamp Event")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
interest(1)
}
field(TSEL,DBF_INLINK) {
prompt("Time Stamp Link")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
interest(1)
}
field(DTYP,DBF_DEVICE) {
prompt("Device Type")
promptgroup(GUI_LINKS)
promptgroup("10 - Common")
interest(1)
}
field(DISV,DBF_SHORT) {
prompt("Disable Value")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
initial("1")
}
field(DISA,DBF_SHORT) {
@@ -75,7 +75,7 @@
}
field(SDIS,DBF_INLINK) {
prompt("Scanning Disable")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
interest(1)
}
%#include "epicsMutex.h"
@@ -131,7 +131,7 @@
}
field(ACKT,DBF_MENU) {
prompt("Alarm Ack Transient")
promptgroup(GUI_ALARMS)
promptgroup("70 - Alarm")
special(SPC_NOMOD)
interest(2)
menu(menuYesNo)
@@ -139,7 +139,7 @@
}
field(DISS,DBF_MENU) {
prompt("Disable Alarm Sevrty")
promptgroup(GUI_SCAN)
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
}
@@ -219,7 +219,7 @@
}
field(PRIO,DBF_MENU) {
prompt("Scheduling Priority")
promptgroup(GUI_SCAN)
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuPriority)
@@ -235,14 +235,14 @@
}
field(UDF,DBF_UCHAR) {
prompt("Undefined")
promptgroup(GUI_COMMON)
promptgroup("10 - Common")
pp(TRUE)
interest(1)
initial("1")
}
field(UDFS,DBF_MENU) {
prompt("Undefined Alarm Sevrty")
promptgroup(GUI_COMMON)
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
initial("INVALID")
@@ -256,6 +256,6 @@
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup(GUI_LINKS)
promptgroup("20 - Scan")
interest(1)
}

View File

@@ -224,6 +224,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
return S_db_badDbrtype;
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
&& paddr->special != SPC_DBADDR
&& paddr->special != SPC_ATTRIBUTE) {
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);

View File

@@ -39,6 +39,7 @@
#include "dbChannel.h"
#include "dbCommon.h"
#include "dbEvent.h"
#include "dbLock.h"
#include "dbNotify.h"
#include "dbStaticLib.h"
#include "recSup.h"
@@ -153,28 +154,30 @@ int dbChannel_get_count(
* in the dbAccess.c dbGet() and getOptions() routines.
*/
dbScanLock(dbChannelRecord(chan));
switch(buffer_type) {
case(oldDBR_STRING):
status = dbChannelGetField(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
break;
/* case(oldDBR_INT): */
case(oldDBR_SHORT):
status = dbChannelGetField(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_FLOAT):
status = dbChannelGetField(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_ENUM):
status = dbChannelGetField(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_CHAR):
status = dbChannelGetField(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_LONG):
status = dbChannelGetField(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_DOUBLE):
status = dbChannelGetField(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
status = dbChannelGet(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
break;
case(oldDBR_STS_STRING):
@@ -187,10 +190,10 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
status = dbChannelGetField(chan, DBR_STRING, pold->value, &zero,
status = dbChannelGet(chan, DBR_STRING, pold->value, &zero,
nRequest, pfl);
}
break;
@@ -203,10 +206,10 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &zero,
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -218,10 +221,10 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &zero,
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -233,10 +236,10 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &zero,
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -248,10 +251,10 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &zero,
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -263,10 +266,10 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &zero,
status = dbChannelGet(chan, DBR_LONG, &pold->value, &zero,
nRequest, pfl);
}
break;
@@ -278,11 +281,11 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
options = 0;
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -296,12 +299,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_STRING, pold->value, &options,
status = dbChannelGet(chan, DBR_STRING, pold->value, &options,
nRequest, pfl);
}
break;
@@ -315,12 +318,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -333,12 +336,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -351,12 +354,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -369,12 +372,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_CHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_CHAR, &pold->value, &options,
status = dbChannelGet(chan, DBR_CHAR, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -387,12 +390,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -405,12 +408,12 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_TIME;
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.time; /* structure copy */
options = 0;
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -428,7 +431,7 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -440,7 +443,7 @@ int dbChannel_get_count(
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -457,7 +460,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_AL_DOUBLE;
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = (dbr_short_t) newSt.precision.dp;
@@ -470,7 +473,7 @@ int dbChannel_get_count(
pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
options = 0;
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -486,7 +489,7 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -498,7 +501,7 @@ int dbChannel_get_count(
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -513,7 +516,7 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -525,7 +528,7 @@ int dbChannel_get_count(
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -542,7 +545,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_AL_DOUBLE;
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = (dbr_short_t) newSt.precision.dp;
@@ -555,7 +558,7 @@ int dbChannel_get_count(
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.lower_alarm_limit;
options = 0;
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -574,7 +577,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -588,7 +591,7 @@ int dbChannel_get_count(
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options,
status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -606,7 +609,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = (dbr_short_t) newSt.precision.dp;
@@ -621,7 +624,7 @@ int dbChannel_get_count(
pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit);
options = 0;
status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options,
status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -638,7 +641,7 @@ int dbChannel_get_count(
memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
/* first get status and severity */
options = DBR_STATUS | DBR_ENUM_STRS;
status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
no_str = newSt.no_str;
@@ -648,7 +651,7 @@ int dbChannel_get_count(
strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i]));
/*now get values*/
options = 0;
status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options,
status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -665,7 +668,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -679,7 +682,7 @@ int dbChannel_get_count(
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options,
status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -696,7 +699,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
DBR_AL_LONG;
status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -710,7 +713,7 @@ int dbChannel_get_count(
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options,
status = dbChannelGet(chan, DBR_LONG, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -728,7 +731,7 @@ int dbChannel_get_count(
options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = (dbr_short_t) newSt.precision.dp;
@@ -743,7 +746,7 @@ int dbChannel_get_count(
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
options = 0;
status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options,
status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options,
nRequest, pfl);
}
break;
@@ -756,13 +759,13 @@ int dbChannel_get_count(
} newSt;
options = DBR_STATUS;
status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl);
status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->ackt = newSt.ackt;
pold->acks = newSt.acks;
options = 0;
status = dbChannelGetField(chan, DBR_STRING, pold->value,
status = dbChannelGet(chan, DBR_STRING, pold->value,
&options, nRequest, pfl);
}
break;
@@ -791,8 +794,12 @@ int dbChannel_get_count(
}
break;
default:
return -1;
status = -1;
break;
}
dbScanUnlock(dbChannelRecord(chan));
if (status) return -1;
return 0;
}

View File

@@ -19,7 +19,8 @@
#ifndef INCLdb_field_logh
#define INCLdb_field_logh
#include "epicsTime.h"
#include <epicsTime.h>
#include <epicsTypes.h>
#ifdef __cplusplus
extern "C" {
@@ -32,18 +33,20 @@ extern "C" {
* priority task pending on the event queue wakes up). Strings would slow down
* events for more reasonable size values. DB fields of native type string
* will most likely change infrequently.
*
*
* Strings can be added to the set of types for which updates will be queued
* by defining the macro DB_EVENT_LOG_STRINGS. The code in db_add_event()
* will adjust automatically, it just compares field sizes.
*/
union native_value {
short dbf_int;
short dbf_short;
float dbf_float;
short dbf_enum;
char dbf_char;
long dbf_long;
double dbf_double;
epicsInt8 dbf_char;
epicsInt16 dbf_short;
epicsEnum16 dbf_enum;
epicsInt32 dbf_long;
epicsFloat32 dbf_float;
epicsFloat64 dbf_double;
#ifdef DB_EVENT_LOG_STRINGS
char dbf_string[MAX_STRING_SIZE];
char dbf_string[MAX_STRING_SIZE];
#endif
};

View File

@@ -12,14 +12,17 @@ include $(TOP)/configure/CONFIG
TESTLIBRARY = dbTestIoc
dbTestIoc_SRCS += arrRecord.c
dbTestIoc_SRCS += xRecord.c
dbTestIoc_SRCS += dbLinkdset.c
dbTestIoc_LIBS = dbCore ca Com
TARGETS += $(COMMON_DIR)/dbTestIoc.dbd
DBDDEPENDS_FILES += dbTestIoc.dbd$(DEP)
dbTestIoc_DBD += menuGlobal.dbd
dbTestIoc_DBD += menuConvert.dbd
dbTestIoc_DBD += menuScan.dbd
#dbTestIoc_DBD += arrRecord.dbd
dbTestIoc_DBD += xRecord.dbd
dbTestIoc_DBD += dbLinkdset.dbd
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
@@ -76,6 +79,7 @@ TESTS += dbCaStatsTest
TESTFILES += ../dbCaStatsTest.db
TARGETS += $(COMMON_DIR)/scanIoTest.dbd
DBDDEPENDS_FILES += scanIoTest.dbd$(DEP)
scanIoTest_DBD += menuGlobal.dbd
scanIoTest_DBD += menuConvert.dbd
scanIoTest_DBD += menuScan.dbd
@@ -95,6 +99,17 @@ dbChannelTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbChannelTest.c
TESTS += dbChannelTest
TARGETS += $(COMMON_DIR)/dbChArrTest.dbd
DBDDEPENDS_FILES += dbChArrTest.dbd$(DEP)
dbChArrTest_DBD += arrRecord.dbd
TESTPROD_HOST += dbChArrTest
dbChArrTest_SRCS += dbChArrTest.cpp
dbChArrTest_SRCS += dbChArrTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbChArrTest.cpp
testHarness_SRCS += dbChArrTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/dbChArrTest.dbd ../dbChArrTest.db
TESTS += dbChArrTest
TESTPROD_HOST += chfPluginTest
chfPluginTest_SRCS += chfPluginTest.c
chfPluginTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
@@ -132,7 +147,7 @@ TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
dbPutLinkTest$(DEP): $(COMMON_DIR)/xRecord.h
scanIoTest$(DEP): $(COMMON_DIR)/yRecord.h

135
src/ioc/db/test/arrRecord.c Normal file
View File

@@ -0,0 +1,135 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* arrRecord.c - minimal array record for test purposes: no processing */
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*
* vaguely implemented like parts of recWaveform.c by Bob Dalesio
*
*/
#include <stdio.h>
#include "dbDefs.h"
#include "epicsPrint.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbFldTypes.h"
#include "recSup.h"
#include "recGbl.h"
#include "cantProceed.h"
#define GEN_SIZE_OFFSET
#include "arrRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
static long init_record(arrRecord *, int);
static long process(arrRecord *);
#define special NULL
#define get_value NULL
static long cvt_dbaddr(DBADDR *);
static long get_array_info(DBADDR *, long *, long *);
static long put_array_info(DBADDR *, long);
#define get_units NULL
#define get_precision NULL
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
#define get_graphic_double NULL
#define get_control_double NULL
#define get_alarm_double NULL
rset arrRSET = {
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset, arrRSET);
static long init_record(arrRecord *prec, int pass)
{
if (pass == 0) {
if (prec->nelm <= 0)
prec->nelm = 1;
if (prec->ftvl > DBF_ENUM)
prec->ftvl = DBF_UCHAR;
prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl),
"arr calloc failed");
if (prec->nelm == 1) {
prec->nord = 1;
} else {
prec->nord = 0;
}
return 0;
}
return 0;
}
static long process(arrRecord *prec)
{
return 0;
}
static long cvt_dbaddr(DBADDR *paddr)
{
arrRecord *prec = (arrRecord *) paddr->precord;
paddr->pfield = prec->bptr;
paddr->no_elements = prec->nelm;
paddr->field_type = prec->ftvl;
paddr->field_size = dbValueSize(prec->ftvl);
paddr->dbr_field_type = prec->ftvl;
return 0;
}
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
{
arrRecord *prec = (arrRecord *) paddr->precord;
*no_elements = prec->nord;
*offset = prec->off;
return 0;
}
static long put_array_info(DBADDR *paddr, long nNew)
{
arrRecord *prec = (arrRecord *) paddr->precord;
prec->nord = nNew;
if (prec->nord > prec->nelm)
prec->nord = prec->nelm;
return 0;
}

View File

@@ -0,0 +1,34 @@
include "menuGlobal.dbd"
include "menuConvert.dbd"
include "menuScan.dbd"
recordtype(arr) {
include "dbCommon.dbd"
field(VAL, DBF_NOACCESS) {
prompt("Value")
special(SPC_DBADDR)
pp(TRUE)
extra("void *val")
}
field(NELM, DBF_ULONG) {
prompt("Number of Elements")
special(SPC_NOMOD)
initial("1")
}
field(FTVL, DBF_MENU) {
prompt("Field Type of Value")
special(SPC_NOMOD)
menu(menuFtype)
}
field(NORD, DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(OFF, DBF_ULONG) {
prompt("Offset into array")
}
field(BPTR, DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
extra("void *bptr")
}
}

View File

@@ -99,7 +99,7 @@ MAIN(callbackParallelTest)
myPvt *pcbt[NCALLBACKS];
epicsTimeStamp start;
int noCpus = epicsThreadGetCPUs();
int i, j;
int i, j, slowups, faults;
/* Statistics: min/max/sum/sum^2/n for each priority */
double setupError[NUM_CALLBACK_PRIORITIES][5];
double timeError[NUM_CALLBACK_PRIORITIES][5];
@@ -109,7 +109,7 @@ MAIN(callbackParallelTest)
for (j = 0; j < 5; j++)
setupError[i][j] = timeError[i][j] = defaultError[j];
testPlan(NCALLBACKS * 2 + 1);
testPlan(4);
testDiag("Starting %d parallel callback threads", noCpus);
@@ -138,7 +138,7 @@ MAIN(callbackParallelTest)
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
pcbt[NCALLBACKS-1]->pass = 0;
testOk1(epicsTimeGetCurrent(&start)==epicsTimeOK);
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
for (i = 0; i < NCALLBACKS ; i++) {
callbackRequest(&pcbt[i]->cb1);
@@ -147,28 +147,43 @@ MAIN(callbackParallelTest)
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
epicsEventWait(finished);
slowups = 0;
faults = 0;
for (i = 0; i < NCALLBACKS ; i++) {
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
testFail("pass = %d for delay = %f", pcbt[i]->pass, pcbt[i]->delay);
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
++faults, pcbt[i]->pass, pcbt[i]->delay);
else {
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
testOk(fabs(delta) < 0.05, "callback %.02f setup time |%f| < 0.05",
if (fabs(delta) >= 0.05) {
slowups++;
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
pcbt[i]->delay, delta);
}
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
}
}
testOk(faults == 0, "%d faults during callback setup", faults);
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
slowups = 0;
for (i = 0; i < NCALLBACKS ; i++) {
double delta, error;
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
continue;
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
error = delta - pcbt[i]->delay;
testOk(fabs(error) < 0.05, "delay %.02f seconds, callback time error |%.04f| < 0.05",
if (fabs(error) >= 0.05) {
slowups++;
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
pcbt[i]->delay, error);
}
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
}
testOk(slowups < 5, "%d slowups during callbacks", slowups);
testDiag("Setup time statistics");
printStats(setupError[0], "LOW");

View File

@@ -99,7 +99,7 @@ MAIN(callbackTest)
{
myPvt *pcbt[NCALLBACKS];
epicsTimeStamp start;
int i, j;
int i, j, slowups, faults;
/* Statistics: min/max/sum/sum^2/n for each priority */
double setupError[NUM_CALLBACK_PRIORITIES][5];
double timeError[NUM_CALLBACK_PRIORITIES][5];
@@ -109,7 +109,7 @@ MAIN(callbackTest)
for (j = 0; j < 5; j++)
setupError[i][j] = timeError[i][j] = defaultError[j];
testPlan(NCALLBACKS * 2 + 1);
testPlan(4);
callbackInit();
epicsThreadSleep(1.0);
@@ -135,7 +135,7 @@ MAIN(callbackTest)
pcbt[NCALLBACKS-1]->delay = TEST_DELAY(NCALLBACKS) + 1.0;
pcbt[NCALLBACKS-1]->pass = 0;
testOk1(epicsTimeGetCurrent(&start)==epicsTimeOK);
testOk(epicsTimeGetCurrent(&start)==epicsTimeOK, "Time-of-day clock Ok");
for (i = 0; i < NCALLBACKS ; i++) {
callbackRequest(&pcbt[i]->cb1);
@@ -144,28 +144,43 @@ MAIN(callbackTest)
testDiag("Waiting %.02f sec", pcbt[NCALLBACKS-1]->delay);
epicsEventWait(finished);
slowups = 0;
faults = 0;
for (i = 0; i < NCALLBACKS ; i++) {
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
testFail("pass = %d for delay = %f", pcbt[i]->pass, pcbt[i]->delay);
testDiag("callback setup fault #%d: pass = %d for delay = %.02f",
++faults, pcbt[i]->pass, pcbt[i]->delay);
else {
double delta = epicsTimeDiffInSeconds(&pcbt[i]->pass1Time, &start);
testOk(fabs(delta) < 0.05, "callback %.02f setup time |%f| < 0.05",
if (fabs(delta) >= 0.05) {
slowups++;
testDiag("callback %.02f setup time |%f| >= 0.05 seconds",
pcbt[i]->delay, delta);
}
updateStats(setupError[i%NUM_CALLBACK_PRIORITIES], delta);
}
}
testOk(faults == 0, "%d faults during callback setup", faults);
testOk(slowups <= 1, "%d slowups during callback setup", slowups);
slowups = 0;
for (i = 0; i < NCALLBACKS ; i++) {
double delta, error;
if(pcbt[i]->resultFail || pcbt[i]->pass!=2)
continue;
delta = epicsTimeDiffInSeconds(&pcbt[i]->pass2Time, &pcbt[i]->pass1Time);
error = delta - pcbt[i]->delay;
testOk(fabs(error) < 0.05, "delay %.02f seconds, callback time error |%.04f| < 0.05",
if (fabs(error) >= 0.05) {
slowups++;
testDiag("delay %.02f seconds, delay error |%.04f| >= 0.05",
pcbt[i]->delay, error);
}
updateStats(timeError[i%NUM_CALLBACK_PRIORITIES], error);
}
testOk(slowups < 5, "%d slowups during callbacks", slowups);
testDiag("Setup time statistics");
printStats(setupError[0], "LOW");

View File

@@ -418,7 +418,7 @@ static void channelRegisterPost(dbChannel *chan, void *user,
static void channel_report(dbChannel *chan, void *user, int level,
const unsigned short indent)
{
testOk(level == R_LEVEL - 1, "channel_report: level correct");
testOk(level == R_LEVEL - 2, "channel_report: level correct %u == %u", level, R_LEVEL-2);
if (user == puser1) {
testOk(e1 & e_report, "channel_report (1) called");
c1 |= e_report;

View File

@@ -0,0 +1,246 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2003 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to the Software License Agreement
* found in the file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Authors: Ralph Lange <ralph.lange@gmx.de>,
* Andrew Johnson <anj@aps.anl.gov>
*/
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "registryFunction.h"
#include "epicsThread.h"
#include "epicsExit.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "envDefs.h"
#include "dbStaticLib.h"
#include "dbmf.h"
#include "registry.h"
#include "dbAddr.h"
#include "dbAccess.h"
#include "asDbLib.h"
#include "iocInit.h"
#include "iocsh.h"
#include "dbChannel.h"
#include "epicsUnitTest.h"
#include "testMain.h"
#include "osiFileName.h"
extern "C" {
int dbChArrTest_registerRecordDeviceDriver(struct dbBase *pdbbase);
}
#define CA_SERVER_PORT "65535"
const char *server_port = CA_SERVER_PORT;
static void createAndOpen(const char *name, dbChannel**pch)
{
testOk(!!(*pch = dbChannelCreate(name)), "dbChannel %s created", name);
testOk(!(dbChannelOpen(*pch)), "dbChannel opened");
testOk((ellCount(&(*pch)->pre_chain) == 0), "no filters in pre chain");
testOk((ellCount(&(*pch)->post_chain) == 0), "no filters in post chain");
}
extern "C" {
static void freeArray(db_field_log *pfl) {
if (pfl->type == dbfl_type_ref) {
free(pfl->u.r.field);
}
}
}
static void testHead (const char *title, const char *typ = "") {
const char *line = "------------------------------------------------------------------------------";
testDiag("%s", line);
testDiag(title, typ);
testDiag("%s", line);
}
static void check(short dbr_type) {
dbChannel *pch;
db_field_log *pfl;
dbAddr valaddr;
dbAddr offaddr;
const char *offname = NULL, *valname = NULL, *typname = NULL;
epicsInt32 buf[26];
long off, req;
int i;
switch (dbr_type) {
case DBR_LONG:
offname = "i32.OFF";
valname = "i32.VAL";
typname = "long";
break;
case DBR_DOUBLE:
offname = "f64.OFF";
valname = "f64.VAL";
typname = "double";
break;
case DBR_STRING:
offname = "c40.OFF";
valname = "c40.VAL";
typname = "string";
break;
default:
testDiag("Invalid data type %d", dbr_type);
}
(void) dbNameToAddr(offname, &offaddr);
(void) dbNameToAddr(valname, &valaddr);
testHead("Ten %s elements", typname);
/* Fill the record's array field with data, 10..19 */
epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19};
(void) dbPutField(&valaddr, DBR_LONG, ar, 10);
/* Open a channel to it, make sure no filters present */
createAndOpen(valname, &pch);
testOk(pch->final_type == valaddr.field_type,
"final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
testOk(pch->final_no_elements == valaddr.no_elements,
"final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
/* TEST1 sets the record's OFF field, then requests 10 elements from the channel,
* passing in a transparent db_field_log and converting the data to LONG on the way in.
* It checks that it got back the expected data and the right number of elements.
*/
#define TEST1(Size, Offset, Text, Expected) \
testDiag("Reading from offset = %d (%s)", Offset, Text); \
off = Offset; req = 10; \
memset(buf, 0, sizeof(buf)); \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
for (i=0; i<Size; i++) \
testDiag("Element %d expected %d got %d", i, Expected[i], buf[i]); \
db_delete_field_log(pfl);
const epicsInt32 res_10_0[] = {10,11,12,13,14,15,16,17,18,19};
TEST1(10, 0, "no offset", res_10_0);
const epicsInt32 res_10_4[] = {14,15,16,17,18,19,10,11,12,13};
TEST1(10, 4, "wrapped", res_10_4);
/* Partial array */
testHead("Five %s elements", typname);
off = 0; /* Reset offset for writing the next buffer */
(void) dbPutField(&offaddr, DBR_LONG, &off, 1);
(void) dbPutField(&valaddr, DBR_LONG, &ar[5], 5);
createAndOpen(valname, &pch);
testOk(pch->final_type == valaddr.field_type,
"final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
testOk(pch->final_no_elements == valaddr.no_elements,
"final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
const epicsInt32 res_5_0[] = {15,16,17,18,19};
TEST1(5, 0, "no offset", res_5_0);
const epicsInt32 res_5_3[] = {18,19,15,16,17};
TEST1(5, 3, "wrapped", res_5_3);
/* TEST2 sets the record's OFF field, then requests 15 elements from the channel
* but passes in a db_field_log with alternate data, converting that data to LONG.
* It checks that it got back the expected data and the right number of elements.
*/
#define TEST2(Size, Offset, Text, Expected) \
testDiag("Reading from offset = %d (%s)", Offset, Text); \
off = Offset; req = 15; \
memset(buf, 0, sizeof(buf)); \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
pfl->type = dbfl_type_ref; \
pfl->field_type = DBF_CHAR; \
pfl->field_size = 1; \
pfl->no_elements = 26; \
pfl->u.r.dtor = freeArray; \
pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
for (i=0; i<Size; i++) \
testDiag("Element %d expected '%c' got '%c'", i, Expected[i], buf[i]); \
db_delete_field_log(pfl);
testHead("Fifteen letters from field-log instead of %s", typname);
const epicsInt32 res_15[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o'};
TEST2(15, 0, "no offset", res_15);
TEST2(15, 10, "ignored", res_15);
dbChannelDelete(pch);
}
static dbEventCtx evtctx;
extern "C" {
static void dbChArrTestCleanup(void* junk)
{
dbFreeBase(pdbbase);
registryFree();
pdbbase=0;
db_close_events(evtctx);
dbmfFreeChunks();
}
}
MAIN(dbChArrTest)
{
testPlan(102);
/* Prepare the IOC */
epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
if (dbReadDatabase(&pdbbase, "dbChArrTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL))
testAbort("Database description not loaded");
dbChArrTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChArrTest.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
epicsAtExit(&dbChArrTestCleanup,NULL);
/* Start the IOC */
iocInit();
evtctx = db_init_events();
check(DBR_LONG);
check(DBR_DOUBLE);
check(DBR_STRING);
return testDone();
}

View File

@@ -0,0 +1,15 @@
record(arr, "i32") {
field(DESC, "test array record")
field(NELM, "10")
field(FTVL, "LONG")
}
record(arr, "f64") {
field(DESC, "test array record")
field(NELM, "10")
field(FTVL, "DOUBLE")
}
record(arr, "c40") {
field(DESC, "test array record")
field(NELM, "10")
field(FTVL, "STRING")
}

View File

@@ -242,7 +242,7 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
testOk1(!!(pch = dbChannelCreate("x.{\"scalar\":null}")));
e = e_report;
dbChannelShow(pch, 1, 2);
dbChannelShow(pch, 2, 2);
e = e_close;
if (pch) dbChannelDelete(pch);

View File

@@ -165,8 +165,9 @@ typedef struct dbBase {
ELLLIST functionList;
ELLLIST variableList;
ELLLIST bptList;
ELLLIST filterList;
void *pathPvt;
ELLLIST filterList;
ELLLIST guiGroupList;
void *pathPvt;
struct dbPvd *ppvd;
struct gphPvt *pgpHash;
short ignoreMissingMenus;

View File

@@ -34,7 +34,6 @@
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "epicsExport.h"
#include "guigroup.h"
#include "link.h"
#include "special.h"
@@ -49,6 +48,9 @@ epicsExportAddress(int,dbRecordsOnceOnly);
epicsShareDef int dbBptNotMonotonic=0;
epicsExportAddress(int,dbBptNotMonotonic);
epicsShareDef int dbQuietMacroWarnings=0;
epicsExportAddress(int,dbQuietMacroWarnings);
/*private routines */
static void yyerrorAbort(char *str);
static void allocTemp(void *pvoid);
@@ -68,6 +70,7 @@ static void dbRecordtypeEmpty(void);
static void dbRecordtypeBody(void);
static void dbRecordtypeFieldHead(char *name,char *type);
static void dbRecordtypeFieldItem(char *name,char *value);
static short findOrAddGuiGroup(const char *name);
static void dbDevice(char *recordtype,char *linktype,
char *dsetname,char *choicestring);
@@ -230,6 +233,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
free((void *)macPairs);
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
}
macSuppressWarning(macHandle,dbQuietMacroWarnings);
}
pinputFile = dbCalloc(1,sizeof(inputFile));
if(filename) {
@@ -320,10 +324,9 @@ static int db_yyinput(char *buf, int max_size)
if(fgetsRtn) {
int exp = macExpandString(macHandle,mac_input_buffer,
my_buffer,MY_BUFFER_SIZE);
if(exp < 0) {
errPrintf(0,__FILE__, __LINE__,
"macExpandString failed for file %s",
pinputFileNow->filename);
if (exp < 0) {
fprintf(stderr, "Warning: '%s' line %d has undefined macros\n",
pinputFileNow->filename, pinputFileNow->line_num+1);
}
}
} else {
@@ -492,7 +495,23 @@ static void dbRecordtypeFieldHead(char *name,char *type)
yyerrorAbort("Illegal Field Type");
pdbFldDes->field_type = i;
}
static short findOrAddGuiGroup(const char *name)
{
dbGuiGroup *pdbGuiGroup;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
if (!pgphentry) {
pdbGuiGroup = dbCalloc(1,sizeof(dbGuiGroup));
pdbGuiGroup->name = epicsStrDup(name);
ellAdd(&pdbbase->guiGroupList, &pdbGuiGroup->node);
pdbGuiGroup->key = ellCount(&pdbbase->guiGroupList);
pgphentry = gphAdd(pdbbase->pgpHash, pdbGuiGroup->name, &pdbbase->guiGroupList);
pgphentry->userPvt = pdbGuiGroup;
}
return ((dbGuiGroup *)pgphentry->userPvt)->key;
}
static void dbRecordtypeFieldItem(char *name,char *value)
{
dbFldDes *pdbFldDes;
@@ -514,14 +533,7 @@ static void dbRecordtypeFieldItem(char *name,char *value)
return;
}
if(strcmp(name,"promptgroup")==0) {
int i;
for(i=0; i<GUI_NTYPES; i++) {
if(strcmp(value,pamapguiGroup[i].strvalue)==0) {
pdbFldDes->promptgroup = pamapguiGroup[i].value;
return;
}
}
yyerror("Illegal promptgroup. See guigroup.h for legal values");
pdbFldDes->promptgroup = findOrAddGuiGroup(value);
return;
}
if(strcmp(name,"prompt")==0) {

View File

@@ -31,7 +31,6 @@
#include "postfix.h"
#define DBFLDTYPES_GBLSOURCE
#define GUIGROUPS_GBLSOURCE
#define SPECIAL_GBLSOURCE
#define epicsExportSharedSymbols
@@ -41,7 +40,6 @@
#include "dbStaticPvt.h"
#include "devSup.h"
#include "drvSup.h"
#include "guigroup.h"
#include "link.h"
#include "special.h"
@@ -417,6 +415,7 @@ dbBase * dbAllocBase(void)
ellInit(&pdbbase->variableList);
ellInit(&pdbbase->bptList);
ellInit(&pdbbase->filterList);
ellInit(&pdbbase->guiGroupList);
gphInitPvt(&pdbbase->pgpHash,256);
dbPvdInitPvt(pdbbase);
return (pdbbase);
@@ -442,8 +441,10 @@ void dbFreeBase(dbBase *pdbbase)
drvSup *pdrvSupNext;
brkTable *pbrkTable;
brkTable *pbrkTableNext;
chFilterPlugin *pfilt;
chFilterPlugin *pfiltNext;
chFilterPlugin *pfilt;
chFilterPlugin *pfiltNext;
dbGuiGroup *pguiGroup;
dbGuiGroup *pguiGroupNext;
int i;
DBENTRY dbentry;
@@ -584,6 +585,15 @@ void dbFreeBase(dbBase *pdbbase)
free(pfilt);
pfilt = pfiltNext;
}
pguiGroup = (dbGuiGroup *)ellFirst(&pdbbase->guiGroupList);
while (pguiGroup) {
pguiGroupNext = (dbGuiGroup *)ellNext(&pguiGroup->node);
gphDelete(pdbbase->pgpHash, pguiGroup->name, &pdbbase->guiGroupList);
ellDelete(&pdbbase->guiGroupList, &pguiGroup->node);
free(pguiGroup->name);
free((void *)pguiGroup);
pguiGroup = pguiGroupNext;
}
gphFreeMem(pdbbase->pgpHash);
dbPvdFreeMem(pdbbase);
dbFreePath(pdbbase);
@@ -738,6 +748,31 @@ static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length)
return 0;
}
char *dbGetPromptGroupNameFromKey(DBBASE *pdbbase, const short key)
{
dbGuiGroup *pdbGuiGroup;
if (!pdbbase) return NULL;
for (pdbGuiGroup = (dbGuiGroup *)ellFirst(&pdbbase->guiGroupList);
pdbGuiGroup; pdbGuiGroup = (dbGuiGroup *)ellNext(&pdbGuiGroup->node)) {
if (pdbGuiGroup->key == key) return pdbGuiGroup->name;
}
return NULL;
}
short dbGetPromptGroupKeyFromName(DBBASE *pdbbase, const char *name)
{
GPHENTRY *pgphentry;
if (!pdbbase) return 0;
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
if (!pgphentry) {
return 0;
} else {
return ((dbGuiGroup*)pgphentry->userPvt)->key;
}
}
long dbWriteRecord(DBBASE *ppdbbase,const char *filename,
const char *precordTypename,int level)
@@ -937,16 +972,11 @@ long dbWriteRecordTypeFP(
fprintf(fp,"\t\tprompt(\"%s\")\n",pdbFldDes->prompt);
if(pdbFldDes->initial)
fprintf(fp,"\t\tinitial(\"%s\")\n",pdbFldDes->initial);
if(pdbFldDes->promptgroup) {
for(j=0; j<GUI_NTYPES; j++) {
if(pamapguiGroup[j].value == pdbFldDes->promptgroup) {
fprintf(fp,"\t\tpromptgroup(%s)\n",
pamapguiGroup[j].strvalue);
break;
}
}
}
if(pdbFldDes->special) {
if (pdbFldDes->promptgroup) {
fprintf(fp,"\t\tpromptgroup(\"%s\")\n",
dbGetPromptGroupNameFromKey(pdbbase, pdbFldDes->promptgroup));
}
if(pdbFldDes->special) {
if(pdbFldDes->special >= SPC_NTYPES) {
fprintf(fp,"\t\tspecial(%d)\n",pdbFldDes->special);
} else for(j=0; j<SPC_NTYPES; j++) {
@@ -2051,7 +2081,10 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
switch (pflddes->field_type) {
case DBF_STRING:
if(!pfield) return(S_dbLib_fieldNotFound);
strncpy((char *)pfield, pstring,pflddes->size);
if(strlen(pstring) >= (size_t)pflddes->size) return S_dbLib_strLen;
strncpy((char *)pfield, pstring, pflddes->size-1);
((char *)pfield)[pflddes->size-1] = 0;
if((pflddes->special == SPC_CALC) && !stringHasMacro) {
char rpcl[RPCL_LEN];
short err;
@@ -2062,7 +2095,6 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
calcErrorStr(err), pstring);
}
}
if((short)strlen(pstring) >= pflddes->size) status = S_dbLib_strLen;
break;
case DBF_CHAR:
@@ -3181,14 +3213,9 @@ void dbDumpField(
if(!pdbFldDes->promptgroup) {
printf("\t promptgroup: %d\n",pdbFldDes->promptgroup);
} else {
for(j=0; j<GUI_NTYPES; j++) {
if(pamapguiGroup[j].value == pdbFldDes->promptgroup) {
printf("\t promptgroup: %s\n",
pamapguiGroup[j].strvalue);
break;
}
}
}
printf("\t promptgroup: %s\n",
dbGetPromptGroupNameFromKey(pdbbase, pdbFldDes->promptgroup));
}
printf("\t interest: %hd\n", pdbFldDes->interest);
printf("\t as_level: %d\n",pdbFldDes->as_level);
printf("\t initial: %s\n",

View File

@@ -81,6 +81,10 @@ epicsShareFunc long dbReadDatabaseFP(DBBASE **ppdbbase,
FILE *fp, const char *path, const char *substitutions);
epicsShareFunc long dbPath(DBBASE *pdbbase, const char *path);
epicsShareFunc long dbAddPath(DBBASE *pdbbase, const char *path);
epicsShareFunc char * dbGetPromptGroupNameFromKey(DBBASE *pdbbase,
const short key);
epicsShareFunc short dbGetPromptGroupKeyFromName(DBBASE *pdbbase,
const char *name);
epicsShareFunc long dbWriteRecord(DBBASE *ppdbbase,
const char *filename, const char *precordTypename, int level);
epicsShareFunc long dbWriteRecordFP(DBBASE *ppdbbase,

View File

@@ -42,6 +42,13 @@ typedef struct dbPathNode {
char *directory;
} dbPathNode;
/* Element of the global gui group list */
typedef struct dbGuiGroup {
ELLNODE node;
short key;
char *name;
} dbGuiGroup;
/*The following are in dbPvdLib.c*/
/*directory*/
typedef struct{

View File

@@ -16,68 +16,11 @@
#ifndef __gui_group_h__
#define __gui_group_h__
#define GUI_COMMON 1
#define GUI_ALARMS 2
#define GUI_BITS1 3
#define GUI_BITS2 4
#define GUI_CALC 5
#define GUI_CLOCK 6
#define GUI_COMPRESS 7
#define GUI_CONVERT 8
#define GUI_DISPLAY 9
#define GUI_HIST 10
#define GUI_INPUTS 11
#define GUI_LINKS 12
#define GUI_MBB 13
#define GUI_MOTOR 14
#define GUI_OUTPUT 15
#define GUI_PID 16
#define GUI_PULSE 17
#define GUI_SELECT 18
#define GUI_SEQ1 19
#define GUI_SEQ2 20
#define GUI_SEQ3 21
#define GUI_SUB 22
#define GUI_TIMER 23
#define GUI_WAVE 24
#define GUI_SCAN 25
#define GUI_NTYPES 25
typedef struct mapguiGroup{
char *strvalue;
int value;
}mapguiGroup;
#ifndef GUIGROUPS_GBLSOURCE
extern mapguiGroup pamapguiGroup[];
#else
mapguiGroup pamapguiGroup[GUI_NTYPES] = {
{"GUI_COMMON",GUI_COMMON},
{"GUI_ALARMS",GUI_ALARMS},
{"GUI_BITS1",GUI_BITS1},
{"GUI_BITS2",GUI_BITS2},
{"GUI_CALC",GUI_CALC},
{"GUI_CLOCK",GUI_CLOCK},
{"GUI_COMPRESS",GUI_COMPRESS},
{"GUI_CONVERT",GUI_CONVERT},
{"GUI_DISPLAY",GUI_DISPLAY},
{"GUI_HIST",GUI_HIST},
{"GUI_INPUTS",GUI_INPUTS},
{"GUI_LINKS",GUI_LINKS},
{"GUI_MBB",GUI_MBB},
{"GUI_MOTOR",GUI_MOTOR},
{"GUI_OUTPUT",GUI_OUTPUT},
{"GUI_PID",GUI_PID},
{"GUI_PULSE",GUI_PULSE},
{"GUI_SELECT",GUI_SELECT},
{"GUI_SEQ1",GUI_SEQ1},
{"GUI_SEQ2",GUI_SEQ2},
{"GUI_SEQ3",GUI_SEQ3},
{"GUI_SUB",GUI_SUB},
{"GUI_TIMER",GUI_TIMER},
{"GUI_WAVE",GUI_WAVE},
{"GUI_SCAN",GUI_SCAN}
};
#endif /*GUIGROUPS_GBLSOURCE*/
#error As of Base 3.15.4, the promptgroup implementation has changed. \
This header file (guigroup.h) is invalid and will be removed shortly. \
Instead, you should include dbStaticLib.h, parse the DBD, \
and use dbGetPromptGroupNameFromKey() and dbGetPromptGroupKeyFromName() \
that have been added to dbStaticLib. \
More details in the 3.15.4 release notes and the AppDev Guide.
#endif /*__gui_group_h__*/

View File

@@ -14,8 +14,12 @@ variable(asCaDebug,int)
# Static database access variables
variable(dbRecordsOnceOnly,int)
variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int)
# dbLoadTemplate settings
variable(dbTemplateMaxVars,int)
# Default number of parallel callback threads
variable(callbackParallelThreadsDefault,int)
# Real-time operation
variable(dbThreadRealtimeLock,int)

View File

@@ -36,7 +36,7 @@
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "epicsExport.h" /* defines epicsExportSharedSymbols */
#include "alarm.h"
#include "asDbLib.h"
#include "callback.h"
@@ -86,7 +86,9 @@ static void initDatabase(void);
static void initialProcess(void);
static void exitDatabase(void *dummy);
int dbThreadRealtimeLock = 1;
epicsExportAddress(int, dbThreadRealtimeLock);
/*
* Initialize EPICS on the IOC.
*/
@@ -186,6 +188,10 @@ int iocBuild(void)
rsrv_init();
status = iocBuild_3();
if (dbThreadRealtimeLock)
epicsThreadRealtimeLock();
if (!status) iocBuildMode = buildRSRV;
return status;
}

View File

@@ -7,6 +7,8 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "envDefs.h"
#include "epicsVersion.h"
#include "iocsh.h"
#include "libComRegister.h"
@@ -21,10 +23,29 @@
#include "registryIocRegister.h"
#include "rsrvIocRegister.h"
#define quote(v) #v
#define str(v) quote(v)
void iocshRegisterCommon(void)
{
const char *targetArch = envGetConfigParamPtr(&EPICS_BUILD_TARGET_ARCH);
iocshPpdbbase = &pdbbase;
/* This uses a config param so the user can override it */
if (targetArch) {
epicsEnvSet("ARCH", targetArch);
}
/* Base build version variables */
epicsEnvSet("EPICS_VERSION_MAJOR", str(EPICS_VERSION));
epicsEnvSet("EPICS_VERSION_MIDDLE", str(EPICS_REVISION));
epicsEnvSet("EPICS_VERSION_MINOR", str(EPICS_MODIFICATION));
epicsEnvSet("EPICS_VERSION_PATCH", str(EPICS_PATCH_LEVEL));
epicsEnvSet("EPICS_VERSION_SNAPSHOT", EPICS_DEV_SNAPSHOT);
epicsEnvSet("EPICS_VERSION_SITE", EPICS_SITE_VERSION);
epicsEnvSet("EPICS_VERSION_SHORT", EPICS_VERSION_SHORT);
epicsEnvSet("EPICS_VERSION_FULL", EPICS_VERSION_FULL);
dbStaticIocRegister();
registryIocRegister();
dbIocRegister();

View File

@@ -1112,7 +1112,7 @@ unsigned cid
* casAccessRightsCB()
*
* If access right state changes then inform the client.
*
* asLock is held
*/
static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
{
@@ -1126,7 +1126,7 @@ static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
pclient = pciu->client;
assert(pclient);
if(pclient == prsrv_cast_client){
if(pclient->proto==IPPROTO_UDP){
return;
}
@@ -1193,7 +1193,7 @@ static void access_rights_reply ( struct channel_in_use * pciu )
int v41;
int status;
assert ( pciu->client != prsrv_cast_client );
assert ( pciu->client->proto!=IPPROTO_UDP );
/*
* noop if this is an old client
@@ -1321,7 +1321,7 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
}
}
else {
epicsMutexMustLock(prsrv_cast_client->chanListLock);
epicsMutexMustLock(client->chanListLock);
/*
* clients which dont claim their
* channel in use block prior to
@@ -1331,7 +1331,7 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
if(!pciu){
errlogPrintf("CAS: client timeout disconnect id=%d\n",
mp->m_cid);
epicsMutexUnlock(prsrv_cast_client->chanListLock);
epicsMutexUnlock(client->chanListLock);
SEND_LOCK(client);
send_err(
mp,
@@ -1342,24 +1342,6 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
return RSRV_ERROR;
}
/*
* duplicate claim message are unacceptable
* (so we disconnect the client)
*/
if (pciu->client!=prsrv_cast_client) {
errlogPrintf("CAS: duplicate claim disconnect id=%d\n",
mp->m_cid);
epicsMutexUnlock(prsrv_cast_client->chanListLock);
SEND_LOCK(client);
send_err(
mp,
ECA_INTERNAL,
client,
"duplicate claim in old connect protocol");
SEND_UNLOCK(client);
return RSRV_ERROR;
}
/*
* remove channel in use block from
* the UDP client where it could time
@@ -1367,9 +1349,9 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
* who is claiming it
*/
ellDelete(
&prsrv_cast_client->chanList,
&client->chanList,
&pciu->node);
epicsMutexUnlock(prsrv_cast_client->chanListLock);
epicsMutexUnlock(client->chanListLock);
epicsMutexMustLock(client->chanListLock);
pciu->state = rsrvCS_pendConnectResp;
@@ -1586,6 +1568,9 @@ static void sendAllUpdateAS ( struct client *client )
else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ) {
access_rights_reply ( pciu );
}
else if ( pciu->state == rsrvCS_shutdown ) {
/* no-op */
}
else {
errlogPrintf (
"%s at %d: corrupt channel state detected durring AR update\n",
@@ -2065,10 +2050,15 @@ static int clear_channel_reply ( caHdrLargeArray *mp,
if ( pciu->state == rsrvCS_inService ||
pciu->state == rsrvCS_pendConnectResp ) {
ellDelete ( &client->chanList, &pciu->node );
pciu->state = rsrvCS_shutdown;
}
else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ||
pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) {
ellDelete ( &client->chanPendingUpdateARList, &pciu->node );
pciu->state = rsrvCS_shutdown;
}
else if ( pciu->state == rsrvCS_shutdown ) {
/* no-op */
}
else {
epicsMutexUnlock( client->chanListLock );
@@ -2515,12 +2505,7 @@ int camessage ( struct client *client )
unsigned bytes_left;
int status = RSRV_ERROR;
if ( ! pCaBucket ) {
pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE);
if(!pCaBucket){
return RSRV_ERROR;
}
}
assert(pCaBucket);
/* drain remnents of large messages that will not fit */
if ( client->recvBytesToDrain ) {
@@ -2623,7 +2608,7 @@ int camessage ( struct client *client )
if ( CASDEBUG > 2 )
log_header (NULL, client, &msg, pBody, nmsg);
if ( client == prsrv_cast_client ) {
if ( client->proto==IPPROTO_UDP ) {
if ( msg.m_cmmd < NELEMENTS ( udpJumpTable ) ) {
status = ( *udpJumpTable[msg.m_cmmd] )( &msg, pBody, client );
if (status!=RSRV_OK) {

View File

@@ -222,7 +222,7 @@ void cas_send_dg_msg ( struct client * pclient )
/*
* add placeholder for the first version message should it be needed
*/
rsrv_version_reply ( prsrv_cast_client );
rsrv_version_reply ( pclient );
SEND_UNLOCK(pclient);

File diff suppressed because it is too large Load Diff

View File

@@ -54,7 +54,7 @@
/*
* clean_addrq
*/
static void clean_addrq(void)
static void clean_addrq(struct client *client)
{
struct channel_in_use * pciu;
struct channel_in_use * pnextciu;
@@ -67,9 +67,9 @@ static void clean_addrq(void)
epicsTimeGetCurrent ( &current );
epicsMutexMustLock ( prsrv_cast_client->chanListLock );
epicsMutexMustLock ( client->chanListLock );
pnextciu = (struct channel_in_use *)
prsrv_cast_client->chanList.node.next;
client->chanList.node.next;
while( (pciu = pnextciu) ) {
pnextciu = (struct channel_in_use *)pciu->node.next;
@@ -77,7 +77,7 @@ static void clean_addrq(void)
delay = epicsTimeDiffInSeconds(&current,&pciu->time_at_creation);
if (delay > timeout) {
ellDelete(&prsrv_cast_client->chanList, &pciu->node);
ellDelete(&client->chanList, &pciu->node);
LOCK_CLIENTQ;
s = bucketRemoveItemUnsignedId (
pCaBucket,
@@ -96,7 +96,7 @@ static void clean_addrq(void)
if(delay>maxdelay) maxdelay = delay;
}
}
epicsMutexUnlock ( prsrv_cast_client->chanListLock );
epicsMutexUnlock ( client->chanListLock );
# ifdef DEBUG
if(ndelete){
@@ -115,70 +115,19 @@ static void clean_addrq(void)
*/
void cast_server(void *pParm)
{
osiSockAddrNode *paddrNode;
struct sockaddr_in sin;
rsrv_iface_config *conf = pParm;
int status;
int count=0;
int mysocket=0;
struct sockaddr_in new_recv_addr;
osiSocklen_t recv_addr_size;
osiSockIoctl_t nchars;
SOCKET recv_sock, reply_sock;
struct client *client;
recv_addr_size = sizeof(new_recv_addr);
if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) {
epicsSocketDestroy ( IOC_cast_sock );
}
/*
* Open the socket.
* Use ARPA Internet address format and datagram socket.
*/
if ( ( IOC_cast_sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0) ) == INVALID_SOCKET ) {
epicsPrintf ("CAS: cast socket creation error\n");
epicsThreadSuspendSelf ();
}
/*
* some concern that vxWorks will run out of mBuf's
* if this change is made
*
* joh 11-10-98
*/
#if 0
{
/*
*
* this allows for faster connects by queuing
* additional incomming UDP search frames
*
* this allocates a 32k buffer
* (uses a power of two)
*/
int size = 1u<<15u;
status = setsockopt (IOC_cast_sock, SOL_SOCKET,
SO_RCVBUF, (char *)&size, sizeof(size));
if (status<0) {
epicsPrintf ("CAS: unable to set cast socket size\n");
}
}
#endif
epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock );
paddrNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList );
memcpy(&sin, &paddrNode->addr.ia, sizeof (sin));
/* get server's Internet address */
if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
epicsPrintf ("CAS: UDP server port bind error was \"%s\"\n", sockErrBuf );
epicsSocketDestroy ( IOC_cast_sock );
epicsThreadSuspendSelf ();
}
reply_sock = conf->udp;
/*
* setup new client structure but reuse old structure if
@@ -186,27 +135,39 @@ void cast_server(void *pParm)
*
*/
while ( TRUE ) {
prsrv_cast_client = create_client ( IOC_cast_sock, IPPROTO_UDP );
if ( prsrv_cast_client ) {
client = create_client ( reply_sock, IPPROTO_UDP );
if ( client ) {
break;
}
epicsThreadSleep(300.0);
}
if (conf->startbcast) {
recv_sock = conf->udpbcast;
conf->bclient = client;
}
else {
recv_sock = conf->udp;
conf->client = client;
}
client->udpRecv = recv_sock;
casAttachThreadToClient ( prsrv_cast_client );
casAttachThreadToClient ( client );
/*
* add placeholder for the first version message should it be needed
*/
rsrv_version_reply ( prsrv_cast_client );
rsrv_version_reply ( client );
/* these pointers become invalid after signaling casudp_startStopEvent */
conf = NULL;
epicsEventSignal(casudp_startStopEvent);
while (TRUE) {
status = recvfrom (
IOC_cast_sock,
prsrv_cast_client->recv.buf,
prsrv_cast_client->recv.maxstk,
recv_sock,
client->recv.buf,
client->recv.maxstk,
0,
(struct sockaddr *)&new_recv_addr,
&recv_addr_size);
@@ -219,71 +180,90 @@ void cast_server(void *pParm)
sockErrBuf);
epicsThreadSleep(1.0);
}
}
else if (casudp_ctl == ctlRun) {
prsrv_cast_client->recv.cnt = (unsigned) status;
prsrv_cast_client->recv.stk = 0ul;
epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv);
prsrv_cast_client->minor_version_number = 0;
prsrv_cast_client->seqNoOfReq = 0;
} else {
size_t idx;
for(idx=0; casIgnoreAddrs[idx]; idx++)
{
if(new_recv_addr.sin_addr.s_addr==casIgnoreAddrs[idx]) {
status = -1; /* ignore */
break;
}
}
}
if (status >= 0 && casudp_ctl == ctlRun) {
client->recv.cnt = (unsigned) status;
client->recv.stk = 0ul;
epicsTimeGetCurrent(&client->time_at_last_recv);
client->minor_version_number = 0;
client->seqNoOfReq = 0;
/*
* If we are talking to a new client flush to the old one
* in case we are holding UDP messages waiting to
* see if the next message is for this same client.
*/
if (prsrv_cast_client->send.stk>sizeof(caHdr)) {
status = memcmp(&prsrv_cast_client->addr,
if (client->send.stk>sizeof(caHdr)) {
status = memcmp(&client->addr,
&new_recv_addr, recv_addr_size);
if(status){
/*
* if the address is different
*/
cas_send_dg_msg(prsrv_cast_client);
prsrv_cast_client->addr = new_recv_addr;
cas_send_dg_msg(client);
client->addr = new_recv_addr;
}
}
else {
prsrv_cast_client->addr = new_recv_addr;
client->addr = new_recv_addr;
}
if (CASDEBUG>1) {
char buf[40];
ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
errlogPrintf ("CAS: cast server msg of %d bytes from addr %s\n",
prsrv_cast_client->recv.cnt, buf);
client->recv.cnt, buf);
}
if (CASDEBUG>2)
count = ellCount (&prsrv_cast_client->chanList);
count = ellCount (&client->chanList);
status = camessage ( prsrv_cast_client );
status = camessage ( client );
if(status == RSRV_OK){
if(prsrv_cast_client->recv.cnt !=
prsrv_cast_client->recv.stk){
if(client->recv.cnt !=
client->recv.stk){
char buf[40];
ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n",
prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf);
client->recv.cnt - client->recv.stk, buf);
epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
&client->time_at_last_recv);
epicsPrintf ("CAS: message received at %s\n", buf);
}
}
else {
char buf[40];
ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf);
epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
&client->time_at_last_recv);
epicsPrintf ("CAS: message received at %s\n", buf);
}
if (CASDEBUG>2) {
if ( ellCount (&prsrv_cast_client->chanList) ) {
if ( ellCount (&client->chanList) ) {
errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n",
ellCount(&prsrv_cast_client->chanList)-count,
ellCount(&prsrv_cast_client->chanList));
ellCount(&client->chanList)-count,
ellCount(&client->chanList));
}
}
}
@@ -292,15 +272,22 @@ void cast_server(void *pParm)
* allow messages to batch up if more are comming
*/
nchars = 0; /* supress purify warning */
status = socket_ioctl(IOC_cast_sock, FIONREAD, &nchars);
status = socket_ioctl(recv_sock, FIONREAD, &nchars);
if (status<0) {
errlogPrintf ("CA cast server: Unable to fetch N characters pending\n");
cas_send_dg_msg (prsrv_cast_client);
clean_addrq ();
cas_send_dg_msg (client);
clean_addrq (client);
}
else if (nchars == 0) {
cas_send_dg_msg (prsrv_cast_client);
clean_addrq ();
cas_send_dg_msg (client);
clean_addrq (client);
}
}
/* ATM never reached, just a placeholder */
if(!mysocket)
client->sock = INVALID_SOCKET; /* only one cast_server should destroy the reply socket */
destroy_client(client);
epicsSocketDestroy(recv_sock);
}

View File

@@ -35,46 +35,19 @@
#define epicsExportSharedSymbols
#include "server.h"
/*
* forcePort ()
*/
static void forcePort (ELLLIST *pList, unsigned short port)
{
osiSockAddrNode *pNode;
pNode = (osiSockAddrNode *) ellFirst ( pList );
while ( pNode ) {
if ( pNode->addr.sa.sa_family == AF_INET ) {
pNode->addr.ia.sin_port = htons ( port );
}
pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
}
}
/*
* RSRV_ONLINE_NOTIFY_TASK
*/
void rsrv_online_notify_task(void *pParm)
{
unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
osiSockAddrNode *pNode;
double delay;
double maxdelay;
long longStatus;
double maxPeriod;
caHdr msg;
int status;
SOCKET sock;
int intTrue = TRUE;
unsigned short port;
ca_uint32_t beaconCounter = 0;
char * pStr;
int autoBeaconAddr;
ELLLIST autoAddrList;
char buf[16];
unsigned priorityOfUDP;
epicsThreadBooleanStatus tbs;
epicsThreadId tid;
taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL);
@@ -94,189 +67,34 @@ void rsrv_online_notify_task(void *pParm)
delay = 0.02; /* initial beacon period in sec */
maxdelay = maxPeriod;
/*
* Open the socket.
* Use ARPA Internet address format and datagram socket.
* Format described in <sys/socket.h>.
*/
if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
errlogPrintf ("CAS: online socket creation error\n");
epicsThreadSuspendSelf ();
}
status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST,
(char *)&intTrue, sizeof(intTrue));
if (status<0) {
errlogPrintf ("CAS: online socket set up error\n");
epicsThreadSuspendSelf ();
}
{
/*
* this connect is to supress a warning message on Linux
* when we shutdown the read side of the socket. If it
* fails (and it will on old ip kernels) we just ignore
* the failure.
*/
osiSockAddr sockAddr;
sockAddr.ia.sin_family = AF_UNSPEC;
sockAddr.ia.sin_port = htons ( 0 );
sockAddr.ia.sin_addr.s_addr = htonl (0);
connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) );
shutdown ( sock, SHUT_RD );
}
memset((char *)&msg, 0, sizeof msg);
msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP);
msg.m_count = htons (ca_server_port);
msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION);
ellInit ( & beaconAddrList );
ellInit ( & autoAddrList );
pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf);
if ( ! pStr ) {
pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf);
}
if (pStr) {
if (strstr(pStr,"no")||strstr(pStr,"NO")) {
autoBeaconAddr = FALSE;
}
else if (strstr(pStr,"yes")||strstr(pStr,"YES")) {
autoBeaconAddr = TRUE;
}
else {
fprintf(stderr,
"CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr);
autoBeaconAddr = TRUE;
}
}
else {
autoBeaconAddr = TRUE;
}
/*
* load user and auto configured
* broadcast address list
*/
if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) {
port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT,
(unsigned short) CA_REPEATER_PORT );
}
else {
port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT,
(unsigned short) CA_REPEATER_PORT );
}
/*
* discover beacon addresses associated with this interface
*/
if ( autoBeaconAddr ) {
osiSockAddr addr;
ELLLIST tmpList;
ellInit ( &tmpList );
addr.ia.sin_family = AF_UNSPEC;
osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr);
forcePort ( &tmpList, port );
removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 );
}
/*
* by default use EPICS_CA_ADDR_LIST for the
* beacon address list
*/
{
const ENV_PARAM *pParam;
if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) ||
envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) {
pParam = &EPICS_CAS_BEACON_ADDR_LIST;
}
else {
pParam = &EPICS_CA_ADDR_LIST;
}
/*
* add in the configured addresses
*/
addAddrToChannelAccessAddressList (
&autoAddrList, pParam, port, pParam == &EPICS_CA_ADDR_LIST );
}
removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 );
if ( ellCount ( &beaconAddrList ) == 0 ) {
errlogPrintf ("The CA server's beacon address list was empty after initialization?\n");
}
# ifdef DEBUG
printChannelAccessAddressList (&beaconAddrList);
# endif
tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP );
if ( tbs != epicsThreadBooleanStatusSuccess ) {
priorityOfUDP = priorityOfSelf;
}
casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
casudp_ctl = ctlPause;
tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP,
epicsThreadGetStackSize (epicsThreadStackMedium),
cast_server, 0 );
if ( tid == 0 ) {
epicsPrintf ( "CAS: unable to start UDP daemon thread\n" );
}
epicsEventMustWait(casudp_startStopEvent);
epicsEventSignal(beacon_startStopEvent);
while (TRUE) {
pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList);
while (pNode) {
char buf[64];
ELLNODE *cur;
status = connect (sock, &pNode->addr.sa,
sizeof(pNode->addr.sa));
if (status<0) {
/* send beacon to each interface */
for(cur=ellFirst(&beaconAddrList); cur; cur=ellNext(cur))
{
osiSockAddrNode *pAddr = CONTAINER(cur, osiSockAddrNode, node);
status = sendto (beaconSocket, (char *)&msg, sizeof(msg), 0,
&pAddr->addr.sa, sizeof(pAddr->addr));
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n",
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf));
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
__FILE__, buf, sockErrBuf);
}
else {
struct sockaddr_in if_addr;
osiSocklen_t size = sizeof (if_addr);
status = getsockname (sock, (struct sockaddr *) &if_addr, &size);
if (status<0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n",
__FILE__, sockErrBuf);
}
else if (if_addr.sin_family==AF_INET) {
msg.m_available = if_addr.sin_addr.s_addr;
msg.m_cid = htonl ( beaconCounter );
status = send (sock, (char *)&msg, sizeof(msg), 0);
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
__FILE__, buf, sockErrBuf);
}
else {
assert (status == sizeof(msg));
}
}
assert (status == sizeof(msg));
}
pNode = (osiSockAddrNode *) pNode->node.next;
}
epicsThreadSleep(delay);
@@ -287,7 +105,7 @@ void rsrv_online_notify_task(void *pParm)
}
}
beaconCounter++; /* expected to overflow */
msg.m_cid = htonl ( beaconCounter++ ); /* expected to overflow */
while (beacon_ctl == ctlPause) {
epicsThreadSleep(0.1);

View File

@@ -32,6 +32,7 @@
#include "ellLib.h"
#include "epicsTime.h"
#include "epicsAssert.h"
#include "osiSock.h"
#ifdef rsrvRestore_epicsExportSharedSymbols
#define epicsExportSharedSymbols
@@ -88,7 +89,7 @@ typedef struct client {
char *pUserName;
char *pHostName;
epicsEventId blockSem; /* used whenever the client blocks */
SOCKET sock;
SOCKET sock, udpRecv;
int proto;
epicsThreadId tid;
unsigned minor_version_number;
@@ -98,12 +99,25 @@ typedef struct client {
char disconnect; /* disconnect detected */
} client;
/* Channel state shows which struct client list a
* channel_in_us::node is in.
*
* client::chanList
* rsrvCS_pendConnectResp, rsrvCS_inService
* client::chanPendingUpdateARList
* rsrvCS_pendConnectRespUpdatePendAR, rsrvCS_inServiceUpdatePendAR
* Not in any list
* rsrvCS_shutdown
*
* rsrvCS_invalid is not used
*/
enum rsrvChanState {
rsrvCS_invalid,
rsrvCS_pendConnectResp,
rsrvCS_inService,
rsrvCS_pendConnectRespUpdatePendAR,
rsrvCS_inServiceUpdatePendAR
rsrvCS_inServiceUpdatePendAR,
rsrvCS_shutdown
};
/*
@@ -137,6 +151,16 @@ struct event_ext {
char modified; /* mod & ev flw ctrl enbl */
};
typedef struct {
ELLNODE node;
osiSockAddr tcpAddr, /* TCP listener endpoint */
udpAddr, /* UDP name unicast receiver endpoint */
udpbcastAddr; /* UDP name broadcast receiver endpoint */
SOCKET tcp, udp, udpbcast;
struct client *client, *bclient;
unsigned int startbcast:1;
} rsrv_iface_config;
enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
@@ -160,15 +184,16 @@ enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
#endif
GLBLTYPE int CASDEBUG;
GLBLTYPE SOCKET IOC_sock;
GLBLTYPE SOCKET IOC_cast_sock;
GLBLTYPE unsigned short ca_server_port;
GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */
GLBLTYPE unsigned short ca_server_port, ca_udp_port, ca_beacon_port;
GLBLTYPE ELLLIST clientQ; /* (TCP clients) locked by clientQlock */
GLBLTYPE ELLLIST clientQudp; /* locked by clientQlock */
GLBLTYPE ELLLIST servers; /* rsrv_iface_config::node, read-only after rsrv_init() */
GLBLTYPE ELLLIST beaconAddrList;
GLBLTYPE ELLLIST casIntfAddrList;
GLBLTYPE SOCKET beaconSocket;
GLBLTYPE ELLLIST casIntfAddrList, casMCastAddrList;
GLBLTYPE epicsUInt32 *casIgnoreAddrs;
GLBLTYPE epicsMutexId clientQlock;
GLBLTYPE struct client *prsrv_cast_client;
GLBLTYPE BUCKET *pCaBucket;
GLBLTYPE BUCKET *pCaBucket; /* locked by clientQlock */
GLBLTYPE void *rsrvClientFreeList;
GLBLTYPE void *rsrvChanFreeList;
GLBLTYPE void *rsrvEventFreeList;
@@ -176,7 +201,7 @@ GLBLTYPE void *rsrvSmallBufFreeListTCP;
GLBLTYPE void *rsrvLargeBufFreeListTCP;
GLBLTYPE unsigned rsrvSizeofLargeBufTCP;
GLBLTYPE void *rsrvPutNotifyFreeList;
GLBLTYPE unsigned rsrvChannelCount;
GLBLTYPE unsigned rsrvChannelCount; /* locked by clientQlock */
GLBLTYPE epicsEventId casudp_startStopEvent;
GLBLTYPE epicsEventId beacon_startStopEvent;
@@ -185,6 +210,7 @@ GLBLTYPE volatile enum ctl casudp_ctl;
GLBLTYPE volatile enum ctl beacon_ctl;
GLBLTYPE volatile enum ctl castcp_ctl;
GLBLTYPE unsigned int threadPrios[5];
#define CAS_HASH_TABLE_SIZE 4096

View File

@@ -45,6 +45,11 @@ Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
Com_RCS = Com.rc
ifeq ($(T_A),$(EPICS_HOST_ARCH))
# Antelope & flex are needed to finish libCom
DELAY_INSTALL_LIBS = YES
endif
include $(TOP)/configure/RULES
include $(LIBCOM)/as/RULES

View File

@@ -529,6 +529,12 @@ Init (rtems_task_argument ignored)
putenv ("TERM=xterm");
putenv ("IOCSH_HISTSIZE=20");
/*
* Display some OS information
*/
printf("\n***** RTEMS Version: %s *****\n",
rtems_get_version_string());
/*
* Start network
*/

View File

@@ -486,7 +486,7 @@ epicsShareFunc int epicsShareAPI bucketShow(BUCKET *pb)
unsigned count;
unsigned maxEntries;
printf( "Bucket entries in use = %d bytes in use = %ld\n",
printf( " Bucket entries in use = %d bytes in use = %ld\n",
pb->nInUse,
(long) (sizeof(*pb)+(pb->hashIdMask+1)*
sizeof(ITEM *)+pb->nInUse*sizeof(ITEM)));
@@ -511,7 +511,7 @@ epicsShareFunc int epicsShareAPI bucketShow(BUCKET *pb)
mean = X/nElem;
stdDev = sqrt(XX/nElem - mean*mean);
printf( "Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
printf( " Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
mean,
stdDev,
maxEntries);

View File

@@ -33,6 +33,10 @@ static int cond_search(const char **ppinst, int match);
#define PI 3.14159265358979323
#endif
/* Turn off global optimization for 64-bit MSVC builds */
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
# pragma optimize("g", off)
#endif
/* calcPerform
*
@@ -45,6 +49,7 @@ epicsShareFunc long
double *ptop; /* stack pointer */
double top; /* value from top of stack */
epicsInt32 itop; /* integer from top of stack */
epicsUInt32 utop; /* unsigned integer from top of stack */
int op;
int nargs;
@@ -150,7 +155,7 @@ epicsShareFunc long
break;
case ABS_VAL:
if (*ptop < 0.0) *ptop = - *ptop;
*ptop = fabs(*ptop);
break;
case EXP:
@@ -262,7 +267,7 @@ epicsShareFunc long
case NINT:
top = *ptop;
*ptop = (double)(epicsInt32)(top >= 0 ? top + 0.5 : top - 0.5);
*ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5);
break;
case RANDOM:
@@ -283,34 +288,45 @@ epicsShareFunc long
*ptop = ! *ptop;
break;
/* For bitwise operations on values with bit 31 set, double values
* must first be cast to unsigned to correctly set that bit; the
* double value must be negative in that case. The result must be
* cast to a signed integer before converting to the double result.
*/
case BIT_OR:
itop = (epicsInt32) *ptop--;
*ptop = (epicsInt32) *ptop | itop;
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
break;
case BIT_AND:
itop = (epicsInt32) *ptop--;
*ptop = (epicsInt32) *ptop & itop;
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
break;
case BIT_EXCL_OR:
itop = (epicsInt32) *ptop--;
*ptop = (epicsInt32) *ptop ^ itop;
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
break;
case BIT_NOT:
itop = (epicsInt32) *ptop;
*ptop = ~itop;
utop = *ptop;
*ptop = (epicsInt32) ~utop;
break;
/* The shift operators use signed integers, so a right-shift will
* extend the sign bit into the left-hand end of the value. The
* double-casting through unsigned here is important, see above.
*/
case RIGHT_SHIFT:
itop = (epicsInt32) *ptop--;
*ptop = (epicsInt32) *ptop >> itop;
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
break;
case LEFT_SHIFT:
itop = (epicsInt32) *ptop--;
*ptop = (epicsInt32) *ptop << itop;
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
break;
case NOT_EQ:
@@ -367,6 +383,9 @@ epicsShareFunc long
*presult = *ptop;
return 0;
}
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
# pragma optimize("", on)
#endif
epicsShareFunc long

View File

@@ -251,7 +251,7 @@ epicsShareFunc long
goto bad;
}
psrc = pnext;
lit_i = (int) lit_d;
lit_i = (epicsInt32) lit_d;
if (lit_d != (double) lit_i) {
*pout++ = pel->code;
memcpy(pout, &lit_d, sizeof(double));
@@ -272,8 +272,8 @@ epicsShareFunc long
}
psrc = pnext;
*pout++ = LITERAL_INT;
memcpy(pout, &lit_ui, sizeof(epicsInt32));
pout += sizeof(epicsInt32);
memcpy(pout, &lit_ui, sizeof(epicsUInt32));
pout += sizeof(epicsUInt32);
}
operand_needed = FALSE;

View File

@@ -8,5 +8,7 @@
# This is a Makefile fragment, see src/libCom/Makefile.
envData.c: $(LIBCOM)/env/envDefs.h $(LIBCOM)/env/bldEnvData.pl \
$(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV
$(PERL) $(LIBCOM)/env/bldEnvData.pl $(INSTALL_QUIETLY) $(CONFIG)
$(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV \
$(wildcard $(CONFIG)/os/CONFIG_SITE_ENV.$(T_A))
$(PERL) $(LIBCOM)/env/bldEnvData.pl $(INSTALL_QUIETLY) -t $(T_A) \
-c $(CMPLR_CLASS) -s $(OS_CLASS) $(CONFIG)

View File

@@ -26,13 +26,13 @@ use Text::Wrap;
my $tool = basename($0);
our ($opt_h, $opt_q);
our ($opt_h, $opt_q, $opt_t, $opt_s, $opt_c);
our $opt_o = 'envData.c';
$Getopt::Std::OUTPUT_HELP_VERSION = 1;
$Text::Wrap::columns = 75;
&HELP_MESSAGE unless getopts('ho:q') && @ARGV == 1;
&HELP_MESSAGE unless getopts('ho:qt:s:c:') && @ARGV == 1;
&HELP_MESSAGE if $opt_h;
my $config = AbsPath(shift);
@@ -52,16 +52,31 @@ while (<SRC>) {
}
close SRC;
# Read the values from the CONFIG_ENV and CONFIG_SITE_ENV files
# A list of configure/CONFIG_* files to read
#
my $config_env = "$config/CONFIG_ENV";
my $config_site_env = "$config/CONFIG_SITE_ENV";
my @configs = ("$config/CONFIG_ENV", "$config/CONFIG_SITE_ENV");
my %values;
readReleaseFiles($config_env, \%values);
readReleaseFiles($config_site_env, \%values);
if ($opt_t) {
my $config_arch_env = "$config/os/CONFIG_SITE_ENV.$opt_t";
push @configs, $config_arch_env
if -f $config_arch_env;
}
# Warn about any vars with no value
my @sources = ($env_defs, @configs);
# Get values from the config files
#
my (%values, @dummy);
readRelease($_, \%values, \@dummy) foreach @configs;
expandRelease(\%values);
# Get values from the command-line
#
$values{EPICS_BUILD_COMPILER_CLASS} = $opt_c if $opt_c;
$values{EPICS_BUILD_OS_CLASS} = $opt_s if $opt_s;
$values{EPICS_BUILD_TARGET_ARCH} = $opt_t if $opt_t;
# Warn about vars with no configured value
#
my @undefs = grep {!exists $values{$_}} @vars;
warn "$tool: No value given for $_\n" foreach @undefs;
@@ -73,13 +88,13 @@ print "Generating $opt_o\n" unless $opt_q;
open OUT, '>', $opt_o
or die "$tool: Cannot create $opt_o: $!\n";
my $sources = join "\n", map {" * $_"} @sources;
print OUT << "END";
/* Generated file $opt_o
*
* Created from
* $env_defs
* $config_env
* $config_site_env
$sources
*/
#include <stddef.h>
@@ -88,18 +103,23 @@ print OUT << "END";
END
# Define all parameters, giving variable name and default value
# Define a default value for each named parameter
#
foreach my $var (@vars) {
my $default = $values{$var} || '';
$default =~ s/^"//;
$default =~ s/"$//;
my $default = $values{$var};
if (defined $default) {
$default =~ s/^"//;
$default =~ s/"$//;
}
else {
$default = '';
}
print OUT "epicsShareDef const ENV_PARAM $var =\n",
" {\"$var\", \"$default\"};\n";
}
# Now create a list of all those parameters
# Also provide a list of all defined parameters
#
print OUT "\n",
"epicsShareDef const ENV_PARAM* env_param_list[] = {\n",
@@ -112,6 +132,9 @@ sub HELP_MESSAGE {
" -h Help: Print this message\n",
" -q Quiet: Only print errors\n",
" -o file Output filename, default is $opt_o\n",
" -t arch Target architecture \$(T_A) name\n",
" -s os Operating system \$(OS_CLASS)\n",
" -c comp Compiler class \$(CMPLR_CLASS)\n",
"\n";
exit 1;

View File

@@ -40,7 +40,7 @@ typedef struct envParam {
} ENV_PARAM;
/*
* bldEnvData looks for "epicsShareExtern const ENV_PARAM"
* bldEnvData.pl looks for "epicsShareExtern const ENV_PARAM <name>;"
*/
epicsShareExtern const ENV_PARAM EPICS_CA_ADDR_LIST;
epicsShareExtern const ENV_PARAM EPICS_CA_CONN_TMO;
@@ -58,6 +58,9 @@ epicsShareExtern const ENV_PARAM EPICS_CAS_SERVER_PORT;
epicsShareExtern const ENV_PARAM EPICS_CA_BEACON_PERIOD; /* deprecated */
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PERIOD;
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PORT;
epicsShareExtern const ENV_PARAM EPICS_BUILD_COMPILER_CLASS;
epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS;
epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH;
epicsShareExtern const ENV_PARAM EPICS_TIMEZONE;
epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET;
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT;
@@ -88,6 +91,8 @@ epicsShareFunc long epicsShareAPI
envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong);
epicsShareFunc unsigned short epicsShareAPI envGetInetPortConfigParam
(const ENV_PARAM *pEnv, unsigned short defaultPort);
epicsShareFunc long epicsShareAPI
envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool);
epicsShareFunc long epicsShareAPI epicsPrtEnvParams(void);
epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value);
epicsShareFunc void epicsShareAPI epicsEnvShow (const char *name);

View File

@@ -43,6 +43,7 @@
#define epicsExportSharedSymbols
#include "epicsStdlib.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "errMdef.h"
#include "errlog.h"
#include "envDefs.h"
@@ -319,7 +320,19 @@ long *pLong /* O pointer to place to store value */
}
return -1;
}
long epicsShareAPI
envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool)
{
char text[20];
if(!envGetConfigParam(pParam, sizeof(text), text))
return -1;
*pBool = epicsStrCaseCmp(text, "yes")==0;
return 0;
}
/*+/subr**********************************************************************
* NAME envPrtConfigParam - print value of a configuration parameter
*

View File

@@ -70,12 +70,12 @@ epicsShareFunc int
/* These macros return 1 if successful, 0 on failure.
* This is analagous to the return value from sscanf()
*/
#define epicsScanLong(str, to, base) !epicsParseLong(str, to, base, NULL)
#define epicsScanULong(str, to, base) !epicsParseULong(str, to, base, NULL)
#define epicsScanLLong(str, to, base) !epicsParseLLong(str, to, base, NULL)
#define epicsScanULLong(str, to, base) !epicsParseULLong(str, to, base, NULL)
#define epicsScanFloat(str, to) !epicsParseFloat(str, to, NULL)
#define epicsScanDouble(str, to) !epicsParseDouble(str, to, NULL)
#define epicsScanLong(str, to, base) (!epicsParseLong(str, to, base, NULL))
#define epicsScanULong(str, to, base) (!epicsParseULong(str, to, base, NULL))
#define epicsScanLLong(str, to, base) (!epicsParseLLong(str, to, base, NULL))
#define epicsScanULLong(str, to, base) (!epicsParseULLong(str, to, base, NULL))
#define epicsScanFloat(str, to) (!epicsParseFloat(str, to, NULL))
#define epicsScanDouble(str, to) (!epicsParseDouble(str, to, NULL))
#ifdef __cplusplus
}

View File

@@ -81,7 +81,6 @@ template class tsFreeList
extern "C" {
static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * );
static void ipAddrToAsciiEngineShutdownRequest ( void * );
}
// - this class executes the synchronous DNS query
@@ -107,10 +106,7 @@ private:
unsigned cancelPendingCount;
bool exitFlag;
bool callbackInProgress;
static epicsMutex * pGlobalMutex;
static ipAddrToAsciiEnginePrivate * pEngine;
static unsigned numberOfReferences;
static bool shutdownRequest;
ipAddrToAsciiTransaction & createTransaction ();
void release ();
void run ();
@@ -118,15 +114,11 @@ private:
ipAddrToAsciiEnginePrivate & operator = ( const ipAddrToAsciiEngine & );
friend class ipAddrToAsciiEngine;
friend class ipAddrToAsciiTransactionPrivate;
friend void ipAddrToAsciiEngineShutdownRequest ( void * );
friend void ipAddrToAsciiEngineGlobalMutexConstruct ( void * );
};
epicsMutex * ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0;
ipAddrToAsciiEnginePrivate * ipAddrToAsciiEnginePrivate :: pEngine = 0;
unsigned ipAddrToAsciiEnginePrivate :: numberOfReferences = 0u;
bool ipAddrToAsciiEnginePrivate :: shutdownRequest = false;
static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = 0;
static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = EPICS_THREAD_ONCE_INIT;
// the users are not required to supply a show routine
// for there transaction callback class
@@ -137,26 +129,13 @@ ipAddrToAsciiCallBack::~ipAddrToAsciiCallBack () {}
ipAddrToAsciiTransaction::~ipAddrToAsciiTransaction () {}
ipAddrToAsciiEngine::~ipAddrToAsciiEngine () {}
static void ipAddrToAsciiEngineShutdownRequest ( void * )
{
bool deleteGlobalMutexCondDetected = false;
{
epicsGuard < epicsMutex >
guard ( * ipAddrToAsciiEnginePrivate :: pGlobalMutex );
ipAddrToAsciiEnginePrivate :: shutdownRequest = true;
deleteGlobalMutexCondDetected =
( ipAddrToAsciiEnginePrivate :: numberOfReferences == 0 );
}
if ( deleteGlobalMutexCondDetected ) {
delete ipAddrToAsciiEnginePrivate :: pGlobalMutex;
ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0;
}
}
static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * )
{
ipAddrToAsciiEnginePrivate :: pGlobalMutex = newEpicsMutex;
epicsAtExit ( ipAddrToAsciiEngineShutdownRequest, 0 );
try {
ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate ();
} catch (std::exception& e) {
errlogPrintf("ipAddrToAsciiEnginePrivate ctor fails with: %s\n", e.what());
}
}
// for now its probably sufficent to allocate one
@@ -168,21 +147,8 @@ ipAddrToAsciiEngine & ipAddrToAsciiEngine::allocate ()
epicsThreadOnce (
& ipAddrToAsciiEngineGlobalMutexOnceFlag,
ipAddrToAsciiEngineGlobalMutexConstruct, 0 );
// since we must not own lock when checking this flag
// this diagnostic has imperfect detection, but never
// incorrect detection
if ( ipAddrToAsciiEnginePrivate :: shutdownRequest ) {
throw std :: runtime_error (
"ipAddrToAsciiEngine::allocate (): "
"attempts to create an "
"ipAddrToAsciiEngine while the exit "
"handlers are running are rejected");
}
epicsGuard < epicsMutex > guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex );
if ( ! ipAddrToAsciiEnginePrivate::pEngine ) {
ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate ();
}
ipAddrToAsciiEnginePrivate::numberOfReferences++;
if(!ipAddrToAsciiEnginePrivate::pEngine)
throw std::runtime_error("ipAddrToAsciiEngine::allocate fails");
return * ipAddrToAsciiEnginePrivate::pEngine;
}
@@ -206,32 +172,8 @@ ipAddrToAsciiEnginePrivate::~ipAddrToAsciiEnginePrivate ()
this->thread.exitWait ();
}
// for now its probably sufficient to allocate one
// DNS transaction thread for all codes sharing
// the same process that need DNS services but we
// leave our options open for the future
void ipAddrToAsciiEnginePrivate::release ()
{
bool deleteGlobalMutexCondDetected = false;
epicsThreadOnce (
& ipAddrToAsciiEngineGlobalMutexOnceFlag,
ipAddrToAsciiEngineGlobalMutexConstruct, 0 );
{
epicsGuard < epicsMutex >
guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex );
assert ( ipAddrToAsciiEnginePrivate::numberOfReferences > 0u );
ipAddrToAsciiEnginePrivate::numberOfReferences--;
if ( ipAddrToAsciiEnginePrivate::numberOfReferences == 0u ) {
deleteGlobalMutexCondDetected =
ipAddrToAsciiEnginePrivate :: shutdownRequest;
delete ipAddrToAsciiEnginePrivate :: pEngine;
ipAddrToAsciiEnginePrivate :: pEngine = 0;
}
}
if ( deleteGlobalMutexCondDetected ) {
delete ipAddrToAsciiEnginePrivate :: pGlobalMutex;
ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0;
}
}
void ipAddrToAsciiEnginePrivate::show ( unsigned level ) const
@@ -323,12 +265,16 @@ void ipAddrToAsciiEnginePrivate::run ()
continue;
}
// fix for lp:1580623
// a destructing cac sets pCurrent to NULL, so
// make local copy to avoid race when releasing the guard
ipAddrToAsciiTransactionPrivate *pCur = this->pCurrent;
this->callbackInProgress = true;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
// dont call callback with lock applied
this->pCurrent->pCB->transactionComplete ( this->nameTmp );
pCur->pCB->transactionComplete ( this->nameTmp );
}
this->callbackInProgress = false;
@@ -365,6 +311,8 @@ ipAddrToAsciiTransactionPrivate::~ipAddrToAsciiTransactionPrivate ()
if ( this->engine.pCurrent == this &&
this->engine.callbackInProgress &&
! this->engine.thread.isCurrentThread() ) {
// cancel from another thread while callback in progress
// waits for callback to complete
assert ( this->engine.cancelPendingCount < UINT_MAX );
this->engine.cancelPendingCount++;
{
@@ -382,9 +330,11 @@ ipAddrToAsciiTransactionPrivate::~ipAddrToAsciiTransactionPrivate ()
}
else {
if ( this->engine.pCurrent == this ) {
// cancel from callback, or while lookup in progress
this->engine.pCurrent = 0;
}
else {
// cancel before lookup starts
this->engine.labor.remove ( *this );
}
this->pending = false;

View File

@@ -47,8 +47,11 @@ map {
die "$tool: Variable missing from $infile" unless defined $_;
} $ver, $rev, $mod, $patch, $snapshot, $commit_date;
$commit_date =~ s/^\$\$Date$\$$/\1/;
my $ver_str = "$ver.$rev.$mod";
$ver_str .= ".$patch" if $patch > 0;
my $ver_short = $ver_str;
$ver_str .= $snapshot if $snapshot ne '';
$ver_str .= "-$opt_v" if $opt_v;
@@ -71,10 +74,15 @@ print $OUT <<"END";
#define EPICS_PATCH_LEVEL $patch
#define EPICS_DEV_SNAPSHOT "$snapshot"
#define EPICS_SITE_VERSION "$opt_v"
#define EPICS_VERSION_SHORT "$ver_short"
#define EPICS_VERSION_FULL "$ver_str"
#define EPICS_VERSION_STRING "EPICS $ver_str"
#define epicsReleaseVersion "EPICS R$ver_str $commit_date"
#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#ifndef VERSION_INT
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#endif
#define EPICS_VERSION_INT VERSION_INT($ver, $rev, $mod, $patch)
#endif /* INC_${obase}_H */

View File

@@ -105,7 +105,7 @@
#undef epicsShareAPI
#undef READONLY
#if defined(_WIN32) || defined(__CYGWIN32__)
#if defined(_WIN32) || defined(__CYGWIN__)
/*
* Check if EPICS_BUILD_DLL or EPICS_CALL_DLL defined and use the dllimport/
* dllexport keywords if this is a shared library build of base under WIN32.

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// $Revision-Id$
@@ -37,22 +37,22 @@ epicsThreadRunable::~epicsThreadRunable () {}
void epicsThreadRunable::run () {}
void epicsThreadRunable::show ( unsigned int ) const {}
class epicsThread :: unableToCreateThread :
class epicsThread :: unableToCreateThread :
public std :: exception {
public:
const char * what () const throw ();
};
const char * epicsThread ::
const char * epicsThread ::
unableToCreateThread :: what () const throw ()
{
return "unable to create thread";
}
void epicsThread :: printLastChanceExceptionMessage (
void epicsThread :: printLastChanceExceptionMessage (
const char * pExceptionTypeName,
const char * pExceptionContext )
{
{
char date[64];
try {
epicsTime cur = epicsTime :: getCurrent ();
@@ -63,51 +63,52 @@ void epicsThread :: printLastChanceExceptionMessage (
}
char name [128];
epicsThreadGetName ( this->id, name, sizeof ( name ) );
errlogPrintf (
errlogPrintf (
"epicsThread: Unexpected C++ exception \"%s\" "
"with type \"%s\" in thread \"%s\" at %s\n",
pExceptionContext, pExceptionTypeName, name, date );
errlogFlush ();
// this should behave as the C++ implementation intends when an
// exception isnt handled. If users dont like this behavior, they
// can install an application specific unexpected handler.
// This behavior matches the C++ implementation when an exception
// isn't handled by the thread code. Users can install their own
// application-specific unexpected handler if preferred.
std::unexpected ();
}
extern "C" void epicsThreadCallEntryPoint ( void * pPvt )
{
epicsThread * pThread =
epicsThread * pThread =
static_cast <epicsThread *> ( pPvt );
bool waitRelease = false;
bool threadDestroyed = false;
try {
pThread->pWaitReleaseFlag = & waitRelease;
pThread->pThreadDestroyed = & threadDestroyed;
if ( pThread->beginWait () ) {
pThread->runable.run ();
// current thread may have run the destructor
// so must not touch the this pointer from
// here on down if waitRelease is true
// The run() routine may have destroyed the epicsThread
// object by now; pThread can only be used below here
// when the threadDestroyed flag is false.
}
}
catch ( const epicsThread::exitException & ) {
}
catch ( std :: exception & except ) {
if ( ! waitRelease ) {
pThread->printLastChanceExceptionMessage (
if ( ! threadDestroyed ) {
pThread->printLastChanceExceptionMessage (
typeid ( except ).name (), except.what () );
}
}
catch ( ... ) {
if ( ! waitRelease ) {
pThread->printLastChanceExceptionMessage (
if ( ! threadDestroyed ) {
pThread->printLastChanceExceptionMessage (
"catch ( ... )", "Non-standard C++ exception" );
}
}
if ( ! waitRelease ) {
if ( ! threadDestroyed ) {
epicsGuard < epicsMutex > guard ( pThread->mutex );
pThread->pThreadDestroyed = NULL;
pThread->terminated = true;
pThread->exitEvent.signal ();
// once the terminated flag is set and we release the lock
// then the "this" pointer must not be touched again
// After the terminated flag is set and guard's destructor
// releases the lock, pThread must never be used again.
}
}
@@ -135,12 +136,12 @@ void epicsThread::exitWait () throw ()
bool epicsThread::exitWait ( const double delay ) throw ()
{
try {
// if destructor is running in managed thread then of
// course we will not wait for the managed thread to
// exit
// When called (usually by a destructor) in the context of
// the managed thread we can't wait for the thread to exit.
// Set the threadDestroyed flag and return success.
if ( this->isCurrentThread() ) {
if ( this->pWaitReleaseFlag ) {
*this->pWaitReleaseFlag = true;
if ( this->pThreadDestroyed ) {
*this->pThreadDestroyed = true;
}
return true;
}
@@ -157,14 +158,14 @@ bool epicsThread::exitWait ( const double delay ) throw ()
}
}
catch ( std :: exception & except ) {
errlogPrintf (
errlogPrintf (
"epicsThread::exitWait(): Unexpected exception "
" \"%s\"\n",
" \"%s\"\n",
except.what () );
epicsThreadSleep ( epicsMin ( delay, 5.0 ) );
}
catch ( ... ) {
errlogPrintf (
errlogPrintf (
"Non-standard unexpected exception in "
"epicsThread::exitWait()\n" );
epicsThreadSleep ( epicsMin ( delay, 5.0 ) );
@@ -174,14 +175,14 @@ bool epicsThread::exitWait ( const double delay ) throw ()
return this->terminated;
}
epicsThread::epicsThread (
epicsThread::epicsThread (
epicsThreadRunable & runableIn, const char * pName,
unsigned stackSize, unsigned priority ) :
runable ( runableIn ), id ( 0 ), pWaitReleaseFlag ( 0 ),
runable ( runableIn ), id ( 0 ), pThreadDestroyed ( 0 ),
begin ( false ), cancel ( false ), terminated ( false )
{
this->id = epicsThreadCreate (
pName, priority, stackSize, epicsThreadCallEntryPoint,
this->id = epicsThreadCreate (
pName, priority, stackSize, epicsThreadCallEntryPoint,
static_cast < void * > ( this ) );
if ( ! this->id ) {
throw unableToCreateThread ();
@@ -193,11 +194,11 @@ epicsThread::~epicsThread () throw ()
while ( ! this->exitWait ( 10.0 ) ) {
char nameBuf [256];
this->getName ( nameBuf, sizeof ( nameBuf ) );
fprintf ( stderr,
fprintf ( stderr,
"epicsThread::~epicsThread(): "
"blocking for thread \"%s\" to exit\n",
"blocking for thread \"%s\" to exit\n",
nameBuf );
fprintf ( stderr,
fprintf ( stderr,
"was epicsThread object destroyed before thread exit ?\n");
}
}
@@ -272,11 +273,6 @@ void epicsThread::sleep (double seconds) throw ()
epicsThreadSleep (seconds);
}
//epicsThread & epicsThread::getSelf ()
//{
// return * static_cast<epicsThread *> ( epicsThreadGetIdSelf () );
//}
const char *epicsThread::getNameSelf () throw ()
{
return epicsThreadGetNameSelf ();
@@ -303,7 +299,7 @@ void epicsThread :: show ( unsigned level ) const throw ()
if ( level > 0u ) {
epicsThreadShow ( this->id, level - 1 );
if ( level > 1u ) {
::printf ( "pWaitReleaseFlag = %p\n", this->pWaitReleaseFlag );
::printf ( "pThreadDestroyed = %p\n", this->pThreadDestroyed );
::printf ( "begin = %c, cancel = %c, terminated = %c\n",
this->begin ? 'T' : 'F',
this->cancel ? 'T' : 'F',
@@ -323,12 +319,12 @@ extern "C" {
epicsThreadPrivateId okToBlockPrivate;
static const int okToBlockNo = 0;
static const int okToBlockYes = 1;
static void epicsThreadOnceIdInit(void *)
{
okToBlockPrivate = epicsThreadPrivateCreate();
}
int epicsShareAPI epicsThreadIsOkToBlock(void)
{
const int *pokToBlock;
@@ -336,7 +332,7 @@ extern "C" {
pokToBlock = (int *) epicsThreadPrivateGet(okToBlockPrivate);
return (pokToBlock ? *pokToBlock : 0);
}
void epicsShareAPI epicsThreadSetOkToBlock(int isOkToBlock)
{
const int *pokToBlock;
@@ -344,12 +340,12 @@ extern "C" {
pokToBlock = (isOkToBlock) ? &okToBlockYes : &okToBlockNo;
epicsThreadPrivateSet(okToBlockPrivate, (void *)pokToBlock);
}
epicsThreadId epicsShareAPI epicsThreadMustCreate (
const char *name, unsigned int priority, unsigned int stackSize,
EPICSTHREADFUNC funptr,void *parm)
EPICSTHREADFUNC funptr,void *parm)
{
epicsThreadId id = epicsThreadCreate (
epicsThreadId id = epicsThreadCreate (
name, priority, stackSize, funptr, parm );
assert ( id );
return id;

View File

@@ -57,6 +57,12 @@ typedef epicsThreadId epicsThreadOnceId;
epicsShareFunc void epicsShareAPI epicsThreadOnce(
epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg);
/* When real-time scheduling is active, attempt any post-init operations
* that preserve real-time performance. For POSIX targets this locks the
* process into RAM, preventing swap-related VM faults.
*/
epicsShareFunc void epicsThreadRealtimeLock(void);
epicsShareFunc void epicsShareAPI epicsThreadExitMain(void);
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (
@@ -152,10 +158,10 @@ public:
bool isCurrentThread () const throw ();
bool operator == ( const epicsThread & ) const throw ();
void show ( unsigned level ) const throw ();
/* these operate on the current thread */
static void suspendSelf () throw ();
static void sleep (double seconds) throw ();
/* static epicsThread & getSelf (); */
static const char * getNameSelf () throw ();
static bool isOkToBlock () throw ();
static void setOkToBlock ( bool isOkToBlock ) throw ();
@@ -168,7 +174,7 @@ private:
epicsMutex mutex;
epicsEvent event;
epicsEvent exitEvent;
bool * pWaitReleaseFlag;
bool * pThreadDestroyed;
bool begin;
bool cancel;
bool terminated;

View File

@@ -41,6 +41,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
#define SOCK_EINPROGRESS EINPROGRESS

View File

@@ -43,6 +43,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
#define SOCK_EINPROGRESS EINPROGRESS

View File

@@ -51,6 +51,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
#define SOCK_EINPROGRESS EINPROGRESS

View File

@@ -248,6 +248,9 @@ epicsThreadInit (void)
}
}
void epicsThreadRealtimeLock(void)
{}
/*
* Create and start a new thread
*/

View File

@@ -10,6 +10,9 @@
*
* Author: W. Eric Norum
*/
#define __BSD_VISIBLE 1
#include <sys/types.h>
#include <sys/socket.h>
#include <epicsStdio.h>
#include <rtems.h>
@@ -40,8 +43,37 @@ void osdTimeRegister(void)
int osdNTPGet(struct timespec *ts)
{
static unsigned bequiet;
ssize_t ret;
if (ntpSocket < 0)
return -1;
/* rtems_bsdnet_get_ntp() will send an NTP request, then
* call recvfrom() exactly once to process the expected reply.
* Any leftovers in the socket buffer (ie. duplicates of
* previous replies) will cause problems.
* So flush out the socket buffer first.
*/
do {
char junk[16];
ret = recvfrom(ntpSocket, junk, sizeof(junk), MSG_DONTWAIT, NULL, NULL);
if (ret == -1 && errno == EAGAIN) {
break;
}
else if (ret == -1) {
if (!bequiet) {
printf("osdNTPGet cleaner error: %s\n", strerror(errno));
bequiet = 1;
}
break;
}
else {
bequiet = 0;
}
} while (ret > 0);
return rtems_bsdnet_get_ntp(ntpSocket, NULL, ts);
}

View File

@@ -21,7 +21,7 @@
# define WIN32
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#define SOCKERRNO WSAGetLastError()
@@ -49,6 +49,7 @@ typedef int osiSocklen_t;
#define SOCK_ECONNRESET WSAECONNRESET
#define SOCK_ETIMEDOUT WSAETIMEDOUT
#define SOCK_EADDRINUSE WSAEADDRINUSE
#define SOCK_EADDRNOTAVAIL WSAEADDRNOTAVAIL
#define SOCK_ECONNREFUSED WSAECONNREFUSED
#define SOCK_ECONNABORTED WSAECONNABORTED
#define SOCK_EINPROGRESS WSAEINPROGRESS

View File

@@ -23,7 +23,7 @@ epicsShareFunc double epicsStrtod(const char *str, char **endp);
* Older compilers have these equivalents though
*/
#ifndef _MINGW
#if !defined(_MINGW) && (_MSC_VER < 1800)
# define strtoll _strtoi64
# define strtoull _strtoui64
#endif

View File

@@ -303,6 +303,10 @@ static unsigned osdPriorityMagFromPriorityOSI ( unsigned osiPriority, unsigned p
return magnitude;
}
epicsShareFunc
void epicsThreadRealtimeLock(void)
{}
/*
* epicsThreadGetOsdPriorityValue ()
*/

View File

@@ -124,148 +124,31 @@ static int osdTimeGetCurrent ( epicsTimeStamp *pDest )
return epicsTimeOK;
}
inline void UnixTimeToFileTime ( const time_t * pAnsiTime, LPFILETIME pft )
{
LONGLONG ll = Int32x32To64 ( *pAnsiTime, 10000000 ) + 116444736000000000LL;
pft->dwLowDateTime = static_cast < DWORD > ( ll );
pft->dwHighDateTime = static_cast < DWORD > ( ll >>32 );
}
static int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31,
31, 30, 31, 30, 31 };
static bool isLeapYear ( DWORD year )
{
if ( (year % 4) == 0 ) {
return ( ( year % 100 ) != 0 || ( year % 400 ) == 0 );
} else {
return false;
}
}
static int dayOfYear ( DWORD day, DWORD month, DWORD year )
{
DWORD nDays = 0;
for ( unsigned m = 1; m < month; m++ ) {
nDays += daysInMonth[m-1];
if ( m == 2 && isLeapYear(year) ) {
nDays++;
}
}
return nDays + day;
}
// synthesize a reentrant gmtime on WIN32
int epicsShareAPI epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
{
FILETIME ft;
UnixTimeToFileTime ( pAnsiTime, &ft );
SYSTEMTIME st;
BOOL status = FileTimeToSystemTime ( &ft, &st );
if ( ! status ) {
return epicsTimeERROR;
struct tm * pRet = gmtime ( pAnsiTime );
if ( pRet ) {
*pTM = *pRet;
return epicsTimeOK;
}
else {
return errno;
}
pTM->tm_sec = st.wSecond; // seconds after the minute - [0,59]
pTM->tm_min = st.wMinute; // minutes after the hour - [0,59]
pTM->tm_hour = st.wHour; // hours since midnight - [0,23]
assert ( st.wDay >= 1 && st.wDay <= 31 );
pTM->tm_mday = st.wDay; // day of the month - [1,31]
assert ( st.wMonth >= 1 && st.wMonth <= 12 );
pTM->tm_mon = st.wMonth - 1; // months since January - [0,11]
assert ( st.wYear >= 1900 );
pTM->tm_year = st.wYear - 1900; // years since 1900
pTM->tm_wday = st.wDayOfWeek; // days since Sunday - [0,6]
pTM->tm_yday = dayOfYear ( st.wDay, st.wMonth, st.wYear ) - 1;
pTM->tm_isdst = 0;
return epicsTimeOK;
}
// synthesize a reentrant localtime on WIN32
int epicsShareAPI epicsTime_localtime (
const time_t * pAnsiTime, struct tm * pTM )
{
FILETIME ft;
UnixTimeToFileTime ( pAnsiTime, & ft );
TIME_ZONE_INFORMATION tzInfo;
DWORD tzStatus = GetTimeZoneInformation ( & tzInfo );
if ( tzStatus == TIME_ZONE_ID_INVALID ) {
return epicsTimeERROR;
struct tm * pRet = localtime ( pAnsiTime );
if ( pRet ) {
*pTM = *pRet;
return epicsTimeOK;
}
//
// There are remarkable weaknesses in the FileTimeToLocalFileTime
// interface so we don't use it here. Unfortunately, there is no
// corresponding function that works on file time.
//
SYSTEMTIME st;
BOOL success = FileTimeToSystemTime ( & ft, & st );
if ( ! success ) {
return epicsTimeERROR;
else {
return errno;
}
SYSTEMTIME lst;
success = SystemTimeToTzSpecificLocalTime (
& tzInfo, & st, & lst );
if ( ! success ) {
return epicsTimeERROR;
}
//
// We must convert back to file time so that we can determine if DST
// is active...
//
FILETIME lft;
success = SystemTimeToFileTime ( & lst, & lft );
if ( ! success ) {
return epicsTimeERROR;
}
int is_dst = -1; // unknown state of dst
if ( tzStatus != TIME_ZONE_ID_UNKNOWN &&
tzInfo.StandardDate.wMonth != 0 &&
tzInfo.DaylightDate.wMonth != 0) {
// determine if the specified date is
// in daylight savings time
tzInfo.StandardDate.wYear = st.wYear;
FILETIME StandardDateFT;
success = SystemTimeToFileTime (
& tzInfo.StandardDate, & StandardDateFT );
if ( ! success ) {
return epicsTimeERROR;
}
tzInfo.DaylightDate.wYear = st.wYear;
FILETIME DaylightDateFT;
success = SystemTimeToFileTime (
& tzInfo.DaylightDate, & DaylightDateFT );
if ( ! success ) {
return epicsTimeERROR;
}
if ( CompareFileTime ( & lft, & DaylightDateFT ) >= 0
&& CompareFileTime ( & lft, & StandardDateFT ) < 0 ) {
is_dst = 1;
}
else {
is_dst = 0;
}
}
pTM->tm_sec = lst.wSecond; // seconds after the minute - [0,59]
pTM->tm_min = lst.wMinute; // minutes after the hour - [0,59]
pTM->tm_hour = lst.wHour; // hours since midnight - [0,23]
assert ( lst.wDay >= 1 && lst.wDay <= 31 );
pTM->tm_mday = lst.wDay; // day of the month - [1,31]
assert ( lst.wMonth >= 1 && lst.wMonth <= 12 );
pTM->tm_mon = lst.wMonth - 1; // months since January - [0,11]
assert ( lst.wYear >= 1900 );
pTM->tm_year = lst.wYear - 1900; // years since 1900
pTM->tm_wday = lst.wDayOfWeek; // days since Sunday - [0,6]
pTM->tm_yday = dayOfYear ( lst.wDay, lst.wMonth, lst.wYear ) - 1;
pTM->tm_isdst = is_dst;
return epicsTimeOK;
}
currentTime::currentTime () :

View File

@@ -16,11 +16,17 @@
#ifndef INC_osdTime_H
#define INC_osdTime_H
/* MinGW only has a snippet time.h not protected against multiple inclusion */
#if defined(__struct_timespec_defined)
#define _TIMESPEC_DEFINED 1
#endif
#if ! defined(_MINGW) || ! defined(_TIMESPEC_DEFINED)
# if _MSC_VER >= 1900
# include <time.h>
# else
#define __struct_timespec_defined 1
#define _TIMESPEC_DEFINED 1
struct timespec {
time_t tv_sec; /* seconds since some epoch */

View File

@@ -50,6 +50,7 @@ typedef int osiSocklen_t;
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
#define SOCK_EINPROGRESS EINPROGRESS

View File

@@ -13,6 +13,7 @@
#include <epicsTypes.h>
#include <epicsEndian.h>
#include <compilerSpecific.h>
#include <shareLib.h>
#ifdef __cplusplus
@@ -27,7 +28,7 @@
/** @brief Read a single byte.
*/
INLINE
static EPICS_ALWAYS_INLINE
epicsUInt8
ioread8(volatile void* addr)
{
@@ -36,7 +37,7 @@ ioread8(volatile void* addr)
/** @brief Write a single byte.
*/
INLINE
static EPICS_ALWAYS_INLINE
void
iowrite8(volatile void* addr, epicsUInt8 val)
{
@@ -46,7 +47,7 @@ iowrite8(volatile void* addr, epicsUInt8 val)
/** @brief Read two bytes in host order.
* Not byte swapping
*/
INLINE
static EPICS_ALWAYS_INLINE
epicsUInt16
nat_ioread16(volatile void* addr)
{
@@ -56,7 +57,7 @@ nat_ioread16(volatile void* addr)
/** @brief Write two byte in host order.
* Not byte swapping
*/
INLINE
static EPICS_ALWAYS_INLINE
void
nat_iowrite16(volatile void* addr, epicsUInt16 val)
{
@@ -66,7 +67,7 @@ nat_iowrite16(volatile void* addr, epicsUInt16 val)
/** @brief Read four bytes in host order.
* Not byte swapping
*/
INLINE
static EPICS_ALWAYS_INLINE
epicsUInt32
nat_ioread32(volatile void* addr)
{
@@ -76,7 +77,7 @@ nat_ioread32(volatile void* addr)
/** @brief Write four byte in host order.
* Not byte swapping
*/
INLINE
static EPICS_ALWAYS_INLINE
void
nat_iowrite32(volatile void* addr, epicsUInt32 val)
{

View File

@@ -54,7 +54,7 @@ static struct ifreq * ifreqNext ( struct ifreq *pifreq )
struct ifreq *ifr;
ifr = ( struct ifreq * )( ifreqSize (pifreq) + ( char * ) pifreq );
ifDepenDebugPrintf( ("ifreqNext() pifreq 0x%08x, size 0x%08x, ifr 0x%08x\n", pifreq, ifreqSize (pifreq), ifr) );
ifDepenDebugPrintf( ("ifreqNext() pifreq %p, size 0x%x, ifr 0x%p\n", pifreq, (unsigned)ifreqSize (pifreq), ifr) );
return ifr;
}
@@ -105,8 +105,7 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
ifconf.ifc_req = pIfreqList;
status = socket_ioctl (socket, SIOCGIFCONF, &ifconf);
if (status < 0 || ifconf.ifc_len == 0) {
ifDepenDebugPrintf(("osiSockDiscoverBroadcastAddresses(): status: 0x08x, ifconf.ifc_len: %d\n", status, ifconf.ifc_len));
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration\n");
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration (%d)\n", status);
free (pIfreqList);
return;
}
@@ -129,8 +128,8 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
ifDepenDebugPrintf (("osiSockDiscoverBroadcastAddresses(): found IFACE: %s len: 0x%x current_ifreqsize: 0x%x \n",
pIfreqList->ifr_name,
ifreq_size(pifreq),
current_ifreqsize));
(unsigned)ifreq_size(pifreq),
(unsigned)current_ifreqsize));
/*
* If its not an internet interface then dont use it
@@ -197,14 +196,22 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses
* interface.
*/
if ( pIfreqList->ifr_flags & IFF_BROADCAST ) {
osiSockAddr baddr;
status = socket_ioctl (socket, SIOCGIFBRDADDR, pIfreqList);
if ( status ) {
errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": bcast addr fetch fail\n", pIfreqList->ifr_name);
free ( pNewNode );
continue;
}
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( pNewNode->addr.ia.sin_addr.s_addr ) ) );
baddr.sa = pIfreqList->ifr_broadaddr;
if (baddr.ia.sin_family==AF_INET && baddr.ia.sin_addr.s_addr != INADDR_ANY) {
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
} else {
ifDepenDebugPrintf ( ( "Ignoring broadcast addr = \n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
free ( pNewNode );
continue;
}
}
#if defined (IFF_POINTOPOINT)
else if ( pIfreqList->ifr_flags & IFF_POINTOPOINT ) {

View File

@@ -44,6 +44,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
#define SOCK_EINPROGRESS EINPROGRESS

View File

@@ -42,6 +42,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
#define SOCK_EINPROGRESS EINPROGRESS

View File

@@ -19,7 +19,7 @@ extern "C" {
#ifdef isfinite
# undef finite
# define finite(x) isfinite(x)
# define finite(x) isfinite((double)(x))
#endif
epicsShareExtern float epicsNAN;

View File

@@ -357,21 +357,10 @@ static void once(void)
pcommonAttr->maxPriority);
}
#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
if(errVerbose) {
fprintf(stderr, "LRT: min priority: %d max priority %d\n",
if (errVerbose) {
fprintf(stderr, "LRT: min priority: %d max priority %d\n",
pcommonAttr->minPriority, pcommonAttr->maxPriority);
}
if (pcommonAttr->maxPriority > pcommonAttr->minPriority) {
status = mlockall(MCL_CURRENT | MCL_FUTURE);
if(status) {
fprintf(stderr, "Unable to lock the virtual address space using mlockall\n");
} else {
fprintf(stderr,"Successfully locked memory using mlockAll\n");
}
}
#endif
#else
if(errVerbose) fprintf(stderr,"task priorities are not implemented\n");
@@ -425,7 +414,22 @@ static void epicsThreadInit(void)
checkStatusQuit(status,"pthread_once","epicsThreadInit");
}
epicsShareFunc
void epicsThreadRealtimeLock(void)
{
#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
if (pcommonAttr->maxPriority > pcommonAttr->minPriority) {
int status = mlockall(MCL_CURRENT | MCL_FUTURE);
if (status) {
fprintf(stderr, "epicsThreadRealtimeLock "
"Warning: Unable to lock the virtual address space.\n"
"VM page faults may harm real-time performance.\n");
}
}
#endif
}
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
{
#if defined (OSITHREAD_USE_DEFAULT_STACK)

View File

@@ -44,7 +44,7 @@
} // extern "C"
#endif
#ifdef CYGWIN32
#ifdef __CYGWIN__
int clock_settime(clockid_t clock, const timespec *tp)
{
return -EFAULT;

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