Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
841ef37820 | ||
|
|
f550f278ad | ||
|
|
1706da98cc | ||
|
|
e8be04bc43 | ||
|
|
dee526f2f6 | ||
|
|
59cffd51ae | ||
|
|
9b5034f307 | ||
|
|
e2881fb37e | ||
|
|
afd9697290 | ||
|
|
9988be0906 | ||
|
|
a6812c5869 | ||
|
|
b89494a840 | ||
|
|
771ad6a442 | ||
|
|
d214d81794 | ||
|
|
c70b1a9a29 | ||
|
|
c9c4eea0f8 | ||
|
|
78ce2dac05 | ||
|
|
b2285bb8aa | ||
|
|
59cb5ba6a0 | ||
|
|
c8e5deca76 | ||
|
|
5b09bb6e71 | ||
|
|
ede52d96b8 | ||
|
|
ceccafe823 | ||
|
|
f955199805 | ||
|
|
2af0c10470 | ||
|
|
89f0f1338a | ||
|
|
6ce8dfec01 | ||
|
|
c1ab30142a | ||
|
|
2db2f1a53f | ||
|
|
b811d3402f | ||
|
|
a64cb4a877 | ||
|
|
e75a72ef76 | ||
|
|
33e099a51b | ||
|
|
345cfcffa8 | ||
|
|
655c5bed92 | ||
|
|
2c99c36ef9 | ||
|
|
71d4d3ecbd | ||
|
|
86138fdd23 | ||
|
|
8c993405b4 | ||
|
|
96259b7bdc | ||
|
|
bf8ff4e5f1 | ||
|
|
25576c316a | ||
|
|
2d3de1916b | ||
|
|
fe34c6f35e | ||
|
|
52cdfe0a44 | ||
|
|
16ddcaeaed | ||
|
|
297206e247 | ||
|
|
3110322f8c | ||
|
|
63bf8a8219 | ||
|
|
ec7193d0be | ||
|
|
17dea964a6 | ||
|
|
12283ce25a | ||
|
|
f486dba478 | ||
|
|
1f95d0db12 | ||
|
|
e02c5c3026 | ||
|
|
8e9d75ad71 | ||
|
|
630663caa8 | ||
|
|
7a84a1abba | ||
|
|
95cb81c286 | ||
|
|
a9606dbf6e | ||
|
|
409ee26fae | ||
|
|
9a4787155c | ||
|
|
84dba0d2b7 | ||
|
|
87f6c3dec9 | ||
|
|
940814becf | ||
|
|
68a1a529b2 | ||
|
|
ce38caf41b | ||
|
|
f03f10e664 | ||
|
|
b4f4fb853d | ||
|
|
b518ebe85b | ||
|
|
e461d782f4 | ||
|
|
ef2a381e92 | ||
|
|
265d4962a4 | ||
|
|
db9267bbd5 | ||
|
|
1cf3fa9ba9 | ||
|
|
3e8b0028dc | ||
|
|
d8f18c27f4 | ||
|
|
801c01b9b6 | ||
|
|
0c1874bbfe |
@@ -48,6 +48,7 @@ environment:
|
||||
TOOLCHAIN: 2017
|
||||
- TOOLCHAIN: cygwin
|
||||
- TOOLCHAIN: mingw
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
|
||||
# Platform: architecture
|
||||
platform:
|
||||
@@ -60,6 +61,10 @@ matrix:
|
||||
# VS Express installs don't have the 64 bit compiler
|
||||
- platform: x64
|
||||
TOOLCHAIN: 10.0
|
||||
# Cygwin static-debug has compiler problems
|
||||
- configuration: static-debug
|
||||
TOOLCHAIN: cygwin
|
||||
|
||||
|
||||
#---------------------------------#
|
||||
# building & testing #
|
||||
@@ -81,6 +86,9 @@ test_script:
|
||||
|
||||
notifications:
|
||||
|
||||
- provider: Slack
|
||||
incoming_webhook:
|
||||
secure: RYOm3FIUYeZGjWKaeTVKwq+C3fzK54AKwbmAoECED45mex3lN+8HmrC845a6mg9xPUJ/ND51RopWVaKDD9/UzaM0SO195RQLKqUTIUafiuM=
|
||||
- provider: Email
|
||||
to:
|
||||
- core-talk@aps.anl.gov
|
||||
on_build_success: false
|
||||
|
||||
- provider: GitHubPullRequest
|
||||
|
||||
@@ -42,13 +42,13 @@ if "%TOOLCHAIN%"=="mingw" (
|
||||
set "MAKE=mingw32-make"
|
||||
if "%OS%"=="64BIT" (
|
||||
set "EPICS_HOST_ARCH=windows-x64-mingw"
|
||||
set "INCLUDE=C:\tools\mingw64\include;%INCLUDE%"
|
||||
set "PATH=C:\tools\mingw64\bin;%PATH%"
|
||||
set "INCLUDE=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\include;%INCLUDE%"
|
||||
set "PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%"
|
||||
echo [INFO] MinGW Toolchain 64bit
|
||||
) else (
|
||||
set "EPICS_HOST_ARCH=win32-x86-mingw"
|
||||
set "INCLUDE=C:\tools\mingw32\include;%INCLUDE%"
|
||||
set "PATH=C:\tools\mingw32\bin;%PATH%"
|
||||
set "INCLUDE=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\include;%INCLUDE%"
|
||||
set "PATH=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin;%PATH%"
|
||||
echo [INFO] MinGW Toolchain 32bit
|
||||
)
|
||||
echo [INFO] Compiler Version
|
||||
|
||||
@@ -55,16 +55,9 @@ if "%TOOLCHAIN%"=="mingw" (
|
||||
) || (
|
||||
echo [INFO] EPICS set up for optimized build
|
||||
)
|
||||
if "%OS%"=="64BIT" (
|
||||
echo [INFO] Installing MinGW 64bit
|
||||
cinst mingw || cinst mingw
|
||||
) else (
|
||||
echo [INFO] Installing MinGW 32bit
|
||||
cinst mingw --x86 || cinst mingw --x86
|
||||
)
|
||||
)
|
||||
|
||||
echo [INFO] Installing Make 4.1
|
||||
curl -fsS --retry 3 -o C:\tools\make-4.1.zip https://epics.anl.gov/download/tools/make-4.1-win64.zip
|
||||
echo [INFO] Installing Make 4.2.1 from ANL web site
|
||||
curl -fsS --retry 3 -o C:\tools\make-4.2.1.zip https://epics.anl.gov/download/tools/make-4.2.1-win64.zip
|
||||
cd \tools
|
||||
"C:\Program Files\7-Zip\7z" e make-4.1.zip
|
||||
"C:\Program Files\7-Zip\7z" e make-4.2.1.zip
|
||||
|
||||
@@ -16,23 +16,46 @@ PREFIX="$3"
|
||||
if ! [ "$TOPREV" ]
|
||||
then
|
||||
cat <<EOF >&2
|
||||
usage: $0 [rev] [outfile.tar.gz] [prefix/]
|
||||
usage: $0 <rev> [<outfile> [<prefix>]]
|
||||
|
||||
<rev> may be any git revision spec. (tag, branch, or commit id).
|
||||
|
||||
Output file may be .tar.gz, .tar.bz2, or any extension supported by "tar -a".
|
||||
If output file name is omitted, "base-<rev>.tar.gz" will be used.
|
||||
If <prefix> is omitted, the default prefix is "base-<rev>/".
|
||||
If provided, <outfile> must end with ".tar", ".tar.gz" or ".tar.bz2".
|
||||
If <outfile> is omitted, "base-<rev>.tar.gz" will be used.
|
||||
If provided, <prefix> must end with "/". If <prefix> is omitted,
|
||||
the default is "base-<rev>/".
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ "$FINALTAR" ] || FINALTAR="base-$TOPREV.tar.gz"
|
||||
[ "$PREFIX" ] || PREFIX="base-$TOPREV/"
|
||||
case "$FINALTAR" in
|
||||
"")
|
||||
TAROPT=-z
|
||||
FINALTAR="base-$TOPREV.tar.gz"
|
||||
;;
|
||||
*.tar)
|
||||
TAROPT=""
|
||||
;;
|
||||
*.tar.gz)
|
||||
TAROPT=-z
|
||||
;;
|
||||
*.tar.bz2)
|
||||
TAROPT=-j
|
||||
;;
|
||||
*)
|
||||
die "outfile must end with '.tar.gz' or '.tar.bz2'"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$PREFIX" in
|
||||
*/) ;;
|
||||
*) die "Prefix must end with '/'";;
|
||||
"")
|
||||
PREFIX="base-$TOPREV/"
|
||||
;;
|
||||
*/)
|
||||
;;
|
||||
*)
|
||||
die "Prefix must end with '/'"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check for both <tag> and R<tag>
|
||||
@@ -97,13 +120,11 @@ then
|
||||
fi
|
||||
|
||||
# Use the filtered list to build the final tar
|
||||
# The -a option chooses compression automatically based on output file name.
|
||||
|
||||
tar -C "$TDIR"/tar --files-from="$TDIR"/list.2 -caf "$FINALTAR"
|
||||
tar -c $TAROPT -C "$TDIR"/tar -T "$TDIR"/list.2 -f "$FINALTAR"
|
||||
|
||||
echo "Wrote $FINALTAR"
|
||||
|
||||
tar -taf "$FINALTAR" > "$TDIR"/list.3
|
||||
tar -t $TAROPT -f "$FINALTAR" > "$TDIR"/list.3
|
||||
|
||||
# make sure we haven't picked up anything extra
|
||||
if ! diff -u "$TDIR"/list.2 "$TDIR"/list.3
|
||||
|
||||
@@ -48,11 +48,11 @@ EPICS_VERSION = 7
|
||||
EPICS_REVISION = 0
|
||||
|
||||
# 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
|
||||
EPICS_PATCH_LEVEL = 2
|
||||
# Not included in the official EPICS version number if zero
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
|
||||
# Between official releases, the EPICS_PATCH_LEVEL gets incremented
|
||||
# and a -DEV suffix is added (similar to the Maven -SNAPSHOT versions)
|
||||
|
||||
@@ -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 EPICS 7.0.2</title>
|
||||
<title>Known Problems in EPICS 7.0.3</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="text-align: center">EPICS 7.0.2: Known Problems</h1>
|
||||
<h1 style="text-align: center">EPICS 7.0.3: Known Problems</h1>
|
||||
|
||||
<p>Any patch files linked below should be applied at the root of the
|
||||
base-7.0.2 tree. Download them, then use the GNU Patch program as
|
||||
base-7.0.3 tree. Download them, then use the GNU Patch program as
|
||||
follows:</p>
|
||||
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-7.0.2</b>
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-7.0.3</b>
|
||||
% <b>patch -p1 < <i>/path/to/</i>file.patch</b></pre></blockquote>
|
||||
|
||||
<p>The following problems were known by the developers at the time of this
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
Installation Instructions
|
||||
|
||||
EPICS Base Release 7.0.2
|
||||
EPICS Base Release 7.0.3
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
* What is EPICS base?
|
||||
* What is new in this release?
|
||||
* Copyright
|
||||
* Supported platforms
|
||||
* Supported compilers
|
||||
* Software requirements
|
||||
* Host system storage requirements
|
||||
* Documentation
|
||||
* Directory Structure
|
||||
* Build related components
|
||||
* Building EPICS base (Unix and Win32)
|
||||
* Example application and extension
|
||||
* Multiple host platforms
|
||||
* What is EPICS base?
|
||||
* What is new in this release?
|
||||
* Copyright
|
||||
* Supported platforms
|
||||
* Supported compilers
|
||||
* Software requirements
|
||||
* Host system storage requirements
|
||||
* Documentation
|
||||
* Directory Structure
|
||||
* Build related components
|
||||
* Building EPICS base (Unix and Win32)
|
||||
* Example application and extension
|
||||
* Multiple host platforms
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<BODY>
|
||||
<CENTER>
|
||||
<H1>Installation Instructions</H1>
|
||||
<H2>EPICS Base Release 7.0.2</H2><BR>
|
||||
<H2>EPICS Base Release 7.0.3</H2><BR>
|
||||
</CENTER>
|
||||
<HR>
|
||||
<H3> Table of Contents</H3>
|
||||
|
||||
@@ -20,7 +20,7 @@ release.</p>
|
||||
which should also be read to understand what has changed since an earlier
|
||||
release.</p>
|
||||
|
||||
<h1 align="center">EPICS Release 7.0.2.2</h1>
|
||||
<h1 align="center">EPICS Release 7.0.3</h1>
|
||||
|
||||
<!-- Insert new items immediately below this template ...
|
||||
|
||||
@@ -30,6 +30,28 @@ release.</p>
|
||||
|
||||
-->
|
||||
|
||||
<h3>epicsTimeGetCurrent() optimization</h3>
|
||||
|
||||
<p>Add a fast path to epicsTimeGetCurrent() and related calls
|
||||
in the common case where only the default OS current time provider is
|
||||
registered. This path does not take the global mutex guarding
|
||||
the time providers list, potentially reducing lock contention.</p>
|
||||
|
||||
<h3>dbEvent tweak Queue size</h3>
|
||||
|
||||
<p>The size of the queue used by dbEvent to push monitor updates
|
||||
has been slightly increased based on DBR_TIME_DOUBLE to better fill
|
||||
an ethernet frame. This may result in slightly fewer, but larger
|
||||
frames being sent.</p>
|
||||
|
||||
<h3>mbbo/mbbiDirect number of bits as precision</h3>
|
||||
|
||||
<p>Report NOBT as "precision" through the dbAccess API.
|
||||
This is not accessible through CA, but is planned to be used through
|
||||
QSRV.</p>
|
||||
|
||||
<h1 align="center">EPICS Release 7.0.2.2</h1>
|
||||
|
||||
<h3>Build System changes</h3>
|
||||
|
||||
<ul>
|
||||
@@ -1015,6 +1037,15 @@ of its CALLBACK objects.</p>
|
||||
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Cleaning up with Multiple CA contexts in a Process</h3>
|
||||
|
||||
<p>Bruno Martins reported a problem with the CA client library at shutdown in a
|
||||
process that uses multiple CA client contexts. The first context that triggers
|
||||
the CA client exit handler prevents any others from being able to clean up
|
||||
because it resets the ID of an internal epicsThreadPrivate variable which is
|
||||
shared by all clients. This action has been removed from the client library,
|
||||
which makes cleanup of clients like this possible.</p>
|
||||
|
||||
<h3>Perl CA bindings fixed for macOS Mojave</h3>
|
||||
|
||||
<p>Apple removed some Perl header files from macOS Mojave that were available
|
||||
|
||||
@@ -126,9 +126,10 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Website Manager</td>
|
||||
<td>Create a release milestone on Launchpad if necessary and set the
|
||||
expected release date. Note that pre-release and release-candidate
|
||||
versions do not appear on Launchpad, only the final release.</td>
|
||||
<td>Create a release milestone on Launchpad. If a target release date is
|
||||
known set "Date Targeted" to the expected release date. Note that
|
||||
pre-release and release-candidate versions should not get Launchpad
|
||||
milestones, only the final release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Creating pre-release and release-candidate versions</th>
|
||||
@@ -146,17 +147,17 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Tag the module in Git, using these tag conventions:
|
||||
<ul>
|
||||
<li>
|
||||
<tt>R7.0.2-pre<i>n</i></tt>
|
||||
<tt>R7.0.3-pre<i>n</i></tt>
|
||||
— pre-release tag
|
||||
</li>
|
||||
<li>
|
||||
<tt>R7.0.2-rc<i>n</i></tt>
|
||||
<tt>R7.0.3-rc<i>n</i></tt>
|
||||
— release candidate tag
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for 7.0.2-rc1' R7.0.2-rc1
|
||||
git tag -m 'ANJ: Tagged for 7.0.3-rc1' R7.0.3-rc1
|
||||
</tt></blockquote>
|
||||
Note that submodules must <em>not</em> be tagged with the version used
|
||||
for the top-level, they each have their own separate version numbers
|
||||
@@ -170,11 +171,11 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.2-rc1 base-7.0.2-rc1.tar.gz base-7.0.2-rc1/
|
||||
./.tools/make-tar.sh R7.0.3-rc1 base-7.0.3-rc1.tar.gz base-7.0.3-rc1/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-7.0.2-rc1.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.3-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -302,7 +303,7 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Tag the epics-base module in Git:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for 7.0.2.2' R7.0.2.2</i>
|
||||
git tag -m 'ANJ: Tagged for 7.0.3' R7.0.3</i>
|
||||
</tt></blockquote>
|
||||
Don't push the new tag to the Launchpad repository yet.</td>
|
||||
</tr>
|
||||
@@ -314,11 +315,11 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.2.2 base-7.0.2.2.tar.gz base-7.0.2.2/
|
||||
./.tools/make-tar.sh R7.0.3 base-7.0.3.tar.gz base-7.0.3/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-7.0.2.2.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.3.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -348,27 +349,16 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
with a "-DEV" tag added (where applicable).
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="3">Publish to epics.anl.gov</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Copy the tarfile and its signature to the Base download area of the
|
||||
website.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Find all Launchpad bug reports with the status Fix Committed which
|
||||
have been fixed in this release and mark them Fix Released.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Publish and Announce it</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
Launchpad milestone for this release version.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
@@ -400,6 +390,47 @@ starting at <a href="#ReleaseApproval">Release Approval</a>.</p>
|
||||
<td>Add an entry to the website News page, linking to the new version
|
||||
webpage.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="3">Publish to epics-controls</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
epics-controls web-server [ToDo: ssh-key, location]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Follow instructions on
|
||||
<a href="https://epics-controls.org/resources-and-support/documents/epics-website-documentation/adding-a-page-for-a-new-release/">
|
||||
Add a page for a new release</a> to create a new release webpage (not
|
||||
required for a patch release though, just edit the existing page).</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="3">Publish to Launchpad</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Website Manager</td>
|
||||
<td>Go to the Launchpad milestone for this release. Click the Create
|
||||
release button and add the release date. Put a URL for the release page
|
||||
in the Release notes box, and click the Create release button. Upload
|
||||
the tar file and its <tt>.asc</tt> signature file to the new Launchpad
|
||||
release page.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Find all Launchpad bug reports with the status Fix Committed which
|
||||
have been fixed in this release and mark them Fix Released.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="3">Make Announcement</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 13
|
||||
EPICS_CA_MAINTENANCE_VERSION = 3
|
||||
EPICS_CA_MAINTENANCE_VERSION = 4
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 0
|
||||
|
||||
@@ -3143,7 +3143,8 @@ indicating the current state of the channel.</p>
|
||||
<dl>
|
||||
<dt><code>COUNT</code></dt>
|
||||
<dd>The element count to be read from the specified channel. A count of
|
||||
zero means use the current element count from the server.</dd>
|
||||
zero means use the current element count from the server, effectively
|
||||
resulting in a variable size array subscription.</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><code>CHID</code></dt>
|
||||
|
||||
@@ -45,20 +45,12 @@ static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
const unsigned ca_client_context :: flushBlockThreshold = 0x58000;
|
||||
|
||||
extern "C" void cacExitHandler ( void *)
|
||||
{
|
||||
epicsThreadPrivateDelete ( caClientCallbackThreadId );
|
||||
caClientCallbackThreadId = 0;
|
||||
delete ca_client_context::pDefaultServiceInstallMutex;
|
||||
}
|
||||
|
||||
// runs once only for each process
|
||||
extern "C" void cacOnceFunc ( void * )
|
||||
{
|
||||
caClientCallbackThreadId = epicsThreadPrivateCreate ();
|
||||
assert ( caClientCallbackThreadId );
|
||||
ca_client_context::pDefaultServiceInstallMutex = newEpicsMutex;
|
||||
epicsAtExit ( cacExitHandler,0 );
|
||||
}
|
||||
|
||||
extern epicsThreadPrivateId caClientContextId;
|
||||
@@ -67,6 +59,8 @@ cacService * ca_client_context::pDefaultService = 0;
|
||||
epicsMutex * ca_client_context::pDefaultServiceInstallMutex;
|
||||
|
||||
ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
|
||||
mutex(__FILE__, __LINE__),
|
||||
cbMutex(__FILE__, __LINE__),
|
||||
createdByThread ( epicsThreadGetIdSelf () ),
|
||||
ca_exception_func ( 0 ), ca_exception_arg ( 0 ),
|
||||
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ),
|
||||
|
||||
@@ -289,7 +289,6 @@ private:
|
||||
};
|
||||
|
||||
extern "C" void cacOnceFunc ( void * );
|
||||
extern "C" void cacExitHandler ( void *);
|
||||
|
||||
struct ca_client_context : public cacContextNotify
|
||||
{
|
||||
@@ -429,7 +428,6 @@ private:
|
||||
ca_client_context & operator = ( const ca_client_context & );
|
||||
|
||||
friend void cacOnceFunc ( void * );
|
||||
friend void cacExitHandler ( void *);
|
||||
static cacService * pDefaultService;
|
||||
static epicsMutex * pDefaultServiceInstallMutex;
|
||||
static const unsigned flushBlockThreshold;
|
||||
|
||||
@@ -37,6 +37,7 @@ repeaterSubscribeTimer::repeaterSubscribeTimer (
|
||||
epicsMutex & cbMutexIn, cacContextNotify & ctxNotifyIn ) :
|
||||
timer ( queueIn.createTimer () ), iiu ( iiuIn ),
|
||||
cbMutex ( cbMutexIn ),ctxNotify ( ctxNotifyIn ),
|
||||
stateMutex(__FILE__, __LINE__),
|
||||
attempts ( 0 ), registered ( false ), once ( false )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 17
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 3
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 4
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef struct cbQueueSet {
|
||||
epicsRingPointerId queue;
|
||||
int queueOverflow;
|
||||
int queueOverflows;
|
||||
int shutdown;
|
||||
int shutdown; // use atomic
|
||||
int threadsConfigured;
|
||||
int threadsRunning;
|
||||
} cbQueueSet;
|
||||
@@ -71,12 +71,15 @@ epicsExportAddress(int,callbackParallelThreadsDefault);
|
||||
/* Timer for Delayed Requests */
|
||||
static epicsTimerQueueId timerQueue;
|
||||
|
||||
/* Shutdown handling */
|
||||
enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
|
||||
static volatile enum ctl cbCtl;
|
||||
static epicsEventId startStopEvent;
|
||||
enum cbState_t {
|
||||
cbInit, /* before callbackInit() and after callbackCleanup() */
|
||||
cbRun, /* after callbackInit() and before callbackStop() */
|
||||
cbStop, /* after callbackStop() and before callbackCleanup() */
|
||||
};
|
||||
|
||||
static int callbackIsInit;
|
||||
static int cbState; // holdscbState_t, use atomic ops
|
||||
|
||||
static epicsEventId startStopEvent;
|
||||
|
||||
/* Static data */
|
||||
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
|
||||
@@ -96,7 +99,7 @@ static int priorityValue[NUM_CALLBACK_PRIORITIES] = {0, 1, 2};
|
||||
|
||||
int callbackSetQueueSize(int size)
|
||||
{
|
||||
if (callbackIsInit) {
|
||||
if (epicsAtomicGetIntT(&cbState)!=cbInit) {
|
||||
fprintf(stderr, "Callback system already initialized\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -107,7 +110,7 @@ int callbackSetQueueSize(int size)
|
||||
int callbackQueueStatus(const int reset, callbackQueueStats *result)
|
||||
{
|
||||
int ret;
|
||||
if (!callbackIsInit) return -1;
|
||||
if (epicsAtomicGetIntT(&cbState)==cbInit) return -1;
|
||||
if (result) {
|
||||
int prio;
|
||||
result->size = callbackQueueSize;
|
||||
@@ -151,7 +154,7 @@ void callbackQueueShow(const int reset)
|
||||
|
||||
int callbackParallelThreads(int count, const char *prio)
|
||||
{
|
||||
if (callbackIsInit) {
|
||||
if (epicsAtomicGetIntT(&cbState)!=cbInit) {
|
||||
fprintf(stderr, "Callback system already initialized\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -207,7 +210,7 @@ static void callbackTask(void *arg)
|
||||
taskwdInsert(0, NULL, NULL);
|
||||
epicsEventSignal(startStopEvent);
|
||||
|
||||
while(!mySet->shutdown) {
|
||||
while(!epicsAtomicGetIntT(&mySet->shutdown)) {
|
||||
void *ptr;
|
||||
if (epicsRingPointerIsEmpty(mySet->queue))
|
||||
epicsEventMustWait(mySet->semWakeUp);
|
||||
@@ -230,11 +233,10 @@ void callbackStop(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cbCtl == ctlExit) return;
|
||||
cbCtl = ctlExit;
|
||||
if (epicsAtomicCmpAndSwapIntT(&cbState, cbRun, cbStop)!=cbRun) return;
|
||||
|
||||
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
|
||||
callbackQueue[i].shutdown = 1;
|
||||
epicsAtomicSetIntT(&callbackQueue[i].shutdown, 1);
|
||||
epicsEventSignal(callbackQueue[i].semWakeUp);
|
||||
}
|
||||
|
||||
@@ -252,6 +254,10 @@ void callbackCleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(epicsAtomicCmpAndSwapIntT(&cbState, cbStop, cbInit)!=cbStop) {
|
||||
fprintf(stderr, "callbackCleanup() but not stopped\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
|
||||
cbQueueSet *mySet = &callbackQueue[i];
|
||||
|
||||
@@ -261,7 +267,6 @@ void callbackCleanup(void)
|
||||
}
|
||||
|
||||
epicsTimerQueueRelease(timerQueue);
|
||||
callbackIsInit = 0;
|
||||
memset(callbackQueue, 0, sizeof(callbackQueue));
|
||||
}
|
||||
|
||||
@@ -271,15 +276,14 @@ void callbackInit(void)
|
||||
int j;
|
||||
char threadName[32];
|
||||
|
||||
if (callbackIsInit) {
|
||||
errlogMessage("Warning: callbackInit called again before callbackCleanup\n");
|
||||
if (epicsAtomicCmpAndSwapIntT(&cbState, cbInit, cbRun)!=cbInit) {
|
||||
fprintf(stderr, "Warning: callbackInit called again before callbackCleanup\n");
|
||||
return;
|
||||
}
|
||||
callbackIsInit = 1;
|
||||
|
||||
if(!startStopEvent)
|
||||
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
cbCtl = ctlRun;
|
||||
|
||||
timerQueue = epicsTimerQueueAllocate(0, epicsThreadPriorityScanHigh);
|
||||
|
||||
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
|
||||
|
||||
@@ -49,7 +49,13 @@
|
||||
#include "link.h"
|
||||
#include "special.h"
|
||||
|
||||
#define EVENTSPERQUE 32
|
||||
/* Queue size based on Ethernet MTU of 1500 bytes.
|
||||
* Assume <=66 bytes of ethernet+IP+TCP overhead
|
||||
* and 40 byte CA messages (DBF_TIME_DOUBLE).
|
||||
*
|
||||
* (1500-66)/40 -> 35
|
||||
*/
|
||||
#define EVENTSPERQUE 36
|
||||
#define EVENTENTRIES 4 /* the number of que entries for each event */
|
||||
#define EVENTQUESIZE (EVENTENTRIES * EVENTSPERQUE)
|
||||
#define EVENTQEMPTY ((struct evSubscrip *)NULL)
|
||||
|
||||
@@ -13,7 +13,7 @@ SRC_DIRS += $(IOCDIR)/dbtemplate
|
||||
|
||||
PROD_HOST += msi
|
||||
|
||||
msi_SRCS = msi.c
|
||||
msi_SRCS = msi.cpp
|
||||
msi_LIBS += Com
|
||||
HTMLS += msi.html
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
/* msi - macro substitutions and include */
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -18,7 +21,6 @@
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include <macLib.h>
|
||||
#include <ellLib.h>
|
||||
#include <errlog.h>
|
||||
#include <epicsString.h>
|
||||
#include <osiFileName.h>
|
||||
@@ -56,32 +58,35 @@ int din = 0;
|
||||
typedef struct inputData inputData;
|
||||
|
||||
static void inputConstruct(inputData **ppvt);
|
||||
static void inputDestruct(inputData *pvt);
|
||||
static void inputAddPath(inputData *pvt, char *pval);
|
||||
static void inputBegin(inputData *pvt, char *fileName);
|
||||
static char *inputNextLine(inputData *pvt);
|
||||
static void inputNewIncludeFile(inputData *pvt, char *name);
|
||||
static void inputErrPrint(inputData *pvt);
|
||||
static void inputDestruct(inputData * const pvt);
|
||||
static void inputAddPath(inputData * const pvt, const char * const pval);
|
||||
static void inputBegin(inputData * const pvt, const char * const fileName);
|
||||
static char *inputNextLine(inputData * const pvt);
|
||||
static void inputNewIncludeFile(inputData * const pvt, const char * const name);
|
||||
static void inputErrPrint(const inputData * const pvt);
|
||||
|
||||
/* Module to read the substitution file */
|
||||
typedef struct subInfo subInfo;
|
||||
|
||||
static void substituteOpen(subInfo **ppvt, char *substitutionName);
|
||||
static void substituteDestruct(subInfo *pvt);
|
||||
static int substituteGetNextSet(subInfo *pvt, char **filename);
|
||||
static int substituteGetGlobalSet(subInfo *pvt);
|
||||
static char *substituteGetReplacements(subInfo *pvt);
|
||||
static char *substituteGetGlobalReplacements(subInfo *pvt);
|
||||
static void substituteOpen(subInfo **ppvt, const std::string& substitutionName);
|
||||
static void substituteDestruct(subInfo * const pvt);
|
||||
static bool substituteGetNextSet(subInfo * const pvt, char **filename);
|
||||
static bool substituteGetGlobalSet(subInfo * const pvt);
|
||||
static const char *substituteGetReplacements(subInfo * const pvt);
|
||||
static const char *substituteGetGlobalReplacements(subInfo * const pvt);
|
||||
|
||||
/* Forward references to local routines */
|
||||
static void usageExit(int status);
|
||||
static void abortExit(int status);
|
||||
static void addMacroReplacements(MAC_HANDLE *macPvt, char *pval);
|
||||
static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName);
|
||||
static void usageExit(const int status);
|
||||
static void abortExit(const int status);
|
||||
static void addMacroReplacements(MAC_HANDLE * const macPvt,
|
||||
const char * const pval);
|
||||
static void makeSubstitutions(inputData * const inputPvt,
|
||||
MAC_HANDLE * const macPvt,
|
||||
const char * const templateName);
|
||||
|
||||
/*Global variables */
|
||||
static int opt_V = 0;
|
||||
static int opt_D = 0;
|
||||
static bool opt_D = false;
|
||||
|
||||
static char *outFile = 0;
|
||||
static int numDeps = 0, depHashes[MAX_DEPS];
|
||||
@@ -92,23 +97,21 @@ int main(int argc,char **argv)
|
||||
inputData *inputPvt;
|
||||
MAC_HANDLE *macPvt;
|
||||
char *pval;
|
||||
int narg;
|
||||
char *substitutionName = 0;
|
||||
std::string substitutionName;
|
||||
char *templateName = 0;
|
||||
int i;
|
||||
int localScope = 1;
|
||||
bool localScope = true;
|
||||
|
||||
inputConstruct(&inputPvt);
|
||||
macCreateHandle(&macPvt, 0);
|
||||
while ((argc > 1) && (argv[1][0] == '-')) {
|
||||
narg = (strlen(argv[1]) == 2) ? 2 : 1;
|
||||
int narg = (strlen(argv[1]) == 2) ? 2 : 1;
|
||||
pval = (narg == 1) ? (argv[1] + 2) : argv[2];
|
||||
|
||||
if (strncmp(argv[1], "-I", 2) == 0) {
|
||||
inputAddPath(inputPvt, pval);
|
||||
}
|
||||
else if (strcmp(argv[1], "-D") == 0) {
|
||||
opt_D = 1;
|
||||
opt_D = true;
|
||||
narg = 1; /* no argument for this option */
|
||||
}
|
||||
else if(strncmp(argv[1], "-o", 2) == 0) {
|
||||
@@ -118,14 +121,14 @@ int main(int argc,char **argv)
|
||||
addMacroReplacements(macPvt, pval);
|
||||
}
|
||||
else if(strncmp(argv[1], "-S", 2) == 0) {
|
||||
substitutionName = epicsStrDup(pval);
|
||||
substitutionName = pval;
|
||||
}
|
||||
else if (strcmp(argv[1], "-V") == 0) {
|
||||
opt_V = 1;
|
||||
narg = 1; /* no argument for this option */
|
||||
}
|
||||
else if (strcmp(argv[1], "-g") == 0) {
|
||||
localScope = 0;
|
||||
localScope = false;
|
||||
narg = 1; /* no argument for this option */
|
||||
}
|
||||
else if (strcmp(argv[1], "-h") == 0) {
|
||||
@@ -137,7 +140,7 @@ int main(int argc,char **argv)
|
||||
}
|
||||
|
||||
argc -= narg;
|
||||
for (i = 1; i < argc; i++)
|
||||
for (int i = 1; i < argc; i++)
|
||||
argv[i] = argv[i + narg];
|
||||
}
|
||||
|
||||
@@ -165,24 +168,24 @@ int main(int argc,char **argv)
|
||||
if (argc == 2)
|
||||
templateName = epicsStrDup(argv[1]);
|
||||
|
||||
if (!substitutionName) {
|
||||
if (substitutionName.empty()) {
|
||||
STEP("Single template+substitutions file");
|
||||
makeSubstitutions(inputPvt, macPvt, templateName);
|
||||
}
|
||||
else {
|
||||
subInfo *substitutePvt;
|
||||
char *filename = 0;
|
||||
int isGlobal, isFile;
|
||||
bool isGlobal, isFile;
|
||||
|
||||
STEPS("Substitutions from file", substitutionName);
|
||||
STEPS("Substitutions from file", substitutionName.c_str());
|
||||
substituteOpen(&substitutePvt, substitutionName);
|
||||
do {
|
||||
isGlobal = substituteGetGlobalSet(substitutePvt);
|
||||
if (isGlobal) {
|
||||
STEP("Handling global macros");
|
||||
pval = substituteGetGlobalReplacements(substitutePvt);
|
||||
if (pval)
|
||||
addMacroReplacements(macPvt, pval);
|
||||
const char *macStr = substituteGetGlobalReplacements(substitutePvt);
|
||||
if (macStr)
|
||||
addMacroReplacements(macPvt, macStr);
|
||||
}
|
||||
else if ((isFile = substituteGetNextSet(substitutePvt, &filename))) {
|
||||
if (templateName)
|
||||
@@ -193,11 +196,12 @@ int main(int argc,char **argv)
|
||||
}
|
||||
|
||||
STEPS("Handling template file", filename);
|
||||
while ((pval = substituteGetReplacements(substitutePvt))) {
|
||||
const char *macStr;
|
||||
while ((macStr = substituteGetReplacements(substitutePvt))) {
|
||||
if (localScope)
|
||||
macPushScope(macPvt);
|
||||
|
||||
addMacroReplacements(macPvt, pval);
|
||||
addMacroReplacements(macPvt, macStr);
|
||||
makeSubstitutions(inputPvt, macPvt, filename);
|
||||
|
||||
if (localScope)
|
||||
@@ -207,18 +211,18 @@ int main(int argc,char **argv)
|
||||
} while (isGlobal || isFile);
|
||||
substituteDestruct(substitutePvt);
|
||||
}
|
||||
errlogFlush();
|
||||
macDeleteHandle(macPvt);
|
||||
errlogFlush(); // macLib calls errlogPrintf()
|
||||
inputDestruct(inputPvt);
|
||||
if (opt_D) {
|
||||
printf("\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
free(templateName);
|
||||
free(substitutionName);
|
||||
return opt_V & 2;
|
||||
}
|
||||
|
||||
void usageExit(int status)
|
||||
void usageExit(const int status)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: msi [options] [template]\n"
|
||||
@@ -236,7 +240,7 @@ void usageExit(int status)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void abortExit(int status)
|
||||
void abortExit(const int status)
|
||||
{
|
||||
if (outFile) {
|
||||
fclose(stdout);
|
||||
@@ -245,7 +249,8 @@ void abortExit(int status)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static void addMacroReplacements(MAC_HANDLE *macPvt, char *pval)
|
||||
static void addMacroReplacements(MAC_HANDLE * const macPvt,
|
||||
const char * const pval)
|
||||
{
|
||||
char **pairs;
|
||||
long status;
|
||||
@@ -268,7 +273,9 @@ static void addMacroReplacements(MAC_HANDLE *macPvt, char *pval)
|
||||
typedef enum {cmdInclude,cmdSubstitute} cmdType;
|
||||
static const char *cmdNames[] = {"include","substitute"};
|
||||
|
||||
static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName)
|
||||
static void makeSubstitutions(inputData * const inputPvt,
|
||||
MAC_HANDLE * const macPvt,
|
||||
const char * const templateName)
|
||||
{
|
||||
char *input;
|
||||
static char buffer[MAX_BUFFER_SIZE];
|
||||
@@ -292,7 +299,6 @@ static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *tem
|
||||
if (command) {
|
||||
char *pstart;
|
||||
char *pend;
|
||||
char *copy;
|
||||
int cmdind=-1;
|
||||
int i;
|
||||
|
||||
@@ -325,16 +331,15 @@ static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *tem
|
||||
/*skip quote and any trailing blanks*/
|
||||
while (*++p == ' ') ;
|
||||
if (*p != '\n' && *p != 0) goto endcmd;
|
||||
copy = calloc(pend-pstart + 1, sizeof(char));
|
||||
strncpy(copy, pstart, pend-pstart);
|
||||
std::string copy = std::string(pstart, pend);
|
||||
|
||||
switch(cmdind) {
|
||||
case cmdInclude:
|
||||
inputNewIncludeFile(inputPvt,copy);
|
||||
inputNewIncludeFile(inputPvt, copy.c_str());
|
||||
break;
|
||||
|
||||
case cmdSubstitute:
|
||||
addMacroReplacements(macPvt,copy);
|
||||
addMacroReplacements(macPvt, copy.c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -342,7 +347,6 @@ static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *tem
|
||||
inputErrPrint(inputPvt);
|
||||
abortExit(1);
|
||||
}
|
||||
free(copy);
|
||||
expand = 0;
|
||||
}
|
||||
|
||||
@@ -361,94 +365,72 @@ endcmd:
|
||||
}
|
||||
|
||||
typedef struct inputFile {
|
||||
ELLNODE node;
|
||||
char *filename;
|
||||
std::string filename;
|
||||
FILE *fp;
|
||||
int lineNum;
|
||||
} inputFile;
|
||||
|
||||
typedef struct pathNode {
|
||||
ELLNODE node;
|
||||
char *directory;
|
||||
} pathNode;
|
||||
|
||||
struct inputData {
|
||||
ELLLIST inputFileList;
|
||||
ELLLIST pathList;
|
||||
std::list<inputFile> inputFileList;
|
||||
std::list<std::string> pathList;
|
||||
char inputBuffer[MAX_BUFFER_SIZE];
|
||||
inputData() { memset(inputBuffer, 0, sizeof(inputBuffer) * sizeof(inputBuffer[0])); };
|
||||
};
|
||||
|
||||
static void inputOpenFile(inputData *pinputData, char *filename);
|
||||
static void inputOpenFile(inputData *pinputData, const char * const filename);
|
||||
static void inputCloseFile(inputData *pinputData);
|
||||
static void inputCloseAllFiles(inputData *pinputData);
|
||||
|
||||
static void inputConstruct(inputData **ppvt)
|
||||
{
|
||||
inputData *pinputData;
|
||||
|
||||
pinputData = calloc(1, sizeof(inputData));
|
||||
ellInit(&pinputData->inputFileList);
|
||||
ellInit(&pinputData->pathList);
|
||||
*ppvt = pinputData;
|
||||
*ppvt = new inputData;
|
||||
}
|
||||
|
||||
static void inputDestruct(inputData *pinputData)
|
||||
static void inputDestruct(inputData * const pinputData)
|
||||
{
|
||||
pathNode *ppathNode;
|
||||
|
||||
inputCloseAllFiles(pinputData);
|
||||
while ((ppathNode = (pathNode *) ellFirst(&pinputData->pathList))) {
|
||||
ellDelete(&pinputData->pathList, &ppathNode->node);
|
||||
free(ppathNode->directory);
|
||||
free(ppathNode);
|
||||
}
|
||||
free(pinputData);
|
||||
delete(pinputData);
|
||||
}
|
||||
|
||||
static void inputAddPath(inputData *pinputData, char *path)
|
||||
static void inputAddPath(inputData * const pinputData, const char * const path)
|
||||
{
|
||||
ELLLIST *ppathList = &pinputData->pathList;
|
||||
pathNode *ppathNode;
|
||||
const char *pcolon;
|
||||
const char *pdir;
|
||||
size_t len;
|
||||
int emptyName;
|
||||
const char sep = *OSI_PATH_LIST_SEPARATOR;
|
||||
|
||||
ENTER;
|
||||
pdir = path;
|
||||
/*an empty name at beginning, middle, or end means current directory*/
|
||||
while (pdir && *pdir) {
|
||||
emptyName = ((*pdir == sep) ? 1 : 0);
|
||||
bool emptyName = (*pdir == sep);
|
||||
if (emptyName) ++pdir;
|
||||
|
||||
ppathNode = (pathNode *) calloc(1, sizeof(pathNode));
|
||||
ellAdd(ppathList, &ppathNode->node);
|
||||
|
||||
std::string directory;
|
||||
if (!emptyName) {
|
||||
pcolon = strchr(pdir, sep);
|
||||
len = (pcolon ? (pcolon - pdir) : strlen(pdir));
|
||||
if (len > 0) {
|
||||
ppathNode->directory = (char *) calloc(len + 1, sizeof(char));
|
||||
strncpy(ppathNode->directory, pdir, len);
|
||||
directory = std::string(pdir, len);
|
||||
pdir = pcolon;
|
||||
/*unless at end skip past first colon*/
|
||||
if (pdir && *(pdir + 1) != 0) ++pdir;
|
||||
}
|
||||
else { /*must have been trailing : */
|
||||
emptyName = 1;
|
||||
emptyName = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyName) {
|
||||
ppathNode->directory = (char *) calloc(2, sizeof(char));
|
||||
strcpy(ppathNode->directory, ".");
|
||||
directory = ".";
|
||||
}
|
||||
|
||||
pinputData->pathList.push_back(directory);
|
||||
}
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void inputBegin(inputData *pinputData, char *fileName)
|
||||
static void inputBegin(inputData * const pinputData, const char * const fileName)
|
||||
{
|
||||
ENTER;
|
||||
inputCloseAllFiles(pinputData);
|
||||
@@ -456,16 +438,16 @@ static void inputBegin(inputData *pinputData, char *fileName)
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static char *inputNextLine(inputData *pinputData)
|
||||
static char *inputNextLine(inputData * const pinputData)
|
||||
{
|
||||
inputFile *pinputFile;
|
||||
char *pline;
|
||||
std::list<inputFile>& inFileList = pinputData->inputFileList;
|
||||
|
||||
ENTER;
|
||||
while ((pinputFile = (inputFile *) ellFirst(&pinputData->inputFileList))) {
|
||||
pline = fgets(pinputData->inputBuffer, MAX_BUFFER_SIZE, pinputFile->fp);
|
||||
while (!inFileList.empty()) {
|
||||
inputFile& inFile = inFileList.front();
|
||||
char *pline = fgets(pinputData->inputBuffer, MAX_BUFFER_SIZE, inFile.fp);
|
||||
if (pline) {
|
||||
++pinputFile->lineNum;
|
||||
++inFile.lineNum;
|
||||
EXITS(pline);
|
||||
return pline;
|
||||
}
|
||||
@@ -475,32 +457,31 @@ static char *inputNextLine(inputData *pinputData)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inputNewIncludeFile(inputData *pinputData, char *name)
|
||||
static void inputNewIncludeFile(inputData * const pinputData,
|
||||
const char * const name)
|
||||
{
|
||||
ENTER;
|
||||
inputOpenFile(pinputData,name);
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void inputErrPrint(inputData *pinputData)
|
||||
static void inputErrPrint(const inputData *const pinputData)
|
||||
{
|
||||
inputFile *pinputFile;
|
||||
|
||||
ENTER;
|
||||
fprintf(stderr, "input: '%s' at ", pinputData->inputBuffer);
|
||||
pinputFile = (inputFile *) ellFirst(&pinputData->inputFileList);
|
||||
while (pinputFile) {
|
||||
fprintf(stderr, "line %d of ", pinputFile->lineNum);
|
||||
const std::list<inputFile>& inFileList = pinputData->inputFileList;
|
||||
std::list<inputFile>::const_iterator inFileIt = inFileList.begin();
|
||||
while (inFileIt != inFileList.end()) {
|
||||
fprintf(stderr, "line %d of ", inFileIt->lineNum);
|
||||
|
||||
if (pinputFile->filename) {
|
||||
fprintf(stderr, " file %s\n", pinputFile->filename);
|
||||
if (!inFileIt->filename.empty()) {
|
||||
fprintf(stderr, " file %s\n", inFileIt->filename.c_str());
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "stdin:\n");
|
||||
}
|
||||
|
||||
pinputFile = (inputFile *) ellNext(&pinputFile->node);
|
||||
if (pinputFile) {
|
||||
if (++inFileIt != inFileList.end()) {
|
||||
fprintf(stderr, " included from ");
|
||||
}
|
||||
else {
|
||||
@@ -511,12 +492,11 @@ static void inputErrPrint(inputData *pinputData)
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void inputOpenFile(inputData *pinputData,char *filename)
|
||||
static void inputOpenFile(inputData *pinputData, const char * const filename)
|
||||
{
|
||||
ELLLIST *ppathList = &pinputData->pathList;
|
||||
pathNode *ppathNode = 0;
|
||||
inputFile *pinputFile;
|
||||
char *fullname = 0;
|
||||
std::list<std::string>& pathList = pinputData->pathList;
|
||||
std::list<std::string>::iterator pathIt = pathList.end();
|
||||
std::string fullname;
|
||||
FILE *fp = 0;
|
||||
|
||||
ENTER;
|
||||
@@ -524,24 +504,19 @@ static void inputOpenFile(inputData *pinputData,char *filename)
|
||||
STEP("Using stdin");
|
||||
fp = stdin;
|
||||
}
|
||||
else if ((ellCount(ppathList) == 0) || strchr(filename, '/')){
|
||||
else if (pathList.empty() || strchr(filename, '/')){
|
||||
STEPS("Opening ", filename);
|
||||
fp = fopen(filename, "r");
|
||||
}
|
||||
else {
|
||||
ppathNode = (pathNode *) ellFirst(ppathList);
|
||||
while (ppathNode) {
|
||||
fullname = calloc(strlen(filename) + strlen(ppathNode->directory) + 2,
|
||||
sizeof(char));
|
||||
strcpy(fullname, ppathNode->directory);
|
||||
strcat(fullname, "/");
|
||||
strcat(fullname, filename);
|
||||
pathIt = pathList.begin();
|
||||
while(pathIt != pathList.end()) {
|
||||
fullname = *pathIt + "/" + filename;
|
||||
STEPS("Trying", filename);
|
||||
fp = fopen(fullname, "r");
|
||||
fp = fopen(fullname.c_str(), "r");
|
||||
if (fp)
|
||||
break;
|
||||
free(fullname);
|
||||
ppathNode = (pathNode *) ellNext(&ppathNode->node);
|
||||
++pathIt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,20 +527,20 @@ static void inputOpenFile(inputData *pinputData,char *filename)
|
||||
}
|
||||
|
||||
STEP("File opened");
|
||||
pinputFile = calloc(1, sizeof(inputFile));
|
||||
inputFile inFile = inputFile();
|
||||
|
||||
if (ppathNode) {
|
||||
pinputFile->filename = fullname;
|
||||
if (pathIt != pathList.end()) {
|
||||
inFile.filename = fullname;
|
||||
}
|
||||
else if (filename) {
|
||||
pinputFile->filename = epicsStrDup(filename);
|
||||
inFile.filename = filename;
|
||||
}
|
||||
else {
|
||||
pinputFile->filename = epicsStrDup("stdin");
|
||||
inFile.filename = "stdin";
|
||||
}
|
||||
|
||||
if (opt_D) {
|
||||
int hash = epicsStrHash(pinputFile->filename, 12345);
|
||||
int hash = epicsStrHash(inFile.filename.c_str(), 12345);
|
||||
int i = 0;
|
||||
int match = 0;
|
||||
|
||||
@@ -578,7 +553,7 @@ static void inputOpenFile(inputData *pinputData,char *filename)
|
||||
if (!match) {
|
||||
const char *wrap = numDeps ? " \\\n" : "";
|
||||
|
||||
printf("%s %s", wrap, pinputFile->filename);
|
||||
printf("%s %s", wrap, inFile.filename.c_str());
|
||||
if (numDeps < MAX_DEPS) {
|
||||
depHashes[numDeps++] = hash;
|
||||
}
|
||||
@@ -589,33 +564,29 @@ static void inputOpenFile(inputData *pinputData,char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
pinputFile->fp = fp;
|
||||
ellInsert(&pinputData->inputFileList, 0, &pinputFile->node);
|
||||
inFile.fp = fp;
|
||||
pinputData->inputFileList.push_front(inFile);
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void inputCloseFile(inputData *pinputData)
|
||||
{
|
||||
inputFile *pinputFile;
|
||||
|
||||
std::list<inputFile>& inFileList = pinputData->inputFileList;
|
||||
ENTER;
|
||||
pinputFile = (inputFile *) ellFirst(&pinputData->inputFileList);
|
||||
if (pinputFile) {
|
||||
ellDelete(&pinputData->inputFileList, &pinputFile->node);
|
||||
if (fclose(pinputFile->fp))
|
||||
fprintf(stderr, "msi: Can't close input file '%s'\n", pinputFile->filename);
|
||||
free(pinputFile->filename);
|
||||
free(pinputFile);
|
||||
if(!inFileList.empty()) {
|
||||
inputFile& inFile = inFileList.front();
|
||||
if (fclose(inFile.fp))
|
||||
fprintf(stderr, "msi: Can't close input file '%s'\n", inFile.filename.c_str());
|
||||
inFileList.erase(inFileList.begin());
|
||||
}
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void inputCloseAllFiles(inputData *pinputData)
|
||||
{
|
||||
inputFile *pinputFile;
|
||||
|
||||
ENTER;
|
||||
while ((pinputFile = (inputFile *) ellFirst(&pinputData->inputFileList))) {
|
||||
const std::list<inputFile>& inFileList = pinputData->inputFileList;
|
||||
while(!inFileList.empty()) {
|
||||
inputCloseFile(pinputData);
|
||||
}
|
||||
EXIT;
|
||||
@@ -627,7 +598,7 @@ typedef enum {
|
||||
} tokenType;
|
||||
|
||||
typedef struct subFile {
|
||||
char *substitutionName;
|
||||
std::string substitutionName;
|
||||
FILE *fp;
|
||||
int lineNum;
|
||||
char inputBuffer[MAX_BUFFER_SIZE];
|
||||
@@ -636,25 +607,20 @@ typedef struct subFile {
|
||||
char string[MAX_BUFFER_SIZE];
|
||||
} subFile;
|
||||
|
||||
typedef struct patternNode {
|
||||
ELLNODE node;
|
||||
char *var;
|
||||
} patternNode;
|
||||
|
||||
struct subInfo {
|
||||
subFile *psubFile;
|
||||
int isFile;
|
||||
bool isFile;
|
||||
char *filename;
|
||||
int isPattern;
|
||||
ELLLIST patternList;
|
||||
size_t size;
|
||||
size_t curLength;
|
||||
char *macroReplacements;
|
||||
bool isPattern;
|
||||
std::list<std::string> patternList;
|
||||
std::string macroReplacements;
|
||||
subInfo() : psubFile(NULL), isFile(false), filename(NULL),
|
||||
isPattern(false) {};
|
||||
};
|
||||
|
||||
static char *subGetNextLine(subFile *psubFile);
|
||||
static tokenType subGetNextToken(subFile *psubFile);
|
||||
static void subFileErrPrint(subFile *psubFile,char * message);
|
||||
static void subFileErrPrint(subFile *psubFile, const char * message);
|
||||
static void freeSubFile(subInfo *psubInfo);
|
||||
static void freePattern(subInfo *psubInfo);
|
||||
static void catMacroReplacements(subInfo *psubInfo,const char *value);
|
||||
@@ -668,7 +634,7 @@ void freeSubFile(subInfo *psubInfo)
|
||||
if (fclose(psubFile->fp))
|
||||
fprintf(stderr, "msi: Can't close substitution file\n");
|
||||
}
|
||||
free(psubFile);
|
||||
delete(psubFile);
|
||||
free(psubInfo->filename);
|
||||
psubInfo->psubFile = 0;
|
||||
EXIT;
|
||||
@@ -676,43 +642,36 @@ void freeSubFile(subInfo *psubInfo)
|
||||
|
||||
void freePattern(subInfo *psubInfo)
|
||||
{
|
||||
patternNode *ppatternNode;
|
||||
|
||||
ENTER;
|
||||
while ((ppatternNode = (patternNode *) ellFirst(&psubInfo->patternList))) {
|
||||
ellDelete(&psubInfo->patternList, &ppatternNode->node);
|
||||
free(ppatternNode->var);
|
||||
free(ppatternNode);
|
||||
}
|
||||
psubInfo->isPattern = 0;
|
||||
psubInfo->patternList.clear();
|
||||
psubInfo->isPattern = false;
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void substituteDestruct(subInfo *psubInfo)
|
||||
static void substituteDestruct(subInfo * const psubInfo)
|
||||
{
|
||||
ENTER;
|
||||
freeSubFile(psubInfo);
|
||||
freePattern(psubInfo);
|
||||
free(psubInfo);
|
||||
delete(psubInfo);
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static void substituteOpen(subInfo **ppvt, char *substitutionName)
|
||||
static void substituteOpen(subInfo **ppvt, const std::string& substitutionName)
|
||||
{
|
||||
subInfo *psubInfo;
|
||||
subFile *psubFile;
|
||||
FILE *fp;
|
||||
|
||||
ENTER;
|
||||
psubInfo = calloc(1, sizeof(subInfo));
|
||||
psubInfo = new subInfo;
|
||||
*ppvt = psubInfo;
|
||||
psubFile = calloc(1, sizeof(subFile));
|
||||
psubFile = new subFile;
|
||||
psubInfo->psubFile = psubFile;
|
||||
ellInit(&psubInfo->patternList);
|
||||
|
||||
fp = fopen(substitutionName, "r");
|
||||
fp = fopen(substitutionName.c_str(), "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "msi: Can't open file '%s'\n", substitutionName);
|
||||
fprintf(stderr, "msi: Can't open file '%s'\n", substitutionName.c_str());
|
||||
abortExit(1);
|
||||
}
|
||||
|
||||
@@ -725,7 +684,7 @@ static void substituteOpen(subInfo **ppvt, char *substitutionName)
|
||||
EXIT;
|
||||
}
|
||||
|
||||
static int substituteGetGlobalSet(subInfo *psubInfo)
|
||||
static bool substituteGetGlobalSet(subInfo * const psubInfo)
|
||||
{
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
|
||||
@@ -737,17 +696,16 @@ static int substituteGetGlobalSet(subInfo *psubInfo)
|
||||
strcmp(psubFile->string, "global") == 0) {
|
||||
subGetNextToken(psubFile);
|
||||
EXITD(1);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
EXITD(0);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
static bool substituteGetNextSet(subInfo * const psubInfo,char **filename)
|
||||
{
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
patternNode *ppatternNode;
|
||||
|
||||
ENTER;
|
||||
*filename = 0;
|
||||
@@ -756,7 +714,7 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
|
||||
if (psubFile->token == tokenEOF) {
|
||||
EXITD(0);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (psubFile->token == tokenString &&
|
||||
@@ -764,7 +722,7 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
size_t len;
|
||||
|
||||
STEP("Parsed 'file'");
|
||||
psubInfo->isFile = 1;
|
||||
psubInfo->isFile = true;
|
||||
if (subGetNextToken(psubFile) != tokenString) {
|
||||
subFileErrPrint(psubFile, "Parse error, expecting a filename");
|
||||
abortExit(1);
|
||||
@@ -799,7 +757,7 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
|
||||
if (psubFile->token == tokenLBrace) {
|
||||
EXITD(1);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (psubFile->token == tokenRBrace) {
|
||||
@@ -815,7 +773,7 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
|
||||
STEP("Parsed 'pattern'");
|
||||
freePattern(psubInfo);
|
||||
psubInfo->isPattern = 1;
|
||||
psubInfo->isPattern = true;
|
||||
|
||||
while (subGetNextToken(psubFile) == tokenSeparator);
|
||||
|
||||
@@ -825,15 +783,13 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
}
|
||||
STEP("Parsed '{'");
|
||||
|
||||
while (1) {
|
||||
while (true) {
|
||||
while (subGetNextToken(psubFile) == tokenSeparator);
|
||||
|
||||
if (psubFile->token != tokenString)
|
||||
break;
|
||||
|
||||
ppatternNode = calloc(1, sizeof(patternNode));
|
||||
ellAdd(&psubInfo->patternList, &ppatternNode->node);
|
||||
ppatternNode->var = epicsStrDup(psubFile->string);
|
||||
psubInfo->patternList.push_back(psubFile->string);
|
||||
}
|
||||
|
||||
if (psubFile->token != tokenRBrace) {
|
||||
@@ -843,23 +799,21 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename)
|
||||
|
||||
subGetNextToken(psubFile);
|
||||
EXITD(1);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *substituteGetGlobalReplacements(subInfo *psubInfo)
|
||||
static const char *substituteGetGlobalReplacements(subInfo * const psubInfo)
|
||||
{
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
|
||||
ENTER;
|
||||
if (psubInfo->macroReplacements)
|
||||
psubInfo->macroReplacements[0] = 0;
|
||||
psubInfo->curLength = 0;
|
||||
psubInfo->macroReplacements.clear();
|
||||
|
||||
while (psubFile->token == tokenSeparator)
|
||||
subGetNextToken(psubFile);
|
||||
|
||||
if (psubFile->token == tokenRBrace && psubInfo->isFile) {
|
||||
psubInfo->isFile = 0;
|
||||
psubInfo->isFile = false;
|
||||
free(psubInfo->filename);
|
||||
psubInfo->filename = 0;
|
||||
freePattern(psubInfo);
|
||||
@@ -877,12 +831,12 @@ static char *substituteGetGlobalReplacements(subInfo *psubInfo)
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (true) {
|
||||
switch(subGetNextToken(psubFile)) {
|
||||
case tokenRBrace:
|
||||
subGetNextToken(psubFile);
|
||||
EXITS(psubInfo->macroReplacements);
|
||||
return psubInfo->macroReplacements;
|
||||
EXITS(psubInfo->macroReplacements.c_str());
|
||||
return psubInfo->macroReplacements.c_str();
|
||||
|
||||
case tokenSeparator:
|
||||
catMacroReplacements(psubInfo, ",");
|
||||
@@ -902,21 +856,18 @@ static char *substituteGetGlobalReplacements(subInfo *psubInfo)
|
||||
}
|
||||
}
|
||||
|
||||
static char *substituteGetReplacements(subInfo *psubInfo)
|
||||
static const char *substituteGetReplacements(subInfo * const psubInfo)
|
||||
{
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
patternNode *ppatternNode;
|
||||
|
||||
ENTER;
|
||||
if (psubInfo->macroReplacements)
|
||||
psubInfo->macroReplacements[0] = 0;
|
||||
psubInfo->curLength = 0;
|
||||
psubInfo->macroReplacements.clear();
|
||||
|
||||
while (psubFile->token == tokenSeparator)
|
||||
subGetNextToken(psubFile);
|
||||
|
||||
if (psubFile->token==tokenRBrace && psubInfo->isFile) {
|
||||
psubInfo->isFile = 0;
|
||||
psubInfo->isFile = false;
|
||||
free(psubInfo->filename);
|
||||
psubInfo->filename = 0;
|
||||
freePattern(psubInfo);
|
||||
@@ -936,15 +887,16 @@ static char *substituteGetReplacements(subInfo *psubInfo)
|
||||
}
|
||||
|
||||
if (psubInfo->isPattern) {
|
||||
int gotFirstPattern = 0;
|
||||
bool gotFirstPattern = false;
|
||||
|
||||
while (subGetNextToken(psubFile) == tokenSeparator);
|
||||
ppatternNode = (patternNode *) ellFirst(&psubInfo->patternList);
|
||||
while (1) {
|
||||
std::list<std::string>& patternList = psubInfo->patternList;
|
||||
std::list<std::string>::iterator patternIt = patternList.begin();
|
||||
while (true) {
|
||||
if (psubFile->token == tokenRBrace) {
|
||||
subGetNextToken(psubFile);
|
||||
EXITS(psubInfo->macroReplacements);
|
||||
return psubInfo->macroReplacements;
|
||||
EXITS(psubInfo->macroReplacements.c_str());
|
||||
return psubInfo->macroReplacements.c_str();
|
||||
}
|
||||
|
||||
if (psubFile->token != tokenString) {
|
||||
@@ -954,13 +906,13 @@ static char *substituteGetReplacements(subInfo *psubInfo)
|
||||
|
||||
if (gotFirstPattern)
|
||||
catMacroReplacements(psubInfo, ",");
|
||||
gotFirstPattern = 1;
|
||||
gotFirstPattern = true;
|
||||
|
||||
if (ppatternNode) {
|
||||
catMacroReplacements(psubInfo, ppatternNode->var);
|
||||
if (patternIt != patternList.end()) {
|
||||
catMacroReplacements(psubInfo, patternIt->c_str());
|
||||
catMacroReplacements(psubInfo, "=");
|
||||
catMacroReplacements(psubInfo, psubFile->string);
|
||||
ppatternNode = (patternNode *) ellNext(&ppatternNode->node);
|
||||
++patternIt;
|
||||
}
|
||||
else {
|
||||
subFileErrPrint(psubFile, "Warning, too many values given");
|
||||
@@ -969,12 +921,12 @@ static char *substituteGetReplacements(subInfo *psubInfo)
|
||||
while (subGetNextToken(psubFile) == tokenSeparator);
|
||||
}
|
||||
}
|
||||
else while(1) {
|
||||
else while(true) {
|
||||
switch(subGetNextToken(psubFile)) {
|
||||
case tokenRBrace:
|
||||
subGetNextToken(psubFile);
|
||||
EXITS(psubInfo->macroReplacements);
|
||||
return psubInfo->macroReplacements;
|
||||
EXITS(psubInfo->macroReplacements.c_str());
|
||||
return psubInfo->macroReplacements.c_str();
|
||||
|
||||
case tokenSeparator:
|
||||
catMacroReplacements(psubInfo, ",");
|
||||
@@ -1017,11 +969,12 @@ static char *subGetNextLine(subFile *psubFile)
|
||||
return &psubFile->inputBuffer[0];
|
||||
}
|
||||
|
||||
static void subFileErrPrint(subFile *psubFile,char * message)
|
||||
static void subFileErrPrint(subFile *psubFile, const char * message)
|
||||
{
|
||||
fprintf(stderr, "msi: %s\n",message);
|
||||
fprintf(stderr, " in substitution file '%s' at line %d:\n %s",
|
||||
psubFile->substitutionName, psubFile->lineNum, psubFile->inputBuffer);
|
||||
psubFile->substitutionName.c_str(), psubFile->lineNum,
|
||||
psubFile->inputBuffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1107,32 +1060,8 @@ done:
|
||||
|
||||
static void catMacroReplacements(subInfo *psubInfo, const char *value)
|
||||
{
|
||||
size_t len = strlen(value);
|
||||
|
||||
ENTER;
|
||||
if (psubInfo->size <= (psubInfo->curLength + len)) {
|
||||
size_t newsize = psubInfo->size + MAX_BUFFER_SIZE;
|
||||
char *newbuf;
|
||||
|
||||
STEP("Enlarging buffer");
|
||||
if (newsize <= psubInfo->curLength + len)
|
||||
newsize = psubInfo->curLength + len + 1;
|
||||
newbuf = calloc(1, newsize);
|
||||
if (!newbuf) {
|
||||
fprintf(stderr, "calloc failed for size %lu\n",
|
||||
(unsigned long) newsize);
|
||||
abortExit(1);
|
||||
}
|
||||
if (psubInfo->macroReplacements) {
|
||||
memcpy(newbuf, psubInfo->macroReplacements, psubInfo->curLength);
|
||||
free(psubInfo->macroReplacements);
|
||||
}
|
||||
psubInfo->size = newsize;
|
||||
psubInfo->macroReplacements = newbuf;
|
||||
}
|
||||
|
||||
STEPS("Appending", value);
|
||||
strcat(psubInfo->macroReplacements, value);
|
||||
psubInfo->curLength += len;
|
||||
psubInfo->macroReplacements += value;
|
||||
EXIT;
|
||||
}
|
||||
@@ -241,7 +241,7 @@ Assuming there is a system state called "blue", that is being controlled by
|
||||
some other facility such as a timing system, updates could be restricted to
|
||||
periods only when "blue" is true by using
|
||||
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{"while":"blue"}'
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{"sync":{"while":"blue"}}'
|
||||
...
|
||||
|
||||
=cut
|
||||
|
||||
@@ -348,9 +348,9 @@ static long get_enum_strs(const DBADDR *paddr,struct dbr_enumStrs *pes)
|
||||
/*SETTING no_str=0 breaks channel access clients*/
|
||||
pes->no_str = 2;
|
||||
memset(pes->strs,'\0',sizeof(pes->strs));
|
||||
strncpy(pes->strs[0],prec->znam,sizeof(prec->znam));
|
||||
strncpy(pes->strs[0],prec->znam,sizeof(pes->strs[0]));
|
||||
if(*prec->znam!=0) pes->no_str=1;
|
||||
strncpy(pes->strs[1],prec->onam,sizeof(prec->onam));
|
||||
strncpy(pes->strs[1],prec->onam,sizeof(pes->strs[1]));
|
||||
if(*prec->onam!=0) pes->no_str=2;
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ static long special(DBADDR *, int);
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_units NULL
|
||||
#define get_precision NULL
|
||||
static long get_precision(const DBADDR *, long *);
|
||||
#define get_enum_str NULL
|
||||
#define get_enum_strs NULL
|
||||
#define put_enum_str NULL
|
||||
@@ -204,6 +204,16 @@ static long special(DBADDR *paddr, int after)
|
||||
}
|
||||
}
|
||||
|
||||
static long get_precision(const DBADDR *paddr,long *precision)
|
||||
{
|
||||
mbbiDirectRecord *prec=(mbbiDirectRecord *)paddr->precord;
|
||||
if(dbGetFieldIndex(paddr)==mbbiDirectRecordVAL)
|
||||
*precision = prec->nobt;
|
||||
else
|
||||
recGblGetPrec(paddr,precision);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void monitor(mbbiDirectRecord *prec)
|
||||
{
|
||||
epicsUInt16 events = recGblResetAlarms(prec);
|
||||
|
||||
@@ -51,7 +51,7 @@ static long special(DBADDR *, int);
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_units NULL
|
||||
#define get_precision NULL
|
||||
static long get_precision(const DBADDR *, long *);
|
||||
#define get_enum_str NULL
|
||||
#define get_enum_strs NULL
|
||||
#define put_enum_str NULL
|
||||
@@ -313,6 +313,16 @@ static long special(DBADDR *paddr, int after)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_precision(const DBADDR *paddr,long *precision)
|
||||
{
|
||||
mbboDirectRecord *prec=(mbboDirectRecord *)paddr->precord;
|
||||
if(dbGetFieldIndex(paddr)==mbboDirectRecordVAL)
|
||||
*precision = prec->nobt;
|
||||
else
|
||||
recGblGetPrec(paddr,precision);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void monitor(mbboDirectRecord *prec)
|
||||
{
|
||||
epicsUInt16 events = recGblResetAlarms(prec);
|
||||
|
||||
@@ -99,7 +99,7 @@ static void monitor(stateRecord *prec)
|
||||
monitor_mask = recGblResetAlarms(prec);
|
||||
if(strncmp(prec->oval,prec->val,sizeof(prec->val))) {
|
||||
db_post_events(prec,&(prec->val[0]),monitor_mask|DBE_VALUE|DBE_LOG);
|
||||
strncpy(prec->oval,prec->val,sizeof(prec->val));
|
||||
strncpy(prec->oval,prec->val,sizeof(prec->oval));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->val));
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->oval));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -183,7 +182,7 @@ static void monitor(stringinRecord *prec)
|
||||
|
||||
if (strncmp(prec->oval, prec->val, sizeof(prec->val))) {
|
||||
monitor_mask |= DBE_VALUE | DBE_LOG;
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->val));
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->oval));
|
||||
}
|
||||
|
||||
if (prec->mpst == stringinPOST_Always)
|
||||
|
||||
@@ -126,8 +126,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if(status)
|
||||
return status;
|
||||
}
|
||||
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->val));
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->oval));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -215,7 +214,7 @@ static void monitor(stringoutRecord *prec)
|
||||
|
||||
if (strncmp(prec->oval, prec->val, sizeof(prec->val))) {
|
||||
monitor_mask |= DBE_VALUE | DBE_LOG;
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->val));
|
||||
strncpy(prec->oval, prec->val, sizeof(prec->oval));
|
||||
}
|
||||
|
||||
if (prec->mpst == stringoutPOST_Always)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
use strict;
|
||||
use Test;
|
||||
|
||||
BEGIN {plan tests => 9}
|
||||
BEGIN {plan tests => 12}
|
||||
|
||||
# Check include/substitute command model
|
||||
ok(msi('-I .. ../t1-template.txt'), slurp('../t1-result.txt'));
|
||||
@@ -33,16 +33,9 @@ ok(msi('-S../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt'));
|
||||
|
||||
# Output option -o and verbose option -V
|
||||
my $out = 't7-output.txt';
|
||||
my $count = 5; # Try up to 5 times...
|
||||
my $result;
|
||||
do {
|
||||
unlink $out;
|
||||
msi("-I.. -V -o $out ../t1-template.txt");
|
||||
$result = slurp($out);
|
||||
print "# msi output file empty, retrying\n"
|
||||
if $result eq '';
|
||||
} while ($result eq '') && (--$count > 0);
|
||||
ok($result, slurp('../t7-result.txt'));
|
||||
unlink $out;
|
||||
msi("-I.. -V -o $out ../t1-template.txt");
|
||||
ok(slurp($out), slurp('../t7-result.txt'));
|
||||
|
||||
# Dependency generation, include/substitute model
|
||||
ok(msi('-I.. -D -o t8.txt ../t1-template.txt'), slurp('../t8-result.txt'));
|
||||
@@ -50,6 +43,17 @@ ok(msi('-I.. -D -o t8.txt ../t1-template.txt'), slurp('../t8-result.txt'));
|
||||
# Dependency generation, dbLoadTemplate format
|
||||
ok(msi('-I.. -D -ot9.txt -S ../t2-substitution.txt'), slurp('../t9-result.txt'));
|
||||
|
||||
# Substitution file, variable format, with 0 variable definitions
|
||||
ok(msi('-I. -I.. -S ../t10-substitute.txt'), slurp('../t10-result.txt'));
|
||||
|
||||
# Substitution file, pattern format, with 0 pattern definitions
|
||||
ok(msi('-I. -I.. -S ../t11-substitute.txt'), slurp('../t11-result.txt'));
|
||||
|
||||
# Substitution file, environment variable macros in template filename
|
||||
my %envs = (TEST_NO => 12, PREFIX => 't');
|
||||
@ENV{ keys %envs } = values %envs;
|
||||
ok(msi('-I. -I.. -S ../t12-substitute.txt'), slurp('../t12-result.txt'));
|
||||
delete @ENV{ keys %envs }; # Not really needed
|
||||
|
||||
# Test support routines
|
||||
|
||||
@@ -63,21 +67,8 @@ sub slurp {
|
||||
|
||||
sub msi {
|
||||
my ($args) = @_;
|
||||
my $nul = $^O eq 'MSWin32' ? 'NUL' : '/dev/null';
|
||||
my $msi = '@TOP@/bin/@ARCH@/msi';
|
||||
$msi .= '.exe' if ($^O eq 'MSWin32') || ($^O eq 'cygwin');
|
||||
my $result;
|
||||
if ($args =~ m/-o / && $args !~ m/-D/) {
|
||||
# An empty result is expected
|
||||
$result = `$msi $args`;
|
||||
}
|
||||
else {
|
||||
# Try up to 5 times, sometimes msi fails on Windows
|
||||
my $count = 5;
|
||||
do {
|
||||
$result = `$msi $args`;
|
||||
print "# result of '$msi $args' empty, retrying\n"
|
||||
if $result eq '';
|
||||
} while ($result eq '') && (--$count > 0);
|
||||
}
|
||||
return $result;
|
||||
$msi =~ tr(/)(\\) if $^O eq 'MSWin32';
|
||||
return `$msi $args 2>$nul`;
|
||||
}
|
||||
|
||||
4
modules/database/test/ioc/dbtemplate/t10-result.txt
Normal file
4
modules/database/test/ioc/dbtemplate/t10-result.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
# comment line
|
||||
a=$(a)
|
||||
# comment line
|
||||
a=gbl
|
||||
8
modules/database/test/ioc/dbtemplate/t10-substitute.txt
Normal file
8
modules/database/test/ioc/dbtemplate/t10-substitute.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
file t10-template.txt {
|
||||
{}
|
||||
}
|
||||
|
||||
global { a=gbl }
|
||||
file t10-template.txt {
|
||||
{}
|
||||
}
|
||||
2
modules/database/test/ioc/dbtemplate/t10-template.txt
Normal file
2
modules/database/test/ioc/dbtemplate/t10-template.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# comment line
|
||||
a=$(a)
|
||||
4
modules/database/test/ioc/dbtemplate/t11-result.txt
Normal file
4
modules/database/test/ioc/dbtemplate/t11-result.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
# comment line
|
||||
a=$(a)
|
||||
# comment line
|
||||
a=gbl
|
||||
10
modules/database/test/ioc/dbtemplate/t11-substitute.txt
Normal file
10
modules/database/test/ioc/dbtemplate/t11-substitute.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
file t11-template.txt {
|
||||
pattern {}
|
||||
{}
|
||||
}
|
||||
|
||||
global { a=gbl }
|
||||
file t11-template.txt {
|
||||
pattern {}
|
||||
{}
|
||||
}
|
||||
2
modules/database/test/ioc/dbtemplate/t11-template.txt
Normal file
2
modules/database/test/ioc/dbtemplate/t11-template.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# comment line
|
||||
a=$(a)
|
||||
2
modules/database/test/ioc/dbtemplate/t12-result.txt
Normal file
2
modules/database/test/ioc/dbtemplate/t12-result.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# comment line
|
||||
a=foo
|
||||
3
modules/database/test/ioc/dbtemplate/t12-substitute.txt
Normal file
3
modules/database/test/ioc/dbtemplate/t12-substitute.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
file $(PREFIX)$(TEST_NO)-template.txt {
|
||||
{ a=foo }
|
||||
}
|
||||
2
modules/database/test/ioc/dbtemplate/t12-template.txt
Normal file
2
modules/database/test/ioc/dbtemplate/t12-template.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# comment line
|
||||
a=$(a)
|
||||
@@ -1,4 +1,4 @@
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 17
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 4
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 5
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
static unsigned short ioc_log_port;
|
||||
static long ioc_log_file_limit;
|
||||
static char ioc_log_file_name[256];
|
||||
static char ioc_log_file_name[512];
|
||||
static char ioc_log_file_command[256];
|
||||
|
||||
|
||||
@@ -866,7 +866,12 @@ static int setupSIGHUP(struct ioc_log_server *pserver)
|
||||
*/
|
||||
static void sighupHandler(int signo)
|
||||
{
|
||||
(void) write(sighupPipe[1], "SIGHUP\n", 7);
|
||||
const char msg[] = "SIGHUP\n";
|
||||
const ssize_t bytesWritten = write(sighupPipe[1], msg, sizeof(msg));
|
||||
if (bytesWritten != sizeof(msg)) {
|
||||
fprintf(stderr, "iocLogServer: failed to write to SIGHUP pipe because "
|
||||
"`%s'\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,7 +889,10 @@ static void serviceSighupRequest(void *pParam)
|
||||
/*
|
||||
* Read and discard message from pipe.
|
||||
*/
|
||||
(void) read(sighupPipe[0], buff, sizeof buff);
|
||||
if (read(sighupPipe[0], buff, sizeof buff) <= 0) {
|
||||
fprintf(stderr, "iocLogServer: failed to read from SIGHUP pipe because "
|
||||
"`%s'\n", strerror(errno));
|
||||
};
|
||||
|
||||
/*
|
||||
* Determine new log file name.
|
||||
|
||||
@@ -171,6 +171,7 @@ ipAddrToAsciiEngine & ipAddrToAsciiEngine::allocate ()
|
||||
}
|
||||
|
||||
ipAddrToAsciiGlobal::ipAddrToAsciiGlobal () :
|
||||
mutex(__FILE__, __LINE__),
|
||||
thread ( *this, "ipToAsciiProxy",
|
||||
epicsThreadGetStackSize(epicsThreadStackBig),
|
||||
epicsThreadPriorityLow ),
|
||||
|
||||
@@ -78,6 +78,11 @@ static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
static const char * const tsfmt = "%Y-%m-%d %H:%M:%S.%09f";
|
||||
|
||||
/* defined in osiClockTime.c or osdTime.cpp */
|
||||
int osdTimeGetCurrent ( epicsTimeStamp *pDest );
|
||||
/* cleared if/when gtPvt.timeProviders contains more than the default osdTimeGetCurrent() */
|
||||
static int useOsdGetCurrent = 1;
|
||||
|
||||
/* Implementation */
|
||||
|
||||
static void generalTime_InitOnce(void *dummy)
|
||||
@@ -103,6 +108,9 @@ int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int *pPrio, int ignore)
|
||||
gtProvider *ptp;
|
||||
int status = S_time_noProvider;
|
||||
|
||||
if(useOsdGetCurrent)
|
||||
return osdTimeGetCurrent(pDest);
|
||||
|
||||
generalTime_Init();
|
||||
|
||||
IFDEBUG(2)
|
||||
@@ -148,6 +156,9 @@ int epicsShareAPI epicsTimeGetCurrent(epicsTimeStamp *pDest)
|
||||
int status = S_time_noProvider;
|
||||
epicsTimeStamp ts;
|
||||
|
||||
if(useOsdGetCurrent)
|
||||
return osdTimeGetCurrent(pDest);
|
||||
|
||||
generalTime_Init();
|
||||
|
||||
IFDEBUG(20)
|
||||
@@ -370,6 +381,11 @@ static void insertProvider(gtProvider *ptp, ELLLIST *plist, epicsMutexId lock)
|
||||
ellAdd(plist, &ptp->node);
|
||||
}
|
||||
|
||||
/* Check to see if we have more than just the OS default time source */
|
||||
if(plist==>Pvt.timeProviders && (ellCount(plist)!=1 || ptp->get.Time!=&osdTimeGetCurrent)) {
|
||||
useOsdGetCurrent = 0;
|
||||
}
|
||||
|
||||
epicsMutexUnlock(lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,9 +205,6 @@ epicsTime::epicsTime (const epicsTimeStamp &ts)
|
||||
epicsTime::epicsTime () :
|
||||
secPastEpoch(0u), nSec(0u) {}
|
||||
|
||||
epicsTime::epicsTime (const epicsTime &t) :
|
||||
secPastEpoch (t.secPastEpoch), nSec (t.nSec) {}
|
||||
|
||||
epicsTime epicsTime::getCurrent ()
|
||||
{
|
||||
epicsTimeStamp current;
|
||||
|
||||
@@ -82,7 +82,6 @@ public:
|
||||
class formatProblemWithStructTM {};
|
||||
|
||||
epicsTime ();
|
||||
epicsTime ( const epicsTime & t );
|
||||
|
||||
static epicsTime getEvent ( const epicsTimeEvent & );
|
||||
static epicsTime getCurrent ();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
static clock_serv_t host_clock;
|
||||
|
||||
extern "C" {
|
||||
static int osdTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
int osdTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
{
|
||||
mach_timespec_t mts;
|
||||
struct timespec ts;
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
|
||||
extern "C" void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
|
||||
|
||||
static int osdTimeGetCurrent ( epicsTimeStamp *pDest );
|
||||
extern "C"
|
||||
int osdTimeGetCurrent ( epicsTimeStamp *pDest );
|
||||
|
||||
// for mingw
|
||||
#if !defined ( MAXLONGLONG )
|
||||
@@ -116,7 +117,7 @@ static int done = timeRegister();
|
||||
//
|
||||
// osdTimeGetCurrent ()
|
||||
//
|
||||
static int osdTimeGetCurrent ( epicsTimeStamp *pDest )
|
||||
int osdTimeGetCurrent ( epicsTimeStamp *pDest )
|
||||
{
|
||||
assert ( pCurrentTime );
|
||||
|
||||
|
||||
@@ -7,12 +7,30 @@
|
||||
* Author: Till Straumann <strauman@slac.stanford.edu>, 2011, 2014
|
||||
*/
|
||||
|
||||
// pull in libc feature test macros
|
||||
#include <stdlib.h>
|
||||
|
||||
// execinfo.h may not be present if uclibc is configured to omit backtrace()
|
||||
#if !defined(__UCLIBC_MAJOR__) || defined(__UCLIBC_HAS_EXECINFO__)
|
||||
# define HAS_EXECINFO 1
|
||||
#else
|
||||
# define HAS_EXECINFO 0
|
||||
#endif
|
||||
|
||||
#if HAS_EXECINFO
|
||||
|
||||
#include <execinfo.h>
|
||||
|
||||
#endif
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStackTracePvt.h"
|
||||
|
||||
int epicsBackTrace(void **buf, int buf_sz)
|
||||
{
|
||||
#if HAS_EXECINFO
|
||||
return backtrace(buf, buf_sz);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -153,6 +153,10 @@ epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex)
|
||||
|
||||
void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level)
|
||||
{
|
||||
/* GLIBC w/ NTPL is passing the &lock.__data.__lock as the first argument (UADDR)
|
||||
* of the futex() syscall. __lock is at offset 0 of the enclosing structures.
|
||||
*/
|
||||
printf(" pthread_mutex_t* uaddr=%p\n", &pmutex->lock);
|
||||
}
|
||||
|
||||
#else /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
|
||||
|
||||
@@ -906,7 +906,7 @@ epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum ()
|
||||
{
|
||||
double hz;
|
||||
hz = sysconf ( _SC_CLK_TCK );
|
||||
if(hz<0)
|
||||
if(hz<=0)
|
||||
return 0.0;
|
||||
return 1.0 / hz;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
LAST_RESORT_PRIORITY, osdTimeGetCurrent)
|
||||
|
||||
extern "C" {
|
||||
static int osdTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
int osdTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
@@ -65,7 +65,7 @@ typedef int SOCKET;
|
||||
#define socket_ioctl(A,B,C) ioctl(A,B,(int)C)
|
||||
typedef int osiSockIoctl_t;
|
||||
typedef int osiSocklen_t;
|
||||
typedef int osiSockOptMcastLoop_t;
|
||||
typedef char osiSockOptMcastLoop_t;
|
||||
typedef char osiSockOptMcastTTL_t;
|
||||
|
||||
#define FD_IN_FDSET(FD) ((FD)<FD_SETSIZE&&(FD)>=0)
|
||||
|
||||
@@ -40,7 +40,7 @@ static struct {
|
||||
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
|
||||
#if defined(CLOCK_REALTIME) && !defined(_WIN32)
|
||||
#if defined(CLOCK_REALTIME) && !defined(_WIN32) && !defined(__APPLE__)
|
||||
/* This code is not used on systems without Posix CLOCK_REALTIME,
|
||||
* but the only way to detect that is from the OS headers, so the
|
||||
* Makefile can't exclude compiling this file on those systems.
|
||||
@@ -48,7 +48,7 @@ static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
/* Forward references */
|
||||
|
||||
static int ClockTimeGetCurrent(epicsTimeStamp *pDest);
|
||||
int osdTimeGetCurrent(epicsTimeStamp *pDest);
|
||||
|
||||
#if defined(vxWorks) || defined(__rtems__)
|
||||
static void ClockTimeSync(void *dummy);
|
||||
@@ -89,7 +89,7 @@ static void ClockTime_InitOnce(void *pfirst)
|
||||
|
||||
/* Register as a time provider */
|
||||
generalTimeRegisterCurrentProvider("OS Clock", LAST_RESORT_PRIORITY,
|
||||
ClockTimeGetCurrent);
|
||||
osdTimeGetCurrent);
|
||||
}
|
||||
|
||||
void ClockTime_Init(int synchronize)
|
||||
@@ -125,7 +125,7 @@ void ClockTime_Init(int synchronize)
|
||||
else {
|
||||
/* No synchronization thread */
|
||||
if (firstTime)
|
||||
ClockTimeGetCurrent(&ClockTimePvt.startTime);
|
||||
osdTimeGetCurrent(&ClockTimePvt.startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ static void ClockTimeSync(void *dummy)
|
||||
|
||||
/* Time Provider Routine */
|
||||
|
||||
static int ClockTimeGetCurrent(epicsTimeStamp *pDest)
|
||||
int osdTimeGetCurrent(epicsTimeStamp *pDest)
|
||||
{
|
||||
struct timespec clockNow;
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ private:
|
||||
epicsThread thread;
|
||||
const double sleepQuantum;
|
||||
bool okToShare;
|
||||
bool exitFlag;
|
||||
int exitFlag; // use atomic ops
|
||||
bool terminateFlag;
|
||||
void run ();
|
||||
void reschedule ();
|
||||
|
||||
@@ -25,6 +25,7 @@ const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds
|
||||
epicsTimerQueue::~epicsTimerQueue () {}
|
||||
|
||||
timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) :
|
||||
mutex(__FILE__, __LINE__),
|
||||
notify ( notifyIn ),
|
||||
pExpireTmr ( 0 ),
|
||||
processThread ( 0 ),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAtomic.h"
|
||||
#include "timerPrivate.h"
|
||||
#include "errlog.h"
|
||||
|
||||
@@ -46,7 +47,7 @@ timerQueueActive ::
|
||||
_refMgr ( refMgr ), queue ( *this ), thread ( *this, "timerQueue",
|
||||
epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
|
||||
sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ),
|
||||
exitFlag ( false ), terminateFlag ( false )
|
||||
exitFlag ( 0 ), terminateFlag ( false )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@ timerQueueActive::~timerQueueActive ()
|
||||
{
|
||||
this->terminateFlag = true;
|
||||
this->rescheduleEvent.signal ();
|
||||
while ( ! this->exitFlag ) {
|
||||
while ( ! epics::atomic::get(this->exitFlag) ) {
|
||||
this->exitEvent.wait ( 1.0 );
|
||||
}
|
||||
// in case other threads are waiting here also
|
||||
@@ -87,7 +88,7 @@ void timerQueueActive :: _printLastChanceExceptionMessage (
|
||||
|
||||
void timerQueueActive :: run ()
|
||||
{
|
||||
this->exitFlag = false;
|
||||
epics::atomic::set(this->exitFlag, 0);
|
||||
while ( ! this->terminateFlag ) {
|
||||
try {
|
||||
double delay = this->queue.process ( epicsTime::getCurrent() );
|
||||
@@ -105,7 +106,7 @@ void timerQueueActive :: run ()
|
||||
epicsThreadSleep ( 10.0 );
|
||||
}
|
||||
}
|
||||
this->exitFlag = true;
|
||||
epics::atomic::set(this->exitFlag, 1);
|
||||
this->exitEvent.signal (); // no access to queue after exitEvent signal
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ void timerQueueActive::show ( unsigned int level ) const
|
||||
printf ( "exit event\n" );
|
||||
this->exitEvent.show ( level - 1u );
|
||||
printf ( "exitFlag = %c, terminateFlag = %c\n",
|
||||
this->exitFlag ? 'T' : 'F',
|
||||
epics::atomic::get(this->exitFlag) ? 'T' : 'F',
|
||||
this->terminateFlag ? 'T' : 'F' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "timerPrivate.h"
|
||||
|
||||
timerQueueActiveMgr::timerQueueActiveMgr ()
|
||||
:mutex(__FILE__, __LINE__)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -255,8 +255,8 @@ TESTSPEC_RTEMS = libComTestHarness.boot; epicsRunLibComTests
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),)
|
||||
TESTPROD_RTEMS = $(TESTPROD_HOST)
|
||||
TESTSCRIPTS_RTEMS += $(filter-out epicsUnitTestTest.t, $(TESTS:%=%.t))
|
||||
TESTPROD = $(TESTPROD_HOST)
|
||||
TESTSCRIPTS += $(filter-out epicsUnitTestTest.t, $(TESTS:%=%.t))
|
||||
endif
|
||||
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ typedef struct {
|
||||
size_t checkLen;
|
||||
epicsEventId jammer;
|
||||
int jam;
|
||||
epicsEventId done;
|
||||
} clientPvt;
|
||||
|
||||
static void testLogPrefix(void);
|
||||
@@ -102,12 +103,13 @@ static const char prefixexpectedmsg[] = "A message without prefix"
|
||||
static char prefixmsgbuffer[1024];
|
||||
|
||||
|
||||
static
|
||||
void testEqInt_(int lhs, int rhs, const char *LHS, const char *RHS)
|
||||
static void
|
||||
testEqInt_(int line, int lhs, int rhs, const char *LHS, const char *RHS)
|
||||
{
|
||||
testOk(lhs==rhs, "%s (%d) == %s (%d)", LHS, lhs, RHS, rhs);
|
||||
testOk(lhs==rhs, "%d: %s (%d) == %s (%d)", line, LHS, lhs, RHS, rhs);
|
||||
}
|
||||
#define testEqInt(L, R) testEqInt_(L, R, #L, #R);
|
||||
#define testEqInt(L, R) testEqInt_(__LINE__, L, R, #L, #R);
|
||||
|
||||
static
|
||||
void logClient(void* raw, const char* msg)
|
||||
{
|
||||
@@ -161,6 +163,7 @@ void logClient(void* raw, const char* msg)
|
||||
}
|
||||
|
||||
pvt->count++;
|
||||
epicsEventSignal(pvt->done);
|
||||
}
|
||||
|
||||
MAIN(epicsErrlogTest)
|
||||
@@ -169,7 +172,7 @@ MAIN(epicsErrlogTest)
|
||||
char msg[256];
|
||||
clientPvt pvt, pvt2;
|
||||
|
||||
testPlan(32);
|
||||
testPlan(40);
|
||||
|
||||
strcpy(msg, truncmsg);
|
||||
|
||||
@@ -188,7 +191,9 @@ MAIN(epicsErrlogTest)
|
||||
pvt2.jam = 0;
|
||||
|
||||
pvt.jammer = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvt.done = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvt2.jammer = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvt2.done = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
testDiag("Check listener registration");
|
||||
|
||||
@@ -200,6 +205,7 @@ MAIN(epicsErrlogTest)
|
||||
errlogPrintfNoConsole("%s", pvt.expect);
|
||||
errlogFlush();
|
||||
|
||||
epicsEventMustWait(pvt.done);
|
||||
testEqInt(pvt.count, 1);
|
||||
|
||||
errlogAddListener(&logClient, &pvt2);
|
||||
@@ -210,7 +216,10 @@ MAIN(epicsErrlogTest)
|
||||
errlogPrintfNoConsole("%s", pvt.expect);
|
||||
errlogFlush();
|
||||
|
||||
epicsEventMustWait(pvt.done);
|
||||
testEqInt(pvt.count, 2);
|
||||
|
||||
epicsEventMustWait(pvt2.done);
|
||||
testEqInt(pvt2.count, 1);
|
||||
|
||||
/* Removes the first listener */
|
||||
@@ -223,6 +232,10 @@ MAIN(epicsErrlogTest)
|
||||
errlogPrintfNoConsole("%s", pvt2.expect);
|
||||
errlogFlush();
|
||||
|
||||
testOk(epicsEventWaitWithTimeout(pvt.done, 0.5) == epicsEventWaitTimeout,
|
||||
"%d: Listener 1 didn't run", __LINE__);
|
||||
testOk(epicsEventTryWait(pvt2.done) == epicsEventOK,
|
||||
"%d: Listener 2 ran", __LINE__);
|
||||
testEqInt(pvt.count, 2);
|
||||
testEqInt(pvt2.count, 2);
|
||||
|
||||
@@ -234,6 +247,10 @@ MAIN(epicsErrlogTest)
|
||||
errlogPrintfNoConsole("Something different");
|
||||
errlogFlush();
|
||||
|
||||
testOk(epicsEventWaitWithTimeout(pvt.done, 0.5) == epicsEventWaitTimeout,
|
||||
"%d: Listener 1 didn't run", __LINE__);
|
||||
testOk(epicsEventTryWait(pvt2.done) == epicsEventWaitTimeout,
|
||||
"%d: Listener 2 didn't run", __LINE__);
|
||||
testEqInt(pvt.count, 2);
|
||||
testEqInt(pvt2.count, 2);
|
||||
|
||||
@@ -248,6 +265,7 @@ MAIN(epicsErrlogTest)
|
||||
errlogPrintfNoConsole("%s", longmsg);
|
||||
errlogFlush();
|
||||
|
||||
epicsEventMustWait(pvt.done);
|
||||
testEqInt(pvt.count, 3);
|
||||
|
||||
pvt.expect = NULL;
|
||||
@@ -259,13 +277,15 @@ MAIN(epicsErrlogTest)
|
||||
pvt.jam = 1;
|
||||
|
||||
errlogPrintfNoConsole("%s", longmsg);
|
||||
epicsThreadSleep(0.1);
|
||||
|
||||
testOk(epicsEventWaitWithTimeout(pvt.done, 0.5) == epicsEventWaitTimeout,
|
||||
"%d: Listener 1 didn't run", __LINE__);
|
||||
testEqInt(pvt.count, 3);
|
||||
|
||||
epicsEventSignal(pvt.jammer);
|
||||
errlogFlush();
|
||||
|
||||
epicsEventMustWait(pvt.done);
|
||||
testEqInt(pvt.count, 4);
|
||||
|
||||
testDiag("Find buffer capacity (%u theoretical)",LOGBUFSIZE);
|
||||
@@ -303,6 +323,9 @@ MAIN(epicsErrlogTest)
|
||||
errlogFlush();
|
||||
}
|
||||
|
||||
testOk(epicsEventTryWait(pvt.done) == epicsEventOK,
|
||||
"%d: Listener 1 ran", __LINE__);
|
||||
|
||||
testDiag("Checking buffer use after partial flush");
|
||||
|
||||
/* Use the numbers from the largest block size above */
|
||||
@@ -317,16 +340,18 @@ MAIN(epicsErrlogTest)
|
||||
for (i = 0; i < N; i++) {
|
||||
errlogPrintfNoConsole("%s", msg);
|
||||
}
|
||||
epicsThreadSleep(0.1); /* should really be a second Event */
|
||||
|
||||
testOk(epicsEventWaitWithTimeout(pvt.done, 0.5) == epicsEventWaitTimeout,
|
||||
"%d: Listener 1 didn't run", __LINE__);
|
||||
testEqInt(pvt.count, 0);
|
||||
|
||||
/* Extract the first 2 messages, 2*(sizeof(msgNode) + 128) bytes */
|
||||
pvt.jam = -2;
|
||||
epicsEventSignal(pvt.jammer);
|
||||
epicsThreadSleep(0.1);
|
||||
epicsThreadSleep(0.5);
|
||||
|
||||
testDiag("Drained %u messages", pvt.count);
|
||||
epicsEventMustWait(pvt.done);
|
||||
testEqInt(pvt.count, 2);
|
||||
|
||||
/* The buffer has space for 1 more message: sizeof(msgNode) + 256 bytes */
|
||||
@@ -335,12 +360,15 @@ MAIN(epicsErrlogTest)
|
||||
testDiag("Overflow the buffer");
|
||||
errlogPrintfNoConsole("%s", msg);
|
||||
|
||||
testOk(epicsEventWaitWithTimeout(pvt.done, 0.5) == epicsEventWaitTimeout,
|
||||
"%d: Listener 1 didn't run", __LINE__);
|
||||
testEqInt(pvt.count, 2);
|
||||
|
||||
epicsEventSignal(pvt.jammer); /* Empty */
|
||||
errlogFlush();
|
||||
|
||||
testDiag("Logged %u messages", pvt.count);
|
||||
epicsEventMustWait(pvt.done);
|
||||
testEqInt(pvt.count, N+1);
|
||||
|
||||
/* Clean up */
|
||||
|
||||
@@ -381,8 +381,14 @@ MAIN(epicsStdlibTest)
|
||||
|
||||
testOk(epicsParseFloat("1e-40", &f, NULL) == S_stdlib_underflow,
|
||||
"Float '1e-40' => underflow");
|
||||
#ifdef vxWorks
|
||||
testTodoBegin("Not detected on VxWorks");
|
||||
#endif
|
||||
testOk(epicsParseDouble("1e-330", &d, NULL) == S_stdlib_underflow,
|
||||
"Double '1e-330' => underflow");
|
||||
#ifdef vxWorks
|
||||
testTodoEnd();
|
||||
#endif
|
||||
|
||||
testOk(epicsScanFloat("1e30", &f) && fabs(f - 1e30) < 1e24,
|
||||
"Float '1e30'");
|
||||
|
||||
@@ -108,11 +108,11 @@ inline double delayVerify::delay () const
|
||||
|
||||
double delayVerify::checkError () const
|
||||
{
|
||||
const double messageThresh = 2.0; // percent
|
||||
const double messageThresh = 5.0; // percent
|
||||
double actualDelay = this->expireStamp - this->beginStamp;
|
||||
double measuredError = actualDelay - this->expectedDelay;
|
||||
double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay;
|
||||
if ( ! testOk1 ( percentError < messageThresh ) ) {
|
||||
if ( ! testOk ( percentError < messageThresh, "%f < %f", percentError, messageThresh ) ) {
|
||||
testDiag ( "delay = %f s, error = %f s (%.1f %%)",
|
||||
this->expectedDelay, measuredError, percentError );
|
||||
}
|
||||
|
||||
Submodule modules/normativeTypes updated: e803240fbf...c6168a7477
Submodule modules/pvAccess updated: 5b333922d5...936f5d35d8
Submodule modules/pvData updated: 6da871fa64...6ceaa6adb0
Submodule modules/pvDatabase updated: 2715f585e0...70ee857782
Submodule modules/pva2pva updated: 521154fd52...ce39c93201
Submodule modules/pvaClient updated: 428adb270e...aba40922e6
Reference in New Issue
Block a user