Compare commits

...

68 Commits

Author SHA1 Message Date
e9dcdd8936 do not set EPICS_BASE as that changes the default EPICS version chosen by iocsh and takes precedence over the /usr/local/epics/base link
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 1s
Base / Cross linux-aarch64 (push) Failing after 2s
Base / Cross linux-arm gnueabi (push) Failing after 1s
Base / Cross linux-arm gnueabihf (push) Failing after 2s
Base / CentOS-7 (push) Failing after 1s
Base / Fedora-33 (push) Failing after 2s
Base / Fedora-latest (push) Failing after 1s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
2024-01-29 17:07:43 +01:00
e2bb42d8d3 obsolete caRepeater rpm
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 2s
Base / Cross linux-aarch64 (push) Failing after 1s
Base / Cross linux-arm gnueabi (push) Failing after 2s
Base / Cross linux-arm gnueabihf (push) Failing after 1s
Base / CentOS-7 (push) Failing after 2s
Base / Fedora-33 (push) Failing after 1s
Base / Fedora-latest (push) Failing after 2s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
2023-12-10 13:47:17 +01:00
abcada0d85 add rpm specfile and profile script
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 1s
Base / Cross linux-aarch64 (push) Failing after 2s
Base / Cross linux-arm gnueabi (push) Failing after 1s
Base / Cross linux-arm gnueabihf (push) Failing after 2s
Base / CentOS-7 (push) Failing after 1s
Base / Fedora-33 (push) Failing after 2s
Base / Fedora-latest (push) Failing after 1s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
2023-12-08 15:32:20 +01:00
2c35d60a64 silent wine errors 2023-12-08 11:38:38 +01:00
af1b77eb0f fix rpath when FINAL_LOCATION is set 2023-12-07 16:07:02 +01:00
93947eb027 prevents using make -j2 2023-12-06 14:24:56 +01:00
961671259f Add support for RHEL9 2023-12-04 16:00:24 +01:00
Michael Davidsaver
db2482117d rationalize osdMutex
Avoids split allocation.
Eliminates special case free-list.

win32: eliminate pre-XP
rtems-score: eliminate non-fast
2023-12-04 11:04:51 +01:00
a66caa5985 move cross compilers away from AFS 2023-12-04 10:08:47 +01:00
4803aae904 re-enable alternative PowerPMAC archs 2023-12-01 16:52:41 +01:00
427be18e2e upgrade cross windows build to use mvsc 2019 on Linux archs that support it 2023-12-01 16:52:41 +01:00
fff690a449 skip Microsoft noise in rc 2023-12-01 16:52:41 +01:00
428b836500 switch to 64 bit raspbian cross compiler 2023-12-01 16:52:41 +01:00
6c74507b11 all our current host OS can build nilrt7-armv7a 2023-12-01 16:52:40 +01:00
122ca4e1d3 change PROC to ASL0 2023-12-01 16:51:49 +01:00
Ralph Lange
ba1bf00ce7 Use split() for fetching last tag with darcs
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 2s
Base / Cross linux-aarch64 (push) Failing after 1s
Base / Cross linux-arm gnueabi (push) Failing after 2s
Base / Cross linux-arm gnueabihf (push) Failing after 1s
Base / CentOS-7 (push) Failing after 2s
Base / Fedora-33 (push) Failing after 1s
Base / Fedora-latest (push) Failing after 2s
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
(setting $/='' breaks reading multi-line into an array)
2023-12-01 16:50:24 +01:00
Érico Nogueira
68fea5c2ca Set ASL0 for mbboDirect Bx fields.
Since the record's VAL field is ASL0, it doesn't make sense to gate
writes into the Bx fields with ASL1.
2023-12-01 16:49:41 +01:00
Michael Davidsaver
3f03efe7fe Add ERROR to error messages 2023-12-01 16:49:30 +01:00
Michael Davidsaver
98dc97022a const-ify dbLink arrays
external code really should never be modifying pamaplinkType[]
2023-12-01 16:49:18 +01:00
Uchenna Ezeobi
5d01b637a7 Config: Fixed Hard coded LDFLAGS in MVME2500 2023-12-01 16:49:03 +01:00
Michael Davidsaver
69a184ee1d update submodules 2023-12-01 16:48:54 +01:00
Michael Davidsaver
aebacff3db release notes 2023-12-01 16:48:45 +01:00
Michael Davidsaver
27ad623d68 bi "Raw Soft Channel" use MASK
If set, apply MASK to value read into RVAL.
2023-12-01 16:48:06 +01:00
Michael Davidsaver
1b23701946 incorrect error check on GetStdHandle()
Likely inconsequential as GetConsoleMode() should
return 0 when given an invalid handle.
2023-12-01 16:47:45 +01:00
Michael Davidsaver
0502fe25e4 print ANSI escapes to stderr
unconditionally print ANSI some escapes (to colorize errors)
to the stderr stream.
2023-12-01 16:47:18 +01:00
Michael Davidsaver
77a37781af colorize more errlog messages 2023-12-01 16:38:54 +01:00
Jeremy Lorelli
ba21e655df Null check callback function in callbackRequest
Previously, calling callbackRequest(pcallback), where pcallback->callback
is NULL, would result in a crash on one of the callback threads.
2023-12-01 16:36:43 +01:00
Michael Davidsaver
2e727a0262 update ci-scripts 2023-12-01 16:36:35 +01:00
Michael Davidsaver
f4cb31d5d5 dbRecordField() add "did you mean..." hint for unknown field 2023-12-01 16:36:24 +01:00
Michael Davidsaver
ab4e687816 const-ify dbCopyEntry() and dbCopyEntryContents() 2023-12-01 16:36:12 +01:00
Michael Davidsaver
1d1926eaf3 avoid hang during concurrent db_cancel_event()
cf. fab8fd7102
2023-12-01 16:36:03 +01:00
Michael Davidsaver
d31ba6ade3 doc 2023-12-01 16:35:55 +01:00
609147dad0 gha: turn most warnings into errors in github build 2023-12-01 16:35:46 +01:00
Michael Davidsaver
5a5535aa5b iocsh: keep history file 2023-12-01 16:35:36 +01:00
JJL772
de61390049 Com: Make STATIC_ASSERT macro typedefs unique 2023-12-01 16:35:29 +01:00
Michael Davidsaver
304d8217d9 dbRecordsOnceOnly allow append only with "*"
with

> record(ai, "myrec") {}

dbRecordsOnceOnly!=0 currently disallows appending fields with either form:

> record("*", "myrec") {} # error
> record(ai, "myrec") {}  # error

Change the meaning such that dbRecordsOnceOnly!=0
allways allows appending when explicitly intended (rtype "*").

> record("*", "myrec") {} # allowed
> record(ai, "myrec") {}  # error

Also clearly label this parse error.
2023-12-01 16:35:18 +01:00
Jack Harper
2c95dc91e9 iocsh: add comment to cvtArg explaining default iocsharg behaviour 2023-12-01 16:34:35 +01:00
Michael Davidsaver
8cc15c6e68 remove unused local 2023-12-01 16:34:24 +01:00
AlexWells
680e1734a4 iocsh: Add underline separator between help outputs
Also tweaks the overall format of the message a bit.
Add tests for new help output format
2023-12-01 16:34:04 +01:00
4aea7de032 update modules/pvData 2023-12-01 16:33:42 +01:00
Michael Davidsaver
bddbc38e0b update ci-scripts 2023-12-01 16:28:58 +01:00
Jeremy Lorelli
67e669c5e5 libCom: Fix buggy pointer dereference in postfix() 2023-12-01 16:02:34 +01:00
Michael Davidsaver
e291ca0a03 Fix compile w/ vs2012 2023-12-01 15:04:24 +01:00
Emilio Perez
5b84a86ccd Allow adding error symbols after early initialization
This was acomplished by making errSymbolAdd add the error symbol directly
into the global hash table and removing errnumlist which is not needed
anymore.

Unit tests were added for checking the following cases:
- Adding a valid symbol and checking that it exists (fixed by this change)
- Getting an existing error symbol
- Getting a non existing error symbol
- Adding an invalid error symbol (fixed by this change)
- Adding an error symbol with a code that already
  exists (fixed by this change)

Therefore, issue #268 was fixed

error: statically allocate error symbol hash table

This will allow calling errSymbolAdd before errSymBld, therefore, a
function adding error symbols can now be run before iocInit or errlogInit

error: add a constant for the minimum module number

Make adding an identical error symbol not fail

A test case was also added which test that adding an error symbol
with same error code and message as one added before will not fail

Add locking to error symbol table

This protects the cases of:
- simultaneously adding and requesting of an error symbol
- simultaneously adding many error symbols

Update release notes regarding adding error symbols
2023-12-01 15:03:00 +01:00
Michael Davidsaver
cb6442da71 epicsThreadShow() zombies
Flag when the thread has returned, but the tracking
struct is still around.  eg. in need of joining.
2023-12-01 15:01:10 +01:00
Érico Nogueira
49b9573f3a libCom: detect support for backtrace() with __has_include.
This is necessary in order to build epics-base with musl libc, for
example, and any other C libraries which don't include this
functionality. In order to not regress builds with older compilers, we
still support the uclibc check. Furthermore, it has been checked that
uclibc-ng (the maintained version of uclibc) doesn't install the
<execinfo.h> header when the functionality is disabled [1] [2].

To avoid repetition, we don't define HAS_EXECINFO to 0 when it is not
available.

[1] https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Makefile.in?id=cdb07d2cd52af39feb425e6d36c02b30916b9f0a#n224
[2] https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Makefile.in?id=cdb07d2cd52af39feb425e6d36c02b30916b9f0a#n277
2023-12-01 15:01:01 +01:00
Michael Davidsaver
42dfca2b54 dbEvent: handle multiple db_event_cancel()
Allow for multiple db_event_cancel() (concurrent or
self-cancel) prior to event_task wakeup.

In db_event_cancel(), immediate free() only if idle
(not queued or in progress).  Otherwise, defer free()
to event task.  Avoids need to immediately expunge
canceled event from queue.  Allow event task to
process canceled events as normal (except no user_sub)
until npend==0.
2023-12-01 15:00:51 +01:00
Michael Davidsaver
3fd79a21a2 privatize evSubscrip 2023-12-01 15:00:34 +01:00
Michael Davidsaver
12f311b780 dbEvent minor 2023-12-01 15:00:16 +01:00
Michael Davidsaver
8abc9f8d03 minor 2023-12-01 15:00:08 +01:00
Michael Davidsaver
ae6f01b8ee doc dbLock.h 2023-12-01 14:59:56 +01:00
1d3a2defa2 Merge 7.0 commit 'ca9c95' into PSI-7.0 2023-12-01 14:21:07 +01:00
Michael Davidsaver
ca9c957e62 doc add page for initHooks.h 2023-09-05 08:53:40 +02:00
Michael Davidsaver
8488c9e891 initHookName() assert length
basic compile time consistency check.
2023-09-05 08:53:07 +02:00
Michael Davidsaver
1f2edb69d2 silence -Wformat-security for printfRecord
we know what we are doing... right?
2023-09-05 08:53:03 +02:00
Michael Davidsaver
fe3ee85aee doc errSymTbl.h 2023-09-05 08:52:58 +02:00
Michael Davidsaver
a74789d9c0 db: decimate and sync filters don't drop DBE_PROPERTY 2023-08-28 14:17:00 +02:00
Michael Davidsaver
7830345e59 move IocshRegister() to iocshInit()
No need for both global ctor and lazy init
2023-08-28 14:17:00 +02:00
Michael Davidsaver
1595ed8860 quieting clang-tidy, non-functional changes
Changes to syntax which should not effect generated code
2023-08-28 14:17:00 +02:00
Michael Davidsaver
d97943b697 timerPrivate.h: mark override/final
Clarify the class hierarchy by decorating types and
method override and/or final whenever possible.
Does not change the hierarchy.
2023-08-28 14:17:00 +02:00
Michael Davidsaver
f8f4376594 ~fdRegForOldFdmgr() can't throw doubleDelete
Exceptions can't actually be thrown from a
C++ class destructor.
2023-08-28 14:17:00 +02:00
Érico Nogueira
df397f4ade fix typo in boRecord.dbd.pod 2023-08-28 14:17:00 +02:00
Zainab Olalekan
7fd690e53e Fix libcom test failure on RTEMS 2023-08-28 14:17:00 +02:00
Andrew Johnson
bc5d347bb2 Call perror() before close(), add detail to messages 2023-08-28 14:17:00 +02:00
Chris Johns
3ea29f581b rtems: Close NTP socket 2023-08-28 14:17:00 +02:00
AlexWells
6de82bb0fd Additional help messages for iocsh
Henrique Silva <henrique.silva@ess.eu>
2023-08-28 13:24:16 +02:00
e1a51e2839 extra parentheses around second sizeof to silence "does not compute number of elements" warning 2023-08-28 13:24:16 +02:00
Michael Davidsaver
0f59d823d3 appveyor remove skip_commits: 2023-08-28 13:24:16 +02:00
129 changed files with 1904 additions and 1050 deletions

2
.ci

Submodule .ci updated: 1e0e326f74...130e88b709

View File

@@ -51,6 +51,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

3
.gitignore vendored
View File

@@ -17,3 +17,6 @@ O.*/
*.log
.*.swp
.DS_Store
.iocsh_history
RPMS
SRPMS

View File

@@ -30,3 +30,6 @@ copysrc:
tar:
tar cfjP epics_base-$(EPICS_VERSION_NUMBER).tar.bz2 $(INSTALL_LOCATION)
rpm:
rpmbuild -bb epics-base.spec

View File

@@ -0,0 +1,18 @@
# Include definitions common to linux pentium targets
include $(CONFIG)/os/CONFIG.Common.linux-x86_64
TOOLSET_LOCATION = /opt/rh
TOOLSET = gcc-toolset-12
STD_CXXFLAGS = -std=c++20
# Fix bug in gcc-toolset-11 calling the old assembler
ifneq ($(filter %-11,$(TOOLSET)),)
TARGET_CPPFLAGS += $(TOOLSET_DIR:%=-B$(SYSROOT)%/bin)
TARGET_LDFLAGS += $(TOOLSET_DIR:%=-B$(SYSROOT)%/bin)
endif
ifneq (($(TOOLSET)),)
# Perl requests (native) annobin incompatible with the annobin from any TOOLSET
# Disable Perl specific CFLAGS
override Cap5_CFLAGS=
endif

View File

@@ -0,0 +1,3 @@
include $(CONFIG)/os/CONFIG.Common.linux-clang
STD_CXXFLAGS = -std=c++2a

View File

@@ -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))

View File

@@ -1,6 +1,6 @@
include $(CONFIG)/os/CONFIG.Common.vxWorks-ppc604_long
VXWORKS_VERSION = 5.5.1
WIND_BASE = /afs/psi.ch/project/vxworks/Tornado2.2.1
WIND_BASE = /opt/VxWorks/Tornado2.2.1
#there is a problem with our ccppc and optimization
# -O0 works, -O and -O1 and higher are buggy

View File

@@ -12,7 +12,7 @@ SDK_DIR = /opt/xgcc/gcc-8.3.0-deb10
GNU_ARCH = x86_64-deb10-linux-gnu
SDKTARGETSYSROOT=$(SDK_DIR)/$(GNU_ARCH)/sys-root/
GNU_DIR = $(SDK_DIR)
GNU_BIN = $(GNU_DIR)/bin/
GNU_BIN = $(GNU_DIR)/bin
GNU_TARGET_INCLUDE_DIR =
GNU_TARGET=x86_64-deb10-linux-gnu

View File

@@ -24,17 +24,23 @@ STATIC_LDFLAGS_NO=
STATIC_LDLIBS_YES= -Wl,-Bdynamic
# Set runtime path for shared libraries if LINKER_USE_RPATH=YES
SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%)
SHRLIBDIR_RPATH_LDFLAGS_YES = $(subst $(abspath $(LINKER_ORIGIN_ROOT)),$(FINAL_LOCATION),$(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%))
SHRLIBDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(SHRLIB_DEPLIB_DIRS))
SHRLIBDIR_LDFLAGS += \
$(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
# Set runtime path for products if LINKER_USE_RPATH=YES
PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%)
PRODDIR_RPATH_LDFLAGS_YES = $(subst $(abspath $(LINKER_ORIGIN_ROOT)),$(FINAL_LOCATION),$(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%))
PRODDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(PROD_DEPLIB_DIRS))
PRODDIR_LDFLAGS += \
$(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
ifneq ($(LINKER_USE_RPATH:NO=),)
ifeq ($(T_A),$(EPICS_HOST_ARCH))
LD_LIBRARY_PATH:=$(LD_LIBRARY_PATH:%=%:)$(INSTALL_LIB)
endif
endif
# Link libraries controlled by COMMANDLINE_LIBRARY
# The newest Linux versions only need readline, older ones need both
# readline and ncurses, and the oldest need readline and curses

View File

@@ -3,7 +3,7 @@
# Include definitions common to all Linux ARM targets
include $(CONFIG)/os/CONFIG.Common.linux-arm
GNU_DIR=/afs/psi.ch/project/embeddedlinux/moxa/arm-linux-4.4.2-v4
GNU_DIR=/opt/moxa/arm-linux-4.4.2-v4
GNU_TARGET=arm
ARCH_DEP_LDFLAGS+=-Wl,-rpath-link,$(GNU_DIR)/arm-none-linux-gnueabi/lib
ARCH_DEP_LDFLAGS+=-Wl,-rpath-link,$(INSTALL_LIB)

View File

@@ -7,7 +7,7 @@ COMMANDLINE_LIBRARY = READLINE_CURSES
ARCH_CLASS = xscale
GNU_DIR=/afs/psi.ch/project/embeddedlinux/moxa/xscale_be/armv5teb-montavista-linuxeabi
GNU_DIR=/opt/moxa/xscale_be/armv5teb-montavista-linuxeabi
ARCH_DEP_CFLAGS += -funwind-tables

View File

@@ -1,4 +1,5 @@
# National Instruments CompactRIO running LabView RT 19.5.1
# requires RPM gcc-c++-arm-linux-gnu
# Include definitions common to all Linux targets
include $(CONFIG)/os/CONFIG.Common.linuxCommon
@@ -8,10 +9,11 @@ ARCH_CLASS = arm
GNU_TARGET = arm-linux-gnu
SYSROOT = /opt/LabVIEW-RT-19.5.1/arm/sysroots/armv7a-vfp-neon-nilrt-linux-gnueabi
GNU_BIN = /bin
GNU_BIN = /opt/RHEL7/bin
LD_LIBRARY_PATH=/usr/$$LIB:/opt/RHEL7/$$LIB
ARCH_DEP_CPPFLAGS += -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon
ARCH_DEP_CXXFLAGS += -I$(SYSROOT)/usr/include/c++/4.7.2/arm-nilrt-linux-gnueabi/
ARCH_DEP_CXXFLAGS += -I$(SYSROOT)/usr/include/c++/4.7.2/
ARCH_DEP_CXXFLAGS += -I=/usr/include/c++/4.7.2/arm-nilrt-linux-gnueabi
ARCH_DEP_CXXFLAGS += -I=/usr/include/c++/4.7.2
COMMANDLINE_LIBRARY = READLINE_NCURSES

View File

@@ -10,13 +10,13 @@ include $(CONFIG)/os/CONFIG.Common.linuxCommon
# Due to missing/messed up libs in the toolchain, readline needs copies of
# libtinfo.so.5.9 and libreadline.so.6.2 from a Raspbian 7 rootfs
# /lib/arm-linux-gnueabihf/ to the toolchain, e.g.
# $(SDK_DIR)/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf/
# $(SDK_DIR)/$(SDK_TARGET)/arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf/
# and manually created links libtinfo.so.5 and libreadline.so.
# For gcc-linaro-arm-linux-gnueabihf-raspbian, an existing incompatible
# libtinfo.so.5 is in the way. Remove it.
# (Built with glibc 2.16 like installed on Raspbian 9 but toolchain uses glibc 2.13.)
# Also copy /usr/include/readline/ directory from some readline 6 installation
# to $(SDK_DIR)/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/usr/include/
# to $(SDK_DIR)/$(SDK_TARGET)/arm-linux-gnueabihf/libc/usr/include/
ARCH_CLASS = arm
@@ -25,10 +25,10 @@ SDK_DIR = /opt/raspberrypi/arm-bcm2708
# Available SDK_TARGETs:
# gcc 4.8.3 for 32 bit hosts with GLIBC 2.3 or higher
SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian
# SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian
# gcc 4.8.3 for 64 bit hosts with GLIBC 2.14 or higher
# SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian-x64
SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian-x64
# gcc 4.7.1 for 64 bit hosts with GLIBC 2.8 or higher
# SDK_TARGET = arm-linux-gnueabihf

View File

@@ -2,5 +2,9 @@ include $(CONFIG)/os/CONFIG.windows-x64.windows-x64
VALID_BUILDS = Ioc Command
PATH := /opt/wine-msvc-2017/bin/x64:$(PATH)
MSVC_VERSION ?= 2019
PATH := /opt/gfa-wine/bin:/opt/wine-msvc-$(MSVC_VERSION)/bin/x64:$(PATH)
export WINEPREFIX = $(HOME)/.wine-$(EPICS_HOST_ARCH)
export WINEDEBUG=fixme-all
export WINEDLLOVERRIDES="mscoree,mshtml="
export WINE = wine64

View File

@@ -1 +1,3 @@
# MSVC_VERSION 2019 in wine 4 for on RHEL7 would require winetricks
MSVC_VERSION = 2017
include $(CONFIG)/os/CONFIG.Linux.windows-x64

View File

@@ -1 +0,0 @@
GNU_BIN = /opt/RHEL7/bin

View File

@@ -0,0 +1,3 @@
#CONFIG.$(EPICS_HOST_ARCH).Common is required by build system
#Include definitions common to linux hosts
include $(CONFIG)/os/CONFIG.linux-x86_64.Common

View File

@@ -0,0 +1,18 @@
# Include common linux definitions
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
# "Cross compile" for RHEL7-x86_64
# Expects RHEL7 RPMs c++ and readline-devel installed
# in $(SYSROOT)
# This can be installed on RHEL7 with:
# yum install --installroot=$(SYSROOT) <packages>
# (Assuming $(SYSROOT) is on a shared network volume.)
# Optionally use a newer TOOLSET (installed on $(SYSROOT)).
SYSROOT = /opt/RHEL7
# "Cross" TOOLSET progs need to find their libraries
LD_LIBRARY_PATH = $(TOOLSET_DIR:%=$(SYSROOT)%/usr/$$LIB:)/usr/$$LIB:$(SYSROOT)/usr/$$LIB
# The linker has problems to find indirectly referenced libraries
PROD_LDLIBS += $(LDLIBS)

View File

@@ -0,0 +1,23 @@
# Include common linux definitions
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
# "Cross compile" for RHEL8-x86_64
# Expects RHEL8 RPMs gcc-toolset-12-gcc-c++ and readline-devel
# to be installed in $(SYSROOT)
# These can be installed on RHEL8 with:
# yum install --installroot=$(SYSROOT) <packages>
# (Assuming $(SYSROOT) is on a shared network volume.)
SYSROOT = /opt/RHEL8
# "Cross" TOOLSET progs need to find their libraries.
# But linker gets confused with LD_LIBRARY_PATH.
# Thus only wrap the compiler.
WRAPPER = -wrapper env,LD_LIBRARY_PATH=$(TOOLSET_DIR:%=$(SYSROOT)%/usr/lib64:)/usr/lib64:$(SYSROOT)/usr/lib64
TARGET_CPPFLAGS += $(WRAPPER)
TARGET_PROD_LDFLAGS += $(WRAPPER)
# These programs as cross tools would also need LD_LIBRARY_PATH.
# But but our host versions work just fine.
AR = ar -rc
RANLIB = ranlib

View File

@@ -0,0 +1,2 @@
# Include common linux definitions
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86

View File

@@ -0,0 +1 @@
include $(CONFIG)/os/CONFIG.Linux.windows-x64

View File

@@ -16,7 +16,7 @@ OPT_WHOLE_PROGRAM = YES
WINLINK = link
RCCMD = rc -l 0x409 $(INCLUDES) -fo $@ $<
RCCMD = rc -nologo -l 0x409 $(INCLUDES) -fo $@ $<
ARCMD = lib -nologo -verbose -out:$@ $(LIB_OPT_LDFLAGS) $(LIBRARY_LD_OBJS)

View File

@@ -1,2 +0,0 @@
SHRLIB_SUFFIX = $(SHRLIB_SUFFIX_BASE)
LOADABLE_SHRLIB_SUFFIX = $(SHRLIB_SUFFIX_BASE)

View File

@@ -87,7 +87,7 @@ CODE_CXXFLAGS =
#WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
#WIND_BASE = /usr/local/vw/vxWorks-$(VXWORKS_VERSION)
#WIND_BASE = /ade/vxWorks/$(VXWORKS_VERSION)
WIND_BASE = /afs/psi.ch/project/vxworks/VxWorks$(VXWORKS_VERSION)
WIND_BASE = /opt/VxWorks/VxWorks$(VXWORKS_VERSION)
#--------------------------------------------------
# Modules we cannot build with old compiler

View File

@@ -3,8 +3,3 @@ include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
# Improved error checking with clang
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64-clang
CROSS_COMPILER_RUNTEST_ARCHS += RHEL7-x86_64-clang
# NI Linux Real-Time 7.x
# requires RPM gcc-c++-arm-linux-gnu
# Not available on RHEL8
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a

View File

@@ -5,7 +5,3 @@ CROSS_COMPILER_TARGET_ARCHS += RHEL8-x86_64-clang
# Build for old RHEL7 64 bit
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64
# NI Linux Real-Time 7.x
# requires RPM gcc-c++-arm-linux-gnu
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a

View File

@@ -0,0 +1,10 @@
include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
# Improved error checking with clang
CROSS_COMPILER_TARGET_ARCHS += RHEL9-x86_64-clang
# Build for old RHEL8 64 bit
CROSS_COMPILER_TARGET_ARCHS += RHEL8-x86_64
# Build for old RHEL7 64 bit
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64

View File

@@ -38,7 +38,7 @@ CROSS_COMPILER_TARGET_ARCHS += eldk52-e500v2
# DeltaTau PowerPMAC
CROSS_COMPILER_TARGET_ARCHS += eldk42-ppc4xxFP
#CROSS_COMPILER_TARGET_ARCHS += eldk53-ppc4xxFP
CROSS_COMPILER_TARGET_ARCHS += eldk53-ppc4xxFP
# Test other vxWorks versions
#CROSS_COMPILER_TARGET_ARCHS += V66-ppc603
@@ -48,9 +48,6 @@ CROSS_COMPILER_TARGET_ARCHS += eldk42-ppc4xxFP
# (No PVA because of old compiler)
#CROSS_COMPILER_TARGET_ARCHS += V62-ppc604
# Raspberry Pi
CROSS_COMPILER_TARGET_ARCHS += raspbian-arm
# RTEMS (Can only have 1 RTEMS major version in 1 EPICS installation
# because they overwrite their header files.)
#CROSS_COMPILER_TARGET_ARCHS += RTEMS49-pc386

View File

@@ -25,4 +25,10 @@ CROSS_COMPILER_TARGET_ARCHS += yocto40-aarch64
CROSS_COMPILER_TARGET_ARCHS += deb10-x86_64
# Newer DeltaTau PowerPMAC
#CROSS_COMPILER_TARGET_ARCHS += gcc8-ppc4xxFP
CROSS_COMPILER_TARGET_ARCHS += gcc8-ppc4xxFP
# Raspberry Pi
CROSS_COMPILER_TARGET_ARCHS += raspbian-arm
# NI Linux Real-Time 7.x
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a

View File

@@ -22,6 +22,62 @@ should also be read to understand what has changed since earlier releases:
## Changes made on the 7.0 branch since 7.0.7
### PROC field changed to ASL0
The PROC field has been changed from access security level ASL1 to ASL0.
This allows users to trigger processing a record without having the rights
to reconfigure the records.
### 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`
Add support for CA tools timeout from environment variable `$EPICS_CLI_TIMEOUT`
@@ -63,7 +119,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.
@@ -118,7 +174,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
@@ -130,14 +188,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

6
epics-base.sh Normal file
View File

@@ -0,0 +1,6 @@
_OLD_EXTGLOB=$(shopt -p extglob)
shopt -s extglob
test -n "$EPICS_HOST_ARCH" || export EPICS_HOST_ARCH=$(/bin/sed "s%cpe:/o:redhat:enterprise_linux:\([0-9]*\).*%RHEL\1-`/bin/uname -m`%" /etc/system-release-cpe)
PATH=${PATH//\/usr\/local\/epics\/base-+([0-9]).+([0-9]).+([0-9])\/bin\/$EPICS_HOST_ARCH}:$(echo $(ls -dvr /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/$EPICS_HOST_ARCH) | tr ' ' :)
eval $_OLD_EXTGLOB
unset _OLD_EXTGLOB

386
epics-base.spec Normal file
View File

@@ -0,0 +1,386 @@
# Always make sure EpicsVersion.Version-Release matches the git tag!
%define EpicsVersion 7.0.7
Name: epics-base-%{EpicsVersion}
Summary: EPICS Base %{EpicsVersion}
Version: 1
Release: 5%{?dist}
License: EPICS Open License
Group: Development/Languages
URL: https://git.psi.ch/epics_base/base-7.0
Obsoletes: caRepeater
%define module_name %{name}
%define prog_folder /usr/local/epics/base-%{EpicsVersion}
%define debug_package %{nil}
# do not strip libraries
%global __strip /bin/true
%undefine __brp_strip
%undefine __brp_mangle_shebangs
%undefine __brp_ldconfig
%define _binaries_in_noarch_packages_terminate_build 0
%if %{defined rhel}
%global epics_host_arch RHEL%{rhel}-%{_host_cpu}
%endif
%description
EPICS is a set of Open Source software tools, libraries and applications
developed collaboratively and used worldwide to create distributed soft
real-time control systems for scientific instruments such as a particle
accelerators, telescopes and other large scientific experiments.
This RPM is a binary-only package.
###########################################
%package host-devel
Requires: make >= 3.80
BuildRequires: make >= 3.80
Summary: Minimal stuff needed to build EPICS host apps
Requires: %{name} = %{version}-%{release}
# This EPICS installation uses the toolset 12 compiler
%if 0%{?rhel} == 7
Requires: devtoolset-12-gcc-c++
BuildRequires: devtoolset-12-gcc-c++
%endif
%if 0%{?rhel} >= 8
Requires: gcc-toolset-12-gcc-c++
BuildRequires: gcc-toolset-12-gcc-c++
%endif
# The perl stuff we need
Requires: perl-interpreter >= 5.10.1
BuildRequires: perl-interpreter >= 5.10.1
%if 0%{?rhel} >= 7
Requires: perl-File-Path perl-Getopt-Long perl-Pod-Usage perl-Time-HiRes perl-Data-Dumper perl-Scalar-List-Utils
BuildRequires: perl-File-Path perl-Getopt-Long perl-Pod-Usage perl-Time-HiRes perl-Data-Dumper perl-Scalar-List-Utils
%endif
%if 0%{?rhel} >= 8
Requires: perl-Text-Tabs+Wrap
BuildRequires: perl-Text-Tabs+Wrap
%endif
%if 0%{?rhel} >= 9
Requires: perl-File-Find perl-File-Basename perl-File-Copy perl-FindBin perl-Getopt-Std perl-POSIX
BuildRequires: perl-File-Find perl-File-Basename perl-File-Copy perl-FindBin perl-Getopt-Std perl-POSIX
%endif
%if 0%{?rhel} == 7
# Perl auto-detection is broken
# It does not find all EPICS internal packages
%global __requires_exclude_from ^%{prog_folder}/bin/.*\\.pl$
%endif
%description host-devel
Contains headers etc to build EPICS host applications.
###########################################
%package compat
Summary: EPICS base %{EpicsVersion} for other RHEL versions
Requires: %{name} = %{version}-%{release}
AutoReqProv: no
%description compat
Contains EPICS binaries that run on other RHEL versions.
###########################################
%package wine
Summary: EPICS base %{EpicsVersion} for wine
Requires: %{name} = %{version}-%{release}
Requires: wine
BuildRequires: wine
%description wine
Allows to run EPICS in wine.
###########################################
%package boot
Summary: EPICS base %{EpicsVersion} for boot servers
BuildArch: noarch
AutoReqProv: no
Prefix: /usr/local/epics
%description boot
Contains files needed on NFS server to boot EPICS targets from.
This package can be relocated.
###########################################
%package devel
Summary: EPICS base %{EpicsVersion} for development environments
Requires: %{name} = %{version}-%{release}
Requires: %{name}-host-devel = %{version}-%{release}
Requires: %{name}-boot = %{version}-%{release}
Requires: gfa-cross-compiler-links
BuildArch: noarch
AutoReqProv: no
%description devel
All what is needed to develop EPICS for different target architectures.
###########################################
%package devel-static
Summary: EPICS base %{EpicsVersion} for development environments including static libraries
Requires: %{name}-devel = %{version}-%{release}
BuildArch: noarch
AutoReqProv: no
%description devel-static
Contains the static libraries (*.a) for EPICS development systems.
Only needed to build statically linked applications.
###########################################
%package src
Summary: Sources code of EPICS base %{EpicsVersion}
BuildArch: noarch
AutoReqProv: no
Prefix: /usr/local/epics
%description src
The source code of EPICS base %{EpicsVersion}.
May help when debugging
###########################################
%package doc
Summary: EPICS base %{EpicsVersion} documentation
BuildArch: noarch
AutoReqProv: no
Prefix: /usr/local/epics
%description doc
The documentation of EPICS base %{EpicsVersion}.
###########################################
# Our sources are locally in this directory
# and here we also build
# RPMS and SRPMS will be stored here, too
%define _topdir %(pwd)
%define _sourcedir %{_topdir}
%define _builddir %{_topdir}
%prep
%{__rm} -rf %{buildroot}/usr/lib
%{__rm} -f modules/RELEASE.*.local
git submodule update --init modules
%{__mkdir_p} RPMS
%{__mkdir_p} SRPMS
%build
%if %{defined epics_host_arch}
export EPICS_HOST_ARCH=%{epics_host_arch}
%endif
%{__make} -j $RPM_BUILD_NCPUS INSTALL_LOCATION=%{buildroot}/%{prog_folder} FINAL_LOCATION=%{prog_folder}
%{__make} INSTALL_LOCATION=%{buildroot}/%{prog_folder} copysrc
# remove files we do not need
shopt -s extglob
%{__rm} -f %{buildroot}/%{prog_folder}/bin/{V,RTEMS}*/{*Harness,softIoc,softIocPVA}
%{__rm} -f %{buildroot}/%{prog_folder}/bin/RTEMS*/TEMP.*
# install the profile script
%{__install} epics-base.sh %{buildroot}/%{prog_folder}/bin
# Do not use install section because build already installed
# and install will delete our buildroot!
%clean
%{__make} realclean
%{__rm} -f modules/RELEASE.*.local
# Link caRepeater and profile script to highest installed EPICS version after install and uninstall
%post
shopt -s extglob
if [ -e /etc/profile.d/epics-base.sh ]
then
%{__rm} -f /etc/profile.d/epics-base.sh
fi
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/epics-base.sh | /usr/bin/head -n1)" /etc/profile.d/
SYSTEMD_DIR=$(pkg-config systemd --variable=systemdsystemunitdir)
if [ -n "$SYSTEMD_DIR" ]
then
systemctl is-enabled caRepeater.service 2>/dev/null && systemctl disable --now caRepeater.service
test -e $SYSTEMD_DIR/caRepeater.service && %{__rm} $SYSTEMD_DIR/caRepeater.service
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/%{epics_host_arch}/caRepeater.service | /usr/bin/head -n1)" $SYSTEMD_DIR/
systemctl daemon-reload
killall caRepeater 2>/dev/null
systemctl enable --now caRepeater.service
fi
%postun
shopt -s extglob
if [ -e /etc/profile.d/epics-base.sh ]
then
%{__rm} -f /etc/profile.d/epics-base.sh
fi
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/epics-base.sh 2>/dev/null | /usr/bin/head -n1)" /etc/profile.d/ 2>/dev/null
SYSTEMD_DIR=$(pkg-config systemd --variable=systemdsystemunitdir)
if [ -n "$SYSTEMD_DIR" ]
then
systemctl disable --now caRepeater.service
%{__rm} -f $SYSTEMD_DIR/caRepeater.service
%{__ln_s} "$(/usr/bin/ls -dvr1 /usr/local/epics/base-+([0-9]).+([0-9]).+([0-9])/bin/%{epics_host_arch}/caRepeater.service 2>/dev/null | /usr/bin/head -n1)" $SYSTEMD_DIR/ 2>/dev/null
systemctl daemon-reload
if [ -e $SYSTEMD_DIR/caRepeater.service ]
then
killall caRepeater 2>/dev/null
systemctl enable --now caRepeater.service
fi
fi
%files
%defattr(-,root,root,-)
%dir %{prog_folder}
%dir %{prog_folder}/configure
%{prog_folder}/configure/CONFIG_BASE_VERSION
%dir %{prog_folder}/dbd
%{prog_folder}/dbd/softIoc*.dbd
%dir %{prog_folder}/bin
%dir %{prog_folder}/lib
%{prog_folder}/db
%{prog_folder}/bin/epics-base.sh
# Install host binaries but avoid installing *.pl scripts
# and other development tools
%if %{defined rhel}
%dir %{prog_folder}/bin/RHEL%{rhel}*
%{prog_folder}/bin/RHEL%{rhel}*/[Scips]*[^.]??
%{prog_folder}/bin/RHEL%{rhel}*/p2p
%{prog_folder}/bin/RHEL%{rhel}*/msi
%dir %{prog_folder}/lib/RHEL%{rhel}*
%{prog_folder}/lib/RHEL%{rhel}*/*.so*
%endif
###########################################
%files compat
%if %{?rhel} > 7
%{prog_folder}/bin/RHEL7*
%dir %{prog_folder}/lib/RHEL7*
%{prog_folder}/lib/RHEL7*/*.so*
%endif
%if %{?rhel} > 8
%{prog_folder}/bin/RHEL8*
%dir %{prog_folder}/lib/RHEL8*
%{prog_folder}/lib/RHEL8*/*.so*
%endif
%if %{?rhel} > 9
%{prog_folder}/bin/RHEL9*
%dir %{prog_folder}/lib/RHEL9*
%{prog_folder}/lib/RHEL9*/*.so*
%endif
###########################################
%files wine
%{prog_folder}/bin/win*
###########################################
%files boot
%defattr(-,root,root,-)
%dir %{prog_folder}/configure
%{prog_folder}/configure/CONFIG_BASE_VERSION
%dir %{prog_folder}/dbd
%{prog_folder}/dbd/softIoc*.dbd
%{prog_folder}/db
%dir %{prog_folder}/lib
# avoid pulling in pkgconfig and perl
%dir %{prog_folder}/lib/[a-z]*-*
%{prog_folder}/lib/[a-z]*-*/*.so*
%dir %{prog_folder}/bin
# avoid pulling in host files again
# but get all cross architectures (mostly lower case)
# including all Windows dlls (hence listed twice: here and in wine)
%dir %{prog_folder}/bin/[a-z]*
%{prog_folder}/bin/[a-z]*/[Scips]*[^.]??
%{prog_folder}/bin/[a-z]*/msi*
%{prog_folder}/bin/[a-z]*/*.dll
# vxWorks and RTEMS
%dir %{prog_folder}/bin/V*
%{prog_folder}/bin/V*/*.munch
%{prog_folder}/bin/V*/*.o
%dir %{prog_folder}/bin/RTEMS*
%{prog_folder}/bin/RTEMS*/*.boot
###########################################
%files host-devel
%defattr(-,root,root,-)
%{prog_folder}/configure
%{prog_folder}/cfg
%{prog_folder}/include
%{prog_folder}/templates
%if %{defined rhel}
%{prog_folder}/bin/RHEL%{rhel}*/[^Scips]*[^.]??
%{prog_folder}/bin/RHEL%{rhel}*/*.??
%endif
%{prog_folder}/lib/pkgconfig
%{prog_folder}/lib/perl
%{prog_folder}/lib/win*
%{prog_folder}/lib/RTEMS*
%{prog_folder}/dbd
###########################################
%files devel
%defattr(-,root,root,-)
%{prog_folder}/bin/[a-z]*/[^Scips]*[^.]??
# VxWorks and RTEMS need static libs
%{prog_folder}/lib/V*
###########################################
%files devel-static
%defattr(-,root,root,-)
# Install bulky static libs for Linux targets only on request
%{prog_folder}/lib/RHEL*/*.a
%{prog_folder}/lib/[a-z]*/*.a
###########################################
%files src
%defattr(-,root,root,-)
%dir %{prog_folder}
%{prog_folder}/modules
###########################################
%files doc
%defattr(-,root,root,-)
%dir %{prog_folder}
%docdir %{prog_folder}/html
%{prog_folder}/html

View File

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

View File

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

View File

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

View File

@@ -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)) {

View File

@@ -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");

View File

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

View File

@@ -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;

View File

@@ -240,6 +240,7 @@ The B<SPVT> field is for internal use by the scanning system.
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
asl(ASL0)
pp(TRUE)
interest(3)
}

View File

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

View File

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

View File

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

View File

@@ -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)
{

View File

@@ -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(

View File

@@ -10,6 +10,7 @@
#define DBLOCKPVT_H
#include "dbLock.h"
#include "epicsMutex.h"
#include "epicsSpin.h"
/* Define to enable additional error checking */

View File

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

View File

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

View File

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

View File

@@ -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;
@@ -2204,12 +2204,12 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
*/
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
errlogPrintf("Error: %s.%s: can't initialize link type %s with \"%s\" (type %s)\n",
prec->name, pflddes->name, pamaplinkType[plink->type].strvalue, plink->text, pamaplinkType[link_info.ltype].strvalue);
errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %d with \"%s\" (type %s)\n",
prec->name, pflddes->name, plink->type, plink->text, pamaplinkType[link_info.ltype].strvalue);
} else if(dbSetLink(plink, &link_info, devsup)) {
errlogPrintf("Error: %s.%s: failed to initialize link type %s with \"%s\" (type %s)\n",
prec->name, pflddes->name, pamaplinkType[plink->type].strvalue, plink->text, pamaplinkType[link_info.ltype].strvalue);
errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %d with \"%s\" (type %s)\n",
prec->name, pflddes->name, plink->type, plink->text, pamaplinkType[link_info.ltype].strvalue);
}
free(plink->text);
plink->text = NULL;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

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

View File

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

View File

@@ -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();

View File

@@ -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());

View File

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

View File

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

View File

@@ -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)

View File

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

View File

@@ -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 UNRELEASED) If the MASK field is non-zero, then this MASK is applied to RVAL.
The value of RVAL is then converted using the process described in the
next section.
=fields INP, DTYP, ZNAM, ONAM, RVAL, VAL

View File

@@ -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

View File

@@ -323,6 +323,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)
@@ -330,6 +331,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)
@@ -337,6 +339,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)
@@ -344,6 +347,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)
@@ -351,6 +355,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)
@@ -358,6 +363,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)
@@ -365,6 +371,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)
@@ -372,6 +379,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)
@@ -379,6 +387,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)
@@ -386,6 +395,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)
@@ -393,6 +403,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)
@@ -400,6 +411,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)
@@ -407,6 +419,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)
@@ -414,6 +427,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)
@@ -421,6 +435,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)
@@ -428,6 +443,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)
@@ -435,6 +451,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)
@@ -442,6 +459,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)
@@ -449,6 +467,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)
@@ -456,6 +475,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)
@@ -463,6 +483,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)
@@ -470,6 +491,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)
@@ -477,6 +499,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)
@@ -484,6 +507,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)
@@ -491,6 +515,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)
@@ -498,6 +523,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)
@@ -505,6 +531,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)
@@ -512,6 +539,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)
@@ -519,6 +547,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)
@@ -526,6 +555,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)
@@ -533,6 +563,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)
@@ -540,6 +571,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)

View File

@@ -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)
{

View File

@@ -4,6 +4,8 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include <string.h>
#include <errlog.h>

View File

@@ -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".

View File

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

View File

@@ -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,

View File

@@ -336,6 +336,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) {
@@ -354,6 +358,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) {

View File

@@ -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 */ )
{

View File

@@ -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;
}
/****************************************************************************
*

View File

@@ -105,14 +105,13 @@ int errSymbolAdd(long errNum, const char *name)
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();
epicsUInt16 hashInd = errhash(errNum);
epicsMutexLock(errHashTable.tableMutexId);
phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd];
pNextNode = (ERRNUMNODE*) *phashnode;
@@ -271,7 +270,6 @@ void errSymTestPrint(long errNum)
if ( message[0] == '\0' ) return;
printf("module %hu number %hu message=\"%s\"\n",
modnum, errnum, message);
return;
}
/****************************************************************

View File

@@ -38,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

View File

@@ -247,7 +247,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))

View File

@@ -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")
/** @} */

View File

@@ -206,7 +206,6 @@ LIBCOM_API void fdManager::process (double delay)
this->pTimerQueue->process(epicsTime::getCurrent());
}
this->processInProg = false;
return;
}
//

View File

@@ -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 ()
{

View File

@@ -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)

View File

@@ -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)
@@ -171,7 +170,6 @@ void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
}
epicsMutexUnlock(pgphPvt->lock);
return;
}
void epicsStdCall gphFreeMem(gphPvt *pgphPvt)

View File

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

View File

@@ -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,73 @@ 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 UNRELEASED 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 UNRELEASED 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
/* 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

View File

@@ -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);
@@ -647,6 +639,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;
@@ -655,6 +656,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;
@@ -667,6 +674,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
@@ -769,6 +796,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)
@@ -902,15 +936,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++) {
@@ -923,11 +961,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;
}
}
}
}
@@ -1397,12 +1438,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);
@@ -1455,7 +1496,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);
@@ -1527,24 +1568,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;

View File

@@ -191,7 +191,9 @@ static const iocshArg * const epicsEnvShowArgs[1] = {&epicsEnvShowArg0};
static const iocshFuncDef epicsEnvShowFuncDef = {"epicsEnvShow",1,epicsEnvShowArgs,
"Show environment variables on your system\n"
" (default) - show all environment variables\n"
" name - show value of specific environment variable\n"};
" name - show value of specific environment variable\n"
"Example: epicsEnvShow\n"
"Example: epicsEnvShow PATH"};
static void epicsEnvShowCallFunc(const iocshArgBuf *args)
{
epicsEnvShow (args[0].sval);
@@ -258,10 +260,11 @@ static void eltcCallFunc(const iocshArgBuf *args)
/* errlogInit */
static const iocshArg errlogInitArg0 = { "bufSize",iocshArgInt};
static const iocshArg * const errlogInitArgs[1] = {&errlogInitArg0};
static const iocshFuncDef errlogInitFuncDef =
{"errlogInit",1,errlogInitArgs,
"Initialize error log client buffer size\n"
" bufSize - size of circular buffer (default = 1280 bytes)\n"};
static const iocshFuncDef errlogInitFuncDef = {
"errlogInit",1,errlogInitArgs,
"Initialize error log client buffer size\n"
" bufSize - size of circular buffer (default = 1280 bytes)\n"
};
static void errlogInitCallFunc(const iocshArgBuf *args)
{
errlogInit(args[0].ival);
@@ -272,11 +275,12 @@ static const iocshArg errlogInit2Arg0 = { "bufSize",iocshArgInt};
static const iocshArg errlogInit2Arg1 = { "maxMsgSize",iocshArgInt};
static const iocshArg * const errlogInit2Args[] =
{&errlogInit2Arg0, &errlogInit2Arg1};
static const iocshFuncDef errlogInit2FuncDef =
{"errlogInit2", 2, errlogInit2Args,
"Initialize error log client buffer size and maximum message size\n"
" bufSize - size of circular buffer (default = 1280 bytes)\n"
" maxMsgSize - maximum size of error message (default = 256 bytes)\n"};
static const iocshFuncDef errlogInit2FuncDef = {
"errlogInit2", 2, errlogInit2Args,
"Initialize error log client buffer size and maximum message size\n"
" bufSize - size of circular buffer (default = 1280 bytes)\n"
" maxMsgSize - maximum size of error message (default = 256 bytes)\n"
};
static void errlogInit2CallFunc(const iocshArgBuf *args)
{
errlogInit2(args[0].ival, args[1].ival);
@@ -311,9 +315,8 @@ static void iocLogPrefixCallFunc(const iocshArgBuf *args)
/* epicsThreadShowAll */
static const iocshArg epicsThreadShowAllArg0 = { "level",iocshArgInt};
static const iocshArg * const epicsThreadShowAllArgs[1] = {&epicsThreadShowAllArg0};
static const iocshFuncDef epicsThreadShowAllFuncDef =
{"epicsThreadShowAll",1,epicsThreadShowAllArgs,
"Display info about all threads\n"};
static const iocshFuncDef epicsThreadShowAllFuncDef = {"epicsThreadShowAll",1,epicsThreadShowAllArgs,
"Display info about all threads\n"};
static void epicsThreadShowAllCallFunc(const iocshArgBuf *args)
{
epicsThreadShowAll(args[0].ival);
@@ -368,9 +371,8 @@ static void threadCallFunc(const iocshArgBuf *args)
/* taskwdShow */
static const iocshArg taskwdShowArg0 = { "level",iocshArgInt};
static const iocshArg * const taskwdShowArgs[1] = {&taskwdShowArg0};
static const iocshFuncDef taskwdShowFuncDef =
{"taskwdShow",1,taskwdShowArgs,
"Show number of tasks and monitors registered\n"};
static const iocshFuncDef taskwdShowFuncDef = {"taskwdShow",1,taskwdShowArgs,
"Show number of tasks and monitors registered\n"};
static void taskwdShowCallFunc(const iocshArgBuf *args)
{
taskwdShow(args[0].ival);
@@ -381,11 +383,12 @@ static const iocshArg epicsMutexShowAllArg0 = { "onlyLocked",iocshArgInt};
static const iocshArg epicsMutexShowAllArg1 = { "level",iocshArgInt};
static const iocshArg * const epicsMutexShowAllArgs[2] =
{&epicsMutexShowAllArg0,&epicsMutexShowAllArg1};
static const iocshFuncDef epicsMutexShowAllFuncDef =
{"epicsMutexShowAll",2,epicsMutexShowAllArgs,
"Display information about all epicsMutex semaphores\n"
" onlyLocked - non-zero to show only locked semaphores\n"
" level - desired information level to report\n"};
static const iocshFuncDef epicsMutexShowAllFuncDef = {
"epicsMutexShowAll",2,epicsMutexShowAllArgs,
"Display information about all epicsMutex semaphores\n"
" onlyLocked - non-zero to show only locked semaphores\n"
" level - desired information level to report\n"
};
static void epicsMutexShowAllCallFunc(const iocshArgBuf *args)
{
epicsMutexShowAll(args[0].ival,args[1].ival);
@@ -394,9 +397,8 @@ static void epicsMutexShowAllCallFunc(const iocshArgBuf *args)
/* epicsThreadSleep */
static const iocshArg epicsThreadSleepArg0 = { "seconds",iocshArgDouble};
static const iocshArg * const epicsThreadSleepArgs[1] = {&epicsThreadSleepArg0};
static const iocshFuncDef epicsThreadSleepFuncDef =
{"epicsThreadSleep",1,epicsThreadSleepArgs,
"Pause execution of IOC shell for <seconds> seconds\n"};
static const iocshFuncDef epicsThreadSleepFuncDef = {"epicsThreadSleep",1,epicsThreadSleepArgs,
"Pause execution of IOC shell for <seconds> seconds\n"};
static void epicsThreadSleepCallFunc(const iocshArgBuf *args)
{
epicsThreadSleep(args[0].dval);
@@ -451,18 +453,18 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args)
static const iocshArg generalTimeReportArg0 = { "interest_level", iocshArgInt};
static const iocshArg * const generalTimeReportArgs[1] = { &generalTimeReportArg0 };
static const iocshFuncDef generalTimeReportFuncDef = {"generalTimeReport",1,generalTimeReportArgs,
"Display time providers and their priority levels"
" for current and event times\n"};
"Display time providers information for given interest level.\n"
"interest level 0 - List providers and their priorities.\n"
" 1 - Additionally show current time obtained from each provider.\n"};
static void generalTimeReportCallFunc(const iocshArgBuf *args)
{
generalTimeReport(args[0].ival);
}
/* installLastResortEventProvider */
static const iocshFuncDef installLastResortEventProviderFuncDef = {"installLastResortEventProvider", 0, NULL,
"Installs the optional Last Resort event provider"
" at priority 999,\nwhich returns the current time"
" for every event number\n"};
static const iocshFuncDef installLastResortEventProviderFuncDef = {"installLastResortEventProvider",0,NULL,
"Installs the optional Last Resort event provider at priority 999,\n"
"which returns the current time for every event number\n"};
static void installLastResortEventProviderCallFunc(const iocshArgBuf *args)
{
installLastResortEventProvider();

View File

@@ -711,8 +711,6 @@ static void freeLogClient(struct iocLogClient *pclient)
epicsSocketDestroy ( pclient->insock );
free (pclient);
return;
}

View File

@@ -559,7 +559,7 @@ void epicsStdCall iocLogPrefix(const char * prefix)
if (logClientPrefix) {
/* No error message if the new prefix is identical to the old one */
if (strcmp(logClientPrefix, prefix))
if (strcmp(logClientPrefix, prefix)!=0)
printf (ERL_WARNING " iocLogPrefix: The prefix was already set to "
"\"%s\" and can't be changed.\n", logClientPrefix);
return;

View File

@@ -72,7 +72,7 @@ static void trans ( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
static void refer ( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
const char **rawval, char **value, char *valend );
static void cpy2val( const char *src, char **value, char *valend );
static void cpy2val( const char *src, char **value, const char *valend );
static char *Strdup( const char *string );
@@ -948,8 +948,6 @@ static void trans( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
still there to be seen) */
*rawval = ( *r == '\0' ) ? r - 1 : r;
*value = v;
return;
}
/*
@@ -1110,14 +1108,13 @@ cleanup:
*rawval = r;
*value = v;
return;
}
/*
* Copy a string, honoring the 'end of destination string' pointer
* Returns with **value pointing to the '\0' terminator
*/
static void cpy2val(const char *src, char **value, char *valend)
static void cpy2val(const char *src, char **value, const char *valend)
{
char *v = *value;
while ((v < valend) && (*v = *src++)) { v++; }

View File

@@ -15,13 +15,10 @@
#include <stdio.h>
#include <string.h>
#include "dbDefs.h"
#include "epicsTypes.h"
#include "osiSock.h"
#ifndef NELEMENTS
#define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif /*NELEMENTS*/
/*
* addrArrayToUL ()
*/

View File

@@ -35,8 +35,6 @@
#include "cantProceed.h"
#include "epicsExit.h"
void epicsMutexCleanup(void);
typedef struct exitNode {
ELLNODE node;
epicsExitFunc func;
@@ -115,8 +113,6 @@ LIBCOM_API void epicsExitCallAtExits(void)
epicsExitCallAtExitsPvt ( pep );
destroyExitPvt ( pep );
}
/* Handle specially to avoid circular reference */
epicsMutexCleanup();
}
LIBCOM_API void epicsExitCallAtThreadExits(void)

View File

@@ -503,7 +503,7 @@ long devUnregisterAddress(
return S_dev_addressNotFound;
}
if (strcmp(pOwnerName,pRange->pOwnerName)) {
if (strcmp(pOwnerName,pRange->pOwnerName)!=0) {
s = S_dev_addressOverlap;
errPrintf (
s,

View File

@@ -78,14 +78,22 @@ LIBCOM_API void epicsAssert (const char *pFile, const unsigned line,
#if __cplusplus>=201103L
#define STATIC_ASSERT(expr) static_assert(expr, #expr)
#else
#define STATIC_JOIN(x, y) STATIC_JOIN2(x, y)
#define STATIC_JOIN2(x, y) x ## y
#define STATIC_JOIN(x, y, z, w) STATIC_JOIN4(x, y, z, w)
#define STATIC_JOIN4(x, y, z, w) x ## y ## z ## w
/* Compilers that do not support __COUNTER__ (e.g. GCC 4.1) will not be able to use unique static assert typedefs */
#ifdef __COUNTER__
# define STATIC_ASSERT_MSG(l) STATIC_JOIN(static_assert_, __COUNTER__, _failed_at_line_, l)
#else
# define STATIC_ASSERT_MSG(l) STATIC_JOIN(static_assert_, 0, _failed_at_line_, l)
#endif
/**\brief Declare a condition that should be true at compile-time.
* \param expr A C/C++ const-expression that should evaluate to True.
*/
#define STATIC_ASSERT(expr) \
typedef int STATIC_JOIN(static_assert_failed_at_line_, __LINE__) \
typedef int STATIC_ASSERT_MSG(__LINE__) \
[ (expr) ? 1 : -1 ] EPICS_UNUSED
#endif

View File

@@ -26,30 +26,23 @@
#include <stdio.h>
#include <string.h>
#include "dbDefs.h"
#include "epicsStdio.h"
#include "epicsThread.h"
#include "valgrind/valgrind.h"
#include "ellLib.h"
#include "errlog.h"
#include "epicsMutex.h"
#include "epicsMutexImpl.h"
#include "epicsThread.h"
#include "cantProceed.h"
static epicsThreadOnceId epicsMutexOsiOnce = EPICS_THREAD_ONCE_INIT;
static ELLLIST mutexList;
static ELLLIST freeList;
struct epicsMutexParm {
ELLNODE node;
epicsMutexOSD * id;
# ifdef LOG_LAST_OWNER
epicsThreadId lastOwner;
# endif
const char *pFileName;
int lineno;
};
static epicsMutexOSD * epicsMutexGlobalLock;
static ELLLIST mutexList = ELLLIST_INIT;
/* Specially initialized to bootstrap initialization.
* When supported (posix and !rtems) use statically initiallized mutex.
* Otherwise, initialize via epicsMutexOsdSetup().
*/
struct epicsMutexParm epicsMutexGlobalLock = {ELLNODE_INIT, __FILE__, __LINE__};
// vxWorks 5.4 gcc fails during compile when I use std::exception
using namespace std;
@@ -76,176 +69,82 @@ const char * epicsMutex::invalidMutex::what () const throw ()
return "epicsMutex::invalidMutex()";
}
static void epicsMutexOsiInit(void *) {
ellInit(&mutexList);
ellInit(&freeList);
VALGRIND_CREATE_MEMPOOL(&freeList, 0, 0);
epicsMutexGlobalLock = epicsMutexOsdCreate();
}
epicsMutexId epicsStdCall epicsMutexOsiCreate(
const char *pFileName,int lineno)
{
epicsMutexOSD * id;
epicsMutexOsdSetup();
epicsThreadOnce(&epicsMutexOsiOnce, epicsMutexOsiInit, NULL);
epicsMutexId ret = (epicsMutexId)calloc(1, sizeof(*ret));
if(ret) {
ret->pFileName = pFileName;
ret->lineno = lineno;
if(!epicsMutexOsdPrepare(ret)) {
epicsMutexMustLock(&epicsMutexGlobalLock);
ellAdd(&mutexList, &ret->node);
(void)epicsMutexUnlock(&epicsMutexGlobalLock);
} else {
free(ret);
ret = NULL;
}
id = epicsMutexOsdCreate();
if(!id) {
return 0;
}
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
epicsMutexParm *pmutexNode =
reinterpret_cast < epicsMutexParm * > ( ellFirst(&freeList) );
if(pmutexNode) {
ellDelete(&freeList,&pmutexNode->node);
VALGRIND_MEMPOOL_FREE(&freeList, pmutexNode);
} else {
pmutexNode = static_cast < epicsMutexParm * > ( calloc(1,sizeof(epicsMutexParm)) );
}
VALGRIND_MEMPOOL_ALLOC(&freeList, pmutexNode, sizeof(epicsMutexParm));
pmutexNode->id = id;
# ifdef LOG_LAST_OWNER
pmutexNode->lastOwner = 0;
# endif
pmutexNode->pFileName = pFileName;
pmutexNode->lineno = lineno;
ellAdd(&mutexList,&pmutexNode->node);
epicsMutexOsdUnlock(epicsMutexGlobalLock);
return(pmutexNode);
return ret;
}
epicsMutexId epicsStdCall epicsMutexOsiMustCreate(
const char *pFileName,int lineno)
{
epicsMutexId id = epicsMutexOsiCreate(pFileName,lineno);
assert(id);
return(id );
if(!id) {
cantProceed("epicsMutexOsiMustCreate() fails at %s:%d\n",
pFileName, lineno);
}
return id;
}
void epicsStdCall epicsMutexDestroy(epicsMutexId pmutexNode)
{
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
ellDelete(&mutexList,&pmutexNode->node);
epicsMutexOsdDestroy(pmutexNode->id);
VALGRIND_MEMPOOL_FREE(&freeList, pmutexNode);
VALGRIND_MEMPOOL_ALLOC(&freeList, &pmutexNode->node, sizeof(pmutexNode->node));
ellAdd(&freeList,&pmutexNode->node);
epicsMutexOsdUnlock(epicsMutexGlobalLock);
}
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
{
epicsMutexOsdUnlock(pmutexNode->id);
}
epicsMutexLockStatus epicsStdCall epicsMutexLock(
epicsMutexId pmutexNode)
{
epicsMutexLockStatus status =
epicsMutexOsdLock(pmutexNode->id);
# ifdef LOG_LAST_OWNER
if ( status == epicsMutexLockOK ) {
pmutexNode->lastOwner = epicsThreadGetIdSelf();
}
# endif
return status;
}
epicsMutexLockStatus epicsStdCall epicsMutexTryLock(
epicsMutexId pmutexNode)
{
epicsMutexLockStatus status =
epicsMutexOsdTryLock(pmutexNode->id);
# ifdef LOG_LAST_OWNER
if ( status == epicsMutexLockOK ) {
pmutexNode->lastOwner = epicsThreadGetIdSelf();
}
# endif
return status;
}
/* Empty the freeList.
* Called from epicsExit.c, but not via epicsAtExit()
* to avoid the possibility of a circular reference.
*/
extern "C"
void epicsMutexCleanup(void)
{
ELLNODE *cur;
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
while((cur=ellGet(&freeList))!=NULL) {
VALGRIND_MEMPOOL_FREE(&freeList, cur);
free(cur);
if(pmutexNode) {
epicsMutexMustLock(&epicsMutexGlobalLock);
ellDelete(&mutexList, &pmutexNode->node);
(void)epicsMutexUnlock(&epicsMutexGlobalLock);
epicsMutexOsdCleanup(pmutexNode);
free(pmutexNode);
}
epicsMutexOsdUnlock(epicsMutexGlobalLock);
}
void epicsStdCall epicsMutexShow(
epicsMutexId pmutexNode, unsigned int level)
{
# ifdef LOG_LAST_OWNER
char threadName [255];
if ( pmutexNode->lastOwner ) {
# error currently not safe to fetch name for stale thread
epicsThreadGetName ( pmutexNode->lastOwner,
threadName, sizeof ( threadName ) );
}
else {
strcpy ( threadName, "<not used>" );
}
printf("epicsMutexId %p last owner \"%s\" source %s line %d\n",
(void *)pmutexNode, threadName,
pmutexNode->pFileName, pmutexNode->lineno);
# else
printf("epicsMutexId %p source %s line %d\n",
(void *)pmutexNode, pmutexNode->pFileName,
pmutexNode->lineno);
# endif
printf("epicsMutexId %p source %s line %d\n",
(void *)pmutexNode, pmutexNode->pFileName,
pmutexNode->lineno);
if ( level > 0 ) {
epicsMutexOsdShow(pmutexNode->id,level-1);
epicsMutexOsdShow(pmutexNode,level-1);
}
}
void epicsStdCall epicsMutexShowAll(int onlyLocked,unsigned int level)
{
epicsMutexParm *pmutexNode;
epicsMutexOsdSetup();
if (epicsMutexOsiOnce == EPICS_THREAD_ONCE_INIT)
return;
printf("ellCount(&mutexList) %d ellCount(&freeList) %d\n",
ellCount(&mutexList),ellCount(&freeList));
printf("ellCount(&mutexList) %d\n", ellCount(&mutexList));
epicsMutexOsdShowAll();
epicsMutexLockStatus lockStat =
epicsMutexOsdLock(epicsMutexGlobalLock);
assert ( lockStat == epicsMutexLockOK );
pmutexNode = reinterpret_cast < epicsMutexParm * > ( ellFirst(&mutexList) );
while(pmutexNode) {
epicsMutexMustLock(&epicsMutexGlobalLock);
for(ELLNODE *cur =ellFirst(&mutexList); cur; cur = ellNext(cur)) {
epicsMutexParm *lock = CONTAINER(cur, epicsMutexParm, node);
if(onlyLocked) {
epicsMutexLockStatus status;
status = epicsMutexOsdTryLock(pmutexNode->id);
if(status==epicsMutexLockOK) {
epicsMutexOsdUnlock(pmutexNode->id);
pmutexNode =
reinterpret_cast < epicsMutexParm * >
( ellNext(&pmutexNode->node) );
continue;
// cycle through to test state
if(epicsMutexTryLock(lock)==epicsMutexLockOK) {
epicsMutexUnlock(lock);
continue; // was not locked, skip
}
}
epicsMutexShow(pmutexNode, level);
pmutexNode =
reinterpret_cast < epicsMutexParm * > ( ellNext(&pmutexNode->node) );
epicsMutexShow(lock, level);
}
epicsMutexOsdUnlock(epicsMutexGlobalLock);
epicsMutexUnlock(&epicsMutexGlobalLock);
}
#if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8)

View File

@@ -247,21 +247,6 @@ LIBCOM_API void epicsStdCall epicsMutexShow(
LIBCOM_API void epicsStdCall epicsMutexShowAll(
int onlyLocked,unsigned int level);
/**@privatesection
* The following are interfaces to the OS dependent
* implementation and should NOT be called directly by
* user code.
*/
struct epicsMutexOSD * epicsMutexOsdCreate(void);
void epicsMutexOsdDestroy(struct epicsMutexOSD *);
void epicsMutexOsdUnlock(struct epicsMutexOSD *);
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD *);
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD *);
void epicsMutexOsdShow(struct epicsMutexOSD *,unsigned int level);
#ifdef EPICS_PRIVATE_API
void epicsMutexOsdShowAll(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,66 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2023 Michael Davidsaver
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Only include from osdMutex.c */
#ifndef epicsMutexImpl_H
#define epicsMutexImpl_H
#if defined(vxWorks)
# include <vxWorks.h>
# include <semLib.h>
#elif defined(_WIN32)
# define VC_EXTRALEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#elif defined(__rtems__)
# include <rtems.h>
# include <rtems/score/cpuopts.h>
#else
# include <pthread.h>
#endif
#include "ellLib.h"
#ifdef __cplusplus
extern "C" {
#endif
struct epicsMutexParm {
/* global list of mutex */
ELLNODE node;
/* location where mutex was allocated */
const char *pFileName;
int lineno;
#if defined(vxWorks)
SEM_ID osd;
#elif defined(_WIN32)
CRITICAL_SECTION osd;
#elif defined(__RTEMS_MAJOR__) && __RTEMS_MAJOR__<5
Semaphore_Control *osd;
#else
pthread_mutex_t osd;
#endif
};
void epicsMutexOsdSetup(void);
long epicsMutexOsdPrepare(struct epicsMutexParm *);
void epicsMutexOsdCleanup(struct epicsMutexParm *);
void epicsMutexOsdShow(struct epicsMutexParm *,unsigned int level);
void epicsMutexOsdShowAll(void);
extern struct epicsMutexParm epicsMutexGlobalLock;
#ifdef __cplusplus
} // extern "C
#endif
#endif // epicsMutexImpl_H

View File

@@ -25,6 +25,8 @@ extern "C" {
/** \brief Dump a stack trace
*
* Dump a stack trace to the errlog.
*
* \since 3.15.0.2 Added
*/
LIBCOM_API void epicsStackTrace(void);

View File

@@ -275,18 +275,12 @@ void epicsThread::setPriority (unsigned int priority) throw ()
bool epicsThread::priorityIsEqual (const epicsThread &otherThread) const throw ()
{
if ( epicsThreadIsEqual (this->id, otherThread.id) ) {
return true;
}
return false;
return epicsThreadIsEqual (this->id, otherThread.id)!=0;
}
bool epicsThread::isSuspended () const throw ()
{
if ( epicsThreadIsSuspended (this->id) ) {
return true;
}
return false;
return epicsThreadIsSuspended (this->id)!=0;
}
bool epicsThread::operator == (const epicsThread &rhs) const throw ()

View File

@@ -44,8 +44,9 @@ void epicsTime::throwError(int code)
}
epicsTime::epicsTime ( const epicsTimeStamp & replace ) {
ts = replace;
epicsTime::epicsTime ( const epicsTimeStamp & replace )
:ts(replace)
{
if(ts.nsec >= nSecPerSec)
throw std::logic_error("epicsTimeStamp has overflow in nano-seconds field");
}

View File

@@ -36,6 +36,7 @@ typedef struct epicsThreadOSD {
int isEpicsThread;
int isRealTimeScheduled;
int isOnThreadList;
int isRunning;
unsigned int osiPriority;
int joinable;
char name[1]; /* actually larger */

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