Compare commits
99 Commits
PSI-7.0.7.
...
R7.0.8.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57c930fbee | ||
|
|
785b777baf | ||
|
|
d0d15ee911 | ||
|
|
5af9c7e50d | ||
|
|
5fe563bed8 | ||
|
|
11fba63d18 | ||
|
|
1db37bcd91 | ||
|
|
beec00b403 | ||
|
|
4966baf423 | ||
|
|
e5b4829074 | ||
|
|
d8b5616772 | ||
|
|
92615a77fe | ||
|
|
b3f92d81db | ||
|
|
839f764bcb | ||
|
|
4bb50fe664 | ||
|
|
c77f32b19c | ||
|
|
66ce1c2076 | ||
|
|
1a9dc993c1 | ||
|
|
cb1571783b | ||
|
|
5dfc6caf3c | ||
|
|
cb49bd0133 | ||
|
|
4720b61c1f | ||
| 4383cf291e | |||
|
|
a6977ae731 | ||
|
|
07cbf00187 | ||
|
|
c75b9ad0be | ||
|
|
87acb98d1e | ||
|
|
403e203325 | ||
|
|
a7a56912eb | ||
|
|
fe4a32e425 | ||
|
|
823386573f | ||
|
|
ea8247586f | ||
|
|
e88a186fc3 | ||
|
|
20f32068c3 | ||
|
|
8998341588 | ||
|
|
448fde0671 | ||
|
|
477e36b1f0 | ||
|
|
fad830bd14 | ||
|
|
331df3d7e4 | ||
|
|
4a53713f37 | ||
|
|
2e6fd505d2 | ||
|
|
5ecf7d18a8 | ||
|
|
56dbc949ff | ||
|
|
6a369acd0b | ||
|
|
d9d35a4eab | ||
|
|
116881ad87 | ||
| 96857d92bc | |||
|
|
0cf8c934f9 | ||
|
|
69d05fe5b0 | ||
|
|
511bf1ffca | ||
|
|
7a7028de56 | ||
|
|
7a65c001ce | ||
|
|
0bc6ff3d4c | ||
|
|
f2fe9d1203 | ||
|
|
ffc2d0f23a | ||
|
|
a352865df9 | ||
|
|
63740f2edd | ||
|
|
f4be9daf4d | ||
|
|
3fa1932345 | ||
|
|
95bd5453d9 | ||
|
|
eb3f8a004c | ||
|
|
9f868a1074 | ||
|
|
b41787b6bf | ||
| 19b232545c | |||
|
|
2ca70d3aa2 | ||
|
|
395015aac4 | ||
|
|
92cae86ff2 | ||
|
|
49ea46ee5e | ||
|
|
df908f299b | ||
|
|
6dec68554c | ||
|
|
badd8f518d | ||
|
|
766c9906b5 | ||
|
|
60fa2d31da | ||
|
|
88ea1507f4 | ||
|
|
8c08c57247 | ||
|
|
45b3bce515 | ||
|
|
7c4a21eab4 | ||
|
|
fab8fd7102 | ||
|
|
3d25756065 | ||
|
|
5aca4c684c | ||
|
|
39b5c01c5d | ||
|
|
3b22e5f710 | ||
|
|
9f660f2238 | ||
|
|
ca9c957e62 | ||
|
|
8488c9e891 | ||
|
|
1f2edb69d2 | ||
|
|
fe3ee85aee | ||
|
|
a74789d9c0 | ||
|
|
7830345e59 | ||
|
|
1595ed8860 | ||
|
|
d97943b697 | ||
|
|
f8f4376594 | ||
|
|
df397f4ade | ||
|
|
7fd690e53e | ||
|
|
bc5d347bb2 | ||
|
|
3ea29f581b | ||
|
|
6de82bb0fd | ||
| e1a51e2839 | |||
|
|
0f59d823d3 |
@@ -25,22 +25,6 @@ init:
|
||||
# Set clone depth (do not fetch complete history)
|
||||
clone_depth: 5
|
||||
|
||||
# Skip commits affecting only specific files
|
||||
skip_commits:
|
||||
files:
|
||||
# Removed - 'documentation/*'
|
||||
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
|
||||
# the last commit pushed to a PR only updates the Release Notes the whole
|
||||
# PR build gets skipped. GitHub Actions looks at the complete list
|
||||
# of files changed since its last build, which is much more useful.
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '.tools/*'
|
||||
- '.gitattributes'
|
||||
- '.lgtm.yml'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
#---------------------------------#
|
||||
# build matrix configuration #
|
||||
#---------------------------------#
|
||||
|
||||
@@ -32,22 +32,6 @@ init:
|
||||
# Set clone depth (do not fetch complete history)
|
||||
clone_depth: 5
|
||||
|
||||
# Skip commits affecting only specific files
|
||||
skip_commits:
|
||||
files:
|
||||
# Removed - 'documentation/*'
|
||||
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
|
||||
# the last commit pushed to a PR only updates the Release Notes the whole
|
||||
# PR build gets skipped. GitHub Actions looks at the complete list
|
||||
# of files changed since its last build, which is much more useful.
|
||||
- 'startup/*'
|
||||
- '.github/*'
|
||||
- '.tools/*'
|
||||
- '.lgtm.yml'
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
|
||||
#---------------------------------#
|
||||
# build matrix configuration #
|
||||
#---------------------------------#
|
||||
|
||||
2
.ci
2
.ci
Submodule .ci updated: 1e0e326f74...20f8e05393
2
.github/workflows/check-editorconfig.yml
vendored
2
.github/workflows/check-editorconfig.yml
vendored
@@ -8,6 +8,6 @@ jobs:
|
||||
editorconfig:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: EditorConfig-Action
|
||||
uses: greut/eclint-action@v0
|
||||
|
||||
24
.github/workflows/ci-scripts-build.yml
vendored
24
.github/workflows/ci-scripts-build.yml
vendored
@@ -29,6 +29,7 @@ on:
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
@@ -51,6 +52,25 @@ jobs:
|
||||
matrix:
|
||||
# Job names also name artifacts, character limitations apply
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc-12
|
||||
name: "Ub-22 gcc-12 c++20 Werror"
|
||||
# Turn all warnings into errors,
|
||||
# except for those we could not fix (yet).
|
||||
# Remove respective -Wno-error=... flag once it is fixed.
|
||||
extra: "CMD_CXXFLAGS=-std=c++20
|
||||
CMD_CPPFLAGS='-fdiagnostics-color
|
||||
-Werror
|
||||
-Wno-error=deprecated-declarations
|
||||
-Wno-error=stringop-truncation
|
||||
-Wno-error=restrict
|
||||
-Wno-error=sizeof-pointer-memaccess
|
||||
-Wno-error=nonnull
|
||||
-Wno-error=dangling-pointer
|
||||
-Wno-error=format-overflow
|
||||
-Wno-error=format-security
|
||||
-Wno-error=stringop-overread'"
|
||||
|
||||
- os: ubuntu-20.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
@@ -264,6 +284,10 @@ jobs:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
if: matrix.image!='centos:7'
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@node16
|
||||
if: matrix.image=='centos:7'
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,3 +17,4 @@ O.*/
|
||||
*.log
|
||||
.*.swp
|
||||
.DS_Store
|
||||
.iocsh_history
|
||||
|
||||
@@ -48,7 +48,7 @@ EPICS_VERSION = 7
|
||||
EPICS_REVISION = 0
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 7
|
||||
EPICS_MODIFICATION = 8
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included in the official EPICS version number if zero
|
||||
@@ -56,7 +56,7 @@ EPICS_PATCH_LEVEL = 1
|
||||
|
||||
# Immediately after an official release the EPICS_PATCH_LEVEL is incremented
|
||||
# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions)
|
||||
EPICS_DEV_SNAPSHOT=-DEV
|
||||
EPICS_DEV_SNAPSHOT=
|
||||
|
||||
# No changes should be needed below here
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 14
|
||||
EPICS_CA_MAINTENANCE_VERSION = 3
|
||||
EPICS_CA_MAINTENANCE_VERSION = 4
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 1
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Version number for the database APIs and shared library
|
||||
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 22
|
||||
EPICS_DATABASE_MINOR_VERSION = 23
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 1
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Version number for the libcom APIs and shared library
|
||||
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 22
|
||||
EPICS_LIBCOM_MINOR_VERSION = 23
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -34,5 +34,9 @@ CFG += TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
ifeq ($(GNU),YES)
|
||||
# Pass compiler flags to preprocessor to enable _FORTIFY_SOURCE
|
||||
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): CPPFLAGS += $(CFLAGS)
|
||||
endif
|
||||
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): toolchain.c
|
||||
$(PREPROCESS.cpp)
|
||||
|
||||
@@ -532,11 +532,11 @@ endif # LOADABLE_SHRLIB_SUFFIX
|
||||
ifneq ($(INSTALL_CONFIGS),)
|
||||
$(INSTALL_CONFIG)/%: %
|
||||
$(ECHO) "Installing config file $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D))
|
||||
|
||||
$(INSTALL_CONFIG)/%: ../%
|
||||
$(ECHO) "Installing config file $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D))
|
||||
endif
|
||||
|
||||
$(INSTALL_INCLUDE)/%: $(COMMON_DIR)/%
|
||||
|
||||
@@ -22,7 +22,7 @@ ARCH_DEP_CFLAGS += -DRTEMS_HAS_ALTIVEC
|
||||
#OP_SYS_LDLIBS += -lbspExt #does not use posix stuff ... want to ignore
|
||||
OP_SYS_LDLIBS += -Wl,--gc-sections
|
||||
#ARCH_DEP_LDFLAGS = -mcpu=8540 -meabi -msdata=sysv -mstrict-align -mspe -mabi=spe -mfloat-gprs=double
|
||||
ARCH_DEP_LDFLAGS = -L$(RTEMS_BASE)/powerpc-rtems5/qoriq_e500/lib
|
||||
ARCH_DEP_LDFLAGS = -L$(RTEMS_BASE)/$(GNU_TARGET)$(RTEMS_VERSION)/$(RTEMS_BSP)/lib
|
||||
|
||||
MUNCH_SUFFIX = .img
|
||||
MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX))
|
||||
|
||||
@@ -47,3 +47,8 @@ COMMANDLINE_LIBRARY ?= EPICS
|
||||
#else
|
||||
COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS))
|
||||
#endif
|
||||
|
||||
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE>2
|
||||
OP_SYS_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2
|
||||
#endif
|
||||
|
||||
|
||||
@@ -18,9 +18,107 @@ should also be read to understand what has changed since earlier releases:
|
||||
- [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html)
|
||||
- [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md)
|
||||
|
||||
**This version of EPICS has not been released yet.**
|
||||
## EPICS Release 7.0.8.1
|
||||
|
||||
## Changes made on the 7.0 branch since 7.0.7
|
||||
### Limit to `_FORTIFY_SOURCE=2`
|
||||
|
||||
GCC versions 12 and beyond and glibc have added some aggressive runtime
|
||||
checks for buffer overflows in libc functions at runtime, and the
|
||||
[Ubuntu 2024.04](https://wiki.ubuntu.com/ToolChain/CompilerFlags) release
|
||||
increased their default gcc fortification level from 2 to 3.
|
||||
This has started causing EPICS Base builds to fail on that version, and
|
||||
other OS releases may make that configuration change with similar results.
|
||||
This release detects a compiler configured with `_FORTIFY_SOURCE=3` and
|
||||
overrides it to 2.
|
||||
Later releases of Base will adjust the code, providing information to the
|
||||
compiler to avoid triggering these incorrect protections.
|
||||
|
||||
### Fix issue with compress record
|
||||
|
||||
In Base 7.0.8, an update to the compress record was added to allow for certain
|
||||
algorithms to use partially filled buffers in their computations. Unfortunately,
|
||||
this broke the behaviour of the records in certain cases. This has been fixed.
|
||||
|
||||
### Various minor changes
|
||||
|
||||
These included fixing minor memory leaks and documentation corrections. The
|
||||
`SIZV` field of lsi, lso and printf record VAL fields now can't exceed 32767
|
||||
characters, to match an internal limit.
|
||||
|
||||
### `epicsSocketAccept()` now returns `SOCKET`, not `int`
|
||||
|
||||
This might have some effect on downstream modules still using `int`, but the
|
||||
OS-specific osdSock.h headers which osiSock.h includes have all declared
|
||||
`SOCKET` (in most casese as a typedef for `int`) for many releases.
|
||||
This change removes a compiler warning on WIN32.
|
||||
Further details and the discussion about this change can be found
|
||||
[here](https://github.com/epics-base/epics-base/pull/458).
|
||||
|
||||
### `dbLoadRecords` allows macros with default values
|
||||
|
||||
Previously the parser assumed that files containing macro substitutions were
|
||||
bad if no macro definitions were provided; that assumption was made incorrect
|
||||
once macro substitutions were allowed to provide a default value.
|
||||
|
||||
### Hostname length limit in CA removed
|
||||
|
||||
Before this release, the CA client library only handled hostnames in address
|
||||
list environment variables up to 255 characters long.
|
||||
This limit has been removed.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.8
|
||||
|
||||
### bi "Raw Soft Channel" use MASK
|
||||
|
||||
If MASK is non-zero, The raw device support will now apply MASK to the
|
||||
value read into RVAL.
|
||||
eg. allows extraction of a bit from an input integer.
|
||||
|
||||
```
|
||||
record(longin, "integer") {
|
||||
field(VAL, "0xff")
|
||||
}
|
||||
record(bi, "bit1") {
|
||||
field(DESC, "extract bit 1")
|
||||
field(DTYP, "Raw Soft Channel")
|
||||
field(INP , "integer")
|
||||
field(MASK, "0x2")
|
||||
field(ZNAM, "Clear")
|
||||
field(ONAM, "Set")
|
||||
}
|
||||
```
|
||||
|
||||
### ANSI escapes in stderr
|
||||
|
||||
ANSI escape charactor sequences may now be printed to the stderr stream.
|
||||
These escapes will appear in logs captured from that stream.
|
||||
Tools which parse and/or render these logs may need to be adjusted to
|
||||
either strip out the escapes, or to translate them into markup.
|
||||
(see [ansi2html](https://pypi.org/project/ansi2html/) for example)
|
||||
|
||||
### Allow explicit append with `dbRecordsOnceOnly!=0`
|
||||
|
||||
Previously setting `dbRecordsOnceOnly!=0` prevented any further changes to a record via a .db file. eg.
|
||||
|
||||
```
|
||||
record(ai, "myrec") {}
|
||||
```
|
||||
|
||||
`dbRecordsOnceOnly!=0` previously disallowed appending fields with either form:
|
||||
|
||||
```
|
||||
record("*", "myrec") {} # error
|
||||
record(ai, "myrec") {} # error
|
||||
```
|
||||
|
||||
Beginning with this release, `dbRecordsOnceOnly!=0` allows appending when explicitly intended (when record type is `"*"`).
|
||||
|
||||
```
|
||||
record("*", "myrec") {} # allowed
|
||||
record(ai, "myrec") {} # error
|
||||
```
|
||||
|
||||
### Add `$EPICS_CLI_TIMEOUT`
|
||||
|
||||
@@ -63,7 +161,7 @@ Previously, if a subRecord has an invalid `INP*` link, it was silently failing
|
||||
(and not running the proc function). Now the the status code returned by the
|
||||
subroutine is returned from `dbProcess()`.
|
||||
|
||||
### COMMANDLINE_LIBRARY fallback to GNU_DIR
|
||||
### COMMANDLINE\_LIBRARY fallback to GNU\_DIR
|
||||
|
||||
Fall back to the previous behavior when searching for `readline.h` with older compilers.
|
||||
|
||||
@@ -102,6 +200,10 @@ and string formats, some of which support full nanosecond precision.
|
||||
More information is included in the filters documentation, which can be found in
|
||||
the `html/filters.html` document that is generated during the build
|
||||
|
||||
### Allow adding new error symbols at any time
|
||||
|
||||
`errSymbolAdd` can now be called after early initialization.
|
||||
|
||||
### Add conditional output (OOPT) to the longout record
|
||||
|
||||
The longout record can now be configured using its new OOPT and OOCH fields
|
||||
@@ -114,7 +216,9 @@ This functionality was suggested in
|
||||
be added to other output record types if the community finds it useful,
|
||||
please send feedback about the feature to tech-talk.
|
||||
|
||||
### Tab completion for IOC shell
|
||||
### IOC Shell
|
||||
|
||||
#### Tab completion
|
||||
|
||||
When built with optional GNU libreadline support, the interactive IOC shell
|
||||
will perform tab completion for command names as well as for some arguments
|
||||
@@ -126,14 +230,25 @@ using the new `iocshArgStringRecord` and `iocshArgStringPath` argument types.
|
||||
Both function identically to `iocshArgString` but indicate how to suggest
|
||||
completion strings.
|
||||
|
||||
Builds on macOS (darwin-x86 or darwin-aarch64 targets) normally use Apple's
|
||||
Builds on macOS (`darwin-x86` or `darwin-aarch64` targets) normally use Apple's
|
||||
libedit library in readline compatibility mode, which doesn't support the tab
|
||||
completion API that GNU readline provides. You can use Homebrew or some other
|
||||
third-party package manager to install the GNU readline package, then edit the
|
||||
configure/os/CONFIG_SITE.darwinCommon.darwinCommon file to have EPICS use the
|
||||
`configure/os/CONFIG_SITE.darwinCommon.darwinCommon` file to have EPICS use the
|
||||
real thing to get tab completion in the IOC shell. The default settings in that
|
||||
file currently look for and use a Homebrew-installed readline if present.
|
||||
|
||||
#### Persist history
|
||||
|
||||
Attempt to read and write command to a file (`./.iocsh_history` by default).
|
||||
Name may be overwritten with by setting `$EPICS_IOCSH_HISTFILE` to an
|
||||
alternate path, or disabled by setting to an empty string.
|
||||
|
||||
#### Changes to help output
|
||||
|
||||
Rework the `help` command output to improve formatting and readability,
|
||||
and include a visual marker (a line of underlines) between different help commands.
|
||||
|
||||
### Add FMOD as CALC Expression
|
||||
|
||||
The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC
|
||||
|
||||
@@ -48,14 +48,14 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<p>The following roles are used below:</p>
|
||||
|
||||
<dl>
|
||||
<dt><strong>Release Manager</strong> ()</dt>
|
||||
<dt><strong>Release Manager</strong></dt>
|
||||
<dd>Responsible for managing and tagging the release</dd>
|
||||
<dt><strong>Platform Developers</strong> (informal)</dt>
|
||||
<dd>Responsible for individual operating system platforms</dd>
|
||||
<dt><strong>Core Developers</strong></dt>
|
||||
<dd>Responsible for maintaining the EPICS software</dd>
|
||||
<dt><strong>Application Developers</strong></dt>
|
||||
<dd>Responsible for support modules that depend on EPICS Base.</dd>
|
||||
<dt><strong>APS Website Editor</strong> (Andrew Johnson)</dt>
|
||||
<dd>Responsible for the APS EPICS website</dd>
|
||||
<dt><strong>Website Editors</strong></dt>
|
||||
<dd>Responsible for the EPICS websites</dd>
|
||||
</dl>
|
||||
|
||||
<form>
|
||||
@@ -72,23 +72,22 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Email all developers about the upcoming release and ask for a list
|
||||
of remaining tasks that must be finished.</td>
|
||||
<td>Notify core developers about the upcoming release and ask about any
|
||||
remaining tasks that must be finished.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>All developers</td>
|
||||
<td>Check the bug tracker for any outstanding items and handle
|
||||
appropriately. All bugs that have been fixed should have been marked
|
||||
as Fix Committed.</td>
|
||||
appropriately.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Set the Feature Freeze date, by which time all Git commits for
|
||||
enhancements and new functionality should have been completed. After
|
||||
this date, commits should only be made to fix problems that show up
|
||||
during testing.</td>
|
||||
<td>Set a Feature Freeze date, by which time all Git branches for
|
||||
enhancements and new functionality should have been merged. After this
|
||||
date, commits and merges should only be made to fix problems that show
|
||||
up during testing.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
@@ -97,6 +96,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td>Ensure that documentation will be updated before the release date:
|
||||
<ul>
|
||||
<li>Release Notes</li>
|
||||
<li>Doxygen annotations</li>
|
||||
<li>Other documents</li>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -104,13 +104,8 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Review and update this checklist for the upcoming release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Create a release milestone on Launchpad. If a target release date is
|
||||
known set "Date Targeted" to the expected release date.</td>
|
||||
<td>Review and update this checklist for the upcoming release.
|
||||
Update the release version number in the tags and messages below.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Testing</th>
|
||||
@@ -118,7 +113,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Platform Developers</td>
|
||||
<td>Run the built-in test programs on all available host platforms using
|
||||
<td>Run the internal test programs on all available host platforms using
|
||||
<blockquote><tt>
|
||||
make -s runtests
|
||||
</tt></blockquote></td>
|
||||
@@ -156,6 +151,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td>Check that documentation has been updated:
|
||||
<ul>
|
||||
<li>Release Notes</li>
|
||||
<li>Doxygen annotations</li>
|
||||
<li>Other documents</li>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -167,8 +163,8 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Obtain a positive <q>Ok to release</q> from developers.</td>
|
||||
<td>Core Developers</td>
|
||||
<td>Reach a consensus that the software is ready to release.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3">Creating the final release version</th>
|
||||
@@ -191,27 +187,29 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
cd base-7.0/modules/<module>/documentation<br />
|
||||
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
|
||||
</tt></blockquote>
|
||||
Commit changes (don't push).</li>
|
||||
Commit these changes (don't push).</li>
|
||||
|
||||
<li>Edit the module's release version file
|
||||
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and its top-level
|
||||
<tt>Doxyfile</tt>; set the <tt>DEVELOPMENT_FLAG</tt> value to 0 and
|
||||
remove <tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string.
|
||||
Commit changes (don't push).</li>
|
||||
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and the
|
||||
<tt>Doxyfile</tt>s in the top-level and/or documentation
|
||||
directories. In these, set <tt>DEVELOPMENT_FLAG</tt> to 0 and remove
|
||||
<tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string. Commit these
|
||||
changes (don't push).</li>
|
||||
|
||||
<li>Tag the module:
|
||||
<blockquote><tt>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.7' <module-version>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.8.1' <module-version>
|
||||
</tt></blockquote>
|
||||
</li>
|
||||
|
||||
<li>Update the git submodule on the Base-7.0 branch to the
|
||||
newly-tagged version, but don't commit yet:
|
||||
newly-tagged version, check the module's status matches the tag:
|
||||
<blockquote><tt>
|
||||
cd base-7.0/modules<br />
|
||||
git add <module><br />
|
||||
git submodule status --cached
|
||||
</tt></blockquote>
|
||||
Don't commit the submodule updates yet.
|
||||
</li>
|
||||
|
||||
<li>Edit the module's release version file
|
||||
@@ -221,7 +219,8 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<tt>PROJECT_NUMBER</tt> string, appending <tt>-dev</tt> to the new
|
||||
module version number. Commit changes.</li>
|
||||
|
||||
<li>Push commits and the new tag to the submodule's GitHub repository:
|
||||
<li>Push commits and the new tag to the submodule's GitHub repository
|
||||
(assumed to be the <tt>upstream</tt> remote):
|
||||
<blockquote><tt>
|
||||
cd base-7.0/modules/<module><br />
|
||||
git push --follow-tags upstream master
|
||||
@@ -270,10 +269,9 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td>Tag the epics-base module in Git:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.7
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.8.1
|
||||
</tt></blockquote>
|
||||
<p>Don't push anything to the Launchpad repository
|
||||
yet.</p>
|
||||
<p>Don't push to GitHub yet.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -305,12 +303,12 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.7 ../base-7.0.7.tar.gz base-7.0.7/
|
||||
./.tools/make-tar.sh R7.0.8.1 ../base-7.0.8.1.tar.gz base-7.0.8.1/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
cd ..<br />
|
||||
gpg --armor --sign --detach-sig base-7.0.7.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.8.1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -318,8 +316,9 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Test the tar file by extracting its contents and building it on at
|
||||
least one supported platform. When this succeeds the commits and new git
|
||||
tag can be pushed to the Launchpad repository:
|
||||
least one supported platform. If this succeeds the commits and new git
|
||||
tag can be pushed to the GitHub repository's 7.0 branch (assumed to be
|
||||
the <tt>upstream</tt> remote):
|
||||
<blockquote><tt>
|
||||
git push --follow-tags upstream 7.0
|
||||
</tt></blockquote>
|
||||
@@ -367,7 +366,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="3">Publish to epics-controls</th>
|
||||
<th colspan="3">Publish to epics-controls.org</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
@@ -375,7 +374,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
epics-controls web-server.
|
||||
<blockquote><tt>
|
||||
scp base-7.0.7.tar.gz base-7.0.7.tar.gz.asc epics-controls:download/base<br />
|
||||
scp base-7.0.8.1.tar.gz base-7.0.8.1.tar.gz.asc epics-controls:download/base<br />
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -392,22 +391,22 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="3">Publish to Launchpad</th>
|
||||
<th colspan="3">Publish to GitHub</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release 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>
|
||||
<td>Go to the GitHub
|
||||
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8.1">
|
||||
Create release from tag R7.0.8.1</a> page.
|
||||
Upload the tar file and its <tt>.asc</tt> signature file to the new
|
||||
GitHub 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>
|
||||
<td>We used to close out bug reports in Launchpad at release-time, this
|
||||
would be the time to do that if we have an equivalent on GitHub.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
@@ -34,9 +34,6 @@ pvDatabase_DEPEND_DIRS = pvAccess
|
||||
SUBMODULES += pva2pva
|
||||
pva2pva_DEPEND_DIRS = pvAccess
|
||||
|
||||
SUBMODULES += example
|
||||
example_DEPEND_DIRS = pva2pva pvaClient
|
||||
|
||||
# Allow sites to add extra submodules
|
||||
-include Makefile.local
|
||||
|
||||
|
||||
@@ -2575,7 +2575,8 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
|
||||
SEVCHK ( ca_get ( DBR_FLOAT, chan, &temp ), NULL );
|
||||
SEVCHK ( ca_pend_io ( timeoutToPendIO ), NULL );
|
||||
|
||||
/* printf ( "flow control bypassed %u events\n", flowCtrlCount ); */
|
||||
if (0)
|
||||
printf ( "flow control bypassed %u events\n", flowCtrlCount );
|
||||
|
||||
showProgressEnd ( interestLevel );
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string> // vxWorks 6.0 requires this include
|
||||
|
||||
#include "epicsStdio.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsVersion.h"
|
||||
@@ -1008,7 +1009,7 @@ bool cac::defaultExcep (
|
||||
char buf[512];
|
||||
char hostName[64];
|
||||
iiu.getHostName ( guard, hostName, sizeof ( hostName ) );
|
||||
sprintf ( buf, "host=%s ctx=%.400s", hostName, pCtx );
|
||||
epicsSnprintf( buf, sizeof(buf), "host=%s ctx=%.400s", hostName, pCtx );
|
||||
this->notify.exception ( guard, status, buf, 0, 0u );
|
||||
return true;
|
||||
}
|
||||
@@ -1312,7 +1313,7 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
|
||||
const char * pChannelName, const char * pAcc, const char * pRej )
|
||||
{
|
||||
char buf[256];
|
||||
sprintf ( buf, "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
|
||||
epicsSnprintf( buf, sizeof(buf), "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
|
||||
pChannelName, pAcc, pRej );
|
||||
{
|
||||
callbackManager mgr ( this->notify, this->cbMutex );
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -28,6 +31,7 @@
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsStdioRedirect.h"
|
||||
#include "errlog.h"
|
||||
#include "osiWireFormat.h"
|
||||
@@ -35,39 +39,6 @@
|
||||
#include "addrList.h"
|
||||
#include "iocinf.h"
|
||||
|
||||
/*
|
||||
* getToken()
|
||||
*/
|
||||
static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
|
||||
{
|
||||
bool tokenFound = false;
|
||||
const char *pToken;
|
||||
unsigned i;
|
||||
|
||||
pToken = *ppString;
|
||||
while ( isspace (*pToken) && *pToken ){
|
||||
pToken++;
|
||||
}
|
||||
|
||||
for ( i=0u; i<bufSIze; i++ ) {
|
||||
if ( isspace (pToken[i]) || pToken[i]=='\0' ) {
|
||||
pBuf[i] = '\0';
|
||||
*ppString = &pToken[i];
|
||||
if ( i != 0 ) {
|
||||
tokenFound = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pBuf[i] = pToken[i];
|
||||
}
|
||||
|
||||
if ( tokenFound ) {
|
||||
pBuf[bufSIze-1] = '\0';
|
||||
return pBuf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* addAddrToChannelAccessAddressList ()
|
||||
*/
|
||||
@@ -77,9 +48,7 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
|
||||
{
|
||||
osiSockAddrNode *pNewNode;
|
||||
const char *pStr;
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[256u]; /* large enough to hold an IP address or hostname */
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
@@ -87,31 +56,45 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
|
||||
status = aToIPAddr ( pToken, port, &addr );
|
||||
if (status<0) {
|
||||
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
|
||||
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
|
||||
continue;
|
||||
try {
|
||||
std::vector<char> scratch(pStr, pStr+strlen(pStr)+1); // copy chars and trailing nil
|
||||
|
||||
char *save = NULL;
|
||||
for(const char *pToken = epicsStrtok_r(&scratch[0], " \t\n\r", &save);
|
||||
pToken;
|
||||
pToken = epicsStrtok_r(NULL, " \t\n\r", &save))
|
||||
{
|
||||
if(!pToken[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
status = aToIPAddr ( pToken, port, &addr );
|
||||
if (status<0) {
|
||||
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
|
||||
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
}
|
||||
|
||||
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
} catch(std::exception&) { // only bad_alloc currently possible
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -549,7 +549,7 @@ void epicsStdCall caRepeaterRegistrationMessage (
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
fprintf ( stderr, "error sending registration message to CA repeater daemon was \"%s\"\n",
|
||||
fprintf ( stderr, ERL_ERROR " sending registration message to CA repeater daemon was \"%s\"\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
@@ -813,13 +813,13 @@ bool udpiiu::exceptionRespAction (
|
||||
|
||||
if ( msg.m_postsize > sizeof ( caHdr ) ){
|
||||
errlogPrintf (
|
||||
"error condition \"%s\" detected by %s with context \"%s\" at %s\n",
|
||||
ERL_ERROR " condition \"%s\" detected by %s with context \"%s\" at %s\n",
|
||||
ca_message ( msg.m_available ),
|
||||
name, reinterpret_cast <const char *> ( &reqMsg + 1 ), date );
|
||||
}
|
||||
else{
|
||||
errlogPrintf (
|
||||
"error condition \"%s\" detected by %s at %s\n",
|
||||
ERL_ERROR " condition \"%s\" detected by %s at %s\n",
|
||||
ca_message ( msg.m_available ), name, date );
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <epicsStdlib.h>
|
||||
|
||||
#include <cadef.h>
|
||||
#include <errlog.h>
|
||||
#include <epicsGetopt.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsString.h>
|
||||
@@ -549,7 +550,7 @@ int main (int argc, char *argv[])
|
||||
result = ca_array_put (dbrType, count, pvs[0].chid, pbuf);
|
||||
}
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "Error from put operation: %s\n", ca_message(result));
|
||||
fprintf(stderr, ERL_ERROR " from put operation: %s\n", ca_message(result));
|
||||
free(sbuf); free(dbuf); free(ebuf);
|
||||
return 1;
|
||||
}
|
||||
@@ -570,7 +571,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "Error occured writing data: %s\n", ca_message(result));
|
||||
fprintf(stderr, ERL_ERROR " occured writing data: %s\n", ca_message(result));
|
||||
free(sbuf); free(dbuf); free(ebuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -225,6 +225,11 @@ static void asCaTask(void)
|
||||
if(asCaDebug) printf("asCaTask has cleared all channels\n");
|
||||
epicsEventSignal(asCaTaskWait);
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
cantProceed("Unreachable. Perpetual thread.");
|
||||
|
||||
taskwdRemove(0);
|
||||
}
|
||||
|
||||
void asCaStart(void)
|
||||
|
||||
@@ -21,7 +21,8 @@ static const iocshArg * const asSetFilenameArgs[] = {&asSetFilenameArg0};
|
||||
static const iocshFuncDef asSetFilenameFuncDef =
|
||||
{"asSetFilename",1,asSetFilenameArgs,
|
||||
"Set path+file name of ACF file.\n"
|
||||
"No immediate effect. Run as asInit() to (re)load.\n"};
|
||||
"No immediate effect. Run asInit to (re)load.\n"
|
||||
"Example: asSetFilename /full/path/to/accessSecurityFile\n"};
|
||||
static void asSetFilenameCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
asSetFilename(args[0].sval);
|
||||
@@ -33,7 +34,8 @@ static const iocshArg * const asSetSubstitutionsArgs[] = {&asSetSubstitutionsArg
|
||||
static const iocshFuncDef asSetSubstitutionsFuncDef =
|
||||
{"asSetSubstitutions",1,asSetSubstitutionsArgs,
|
||||
"Set subtitutions used when reading ACF file.\n"
|
||||
"No immediate effect. Run as asInit() to (re)load.\n"};
|
||||
"No immediate effect. Run asInit to (re)load.\n"
|
||||
"Example: asSetSubstitutions var1=5,var2=hello\n"};
|
||||
static void asSetSubstitutionsCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
asSetSubstitutions(args[0].sval);
|
||||
@@ -59,7 +61,10 @@ static void asdbdumpCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg aspuagArg0 = { "uagname",iocshArgString};
|
||||
static const iocshArg * const aspuagArgs[] = {&aspuagArg0};
|
||||
static const iocshFuncDef aspuagFuncDef = {"aspuag",1,aspuagArgs,
|
||||
"Show members of User Access Group.\n"};
|
||||
"Show members of the User Access Group.\n"
|
||||
"If no Group is specified then the members\n"
|
||||
"of all user access groups are displayed.\n"
|
||||
"Example: aspuag mygroup\n"};
|
||||
static void aspuagCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
aspuag(args[0].sval);
|
||||
@@ -69,7 +74,10 @@ static void aspuagCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg asphagArg0 = { "hagname",iocshArgString};
|
||||
static const iocshArg * const asphagArgs[] = {&asphagArg0};
|
||||
static const iocshFuncDef asphagFuncDef = {"asphag",1,asphagArgs,
|
||||
"Show members of Host Access Group.\n"};
|
||||
"Show members of the Host Access Group.\n"
|
||||
"If no Group is specified then the members\n"
|
||||
"of all host access groups are displayed\n"
|
||||
"Example: asphag mygroup\n"};
|
||||
static void asphagCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
asphag(args[0].sval);
|
||||
@@ -78,8 +86,12 @@ static void asphagCallFunc(const iocshArgBuf *args)
|
||||
/* asprules */
|
||||
static const iocshArg asprulesArg0 = { "asgname",iocshArgString};
|
||||
static const iocshArg * const asprulesArgs[] = {&asprulesArg0};
|
||||
static const iocshFuncDef asprulesFuncDef = {"asprules",1,asprulesArgs,
|
||||
"List rules of an Access Security Group.\n"};
|
||||
static const iocshFuncDef asprulesFuncDef = {
|
||||
"asprules",1,asprulesArgs,
|
||||
"List rules of an Access Security Group.\n"
|
||||
"If no Group is specified then list the rules for all groups\n"
|
||||
"Example: asprules mygroup\n"
|
||||
};
|
||||
static void asprulesCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
asprules(args[0].sval);
|
||||
@@ -89,8 +101,14 @@ static void asprulesCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg aspmemArg0 = { "asgname",iocshArgString};
|
||||
static const iocshArg aspmemArg1 = { "clients",iocshArgInt};
|
||||
static const iocshArg * const aspmemArgs[] = {&aspmemArg0,&aspmemArg1};
|
||||
static const iocshFuncDef aspmemFuncDef = {"aspmem",2,aspmemArgs,
|
||||
"List members of Access Security Group.\n"};
|
||||
static const iocshFuncDef aspmemFuncDef = {
|
||||
"aspmem",2,aspmemArgs,
|
||||
"List members of Access Security Group.\n"
|
||||
"If no Group is specified then print the members for all Groups.\n"
|
||||
"If clients is (0, 1) then Channel Access clients attached to each member\n"
|
||||
"(are not, are) shown\n"
|
||||
"Example: aspmem mygroup 1\n",
|
||||
};
|
||||
static void aspmemCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
aspmem(args[0].sval,args[1].ival);
|
||||
@@ -101,8 +119,10 @@ static const iocshArg astacArg0 = { "recordname",iocshArgStringRecord};
|
||||
static const iocshArg astacArg1 = { "user",iocshArgString};
|
||||
static const iocshArg astacArg2 = { "host",iocshArgString};
|
||||
static const iocshArg * const astacArgs[] = {&astacArg0,&astacArg1,&astacArg2};
|
||||
static const iocshFuncDef astacFuncDef = {"astac",3,astacArgs,
|
||||
"Test Access Security privlages granted to user+host.\n"};
|
||||
static const iocshFuncDef astacFuncDef = {
|
||||
"astac",3,astacArgs,
|
||||
"Show what read/write permissions the user:host would have when\n"
|
||||
"accessing a certain PV.\n"};
|
||||
static void astacCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
astac(args[0].sval,args[1].sval,args[2].sval);
|
||||
@@ -111,8 +131,14 @@ static void astacCallFunc(const iocshArgBuf *args)
|
||||
/* ascar */
|
||||
static const iocshArg ascarArg0 = { "level",iocshArgInt};
|
||||
static const iocshArg * const ascarArgs[] = {&ascarArg0};
|
||||
static const iocshFuncDef ascarFuncDef = {"ascar",1,ascarArgs,
|
||||
"Report status of PVs used in INP*() Access Security rules.\n"};
|
||||
static const iocshFuncDef ascarFuncDef = {
|
||||
"ascar",1,ascarArgs,
|
||||
"Report status of PVs used in INP*() Access Security rules.\n"
|
||||
"Level 0 - Summary report\n"
|
||||
" 1 - Summary report plus details on unconnected channels\n"
|
||||
" 2 - Summary report plus detail report on each channel\n"
|
||||
"Example: ascar 1\n"
|
||||
};
|
||||
static void ascarCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
ascar(args[0].ival);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "ellLib.h"
|
||||
#include "cvtTable.h"
|
||||
|
||||
@@ -125,12 +126,12 @@ int main(int argc, char **argv)
|
||||
}
|
||||
inFile = fopen(argv[1],"r");
|
||||
if(!inFile) {
|
||||
fprintf(stderr,"Error opening %s\n",argv[1]);
|
||||
fprintf(stderr,ERL_ERROR " opening %s\n",argv[1]);
|
||||
exit(-1);
|
||||
}
|
||||
outFile = fopen(outFilename,"w");
|
||||
if(!outFile) {
|
||||
fprintf(stderr,"Error opening %s\n",outFilename);
|
||||
fprintf(stderr,ERL_ERROR " opening %s\n",outFilename);
|
||||
exit(-1);
|
||||
}
|
||||
while(fgets(inbuf,MAX_LINE_SIZE,inFile)) {
|
||||
|
||||
@@ -344,6 +344,10 @@ int callbackRequest(epicsCallback *pcallback)
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback was NULL\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
if (!pcallback->callback) {
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback->callback was NULL\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
priority = pcallback->priority;
|
||||
if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) {
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Bad priority\n");
|
||||
|
||||
@@ -798,18 +798,13 @@ int dbLoadRecords(const char* file, const char* subs)
|
||||
return -1;
|
||||
}
|
||||
status = dbReadDatabase(&pdbbase, file, 0, subs);
|
||||
switch(status)
|
||||
{
|
||||
case 0:
|
||||
if(status==0) {
|
||||
if(dbLoadRecordsHook)
|
||||
dbLoadRecordsHook(file, subs);
|
||||
break;
|
||||
case -2:
|
||||
errlogPrintf("dbLoadRecords: failed to load '%s'\n"
|
||||
" Records cannot be loaded after iocInit!\n", file);
|
||||
break;
|
||||
default:
|
||||
errlogPrintf("dbLoadRecords: failed to load '%s'\n", file);
|
||||
} else {
|
||||
fprintf(stderr, ERL_ERROR " failed to load '%s'\n", file);
|
||||
if(status==-2)
|
||||
fprintf(stderr, " Records cannot be loaded after iocInit!\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -41,20 +41,35 @@ extern "C" {
|
||||
/**
|
||||
* event subscription
|
||||
*/
|
||||
typedef struct evSubscrip {
|
||||
struct evSubscrip;
|
||||
|
||||
typedef struct evSubscrip evSubscrip;
|
||||
|
||||
#ifdef EPICS_PRIVATE_API
|
||||
struct evSubscrip {
|
||||
ELLNODE node;
|
||||
struct dbChannel * chan;
|
||||
/* user_sub==NULL used to indicate db_cancel_event() */
|
||||
EVENTFUNC * user_sub;
|
||||
void * user_arg;
|
||||
/* associated queue, may be shared with other evSubscrip */
|
||||
struct event_que * ev_que;
|
||||
/* NULL if !npend. if npend!=0, pointer to last event added to event_que::valque */
|
||||
db_field_log ** pLastLog;
|
||||
unsigned long npend; /**< n times this event is on the queue */
|
||||
unsigned long nreplace; /**< n times replacing event on the queue */
|
||||
/* n times this event is on the queue */
|
||||
unsigned long npend;
|
||||
/* n times replacing event on the queue */
|
||||
unsigned long nreplace;
|
||||
/* DBE mask */
|
||||
unsigned char select;
|
||||
/* if set, subscription will yield dbfl_type_val */
|
||||
char useValque;
|
||||
/* event_task is handling this subscription */
|
||||
char callBackInProgress;
|
||||
/* this node added to dbCommon::mlis */
|
||||
char enabled;
|
||||
} evSubscrip;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct chFilter chFilter;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* Ralph Lange <Ralph.Lange@bessy.de>
|
||||
*/
|
||||
|
||||
#define EPICS_PRIVATE_API
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -75,23 +76,23 @@ struct event_que {
|
||||
unsigned short getix;
|
||||
unsigned short quota; /* the number of assigned entries*/
|
||||
unsigned short nDuplicates; /* N events duplicated on this q */
|
||||
unsigned short nCanceled; /* the number of canceled entries */
|
||||
unsigned possibleStall;
|
||||
};
|
||||
|
||||
struct event_user {
|
||||
struct event_que firstque; /* the first event que */
|
||||
|
||||
ELLLIST waiters; /* event_waiter::node */
|
||||
|
||||
epicsMutexId lock;
|
||||
epicsEventId ppendsem; /* Wait while empty */
|
||||
epicsEventId pflush_sem; /* wait for flush */
|
||||
epicsEventId pexitsem; /* wait for event task to join */
|
||||
|
||||
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
|
||||
void *extralabor_arg;/* parameter to above */
|
||||
|
||||
epicsThreadId taskid; /* event handler task id */
|
||||
struct evSubscrip *pSuicideEvent; /* event that is deleting itself */
|
||||
epicsUInt32 pflush_seq; /* worker cycle count for synchronization */
|
||||
unsigned queovr; /* event que overflow count */
|
||||
unsigned char pendexit; /* exit pend task */
|
||||
unsigned char extra_labor; /* if set call extra labor func */
|
||||
@@ -101,6 +102,11 @@ struct event_user {
|
||||
epicsThreadId init_func_arg;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ELLNODE node; /* event_user::waiters */
|
||||
epicsEventId wake;
|
||||
} event_waiter;
|
||||
|
||||
/*
|
||||
* Reliable intertask communication requires copying the current value of the
|
||||
* channel for later queuing so 3 stepper motor steps of 10 each do not turn
|
||||
@@ -122,10 +128,9 @@ static void *dbevFieldLogFreeList;
|
||||
|
||||
static char *EVENT_PEND_NAME = "eventTask";
|
||||
|
||||
static struct evSubscrip canceledEvent;
|
||||
|
||||
static epicsMutexId stopSync;
|
||||
|
||||
/* unused space in queue (EVENTQUESIZE when empty) */
|
||||
static unsigned short ringSpace ( const struct event_que *pevq )
|
||||
{
|
||||
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
|
||||
@@ -139,17 +144,11 @@ static unsigned short ringSpace ( const struct event_que *pevq )
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* db_event_list ()
|
||||
*/
|
||||
int db_event_list ( const char *pname, unsigned level )
|
||||
{
|
||||
return dbel ( pname, level );
|
||||
}
|
||||
|
||||
/*
|
||||
* dbel ()
|
||||
*/
|
||||
int dbel ( const char *pname, unsigned level )
|
||||
{
|
||||
DBADDR addr;
|
||||
@@ -217,7 +216,6 @@ int dbel ( const char *pname, unsigned level )
|
||||
|
||||
if ( level > 2 ) {
|
||||
unsigned nDuplicates;
|
||||
unsigned nCanceled;
|
||||
if ( pevent->nreplace ) {
|
||||
printf (", discarded by replacement=%ld", pevent->nreplace);
|
||||
}
|
||||
@@ -226,14 +224,10 @@ int dbel ( const char *pname, unsigned level )
|
||||
}
|
||||
LOCKEVQUE(pevent->ev_que);
|
||||
nDuplicates = pevent->ev_que->nDuplicates;
|
||||
nCanceled = pevent->ev_que->nCanceled;
|
||||
UNLOCKEVQUE(pevent->ev_que);
|
||||
if ( nDuplicates ) {
|
||||
printf (", duplicate count =%u\n", nDuplicates );
|
||||
}
|
||||
if ( nCanceled ) {
|
||||
printf (", canceled count =%u\n", nCanceled );
|
||||
}
|
||||
}
|
||||
|
||||
if ( level > 3 ) {
|
||||
@@ -318,9 +312,6 @@ dbEventCtx db_init_events (void)
|
||||
evUser->ppendsem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->ppendsem)
|
||||
goto fail;
|
||||
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->pflush_sem)
|
||||
goto fail;
|
||||
evUser->lock = epicsMutexCreate();
|
||||
if (!evUser->lock)
|
||||
goto fail;
|
||||
@@ -330,7 +321,6 @@ dbEventCtx db_init_events (void)
|
||||
|
||||
evUser->flowCtrlMode = FALSE;
|
||||
evUser->extraLaborBusy = FALSE;
|
||||
evUser->pSuicideEvent = NULL;
|
||||
return (dbEventCtx) evUser;
|
||||
fail:
|
||||
if(evUser->lock)
|
||||
@@ -339,8 +329,6 @@ fail:
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
if(evUser->ppendsem)
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
if(evUser->pflush_sem)
|
||||
epicsEventDestroy (evUser->pflush_sem);
|
||||
if(evUser->pexitsem)
|
||||
epicsEventDestroy (evUser->pexitsem);
|
||||
freeListFree(dbevEventUserFreeList,evUser);
|
||||
@@ -404,7 +392,6 @@ void db_close_events (dbEventCtx ctx)
|
||||
|
||||
epicsEventDestroy(evUser->pexitsem);
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
epicsMutexUnlock (stopSync);
|
||||
@@ -461,8 +448,7 @@ dbEventSubscription db_add_event (
|
||||
while ( TRUE ) {
|
||||
int success = 0;
|
||||
LOCKEVQUE ( ev_que );
|
||||
success = ( ev_que->quota + ev_que->nCanceled <
|
||||
EVENTQUESIZE - EVENTENTRIES );
|
||||
success = ( ev_que->quota < EVENTQUESIZE - EVENTENTRIES );
|
||||
if ( success ) {
|
||||
ev_que->quota += EVENTENTRIES;
|
||||
}
|
||||
@@ -579,62 +565,62 @@ static void event_remove ( struct event_que *ev_que,
|
||||
void db_cancel_event (dbEventSubscription event)
|
||||
{
|
||||
struct evSubscrip * const pevent = (struct evSubscrip *) event;
|
||||
unsigned short getix;
|
||||
struct event_que *que = pevent->ev_que;
|
||||
char sync = 0;
|
||||
|
||||
db_event_disable ( event );
|
||||
|
||||
/*
|
||||
* flag the event as canceled by NULLing out the callback handler
|
||||
*
|
||||
* make certain that the event isn't being accessed while
|
||||
* its call back changes
|
||||
*/
|
||||
LOCKEVQUE (pevent->ev_que);
|
||||
LOCKEVQUE (que);
|
||||
|
||||
pevent->user_sub = NULL;
|
||||
pevent->user_sub = NULL; /* callback pointer doubles as canceled flag */
|
||||
|
||||
/*
|
||||
* purge this event from the queue
|
||||
*
|
||||
* Its better to take this approach rather than waiting
|
||||
* for the event thread to finish removing this event
|
||||
* from the queue because the event thread will not
|
||||
* process if we are in flow control mode. Since blocking
|
||||
* here will block CA's TCP input queue then a dead lock
|
||||
* would be possible.
|
||||
*/
|
||||
for ( getix = pevent->ev_que->getix;
|
||||
pevent->ev_que->evque[getix] != EVENTQEMPTY; ) {
|
||||
if ( pevent->ev_que->evque[getix] == pevent ) {
|
||||
assert ( pevent->ev_que->nCanceled < USHRT_MAX );
|
||||
pevent->ev_que->nCanceled++;
|
||||
event_remove ( pevent->ev_que, getix, &canceledEvent );
|
||||
}
|
||||
getix = RNGINC ( getix );
|
||||
if ( getix == pevent->ev_que->getix ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert ( pevent->npend == 0u );
|
||||
if(pevent->callBackInProgress) {
|
||||
/* this event callback is pending or in-progress in event_task. */
|
||||
if(pevent->ev_que->evUser->taskid != epicsThreadGetIdSelf())
|
||||
sync = 1; /* concurrent to event_task, so wait */
|
||||
|
||||
if ( pevent->ev_que->evUser->taskid == epicsThreadGetIdSelf() ) {
|
||||
pevent->ev_que->evUser->pSuicideEvent = pevent;
|
||||
}
|
||||
else {
|
||||
while ( pevent->callBackInProgress ) {
|
||||
UNLOCKEVQUE (pevent->ev_que);
|
||||
epicsEventMustWait ( pevent->ev_que->evUser->pflush_sem );
|
||||
LOCKEVQUE (pevent->ev_que);
|
||||
}
|
||||
} else if(pevent->npend) {
|
||||
/* some (now defunct) events in the queue, defer free() to event_task */
|
||||
|
||||
} else {
|
||||
/* no other references, cleanup now */
|
||||
|
||||
pevent->ev_que->quota -= EVENTENTRIES;
|
||||
freeListFree ( dbevEventSubscriptionFreeList, pevent );
|
||||
}
|
||||
|
||||
pevent->ev_que->quota -= EVENTENTRIES;
|
||||
UNLOCKEVQUE (que);
|
||||
|
||||
UNLOCKEVQUE (pevent->ev_que);
|
||||
if(sync) {
|
||||
/* cycle through worker */
|
||||
struct event_user *evUser = que->evUser;
|
||||
epicsUInt32 curSeq;
|
||||
event_waiter wait;
|
||||
wait.wake = epicsEventCreate(epicsEventEmpty); /* may fail */
|
||||
|
||||
freeListFree ( dbevEventSubscriptionFreeList, pevent );
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
ellAdd(&evUser->waiters, &wait.node);
|
||||
/* grab current cycle counter, then wait for it to change */
|
||||
curSeq = evUser->pflush_seq;
|
||||
do {
|
||||
epicsMutexUnlock( evUser->lock );
|
||||
/* ensure worker will cycle at least once */
|
||||
epicsEventMustTrigger(evUser->ppendsem);
|
||||
|
||||
return;
|
||||
if(wait.wake) {
|
||||
epicsEventMustWait(wait.wake);
|
||||
} else {
|
||||
epicsThreadSleep(0.01); /* ick. but better than cantProceed() */
|
||||
}
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
} while(curSeq == evUser->pflush_seq);
|
||||
ellDelete(&evUser->waiters, &wait.node);
|
||||
/* destroy under lock to ensure epicsEventMustTrigger() has returned */
|
||||
if(wait.wake)
|
||||
epicsEventDestroy(wait.wake);
|
||||
epicsMutexUnlock( evUser->lock );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -934,10 +920,7 @@ void db_post_single_event (dbEventSubscription event)
|
||||
*/
|
||||
static int event_read ( struct event_que *ev_que )
|
||||
{
|
||||
db_field_log *pfl;
|
||||
int notifiedRemaining = 0;
|
||||
void ( *user_sub ) ( void *user_arg, struct dbChannel *chan,
|
||||
int eventsRemaining, db_field_log *pfl );
|
||||
|
||||
/*
|
||||
* evUser ring buffer must be locked for the multiple
|
||||
@@ -958,19 +941,7 @@ static int event_read ( struct event_que *ev_que )
|
||||
while ( ev_que->evque[ev_que->getix] != EVENTQEMPTY ) {
|
||||
struct evSubscrip *pevent = ev_que->evque[ev_que->getix];
|
||||
int eventsRemaining;
|
||||
|
||||
pfl = ev_que->valque[ev_que->getix];
|
||||
if ( pevent == &canceledEvent ) {
|
||||
ev_que->evque[ev_que->getix] = EVENTQEMPTY;
|
||||
if (ev_que->valque[ev_que->getix]) {
|
||||
db_delete_field_log(ev_que->valque[ev_que->getix]);
|
||||
ev_que->valque[ev_que->getix] = NULL;
|
||||
}
|
||||
ev_que->getix = RNGINC ( ev_que->getix );
|
||||
assert ( ev_que->nCanceled > 0 );
|
||||
ev_que->nCanceled--;
|
||||
continue;
|
||||
}
|
||||
db_field_log *pfl = ev_que->valque[ev_que->getix];
|
||||
|
||||
/*
|
||||
* Simple type values queued up for reliable interprocess
|
||||
@@ -980,13 +951,7 @@ static int event_read ( struct event_que *ev_que )
|
||||
|
||||
event_remove ( ev_que, ev_que->getix, EVENTQEMPTY );
|
||||
ev_que->getix = RNGINC ( ev_que->getix );
|
||||
eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY && !ev_que->nCanceled;
|
||||
|
||||
/*
|
||||
* create a local copy of the call back parameters while
|
||||
* we still have the lock
|
||||
*/
|
||||
user_sub = pevent->user_sub;
|
||||
eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY;
|
||||
|
||||
/*
|
||||
* Next event pointer can be used by event tasks to determine
|
||||
@@ -998,14 +963,12 @@ static int event_read ( struct event_que *ev_que )
|
||||
* record lock, and it is calling db_post_events() waiting
|
||||
* for the event queue lock (which this thread now has).
|
||||
*/
|
||||
if ( user_sub ) {
|
||||
/*
|
||||
* This provides a way to test to see if an event is in use
|
||||
* despite the fact that the event queue does not point to
|
||||
* it.
|
||||
*/
|
||||
if ( pevent->user_sub ) {
|
||||
EVENTFUNC* user_sub = pevent->user_sub;
|
||||
pevent->callBackInProgress = TRUE;
|
||||
|
||||
UNLOCKEVQUE (ev_que);
|
||||
|
||||
/* Run post-event-queue filter chain */
|
||||
if (ellCount(&pevent->chan->post_chain)) {
|
||||
pfl = dbChannelRunPostChain(pevent->chan, pfl);
|
||||
@@ -1016,27 +979,15 @@ static int event_read ( struct event_que *ev_que )
|
||||
eventsRemaining, pfl );
|
||||
notifiedRemaining = eventsRemaining;
|
||||
}
|
||||
|
||||
LOCKEVQUE (ev_que);
|
||||
|
||||
/*
|
||||
* check to see if this event has been canceled each
|
||||
* time that the callBackInProgress flag is set to false
|
||||
* while we have the event queue lock, and post the flush
|
||||
* complete sem if there are no longer any events on the
|
||||
* queue
|
||||
*/
|
||||
if ( ev_que->evUser->pSuicideEvent == pevent ) {
|
||||
ev_que->evUser->pSuicideEvent = NULL;
|
||||
}
|
||||
else {
|
||||
if ( pevent->user_sub==NULL && pevent->npend==0u ) {
|
||||
pevent->callBackInProgress = FALSE;
|
||||
epicsEventSignal ( ev_que->evUser->pflush_sem );
|
||||
}
|
||||
else {
|
||||
pevent->callBackInProgress = FALSE;
|
||||
}
|
||||
}
|
||||
pevent->callBackInProgress = FALSE;
|
||||
}
|
||||
/* callback may have called db_cancel_event(), so must check user_sub again */
|
||||
if(!pevent->user_sub && !pevent->npend) {
|
||||
pevent->ev_que->quota -= EVENTENTRIES;
|
||||
freeListFree ( dbevEventSubscriptionFreeList, pevent );
|
||||
}
|
||||
db_delete_field_log(pfl);
|
||||
}
|
||||
@@ -1051,9 +1002,6 @@ static int event_read ( struct event_que *ev_que )
|
||||
return DB_EVENT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* EVENT_TASK()
|
||||
*/
|
||||
static void event_task (void *pParm)
|
||||
{
|
||||
struct event_user * const evUser = (struct event_user *) pParm;
|
||||
@@ -1094,13 +1042,25 @@ static void event_task (void *pParm)
|
||||
}
|
||||
evUser->extraLaborBusy = FALSE;
|
||||
|
||||
for ( ev_que = &evUser->firstque; ev_que;
|
||||
ev_que = ev_que->nextque ) {
|
||||
for ( ev_que = &evUser->firstque; ev_que; ev_que = ev_que->nextque ) {
|
||||
/* unlock during iteration is safe as event_que will not be free'd */
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
event_read (ev_que);
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
pendexit = evUser->pendexit;
|
||||
|
||||
evUser->pflush_seq++;
|
||||
if(ellCount(&evUser->waiters)) {
|
||||
/* hold lock throughout to avoid race between event trigger and destroy */
|
||||
ELLNODE *cur;
|
||||
for(cur = ellFirst(&evUser->waiters); cur; cur = ellNext(cur)) {
|
||||
event_waiter *w = CONTAINER(cur, event_waiter, node);
|
||||
if(w->wake)
|
||||
epicsEventMustTrigger(w->wake);
|
||||
}
|
||||
}
|
||||
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
} while( ! pendexit );
|
||||
|
||||
@@ -72,7 +72,9 @@ static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg dbbArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbbArgs[1] = {&dbbArg0};
|
||||
static const iocshFuncDef dbbFuncDef = {"dbb",1,dbbArgs,
|
||||
"Add breakpoint to a lock set.\n"};
|
||||
"Set Breakpoint on a record\n"
|
||||
"This command spawns one breakpoint continuation task per lockset,"
|
||||
" in which further record execution is run\n"};
|
||||
static void dbbCallFunc(const iocshArgBuf *args) { dbb(args[0].sval);}
|
||||
|
||||
/* dbd */
|
||||
@@ -86,27 +88,36 @@ static void dbdCallFunc(const iocshArgBuf *args) { dbd(args[0].sval);}
|
||||
static const iocshArg dbcArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbcArgs[1] = {&dbcArg0};
|
||||
static const iocshFuncDef dbcFuncDef = {"dbc",1,dbcArgs,
|
||||
"Continue processing in a lock set.\n"};
|
||||
"Continue processing in a lockset until next breakpoint is found.\n"};
|
||||
static void dbcCallFunc(const iocshArgBuf *args) { dbc(args[0].sval);}
|
||||
|
||||
/* dbs */
|
||||
static const iocshArg dbsArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbsArgs[1] = {&dbsArg0};
|
||||
static const iocshFuncDef dbsFuncDef = {"dbs",1,dbsArgs,
|
||||
"Step through record processing.\n"};
|
||||
"Step through record processing within a lockset.\n"
|
||||
"If called without an argument, automatically steps with the last breakpoint.\n"};
|
||||
static void dbsCallFunc(const iocshArgBuf *args) { dbs(args[0].sval);}
|
||||
|
||||
/* dbstat */
|
||||
static const iocshFuncDef dbstatFuncDef = {"dbstat",0,0,
|
||||
"print list of stopped records, and breakpoints set in locksets.\n"};
|
||||
"Print list of suspended records, and breakpoints set in locksets.\n"};
|
||||
static void dbstatCallFunc(const iocshArgBuf *args) { dbstat();}
|
||||
|
||||
/* dbp */
|
||||
static const iocshArg dbpArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg dbpArg1 = { "interest level",iocshArgInt};
|
||||
static const iocshArg * const dbpArgs[2] = {&dbpArg0,&dbpArg1};
|
||||
static const iocshFuncDef dbpFuncDef = {"dbp",2,dbpArgs,
|
||||
"print stopped record.\n"};
|
||||
static const iocshFuncDef dbpFuncDef = {
|
||||
"dbp",2,dbpArgs,
|
||||
"Print Fields of a currently suspended record by a breakpoint.\n"
|
||||
"interest level 0 - Fields of interest to an Application developer and\n"
|
||||
" that can be changed as a result of record processing.\n"
|
||||
" 1 - Fields of interest to an Application developer and\n"
|
||||
" that do not change during record processing.\n"
|
||||
" 2 - Fields of major interest to a System developer.\n"
|
||||
" 3 - Fields of minor interest to a System developer.\n"
|
||||
" 4 - Internal record fields.\n"};
|
||||
static void dbpCallFunc(const iocshArgBuf *args)
|
||||
{ dbp(args[0].sval,args[1].ival);}
|
||||
|
||||
@@ -114,14 +125,17 @@ static void dbpCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg dbapArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbapArgs[1] = {&dbapArg0};
|
||||
static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs,
|
||||
"toggle printing after processing a certain record.\n"};
|
||||
"Auto Print.\n"
|
||||
"Toggle automatic printing after processing a record that has a breakpoint.\n"};
|
||||
static void dbapCallFunc(const iocshArgBuf *args) { dbap(args[0].sval);}
|
||||
|
||||
/* dbsr */
|
||||
static const iocshArg dbsrArg0 = { "interest level",iocshArgInt};
|
||||
static const iocshArg * const dbsrArgs[1] = {&dbsrArg0};
|
||||
static const iocshFuncDef dbsrFuncDef = {"dbsr",1,dbsrArgs,
|
||||
"Database Server Report.\n"};
|
||||
"Database Server Report.\n"
|
||||
"Print current status of server and number of connected clients.\n"
|
||||
"Level 0 prints summary information. Higher levels print more.\n"};
|
||||
static void dbsrCallFunc(const iocshArgBuf *args) { dbsr(args[0].ival);}
|
||||
|
||||
/* dbcar */
|
||||
@@ -131,9 +145,9 @@ static const iocshArg * const dbcarArgs[2] = {&dbcarArg0,&dbcarArg1};
|
||||
static const iocshFuncDef dbcarFuncDef = {"dbcar",2,dbcarArgs,
|
||||
"Database Channel Access Report.\n"
|
||||
"Shows status of Channel Access links (CA_LINK).\n"
|
||||
"interest level 0 - Shows statistics for all links.\n"
|
||||
" 1 - Shows info. of only disconnected links.\n"
|
||||
" 2 - Shows info. for all links.\n"};
|
||||
" level 0 - Shows statistics for all links.\n"
|
||||
" 1 - Shows info. of only disconnected links.\n"
|
||||
" 2 - Shows info. for all links.\n"};
|
||||
static void dbcarCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbcar(args[0].sval,args[1].ival);
|
||||
@@ -144,7 +158,8 @@ static const iocshArg dbjlrArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg dbjlrArg1 = { "level",iocshArgInt};
|
||||
static const iocshArg * const dbjlrArgs[2] = {&dbjlrArg0,&dbjlrArg1};
|
||||
static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs,
|
||||
"Database JSON link Report.\n"};
|
||||
"Database JSON link Report.\n"
|
||||
"List all JSON links in a record. If no record is specified, print for all\n"};
|
||||
static void dbjlrCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbjlr(args[0].sval,args[1].ival);
|
||||
@@ -156,7 +171,9 @@ static const iocshArg dbelArg1 = { "level",iocshArgInt};
|
||||
static const iocshArg * const dbelArgs[2] = {&dbelArg0,&dbelArg1};
|
||||
static const iocshFuncDef dbelFuncDef = {"dbel",2,dbelArgs,
|
||||
"Database event list.\n"
|
||||
"Show information on dbEvent subscriptions.\n"};
|
||||
"Show information on dbEvent subscriptions.\n"
|
||||
"Higher level shows more information (0 - 4)\n"
|
||||
"Example: dbel aitest 2\n"};
|
||||
static void dbelCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbel(args[0].sval, args[1].ival);
|
||||
@@ -166,7 +183,10 @@ static void dbelCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg dbaArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbaArgs[1] = {&dbaArg0};
|
||||
static const iocshFuncDef dbaFuncDef = {"dba",1,dbaArgs,
|
||||
"dbAddr info.\n"};
|
||||
"Database Address.\n"
|
||||
"Print information in the dbAddr structure for a specific field.\n"
|
||||
"If no field is specified, VAL is assumed.\n\n"
|
||||
"Example: dba(\"aitest.HIGH\")\n"};
|
||||
static void dbaCallFunc(const iocshArgBuf *args) { dba(args[0].sval);}
|
||||
|
||||
/* dbl */
|
||||
@@ -176,7 +196,12 @@ static const iocshArg * const dblArgs[] = {&dblArg0,&dblArg1};
|
||||
static const iocshFuncDef dblFuncDef = {"dbl",2,dblArgs,
|
||||
"Database list.\n"
|
||||
"List record/field names.\n"
|
||||
"With no arguments, lists all record names.\n"};
|
||||
"With no arguments, lists all record names.\n"
|
||||
"If record type is given, then only the names of records maching the type are printed\n"
|
||||
"If a field list is given, then their values are also printed\n\n"
|
||||
"Example: dbl(\"\")\n"
|
||||
" dbl(\"ai\")\n"
|
||||
" dbl(\"ai\",\"HIGH LOW VAL PREC\")\n"};
|
||||
static void dblCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbl(args[0].sval,args[1].sval);
|
||||
@@ -186,28 +211,35 @@ static void dblCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg dbnrArg0 = { "verbose",iocshArgInt};
|
||||
static const iocshArg * const dbnrArgs[1] = {&dbnrArg0};
|
||||
static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs,
|
||||
"List stats on record alias()s.\n"};
|
||||
"List number of records and aliases by type.\n"
|
||||
"If verbose, list all record types regardless of being instanced\n"};
|
||||
static void dbnrCallFunc(const iocshArgBuf *args) { dbnr(args[0].ival);}
|
||||
|
||||
/* dbli */
|
||||
static const iocshArg dbliArg0 = { "pattern",iocshArgString};
|
||||
static const iocshArg * const dbliArgs[1] = {&dbliArg0};
|
||||
static const iocshFuncDef dbliFuncDef = {"dbli",1,dbliArgs,
|
||||
"List info() tags with names matching pattern.\n"};
|
||||
"List info() tags with names matching pattern.\n\n"
|
||||
"Example: dbli(\"autosave*\")\n"};
|
||||
static void dbliCallFunc(const iocshArgBuf *args) { dbli(args[0].sval);}
|
||||
|
||||
/* dbla */
|
||||
static const iocshArg dblaArg0 = { "pattern",iocshArgStringRecord};
|
||||
static const iocshArg * const dblaArgs[1] = {&dblaArg0};
|
||||
static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs,
|
||||
"List record alias()s by alias name pattern.\n"};
|
||||
"List record alias()s by alias name pattern.\n\n"
|
||||
"Example: dbla(\"alia*\")\n"};
|
||||
static void dblaCallFunc(const iocshArgBuf *args) { dbla(args[0].sval);}
|
||||
|
||||
/* dbgrep */
|
||||
static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord};
|
||||
static const iocshArg * const dbgrepArgs[1] = {&dbgrepArg0};
|
||||
static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs,
|
||||
"List record names matching pattern.\n"};
|
||||
"List record names matching pattern.\n"
|
||||
"The pattern can contain any characters that are legal in record names as well as:\n"
|
||||
" - \"?\", which matches 0 or one characters.\n"
|
||||
" - \"*\", which matches 0 or more characters.\n\n"
|
||||
"Example: dbgrep(\"*gpibAi*\")\n"};
|
||||
static void dbgrepCallFunc(const iocshArgBuf *args) { dbgrep(args[0].sval);}
|
||||
|
||||
/* dbgf */
|
||||
@@ -215,7 +247,9 @@ static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbgfArgs[1] = {&dbgfArg0};
|
||||
static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs,
|
||||
"Database Get Field.\n"
|
||||
"Print current value of record field.\n"};
|
||||
"Print current value of record field.\n"
|
||||
"If no field name is specified, VAL is assumed.\n\n"
|
||||
"Example: dbgf(\"aitest.VAL\")\n"};
|
||||
static void dbgfCallFunc(const iocshArgBuf *args) { dbgf(args[0].sval);}
|
||||
|
||||
/* dbpf */
|
||||
@@ -224,7 +258,8 @@ static const iocshArg dbpfArg1 = { "value",iocshArgString};
|
||||
static const iocshArg * const dbpfArgs[2] = {&dbpfArg0,&dbpfArg1};
|
||||
static const iocshFuncDef dbpfFuncDef = {"dbpf",2,dbpfArgs,
|
||||
"Database Put Field.\n"
|
||||
"Change value of record field.\n"};
|
||||
"Change value of record field and read it back with dbgf.\n"
|
||||
"If no field is specified, VAL is assumed\n"};
|
||||
static void dbpfCallFunc(const iocshArgBuf *args)
|
||||
{ dbpf(args[0].sval,args[1].sval);}
|
||||
|
||||
@@ -232,9 +267,17 @@ static void dbpfCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg dbprArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg dbprArg1 = { "interest level",iocshArgInt};
|
||||
static const iocshArg * const dbprArgs[2] = {&dbprArg0,&dbprArg1};
|
||||
static const iocshFuncDef dbprFuncDef = {"dbpr",2,dbprArgs,
|
||||
"Database Print Record.\n"
|
||||
"Print values of record fields.\n"};
|
||||
static const iocshFuncDef dbprFuncDef = {
|
||||
"dbpr",2,dbprArgs,
|
||||
"Database Print Record.\n"
|
||||
"Print values of record fields for given interest level.\n"
|
||||
"interest level 0 - Fields that can be changed as a result of record processing.\n"
|
||||
" 1 - Fields that do not change during record processing.\n"
|
||||
" 2 - Fields of major interest to a System developer.\n"
|
||||
" 3 - Fields of minor interest to a System developer.\n"
|
||||
" 4 - Internal record fields.\n\n"
|
||||
"Example: dbpr aitest 3\n"
|
||||
};
|
||||
static void dbprCallFunc(const iocshArgBuf *args)
|
||||
{ dbpr(args[0].sval,args[1].ival);}
|
||||
|
||||
@@ -250,7 +293,9 @@ static const iocshArg dbtgfArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const dbtgfArgs[1] = {&dbtgfArg0};
|
||||
static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs,
|
||||
"Database Test Get Field.\n"
|
||||
"Get field with different DBR_* types\n"};
|
||||
"Get and print the specified field with all possible DBR_* types\n"
|
||||
"Example: dbtgf aitest\n"
|
||||
"Example: dbtgf aitest.VAL\n"};
|
||||
static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);}
|
||||
|
||||
/* dbtpf */
|
||||
@@ -258,7 +303,10 @@ static const iocshArg dbtpfArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg dbtpfArg1 = { "value",iocshArgString};
|
||||
static const iocshArg * const dbtpfArgs[2] = {&dbtpfArg0,&dbtpfArg1};
|
||||
static const iocshFuncDef dbtpfFuncDef = {"dbtpf",2,dbtpfArgs,
|
||||
"Database Test Put Field.\n"};
|
||||
"Database Test Put Field.\n"
|
||||
"Put the given value to the given PV, then get the value\n"
|
||||
"for all possible DBR_* types\n\n"
|
||||
"Example: dbtpf aitest 5.0\n"};
|
||||
static void dbtpfCallFunc(const iocshArgBuf *args)
|
||||
{ dbtpf(args[0].sval,args[1].sval);}
|
||||
|
||||
@@ -273,14 +321,21 @@ static void dbiorCallFunc(const iocshArgBuf *args)
|
||||
|
||||
/* dbhcr */
|
||||
static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0,
|
||||
"Database Report Device Config.\n"};
|
||||
"Database Hardware Configuration Report.\n"
|
||||
"Produce a report of all hardware links.\n"
|
||||
"The produced report will probably not be in the sort order desired.\n"
|
||||
"Use the UNIX sort command:\n"
|
||||
"dbhcr > report\n"
|
||||
"sort report > report.sorted\n"};
|
||||
static void dbhcrCallFunc(const iocshArgBuf *args) { dbhcr();}
|
||||
|
||||
/* gft */
|
||||
static const iocshArg gftArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg * const gftArgs[1] = {&gftArg0};
|
||||
static const iocshFuncDef gftFuncDef = {"gft",1,gftArgs,
|
||||
"Report dbChannel info and value.\n"};
|
||||
"Report dbChannel info and value.\n"
|
||||
"Example: gft aitest\n"
|
||||
"Example: gft aitest.VAL\n"};
|
||||
static void gftCallFunc(const iocshArgBuf *args) { gft(args[0].sval);}
|
||||
|
||||
/* pft */
|
||||
@@ -288,7 +343,8 @@ static const iocshArg pftArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg pftArg1 = { "value",iocshArgString};
|
||||
static const iocshArg * const pftArgs[2] = {&pftArg0,&pftArg1};
|
||||
static const iocshFuncDef pftFuncDef = {"pft",2,pftArgs,
|
||||
"dbChannel put value.\n"};
|
||||
"dbChannel put value.\n"
|
||||
"Example: pft aitest 5.0\n"};
|
||||
static void pftCallFunc(const iocshArgBuf *args)
|
||||
{ pft(args[0].sval,args[1].sval);}
|
||||
|
||||
@@ -297,9 +353,11 @@ static const iocshArg dbtpnArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg dbtpnArg1 = { "value",iocshArgString};
|
||||
static const iocshArg * const dbtpnArgs[2] = {&dbtpnArg0,&dbtpnArg1};
|
||||
static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs,
|
||||
"Database Put Notify\n"
|
||||
"Database Test Process Notify\n"
|
||||
"Without value, begin async. processing and get\n"
|
||||
"With value, begin put, process, and get\n"};
|
||||
"With value, begin put, process, and get\n"
|
||||
"Example: dbtpn aitest\n"
|
||||
"Example: dbtpn aitest 5.0\n"};
|
||||
static void dbtpnCallFunc(const iocshArgBuf *args)
|
||||
{ dbtpn(args[0].sval,args[1].sval);}
|
||||
|
||||
@@ -314,9 +372,8 @@ 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,
|
||||
"Set/Create record attribute.\n"};
|
||||
static const iocshFuncDef dbPutAttrFuncDef = {"dbPutAttribute",3,dbPutAttrArgs,
|
||||
"Set/Create record attribute.\n"};
|
||||
static void dbPutAttrCallFunc(const iocshArgBuf *args)
|
||||
{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);}
|
||||
|
||||
@@ -325,7 +382,8 @@ static const iocshArg tpnArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg tpnArg1 = { "value",iocshArgString};
|
||||
static const iocshArg * const tpnArgs[2] = {&tpnArg0,&tpnArg1};
|
||||
static const iocshFuncDef tpnFuncDef = {"tpn",2,tpnArgs,
|
||||
"Begin async. process and get.\n"};
|
||||
"Test Process Notify.\n\n"
|
||||
"Example: tpn aitest 5.0\n"};
|
||||
static void tpnCallFunc(const iocshArgBuf *args)
|
||||
{ tpn(args[0].sval,args[1].sval);}
|
||||
|
||||
@@ -334,16 +392,25 @@ static const iocshArg dblsrArg0 = { "record name",iocshArgStringRecord};
|
||||
static const iocshArg dblsrArg1 = { "interest level",iocshArgInt};
|
||||
static const iocshArg * const dblsrArgs[2] = {&dblsrArg0,&dblsrArg1};
|
||||
static const iocshFuncDef dblsrFuncDef = {"dblsr",2,dblsrArgs,
|
||||
"Database Lockset report.\n"};
|
||||
"Database Lockset report.\n"
|
||||
"Generate a report showing the lock set to which each record belongs.\n"
|
||||
"interest level 0 - Show lock set information only.\n"
|
||||
" 1 - Show each record in the lock set.\n"
|
||||
" 2 - Show each record and all database links in the lock set.\n\n"
|
||||
"Example: dblsr aitest 2\n"};
|
||||
static void dblsrCallFunc(const iocshArgBuf *args)
|
||||
{ dblsr(args[0].sval,args[1].ival);}
|
||||
|
||||
/* dbLockShowLocked */
|
||||
static const iocshArg dbLockShowLockedArg0 = { "interest level",iocshArgInt};
|
||||
static const iocshArg * const dbLockShowLockedArgs[1] = {&dbLockShowLockedArg0};
|
||||
static const iocshFuncDef dbLockShowLockedFuncDef =
|
||||
{"dbLockShowLocked",1,dbLockShowLockedArgs,
|
||||
"Show Locksets which are currently locked.\n"};
|
||||
static const iocshFuncDef dbLockShowLockedFuncDef = {
|
||||
"dbLockShowLocked",1,dbLockShowLockedArgs,
|
||||
"Show Locksets which are currently locked.\n"
|
||||
"interest level argument is passed to epicsMutexShow to adjust reported\n"
|
||||
"information.\n\n"
|
||||
"Example: dbLockShowLocked 0\n"
|
||||
};
|
||||
static void dbLockShowLockedCallFunc(const iocshArgBuf *args)
|
||||
{ dbLockShowLocked(args[0].ival);}
|
||||
|
||||
@@ -351,10 +418,9 @@ static void dbLockShowLockedCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg scanOnceSetQueueSizeArg0 = { "size",iocshArgInt};
|
||||
static const iocshArg * const scanOnceSetQueueSizeArgs[1] =
|
||||
{&scanOnceSetQueueSizeArg0};
|
||||
static const iocshFuncDef scanOnceSetQueueSizeFuncDef =
|
||||
{"scanOnceSetQueueSize",1,scanOnceSetQueueSizeArgs,
|
||||
"Change size of Scan once queue.\n"
|
||||
"Must be called before iocInit().\n"};
|
||||
static const iocshFuncDef scanOnceSetQueueSizeFuncDef = {"scanOnceSetQueueSize",1,scanOnceSetQueueSizeArgs,
|
||||
"Change size of Scan once queue.\n"
|
||||
"Must be called before iocInit().\n"};
|
||||
static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
scanOnceSetQueueSize(args[0].ival);
|
||||
@@ -364,9 +430,8 @@ static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg scanOnceQueueShowArg0 = { "reset",iocshArgInt};
|
||||
static const iocshArg * const scanOnceQueueShowArgs[1] =
|
||||
{&scanOnceQueueShowArg0};
|
||||
static const iocshFuncDef scanOnceQueueShowFuncDef =
|
||||
{"scanOnceQueueShow",1,scanOnceQueueShowArgs,
|
||||
"Show details and statitics of scan once queue processing.\n"};
|
||||
static const iocshFuncDef scanOnceQueueShowFuncDef = {"scanOnceQueueShow",1,scanOnceQueueShowArgs,
|
||||
"Show details and statitics of scan once queue processing.\n"};
|
||||
static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
scanOnceQueueShow(args[0].ival);
|
||||
@@ -376,7 +441,8 @@ static void scanOnceQueueShowCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
|
||||
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
|
||||
static const iocshFuncDef scanpplFuncDef = {"scanppl",1,scanpplArgs,
|
||||
"print periodic scan lists.\n"};
|
||||
"Print info for records with periodic scan.\n"
|
||||
"If rate == 0.0, all periods are shown.\n"};
|
||||
static void scanpplCallFunc(const iocshArgBuf *args)
|
||||
{ scanppl(args[0].dval);}
|
||||
|
||||
@@ -408,10 +474,9 @@ static void scanpiolCallFunc(const iocshArgBuf *args) { scanpiol();}
|
||||
static const iocshArg callbackSetQueueSizeArg0 = { "bufsize",iocshArgInt};
|
||||
static const iocshArg * const callbackSetQueueSizeArgs[1] =
|
||||
{&callbackSetQueueSizeArg0};
|
||||
static const iocshFuncDef callbackSetQueueSizeFuncDef =
|
||||
{"callbackSetQueueSize",1,callbackSetQueueSizeArgs,
|
||||
"Change depth of queue for callback workers.\n"
|
||||
"Must be called before iocInit().\n"};
|
||||
static const iocshFuncDef callbackSetQueueSizeFuncDef = {"callbackSetQueueSize",1,callbackSetQueueSizeArgs,
|
||||
"Change depth of queue for callback workers.\n"
|
||||
"Must be called before iocInit().\n"};
|
||||
static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
callbackSetQueueSize(args[0].ival);
|
||||
@@ -421,9 +486,8 @@ static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg callbackQueueShowArg0 = { "reset", iocshArgInt};
|
||||
static const iocshArg * const callbackQueueShowArgs[1] =
|
||||
{&callbackQueueShowArg0};
|
||||
static const iocshFuncDef callbackQueueShowFuncDef =
|
||||
{"callbackQueueShow",1,callbackQueueShowArgs,
|
||||
"Show status of callback thread processing queue.\n"};
|
||||
static const iocshFuncDef callbackQueueShowFuncDef = {"callbackQueueShow",1,callbackQueueShowArgs,
|
||||
"Show status of callback thread processing queue.\n"};
|
||||
static void callbackQueueShowCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
callbackQueueShow(args[0].ival);
|
||||
@@ -434,11 +498,10 @@ static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgI
|
||||
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
|
||||
static const iocshArg * const callbackParallelThreadsArgs[2] =
|
||||
{&callbackParallelThreadsArg0,&callbackParallelThreadsArg1};
|
||||
static const iocshFuncDef callbackParallelThreadsFuncDef =
|
||||
{"callbackParallelThreads",2,callbackParallelThreadsArgs,
|
||||
"Configure multiple workers for a given callback queue priority level.\n"
|
||||
"priority may be omitted or \"*\" to act on all priorities\n"
|
||||
"or one of LOW, MEDIUM, or HIGH.\n"};
|
||||
static const iocshFuncDef callbackParallelThreadsFuncDef = {"callbackParallelThreads",2,callbackParallelThreadsArgs,
|
||||
"Configure multiple workers for a given callback queue priority level.\n"
|
||||
"priority may be omitted or \"*\" to act on all priorities\n"
|
||||
"or one of LOW, MEDIUM, or HIGH.\n"};
|
||||
static void callbackParallelThreadsCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
callbackParallelThreads(args[0].ival, args[1].sval);
|
||||
@@ -447,8 +510,8 @@ static void callbackParallelThreadsCallFunc(const iocshArgBuf *args)
|
||||
/* dbStateCreate */
|
||||
static const iocshArg dbStateArgName = { "name", iocshArgString };
|
||||
static const iocshArg * const dbStateCreateArgs[] = { &dbStateArgName };
|
||||
static const iocshFuncDef dbStateCreateFuncDef = { "dbStateCreate", 1, dbStateCreateArgs,
|
||||
"Allocate new state name for \"state\" filter.\n"};
|
||||
static const iocshFuncDef dbStateCreateFuncDef = {"dbStateCreate", 1, dbStateCreateArgs,
|
||||
"Allocate new state name for \"state\" filter.\n"};
|
||||
static void dbStateCreateCallFunc (const iocshArgBuf *args)
|
||||
{
|
||||
dbStateCreate(args[0].sval);
|
||||
@@ -456,8 +519,8 @@ static void dbStateCreateCallFunc (const iocshArgBuf *args)
|
||||
|
||||
/* dbStateSet */
|
||||
static const iocshArg * const dbStateSetArgs[] = { &dbStateArgName };
|
||||
static const iocshFuncDef dbStateSetFuncDef = { "dbStateSet", 1, dbStateSetArgs,
|
||||
"Change state to set for \"state\" filter.\n"};
|
||||
static const iocshFuncDef dbStateSetFuncDef = {"dbStateSet", 1, dbStateSetArgs,
|
||||
"Change state to set for \"state\" filter.\n"};
|
||||
static void dbStateSetCallFunc (const iocshArgBuf *args)
|
||||
{
|
||||
dbStateId sid = dbStateFind(args[0].sval);
|
||||
@@ -468,8 +531,8 @@ static void dbStateSetCallFunc (const iocshArgBuf *args)
|
||||
|
||||
/* dbStateClear */
|
||||
static const iocshArg * const dbStateClearArgs[] = { &dbStateArgName };
|
||||
static const iocshFuncDef dbStateClearFuncDef = { "dbStateClear", 1, dbStateClearArgs,
|
||||
"Change state to clear for \"state\" filter.\n" };
|
||||
static const iocshFuncDef dbStateClearFuncDef = {"dbStateClear", 1, dbStateClearArgs,
|
||||
"Change state to clear for \"state\" filter.\n"};
|
||||
static void dbStateClearCallFunc (const iocshArgBuf *args)
|
||||
{
|
||||
dbStateId sid = dbStateFind(args[0].sval);
|
||||
@@ -481,8 +544,8 @@ static void dbStateClearCallFunc (const iocshArgBuf *args)
|
||||
/* dbStateShow */
|
||||
static const iocshArg dbStateShowArg1 = { "level", iocshArgInt };
|
||||
static const iocshArg * const dbStateShowArgs[] = { &dbStateArgName, &dbStateShowArg1 };
|
||||
static const iocshFuncDef dbStateShowFuncDef = { "dbStateShow", 2, dbStateShowArgs,
|
||||
"Show set/clear status of named state. (cf. \"state\" filter)\n" };
|
||||
static const iocshFuncDef dbStateShowFuncDef = {"dbStateShow", 2, dbStateShowArgs,
|
||||
"Show set/clear status of named state. (cf. \"state\" filter)\n"};
|
||||
static void dbStateShowCallFunc (const iocshArgBuf *args)
|
||||
{
|
||||
dbStateId sid = dbStateFind(args[0].sval);
|
||||
@@ -494,8 +557,8 @@ static void dbStateShowCallFunc (const iocshArgBuf *args)
|
||||
/* dbStateShowAll */
|
||||
static const iocshArg dbStateShowAllArg0 = { "level", iocshArgInt };
|
||||
static const iocshArg * const dbStateShowAllArgs[] = { &dbStateShowAllArg0 };
|
||||
static const iocshFuncDef dbStateShowAllFuncDef = { "dbStateShowAll", 1, dbStateShowAllArgs,
|
||||
"Show set/clear status of all named states. (cf. \"state\" filter)\n" };
|
||||
static const iocshFuncDef dbStateShowAllFuncDef = {"dbStateShowAll", 1, dbStateShowAllArgs,
|
||||
"Show set/clear status of all named states. (cf. \"state\" filter)\n"};
|
||||
static void dbStateShowAllCallFunc (const iocshArgBuf *args)
|
||||
{
|
||||
dbStateShowAll(args[0].ival);
|
||||
|
||||
@@ -359,6 +359,8 @@ typedef struct lset {
|
||||
* @param plink the link
|
||||
* @param rtn routine to execute
|
||||
* @returns status value
|
||||
*
|
||||
* @since 3.16.1
|
||||
*/
|
||||
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
|
||||
|
||||
|
||||
@@ -869,7 +869,7 @@ nosplit:
|
||||
}
|
||||
}
|
||||
|
||||
static char *msstring[4]={"NMS","MS","MSI","MSS"};
|
||||
static const char *msstring[4]={"NMS","MS","MSI","MSS"};
|
||||
|
||||
long dblsr(char *recordname,int level)
|
||||
{
|
||||
|
||||
@@ -24,18 +24,64 @@ extern "C" {
|
||||
|
||||
struct dbCommon;
|
||||
struct dbBase;
|
||||
/** @brief Lock multiple records.
|
||||
*
|
||||
* A dbLocker allows a caller to simultaneously lock multiple records.
|
||||
* The list of records is provided to dbLockerAlloc().
|
||||
* And the resulting dbLocker can be locked/unlocked repeatedly.
|
||||
*
|
||||
* Each thread can only lock one dbLocker at a time.
|
||||
* While locked, dbScanLock() may be called only on those records
|
||||
* included in the dbLocker.
|
||||
*
|
||||
* @since 3.16.0.1
|
||||
*/
|
||||
struct dbLocker;
|
||||
typedef struct dbLocker dbLocker;
|
||||
|
||||
/** @brief Lock a record for modification.
|
||||
*
|
||||
* While locked, caller may access record using eg. dbGet() or dbPut(),
|
||||
* but not dbGetField() or dbPutField().
|
||||
* The caller must later call dbScanUnlock().
|
||||
* dbScanLock() may be called again as the record lock behaves as a recursive mutex.
|
||||
*/
|
||||
DBCORE_API void dbScanLock(struct dbCommon *precord);
|
||||
/** @brief Unlock a record.
|
||||
*
|
||||
* Reverse the action of dbScanLock()
|
||||
*/
|
||||
DBCORE_API void dbScanUnlock(struct dbCommon *precord);
|
||||
|
||||
/** @brief Prepare to lock a set of records.
|
||||
* @param precs Array of nrecs dbCommon pointers.
|
||||
* @param nrecs Length of precs array
|
||||
* @param flags Set to 0
|
||||
* @return NULL on error
|
||||
* @since 3.16.0.1
|
||||
*/
|
||||
DBCORE_API dbLocker *dbLockerAlloc(struct dbCommon * const *precs,
|
||||
size_t nrecs,
|
||||
unsigned int flags);
|
||||
|
||||
DBCORE_API void dbLockerFree(dbLocker *);
|
||||
/** @brief Free dbLocker allocated by dbLockerAlloc()
|
||||
* @param plocker Must not be NULL
|
||||
* @since 3.16.0.1
|
||||
*/
|
||||
DBCORE_API void dbLockerFree(dbLocker *plocker);
|
||||
|
||||
/** @brief Lock all records of dbLocker
|
||||
*
|
||||
* While locked, caller may access any associated record passed to dbLockerAlloc() .
|
||||
* dbScanLockMany() may not be called again (multi-lock is not recursive).
|
||||
* dbScanLock()/dbScanUnlock() may be called on individual record.
|
||||
* The caller must later call dbScanUnlockMany().
|
||||
* @since 3.16.0.1
|
||||
*/
|
||||
DBCORE_API void dbScanLockMany(dbLocker*);
|
||||
/** @brief Unlock all records of dbLocker
|
||||
* @since 3.16.0.1
|
||||
*/
|
||||
DBCORE_API void dbScanUnlockMany(dbLocker*);
|
||||
|
||||
DBCORE_API unsigned long dbLockGetLockId(
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define DBLOCKPVT_H
|
||||
|
||||
#include "dbLock.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
/* Define to enable additional error checking */
|
||||
|
||||
@@ -506,62 +506,62 @@ long dbtgf(const char *pname)
|
||||
ret_options=0;
|
||||
|
||||
dbr_type = DBR_STRING;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/MAX_STRING_SIZE));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_CHAR;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt8))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_UCHAR;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt8))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_SHORT;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt16))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_USHORT;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt16))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_LONG;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt32))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_ULONG;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt32))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_INT64;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsInt64))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_UINT64;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsUInt64))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_FLOAT;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsFloat32))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_DOUBLE;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsFloat64))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_ENUM;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));
|
||||
no_elements = MIN(addr.no_elements,(sizeof(buffer)/(sizeof(epicsEnum16))));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ void testdbPrepare(void)
|
||||
{
|
||||
if(!testEvtLock)
|
||||
testEvtLock = epicsMutexMustCreate();
|
||||
initHookAnnounce(initHookAfterPrepareDatabase);
|
||||
}
|
||||
|
||||
void testdbReadDatabase(const char* file,
|
||||
@@ -94,6 +95,7 @@ void testIocShutdownOk(void)
|
||||
|
||||
void testdbCleanup(void)
|
||||
{
|
||||
initHookAnnounce(initHookBeforeCleanupDatabase);
|
||||
dbFreeBase(pdbbase);
|
||||
db_cleanup_events();
|
||||
initHookFree();
|
||||
|
||||
@@ -118,6 +118,10 @@ typedef struct dbRecordNode {
|
||||
char *recordname;
|
||||
ELLLIST infoList; /*LIST head of info nodes*/
|
||||
int flags;
|
||||
/** Parse order of this record()
|
||||
* @since 7.0.8.1
|
||||
*/
|
||||
unsigned order;
|
||||
struct dbRecordNode *aliasedRecnode; /* NULL unless flags|DBRN_FLAGS_ISALIAS */
|
||||
}dbRecordNode;
|
||||
|
||||
@@ -184,5 +188,9 @@ typedef struct dbBase {
|
||||
struct gphPvt *pgpHash;
|
||||
short ignoreMissingMenus;
|
||||
short loadCdefs;
|
||||
/** Total number of records.
|
||||
* @since 7.0.8.1
|
||||
*/
|
||||
unsigned no_records;
|
||||
}dbBase;
|
||||
#endif
|
||||
|
||||
@@ -247,23 +247,23 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
}
|
||||
my_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
freeListInitPvt(&freeListPvt,sizeof(tempListNode),100);
|
||||
if(substitutions) {
|
||||
if(macCreateHandle(&macHandle,NULL)) {
|
||||
epicsPrintf("macCreateHandle error\n");
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
macParseDefns(macHandle,(char *)substitutions,&macPairs);
|
||||
if(macPairs ==NULL) {
|
||||
macDeleteHandle(macHandle);
|
||||
macHandle = NULL;
|
||||
} else {
|
||||
macInstallMacros(macHandle,macPairs);
|
||||
free((void *)macPairs);
|
||||
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
}
|
||||
macSuppressWarning(macHandle,dbQuietMacroWarnings);
|
||||
if (substitutions == NULL)
|
||||
substitutions = "";
|
||||
if(macCreateHandle(&macHandle,NULL)) {
|
||||
epicsPrintf("macCreateHandle error\n");
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
macParseDefns(macHandle,substitutions,&macPairs);
|
||||
if(macPairs == NULL) {
|
||||
macDeleteHandle(macHandle);
|
||||
macHandle = NULL;
|
||||
} else {
|
||||
macInstallMacros(macHandle,macPairs);
|
||||
free(macPairs);
|
||||
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
}
|
||||
macSuppressWarning(macHandle,dbQuietMacroWarnings);
|
||||
pinputFile = dbCalloc(1,sizeof(inputFile));
|
||||
if (filename) {
|
||||
pinputFile->filename = macEnvExpand(filename);
|
||||
@@ -1068,7 +1068,7 @@ int dbRecordNameValidate(const char *name)
|
||||
const char *pos = name;
|
||||
|
||||
if (!*name) {
|
||||
yyerrorAbort("Error: Record/Alias name can't be empty");
|
||||
yyerrorAbort(ERL_ERROR ": Record/Alias name can't be empty");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1086,7 +1086,7 @@ int dbRecordNameValidate(const char *name)
|
||||
name, c);
|
||||
|
||||
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
|
||||
epicsPrintf("Error: Bad character '%c' in Record/Alias name \"%s\"\n",
|
||||
epicsPrintf(ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
|
||||
c, name);
|
||||
yyerrorAbort(NULL);
|
||||
return 1;
|
||||
@@ -1110,14 +1110,10 @@ static void dbRecordHead(char *recordType, char *name, int visible)
|
||||
allocTemp(pdbentry);
|
||||
|
||||
if (recordType[0] == '*' && recordType[1] == 0) {
|
||||
if (dbRecordsOnceOnly)
|
||||
epicsPrintf("Record-type \"*\" not valid with dbRecordsOnceOnly\n");
|
||||
else {
|
||||
status = dbFindRecord(pdbentry, name);
|
||||
if (status == 0)
|
||||
return; /* done */
|
||||
epicsPrintf("Record \"%s\" not found\n", name);
|
||||
}
|
||||
status = dbFindRecord(pdbentry, name);
|
||||
if (status == 0)
|
||||
return; /* done */
|
||||
epicsPrintf(ERL_ERROR ": Record \"%s\" not found\n", name);
|
||||
yyerror(NULL);
|
||||
duplicate = TRUE;
|
||||
return;
|
||||
@@ -1136,15 +1132,16 @@ static void dbRecordHead(char *recordType, char *name, int visible)
|
||||
status = dbCreateRecord(pdbentry,name);
|
||||
if (status == S_dbLib_recExists) {
|
||||
if (strcmp(recordType, dbGetRecordTypeName(pdbentry)) != 0) {
|
||||
epicsPrintf("Record \"%s\" of type \"%s\" redefined with new type "
|
||||
epicsPrintf(ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
|
||||
"\"%s\"\n", name, dbGetRecordTypeName(pdbentry), recordType);
|
||||
yyerror(NULL);
|
||||
duplicate = TRUE;
|
||||
return;
|
||||
}
|
||||
else if (dbRecordsOnceOnly) {
|
||||
epicsPrintf("Record \"%s\" already defined (dbRecordsOnceOnly is "
|
||||
"set)\n", name);
|
||||
epicsPrintf(ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
|
||||
"Used record type \"*\" to append.\n",
|
||||
name);
|
||||
yyerror(NULL);
|
||||
duplicate = TRUE;
|
||||
}
|
||||
@@ -1170,8 +1167,28 @@ static void dbRecordField(char *name,char *value)
|
||||
pdbentry = ptempListNode->item;
|
||||
status = dbFindField(pdbentry,name);
|
||||
if (status) {
|
||||
epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
|
||||
dbGetRecordName(pdbentry), name);
|
||||
epicsPrintf("%s Record \"%s\" does not have a field \"%s\"\n",
|
||||
dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name);
|
||||
if(dbGetRecordName(pdbentry)) {
|
||||
DBENTRY temp;
|
||||
double bestSim = -1.0;
|
||||
const dbFldDes *bestFld = NULL;
|
||||
dbCopyEntryContents(pdbentry, &temp);
|
||||
for(status = dbFirstField(&temp, 0); !status; status = dbNextField(&temp, 0)) {
|
||||
double sim = epicsStrSimilarity(name, temp.pflddes->name);
|
||||
if(!bestFld || sim > bestSim) {
|
||||
bestSim = sim;
|
||||
bestFld = temp.pflddes;
|
||||
}
|
||||
}
|
||||
dbFinishEntry(&temp);
|
||||
if(bestSim>0.0) {
|
||||
epicsPrintf(" Did you mean \"%s\"?", bestFld->name);
|
||||
if(bestFld->prompt)
|
||||
epicsPrintf(" (%s)", bestFld->prompt);
|
||||
epicsPrintf("\n");
|
||||
}
|
||||
}
|
||||
yyerror(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "iocsh.h"
|
||||
#include "errSymTbl.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#include "dbStaticIocRegister.h"
|
||||
#include "dbStaticLib.h"
|
||||
@@ -24,7 +25,8 @@ static const iocshArg argRecType = { "recordTypeName", iocshArgString};
|
||||
/* dbDumpPath */
|
||||
static const iocshArg * const dbDumpPathArgs[] = {&argPdbbase};
|
||||
static const iocshFuncDef dbDumpPathFuncDef = {"dbDumpPath",1,dbDumpPathArgs,
|
||||
"Dump .db/.dbd file search path.\n"};
|
||||
"Dump .db/.dbd file search path.\n"
|
||||
"Example: dbDumpPath pdbbase\n"};
|
||||
static void dbDumpPathCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbDumpPath(*iocshPpdbbase);
|
||||
@@ -99,7 +101,8 @@ static void dbDumpDeviceCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg * const dbDumpDriverArgs[] = { &argPdbbase};
|
||||
static const iocshFuncDef dbDumpDriverFuncDef = {"dbDumpDriver",1,dbDumpDriverArgs,
|
||||
"Dump device support information.\n"
|
||||
"Example: dbDumpDriver pdbbase\n"};
|
||||
"Example: dbDumpDriver pdbbase\n"
|
||||
"If the last argument(s) are missing, dump all device support information.\n",};
|
||||
static void dbDumpDriverCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbDumpDriver(*iocshPpdbbase);
|
||||
@@ -124,7 +127,8 @@ static const iocshArg * const dbDumpRegistrarArgs[] = { &argPdbbase};
|
||||
static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs,
|
||||
"Dump list of registered functions including ones for subroutine records,\n"
|
||||
"and ones that can be invoked from iocsh.\n"
|
||||
"Example: dbDumpRegistrar pdbbase\n"};
|
||||
"Example: dbDumpRegistrar pdbbase\n"
|
||||
"If last argument(s) are missing, dump all registered functions\n"};
|
||||
static void dbDumpRegistrarCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbDumpRegistrar(*iocshPpdbbase);
|
||||
@@ -134,7 +138,8 @@ static void dbDumpRegistrarCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg * const dbDumpFunctionArgs[] = { &argPdbbase};
|
||||
static const iocshFuncDef dbDumpFunctionFuncDef = {"dbDumpFunction",1,dbDumpFunctionArgs,
|
||||
"Dump list of registered subroutine functions.\n"
|
||||
"Example: dbDumpFunction pddbase\n"};
|
||||
"Example: dbDumpFunction pddbase\n"
|
||||
"If last argument(s) are missing, dump all registered subroutine functions\n"};
|
||||
static void dbDumpFunctionCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbDumpFunction(*iocshPpdbbase);
|
||||
@@ -144,7 +149,8 @@ static void dbDumpFunctionCallFunc(const iocshArgBuf *args)
|
||||
static const iocshArg * const dbDumpVariableArgs[] = { &argPdbbase};
|
||||
static const iocshFuncDef dbDumpVariableFuncDef = {"dbDumpVariable",1,dbDumpVariableArgs,
|
||||
"Dump list of variables used in the database.\n"
|
||||
"Example: dbDumpVariable pddbase\n"};
|
||||
"Example: dbDumpVariable pddbase\n"
|
||||
"If last argument(s) are missing, dump all variables.\n"};
|
||||
static void dbDumpVariableCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbDumpVariable(*iocshPpdbbase);
|
||||
@@ -159,7 +165,8 @@ static const iocshFuncDef dbDumpBreaktableFuncDef = {
|
||||
2,
|
||||
dbDumpBreaktableArgs,
|
||||
"Dump the given break table\n"
|
||||
"Example: dbDumpBreaktable pdbbase typeKdegC\n",
|
||||
"Example: dbDumpBreaktable pdbbase typeKdegC\n"
|
||||
"If last argument(s) are missing, dump all breakpoint tables.\n",
|
||||
};
|
||||
static void dbDumpBreaktableCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
@@ -176,7 +183,8 @@ static const iocshFuncDef dbPvdDumpFuncDef = {
|
||||
dbPvdDumpArgs,
|
||||
"Dump the various buckets of the process variable directory.\n"
|
||||
"If verbose is greater than 0, also print the process variables in each bucket.\n"
|
||||
"Example: dbPvdDump pdbbase 1\n",
|
||||
"Example: dbPvdDump pdbbase 1\n"
|
||||
"If the last argument(s) are missing, dump all buckets as though verbose is 0.\n",
|
||||
};
|
||||
static void dbPvdDumpCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
@@ -247,7 +255,7 @@ static void dbCreateAliasCallFunc(const iocshArgBuf *args)
|
||||
}
|
||||
dbFinishEntry(&ent);
|
||||
if(status) {
|
||||
fprintf(stderr, "Error: %ld %s\n", status, errSymMsg(status));
|
||||
fprintf(stderr, ERL_ERROR ": %ld %s\n", status, errSymMsg(status));
|
||||
iocshSetError(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ static char *pNullString = "";
|
||||
*/
|
||||
STATIC_ASSERT(messagesize >= 21);
|
||||
|
||||
static char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"};
|
||||
static char *msstring[4]={" NMS"," MS"," MSI"," MSS"};
|
||||
static const char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"};
|
||||
static const char *msstring[4]={" NMS"," MS"," MSI"," MSS"};
|
||||
|
||||
maplinkType pamaplinkType[LINK_NTYPES] = {
|
||||
const maplinkType pamaplinkType[LINK_NTYPES] = {
|
||||
{"CONSTANT",CONSTANT},
|
||||
{"PV_LINK",PV_LINK},
|
||||
{"VME_IO",VME_IO},
|
||||
@@ -89,7 +89,7 @@ static FILE *openOutstream(const char *filename)
|
||||
errno = 0;
|
||||
stream = fopen(filename,"w");
|
||||
if(!stream) {
|
||||
fprintf(stderr,"error opening %s %s\n",filename,strerror(errno));
|
||||
fprintf(stderr,ERL_ERROR " opening %s %s\n",filename,strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return stream;
|
||||
@@ -637,7 +637,7 @@ void dbFinishEntry(DBENTRY *pdbentry)
|
||||
}
|
||||
}
|
||||
|
||||
DBENTRY * dbCopyEntry(DBENTRY *pdbentry)
|
||||
DBENTRY * dbCopyEntry(const DBENTRY *pdbentry)
|
||||
{
|
||||
DBENTRY *pnew;
|
||||
|
||||
@@ -647,7 +647,7 @@ DBENTRY * dbCopyEntry(DBENTRY *pdbentry)
|
||||
return(pnew);
|
||||
}
|
||||
|
||||
void dbCopyEntryContents(DBENTRY *pfrom,DBENTRY *pto)
|
||||
void dbCopyEntryContents(const DBENTRY *pfrom,DBENTRY *pto)
|
||||
{
|
||||
*pto = *pfrom;
|
||||
pto->message = NULL;
|
||||
@@ -1445,6 +1445,7 @@ long dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
|
||||
pdbentry->precnode = pNewRecNode;
|
||||
ppvd = dbPvdAdd(pdbentry->pdbbase,precordType,pNewRecNode);
|
||||
if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
|
||||
pNewRecNode->order = pdbentry->pdbbase->no_records++;
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1686,6 +1687,7 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
|
||||
}
|
||||
|
||||
ellAdd(&precordType->recList, &pnewnode->node);
|
||||
pnewnode->order = pdbentry->pdbbase->no_records++;
|
||||
precordType->no_aliases++;
|
||||
|
||||
return 0;
|
||||
@@ -2204,11 +2206,11 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
|
||||
*/
|
||||
|
||||
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
|
||||
errlogPrintf("Error: %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
|
||||
errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
|
||||
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
|
||||
|
||||
} else if(dbSetLink(plink, &link_info, devsup)) {
|
||||
errlogPrintf("Error: %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
|
||||
errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
|
||||
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
|
||||
}
|
||||
free(plink->text);
|
||||
|
||||
@@ -51,9 +51,9 @@ DBCORE_API void dbInitEntry(DBBASE *pdbbase,
|
||||
DBENTRY *pdbentry);
|
||||
|
||||
DBCORE_API void dbFinishEntry(DBENTRY *pdbentry);
|
||||
DBCORE_API DBENTRY * dbCopyEntry(DBENTRY *pdbentry);
|
||||
DBCORE_API void dbCopyEntryContents(DBENTRY *pfrom,
|
||||
DBENTRY *pto);
|
||||
DBCORE_API DBENTRY * dbCopyEntry(const DBENTRY *pdbentry);
|
||||
DBCORE_API void dbCopyEntryContents(const DBENTRY *pfrom,
|
||||
DBENTRY *pto);
|
||||
|
||||
DBCORE_API extern int dbBptNotMonotonic;
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName)
|
||||
|
||||
status = dbPutStringNum(pdbentry,pflddes->initial);
|
||||
if(status)
|
||||
epicsPrintf("Error initializing %s.%s initial %s\n",
|
||||
epicsPrintf(ERL_ERROR " initializing %s.%s initial %s\n",
|
||||
pdbRecordType->name,pflddes->name,pflddes->initial);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -370,9 +370,9 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); }
|
||||
static int yyerror(char *str)
|
||||
{
|
||||
if (str)
|
||||
epicsPrintf("Error: %s\n", str);
|
||||
epicsPrintf(ERL_ERROR ": %s\n", str);
|
||||
else
|
||||
epicsPrintf("Error");
|
||||
epicsPrintf(ERL_ERROR "");
|
||||
if (!yyFailed) { /* Only print this stuff once */
|
||||
epicsPrintf(" at or before '%s'", yytext);
|
||||
dbIncludePrint();
|
||||
|
||||
@@ -43,11 +43,11 @@ extern "C" {
|
||||
#define VXI_IO 15
|
||||
#define LINK_NTYPES 16
|
||||
typedef struct maplinkType {
|
||||
char *strvalue;
|
||||
const char *strvalue;
|
||||
int value;
|
||||
} maplinkType;
|
||||
|
||||
DBCORE_API extern maplinkType pamaplinkType[];
|
||||
DBCORE_API extern const maplinkType pamaplinkType[LINK_NTYPES];
|
||||
|
||||
#define VXIDYNAMIC 0
|
||||
#define VXISTATIC 1
|
||||
@@ -193,7 +193,7 @@ struct lset;
|
||||
struct link {
|
||||
struct dbCommon *precord; /* Pointer to record owning link */
|
||||
short type;
|
||||
short flags;
|
||||
unsigned short flags;
|
||||
struct lset *lset;
|
||||
char *text; /* Raw link text */
|
||||
union value value;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "osiUnistd.h"
|
||||
#include "macLib.h"
|
||||
#include "dbmf.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#include "epicsExport.h"
|
||||
#include "dbAccess.h"
|
||||
@@ -337,7 +338,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect)
|
||||
|
||||
if (dbTemplateMaxVars < 1)
|
||||
{
|
||||
fprintf(stderr,"Error: dbTemplateMaxVars = %d, must be +ve\n",
|
||||
fprintf(stderr,ERL_ERROR ": dbTemplateMaxVars = %d, must be +ve\n",
|
||||
dbTemplateMaxVars);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ static void addMacroReplacements(MAC_HANDLE * const macPvt,
|
||||
if (status) {
|
||||
status = macInstallMacros(macPvt, pairs);
|
||||
if (!status) {
|
||||
fprintf(stderr, "Error from macInstallMacros\n");
|
||||
fprintf(stderr, ERL_ERROR " from macInstallMacros\n");
|
||||
usageExit(1);
|
||||
}
|
||||
free(pairs);
|
||||
@@ -522,7 +522,7 @@ static void inputOpenFile(inputData *pinputData, const char * const filename)
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
fprintf(stderr, "msi: Can't open file '%s'\n", filename);
|
||||
fprintf(stderr, ERL_ERROR " msi: Can't open file '%s'\n", filename);
|
||||
inputErrPrint(pinputData);
|
||||
abortExit(1);
|
||||
}
|
||||
@@ -672,7 +672,7 @@ static void substituteOpen(subInfo **ppvt, const std::string& substitutionName)
|
||||
|
||||
fp = fopen(substitutionName.c_str(), "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "msi: Can't open file '%s'\n", substitutionName.c_str());
|
||||
fprintf(stderr, ERL_ERROR " msi: Can't open file '%s'\n", substitutionName.c_str());
|
||||
abortExit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ static int iocBuild_2(void)
|
||||
|
||||
scanInit();
|
||||
if (asInit()) {
|
||||
errlogPrintf("iocBuild: asInit Failed.\n");
|
||||
errlogPrintf(ERL_ERROR " iocBuild: asInit Failed.\n");
|
||||
return -1;
|
||||
}
|
||||
dbProcessNotifyInit();
|
||||
|
||||
@@ -38,7 +38,7 @@ static void iocBuildCallFunc(const iocshArgBuf *args)
|
||||
/* iocRun */
|
||||
static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL,
|
||||
"Bring the IOC out of its initial quiescent state to the running state.\n"
|
||||
"See more: iocBuild, iocPause"};
|
||||
"See more: iocBuild, iocPause\n"};
|
||||
static void iocRunCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshSetError(iocRun());
|
||||
@@ -47,7 +47,7 @@ static void iocRunCallFunc(const iocshArgBuf *args)
|
||||
/* iocPause */
|
||||
static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL,
|
||||
"Brings a running IOC to a quiescent state with all record processing frozen.\n"
|
||||
"See more: iocBuild, iocRub, iocInit"};
|
||||
"See more: iocBuild, iocRub, iocInit\n"};
|
||||
static void iocPauseCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshSetError(iocPause());
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsFindSymbol.h>
|
||||
#include <errlog.h>
|
||||
#include <registryRecordType.h>
|
||||
#include <registryDeviceSupport.h>
|
||||
#include <registryDriverSupport.h>
|
||||
@@ -248,7 +249,7 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase)
|
||||
|
||||
} catch(std::exception& e) {
|
||||
dbFinishEntry(&entry);
|
||||
fprintf(stderr, "Error: %s\n", e.what());
|
||||
fprintf(stderr, ERL_ERROR ": %s\n", e.what());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,11 @@ static void req_server (void *pParm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
cantProceed("Unreachable. Perpetual thread.");
|
||||
|
||||
taskwdRemove(0);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -748,6 +753,7 @@ void rsrv_init (void)
|
||||
if(!havesometcp)
|
||||
cantProceed("CAS: No TCP server started\n");
|
||||
}
|
||||
free(socks);
|
||||
|
||||
/* servers list is considered read-only from this point */
|
||||
|
||||
|
||||
@@ -129,7 +129,11 @@ void rsrv_online_notify_task(void *pParm)
|
||||
}
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
cantProceed("Unreachable. Perpetual thread.");
|
||||
|
||||
free(lastError);
|
||||
taskwdRemove(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ static long readLocked(struct link *pinp, void *dummy)
|
||||
|
||||
if (status) return status;
|
||||
|
||||
if (prec->mask)
|
||||
prec->rval &= prec->mask;
|
||||
|
||||
if (dbLinkIsConstant(&prec->tsel) &&
|
||||
prec->tse == epicsTimeEventDeviceTime)
|
||||
dbGetTimeStamp(pinp, &prec->time);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "freeList.h"
|
||||
#include "caeventmask.h"
|
||||
#include "db_field_log.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "epicsExit.h"
|
||||
@@ -60,7 +61,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
myStruct *my = (myStruct*) pvt;
|
||||
epicsInt32 i = my->i;
|
||||
|
||||
if (pfl->ctx == dbfl_context_read)
|
||||
if (pfl->ctx == dbfl_context_read || (pfl->mask & DBE_PROPERTY))
|
||||
return pfl;
|
||||
|
||||
if (i++ == 0)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "freeList.h"
|
||||
#include "caeventmask.h"
|
||||
#include "db_field_log.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "dbState.h"
|
||||
@@ -94,7 +95,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
myStruct *my = (myStruct*) pvt;
|
||||
int actstate;
|
||||
|
||||
if (pfl->ctx == dbfl_context_read)
|
||||
if (pfl->ctx == dbfl_context_read || (pfl->mask & DBE_PROPERTY))
|
||||
return pfl;
|
||||
|
||||
actstate = dbStateGet(my->id);
|
||||
|
||||
@@ -60,8 +60,10 @@ this chapter for information on soft device support.
|
||||
|
||||
If the record gets its values from hardware or uses the C<Raw Soft Channel>
|
||||
device support, the device support routines place the value in the RVAL
|
||||
field which is then converted using the process described in the next
|
||||
section.
|
||||
field.
|
||||
(Since 7.0.8) If the MASK field is non-zero, then this MASK is applied to RVAL.
|
||||
The value from RVAL is then converted using the process described in the
|
||||
next section.
|
||||
|
||||
=fields INP, DTYP, ZNAM, ONAM, RVAL, VAL
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ The desired output needs to be in engineering units.
|
||||
|
||||
The first field that determines where the desired output originates is the
|
||||
output mode select (OMSL) field, which can have two possible values:
|
||||
C<losed_loop> or C<supervisory>. If C<supervisory> is specified, the value
|
||||
C<closed_loop> or C<supervisory>. If C<supervisory> is specified, the value
|
||||
in the VAL field can be set externally via dbPuts at run-time. If
|
||||
C<closed_loop> is specified, the VAL field's value is obtained from the
|
||||
address specified in the Desired Output Link (DOL) field which can be a
|
||||
|
||||
@@ -158,7 +158,7 @@ CEIL: Ceiling (unary)
|
||||
FLOOR: Floor (unary)
|
||||
|
||||
=item *
|
||||
FMOD: Floating point modulo (binary) Added in UNRELEASED
|
||||
FMOD: Floating point modulo (binary) Added in 7.0.8
|
||||
|
||||
=item *
|
||||
LOG: Log base 10 (unary)
|
||||
|
||||
@@ -184,7 +184,7 @@ CEIL: Ceiling (unary)
|
||||
FLOOR: Floor (unary)
|
||||
|
||||
=item *
|
||||
FMOD: Floating point modulo (binary) Added in UNRELEASED
|
||||
FMOD: Floating point modulo (binary) Added in 7.0.8
|
||||
|
||||
=item *
|
||||
LOG: Log base 10 (unary)
|
||||
@@ -1160,7 +1160,7 @@ See next section.
|
||||
|
||||
=head2 C<special>
|
||||
|
||||
This is called id CALC or OCAL is changed. C<special> calls postfix.
|
||||
This is called if CALC or OCAL is changed. C<special> calls postfix.
|
||||
|
||||
=head2 C<get_units>
|
||||
|
||||
|
||||
@@ -149,13 +149,16 @@ static int compare(const void *arg1, const void *arg2)
|
||||
else return 1;
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static int compress_array(compressRecord *prec,
|
||||
double *psource, int no_elements)
|
||||
{
|
||||
epicsInt32 i,j;
|
||||
epicsInt32 j;
|
||||
epicsInt32 n, nnew;
|
||||
epicsInt32 nsam = prec->nsam;
|
||||
double value;
|
||||
epicsUInt32 samples_written = 0;
|
||||
double value = 0.0;
|
||||
|
||||
/* skip out of limit data */
|
||||
if (prec->ilil < prec->ihil) {
|
||||
@@ -167,61 +170,54 @@ static int compress_array(compressRecord *prec,
|
||||
}
|
||||
if (prec->n <= 0)
|
||||
prec->n = 1;
|
||||
if (no_elements < prec->n && prec->pbuf != menuYesNoYES)
|
||||
return 1; /*dont do anything*/
|
||||
n = no_elements;
|
||||
n = prec->n;
|
||||
|
||||
/* determine number of samples to take */
|
||||
if (no_elements < nsam * n)
|
||||
nnew = (no_elements / n);
|
||||
else nnew = nsam;
|
||||
nnew = min(no_elements, nsam * n);
|
||||
|
||||
/* compress according to specified algorithm */
|
||||
switch (prec->alg){
|
||||
case compressALG_N_to_1_Low_Value:
|
||||
/* compress N to 1 keeping the lowest value */
|
||||
for (i = 0; i < nnew; i++) {
|
||||
while (nnew > 0)
|
||||
{
|
||||
if (nnew < n && prec->pbuf != menuYesNoYES)
|
||||
break;
|
||||
|
||||
n = min(n, nnew);
|
||||
switch (prec->alg)
|
||||
{
|
||||
case compressALG_N_to_1_Low_Value:
|
||||
value = *psource++;
|
||||
for (j = 1; j < n; j++, psource++) {
|
||||
for (j = 1; j < n; j++, psource++)
|
||||
{
|
||||
if (value > *psource)
|
||||
value = *psource;
|
||||
}
|
||||
put_value(prec, &value, 1);
|
||||
}
|
||||
break;
|
||||
case compressALG_N_to_1_High_Value:
|
||||
/* compress N to 1 keeping the highest value */
|
||||
for (i = 0; i < nnew; i++){
|
||||
break;
|
||||
case compressALG_N_to_1_High_Value:
|
||||
value = *psource++;
|
||||
for (j = 1; j < n; j++, psource++) {
|
||||
for (j = 1; j < n; j++, psource++)
|
||||
{
|
||||
if (value < *psource)
|
||||
value = *psource;
|
||||
}
|
||||
put_value(prec, &value, 1);
|
||||
}
|
||||
break;
|
||||
case compressALG_N_to_1_Average:
|
||||
/* compress N to 1 keeping the average value */
|
||||
for (i = 0; i < nnew; i++) {
|
||||
value = 0;
|
||||
for (j = 0; j < n; j++, psource++)
|
||||
break;
|
||||
case compressALG_N_to_1_Average:
|
||||
value = *psource++;
|
||||
for (j = 1; j < n; j++, psource++)
|
||||
{
|
||||
value += *psource;
|
||||
value /= n;
|
||||
put_value(prec, &value, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case compressALG_N_to_1_Median:
|
||||
/* compress N to 1 keeping the median value */
|
||||
/* note: sorts source array (OK; it's a work pointer) */
|
||||
for (i = 0; i < nnew; i++, psource += nnew) {
|
||||
}
|
||||
value = value / n;
|
||||
break;
|
||||
case compressALG_N_to_1_Median:
|
||||
/* note: sorts source array (OK; it's a work pointer) */
|
||||
qsort(psource, n, sizeof(double), compare);
|
||||
value = psource[n / 2];
|
||||
put_value(prec, &value, 1);
|
||||
psource += n;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
nnew -= n;
|
||||
put_value(prec, &value, 1);
|
||||
samples_written++;
|
||||
}
|
||||
return 0;
|
||||
return (samples_written == 0);
|
||||
}
|
||||
|
||||
static int array_average(compressRecord *prec,
|
||||
|
||||
@@ -91,10 +91,10 @@ The BPTR field contains a pointer to the unsigned long array of frequency
|
||||
values. The VAL field references this array as well. However, the BPTR field is
|
||||
not accessible at run-time.
|
||||
|
||||
The MCNT field keeps counts the number of signal counts since the last monitor
|
||||
The MCNT field keeps the number of signal counts since the last monitor
|
||||
was invoked.
|
||||
|
||||
The collections controls field (CMD) is a menu field with five choices:
|
||||
The collections controls field (CMD) is a menu field with four choices:
|
||||
|
||||
=menu histogramCMD
|
||||
|
||||
@@ -110,8 +110,6 @@ array. Unlike C<Read>, it doesn't clear the array first.
|
||||
|
||||
The C<Stop> command disables the reading of signal values into the array.
|
||||
|
||||
The C<Setup> command waits until the C<start> or C<read> command has been issued
|
||||
to start counting.
|
||||
|
||||
The CSTA or collections status field implements the CMD field choices by
|
||||
enabling or disabling the reading of values into the histogram array. While
|
||||
|
||||
@@ -85,7 +85,7 @@ for information on the format of hardware addresses and database links.
|
||||
|
||||
=head4 Menu longoutOOPT
|
||||
|
||||
The OOPT field was added in EPICS UNRELEASED.
|
||||
The OOPT field was added in EPICS 7.0.8.
|
||||
|
||||
It determines the condition that causes the output link to be
|
||||
written to. It's a menu field that has six choices:
|
||||
@@ -119,7 +119,7 @@ VAL is non-zero and last value was zero.
|
||||
|
||||
=head4 Changes in OUT field when OOPT = On Change
|
||||
|
||||
The OOCH field was added in EPICS UNRELEASED.
|
||||
The OOCH field was added in EPICS 7.0.8.
|
||||
|
||||
If OOCH is C<YES> (its default value) and the OOPT field is C<On Change>,
|
||||
the record will write to the device support the first time the record gets
|
||||
|
||||
@@ -49,6 +49,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (sizv < 16) {
|
||||
sizv = 16; /* Enforce a minimum size for the VAL field */
|
||||
prec->sizv = sizv;
|
||||
} else if (sizv > 0x7fff) {
|
||||
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
|
||||
prec->sizv = sizv;
|
||||
}
|
||||
|
||||
prec->val = callocMustSucceed(1, sizv, "lsi::init_record");
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
=title Long String Input Record (lsi)
|
||||
|
||||
The long string input record is used to retrieve an arbitrary ASCII string with
|
||||
a maximum length of 65535 characters.
|
||||
a maximum length of 32767 characters.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
@@ -36,7 +36,7 @@ from. It can be a database or channel access link, or a constant. If constant,
|
||||
the VAL field is initialized with the constant and can be changed via dbPuts.
|
||||
Otherwise, the string is read from the specified location each time the record
|
||||
is processed and placed in the VAL field. The maximum number of characters in
|
||||
VAL is given by SIZV, and cannot be larger than 65535. In addition, the
|
||||
VAL is given by SIZV, and cannot be larger than 32767. In addition, the
|
||||
appropriate device support module must be entered into the DTYP field.
|
||||
|
||||
=fields VAL, OVAL, SIZV, INP, DTYP
|
||||
|
||||
@@ -53,6 +53,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (sizv < 16) {
|
||||
sizv = 16; /* Enforce a minimum size for the VAL field */
|
||||
prec->sizv = sizv;
|
||||
} else if (sizv > 0x7fff) {
|
||||
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
|
||||
prec->sizv = sizv;
|
||||
}
|
||||
|
||||
prec->val = callocMustSucceed(1, sizv, "lso::init_record");
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
=title Long String Output Record (lso)
|
||||
|
||||
The long string output record is used to write an arbitrary ASCII string with a
|
||||
maximum length of 65535 characters.
|
||||
maximum length of 32767 characters.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
@@ -41,7 +41,7 @@ C<supervisory> is specified, DOL is ignored, the current value of VAL is
|
||||
written, and VAL can be changed externally via dbPuts at run-time.
|
||||
|
||||
The maximum number of characters in VAL is given by SIZV, and cannot be larger
|
||||
than 65535.
|
||||
than 32767.
|
||||
|
||||
DOL can also be a constant instead of a link, in which case VAL is initialized
|
||||
to the constant value. Most simple string constants are likely to be interpreted
|
||||
|
||||
@@ -322,6 +322,7 @@ to alarms that are common to all record types.
|
||||
field(B0,DBF_UCHAR) {
|
||||
prompt("Bit 0")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -329,6 +330,7 @@ to alarms that are common to all record types.
|
||||
field(B1,DBF_UCHAR) {
|
||||
prompt("Bit 1")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -336,6 +338,7 @@ to alarms that are common to all record types.
|
||||
field(B2,DBF_UCHAR) {
|
||||
prompt("Bit 2")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -343,6 +346,7 @@ to alarms that are common to all record types.
|
||||
field(B3,DBF_UCHAR) {
|
||||
prompt("Bit 3")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -350,6 +354,7 @@ to alarms that are common to all record types.
|
||||
field(B4,DBF_UCHAR) {
|
||||
prompt("Bit 4")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -357,6 +362,7 @@ to alarms that are common to all record types.
|
||||
field(B5,DBF_UCHAR) {
|
||||
prompt("Bit 5")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -364,6 +370,7 @@ to alarms that are common to all record types.
|
||||
field(B6,DBF_UCHAR) {
|
||||
prompt("Bit 6")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -371,6 +378,7 @@ to alarms that are common to all record types.
|
||||
field(B7,DBF_UCHAR) {
|
||||
prompt("Bit 7")
|
||||
promptgroup("51 - Output 0-7")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -378,6 +386,7 @@ to alarms that are common to all record types.
|
||||
field(B8,DBF_UCHAR) {
|
||||
prompt("Bit 8")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -385,6 +394,7 @@ to alarms that are common to all record types.
|
||||
field(B9,DBF_UCHAR) {
|
||||
prompt("Bit 9")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -392,6 +402,7 @@ to alarms that are common to all record types.
|
||||
field(BA,DBF_UCHAR) {
|
||||
prompt("Bit 10")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -399,6 +410,7 @@ to alarms that are common to all record types.
|
||||
field(BB,DBF_UCHAR) {
|
||||
prompt("Bit 11")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -406,6 +418,7 @@ to alarms that are common to all record types.
|
||||
field(BC,DBF_UCHAR) {
|
||||
prompt("Bit 12")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -413,6 +426,7 @@ to alarms that are common to all record types.
|
||||
field(BD,DBF_UCHAR) {
|
||||
prompt("Bit 13")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -420,6 +434,7 @@ to alarms that are common to all record types.
|
||||
field(BE,DBF_UCHAR) {
|
||||
prompt("Bit 14")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -427,6 +442,7 @@ to alarms that are common to all record types.
|
||||
field(BF,DBF_UCHAR) {
|
||||
prompt("Bit 15")
|
||||
promptgroup("52 - Output 8-15")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -434,6 +450,7 @@ to alarms that are common to all record types.
|
||||
field(B10,DBF_UCHAR) {
|
||||
prompt("Bit 16")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -441,6 +458,7 @@ to alarms that are common to all record types.
|
||||
field(B11,DBF_UCHAR) {
|
||||
prompt("Bit 17")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -448,6 +466,7 @@ to alarms that are common to all record types.
|
||||
field(B12,DBF_UCHAR) {
|
||||
prompt("Bit 18")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -455,6 +474,7 @@ to alarms that are common to all record types.
|
||||
field(B13,DBF_UCHAR) {
|
||||
prompt("Bit 19")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -462,6 +482,7 @@ to alarms that are common to all record types.
|
||||
field(B14,DBF_UCHAR) {
|
||||
prompt("Bit 20")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -469,6 +490,7 @@ to alarms that are common to all record types.
|
||||
field(B15,DBF_UCHAR) {
|
||||
prompt("Bit 21")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -476,6 +498,7 @@ to alarms that are common to all record types.
|
||||
field(B16,DBF_UCHAR) {
|
||||
prompt("Bit 22")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -483,6 +506,7 @@ to alarms that are common to all record types.
|
||||
field(B17,DBF_UCHAR) {
|
||||
prompt("Bit 23")
|
||||
promptgroup("53 - Output 16-23")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -490,6 +514,7 @@ to alarms that are common to all record types.
|
||||
field(B18,DBF_UCHAR) {
|
||||
prompt("Bit 24")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -497,6 +522,7 @@ to alarms that are common to all record types.
|
||||
field(B19,DBF_UCHAR) {
|
||||
prompt("Bit 25")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -504,6 +530,7 @@ to alarms that are common to all record types.
|
||||
field(B1A,DBF_UCHAR) {
|
||||
prompt("Bit 26")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -511,6 +538,7 @@ to alarms that are common to all record types.
|
||||
field(B1B,DBF_UCHAR) {
|
||||
prompt("Bit 27")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -518,6 +546,7 @@ to alarms that are common to all record types.
|
||||
field(B1C,DBF_UCHAR) {
|
||||
prompt("Bit 28")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -525,6 +554,7 @@ to alarms that are common to all record types.
|
||||
field(B1D,DBF_UCHAR) {
|
||||
prompt("Bit 29")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -532,6 +562,7 @@ to alarms that are common to all record types.
|
||||
field(B1E,DBF_UCHAR) {
|
||||
prompt("Bit 30")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
@@ -539,6 +570,7 @@ to alarms that are common to all record types.
|
||||
field(B1F,DBF_UCHAR) {
|
||||
prompt("Bit 31")
|
||||
promptgroup("54 - Output 24-31")
|
||||
asl(ASL0)
|
||||
special(SPC_MOD)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
|
||||
@@ -57,6 +57,14 @@
|
||||
else \
|
||||
flags |= F_BADLNK
|
||||
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat-security"
|
||||
/* Intentionally passing non-const format string to epicsSnprintf() below.
|
||||
* Older GCC does not allow pragma GCC within function body.
|
||||
*/
|
||||
#endif
|
||||
|
||||
static void doPrintf(printfRecord *prec)
|
||||
{
|
||||
const char *pfmt = prec->fmt;
|
||||
@@ -314,6 +322,9 @@ static void doPrintf(printfRecord *prec)
|
||||
prec->len = pval - prec->val;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
static long init_record(struct dbCommon *pcommon, int pass)
|
||||
{
|
||||
@@ -326,6 +337,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (sizv < 16) {
|
||||
sizv = 16; /* Enforce a minimum size for the VAL field */
|
||||
prec->sizv = sizv;
|
||||
} else if (sizv > 0x7fff) {
|
||||
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
|
||||
prec->sizv = sizv;
|
||||
}
|
||||
|
||||
prec->val = callocMustSucceed(1, sizv, "printf::init_record");
|
||||
|
||||
@@ -152,7 +152,7 @@ Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Dat
|
||||
for information on specifying links.
|
||||
|
||||
The formatted string is written to the VAL field. The maximum number of
|
||||
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
|
||||
characters in VAL is given by SIZV, and cannot be larger than 32767. The LEN
|
||||
field contains the length of the formatted string in the VAL field.
|
||||
|
||||
=fields FMT, INP0, INP1, INP2, INP3, INP4, INP5, INP6, INP7, INP8, INP9, VAL, SIZV, LEN
|
||||
|
||||
@@ -20,10 +20,14 @@ use EPICS::Getopts;
|
||||
use EPICS::Readfile;
|
||||
use EPICS::macLib;
|
||||
|
||||
our ($opt_D, @opt_I, @opt_S, $opt_o);
|
||||
our ($opt_D, $opt_A, @opt_I, @opt_S, $opt_o);
|
||||
|
||||
getopts('DI@S@o:') or
|
||||
die "Usage: dbdExpand [-D] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ...";
|
||||
getopts('DAI@S@o:') or
|
||||
die "Usage: dbdExpand [-D] [-A] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ...";
|
||||
|
||||
if ($opt_A) {
|
||||
$DBD::Parser::allowAutoDeclarations = 1;
|
||||
}
|
||||
|
||||
my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
|
||||
my $macros = EPICS::macLib->new(@opt_S);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#define EPICS_PRIVATE_API
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <errlog.h>
|
||||
|
||||
@@ -469,6 +469,38 @@ testNto1Average(void) {
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void testNto2Average(void) {
|
||||
DBADDR wfaddr, caddr;
|
||||
|
||||
testDiag("Test N to 1 Average, NSAM=2, N=2");
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
|
||||
|
||||
recTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=2");
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
fetchRecordOrDie("wf", wfaddr);
|
||||
fetchRecordOrDie("comp", caddr);
|
||||
|
||||
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
|
||||
|
||||
dbScanLock(caddr.precord);
|
||||
dbProcess(caddr.precord);
|
||||
|
||||
checkArrD("comp", 2, 1.5, 3.5, 0, 0);
|
||||
dbScanUnlock(caddr.precord);
|
||||
|
||||
testIocShutdownOk();
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
testNto1AveragePartial(void) {
|
||||
double buf = 0.0;
|
||||
@@ -517,6 +549,36 @@ testNto1AveragePartial(void) {
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
testNtoMPartial(void) {
|
||||
DBADDR wfaddr, caddr;
|
||||
|
||||
testDiag("Test Average, N to M, Partial");
|
||||
|
||||
testdbPrepare();
|
||||
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
|
||||
recTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=3,PBUF=YES");
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
fetchRecordOrDie("wf", wfaddr);
|
||||
fetchRecordOrDie("comp", caddr);
|
||||
|
||||
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
|
||||
|
||||
dbScanLock(caddr.precord);
|
||||
dbProcess(caddr.precord);
|
||||
|
||||
checkArrD("comp", 2, 2.0, 4.0, 0, 0);
|
||||
dbScanUnlock(caddr.precord);
|
||||
|
||||
testIocShutdownOk();
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
testNto1LowValue(void) {
|
||||
double buf = 0.0;
|
||||
@@ -634,12 +696,14 @@ testAIAveragePartial(void) {
|
||||
|
||||
MAIN(compressTest)
|
||||
{
|
||||
testPlan(132);
|
||||
testPlan(134);
|
||||
testFIFOCirc();
|
||||
testLIFOCirc();
|
||||
testArrayAverage();
|
||||
testNto1Average();
|
||||
testNto2Average();
|
||||
testNto1AveragePartial();
|
||||
testNtoMPartial();
|
||||
testAIAveragePartial();
|
||||
testNto1LowValue();
|
||||
return testDone();
|
||||
|
||||
@@ -37,7 +37,7 @@ int epicsNtpGetTime(char *ntpIp, struct timespec *now)
|
||||
sockfd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); // Create a UDP socket.
|
||||
|
||||
if ( sockfd < 0 ) {
|
||||
perror( "epicsNtpGetTime" );
|
||||
perror( "epicsNtpGetTime creating socket" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -51,24 +51,29 @@ int epicsNtpGetTime(char *ntpIp, struct timespec *now)
|
||||
|
||||
// Call up the server using its IP address and port number.
|
||||
if ( connect( sockfd, ( struct sockaddr * ) &serv_addr, sizeof( serv_addr) ) < 0 ) {
|
||||
perror( "epicsNtpGetTime" );
|
||||
perror( "epicsNtpGetTime connecting socket" );
|
||||
close( sockfd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Send it the NTP packet it wants. If n == -1, it failed.
|
||||
n = write( sockfd, ( char* ) &packet, sizeof( ntp_packet ) );
|
||||
if ( n < 0 ) {
|
||||
perror( "epicsNtpGetTime" );
|
||||
perror( "epicsNtpGetTime sending NTP request" );
|
||||
close( sockfd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Wait and receive the packet back from the server. If n == -1, it failed.
|
||||
// Wait and receive the packet back from the server. If n == -1, it failed.
|
||||
n = read( sockfd, ( char* ) &packet, sizeof( ntp_packet ) );
|
||||
if ( n < 0 ) {
|
||||
perror( "epicsNtpGetTime" );
|
||||
perror( "epicsNtpGetTime reading NTP reply" );
|
||||
close( sockfd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
close( sockfd );
|
||||
|
||||
// These two fields contain the time-stamp seconds as the packet left the NTP server.
|
||||
// The number of seconds correspond to the seconds passed since 1900.
|
||||
// ntohl() converts the bit/byte order from the network's to host's "endianness".
|
||||
|
||||
@@ -209,7 +209,7 @@ static int yyerror(char *str)
|
||||
if (strlen(str))
|
||||
errlogPrintf("%s at line %d\n", str, line_num);
|
||||
else
|
||||
errlogPrintf("Error at line %d\n", line_num);
|
||||
errlogPrintf(ERL_ERROR " at line %d\n", line_num);
|
||||
yyFailed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -176,12 +176,12 @@ long epicsStdCall asInitFile(const char *filename,const char *substitutions)
|
||||
|
||||
fp = fopen(filename,"r");
|
||||
if(!fp) {
|
||||
errlogPrintf("asInitFile: Can't open file '%s'\n", filename);
|
||||
fprintf(stderr, ERL_ERROR " asInitFile: Can't open file '%s'\n", filename);
|
||||
return(S_asLib_badConfig);
|
||||
}
|
||||
status = asInitFP(fp,substitutions);
|
||||
if(fclose(fp)==EOF) {
|
||||
errMessage(0,"asInitFile: fclose failed!");
|
||||
fprintf(stderr, ERL_ERROR " asInitFile: fclose failed!");
|
||||
if(!status) status = S_asLib_badConfig;
|
||||
}
|
||||
return(status);
|
||||
@@ -359,7 +359,6 @@ void epicsStdCall asPutMemberPvt(ASMEMBERPVT asMemberPvt,void *userPvt)
|
||||
if(!asActive) return;
|
||||
if(!pasgmember) return;
|
||||
pasgmember->userPvt = userPvt;
|
||||
return;
|
||||
}
|
||||
|
||||
long epicsStdCall asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
|
||||
@@ -367,7 +366,7 @@ long epicsStdCall asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
|
||||
{
|
||||
ASGMEMBER *pasgmember = asMemberPvt;
|
||||
ASGCLIENT *pasgclient;
|
||||
int len, i;
|
||||
size_t len, i;
|
||||
|
||||
long status;
|
||||
if(!asActive) return(S_asLib_asNotActive);
|
||||
@@ -395,7 +394,7 @@ long epicsStdCall asChangeClient(
|
||||
{
|
||||
ASGCLIENT *pasgclient = asClientPvt;
|
||||
long status;
|
||||
int len, i;
|
||||
size_t len, i;
|
||||
|
||||
if(!asActive) return(S_asLib_asNotActive);
|
||||
if(!pasgclient) return(S_asLib_badClient);
|
||||
|
||||
@@ -335,6 +335,10 @@ LIBCOM_API long
|
||||
break;
|
||||
|
||||
case SEPERATOR:
|
||||
if (pstacktop == stack) {
|
||||
*perror = CALC_ERR_BAD_SEPERATOR;
|
||||
goto bad;
|
||||
}
|
||||
/* Move operators to the output until open paren */
|
||||
while (pstacktop->name[0] != '(') {
|
||||
if (pstacktop <= stack+1) {
|
||||
@@ -353,6 +357,10 @@ LIBCOM_API long
|
||||
break;
|
||||
|
||||
case CLOSE_PAREN:
|
||||
if (pstacktop == stack) {
|
||||
*perror = CALC_ERR_PAREN_NOT_OPEN;
|
||||
goto bad;
|
||||
}
|
||||
/* Move operators to the output until matching paren */
|
||||
while (pstacktop->name[0] != '(') {
|
||||
if (pstacktop <= stack+1) {
|
||||
|
||||
@@ -222,7 +222,7 @@ extern "C" {
|
||||
* - n parameter minimum value: min(a, b, ...)
|
||||
* - Square root: sqr(a) or sqrt(a)
|
||||
* - Floating point modulo: fmod(num, den)
|
||||
* \since The fmod() function was added in UNRELEASED
|
||||
* \since The fmod() function was added in 7.0.8
|
||||
*
|
||||
* -# ***Trigonometric Functions***
|
||||
* Standard circular trigonometric functions, with angles expressed in radians:
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
static epicsThreadOnceId epicsSigletonOnceFlag ( EPICS_THREAD_ONCE_INIT );
|
||||
static epicsMutex * pEPICSSigletonMutex = 0;
|
||||
epicsThreadOnceId epicsSigletonOnceFlag ( EPICS_THREAD_ONCE_INIT );
|
||||
epicsMutex * pEPICSSigletonMutex = 0;
|
||||
|
||||
extern "C" void SingletonMutexOnce ( void * /* pParm */ )
|
||||
{
|
||||
|
||||
@@ -34,8 +34,6 @@ void ellAdd (ELLLIST *pList, ELLNODE *pNode)
|
||||
|
||||
pList->node.previous = pNode;
|
||||
pList->count++;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
@@ -65,8 +63,6 @@ void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList)
|
||||
pAddList->count = 0;
|
||||
pAddList->node.next = NULL;
|
||||
pAddList->node.previous = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
@@ -86,8 +82,6 @@ void ellDelete (ELLLIST *pList, ELLNODE *pNode)
|
||||
pNode->previous->next = pNode->next;
|
||||
|
||||
pList->count--;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
@@ -136,8 +130,6 @@ void ellExtract (ELLLIST *pSrcList, ELLNODE *pStartNode, ELLNODE *pEndNode, ELLL
|
||||
}
|
||||
pSrcList->count -= count;
|
||||
pDstList->count += count;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
@@ -194,8 +186,6 @@ void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode)
|
||||
pNode->next->previous = pNode;
|
||||
|
||||
plist->count++;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
|
||||
@@ -26,6 +26,7 @@ ERR_S_FILES += $(LIBCOM)/as/asLib.h
|
||||
ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h
|
||||
ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h
|
||||
ERR_S_FILES += $(LIBCOM)/error/errMdef.h
|
||||
ERR_S_FILES += $(LIBCOM)/error/errSymTbl.h
|
||||
ERR_S_FILES += $(TOP)/modules/database/src/ioc/db/dbAccessDefs.h
|
||||
ERR_S_FILES += $(TOP)/modules/database/src/ioc/dbStatic/dbStaticLib.h
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define RTN_SUCCESS(STATUS) ((STATUS)==0)
|
||||
|
||||
/* Module numbers start above 500 for compatibility with vxWorks errnoLib */
|
||||
#define MIN_MODULE_NUM 501
|
||||
|
||||
/* FIXME: M_xxx values could be declared as integer variables and set
|
||||
* at runtime from registration routines; the S_xxx definitions would
|
||||
@@ -32,6 +33,7 @@
|
||||
#define M_stdlib (504 << 16) /* EPICS Standard library */
|
||||
#define M_pool (505 << 16) /* Thread pool */
|
||||
#define M_time (506 << 16) /* epicsTime */
|
||||
#define M_err (507 << 16) /* Error */
|
||||
|
||||
/* ioc */
|
||||
#define M_dbAccess (511 << 16) /* Database Access Routines */
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "cantProceed.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsThread.h"
|
||||
#include "errMdef.h"
|
||||
#include "errSymTbl.h"
|
||||
#include "ellLib.h"
|
||||
@@ -33,69 +36,49 @@
|
||||
static epicsUInt16 errhash(long errNum);
|
||||
|
||||
typedef struct errnumnode {
|
||||
ELLNODE node;
|
||||
long errNum;
|
||||
struct errnumnode *hashnode;
|
||||
const char *message;
|
||||
long pad;
|
||||
} ERRNUMNODE;
|
||||
|
||||
static ELLLIST errnumlist = ELLLIST_INIT;
|
||||
static ERRNUMNODE **hashtable;
|
||||
static int initialized = 0;
|
||||
typedef struct {
|
||||
ERRNUMNODE *table[NHASH * sizeof(ERRNUMNODE *)];
|
||||
epicsMutexId tableMutexId;
|
||||
} errHashTable_t;
|
||||
|
||||
static errHashTable_t errHashTable;
|
||||
|
||||
extern ERRSYMTAB_ID errSymTbl;
|
||||
|
||||
/****************************************************************
|
||||
* ERRSYMBLD
|
||||
*
|
||||
* Create the normal ell LIST of sorted error messages nodes
|
||||
* Followed by linked hash lists - that link together those
|
||||
* ell nodes that have a common hash number.
|
||||
* Populate EPICS error symbols
|
||||
*
|
||||
***************************************************************/
|
||||
int errSymBld(void)
|
||||
{
|
||||
ERRSYMBOL *errArray = errSymTbl->symbols;
|
||||
ERRNUMNODE *perrNumNode = NULL;
|
||||
ERRNUMNODE *pNextNode = NULL;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
int i;
|
||||
int modnum;
|
||||
|
||||
if (initialized)
|
||||
return(0);
|
||||
|
||||
hashtable = (ERRNUMNODE**)callocMustSucceed
|
||||
(NHASH, sizeof(ERRNUMNODE*),"errSymBld");
|
||||
ERRSYMBOL *errArray = errSymTbl->symbols;
|
||||
int i;
|
||||
for (i = 0; i < errSymTbl->nsymbols; i++, errArray++) {
|
||||
modnum = errArray->errNum >> 16;
|
||||
if (modnum < 501) {
|
||||
fprintf(stderr, "errSymBld: ERROR - Module number in errSymTbl < 501 was Module=%lx Name=%s\n",
|
||||
errArray->errNum, errArray->name);
|
||||
continue;
|
||||
}
|
||||
if ((errSymbolAdd(errArray->errNum, errArray->name)) < 0) {
|
||||
if (errSymbolAdd(errArray->errNum, errArray->name)) {
|
||||
fprintf(stderr, "errSymBld: ERROR - errSymbolAdd() failed \n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
perrNumNode = (ERRNUMNODE *) ellFirst(&errnumlist);
|
||||
while (perrNumNode) {
|
||||
/* hash each perrNumNode->errNum */
|
||||
epicsUInt16 hashInd = errhash(perrNumNode->errNum);
|
||||
|
||||
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
|
||||
pNextNode = (ERRNUMNODE*) *phashnode;
|
||||
/* search for last node (NULL) of hashnode linked list */
|
||||
while (pNextNode) {
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
*phashnode = perrNumNode;
|
||||
perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode);
|
||||
}
|
||||
initialized = 1;
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _initErrorHashTable(void *_unused)
|
||||
{
|
||||
errHashTable.tableMutexId = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
static void initErrorHashTable()
|
||||
{
|
||||
static epicsThreadOnceId initErrSymOnceFlag = EPICS_THREAD_ONCE_INIT;
|
||||
epicsThreadOnce(&initErrSymOnceFlag, _initErrorHashTable, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
@@ -109,21 +92,47 @@ static epicsUInt16 errhash(long errNum)
|
||||
|
||||
modnum = (unsigned short) (errNum >> 16);
|
||||
errnum = (unsigned short) (errNum & 0xffff);
|
||||
return (((modnum - 500) * 20) + errnum) % NHASH;
|
||||
return ((modnum - (MIN_MODULE_NUM - 1)) * 20 + errnum) % NHASH;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* ERRSYMBOLADD
|
||||
* adds symbols to the master errnumlist as compiled from errSymTbl.c
|
||||
* adds symbols to the global error symbol hash table
|
||||
***************************************************************/
|
||||
int errSymbolAdd(long errNum, const char *name)
|
||||
{
|
||||
ERRNUMNODE *pNew = (ERRNUMNODE*) callocMustSucceed(1,
|
||||
sizeof(ERRNUMNODE), "errSymbolAdd");
|
||||
ERRNUMNODE *pNextNode = NULL;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
ERRNUMNODE *pNew = NULL;
|
||||
int modnum = (epicsUInt16) (errNum >> 16);
|
||||
epicsUInt16 hashInd = errhash(errNum);
|
||||
|
||||
if (modnum < MIN_MODULE_NUM)
|
||||
return S_err_invCode;
|
||||
|
||||
initErrorHashTable();
|
||||
|
||||
epicsMutexLock(errHashTable.tableMutexId);
|
||||
phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd];
|
||||
pNextNode = (ERRNUMNODE*) *phashnode;
|
||||
|
||||
/* search for last node (NULL) of hashnode linked list */
|
||||
while (pNextNode) {
|
||||
if (pNextNode->errNum == errNum) {
|
||||
int notIdentical = strcmp(name, pNextNode->message);
|
||||
epicsMutexUnlock(errHashTable.tableMutexId);
|
||||
return notIdentical ? S_err_codeExists : 0;
|
||||
}
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
|
||||
pNew = (ERRNUMNODE*) callocMustSucceed(
|
||||
1, sizeof(ERRNUMNODE), "errSymbolAdd");
|
||||
pNew->errNum = errNum;
|
||||
pNew->message = name;
|
||||
ellAdd(&errnumlist, (ELLNODE*)pNew);
|
||||
*phashnode = pNew;
|
||||
epicsMutexUnlock(errHashTable.tableMutexId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,31 +164,31 @@ const char* errSymLookupInternal(long status)
|
||||
if (!status)
|
||||
return "Ok";
|
||||
|
||||
if (!initialized)
|
||||
errSymBld();
|
||||
initErrorHashTable();
|
||||
|
||||
modNum = (unsigned) status;
|
||||
modNum >>= 16;
|
||||
modNum &= 0xffff;
|
||||
if (modNum <= 500) {
|
||||
const char * pStr = strerror ((int) status);
|
||||
if (pStr) {
|
||||
return pStr;
|
||||
}
|
||||
if (modNum < MIN_MODULE_NUM) {
|
||||
return strerror ((int) status);
|
||||
}
|
||||
else {
|
||||
unsigned hashInd = errhash(status);
|
||||
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
|
||||
const char *result = NULL;
|
||||
epicsMutexLock(errHashTable.tableMutexId);
|
||||
phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd];
|
||||
pNextNode = *phashnode;
|
||||
while (pNextNode) {
|
||||
if (pNextNode->errNum==status){
|
||||
return pNextNode->message;
|
||||
result = pNextNode->message;
|
||||
break;
|
||||
}
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
epicsMutexUnlock(errHashTable.tableMutexId);
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* errSymMsg(long status)
|
||||
@@ -210,12 +219,12 @@ void errSymDump(void)
|
||||
int i;
|
||||
int msgcount = 0;
|
||||
|
||||
if (!initialized) errSymBld();
|
||||
initErrorHashTable();
|
||||
|
||||
msgcount = 0;
|
||||
printf("errSymDump: number of hash slots = %d\n", NHASH);
|
||||
for (i = 0; i < NHASH; i++) {
|
||||
ERRNUMNODE **phashnode = &hashtable[i];
|
||||
ERRNUMNODE **phashnode = &errHashTable.table[i];
|
||||
ERRNUMNODE *pNextNode = *phashnode;
|
||||
int count = 0;
|
||||
|
||||
@@ -246,21 +255,21 @@ void errSymTestPrint(long errNum)
|
||||
epicsUInt16 modnum;
|
||||
epicsUInt16 errnum;
|
||||
|
||||
if (!initialized) errSymBld();
|
||||
initErrorHashTable();
|
||||
|
||||
message[0] = '\0';
|
||||
modnum = (epicsUInt16) (errNum >> 16);
|
||||
errnum = (epicsUInt16) (errNum & 0xffff);
|
||||
if (modnum < 501) {
|
||||
if (modnum < MIN_MODULE_NUM) {
|
||||
fprintf(stderr, "Usage: errSymTestPrint(long errNum) \n");
|
||||
fprintf(stderr, "errSymTestPrint: module number < 501 \n");
|
||||
fprintf(stderr,
|
||||
"errSymTestPrint: module number < %d\n", MIN_MODULE_NUM);
|
||||
return;
|
||||
}
|
||||
errSymLookup(errNum, message, sizeof(message));
|
||||
if ( message[0] == '\0' ) return;
|
||||
printf("module %hu number %hu message=\"%s\"\n",
|
||||
modnum, errnum, message);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
@@ -272,10 +281,11 @@ void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
|
||||
long errNum;
|
||||
epicsUInt16 errnum;
|
||||
|
||||
if (!initialized) errSymBld();
|
||||
if (modnum < 501)
|
||||
if (modnum < MIN_MODULE_NUM)
|
||||
return;
|
||||
|
||||
initErrorHashTable();
|
||||
|
||||
/* print range of error messages */
|
||||
for (errnum = begErrNum; errnum <= endErrNum; errnum++) {
|
||||
errNum = modnum << 16;
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "libComAPI.h"
|
||||
#include "epicsTypes.h"
|
||||
|
||||
#define S_err_invCode (M_err | 1) /* Invalid error symbol code */
|
||||
#define S_err_codeExists (M_err | 2) /* Error code already exists */
|
||||
|
||||
/* ERRSYMBOL - entry in symbol table */
|
||||
typedef struct {
|
||||
long errNum; /* errMessage symbol number */
|
||||
@@ -35,13 +38,38 @@ typedef ERRSYMTAB *ERRSYMTAB_ID;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \brief Lookup message from error/status code.
|
||||
* \param status Input code
|
||||
* \param pBuf Output string buffer
|
||||
* \param bufLength Length of output buffer in bytes. Must be non-zero.
|
||||
*
|
||||
* Handles EPICS message codes, and "errno" codes.
|
||||
*
|
||||
* Copies in a mesage for any status code. Unknown status codes
|
||||
* are printed numerically.
|
||||
*/
|
||||
LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength);
|
||||
/** \brief Lookup message from error/status code.
|
||||
* \param status Input code
|
||||
* \returns A statically allocated message string. Never NULL.
|
||||
*
|
||||
* Handles EPICS message codes, and "errno" codes.
|
||||
*
|
||||
* For any unknown status codes, a generic "Unknown code" message is returned.
|
||||
*
|
||||
* \since 3.16.1
|
||||
*/
|
||||
LIBCOM_API const char* errSymMsg(long status);
|
||||
LIBCOM_API void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
|
||||
epicsUInt16 endErrNum);
|
||||
LIBCOM_API void errSymTestPrint(long errNum);
|
||||
LIBCOM_API int errSymBld(void);
|
||||
LIBCOM_API int errSymbolAdd(long errNum, const char *name);
|
||||
/** @brief Define new custom error code and associate message string.
|
||||
* @param errNum New error code. Caller is reponsible for avoiding reuse of existing codes.
|
||||
* @param message New message. Pointer stored. Caller must not free pointed storage.
|
||||
* @return 0 on success
|
||||
*/
|
||||
LIBCOM_API int errSymbolAdd(long errNum, const char *message);
|
||||
LIBCOM_API void errSymDump(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -246,7 +246,7 @@ int isATTY(FILE* fp)
|
||||
else if(fp==stderr)
|
||||
hand = GetStdHandle(STD_ERROR_HANDLE);
|
||||
#ifdef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
if(hand && GetConsoleMode(hand, &mode)) {
|
||||
if(hand!=INVALID_HANDLE_VALUE && GetConsoleMode(hand, &mode)) {
|
||||
(void)SetConsoleMode(hand, mode|ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
mode = 0u;
|
||||
if(GetConsoleMode(hand, &mode) && (mode&ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
||||
|
||||
@@ -180,8 +180,8 @@ LIBCOM_API void errlogAddListener(errlogListener listener, void *pPrivate);
|
||||
* \param listener Function pointer of type ::errlogListener
|
||||
* \param pPrivate This will be passed as the first argument of listener()
|
||||
*
|
||||
* \since UNRELEASED Safe to call from a listener callback.
|
||||
* \until UNRELEASED Self-removal from a listener callback caused corruption.
|
||||
* \since 7.0.8 Safe to call from a listener callback.
|
||||
* \until 7.0.8 Self-removal from a listener callback caused corruption.
|
||||
*/
|
||||
LIBCOM_API int errlogRemoveListeners(errlogListener listener,
|
||||
void *pPrivate);
|
||||
@@ -285,14 +285,16 @@ LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength);
|
||||
#define ANSI_ESC_MAGENTA "\033[35;1m"
|
||||
#define ANSI_ESC_CYAN "\033[36;1m"
|
||||
#define ANSI_ESC_BOLD "\033[1m"
|
||||
#define ANSI_ESC_UNDERLINE "\033[4m"
|
||||
#define ANSI_ESC_RESET "\033[0m"
|
||||
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
|
||||
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
|
||||
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
|
||||
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
|
||||
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
|
||||
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
|
||||
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
|
||||
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
|
||||
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
|
||||
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
|
||||
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
|
||||
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
|
||||
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
|
||||
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
|
||||
#define ANSI_UNDERLINE(STR) ANSI_ESC_UNDERLINE STR ANSI_ESC_RESET
|
||||
#define ERL_ERROR ANSI_RED("ERROR")
|
||||
#define ERL_WARNING ANSI_MAGENTA("WARNING")
|
||||
/** @} */
|
||||
|
||||
@@ -206,7 +206,6 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
}
|
||||
this->processInProg = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -38,10 +38,9 @@ public:
|
||||
// exceptions
|
||||
//
|
||||
class noFunctionSpecified {};
|
||||
class doubleDelete {};
|
||||
|
||||
LIBCOM_API fdRegForOldFdmgr (const SOCKET fdIn, const fdRegType type,
|
||||
const bool onceOnly, fdManager &manager, pCallBackFDMgr pFunc, void *pParam);
|
||||
LIBCOM_API fdRegForOldFdmgr (SOCKET fdIn, fdRegType type,
|
||||
bool onceOnly, fdManager &manager, pCallBackFDMgr pFunc, void *pParam);
|
||||
LIBCOM_API ~fdRegForOldFdmgr ();
|
||||
|
||||
private:
|
||||
@@ -66,7 +65,6 @@ public:
|
||||
// exceptions
|
||||
//
|
||||
class noFunctionSpecified {};
|
||||
class doubleDelete {};
|
||||
private:
|
||||
epicsTimer &timer;
|
||||
oldFdmgr &fdmgr;
|
||||
@@ -116,11 +114,7 @@ LIBCOM_API fdRegForOldFdmgr::fdRegForOldFdmgr
|
||||
}
|
||||
|
||||
LIBCOM_API fdRegForOldFdmgr::~fdRegForOldFdmgr ()
|
||||
{
|
||||
if (this->pFunc==NULL) {
|
||||
throwWithLocation ( doubleDelete () );
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
LIBCOM_API void fdRegForOldFdmgr::callBack ()
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ parse_CPPFLAGS = -DDEFAULT_SKELETON_FILE=$(SKELETON_FILE)
|
||||
|
||||
INC += flex.skel.static
|
||||
|
||||
# flex.c is included in parse.c
|
||||
# flex.c, scan.c and yylex.c are #included by parse.c
|
||||
e_flex_SRCS += ccl.c
|
||||
e_flex_SRCS += dfa.c
|
||||
e_flex_SRCS += ecs.c
|
||||
|
||||
@@ -132,7 +132,6 @@ void cclnegate(int cclp)
|
||||
void list_character_set(FILE *file, int cset[])
|
||||
{
|
||||
int i;
|
||||
char *readable_form();
|
||||
|
||||
putc( '[', file );
|
||||
|
||||
|
||||
@@ -188,7 +188,6 @@ int main(int argc, char *argv[])
|
||||
void flexend(int status)
|
||||
{
|
||||
int tblsiz;
|
||||
char *flex_gettime();
|
||||
|
||||
if ( skelfile != NULL )
|
||||
{
|
||||
@@ -382,7 +381,7 @@ void flexend(int status)
|
||||
void flexinit(int argc, char **argv)
|
||||
{
|
||||
int i, sawcmpflag;
|
||||
char *arg, *flex_gettime(), *mktemp();
|
||||
char *arg;
|
||||
|
||||
printstats = syntaxerror = trace = spprdflt = interactive = caseins = false;
|
||||
backtrack_report = performance_report = ddebug = fulltbl = fullspd = false;
|
||||
|
||||
@@ -567,8 +567,8 @@ extern int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
|
||||
extern int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
|
||||
extern int num_backtracking, bol_needed;
|
||||
|
||||
void *allocate_array(int size, int element_size);
|
||||
void *reallocate_array(void *array, int size, int element_size);
|
||||
extern void *allocate_array(int size, int element_size);
|
||||
extern void *reallocate_array(void *array, int size, int element_size);
|
||||
|
||||
#define allocate_integer_array(size) \
|
||||
(int *) allocate_array( size, sizeof( int ) )
|
||||
@@ -677,10 +677,20 @@ extern int all_upper (Char *);
|
||||
/* bubble sort an integer array */
|
||||
extern void bubble (int [], int);
|
||||
|
||||
/* replace upper-case letter to lower-case */
|
||||
extern Char clower(int c);
|
||||
|
||||
/* returns copy of a string */
|
||||
extern char *copy_string(char *str);
|
||||
|
||||
/* returns copy of a (potentially) unsigned string */
|
||||
extern Char *copy_unsigned_string(Char *str);
|
||||
|
||||
/* shell sort a character array */
|
||||
extern void cshell (Char [], int, int);
|
||||
|
||||
extern void dataend (void); /* finish up a block of data declarations */
|
||||
/* finish up a block of data declarations */
|
||||
extern void dataend (void);
|
||||
|
||||
/* report an error message and terminate */
|
||||
extern void flexerror (char[]) NORETURN;
|
||||
@@ -688,6 +698,9 @@ extern void flexerror (char[]) NORETURN;
|
||||
/* report a fatal error message and terminate */
|
||||
extern void flexfatal (char[]);
|
||||
|
||||
/* return current time */
|
||||
extern char *flex_gettime();
|
||||
|
||||
/* report an error message formatted with one integer argument */
|
||||
extern void lerrif (char[], int);
|
||||
|
||||
@@ -700,11 +713,18 @@ extern void line_directive_out (FILE*);
|
||||
/* generate a data statment for a two-dimensional array */
|
||||
extern void mk2data (int);
|
||||
|
||||
extern void mkdata (int); /* generate a data statement */
|
||||
/* generate a data statement */
|
||||
extern void mkdata (int);
|
||||
|
||||
/* return the integer represented by a string of digits */
|
||||
extern int myctoi (Char []);
|
||||
|
||||
/* return character corresponding to escape sequence */
|
||||
extern Char myesc(Char *array);
|
||||
|
||||
/* return the the human-readable form of a character */
|
||||
extern char *readable_form(int c);
|
||||
|
||||
/* write out one section of the skeleton file */
|
||||
extern void skelout (void);
|
||||
|
||||
@@ -784,8 +804,14 @@ extern void cclinstal (Char [], int);
|
||||
/* lookup the number associated with character class */
|
||||
extern int ccllookup (Char []);
|
||||
|
||||
extern void ndinstal (char[], Char[]); /* install a name definition */
|
||||
extern void scinstal (char[], int); /* make a start condition */
|
||||
/* install a name definition */
|
||||
extern void ndinstal (char[], Char[]);
|
||||
|
||||
/* lookup a name definition */
|
||||
extern Char *ndlookup(char *nd);
|
||||
|
||||
/* make a start condition */
|
||||
extern void scinstal (char[], int);
|
||||
|
||||
/* lookup the number associated with a start condition */
|
||||
extern int sclookup (char[]);
|
||||
|
||||
@@ -217,7 +217,6 @@ void genecs(void)
|
||||
int i, j;
|
||||
static char C_char_decl[] = "static const %s %s[%d] =\n { 0,\n";
|
||||
int numrows;
|
||||
Char clower();
|
||||
|
||||
if ( numecs < csize )
|
||||
printf( C_char_decl, "YY_CHAR", "yy_ec", csize );
|
||||
@@ -237,8 +236,6 @@ void genecs(void)
|
||||
|
||||
if ( trace )
|
||||
{
|
||||
char *readable_form();
|
||||
|
||||
fputs( "\n\nEquivalence Classes:\n\n", stderr );
|
||||
|
||||
numrows = csize / 8;
|
||||
|
||||
@@ -34,11 +34,18 @@
|
||||
|
||||
int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen;
|
||||
int trlcontxt, xcluflg, cclsorted, varlength, variable_trail_rule;
|
||||
Char clower();
|
||||
|
||||
static int madeany = false; /* whether we've made the '.' character class */
|
||||
int previous_continued_action; /* whether the previous rule's action was '|' */
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
void build_eof_action( void );
|
||||
void synerr( char str[] );
|
||||
void format_pinpoint_message( char msg[], char arg[] );
|
||||
void pinpoint_message( char str[] );
|
||||
void yyerror( char msg[] );
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
@@ -626,7 +633,7 @@ string : string CHAR
|
||||
* conditions
|
||||
*/
|
||||
|
||||
void build_eof_action()
|
||||
void build_eof_action( void )
|
||||
|
||||
{
|
||||
int i;
|
||||
@@ -652,8 +659,7 @@ void build_eof_action()
|
||||
|
||||
/* synerr - report a syntax error */
|
||||
|
||||
void synerr( str )
|
||||
char str[];
|
||||
void synerr( char str[] )
|
||||
|
||||
{
|
||||
syntaxerror = true;
|
||||
@@ -665,8 +671,7 @@ char str[];
|
||||
* pinpointing its location
|
||||
*/
|
||||
|
||||
void format_pinpoint_message( msg, arg )
|
||||
char msg[], arg[];
|
||||
void format_pinpoint_message( char msg[], char arg[] )
|
||||
|
||||
{
|
||||
char errmsg[MAXLINE];
|
||||
@@ -678,8 +683,7 @@ char msg[], arg[];
|
||||
|
||||
/* pinpoint_message - write out a message, pinpointing its location */
|
||||
|
||||
void pinpoint_message( str )
|
||||
char str[];
|
||||
void pinpoint_message( char str[] )
|
||||
|
||||
{
|
||||
fprintf( stderr, "\"%s\", line %d: %s\n", infilename, linenum, str );
|
||||
@@ -690,8 +694,7 @@ char str[];
|
||||
* currently, messages are ignore
|
||||
*/
|
||||
|
||||
void yyerror( msg )
|
||||
char msg[];
|
||||
void yyerror( char msg[] )
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
@@ -953,6 +953,7 @@ void yy_load_buffer_state ( void );
|
||||
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
|
||||
void yy_delete_buffer ( YY_BUFFER_STATE b );
|
||||
void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file );
|
||||
void set_input_file( char *file );
|
||||
|
||||
#define yy_new_buffer yy_create_buffer
|
||||
|
||||
@@ -966,7 +967,7 @@ YY_DECL
|
||||
static int bracelevel, didadef;
|
||||
int i, indented_code = false, checking_used = false, new_xlation = false;
|
||||
int doing_codeblock = false;
|
||||
Char nmdef[MAXLINE], myesc();
|
||||
Char nmdef[MAXLINE];
|
||||
|
||||
|
||||
if ( yy_init )
|
||||
@@ -1488,7 +1489,6 @@ case 65:
|
||||
# line 333 "scan.l"
|
||||
{
|
||||
Char *nmdefptr;
|
||||
Char *ndlookup();
|
||||
|
||||
(void) strcpy( nmstr, (char *) yytext );
|
||||
nmstr[yyleng - 1] = '\0'; /* chop trailing brace */
|
||||
@@ -2230,8 +2230,7 @@ int yywrap()
|
||||
|
||||
/* set_input_file - open the given file (if NULL, stdin) for scanning */
|
||||
|
||||
void set_input_file( file )
|
||||
char *file;
|
||||
void set_input_file( char *file )
|
||||
|
||||
{
|
||||
if ( file )
|
||||
|
||||
@@ -108,8 +108,6 @@ void cclinstal(Char *ccltxt, int cclnum)
|
||||
/* we don't bother checking the return status because we are not called
|
||||
* unless the symbol is new
|
||||
*/
|
||||
Char *copy_unsigned_string();
|
||||
|
||||
(void) addsym( (char *) copy_unsigned_string( ccltxt ), (char *) 0, cclnum,
|
||||
ccltab, CCL_HASH_SIZE );
|
||||
}
|
||||
@@ -191,9 +189,6 @@ int hashfunct(char *str, int hash_size)
|
||||
|
||||
void ndinstal(char *nd, Char *def)
|
||||
{
|
||||
char *copy_string();
|
||||
Char *copy_unsigned_string();
|
||||
|
||||
if ( addsym( copy_string( nd ), (char *) copy_unsigned_string( def ), 0,
|
||||
ndtbl, NAME_TABLE_HASH_SIZE ) )
|
||||
synerr( "name defined twice" );
|
||||
@@ -227,8 +222,6 @@ Char *ndlookup(char *nd)
|
||||
|
||||
void scinstal(char *str, int xcluflg)
|
||||
{
|
||||
char *copy_string();
|
||||
|
||||
/* bit of a hack. We know how the default start-condition is
|
||||
* declared, and don't put out a define for it, because it
|
||||
* would come out as "#define 0 1"
|
||||
|
||||
@@ -83,7 +83,6 @@ LIBCOM_API void epicsStdCall
|
||||
pfl->lock = epicsMutexMustCreate();
|
||||
*ppvt = (void *)pfl;
|
||||
VALGRIND_CREATE_MEMPOOL(pfl, REDZONE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
LIBCOM_API void * epicsStdCall freeListCalloc(void *pvt)
|
||||
|
||||
@@ -56,7 +56,6 @@ void epicsStdCall gphInitPvt(gphPvt **ppvt, int size)
|
||||
pgphPvt->paplist = callocMustSucceed(size, sizeof(ELLLIST *), "gphInitPvt");
|
||||
pgphPvt->lock = epicsMutexMustCreate();
|
||||
*ppvt = pgphPvt;
|
||||
return;
|
||||
}
|
||||
|
||||
GPHENTRY * epicsStdCall gphFindParse(gphPvt *pgphPvt, const char *name, size_t len, void *pvtid)
|
||||
@@ -64,7 +63,7 @@ GPHENTRY * epicsStdCall gphFindParse(gphPvt *pgphPvt, const char *name, size_t l
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *gphlist;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
unsigned hash;
|
||||
|
||||
if (pgphPvt == NULL) return NULL;
|
||||
paplist = pgphPvt->paplist;
|
||||
@@ -100,7 +99,7 @@ GPHENTRY * epicsStdCall gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
unsigned hash;
|
||||
|
||||
if (pgphPvt == NULL) return NULL;
|
||||
paplist = pgphPvt->paplist;
|
||||
@@ -145,7 +144,7 @@ void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist = NULL;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
unsigned hash;
|
||||
|
||||
if (pgphPvt == NULL) return;
|
||||
paplist = pgphPvt->paplist;
|
||||
@@ -171,7 +170,6 @@ void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
}
|
||||
|
||||
epicsMutexUnlock(pgphPvt->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
void epicsStdCall gphFreeMem(gphPvt *pgphPvt)
|
||||
|
||||
@@ -139,9 +139,13 @@ const char *initHookName(int state)
|
||||
"initHookBeforeFree",
|
||||
"initHookAfterShutdown",
|
||||
|
||||
"initHookAfterPrepareDatabase",
|
||||
"initHookBeforeCleanupDatabase",
|
||||
|
||||
"initHookAfterInterruptAccept",
|
||||
"initHookAtEnd"
|
||||
};
|
||||
STATIC_ASSERT(NELEMENTS(stateName)==initHookAtEnd+1);
|
||||
if (state < 0 || state >= NELEMENTS(stateName)) {
|
||||
return "Not an initHookState";
|
||||
}
|
||||
|
||||
@@ -8,42 +8,44 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/**
|
||||
* \file initHooks.h
|
||||
/** @page inithooks IOC lifecycle callback hooks.
|
||||
*
|
||||
* \author Benjamin Franksen (BESSY)
|
||||
* \author Marty Kraimer (ANL)
|
||||
* initHookRegister() allows external code to be called at certains points (initHookState)
|
||||
* during IOC startup and shutdown.
|
||||
*
|
||||
* \brief Facility to call functions during iocInit()
|
||||
* The overall states (see getIocState() ) of an IOC are:
|
||||
*
|
||||
* The initHooks facility allows application functions to be called at various
|
||||
* stages/states during IOC initialization, pausing, restart and shutdown.
|
||||
*
|
||||
* All registered application functions will be called whenever the IOC
|
||||
* initialization, pause/resume or shutdown process reaches a new state.
|
||||
* - Void
|
||||
* - From process start until iocInit()
|
||||
* - After iocShutdown()
|
||||
* - Building
|
||||
* - Transiant state during iocInit()
|
||||
* - Built
|
||||
* - Transiant state during iocInit()
|
||||
* - Running
|
||||
* - After iocInit() or iocRun()
|
||||
* - Paused
|
||||
* - After iocPause()
|
||||
*
|
||||
* The following C++ example shows how to use this facility:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* #include <initHooks.h>
|
||||
* #include <epicsExport.h>
|
||||
* static void myHookFunction(initHookState state)
|
||||
* {
|
||||
* switch (state) {
|
||||
* case initHookAfterInitRecSup:
|
||||
* ...
|
||||
* break;
|
||||
* case initHookAfterDatabaseRunning:
|
||||
* ...
|
||||
* break;
|
||||
* default:
|
||||
* break;
|
||||
* if(state == initHookAfterDatabaseRunning) {
|
||||
* // a good point for driver worker threads to be started.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // A static constructor registers hook function at startup:
|
||||
* static int myHookStatus = initHookRegister(myHookFunction);
|
||||
* static void myRegistrar(void) {
|
||||
* initHookRegister(&myHookFunction);
|
||||
* }
|
||||
* extern "C" {
|
||||
* epicsExportRegistrar(myRegistrar);
|
||||
* }
|
||||
* // in some .dbd file add "registrar(myRegistrar)".
|
||||
* \endcode
|
||||
*
|
||||
* An arbitrary number of functions can be registered.
|
||||
*/
|
||||
|
||||
|
||||
@@ -69,41 +71,85 @@ extern "C" {
|
||||
* if the IOC is later paused and restarted.
|
||||
*/
|
||||
typedef enum {
|
||||
|
||||
// iocInit() begins
|
||||
initHookAtIocBuild = 0, /**< Start of iocBuild() / iocInit() */
|
||||
initHookAtBeginning, /**< Database sanity checks passed */
|
||||
initHookAfterCallbackInit, /**< Callbacks, generalTime & taskwd init */
|
||||
initHookAfterCaLinkInit, /**< CA links init */
|
||||
initHookAfterInitDrvSup, /**< Driver support init */
|
||||
initHookAfterInitRecSup, /**< Record support init */
|
||||
initHookAfterInitDevSup, /**< Device support init pass 0 */
|
||||
initHookAfterInitDatabase, /**< Records and locksets init */
|
||||
initHookAfterInitDevSup, /**< Device support init pass 0 (also autosave pass 0) */
|
||||
initHookAfterInitDatabase, /**< Records and locksets init (also autosave pass 1) */
|
||||
initHookAfterFinishDevSup, /**< Device support init pass 1 */
|
||||
initHookAfterScanInit, /**< Scan, AS, ProcessNotify init */
|
||||
initHookAfterInitialProcess, /**< Records with PINI = YES processsed */
|
||||
initHookAfterCaServerInit, /**< RSRV init */
|
||||
initHookAfterIocBuilt, /**< End of iocBuild() */
|
||||
|
||||
// iocInit() continues, and iocRun() begins
|
||||
initHookAtIocRun, /**< Start of iocRun() */
|
||||
initHookAfterDatabaseRunning, /**< Scan tasks and CA links running */
|
||||
initHookAfterCaServerRunning, /**< RSRV running */
|
||||
initHookAfterIocRunning, /**< End of iocRun() / iocInit() */
|
||||
// iocInit() or iocRun() ends
|
||||
|
||||
// iocPause() begins
|
||||
initHookAtIocPause, /**< Start of iocPause() */
|
||||
initHookAfterCaServerPaused, /**< RSRV paused */
|
||||
initHookAfterDatabasePaused, /**< CA links and scan tasks paused */
|
||||
initHookAfterIocPaused, /**< End of iocPause() */
|
||||
// iocPause() ends
|
||||
|
||||
initHookAtShutdown, /**< Start of iocShutdown() (unit tests only) */
|
||||
initHookAfterCloseLinks, /**< Links disabled/deleted */
|
||||
initHookAfterStopScan, /**< Scan tasks stopped. Prior to UNRELEASED, triggered only by unittest code. */
|
||||
initHookAfterStopCallback, /**< Callback tasks stopped */
|
||||
initHookAfterStopLinks, /**< CA links stopped. Prior to UNRELEASED, triggered only by unittest code. */
|
||||
initHookBeforeFree, /**< Resource cleanup about to happen */
|
||||
initHookAfterShutdown, /**< End of iocShutdown() */
|
||||
// iocShutdown() begins
|
||||
/** \brief Start of iocShutdown() (unit tests only)
|
||||
* \since 7.0.3.1 Added
|
||||
*/
|
||||
initHookAtShutdown,
|
||||
/** \brief Links disabled/deleted
|
||||
* \since 7.0.3.1 Added
|
||||
*/
|
||||
initHookAfterCloseLinks,
|
||||
/** \brief Scan tasks stopped.
|
||||
* \since 7.0.8 Triggered during normal IOC shutdown
|
||||
* \since 7.0.3.1 Added, triggered only by unittest code.
|
||||
*/
|
||||
initHookAfterStopScan,
|
||||
/** \brief Callback tasks stopped
|
||||
* \since 7.0.3.1 Added
|
||||
*/
|
||||
initHookAfterStopCallback,
|
||||
/** \brief CA links stopped.
|
||||
* \since 7.0.8 Triggered during normal IOC shutdown
|
||||
* \since 7.0.3.1 Added, triggered only by unittest code.
|
||||
*/
|
||||
initHookAfterStopLinks,
|
||||
/** \brief Resource cleanup about to happen
|
||||
* \since 7.0.3.1 Added
|
||||
*/
|
||||
initHookBeforeFree,
|
||||
/** \brief End of iocShutdown()
|
||||
* \since 7.0.3.1 Added
|
||||
*/
|
||||
initHookAfterShutdown,
|
||||
// iocShutdown() ends
|
||||
|
||||
/** \brief Called during testdbPrepare()
|
||||
* Use this hook to repeat actions each time an empty test database is initialized.
|
||||
* \since 7.0.8 Added, triggered only by unittest code.
|
||||
*/
|
||||
initHookAfterPrepareDatabase,
|
||||
/** \brief Called during testdbCleanup()
|
||||
* Use this hook to perform cleanup each time before a test database is free()'d.
|
||||
* \since 7.0.8 Added, triggered only by unittest code.
|
||||
*/
|
||||
initHookBeforeCleanupDatabase,
|
||||
|
||||
/* Deprecated states: */
|
||||
initHookAfterInterruptAccept, /**< After initHookAfterDatabaseRunning */
|
||||
initHookAtEnd, /**< Before initHookAfterIocRunning */
|
||||
/** Only announced once. Deprecated in favor of initHookAfterDatabaseRunning */
|
||||
initHookAfterInterruptAccept,
|
||||
/** Only announced once. Deprecated in favor of initHookAfterIocRunning */
|
||||
initHookAtEnd,
|
||||
} initHookState;
|
||||
|
||||
/** \brief Type for application callback functions
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -43,6 +44,7 @@
|
||||
|
||||
#if EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_READLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
# define USE_READLINE
|
||||
/* libedit also provides readline.h, but isn't fully compatible with
|
||||
* GNU readline. It also doesn't specifically identify itself.
|
||||
@@ -84,9 +86,10 @@ static struct iocshVariable *iocshVariableHead;
|
||||
static char iocshVarID[] = "iocshVar";
|
||||
extern "C" { static void varCallFunc(const iocshArgBuf *); }
|
||||
static epicsMutexId iocshTableMutex;
|
||||
static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT;
|
||||
static epicsThreadPrivateId iocshContextId;
|
||||
|
||||
static void iocshInit (void);
|
||||
|
||||
/*
|
||||
* I/O redirection
|
||||
*/
|
||||
@@ -121,20 +124,6 @@ struct iocshRedirect {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/*
|
||||
* Set up module variables
|
||||
*/
|
||||
static void iocshOnce (void *)
|
||||
{
|
||||
iocshTableMutex = epicsMutexMustCreate ();
|
||||
iocshContextId = epicsThreadPrivateCreate();
|
||||
}
|
||||
|
||||
static void iocshInit (void)
|
||||
{
|
||||
epicsThreadOnce (&iocshOnceId, iocshOnce, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the table mutex
|
||||
*/
|
||||
@@ -157,19 +146,18 @@ iocshTableUnlock (void)
|
||||
/*
|
||||
* Register a command
|
||||
*/
|
||||
void epicsStdCall iocshRegister (const iocshFuncDef *piocshFuncDef,
|
||||
static
|
||||
void iocshRegisterImpl (const iocshFuncDef *piocshFuncDef,
|
||||
iocshCallFunc func)
|
||||
{
|
||||
struct iocshCommand *l, *p, *n;
|
||||
int i;
|
||||
|
||||
iocshTableLock ();
|
||||
for (l = NULL, p = iocshCommandHead ; p != NULL ; l = p, p = p->next) {
|
||||
i = strcmp (piocshFuncDef->name, p->def.pFuncDef->name);
|
||||
if (i == 0) {
|
||||
p->def.pFuncDef = piocshFuncDef;
|
||||
p->def.func = func;
|
||||
iocshTableUnlock ();
|
||||
return;
|
||||
}
|
||||
if (i < 0)
|
||||
@@ -179,7 +167,6 @@ void epicsStdCall iocshRegister (const iocshFuncDef *piocshFuncDef,
|
||||
"iocshRegister");
|
||||
if (!registryAdd(iocshCmdID, piocshFuncDef->name, (void *)n)) {
|
||||
free (n);
|
||||
iocshTableUnlock ();
|
||||
errlogPrintf ("iocshRegister failed to add %s\n", piocshFuncDef->name);
|
||||
return;
|
||||
}
|
||||
@@ -193,10 +180,15 @@ void epicsStdCall iocshRegister (const iocshFuncDef *piocshFuncDef,
|
||||
}
|
||||
n->def.pFuncDef = piocshFuncDef;
|
||||
n->def.func = func;
|
||||
iocshTableUnlock ();
|
||||
}
|
||||
|
||||
|
||||
void epicsStdCall iocshRegister (const iocshFuncDef *piocshFuncDef,
|
||||
iocshCallFunc func)
|
||||
{
|
||||
iocshTableLock ();
|
||||
iocshRegisterImpl (piocshFuncDef, func);
|
||||
iocshTableUnlock ();
|
||||
}
|
||||
/*
|
||||
* Retrieves a previously registered function with the given name.
|
||||
*/
|
||||
@@ -212,7 +204,7 @@ showError (const char *filename, int lineno, const char *msg, ...)
|
||||
|
||||
va_start (ap, msg);
|
||||
if (filename)
|
||||
fprintf(epicsGetStderr(), "%s line %d: ", filename, lineno);
|
||||
fprintf(epicsGetStderr(), ERL_ERROR " %s line %d: ", filename, lineno);
|
||||
vfprintf (epicsGetStderr(), msg, ap);
|
||||
fputc ('\n', epicsGetStderr());
|
||||
va_end (ap);
|
||||
@@ -643,6 +635,15 @@ struct ReadlineContext {
|
||||
rl_completer_quote_characters = (char*)"\"";
|
||||
rl_attempted_completion_function = &iocsh_attempt_completion;
|
||||
rl_bind_key('\t', rl_complete);
|
||||
compute_hist_file();
|
||||
if(!hist_file.empty()) {
|
||||
if(int err = read_history(hist_file.c_str())) {
|
||||
if(err!=ENOENT)
|
||||
fprintf(stderr, ERL_ERROR " %s (%d) loading '%s'\n",
|
||||
strerror(err), err, hist_file.c_str());
|
||||
}
|
||||
stifle_history(1024); // some limit...
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return context;
|
||||
@@ -651,6 +652,12 @@ struct ReadlineContext {
|
||||
~ReadlineContext() {
|
||||
if(context) {
|
||||
#ifdef USE_READLINE
|
||||
if(!hist_file.empty()) {
|
||||
if(int err = write_history(hist_file.c_str())) {
|
||||
fprintf(stderr, ERL_ERROR " %s (%d) writing '%s'\n",
|
||||
strerror(err), err, hist_file.c_str());
|
||||
}
|
||||
}
|
||||
rl_readline_name = prev_rl_readline_name;
|
||||
rl_basic_word_break_characters = prev_rl_basic_word_break_characters;
|
||||
rl_completer_word_break_characters = prev_rl_completer_word_break_characters;
|
||||
@@ -663,6 +670,26 @@ struct ReadlineContext {
|
||||
epicsReadlineEnd(context);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_READLINE
|
||||
std::string hist_file;
|
||||
|
||||
void compute_hist_file() {
|
||||
std::string scratch;
|
||||
if(const char *env = getenv("EPICS_IOCSH_HISTFILE")) {
|
||||
scratch = env;
|
||||
} else {
|
||||
scratch = ".iocsh_history";
|
||||
}
|
||||
const char *home = getenv("HOME");
|
||||
if(home && scratch.size()>=2 && scratch[0]=='~' && scratch[1]=='/') {
|
||||
std::ostringstream strm;
|
||||
strm<<home<<'/'<<scratch.substr(2);
|
||||
scratch = strm.str();
|
||||
}
|
||||
hist_file.swap(scratch);
|
||||
}
|
||||
#endif // USE_READLINE
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -765,6 +792,13 @@ void epicsStdCall iocshFree(void)
|
||||
iocshTableUnlock ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse argument input based on the arg type specified.
|
||||
* It is worth noting that depending on type this argument may
|
||||
* be defaulted if a value is not specified. For example, a
|
||||
* double/int with no value will default to 0 which may allow
|
||||
* you to add optional arguments to the end of your argument list.
|
||||
*/
|
||||
static int
|
||||
cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
|
||||
const iocshArg *piocshArg)
|
||||
@@ -898,15 +932,19 @@ static void helpCallFunc(const iocshArgBuf *args)
|
||||
"Type 'help <command>' to see the arguments of <command>. eg. 'help db*'\n");
|
||||
}
|
||||
else {
|
||||
bool firstFunction = true;
|
||||
for (int iarg = 1 ; iarg < argc ; iarg++) {
|
||||
for (pcmd = iocshCommandHead ; pcmd != NULL ; pcmd = pcmd->next) {
|
||||
piocshFuncDef = pcmd->def.pFuncDef;
|
||||
if (epicsStrGlobMatch(piocshFuncDef->name, argv[iarg]) != 0) {
|
||||
if(piocshFuncDef->usage) {
|
||||
fputs("\nUsage: ", epicsGetStdout());
|
||||
|
||||
if (! firstFunction) {
|
||||
fprintf(epicsGetStdout(),
|
||||
ANSI_UNDERLINE(" \n"));
|
||||
}
|
||||
|
||||
fprintf(epicsGetStdout(),
|
||||
ANSI_BOLD("%s"),
|
||||
ANSI_BOLD("\n%s"),
|
||||
piocshFuncDef->name);
|
||||
|
||||
for (int a = 0 ; a < piocshFuncDef->nargs ; a++) {
|
||||
@@ -919,11 +957,14 @@ static void helpCallFunc(const iocshArgBuf *args)
|
||||
fprintf(epicsGetStdout(), " '%s'", cp);
|
||||
}
|
||||
}
|
||||
fprintf(epicsGetStdout(),"\n");;
|
||||
fprintf(epicsGetStdout(),"\n");
|
||||
if(piocshFuncDef->usage) {
|
||||
fprintf(epicsGetStdout(), "\n%s", piocshFuncDef->usage);
|
||||
}
|
||||
|
||||
firstFunction = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1393,12 +1434,12 @@ static void varCallFunc(const iocshArgBuf *args)
|
||||
found = 1;
|
||||
}
|
||||
if (!found && name != NULL)
|
||||
fprintf(epicsGetStderr(), "No var matching %s found.\n", name);
|
||||
fprintf(epicsGetStderr(), ANSI_RED("No var matching") " %s found.\n", name);
|
||||
}
|
||||
else {
|
||||
v = (iocshVariable *)registryFind(iocshVarID, args[0].sval);
|
||||
if (v == NULL) {
|
||||
fprintf(epicsGetStderr(), "Var %s not found.\n", name);
|
||||
fprintf(epicsGetStderr(), "Var %s " ANSI_RED("not found.") "\n", name);
|
||||
}
|
||||
else {
|
||||
varHandler(v->pVarDef, value);
|
||||
@@ -1451,7 +1492,7 @@ static const iocshFuncDef onFuncDef = {"on", 1, onArgs,
|
||||
" continue (default) - Ignores error and continue with next commands.\n"
|
||||
" break - Return to caller without executing futher commands.\n"
|
||||
" halt - Suspend process.\n"
|
||||
" wait - stall process for [value] seconds, the continue.\n"};
|
||||
" wait - stall process for [value] seconds, then continue.\n"};
|
||||
static void onCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshContext *context = (iocshContext *) epicsThreadPrivateGet(iocshContextId);
|
||||
@@ -1523,24 +1564,25 @@ static void exitCallFunc(const iocshArgBuf *)
|
||||
{
|
||||
}
|
||||
|
||||
static void localRegister (void)
|
||||
static void iocshOnce (void *)
|
||||
{
|
||||
iocshRegister(&commentFuncDef,commentCallFunc);
|
||||
iocshRegister(&exitFuncDef,exitCallFunc);
|
||||
iocshRegister(&helpFuncDef,helpCallFunc);
|
||||
iocshRegister(&iocshCmdFuncDef,iocshCmdCallFunc);
|
||||
iocshRegister(&iocshLoadFuncDef,iocshLoadCallFunc);
|
||||
iocshRegister(&iocshRunFuncDef,iocshRunCallFunc);
|
||||
iocshRegister(&onFuncDef, onCallFunc);
|
||||
iocshTableMutex = epicsMutexMustCreate ();
|
||||
iocshContextId = epicsThreadPrivateCreate();
|
||||
epicsMutexMustLock (iocshTableMutex);
|
||||
iocshRegisterImpl(&commentFuncDef,commentCallFunc);
|
||||
iocshRegisterImpl(&exitFuncDef,exitCallFunc);
|
||||
iocshRegisterImpl(&helpFuncDef,helpCallFunc);
|
||||
iocshRegisterImpl(&iocshCmdFuncDef,iocshCmdCallFunc);
|
||||
iocshRegisterImpl(&iocshLoadFuncDef,iocshLoadCallFunc);
|
||||
iocshRegisterImpl(&iocshRunFuncDef,iocshRunCallFunc);
|
||||
iocshRegisterImpl(&onFuncDef, onCallFunc);
|
||||
iocshTableUnlock();
|
||||
}
|
||||
|
||||
static void iocshInit (void)
|
||||
{
|
||||
static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT;
|
||||
epicsThreadOnce (&iocshOnceId, iocshOnce, NULL);
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
/*
|
||||
* Register local commands on application startup
|
||||
*/
|
||||
class IocshRegister {
|
||||
public:
|
||||
IocshRegister() { localRegister(); }
|
||||
};
|
||||
static IocshRegister iocshRegisterObj;
|
||||
|
||||
@@ -66,12 +66,16 @@ typedef enum {
|
||||
iocshArgPdbbase,
|
||||
iocshArgArgv,
|
||||
iocshArgPersistentString,
|
||||
/** Equivalent to iocshArgString with a hint for tab completion as a record name.
|
||||
* @since UNRELEASED
|
||||
/**
|
||||
* Equivalent to iocshArgString with a hint for tab completion that the
|
||||
* argument is a record name.
|
||||
* @since 7.0.8
|
||||
*/
|
||||
iocshArgStringRecord,
|
||||
/** Equivalent to iocshArgString with a hint for tab completion as a file system path.
|
||||
* @since UNRELEASED
|
||||
/**
|
||||
* Equivalent to iocshArgString with a hint for tab completion that the
|
||||
* argument is a file system path.
|
||||
* @since 7.0.8
|
||||
*/
|
||||
iocshArgStringPath,
|
||||
}iocshArgType;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user