Compare commits

...

81 Commits

Author SHA1 Message Date
Ralph Lange
42a67524e0 Update CONFIG_BASE_VERSION for 3.15.3, remove "not released" from RELEASE_NOTES 2015-11-22 17:54:12 +01:00
Ralph Lange
d4ed70154b doc: add reference to LP bug #1466129 to known problems page 2015-11-22 17:33:58 +01:00
Andrew Johnson
f776f6b422 Set Base version to -rc1-DEV 2015-10-26 14:31:25 -05:00
Ralph Lange
cd746a339f configure: update CONFIG_BASE_VERSION for 3.15.3-rc1 2015-10-26 17:22:37 +01:00
Ralph Lange
6438750615 tools: change builtin _USER_ macro name to avoid clashes with makeBaseApp 2015-10-26 13:41:46 +01:00
Andrew Johnson
2ec5c80652 Fix internal anchor in filters.pod 2015-10-13 18:39:50 -05:00
Andrew Johnson
e1039bacfc Merged DB file parser fix from 3.14, revno 12605 2015-10-13 14:41:39 -05:00
Andrew Johnson
54381b7bf9 Fix DB file parser crashes 2015-10-13 12:03:32 -05:00
Andrew Johnson
69d3c94328 Set Base version to -pre1-DEV 2015-10-12 10:38:00 -05:00
Ralph Lange
a02860728e configure: update CONFIG_BASE_VERSION for 3.15.3-pre1 2015-10-12 10:35:30 +02:00
Ralph Lange
440ccc3c4a Merged Andrew's ntptime-on-vxworks branch 2015-10-11 12:04:16 +02:00
Ralph Lange
3d19f19d81 Merge Ralph's config-from-snippets branch 2015-10-11 09:59:39 +02:00
Andrew Johnson
214edd42d1 Minor RULES_EXPAND changes
Added support for a _PATTERN variable which calls $(wildcard) and
prepends .. and the other SRC_DIRS automatically.
Use $(ECHO) instead of @echo so make -s works silently.
Added another meta-rule to create .d files when make needs one.
2015-10-11 00:50:50 -05:00
Ralph Lange
f8b0b2f5f0 tools: add new builtin macros to assemblies 2015-10-10 19:12:11 +02:00
Ralph Lange
8596dc41f2 configure: add assemblies to RULES_EXPAND 2015-10-10 18:55:17 +02:00
Ralph Lange
88cb33a04d tools: fix in assembleSnippets script and test for Windows (getpwuid() not implemented) 2015-10-10 18:54:20 +02:00
Ralph Lange
5af0663058 Back out 12706 (assembly integration in build system) 2015-10-10 18:17:35 +02:00
Ralph Lange
830704021d Add creating config files from snippets to build system. 2015-10-09 17:28:46 +02:00
Ralph Lange
96ee2cd00c tools: install assembleSnippets.pl 2015-10-09 15:28:40 +02:00
Ralph Lange
c2d2f671bb tools: add -M option to assembleSnippets.pl (creates dependency file) 2015-10-09 14:15:26 +02:00
Ralph Lange
4b9958304d tools: add assembleSnippets.pl and test 2015-10-09 11:25:45 +02:00
Andrew Johnson
d0875f4f12 Make the NTPTime provider optional on VxWorks 2015-10-05 17:44:26 -05:00
Andrew Johnson
c74eb27474 Merged changes from 3.14 branch, to revno 12604 2015-09-18 11:51:51 -05:00
Ralph Lange
5aa145920d rec: fix promptgroups for biRecord 2015-09-16 13:56:52 +02:00
Andrew Johnson
bc3cbd990f Applied Ambroz Bizjak's freeListItemsAvail.patch 2015-08-31 12:11:30 -05:00
Andrew Johnson
53bf7cd994 Applied Ambroz Bizjak's epicsSingletonMutex.patch 2015-08-31 11:54:04 -05:00
Andrew Johnson
a9c4d59537 Applied Ambroz Bizjak's timerQueueActive.patch 2015-08-31 11:52:32 -05:00
Robert Soliday
d32332d545 libCom/test: Fix for MSVS 2015 2015-08-27 11:34:41 -05:00
Andrew Johnson
88864e949b Merge changes from 3.14 branch, to revno 12599 2015-08-20 11:14:01 -05:00
Andrew Johnson
fe4f607e63 libCom/errlog: Don't store stderr in pvtData.console
Some VxWorks BSPs close the stderr stream that the shell running
the startup script created and open a new one for the interactive
shell. This change makes pvtData.console==NULL mean use stderr
instead of storing the stderr value in pvtData.console at init.
2015-08-13 10:44:52 -05:00
Andrew Johnson
9e82a96700 dbTest: Remove special ENUM handling from dbpf()
This was preventing the value check in cvt_st_menu() from working.
2015-08-10 15:04:11 -05:00
Andrew Johnson
ef7399159c dbAccess: Make dbPut() always do special processing after put
If the value gets rejected by a put to SCAN, we must still call
dbPutSpecial() to add the record back onto its old scan thread.
2015-08-10 15:03:48 -05:00
Andrew Johnson
d7b3293ba3 libCom: Use MSVC's struct timespec when available 2015-08-07 09:41:48 -05:00
Andrew Johnson
9014ca899d dbStatic: Fix invalid memory read 2015-07-30 11:57:50 -05:00
Andrew Johnson
c5130468cd Let dbdToHtml work with wrong newlines 2015-07-24 10:42:09 -05:00
Andrew Johnson
7dd067e887 Merged dbCa bug-fix from 3.14 branch, revno 12595 2015-07-23 18:02:54 -05:00
Andrew Johnson
c56091978c db: Fixed obscure dbCa bug
This could be triggered if dbCaRemoveLink() is called on a link for
which there is an outstanding dbCaPutCallback().

Normally a dbCaPutCallback() callback routine is passed the associated
userPvt pointer as an argument, but in the event that dbCaRemoveLink()
gets used on the same link between the put and its completion callback,
the callback routine was being called with the link pointer as the
argument instead.

For all the existing Asyn Soft Channel device supports this is not a
problem as they all pass the link pointer as their userPvt argument, but
that won't necessarily always be the case.

Also updated the comments describing the process of removing links.
2015-07-23 17:57:30 -05:00
Andrew Johnson
2f8e6bf17e Fix smoothing for Nan/Inf values in devAiSoftCallback 2015-07-23 13:05:38 -05:00
Andrew Johnson
144281e0a3 Removed extraneous .db file 2015-07-23 12:34:05 -05:00
Andrew Johnson
83c2414ad0 Merged changes from 3.14 branch to revno 12594 2015-07-23 10:13:07 -05:00
Michael Davidsaver
504665bf09 iocInit: move dbCaShutdown earlier
Switch dbCaShutdown from an exit hook to
be called from iocShutdown.  Place it
after callback shutdown.
2015-07-21 19:08:07 -04:00
Michael Davidsaver
1411522a11 dbCa: only add dbCaExit once 2015-07-21 15:53:37 -04:00
Andrew Johnson
ae3d3904d9 Fix minor locking issue in dbEvent.c 2015-07-17 18:09:14 -05:00
Andrew Johnson
002bafdf07 Add testHarnessDone 2015-07-17 18:06:58 -05:00
Michael Davidsaver
8bfa40d858 dbScan: avoid race on shutdown 2015-07-16 17:05:41 -04:00
Michael Davidsaver
138e2f1ad5 callback: fix race on shutdown
epicsEventDestory() in the main thread could be called
before epicsEventTrigger() completes in the worker.
2015-07-16 17:05:41 -04:00
Michael Davidsaver
fefe6fd1fc Fix shutdown issues with scan and callback.
The main reason for this merge proposal is the change to "public" API functions.

Use atomic counter to resolve data race on threadsRunning in callback.

Split up callbackShutdown() and scanShutdown() into two phases *Stop() and
*Cleanup(). The *Stop() functions signal worker threads, and wait for them to
exit. The *Cleanup() functions actually reclaim global resources.

These two mechanisms have couplings which are quite complex. I/O Intr scans
involve both scan lists and callbacks.
2015-07-16 11:48:29 -05:00
Andrew Johnson
5eb49ebaf0 Merged changes from 3.14 branch to revno 12590 2015-07-13 13:05:33 -05:00
Andrew Johnson
625172419e libCom: Make epicsReadline behave the same on Darwin 2015-07-01 12:00:42 -05:00
Andrew Johnson
80343363a4 configure: Include RULES_FILE_TYPE earlier
From Benjamin Franksen:

There is one remaining problem with the order of includes in the build
rules for 3.14.12.5: configure/RULES_BUILD includes RULES_FILE_TYPE
(which in turn includes the cfg/RULES* from modules in the RELEASE file)
*after* including RULES.Db and RULES_JAVA. This makes it impossible to
override (pattern) rules in one of these files. Instead,
$(CONFIG)/RULES_FILE_TYPE should be included first.
2015-07-01 11:30:02 -05:00
Andrew Johnson
444b89f557 libCom: Make readline support clean up on epicsExit() 2015-06-30 14:08:32 -05:00
Andrew Johnson
fa1ddeeb1b Removed the last vestiges of RSET::get_value() 2015-06-23 18:04:33 -05:00
Andrew Johnson
ca46bf70b7 Fixes to attribute handling in dbStaticLib
From Peter Leban of i-tech (Libera)
2015-06-23 17:06:54 -05:00
Andrew Johnson
c0e2a44365 Register dbPutAttribute with iocsh 2015-06-23 17:04:37 -05:00
Andrew Johnson
84c3ec7c64 db: Correct DBF_CHAR range in recGbl.c
Seems invisible, but spotted by Lawrence T. Prevatte III.
2015-06-23 15:51:00 -05:00
Andrew Johnson
65e781d58a db: Fix off-by-one error in initHookName()
Thanks to Lawrence T. Prevatte III for noticing that.
2015-06-23 14:46:29 -05:00
Andrew Johnson
a613a96ad3 libCom: Fix routine name in error message 2015-06-18 10:56:43 -05:00
Ralph Lange
fbd2d4dd31 dbStatic: fix buffer overrun in printing functions by extending the local buffer accordingly 2015-06-05 11:10:10 +02:00
Andrew Johnson
2c28d4b69e Merged Lewis Muir's CAref ToC update
Also added some entries for a couple of missing ca_sg routines.
2015-05-15 10:41:19 -05:00
Andrew Johnson
9946681f72 Update version numbers in documentation for 3.15.3 2015-05-15 10:06:06 -05:00
Ralph Lange
196baac7da documentation: put back red "not released yet" header to RELEASE_NOTES 2015-05-15 14:05:59 +02:00
Ralph Lange
ce93142fe1 configure: set version snapshot back to -DEV 2015-05-15 13:50:14 +02:00
Ralph Lange
e7b20537b9 configure: update CONFIG_BASE_VERSION for 3.15.2 (2nd time for tag move) 2015-05-15 13:47:33 +02:00
Ralph Lange
42a8e61832 documentation: remove red "not released yet" header from RELEASE_NOTES 2015-05-15 13:36:42 +02:00
J. Lewis Muir
5d61a512d1 doc: add ca_put_callback to CA ref man func call interface index
The ca_put_callback function is not listed in the CA Reference Manual's
function call interface index; add it.
2015-05-14 16:23:23 -05:00
Ralph Lange
37e1feac12 configure: set version snapshot back to -DEV 2015-05-14 14:16:53 +02:00
Ralph Lange
3090561b5e configure: update CONFIG_BASE_VERSION for 3.15.2 2015-05-14 14:09:28 +02:00
Ralph Lange
1849b9f4ab Update KnownProblems to new version, add Windows parallel build issue 2015-05-14 14:08:18 +02:00
Ralph Lange
2bf58d3187 Update ReleaseChecklist to new version. 2015-05-14 14:06:47 +02:00
Andrew Johnson
2f6fad0cc3 Fixing and/or investigating Cygwin issues 2015-05-01 11:38:54 -05:00
Andrew Johnson
f384232864 Merged Cygwin fix from 3.14 branch, revno 12584 2015-04-29 14:21:40 -05:00
Andrew Johnson
33b9fba00b Fix for latest Cygwin 2015-04-29 14:01:07 -05:00
Ralph Lange
b7b9e2a79b configure: set version snapshot to -rc1-DEV 2015-04-29 14:20:18 +02:00
Ralph Lange
6de155e97a configure: update CONFIG_BASE_VERSION for 3.15.2-rc1 2015-04-29 13:58:56 +02:00
Andrew Johnson
1f73716d5c Adjust linux-x86 & -x86_64 flags
Moved -m64 from ARCH_DEP_*FLAGS to OP_SYS_*FLAGS where it is on -x86.
Added GNU_TUNE_CFLAGS to -x86_64, adjust related comments
Added -D_FILE_OFFSET_BITS=64 to -x86 builds
2015-04-28 11:27:06 -05:00
Andrew Johnson
2774b4c4af Fix type problem with local CA channels
This commit fixes a problem introduced in Bazaar commit 12658.
Local CA channels were seeing the data type of a channel as an
IOC-specific (dbFldTypes.h) type value instead of the CA type
value from db_access.h.

We introduce a pair of dbChannel*CAType() macros which convert
the dbChannel's dbr_field_type and final_type values into the
CA equivalent type values, and use these macros whenever the
CA encoded field type value is needed. This ensures that the
meaning of the dbChannel member fields never changes (in 3.14
the addr.dbr_field_type was overwritten with the converted
value when connected to by rsrv).
2015-04-22 16:51:31 -05:00
Ralph Lange
bcf47ac663 gdd: fix 64 bit warnings using explicit casts for strlen() results 2015-04-16 14:05:33 +02:00
Ralph Lange
da93312b79 configure: fix Windows builds - don't use static link to create DLL stub 2015-04-16 10:55:14 +02:00
Andrew Johnson
874087f454 Update some version numbers in documentation 2015-04-14 17:58:33 -05:00
Andrew Johnson
a6d3c4f792 Document -D option to msi 2015-04-14 17:57:10 -05:00
Ralph Lange
f168a0f612 configure: set version snapshot to -pre1-DEV 2015-04-14 11:04:27 +02:00
68 changed files with 856 additions and 333 deletions

View File

@@ -29,7 +29,7 @@ EPICS_VERSION = 3
EPICS_REVISION = 15
# EPICS_MODIFICATION must be a number >=0 and <256
EPICS_MODIFICATION = 2
EPICS_MODIFICATION = 3
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included if zero
@@ -37,7 +37,7 @@ EPICS_PATCH_LEVEL = 0
# This will end in -DEV between official releases
#EPICS_DEV_SNAPSHOT=-DEV
EPICS_DEV_SNAPSHOT=-pre1
#EPICS_DEV_SNAPSHOT=-pre1
#EPICS_DEV_SNAPSHOT=-pre1-DEV
#EPICS_DEV_SNAPSHOT=-pre2
#EPICS_DEV_SNAPSHOT=-pre2-DEV
@@ -45,7 +45,7 @@ EPICS_DEV_SNAPSHOT=-pre1
#EPICS_DEV_SNAPSHOT=-rc1-DEV
#EPICS_DEV_SNAPSHOT=-rc2
#EPICS_DEV_SNAPSHOT=-rc2-DEV
#EPICS_DEV_SNAPSHOT=
EPICS_DEV_SNAPSHOT=
# No changes should be needed below here

View File

@@ -81,6 +81,8 @@ else
host:
endif
-include $(CONFIG)/RULES_FILE_TYPE
-include $(CONFIG)/RULES.Db
#---------------------------------------------------------------
@@ -122,8 +124,6 @@ LIBTARGETS += $(LIBNAME) $(INSTALL_LIBS) $(TESTLIBNAME) \
$(LOADABLE_SHRLIBNAME) $(INSTALL_LOADABLE_SHRLIBS)
-include $(CONFIG)/RULES_FILE_TYPE
# Main targets
install: buildInstall
@@ -260,7 +260,7 @@ YACCOPT ?= $($*_YACCOPT)
$(LIBNAME) $(TESTLIBNAME): $(LIBRARY_OBJS)
$(LIBNAME) $(TESTLIBNAME): $(LIB_PREFIX)%$(LIB_SUFFIX):
$(filter-out $(DLLSTUB_LIBNAME) $(TESTDLLSTUB_LIBNAME), $(LIBNAME) $(TESTLIBNAME)): $(LIB_PREFIX)%$(LIB_SUFFIX):
@$(RM) $@
$(ARCMD)
ifneq ($(strip $(RANLIB)),)
@@ -270,13 +270,13 @@ endif # RANLIB
$(SHRLIBNAME) $(DLLSTUB_LIBNAME) $(TESTSHRLIBNAME) $(TESTDLLSTUB_LIBNAME): \
$(LIBRARY_OBJS) $(LIBRARY_RESS) $(SHRLIB_DEPLIBS)
$(DLLSTUB_LIBNAME): $(SHRLIBNAME)
$(DLLSTUB_LIBNAME): $(SHRLIBNAME);
$(SHRLIBNAME): $(SHRLIB_PREFIX)%$(SHRLIB_SUFFIX):
@$(RM) $@
$(LINK.shrlib)
$(MT_DLL_COMMAND)
$(TESTDLLSTUB_LIBNAME): $(TESTSHRLIBNAME)
$(TESTDLLSTUB_LIBNAME): $(TESTSHRLIBNAME);
$(TESTSHRLIBNAME): $(SHRLIB_PREFIX)%$(SHRLIB_SUFFIX):
@$(RM) $@
$(LINK.shrlib)

View File

@@ -2,6 +2,9 @@
vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
#---------------------------------------------------------------
# Variable expansion
# Default settings
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl
@@ -24,3 +27,39 @@ expand_clean:
@$(RM) $(EXPANDED)
.PHONY : expand_clean
#---------------------------------------------------------------
# Assemblies (files assembled from snippets)
ASSEMBLE_TOOL ?= $(PERL) $(TOOLS)/assembleSnippets.pl
define COMMON_ASSEMBLY_template
$1_SNIPPETS += $$(foreach dir, .. $$(SRC_DIRS), \
$$(wildcard $$(dir)/$$($1_PATTERN)))
$(COMMON_DIR)/$1: $$($1_SNIPPETS)
$(ECHO) "Assembling common file $$@ from snippets"
@$(RM) $1
$(ASSEMBLE_TOOL) -o $1 $$^
@$(MV) $1 $$@
endef
$(foreach asy, $(COMMON_ASSEMBLIES), \
$(eval $(call COMMON_ASSEMBLY_template,$(strip $(asy)))))
define ASSEMBLY_template
$1_SNIPPETS += $$(foreach dir, .. $$(SRC_DIRS), \
$$(wildcard $$(dir)/$$($1_PATTERN)))
$1: $$($1_SNIPPETS)
$(ECHO) "Assembling file $$@ from snippets"
@$(RM) $$@
$(ASSEMBLE_TOOL) -o $$@ $$^
endef
$(foreach asy, $(ASSEMBLIES), \
$(eval $(call ASSEMBLY_template,$(strip $(asy)))))
define ASSEMBLY_DEP_template
$1$(DEP):
@echo $1: > $$@
endef
$(foreach asy, $(sort $(COMMON_ASSEMBLIES) $(ASSEMBLIES)), \
$(eval $(call ASSEMBLY_DEP_template,$(strip $(asy)))))

View File

@@ -12,9 +12,11 @@ include $(CONFIG)/os/CONFIG.Common.linuxCommon
ARCH_CLASS = x86_64
ARCH_DEP_CFLAGS = $(GNU_TUNE_CFLAGS)
ARCH_DEP_CPPFLAGS += -D_X86_64_
ARCH_DEP_CFLAGS += -m64
ARCH_DEP_LDFLAGS += -m64
OP_SYS_CFLAGS += -m64
OP_SYS_LDFLAGS += -m64
# If your crosscompiler name has a GNU target prefix like <gnutarget>-gcc,
# e.g. x86_64-redhat-linux-gcc, put a GNU_TARGET definition in

View File

@@ -12,3 +12,11 @@
# 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

@@ -12,7 +12,7 @@
# a) LD_LIBRARY_PATH must include the full absolute pathname to
# $(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH) when invoking base
# executables.
# b) Add the runtime path to SHRLIB_DEPLIB_DIRS and PROD_DEPLIB_DIRS, which
# b) Add the runtime path to SHRLIB_DEPLIB_DIRS and PROD_DEPLIB_DIRS, which
# will add the named directory to the list contained in the executables.
# c) Add the runtime path to /etc/ld.so.conf and run ldconfig
# to inform the system of the shared library location.
@@ -33,6 +33,10 @@ COMMANDLINE_LIBRARY = READLINE
#COMMANDLINE_LIBRARY = READLINE_CURSES
# Permit access to 64-bit file-systems
OP_SYS_CFLAGS += -D_FILE_OFFSET_BITS=64
# Uncomment the followings lines to build with CLANG instead of GCC.
#
#GNU = NO
@@ -49,7 +53,6 @@ OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
# Tune GNU compiler output for a specific cpu-type
# (e.g. generic, i386, i486, i586, or i686)
# Tune GNU compiler output for a specific 32-bit cpu-type
# (e.g. generic, native, i386, i686, pentium2/3/4, prescott, k6, athlon etc.)
GNU_TUNE_CFLAGS = -mtune=generic

View File

@@ -47,3 +47,8 @@ COMMANDLINE_LIBRARY = READLINE
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
# Tune GNU compiler output for a specific 64-bit cpu-type
# (e.g. generic, native, core2, nocona, k8, opteron, athlon64, barcelona etc.)
GNU_TUNE_CFLAGS = -mtune=generic

View File

@@ -4,17 +4,17 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Known Problems in R3.15.1</title>
<title>Known Problems in R3.15.3</title>
</head>
<body>
<h1 style="text-align: center">EPICS Base R3.15.1: Known Problems</h1>
<h1 style="text-align: center">EPICS Base R3.15.3: Known Problems</h1>
<p>Any patch files linked below should be applied at the root of the
base-3.15.1 tree. Download them, then use the GNU Patch program as
base-3.15.3 tree. Download them, then use the GNU Patch program as
follows:</p>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.1</b>
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.3</b>
% <b>patch -p0 &lt; <i>/path/to/</i>file.patch</b></pre></blockquote>
<p>The following significant problems have been reported with this
@@ -22,6 +22,19 @@ version of EPICS Base:</p>
<ul>
<li>See LaunchPad bug
<a href="https://bugs.launchpad.net/epics-base/+bug/1466129">#1466129</a>:
The feature that allows an IOC to bind to a single network interface is not
working correctly. The bug mentioned above contains a patch that has been
tested on Linux-64, a complete fix is expected for 3.15.4. Note that Windows
systems are not affected by this bug.</li>
<li>Parallel builds ("make -j") on native Windows are not working properly.
Builds tend to hang (saturating one core); interrupting and running make
again usually finishes the build. Limiting the number of parallel jobs using
something like "make -j8" also helps prevent this problem. Sequential builds
always work and are recommended for automated build environments.</li>
<li>64-bit Windows builds of the CAS library may not work with some compilers.
The code in <tt>src/legacy/gdd</tt> is currently incompatible with the LLP64
model that Windows uses for its 64-bit ABI.</li>

View File

@@ -1,6 +1,6 @@
Installation Instructions
EPICS Base Release 3.15.1
EPICS Base Release 3.15.3
--------------------------------------------------------------------------

View File

@@ -9,7 +9,7 @@
<BODY>
<CENTER>
<H1>Installation Instructions</H1>
<H2>EPICS Base Release 3.15.1</H2><BR>
<H2>EPICS Base Release 3.15.3</H2><BR>
</CENTER>
<HR>
<H3> Table of Contents</H3>

View File

@@ -3,16 +3,54 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>EPICS Base R3.15.2 Release Notes</title>
<title>EPICS Base R3.15.3 Release Notes</title>
</head>
<body lang="en">
<h1 align="center">EPICS Base Release 3.15.2</h1>
<h1 align="center">EPICS Base Release 3.15.3</h1>
<p style="color:red">This version of EPICS Base has not been released yet.</p>
<h2 align="center">Changes between 3.15.2 and 3.15.3</h2>
<!-- Insert new items immediately below here ... -->
<h3>Make the NTP Time provider optional on VxWorks</h3>
<p>Recent versions of VxWorks (sometime after VxWorks 6) provide facilities for
automatically synchronizing the OS clock time with an NTP server. The EPICS time
system used to assume that it had to provide time synchronization on VxWorks,
but now it tests for the existance of either of the two OS synchronization
threads before starting the NTP time provider. It is still possible to force the
NTP provider to be started even if the OS synchronization is running by defining
the environment variable <tt>EPICS_TS_FORCE_NTPTIME</tt> in the startup script
before loading the IOC's .munch file. Forcing may be necessary if the VxWorks
image is not correctly configured with the IP address of a local NTP server.</p>
<h3>Assembling files from numbered snippets</h3>
<p>A tool has been added that assembles file snippets specified on the
command line into a single output file, with sorting and replacing/adding of
snippets done based on their file names. The build system integration requires
the output file to be specified setting COMMON_ASSEMBLIES (arch independent)
or ASSEMBLIES (created by arch), then defining the snippets for each assembly
setting *_SNIPPETS (explicitly) or *_PATTERN (searched relative to all source
directories).
</p>
<h3>Clean up after GNU readline()</h3>
<p>If EPICS Base is built with readline support, any IOC that calls epicsExit()
from a thread other than the main thread is likely to leave the user's terminal
in a weird state, requiring the user to run something like 'stty sane' to clean
it up. This release patches the readline support code to clean up automatically
by registering an epicsAtExit() routine.</p>
<h3>Removed the last vestiges of RSET::get_value()</h3>
<p>The IOC has not called the get_value() routine in the RSET for a very long
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>
<!-- Insert new items immediately below here ... -->
<h3>Raised limit on link field length in database files</h3>

View File

@@ -60,11 +60,8 @@ responsible for these tasks in the past and are expected to continue in the
relevent roles unless the Release Manager designates otherwise:</p>
<dl>
<dt><strong>Release Manager</strong> (Andrew Johnson)</dt>
<dd>Responsible for the release</dd>
<dt><strong>Configuration Manager</strong> (Janet Anderson)</dt>
<dd>Responsible for committing version number updates and for
creating tarfiles</dd>
<dt><strong>Release Manager</strong> (Ralph Lange)</dt>
<dd>Responsible for managing and tagging the release</dd>
<dt><strong>Platform Developers</strong></dt>
<dd>Responsible for individual operating system platforms</dd>
<dt><strong>Application Developers</strong></dt>
@@ -134,42 +131,42 @@ relevent roles unless the Release Manager designates otherwise:</p>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Edit and commit changes to the EPICS version number file
configure/CONFIG_BASE_VERSION.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Tag the module in Bazaar, using these tag conventions:
<ul>
<li>
<tt>R3.15.1-pre<i>n</i></tt>
<tt>R3.15.3-pre<i>n</i></tt>
&mdash; pre-release tag
</li>
<li>
<tt>R3.15.1-rc<i>n</i></tt>
<tt>R3.15.3-rc<i>n</i></tt>
&mdash; release candidate tag, note the <tt>rc</tt> is now
lower-case</li>
</ul>
<blockquote><tt>
cd ~/base/mirror-3.15<br />
bzr tag R3.15.1-rc<i>n</i>
bzr tag R3.15.3-rc<i>n</i>
</tt></blockquote>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Export the tagged version into a tarfile. Note that this command
generates a gzipped tarfile directly from the repository:
<blockquote><tt>
cd ~/base<br />
bzr export --keywords=publish
--root=base-3.15.1-rc<i>n</i>
-r tag:R3.15.1-rc<i>n</i>
baseR3.15.1-rc<i>n</i>.tar.gz
mirror-3.15
--root=base-3.15.3-rc<i>n</i>
-r tag:R3.15.3-rc<i>n</i>
base-3.15.3-rc<i>n</i>.tar.gz
mirror-3.15
</tt></blockquote>
This requires that the Bazaar keywords plugin is installed and
configured properly.
@@ -177,14 +174,15 @@ relevent roles unless the Release Manager designates otherwise:</p>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Test the tarfile by extracting its contents and building it on at
least one supported platform.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Copy the tar file to the Base download area of the website.</td>
<td>Website Manager</td>
<td>If necessary recreate the tarfile following the instructions above.
Copy the tar file to the Base download area of the website</td>
</tr>
<tr>
<td>&nbsp;</td>
@@ -223,13 +221,6 @@ relevent roles unless the Release Manager designates otherwise:</p>
<td>Run the CA client side regression tests on all available host
platforms.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Platform Developers</td>
<td>Build and run the
<a href="https://launchpad.net/epics-base-tests">epics-base-tests</a>
suite on all available platforms.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Platform Developers</td>
@@ -279,32 +270,32 @@ relevent roles unless the Release Manager designates otherwise:</p>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Edit and commit changes to the EPICS version number file
configure/CONFIG_BASE_VERSION.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Tag the module in Bazaar:
<blockquote><tt>
cd ~/base/mirror-3.15<br />
bzr tag R3.15.1</i>
bzr tag R3.15.3</i>
</tt></blockquote>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Export the tagged version into a tarfile. Note that this command
generates a gzipped tarfile directly from the repository:
<blockquote><tt>
cd ~/base<br />
bzr export --keywords=publish
--root=base-3.15.1
-r tag:R3.15.1
baseR3.15.1.tar.gz
mirror-3.15
--root=base-3.15.3
-r tag:R3.15.3
base-3.15.3.tar.gz
mirror-3.15
</tt></blockquote>
This requires that the Bazaar keywords plugin is installed and
configured properly.
@@ -312,7 +303,7 @@ relevent roles unless the Release Manager designates otherwise:</p>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Release Manager</td>
<td>Test the tar file by extracting its contents and building it on at
least one supported platform</td>
</tr>
@@ -321,8 +312,9 @@ relevent roles unless the Release Manager designates otherwise:</p>
</tr>
<tr>
<td>&nbsp;</td>
<td>Configuration Manager</td>
<td>Copy the tar file to the Base download area of the website</td>
<td>Website Manager</td>
<td>If necessary recreate the tarfile following the instructions above.
Copy the tar file to the Base download area of the website</td>
</tr>
<tr>
<td>&nbsp;</td>

View File

@@ -209,6 +209,7 @@ $Date$</span></small></p>
<li><a href="#ca_pend_event">ca_poll</a></li>
<li><a href="#ca_puser">ca_puser</a></li>
<li><a href="#ca_put">ca_put</a></li>
<li><a href="#ca_put">ca_put_callback</a></li>
<li><a href="#ca_set_puser">ca_set_puser</a></li>
<li><a href="#ca_signal">ca_signal</a></li>
<li><a href="#ca_sg_block">ca_sg_block</a></li>
@@ -223,7 +224,7 @@ $Date$</span></small></p>
<li><a href="#ca_test_io">ca_test_io</a></li>
<li><a href="#ca_write_access">ca_write_access</a></li>
<li><a href="#ca_state">channel_state</a></li>
<li><a href="#dbr_size[]">dbr_size[]</a></li>
<li><a href="#dbr_size">dbr_size[]</a></li>
<li><a href="#dbr_size_n">dbr_size_n</a></li>
<li><a href="#dbr_value_size">dbr_value_size[]</a></li>
<li><a href="#dbr_type_t">dbr_type_to_text</a></li>
@@ -3831,7 +3832,7 @@ specified channel and boolean false otherwise.</p>
channel and boolean false otherwise</dd>
</dl>
<h3><code><a name="dbr_size[]">dbr_size[]</a></code></h3>
<h3><code><a name="dbr_size">dbr_size[]</a></code></h3>
<pre>#include &lt;db_access.h&gt;
extern unsigned dbr_size[/* TYPE */];</pre>
@@ -3953,11 +3954,12 @@ int ca_sg_create ( CA_SYNC_GID *PGID );</pre>
<p>A synchronous group can be used to guarantee that a set of channel access
requests have completed. Once a synchronous group has been created then channel
access get and put requests may be issued within it using <code>ca_sg_get()</code> and
<code>ca_sg_put()</code> respectively. The routines <code>ca_sg_block()</code> and <code>ca_sg_test()</code> can be
access get and put requests may be issued within it using
<code>ca_sg_array_get()</code> and <code>ca_sg_array_put()</code> respectively.
The routines <code>ca_sg_block()</code> and <code>ca_sg_test()</code> can be
used to block for and test for completion respectively. The routine
<code>ca_sg_reset()</code> is used to discard knowledge of old requests which have timed out
and in all likelihood will never be satisfied.</p>
<code>ca_sg_reset()</code> is used to discard knowledge of old requests which
have timed out and in all likelihood will never be satisfied.</p>
<p>Any number of asynchronous groups can have application requested operations
outstanding within them at any given time.</p>
@@ -4131,16 +4133,20 @@ status = ca_sg_reset(gid);</pre>
<h3><code><a name="ca_sg_put">ca_sg_array_put()</a></code></h3>
<pre>#include &lt;cadef.h&gt;
int ca_sg_put ( CA_SYNC_GID GID, chtype TYPE,
chid CHID, void *PVALUE );
int ca_sg_array_put ( CA_SYNC_GID GID, chtype TYPE,
unsigned long COUNT, chid CHID, void *PVALUE );</pre>
<p>Write a value, or array of values, to a channel and increment the
outstanding request count of a synchronous group. The <code>ca_sg_array_put()</code>
functionality is implemented using <code>ca_array_put_callback()</code>.</p>
<p>Write a value, or array of values, to a channel and increment the outstanding
request count of a synchronous group. The <code>ca_sg_put()</code> and
<code>ca_sg_array_put()</code> functionality is implemented using
<code>ca_array_put_callback()</code>.</p>
<p>All remote operation requests such as the above are accumulated (buffered)
and not forwarded to the server until one of <code>ca_flush_io()</code>, <code>ca_pend_io()</code>,
<code>ca_pend_event()</code>, or <code>ca_sg_block()</code> are called. This allows several requests to be
and not forwarded to the server until one of <code>ca_flush_io()</code>,
<code>ca_pend_io()</code>, <code>ca_pend_event()</code>, or
<code>ca_sg_block()</code> are called. This allows several requests to be
efficiently sent in one message.</p>
<p>If a connection is lost and then resumed outstanding puts are not
@@ -4193,6 +4199,8 @@ reissued.</p>
<h3><code><a name="ca_sg_get">ca_sg_array_get()</a></code></h3>
<pre>#include &lt;cadef.h&gt;
int ca_sg_get ( CA_SYNC_GID GID, chtype TYPE,
chid CHID, void *PVALUE );
int ca_sg_array_get ( CA_SYNC_GID GID,
chtype TYPE, unsigned long COUNT,
chid CHID, void *PVALUE );</pre>
@@ -4200,16 +4208,19 @@ int ca_sg_array_get ( CA_SYNC_GID GID,
<h4>Description</h4>
<p>Read a value from a channel and increment the outstanding request count of a
synchronous group. The <code>ca_sg_array_get()</code> functionality is implemented using
synchronous group. The <code>ca_sg_get()</code> and
<code>ca_sg_array_get()</code> functionality is implemented using
<code>ca_array_get_callback()</code>.</p>
<p>The values written into your program's variables by <code>ca_sg_get()</code> should not be
referenced by your program until ECA_NORMAL has been received from <code>ca_sg_block()</code>,
or until <code>ca_sg_test()</code> returns ECA_IODONE.</p>
<p>The values written into your program's variables by <code>ca_sg_get()</code>
or <code>ca_sg_array_get()</code> should not be referenced by your program until
ECA_NORMAL has been received from <code>ca_sg_block()</code>, or until
<code>ca_sg_test()</code> returns ECA_IODONE.</p>
<p>All remote operation requests such as the above are accumulated (buffered)
and not forwarded to the server until one of <code>ca_flush_io()</code>, <code>ca_pend_io()</code>,
<code>ca_pend_event()</code>, or <code>ca_sg_block()</code> are called. This allows several requests to be
and not forwarded to the server until one of <code>ca_flush_io()</code>,
<code>ca_pend_io()</code>, <code>ca_pend_event()</code>, or
<code>ca_sg_block()</code> are called. This allows several requests to be
efficiently sent in one message.</p>
<p>If a connection is lost and then resumed outstanding gets are not

View File

@@ -652,7 +652,7 @@ not follow this pattern, but are still printable strings.
=item [1] R3.15 Channel Access Reference Manual by Jeffrey O. Hill
L<http://www.aps.anl.gov/epics/base/R3-15/0-docs/CAref.html>
L<http://www.aps.anl.gov/epics/base/R3-15/2-docs/CAref.html>
=back

View File

@@ -323,7 +323,7 @@ inline int aitString::installBuf(const char* pString, unsigned strLengthIn, unsi
inline int aitString::installBuf(const char* pString)
{
unsigned strLengthIn = strlen(pString);
unsigned strLengthIn = (unsigned) strlen(pString);
return this->installBuf(pString, strLengthIn, strLengthIn+1u);
}
@@ -350,7 +350,7 @@ inline int aitString::installConstBuf(const char* pString, unsigned strLengthIn,
inline int aitString::installConstBuf(const char* pString)
{
unsigned strLengthIn = strlen(pString);
unsigned strLengthIn = (unsigned) strlen(pString);
return this->installConstBuf(pString, strLengthIn, strLengthIn+1u);
}
@@ -378,7 +378,7 @@ inline int aitString::installConstImortalBuf(const char* pString,
inline int aitString::installConstImortalBuf(const char* pString)
{
unsigned strLengthIn = strlen(pString);
unsigned strLengthIn = (unsigned) strlen(pString);
return this->installConstImortalBuf(pString, strLengthIn, strLengthIn+1u);
}
@@ -396,7 +396,7 @@ inline int aitString::copy(const char* pString, unsigned stringLength)
inline int aitString::copy(const char* p)
{
return this->copy(p, strlen(p));
return this->copy(p, (unsigned) strlen(p));
}
inline int aitString::copy(const aitString* p)
@@ -436,7 +436,7 @@ inline aitString::aitString(void)
inline aitString::aitString(const char* p, aitStrType typeIn)
{
unsigned strLengthIn = strlen(p);
unsigned strLengthIn = (unsigned) strlen(p);
this->init(p, typeIn, strLengthIn, strLengthIn+1u);
}

View File

@@ -54,6 +54,7 @@ typedef struct cbQueueSet {
epicsEventId semWakeUp;
epicsRingPointerId queue;
int queueOverflow;
int shutdown;
int threadsConfigured;
int threadsRunning;
} cbQueueSet;
@@ -73,7 +74,8 @@ static epicsTimerQueueId timerQueue;
enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
static volatile enum ctl cbCtl;
static epicsEventId startStopEvent;
static void *exitCallback;
static int callbackIsInit;
/* Static data */
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
@@ -89,7 +91,7 @@ static int priorityValue[NUM_CALLBACK_PRIORITIES] = {0, 1, 2};
int callbackSetQueueSize(int size)
{
if (startStopEvent) {
if (callbackIsInit) {
errlogPrintf("Callback system already initialized\n");
return -1;
}
@@ -99,7 +101,7 @@ int callbackSetQueueSize(int size)
int callbackParallelThreads(int count, const char *prio)
{
if (startStopEvent) {
if (callbackIsInit) {
errlogPrintf("Callback system already initialized\n");
return -1;
}
@@ -149,12 +151,13 @@ int callbackParallelThreads(int count, const char *prio)
static void callbackTask(void *arg)
{
cbQueueSet *mySet = &callbackQueue[*(int*)arg];
int prio = *(int*)arg;
cbQueueSet *mySet = &callbackQueue[prio];
taskwdInsert(0, NULL, NULL);
epicsEventSignal(startStopEvent);
while(TRUE) {
while(!mySet->shutdown) {
void *ptr;
if (epicsRingPointerIsEmpty(mySet->queue))
epicsEventMustWait(mySet->semWakeUp);
@@ -163,42 +166,52 @@ static void callbackTask(void *arg)
CALLBACK *pcallback = (CALLBACK *)ptr;
if(!epicsRingPointerIsEmpty(mySet->queue))
epicsEventMustTrigger(mySet->semWakeUp);
if (ptr == &exitCallback) goto shutdown;
mySet->queueOverflow = FALSE;
(*pcallback->callback)(pcallback);
}
}
shutdown:
mySet->threadsRunning--;
if(!epicsAtomicDecrIntT(&mySet->threadsRunning))
epicsEventSignal(startStopEvent);
taskwdRemove(0);
epicsEventSignal(startStopEvent);
}
void callbackShutdown(void)
void callbackStop(void)
{
int i;
if (cbCtl == ctlExit) return;
cbCtl = ctlExit;
/* sequential shutdown of workers */
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
while (callbackQueue[i].threadsRunning) {
if(epicsRingPointerPush(callbackQueue[i].queue, &exitCallback)) {
epicsEventSignal(callbackQueue[i].semWakeUp);
epicsEventWait(startStopEvent);
} else {
epicsThreadSleep(0.05);
}
}
assert(callbackQueue[i].threadsRunning==0);
epicsEventDestroy(callbackQueue[i].semWakeUp);
epicsRingPointerDelete(callbackQueue[i].queue);
callbackQueue[i].shutdown = 1;
epicsEventSignal(callbackQueue[i].semWakeUp);
}
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
while (epicsAtomicGetIntT(&mySet->threadsRunning)) {
epicsEventSignal(mySet->semWakeUp);
epicsEventWaitWithTimeout(startStopEvent, 0.1);
}
}
}
void callbackCleanup(void)
{
int i;
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
assert(epicsAtomicGetIntT(&mySet->threadsRunning)==0);
epicsEventDestroy(mySet->semWakeUp);
epicsRingPointerDelete(mySet->queue);
}
epicsTimerQueueRelease(timerQueue);
epicsEventDestroy(startStopEvent);
startStopEvent = NULL;
callbackIsInit = 0;
memset(callbackQueue, 0, sizeof(callbackQueue));
}
@@ -208,10 +221,14 @@ void callbackInit(void)
int j;
char threadName[32];
if (startStopEvent)
if (callbackIsInit) {
errlogMessage("Warning: callbackInit called again before callbackCleanup\n");
return;
}
callbackIsInit = 1;
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
if(!startStopEvent)
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
cbCtl = ctlRun;
timerQueue = epicsTimerQueueAllocate(0, epicsThreadPriorityScanHigh);
@@ -239,7 +256,7 @@ void callbackInit(void)
cantProceed("Failed to spawn callback thread %s\n", threadName);
} else {
epicsEventWait(startStopEvent);
callbackQueue[i].threadsRunning++;
epicsAtomicIncrIntT(&callbackQueue[i].threadsRunning);
}
}
}

View File

@@ -57,7 +57,8 @@ typedef void (*CALLBACKFUNC)(struct callbackPvt*);
( (USER) = (void *)((CALLBACK *)(PCALLBACK))->user )
epicsShareFunc void callbackInit(void);
epicsShareFunc void callbackShutdown(void);
epicsShareFunc void callbackStop(void);
epicsShareFunc void callbackCleanup(void);
epicsShareFunc int callbackRequest(CALLBACK *pCallback);
epicsShareFunc void callbackSetProcess(
CALLBACK *pcallback, int Priority, void *pRec);

View File

@@ -1228,20 +1228,20 @@ long dbPut(DBADDR *paddr, short dbrType,
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
nRequest, no_elements, offset);
}
if (status) goto done;
/* update array info */
if (paddr->pfldDes->special == SPC_DBADDR &&
if (!status &&
paddr->pfldDes->special == SPC_DBADDR &&
prset && prset->put_array_info) {
status = prset->put_array_info(paddr, nRequest);
}
if (status) goto done;
/* check if special processing is required */
/* Always do special processing if needed */
if (special) {
status = dbPutSpecial(paddr,1);
if (status) goto done;
long status2 = dbPutSpecial(paddr, 1);
if (status2) goto done;
}
if (status) goto done;
/* Propagate monitor events for this field, */
/* unless the field is VAL and PP is true. */

View File

@@ -100,7 +100,7 @@ static int dbca_chan_count;
* that has been deleted.
*
* Just a few words about handling dbCaRemoveLink because this is when
* it is essential that nothing trys to use a caLink that has been freed.
* it is essential that nothing tries to use a caLink that has been freed.
*
* dbCaRemoveLink is called when links are being modified. This is only
* done with the dbScan mechanism guranteeing that nothing from
@@ -119,19 +119,16 @@ static int dbca_chan_count;
* dbCaTask issues a ca_clear_channel and then frees the caLink.
*
* If any channel access callback gets called before the ca_clear_channel
* it finds pca->plink=0 and does nothing. Once ca_clear_channel
* it finds pca->plink==0 and does nothing. Once ca_clear_channel
* is called no other callback for this caLink will be called.
*
* dbCaPutLinkCallback causes an additional complication because
* when dbCaRemoveLink is called the callback may not have occured.
* What is done is the following:
* If callback has not occured dbCaRemoveLink sets plinkPutCallback=plink
* If putCallback is called before dbCaTask calls ca_clear_channel
* it does NOT call the users callback.
* dbCaTask calls the users callback passing plinkPutCallback AFTER
* it has called ca_clear_channel
* Thus the users callback will get called exactly once.
*/
* If putComplete sees plink==0 it will not call the user's code.
* If pca->putCallback is non-zero, dbCaTask will call the
* user's callback AFTER it has called ca_clear_channel.
* Thus the user's callback will get called exactly once.
*/
static void addAction(caLink *pca, short link_action)
{
@@ -168,7 +165,7 @@ static void addAction(caLink *pca, short link_action)
static void dbCaLinkFree(caLink *pca)
{
dbCaCallback callback;
struct link *plinkPutCallback = 0;
void *userPvt = 0;
if (pca->chid) {
ca_clear_channel(pca->chid);
@@ -176,8 +173,7 @@ static void dbCaLinkFree(caLink *pca)
}
callback = pca->putCallback;
if (callback) {
plinkPutCallback = pca->plinkPutCallback;
pca->plinkPutCallback = 0;
userPvt = pca->putUserPvt;
pca->putCallback = 0;
pca->putType = 0;
}
@@ -188,12 +184,12 @@ static void dbCaLinkFree(caLink *pca)
free(pca->pvname);
epicsMutexDestroy(pca->lock);
free(pca);
if (callback) callback(plinkPutCallback);
if (callback) callback(userPvt);
}
void dbCaCallbackProcess(void *usrPvt)
void dbCaCallbackProcess(void *userPvt)
{
struct link *plink = (struct link *)usrPvt;
struct link *plink = (struct link *)userPvt;
dbCommon *pdbCommon = plink->value.pv_link.precord;
dbScanLock(pdbCommon);
@@ -223,11 +219,6 @@ void dbCaShutdown(void)
}
}
static void dbCaExit(void *arg)
{
dbCaShutdown();
}
void dbCaLinkInitIsolated(void)
{
if (!workListLock)
@@ -235,7 +226,6 @@ void dbCaLinkInitIsolated(void)
if (!workListEvent)
workListEvent = epicsEventMustCreate(epicsEventEmpty);
dbCaCtl = ctlExit;
epicsAtExit(dbCaExit, NULL);
}
void dbCaLinkInit(void)
@@ -297,8 +287,6 @@ void dbCaRemoveLink(struct link *plink)
epicsMutexMustLock(pca->lock);
pca->plink = 0;
plink->value.pv_link.pvt = 0;
if (pca->putCallback)
pca->plinkPutCallback = plink;
/* Unlock before addAction or dbCaTask might free first */
epicsMutexUnlock(pca->lock);
addAction(pca, CA_CLEAR_CHANNEL);
@@ -800,7 +788,7 @@ static void exceptionCallback(struct exception_handler_args args)
}
}
static void putCallback(struct event_handler_args arg)
static void putComplete(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
struct link *plink;
@@ -963,7 +951,7 @@ static void dbCaTask(void *arg)
status = ca_array_put_callback(
pca->dbrType, pca->nelements,
pca->chid, pca->pputNative,
putCallback, pca);
putComplete, pca);
} else {
status = ECA_PUTFAIL;
}
@@ -986,7 +974,7 @@ static void dbCaTask(void *arg)
status = ca_array_put_callback(
DBR_STRING, 1,
pca->chid, pca->pputString,
putCallback, pca);
putComplete, pca);
} else {
status = ECA_PUTFAIL;
}

View File

@@ -63,7 +63,6 @@ typedef struct caLink
short putType;
dbCaCallback putCallback;
void *putUserPvt;
struct link *plinkPutCallback;
/* The following are for access to additional attributes*/
char gotAttributes;
dbCaCallback getAttributes;

View File

@@ -154,6 +154,8 @@ epicsShareFunc long dbChannelTest(const char *name);
epicsShareFunc dbChannel * dbChannelCreate(const char *name);
epicsShareFunc long dbChannelOpen(dbChannel *chan);
/*Following is also defined in db_convert.h*/
epicsShareExtern unsigned short dbDBRnewToDBRold[];
/* In the following macros pChan is dbChannel* */
@@ -175,6 +177,9 @@ epicsShareFunc long dbChannelOpen(dbChannel *chan);
/* evaluates to short */
#define dbChannelExportType(pChan) ((pChan)->addr.dbr_field_type)
/* evaluates to short */
#define dbChannelExportCAType(pChan) (dbDBRnewToDBRold[dbChannelExportType(pChan)])
/* evaluates to short */
#define dbChannelFieldSize(pChan) ((pChan)->addr.field_size)
@@ -185,7 +190,7 @@ epicsShareFunc long dbChannelOpen(dbChannel *chan);
#define dbChannelFinalFieldType(pChan) ((pChan)->final_type)
/* evaluates to short */
#define dbChannelFinalExportType(pChan) ((pChan)->final_type)
#define dbChannelFinalCAType(pChan) (dbDBRnewToDBRold[(pChan)->final_type])
/* evaluates to short */
#define dbChannelFinalFieldSize(pChan) ((pChan)->final_field_size)

View File

@@ -159,7 +159,7 @@ void dbChannelIO::show (
if ( level > 0u ) {
printf ( " type %s, element count %li, field at %p\n",
dbf_type_to_text ( dbChannelExportType ( this->dbch ) ),
dbf_type_to_text ( dbChannelExportCAType ( this->dbch ) ),
dbChannelElements ( this->dbch ),
dbChannelField ( this->dbch ) );
if ( level > 1u ) {
@@ -206,7 +206,7 @@ short dbChannelIO::nativeType (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return dbChannelExportType( this->dbch );
return dbChannelExportCAType( this->dbch );
}
void * dbChannelIO::operator new ( size_t size,

View File

@@ -979,6 +979,7 @@ static void event_task (void *pParm)
{
struct event_user * const evUser = (struct event_user *) pParm;
struct event_que * ev_que;
unsigned char pendexit;
/* init hook */
if (evUser->init_func) {
@@ -1020,9 +1021,10 @@ static void event_task (void *pParm)
event_read (ev_que);
epicsMutexMustLock ( evUser->lock );
}
pendexit = evUser->pendexit;
epicsMutexUnlock ( evUser->lock );
} while ( ! evUser->pendexit );
} while( ! pendexit );
epicsMutexDestroy(evUser->firstque.writelock);

View File

@@ -233,6 +233,17 @@ static void dbtpnCallFunc(const iocshArgBuf *args)
static const iocshFuncDef dbNotifyDumpFuncDef = {"dbNotifyDump",0,0};
static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { dbNotifyDump();}
/* dbPutAttribute */
static const iocshArg dbPutAttrArg0 = { "record type",iocshArgString};
static const iocshArg dbPutAttrArg1 = { "attribute name",iocshArgString};
static const iocshArg dbPutAttrArg2 = { "value",iocshArgString};
static const iocshArg * const dbPutAttrArgs[] =
{&dbPutAttrArg0, &dbPutAttrArg1, &dbPutAttrArg2};
static const iocshFuncDef dbPutAttrFuncDef =
{"dbPutAttribute",3,dbPutAttrArgs};
static void dbPutAttrCallFunc(const iocshArgBuf *args)
{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);}
/* tpn */
static const iocshArg tpnArg0 = { "record name",iocshArgString};
static const iocshArg tpnArg1 = { "value",iocshArgString};
@@ -405,6 +416,7 @@ void dbIocRegister(void)
iocshRegister(&pftFuncDef,pftCallFunc);
iocshRegister(&dbtpnFuncDef,dbtpnCallFunc);
iocshRegister(&dbNotifyDumpFuncDef,dbNotifyDumpCallFunc);
iocshRegister(&dbPutAttrFuncDef,dbPutAttrCallFunc);
iocshRegister(&tpnFuncDef,tpnCallFunc);
iocshRegister(&dblsrFuncDef,dblsrCallFunc);
iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc);

View File

@@ -151,7 +151,7 @@ static void buildScanLists(void);
static void addToList(struct dbCommon *precord, scan_list *psl);
static void deleteFromList(struct dbCommon *precord, scan_list *psl);
void scanShutdown(void)
void scanStop(void)
{
int i;
@@ -168,16 +168,16 @@ void scanShutdown(void)
scanOnce((dbCommon *)&exitOnce);
epicsEventWait(startStopEvent);
}
void scanCleanup(void)
{
deletePeriodic();
ioscanDestroy();
epicsRingPointerDelete(onceQ);
epicsEventDestroy(startStopEvent);
epicsEventDestroy(onceSem);
onceSem = startStopEvent = NULL;
free(periodicTaskId);
papPeriodic = NULL;
periodicTaskId = NULL;
@@ -187,7 +187,8 @@ long scanInit(void)
{
int i;
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
if(!startStopEvent)
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
scanCtl = ctlPause;
initPeriodic();
@@ -639,7 +640,8 @@ static void initOnce(void)
if ((onceQ = epicsRingPointerCreate(onceQueueSize)) == NULL) {
cantProceed("initOnce: Ring buffer create failed\n");
}
onceSem = epicsEventMustCreate(epicsEventEmpty);
if(!onceSem)
onceSem = epicsEventMustCreate(epicsEventEmpty);
onceTaskId = epicsThreadCreate("scanOnce",
epicsThreadPriorityScanLow + nPeriodic,
epicsThreadGetStackSize(epicsThreadStackBig), onceTask, 0);

View File

@@ -46,7 +46,8 @@ struct dbCommon;
epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
epicsShareFunc void scanShutdown(void);
epicsShareFunc void scanStop(void);
epicsShareFunc void scanCleanup(void);
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
epicsShareFunc void postEvent(EVENTPVT epvt);

View File

@@ -334,7 +334,6 @@ long dbpf(const char *pname,const char *pvalue)
{
DBADDR addr;
long status;
epicsUInt16 value;
short dbrType;
size_t n = 1;
@@ -346,16 +345,7 @@ long dbpf(const char *pname,const char *pvalue)
if (nameToAddr(pname, &addr))
return -1;
/* For enumerated types must allow for ENUM rather than string */
/* If entire field is digits then use DBR_ENUM else DBR_STRING */
if (addr.dbr_field_type == DBR_ENUM && *pvalue &&
strspn(pvalue,"0123456789") == strlen(pvalue)) {
sscanf(pvalue, "%hu", &value);
pvalue = (char *) &value;
dbrType = DBR_ENUM;
}
else if (addr.no_elements > 1 &&
if (addr.no_elements > 1 &&
(addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) {
dbrType = addr.dbr_field_type;
n = strlen(pvalue) + 1;

View File

@@ -99,34 +99,21 @@
#define oldDBR_STSACK_STRING oldDBR_PUT_ACKS + 1
#define oldDBR_CLASS_NAME oldDBR_STSACK_STRING + 1
/*Following is defined in db_convert.h*/
extern unsigned short dbDBRnewToDBRold[DBR_ENUM+1];
typedef char DBSTRING[MAX_STRING_SIZE];
struct dbChannel * dbChannel_create(const char *pname)
{
dbChannel *chan = dbChannelCreate(pname);
short ftype;
if (!chan)
return NULL;
ftype = chan->addr.dbr_field_type;
if (INVALID_DB_REQ(ftype)) {
if (INVALID_DB_REQ(dbChannelExportType(chan)) ||
dbChannelOpen(chan)) {
dbChannelDelete(chan);
return NULL;
}
if (dbChannelOpen(chan)) {
dbChannelDelete(chan);
return NULL;
}
/* Convert final_type to CA's type mapping */
chan->final_type = dbDBRnewToDBRold[chan->final_type];
return chan;
}

View File

@@ -49,7 +49,7 @@ int gft(const char *pname)
precord = dbChannelRecord(chan);
elements = dbChannelElements(chan);
type = dbChannelExportType(chan);
type = dbChannelExportCAType(chan);
printf(" Record Name: %s\n", precord->name);
printf("Record Address: 0x%p\n", precord);
@@ -103,7 +103,7 @@ int pft(const char *pname, const char *pvalue)
precord = dbChannelRecord(chan);
elements = dbChannelElements(chan);
type = dbChannelExportType(chan);
type = dbChannelExportCAType(chan);
printf(" Record Name: %s\n", precord->name);
printf("Record Address: 0x%p\n", precord);

View File

@@ -132,7 +132,7 @@ const char *initHookName(int state)
"initHookAfterInterruptAccept",
"initHookAtEnd"
};
if (state < 0 || state > NELEMENTS(stateName)) {
if (state < 0 || state >= NELEMENTS(stateName)) {
return "Not an initHookState";
}
return stateName[state];

View File

@@ -309,11 +309,11 @@ static void getMaxRangeValues(short field_type, double *pupper_limit,
{
switch(field_type){
case DBF_CHAR:
*pupper_limit = -128.0;
*plower_limit = 127.0;
*pupper_limit = (double) CHAR_MAX;
*plower_limit = (double) CHAR_MIN;
break;
case DBF_UCHAR:
*pupper_limit = 255.0;
*pupper_limit = (double) UCHAR_MAX;
*plower_limit = 0.0;
break;
case DBF_SHORT:

View File

@@ -184,7 +184,8 @@ MAIN(callbackParallelTest)
free(pcbt[i]);
}
callbackShutdown();
callbackStop();
callbackCleanup();
return testDone();
}

View File

@@ -181,7 +181,8 @@ MAIN(callbackTest)
free(pcbt[i]);
}
callbackShutdown();
callbackStop();
callbackCleanup();
return testDone();
}

View File

@@ -1 +0,0 @@
record(ai, "somename") {}

View File

@@ -73,15 +73,20 @@ static int yyreset(void)
{whitespace} ;
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
yyerror("Newline in string, closing quote missing");
yyerrorAbort("Newline in string, closing quote missing");
}
. {
char message[40];
YY_BUFFER_STATE *dummy=0;
sprintf(message,"Invalid character '%c'",yytext[0]);
yyerror(message);
if (isprint((int) yytext[0])) {
sprintf(message, "Invalid character '%c'", yytext[0]);
}
else {
sprintf(message, "Invalid character 0x%2.2x", yytext[0]);
}
yyerrorAbort(message);
/*The following suppresses compiler warning messages*/
if(FALSE) yyunput('c',(unsigned char *) message);
if(FALSE) yy_switch_to_buffer(*dummy);

View File

@@ -12,6 +12,7 @@
/*The routines in this module are serially reusable NOT reentrant*/
#include <ctype.h>
#include <epicsStdlib.h>
#include <stddef.h>
#include <stdio.h>

View File

@@ -47,7 +47,7 @@
int dbStaticDebug = 0;
static char *pNullString = "";
#define messagesize 100
#define messagesize 276
#define RPCL_LEN INFIX_TO_POSTFIX_SIZE(80)
static char *ppstring[5]={"NPP","PP","CA","CP","CPP"};
@@ -604,7 +604,10 @@ DBENTRY * dbAllocEntry(dbBase *pdbbase)
void dbFreeEntry(DBENTRY *pdbentry)
{
if(pdbentry->message) free((void *)pdbentry->message);
if (!pdbentry)
return;
if (pdbentry->message)
free((void *)pdbentry->message);
dbmfFree(pdbentry);
}
@@ -1198,7 +1201,7 @@ long dbPutRecordAttribute(
pnew = dbCalloc(1,sizeof(dbRecordAttribute));
if(pattribute) {
ellInsert(&precordType->attributeList,&pattribute->node,
ellInsert(&precordType->attributeList,pattribute->node.previous,
&pnew->node);
} else {
ellAdd(&precordType->attributeList,&pnew->node);
@@ -1226,17 +1229,27 @@ long dbGetAttributePart(DBENTRY *pdbentry, const char **ppname)
const char *pname = *ppname;
dbRecordAttribute *pattribute;
if (!precordType) return S_dbLib_recordTypeNotFound;
if (!precordType)
return S_dbLib_recordTypeNotFound;
pattribute = (dbRecordAttribute *)ellFirst(&precordType->attributeList);
while (pattribute) {
size_t nameLen = strlen(pattribute->name);
int compare = strncmp(pattribute->name, pname, nameLen);
int ch = pname[nameLen];
if (compare == 0 && !(ch == '_' || isalnum(ch))) {
pdbentry->pflddes = pattribute->pdbFldDes;
pdbentry->pfield = pattribute->value;
*ppname = &pname[nameLen];
return 0;
if (compare == 0) {
int ch = pname[nameLen];
if (ch != '_' && !isalnum(ch)) {
/* Any other character can't be in the attribute name */
pdbentry->pflddes = pattribute->pdbFldDes;
pdbentry->pfield = pattribute->value;
*ppname = &pname[nameLen];
return 0;
}
if (strlen(pname) > nameLen) {
compare = -1;
}
}
if (compare >= 0) break;
pattribute = (dbRecordAttribute *)ellNext(&pattribute->node);

View File

@@ -30,7 +30,7 @@ typedef struct rset { /* record support entry table */
RECSUPFUN init_record; /*init record */
RECSUPFUN process; /*process record */
RECSUPFUN special; /*special processing */
RECSUPFUN get_value; /*get value field */
RECSUPFUN get_value; /*no longer used */
RECSUPFUN cvt_dbaddr; /*cvt dbAddr */
RECSUPFUN get_array_info;
RECSUPFUN put_array_info;
@@ -52,21 +52,12 @@ typedef struct rset { /* record support entry table */
#define S_rec_outMem (M_recSup| 3) /*Out of Memory*/
/* Definition os structure for routine get_value */
typedef struct valueDes {
long field_type;
long no_elements;
void * pvalue;
}valueDes;
/************************************************************************
* report(FILE fp,void *precord);
* init();
* init_record(precord,pass);
* process(void *precord);
* special(struct dbAddr *paddr, after);
* get_value(precord,struct valueDes *p);
* cvt_dbaddr(struct dbAddr *paddr);
* get_array_info(paddr,long *no_elements,long *offset);
* put_array_info(paddr,nNew);

View File

@@ -24,7 +24,7 @@ accepted by the EPICS IOC's dbLoadTemplate command.</p>
<h2>Command Syntax:</h2>
<pre>msi -V -g -o<i>outfile</i> -I<i>dir</i> -M<i>subs</i> -S<i>subfile</i> <i>template</i></pre>
<pre>msi -V -g -D -o<i>outfile</i> -I<i>dir</i> -M<i>subs</i> -S<i>subfile</i> <i>template</i></pre>
<p>All parameters are optional. The -o, -I, -M, and -S switches may be
separated from their associated value string by spaces if desired. Output will
@@ -46,6 +46,13 @@ be written to stdout unless the -o option is given.</p>
this was the behavior of previous versions of msi, but it does not follow
common scoping rules and is discouraged.</dd>
<dt><tt>-D</tt></dt>
<dd>Output dependency information suitable for including by a Makefile to
stdout instead of performing the macro substitutions. The <tt>-o</tt> option
must be given to specify the target name for the dependency rules. Other
options should be given exactly as will be used in the macro substitution
process.</dd>
<dt><tt>-o</tt> <i>file</i></dt>
<dd>Output will be written to the specifed file rather than to the standard
output.</dd>

View File

@@ -607,7 +607,8 @@ static void initialProcess(void)
/*
* Shutdown processing.
* set DB_LINK and CA_LINK to PV_LINK
* Delete record scans
*/
static void doCloseLinks(dbRecordType *pdbRecordType, dbCommon *precord,
void *user)
@@ -678,8 +679,15 @@ int iocShutdown(void)
if (iocState == iocVirgin || iocState == iocStopped) return 0;
iterateRecords(doCloseLinks, NULL);
if (iocBuildMode==buildIsolated) {
scanShutdown();
callbackShutdown();
/* stop and "join" threads */
scanStop();
callbackStop();
}
dbCaShutdown();
if (iocBuildMode==buildIsolated) {
/* free resources */
scanCleanup();
callbackCleanup();
iterateRecords(doFreeRecord, NULL);
dbLockCleanupRecords(pdbbase);
asShutdown();

View File

@@ -1255,7 +1255,7 @@ static void claim_ciu_reply ( struct channel_in_use * pciu )
}
status = cas_copy_in_header (
pciu->client, CA_PROTO_CREATE_CHAN, 0u,
dbChannelFinalExportType(pciu->dbch), nElem, pciu->cid,
dbChannelFinalCAType(pciu->dbch), nElem, pciu->cid,
pciu->sid, NULL );
if ( status == ECA_NORMAL ) {
cas_commit_msg ( pciu->client, 0u );
@@ -1301,7 +1301,7 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
}
DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
pName, dbChannelExportType(dbch), dbChannelElements(dbch)) );
pName, dbChannelCAType(dbch), dbChannelElements(dbch)) );
pciu = casCreateChannel (
client,
@@ -2348,7 +2348,7 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
else {
count = (ca_uint16_t) dbChannelFinalElements(dbch);
}
type = (ca_uint16_t) dbChannelFinalExportType(dbch);
type = (ca_uint16_t) dbChannelFinalCAType(dbch);
}
SEND_LOCK ( client );

View File

@@ -52,9 +52,9 @@ void SingletonUntyped :: incrRefCount ( PBuild pBuild )
void SingletonUntyped :: decrRefCount ( PDestroy pDestroy )
{
assert ( _refCount > 0 );
epicsGuard < epicsMutex >
guard ( *pEPICSSigletonMutex );
assert ( _refCount > 0 );
_refCount--;
if ( _refCount == 0 ) {
( *pDestroy ) ( _pInstance );

View File

@@ -120,10 +120,12 @@ epicsShareFunc int errlogPrintf(const char *pFormat, ...)
isOkToBlock = epicsThreadIsOkToBlock();
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
FILE *console = pvtData.console ? pvtData.console : stderr;
va_start(pvar, pFormat);
nchar = vfprintf(pvtData.console, pFormat, pvar);
nchar = vfprintf(console, pFormat, pvar);
va_end (pvar);
fflush(pvtData.console);
fflush(console);
}
if (pvtData.atExit)
@@ -146,6 +148,7 @@ epicsShareFunc int errlogVprintf(
int nchar;
char *pbuffer;
int isOkToBlock;
FILE *console;
if (epicsInterruptIsInterruptContext()) {
epicsInterruptContextMessage
@@ -160,15 +163,17 @@ epicsShareFunc int errlogVprintf(
pbuffer = msgbufGetFree(isOkToBlock);
if (!pbuffer) {
vfprintf(pvtData.console, pFormat, pvar);
fflush(pvtData.console);
console = pvtData.console ? pvtData.console : stderr;
vfprintf(console, pFormat, pvar);
fflush(console);
return 0;
}
nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:"", pvar);
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
fprintf(pvtData.console, "%s", pbuffer);
fflush(pvtData.console);
console = pvtData.console ? pvtData.console : stderr;
fprintf(console, "%s", pbuffer);
fflush(console);
}
msgbufSetSize(nchar);
return nchar;
@@ -243,11 +248,13 @@ epicsShareFunc int errlogSevPrintf(
isOkToBlock = epicsThreadIsOkToBlock();
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
fprintf(pvtData.console, "sevr=%s ", errlogGetSevEnumString(severity));
FILE *console = pvtData.console ? pvtData.console : stderr;
fprintf(console, "sevr=%s ", errlogGetSevEnumString(severity));
va_start(pvar, pFormat);
vfprintf(pvtData.console, pFormat, pvar);
vfprintf(console, pFormat, pvar);
va_end(pvar);
fflush(pvtData.console);
fflush(console);
}
va_start(pvar, pFormat);
@@ -359,7 +366,9 @@ epicsShareFunc int epicsShareAPI errlogRemoveListeners(
epicsMutexUnlock(pvtData.listenerLock);
if (count == 0) {
fprintf(pvtData.console,
FILE *console = pvtData.console ? pvtData.console : stderr;
fprintf(console,
"errlogRemoveListeners: No listeners found\n");
}
return count;
@@ -376,7 +385,7 @@ epicsShareFunc int epicsShareAPI eltc(int yesno)
epicsShareFunc int errlogSetConsole(FILE *stream)
{
errlogInit(0);
pvtData.console = stream ? stream : stderr;
pvtData.console = stream;
return 0;
}
@@ -405,17 +414,19 @@ epicsShareFunc void errPrintf(long status, const char *pFileName,
}
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
FILE *console = pvtData.console ? pvtData.console : stderr;
if (pFileName)
fprintf(pvtData.console, "filename=\"%s\" line number=%d\n",
fprintf(console, "filename=\"%s\" line number=%d\n",
pFileName, lineno);
if (status > 0)
fprintf(pvtData.console, "%s ", name);
fprintf(console, "%s ", name);
va_start(pvar, pformat);
vfprintf(pvtData.console, pformat, pvar);
vfprintf(console, pformat, pvar);
va_end(pvar);
fputc('\n', pvtData.console);
fflush(pvtData.console);
fputc('\n', console);
fflush(console);
}
if (pvtData.atExit)
@@ -473,7 +484,7 @@ static void errlogInitPvt(void *arg)
ellInit(&pvtData.listenerList);
ellInit(&pvtData.msgQueue);
pvtData.toConsole = TRUE;
pvtData.console = stderr;
pvtData.console = NULL;
pvtData.waitForWork = epicsEventMustCreate(epicsEventEmpty);
pvtData.listenerLock = epicsMutexMustCreate();
pvtData.msgQueueLock = epicsMutexMustCreate();
@@ -559,8 +570,10 @@ static void errlogThread(void)
while ((pmessage = msgbufGetSend(&noConsoleMessage))) {
epicsMutexMustLock(pvtData.listenerLock);
if (pvtData.toConsole && !noConsoleMessage) {
fprintf(pvtData.console,"%s",pmessage);
fflush(pvtData.console);
FILE *console = pvtData.console ? pvtData.console : stderr;
fprintf(console, "%s", pmessage);
fflush(console);
}
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
@@ -680,7 +693,9 @@ static void msgbufFreeSend(void)
epicsMutexMustLock(pvtData.msgQueueLock);
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
if (!pnextSend) {
fprintf(pvtData.console, "errlog: msgbufFreeSend logic error\n");
FILE *console = pvtData.console ? pvtData.console : stderr;
fprintf(console, "errlog: msgbufFreeSend logic error\n");
epicsThreadSuspendSelf();
}
ellDelete(&pvtData.msgQueue, &pnextSend->node);

View File

@@ -148,6 +148,10 @@ epicsShareFunc void epicsShareAPI freeListCleanup(void *pvt)
epicsShareFunc size_t epicsShareAPI freeListItemsAvail(void *pvt)
{
FREELISTPVT *pfl = pvt;
return pfl->nBlocksAvailable;
size_t nBlocksAvailable;
epicsMutexMustLock(pfl->lock);
nBlocksAvailable = pfl->nBlocksAvailable;
epicsMutexUnlock(pfl->lock);
return nBlocksAvailable;
}

View File

@@ -211,7 +211,7 @@ int testDone(void) {
/* Our test harness, for RTEMS and vxWorks */
static void harnessExit(void *dummy) {
void testHarnessExit(void *dummy) {
epicsTimeStamp ended;
int Faulty;
@@ -248,7 +248,7 @@ static void harnessExit(void *dummy) {
void testHarness(void) {
epicsThreadOnce(&onceFlag, testOnce, NULL);
epicsAtExit(harnessExit, NULL);
epicsAtExit(testHarnessExit, NULL);
Harness = 1;
Programs = 0;
Tests = 0;

View File

@@ -43,9 +43,11 @@ epicsShareFunc int testDone(void);
typedef int (*TESTFUNC)(void);
epicsShareFunc void testHarness(void);
epicsShareFunc void testHarnessExit(void *dummy);
epicsShareFunc void runTestFunc(const char *name, TESTFUNC func);
#define runTest(func) runTestFunc(#func, func)
#define testHarnessDone() testHarnessExit(0)
#ifdef __cplusplus
}

View File

@@ -80,6 +80,10 @@ Com_SRCS += osiClockTime.c
Com_SRCS_vxWorks += osiNTPTime.c
Com_SRCS_RTEMS += osiNTPTime.c
ifeq ($(OS_CLASS),vxWorks)
osdTime.o: USR_CXXFLAGS += -DBUILD_TIME=$(shell perl -e 'print time')
endif
Com_SRCS += osdSock.c
Com_SRCS += osdSockAddrReuse.cpp
Com_SRCS += osiSock.c

View File

@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -14,15 +13,22 @@
* Author: Jeff Hill
*/
#ifndef osdTimeh
#define osdTimeh
#ifndef INC_osdTime_H
#define INC_osdTime_H
#if ! defined(_MINGW) || ! defined(_TIMESPEC_DEFINED)
# if _MSC_VER >= 1900
# include <time.h>
# else
#define _TIMESPEC_DEFINED 1
struct timespec {
time_t tv_sec; /* seconds since some epoch */
long tv_nsec; /* nanoseconds within the second */
time_t tv_sec; /* seconds since some epoch */
long tv_nsec; /* nanoseconds within the second */
};
# endif /* _MSC_VER */
#endif /* ! defined(_MINGW) || ! defined(_TIMESPEC_DEFINED) */
#endif /* ifndef osdTimeh */
#endif /* ifndef INC_osdTime_H */

View File

@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/param.h> /* for MAXHOSTNAMELEN */
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>

View File

@@ -19,7 +19,7 @@
enum epicsSocketSystemCallInterruptMechanismQueryInfo
epicsSocketSystemCallInterruptMechanismQuery ()
{
#if (CYGWIN_VERSION_DLL_MAJOR >= 1007) && (CYGWIN_VERSION_DLL_MINOR < 15)
#if (CYGWIN_VERSION_DLL_MAJOR == 1007) && (CYGWIN_VERSION_DLL_MINOR < 15)
// Behaviour changed in early Cygwin 1.7 releases, reverted later.
return esscimqi_socketCloseRequired;
#else

View File

@@ -14,6 +14,7 @@
#define epicsExportSharedSymbols
#include "envDefs.h"
#include "epicsExit.h"
#include "epicsReadline.h"
#define EPICS_COMMANDLINE_LIBRARY_EPICS 0
@@ -78,12 +79,21 @@ epicsReadlineEnd(void *context)
#include <readline/readline.h>
#include <readline/history.h>
#include <unistd.h>
struct readlineContext {
FILE *in;
char *line;
};
static enum {rlNone, rlIdle, rlBusy} rlState = rlNone;
static void rlExit(void *dummy) {
if (rlState == rlBusy)
rl_cleanup_after_signal();
}
/*
* Create a command-line context
*/
@@ -92,6 +102,11 @@ epicsReadlineBegin(FILE *in)
{
struct readlineContext *readlineContext;
if (rlState == rlNone) {
epicsAtExit(rlExit, NULL);
rlState = rlIdle;
}
readlineContext = malloc(sizeof *readlineContext);
if (readlineContext != NULL) {
readlineContext->in = in;
@@ -124,7 +139,17 @@ epicsReadline (const char *prompt, void *context)
free (readlineContext->line);
readlineContext->line = NULL;
if (readlineContext->in == NULL) {
if (!isatty(fileno(stdout))) {
/* The libedit readline emulator on Darwin doesn't
* print the prompt when the terminal isn't a tty.
*/
fputs (prompt, stdout);
fflush (stdout);
rl_already_prompted = 1;
}
rlState = rlBusy;
line = readline (prompt);
rlState = rlIdle;
}
else {
line = (char *)malloc (linesize * sizeof *line);

View File

@@ -27,7 +27,7 @@ epicsShareFunc void epicsShareAPI
(char *) & yes, sizeof ( yes ) );
if ( status < 0 ) {
errlogPrintf (
"epicsSocketEnablePortUseForDatagramFanout: "
"epicsSocketEnableAddressReuseDuringTimeWaitState: "
"unable to set SO_REUSEADDR?\n");
}
}

View File

@@ -1,5 +1,5 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* Copyright (c) 2015 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.
@@ -7,11 +7,14 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
#include <vxWorks.h>
#include <sntpcLib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <taskLib.h>
#include "epicsTime.h"
#include "osiNTPTime.h"
@@ -21,6 +24,9 @@
#define NTP_REQUEST_TIMEOUT 4 /* seconds */
static char sntp_sync_task[] = "ipsntps";
static char ntp_daemon[] = "ipntpd";
static const char *pserverAddr = NULL;
extern char* sysBootLine;
@@ -30,18 +36,40 @@ static int timeRegister(void)
if (getenv("TIMEZONE") == NULL) {
const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE);
if (timezone == NULL) {
printf("NTPTime_Init: No Time Zone Information\n");
printf("timeRegister: No Time Zone Information\n");
} else {
epicsEnvSet("TIMEZONE", timezone);
}
}
NTPTime_Init(100); /* init NTP first so it can be used to sync SysTime */
ClockTime_Init(CLOCKTIME_SYNC);
// Define EPICS_TS_FORCE_NTPTIME to force use of NTPTime provider
bool useNTP = getenv("EPICS_TS_FORCE_NTPTIME") != NULL;
if (!useNTP &&
(taskNameToId(sntp_sync_task) != ERROR ||
taskNameToId(ntp_daemon) != ERROR)) {
// A VxWorks 6 SNTP/NTP sync task is running
struct timespec clockNow;
useNTP = clock_gettime(CLOCK_REALTIME, &clockNow) != OK ||
clockNow.tv_sec < BUILD_TIME;
// Assumes VxWorks and the host OS have the same epoch
}
if (useNTP) {
// Start NTP first so it can be used to sync SysTime
NTPTime_Init(100);
ClockTime_Init(CLOCKTIME_SYNC);
} else {
ClockTime_Init(CLOCKTIME_NOSYNC);
}
return 1;
}
static int done = timeRegister();
// Routines for NTPTime provider
int osdNTPGet(struct timespec *ts)
{
return sntpcTimeGet(const_cast<char *>(pserverAddr),
@@ -54,6 +82,7 @@ void osdNTPInit(void)
if (!pserverAddr) { /* use the boot host */
BOOT_PARAMS bootParms;
static char host_addr[BOOT_ADDR_LEN];
bootStringToStruct(sysBootLine, &bootParms);
/* bootParms.had = host IP address */
strncpy(host_addr, bootParms.had, BOOT_ADDR_LEN);
@@ -63,10 +92,13 @@ void osdNTPInit(void)
void osdNTPReport(void)
{
printf("NTP Server = %s\n", pserverAddr);
if (pserverAddr)
printf("NTP Server = %s\n", pserverAddr);
}
// Other Time Routines
// vxWorks localtime_r returns different things in different versions.
// It can't fail though, so we just ignore the return value.
int epicsTime_localtime(const time_t *clock, struct tm *result)

View File

@@ -70,37 +70,54 @@ static void ShutdownCallFunc(const iocshArgBuf *args)
/* Initialization */
static void ClockTime_InitOnce(void *psync)
static void ClockTime_InitOnce(void *pfirst)
{
ClockTimePvt.synchronize = *(int *)psync;
*(int *) pfirst = 1;
ClockTimePvt.loopEvent = epicsEventMustCreate(epicsEventEmpty);
ClockTimePvt.lock = epicsMutexCreate();
if (ClockTimePvt.synchronize) {
/* Start the sync thread */
epicsThreadCreate("ClockTimeSync", epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackSmall),
ClockTimeSync, NULL);
}
else {
ClockTimeGetCurrent(&ClockTimePvt.startTime);
}
epicsAtExit(ClockTime_Shutdown, NULL);
/* Register the iocsh commands */
iocshRegister(&ReportFuncDef, ReportCallFunc);
if (ClockTimePvt.synchronize)
iocshRegister(&ShutdownFuncDef, ShutdownCallFunc);
iocshRegister(&ShutdownFuncDef, ShutdownCallFunc);
/* Finally register as a time provider */
/* Register as a time provider */
generalTimeRegisterCurrentProvider("OS Clock", LAST_RESORT_PRIORITY,
ClockTimeGetCurrent);
}
void ClockTime_Init(int synchronize)
{
epicsThreadOnce(&onceId, ClockTime_InitOnce, &synchronize);
int firstTime = 0;
epicsThreadOnce(&onceId, ClockTime_InitOnce, &firstTime);
if (synchronize == CLOCKTIME_SYNC) {
if (ClockTimePvt.synchronize == CLOCKTIME_NOSYNC) {
/* Start synchronizing */
ClockTimePvt.synchronize = synchronize;
epicsThreadCreate("ClockTimeSync", epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackSmall),
ClockTimeSync, NULL);
}
else {
/* No change, sync thread should already be running */
}
}
else {
if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) {
/* Turn off synchronization thread */
ClockTime_Shutdown(NULL);
}
else {
/* No synchronization thread */
if (firstTime)
ClockTimeGetCurrent(&ClockTimePvt.startTime);
}
}
}
@@ -108,7 +125,7 @@ void ClockTime_Init(int synchronize)
void ClockTime_Shutdown(void *dummy)
{
ClockTimePvt.synchronize = 0;
ClockTimePvt.synchronize = CLOCKTIME_NOSYNC;
epicsEventSignal(ClockTimePvt.loopEvent);
}
@@ -126,7 +143,7 @@ static void ClockTimeSync(void *dummy)
for (epicsEventWaitWithTimeout(ClockTimePvt.loopEvent,
ClockTimeSyncInterval);
ClockTimePvt.synchronize;
ClockTimePvt.synchronize == CLOCKTIME_SYNC;
epicsEventWaitWithTimeout(ClockTimePvt.loopEvent,
ClockTimeSyncInterval)) {
epicsTimeStamp timeNow;
@@ -144,8 +161,8 @@ static void ClockTimeSync(void *dummy)
epicsMutexMustLock(ClockTimePvt.lock);
if (!ClockTimePvt.synchronized) {
ClockTimePvt.startTime = timeNow;
ClockTimePvt.synchronized = 1;
ClockTimePvt.startTime = timeNow;
ClockTimePvt.synchronized = 1;
}
ClockTimePvt.syncFromPriority = priority;
ClockTimePvt.syncTime = timeNow;
@@ -200,29 +217,39 @@ int ClockTime_Report(int level)
#ifdef CLOCK_REALTIME
"initialized"
#else
"included"
"available"
#endif /* CLOCK_REALTIME */
);
} else if (ClockTimePvt.synchronize) {
}
else if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) {
int synchronized, syncFromPriority;
epicsTimeStamp startTime, syncTime;
epicsMutexMustLock(ClockTimePvt.lock);
if (ClockTimePvt.synchronized) {
printf("OS Clock driver has synchronized to a priority=%d provider\n",
ClockTimePvt.syncFromPriority);
synchronized = ClockTimePvt.synchronized;
syncFromPriority = ClockTimePvt.syncFromPriority;
startTime = ClockTimePvt.startTime;
syncTime = ClockTimePvt.syncTime;
epicsMutexUnlock(ClockTimePvt.lock);
if (synchronized) {
printf("OS Clock driver is synchronized to a priority=%d provider\n",
syncFromPriority);
if (level) {
epicsTimeToStrftime(timebuf, sizeof(timebuf),
"%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.startTime);
"%Y-%m-%d %H:%M:%S.%06f", &startTime);
printf("Initial sync was at %s\n", timebuf);
epicsTimeToStrftime(timebuf, sizeof(timebuf),
"%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.syncTime);
"%Y-%m-%d %H:%M:%S.%06f", &syncTime);
printf("Last successful sync was at %s\n", timebuf);
}
printf("Syncronization interval = %.0f seconds\n",
ClockTimeSyncInterval);
} else
printf("OS Clock driver has *not* yet synchronized\n");
epicsMutexUnlock(ClockTimePvt.lock);
} else {
}
else
printf("OS Clock driver is *not* synchronized\n");
}
else {
epicsTimeToStrftime(timebuf, sizeof(timebuf),
"%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.startTime);
printf("Program started at %s\n", timebuf);

View File

@@ -29,7 +29,9 @@ using namespace std;
#if defined ( _MSC_VER )
// some interesting bugs found in the MS implementation of new
# if _MSC_VER > 1310 /* this gets fixed some release after visual studio 7 we hope */
# if _MSC_VER >= 1900
static size_t unsuccessfulNewSize = numeric_limits < size_t > :: max ();
# elif _MSC_VER > 1310 /* this gets fixed some release after visual studio 7 we hope */
static const size_t unsuccessfulNewSize = numeric_limits < size_t > :: max ();
# else
static const size_t unsuccessfulNewSize = numeric_limits < size_t > :: max () - 100;

View File

@@ -101,7 +101,12 @@ void epicsRunLibComTests(void)
runTest(taskwdTest);
/*
* Exit must come last as it never returns
* Report now in case epicsExitTest dies
*/
testHarnessDone();
/*
* epicsExitTest must come last as it never returns
*/
runTest(epicsExitTest);
}

View File

@@ -1,11 +1,10 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* $Revision-Id$
@@ -70,6 +69,7 @@ epicsTimerQueueActiveForC ::
bool okToShare, unsigned priority ) :
timerQueueActive ( refMgr, okToShare, priority )
{
timerQueueActive::start();
}
epicsTimerQueueActiveForC::~epicsTimerQueueActiveForC ()

View File

@@ -1,11 +1,10 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* $Revision-Id$
@@ -134,6 +133,7 @@ class timerQueueActive : public epicsTimerQueueActive,
public:
typedef epicsSingleton < timerQueueActiveMgr > :: reference RefMgr;
timerQueueActive ( RefMgr &, bool okToShare, unsigned priority );
void start ();
epicsTimer & createTimer ();
epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
void show ( unsigned int level ) const;

View File

@@ -1,13 +1,13 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* $Revision-Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
@@ -49,6 +49,10 @@ timerQueueActive ::
epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ),
exitFlag ( false ), terminateFlag ( false )
{
}
void timerQueueActive::start ()
{
this->thread.start ();
}

View File

@@ -23,6 +23,7 @@
#include "dbChannel.h"
#include "dbNotify.h"
#include "epicsAssert.h"
#include "epicsMath.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
@@ -190,7 +191,7 @@ static long read_ai(aiRecord *prec)
}
/* Apply smoothing algorithm */
if (prec->smoo != 0.0 && pdevPvt->smooth)
if (prec->smoo != 0.0 && pdevPvt->smooth && finite(prec->val))
prec->val = prec->val * prec->smoo +
pdevPvt->buffer.value * (1.0 - prec->smoo);
else

View File

@@ -6,13 +6,13 @@ The following filters are available in this release:
=over
=item * L<TimeStamp|/"TimeStamp Filter "ts"">
=item * L<TimeStamp|/"TimeStamp Filter ts">
=item * L<Deadband|/"Deadband Filter "dbnd"">
=item * L<Deadband|/"Deadband Filter dbnd">
=item * L<Array|/"Array Filter "arr"">
=item * L<Array|/"Array Filter arr">
=item * L<Synchronize|/"Synchronize Filter "sync"">
=item * L<Synchronize|/"Synchronize Filter sync">
=back

View File

@@ -29,21 +29,21 @@ recordtype(bi) {
}
field(OSV,DBF_MENU) {
prompt("One Error Severity")
promptgroup(GUI_BITS1)
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(COSV,DBF_MENU) {
prompt("Change of State Svr")
promptgroup(GUI_BITS2)
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(ZNAM,DBF_STRING) {
prompt("Zero Name")
promptgroup(GUI_CALC)
promptgroup(GUI_DISPLAY)
pp(TRUE)
interest(1)
size(26)
@@ -51,7 +51,7 @@ recordtype(bi) {
}
field(ONAM,DBF_STRING) {
prompt("One Name")
promptgroup(GUI_CLOCK)
promptgroup(GUI_DISPLAY)
pp(TRUE)
interest(1)
size(26)

View File

@@ -46,7 +46,7 @@
static long init_record(eventRecord *, int);
static long process(eventRecord *);
static long special(DBADDR *, int);
static long get_value(eventRecord *, struct valueDes *);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
@@ -153,15 +153,6 @@ static long special(DBADDR *paddr, int after)
return 0;
}
static long get_value(eventRecord *prec, struct valueDes *pvdes)
{
pvdes->field_type = DBF_STRING;
pvdes->no_elements=1;
pvdes->pvalue = (void *)(&prec->val);
return(0);
}
static void monitor(eventRecord *prec)
{

View File

@@ -32,6 +32,7 @@ PERL_MODULES += DBD/Recordtype.pm
PERL_MODULES += DBD/Registrar.pm
PERL_MODULES += DBD/Variable.pm
PERL_SCRIPTS += assembleSnippets.pl
PERL_SCRIPTS += convertRelease.pl
PERL_SCRIPTS += cvsclean.pl
PERL_SCRIPTS += dos2unix.pl

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env perl
#*************************************************************************
# Copyright (c) 2015 ITER Organization.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# $Id$
use strict;
use warnings;
use Getopt::Std;
use Sys::Hostname;
use File::Basename;
use Data::Dumper;
our ($opt_o, $opt_d, $opt_m, $opt_i, $opt_M);
$Getopt::Std::OUTPUT_HELP_VERSION = 1;
&HELP_MESSAGE if !getopts('M:i:m:o:d') || @ARGV == 0;
my $out;
my $dep;
my %snippets;
my $ipattern;
my $datetime = localtime();
my $user = $ENV{LOGNAME} || $ENV{USER} || $ENV{USERNAME};
my $host = hostname;
my %replacements = (
_DATETIME_ => $datetime,
_USERNAME_ => $user,
_HOST_ => $host,
);
if ($opt_o) {
open $out, '>', $opt_o or
die "Can't create $opt_o: $!\n";
print STDERR "opened file $opt_o for output\n" if $opt_d;
$replacements{_OUTPUTFILE_} = $opt_o;
} else {
open $out, '>&', STDOUT;
print STDERR "using STDOUT for output\n" if $opt_d;
$replacements{_OUTPUTFILE_} = 'STDERR';
}
if ($opt_m) {
foreach my $r (split /,/, $opt_m) {
(my $k, my $v) = split /=/, $r;
$replacements{$k} = $v;
}
}
if ($opt_M) {
open $dep, '>', $opt_M or
die "Can't create $opt_M: $!\n";
print STDERR "opened dependency file $opt_M for output\n" if $opt_d;
print $dep basename($opt_o), ":";
}
if ($opt_i) {
$ipattern = qr($opt_i);
}
# %snippets is a hash {rank}
# of hashes {name-after-rank}
# of arrays[] [files...]
# of arrays[2] [filename, command]
print STDERR "reading input files\n" if $opt_d;
foreach (@ARGV) {
my $name = basename($_);
if ($opt_i and not $name =~ /$ipattern/) {
print STDERR " snippet $_ does not match input pattern $opt_i - ignoring\n" if $opt_d;
next;
}
if ($name =~ /\A([ARD]?)([0-9]+)(.*[^~])\z/) {
print STDERR " considering snippet $_\n" if $opt_d;
if (exists $snippets{$2}) {
my %rank = %{$snippets{$2}};
my @files = @{ $rank{(keys %rank)[0]} };
my $existcmd = $files[0]->[1];
if ($1 eq "D" and $existcmd ne "D") {
print STDERR " ignoring 'D' default for existing rank $2\n" if $opt_d;
next;
} elsif ($1 eq "R") {
print STDERR " 'R' command - deleting existing rank $2 snippets\n" if $opt_d;
$snippets{$2} = {};
} elsif ($existcmd eq "D") {
print STDERR " deleting existing rank $2 default snippet\n" if $opt_d;
$snippets{$2} = {};
}
}
if ($opt_d) {
print STDERR " adding snippet ";
print STDERR "marked as default " if $1 eq "D";
print STDERR "to rank $2\n";
}
$snippets{$2}{$3} = () if (not exists $snippets{$2}{$3});
push @{$snippets{$2}{$3}}, [ $_, $1 ];
}
}
if ($opt_d) {
print STDERR "finished reading input files\n";
print STDERR "dumping the final snippet structure\n";
print STDERR Dumper(\%snippets);
print STDERR "dumping the macro replacements\n";
print STDERR Dumper(\%replacements);
print STDERR "creating output\n";
}
foreach my $r (sort {$a<=>$b} keys %snippets) {
print STDERR " working on rank $r\n" if $opt_d;
foreach my $n (sort keys %{$snippets{$r}}) {
foreach my $s (@{$snippets{$r}{$n}}) {
my $in;
my $f = $s->[0];
print STDERR " snippet $n from file $f\n" if $opt_d;
open $in, '<', $f or die "Can't open $f: $!\n";
$replacements{_SNIPPETFILE_} = $f;
print $dep " \\\n $f" if $opt_M;
while (<$in>) {
chomp;
foreach my $k (keys %replacements) {
s/$k/$replacements{$k}/g;
}
print $out $_, "\n";
}
close $in;
}
}
}
print STDERR "finished creating output, closing\n" if $opt_d;
if ($opt_M) {
print $dep "\n";
close $dep;
}
close $out;
sub HELP_MESSAGE {
print STDERR "Usage: assembleSnippets.pl [options] snippets ...\n";
print STDERR "Options:\n";
print STDERR " -o file output file [STDOUT]\n";
print STDERR " -d debug mode [no]\n";
print STDERR " -m macros list of macro replacements as \"key=val,key=val\"\n";
print STDERR " -i pattern pattern for input files to match\n";
print STDERR " -M file write file with dependency rule suitable for make\n";
exit 2;
}

View File

@@ -80,7 +80,7 @@ open my $out, '>', $opt_o or
my $pod = join "\n", '=for html <div class="pod">', '',
map {
# Handle a 'recordtype' Pod directive
if (m/^ =recordtype \s+ (.*)/x) {
if (m/^ =recordtype \s+ (\w+) /x) {
my $rn = $1;
my $rtyp = $dbd->recordtype($rn);
die "Unknown recordtype '$rn' in $infile POD directive\n"
@@ -88,7 +88,7 @@ my $pod = join "\n", '=for html <div class="pod">', '',
rtypeToPod($rtyp, $dbd);
}
# Handle a 'menu' Pod directive
elsif (m/^ =menu \s+ (.*)/x) {
elsif (m/^ =menu \s+ (\w+) /x) {
my $mn = $1;
my $menu = $dbd->menu($mn);
die "Unknown menu '$mn' in $infile POD directive\n"
@@ -152,7 +152,7 @@ sub rtypeToPod {
my ($rtyp, $dbd) = @_;
return map {
# Handle a 'fields' Pod directive
if (m/^ =fields \s+ (.*)/x) {
if (m/^ =fields \s+ (\w+ (?:\s* , \s* \w+ )* )/x) {
my @names = split /\s*,\s*/, $1;
# Look up the named fields
my @fields = map {
@@ -170,7 +170,7 @@ sub rtypeToPod {
'</table></blockquote>', '', '=end html';
}
# Handle a 'menu' Pod directive
elsif (m/^ =menu \s+ (.*)/x) {
elsif (m/^ =menu \s+ (\w+) /x) {
my $mn = $1;
my $menu = $dbd->menu($mn);
die "Unknown menu '$mn' in $infile POD directive\n"
@@ -218,7 +218,7 @@ sub fieldTableRow {
# Native type presented to dbAccess users
sub DBD::Recfield::public_type {
my $fld = shift;
m/^=type (.+)$/i && return $1 for $fld->comments;
m/^ =type \s+ (.+) /x && return $1 for $fld->comments;
my $type = $fld->dbf_type;
$type =~ s/^DBF_//;
return $type;
@@ -227,7 +227,7 @@ sub DBD::Recfield::public_type {
# Check if this field is readable
sub DBD::Recfield::readable {
my $fld = shift;
m/^=read (Yes|No)$/i && return $1 for $fld->comments;
m/^ =read \s+ (?i) (Yes|No) /x && return $1 for $fld->comments;
return 'Probably'
if $fld->attribute('special') eq "SPC_DBADDR";
return $fld->dbf_type eq 'DBF_NOACCESS' ? 'No' : 'Yes';
@@ -236,7 +236,7 @@ sub DBD::Recfield::readable {
# Check if this field is writable
sub DBD::Recfield::writable {
my $fld = shift;
m/^=write (Yes|No)$/i && return $1 for $fld->comments;
m/^ =write \s+ (?i) (Yes|No) /x && return $1 for $fld->comments;
my $special = $fld->attribute('special');
return 'No'
if $special eq "SPC_NOMOD";

View File

@@ -18,6 +18,7 @@ TESTS += Menu
TESTS += Recfield
TESTS += Recordtype
TESTS += Registrar
TESTS += Snippets
TESTS += Variable
TESTSCRIPTS_HOST += $(TESTS:%=%.t)

110
src/tools/test/Snippets.plt Normal file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env perl
use File::Path;
use Sys::Hostname;
use Test::More tests => 29;
my $user = $ENV{LOGNAME} || $ENV{USER} || $ENV{USERNAME};
my $host = hostname;
mkdir "a$$";
mkdir "b$$";
sub mksnip {
my ($dir, $file, $line) = @_;
open(my $fh, '>', "$dir$$/$file") or die "can't open $dir$$/$file : $!";
print $fh $line;
close $fh;
}
sub assemble {
my @cmd = ( 'perl', '../../assembleSnippets.pl', '-o', "out$$" );
push @cmd, @_;
system(@cmd);
open(my $fh, '<', "out$$") or die "can't open out$$ : $!";
chomp(my @result = <$fh>);
close $fh;
return join (' ', @result);
}
# Adding two snippets of same rank, sorting alphabetically
mksnip('a', '10_a', '10');
mksnip('b', '10_c', '12');
is assemble("a$$/10_a", "b$$/10_c"), '10 12', "adding same rank; ordered";
is assemble("b$$/10_c", "a$$/10_a"), '10 12', "adding same rank; reverse order";
# Same, with 'A' cmd
mksnip('a', 'A10_a', '10');
mksnip('b', 'A10_c', '12');
is assemble("a$$/10_a", "b$$/A10_c"), '10 12', "'A' add same rank; ordered";
is assemble("b$$/10_c", "a$$/A10_a"), '10 12', "'A' add same rank; reverse order";
# Same name does not create issues
mksnip('b', '10_a', '10x');
is assemble("a$$/10_a", "b$$/10_a"), '10 10x', "adding same name twice; order a-b";
is assemble("b$$/10_a", "a$$/10_a"), '10x 10', "adding same name twice; order b-a";
# Backup files (trailing ~) and hidden files (leading '.') get ignored
mksnip('b', '10_c~', '12~');
mksnip('b', '.10_c', '.12');
is assemble("b$$/10_c", "b$$/10_c~"), '12', "backup file (trailing ~) gets ignored";
is assemble("b$$/10_c", "b$$/.10_c"), '12', "hidden file (leading .) gets ignored";
# Non-numeric filenames get ignored
mksnip('a', 'foo10_a', 'foo10');
is assemble("b$$/10_c", "a$$/foo10_a"), '12', "file starting with [^ADR0-9] gets ignored";
# 'R' command replaces existing snippets of same rank
mksnip('a', 'R10_b', '11');
is assemble("a$$/10_a", "b$$/10_c", "a$$/R10_b"), '11', "'R' cmd; replace all";
is assemble("a$$/10_a", "a$$/R10_b", "b$$/10_c"), '11 12', "'R' cmd; replace one (ordered)";
is assemble("b$$/10_c", "a$$/R10_b", "a$$/10_a"), '10 11', "'R' cmd; replace one (reverse order)";
# 'D' command establishes default that gets overwritten or ignored
mksnip('a', 'D10_a', 'D10');
mksnip('b', 'D10_c', 'D12');
is assemble("a$$/D10_a", "b$$/10_c"), '12', "'D' default; replaced by regular";
is assemble("a$$/D10_a", "b$$/D10_c"), 'D12', "'D' default; replaced by new default (ordered)";
is assemble("b$$/D10_c", "a$$/D10_a"), 'D10', "'D' default; replaced by new default (reverse order)";
is assemble("a$$/D10_a", "a$$/R10_b"), '11', "'D' default; replaced by 'R' cmd";
is assemble("b$$/10_c", "a$$/D10_a"), '12', "'D' default; ignored when regular exists";
# Ranks are sorted numerically
mksnip('b', '09_a', '09');
mksnip('a', '15_a', '15');
mksnip('b', '2_a', '2');
is assemble("a$$/10_a", "b$$/2_a", "a$$/15_a", "b$$/09_a"), '2 09 10 15', "ranks are sorted numerically";
# Builtin macros
mksnip('a', '30_a', '_USERNAME_');
mksnip('a', '30_b', '_OUTPUTFILE_');
mksnip('a', '30_c', '_SNIPPETFILE_');
mksnip('a', '30_d', '_HOST_');
is assemble("a$$/30_a"), "$user", "builtin macro _USERNAME_";
is assemble("a$$/30_b"), "out$$", "builtin macro _OUTPUTFILE_";
is assemble("a$$/30_c"), "a$$/30_c", "builtin macro _SNIPPETFILE_";
is assemble("a$$/30_d"), "$host", "builtin macro _HOST_";
# User macros
mksnip('b', '35_a', 'Line _M1_');
mksnip('b', '35_b', 'Line _M1_ with _M2_');
mksnip('b', '35_c', 'Line _M2_ with _M2_');
is assemble("-m", "_M1_=REP1", "b$$/35_a"), "Line REP1", "single user macro; single occurrence";
is assemble("-m", "_M1_=REP1,_M2_=REP2", "b$$/35_b"), "Line REP1 with REP2", "multiple user macros";
is assemble("-m", "_M2_=REP2", "b$$/35_c"), "Line REP2 with REP2", "single user macro; multiple occurrences";
# Input pattern
mksnip('a', '10_a.cmd', '10cmd');
is assemble("-i", "\.cmd", "a$$/10_a", "b$$/10_c", "a$$/R10_b", "a$$/10_a.cmd"), '10cmd', "input pattern";
# Dependency file generation
assemble("-M", "./dep$$", "a$$/10_a", "b$$/10_c");
open(my $fh, '<', "dep$$") or die "can't open dep$$ : $!";
chomp(my @result = <$fh>);
close $fh;
is "$result[0]", "out$$: \\", "dependency file (line 1)";
is "$result[1]", " a$$/10_a \\", "dependency file (line 2)";
is "$result[2]", " b$$/10_c", "dependency file (line 3)";
rmtree([ "a$$", "b$$", "out$$", "dep$$" ]);