diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index e48336bf8..eeb577824 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -48,11 +48,11 @@ EPICS_VERSION = 7 EPICS_REVISION = 0 # EPICS_MODIFICATION must be a number >=0 and <256 -EPICS_MODIFICATION = 8 +EPICS_MODIFICATION = 9 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included in the official EPICS version number if zero -EPICS_PATCH_LEVEL = 2 +EPICS_PATCH_LEVEL = 1 # Immediately after an official release the EPICS_PATCH_LEVEL is incremented # and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions) @@ -71,6 +71,3 @@ endif EPICS_SHORT_VERSION=$(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)$(EPICS_PATCH_VSTRING) EPICS_VERSION_NUMBER=$(EPICS_SHORT_VERSION)$(EPICS_DEV_SNAPSHOT)$(EPICS_SITE_VSTRING) EPICS_VERSION_STRING="EPICS Version $(EPICS_VERSION_NUMBER)" - -# Provide this in case anyone is still using the old name -COMMIT_DATE="-no-date-" diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index 2cff78816..770e1965f 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -2,7 +2,7 @@ EPICS_CA_MAJOR_VERSION = 4 EPICS_CA_MINOR_VERSION = 14 -EPICS_CA_MAINTENANCE_VERSION = 4 +EPICS_CA_MAINTENANCE_VERSION = 6 # Development flag, set to zero for release versions diff --git a/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION index 8815d2d1e..5c5eae1ee 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -1,7 +1,7 @@ # Version number for the database APIs and shared library EPICS_DATABASE_MAJOR_VERSION = 3 -EPICS_DATABASE_MINOR_VERSION = 23 +EPICS_DATABASE_MINOR_VERSION = 24 EPICS_DATABASE_MAINTENANCE_VERSION = 1 # Development flag, set to zero for release versions diff --git a/configure/CONFIG_LIBCOM_VERSION b/configure/CONFIG_LIBCOM_VERSION index 4aab82a17..7f1487489 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -1,7 +1,7 @@ # Version number for the libcom APIs and shared library EPICS_LIBCOM_MAJOR_VERSION = 3 -EPICS_LIBCOM_MINOR_VERSION = 23 +EPICS_LIBCOM_MINOR_VERSION = 24 EPICS_LIBCOM_MAINTENANCE_VERSION = 1 # Development flag, set to zero for release versions diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV index bacbc14a5..bcc3bdf7a 100644 --- a/configure/CONFIG_SITE_ENV +++ b/configure/CONFIG_SITE_ENV @@ -92,3 +92,6 @@ EPICS_IOC_LOG_FILE_NAME= EPICS_IOC_LOG_FILE_COMMAND= EPICS_IOC_LOG_FILE_LIMIT=1000000 +# Set to 'YES' to call abort() rather than suspend the current thread +# when an assert() fails +EPICS_ABORT_ON_ASSERT=NO diff --git a/configure/os/CONFIG.darwin-aarch64-debug.Common b/configure/os/CONFIG.darwin-aarch64-debug.Common new file mode 100644 index 000000000..49b58c879 --- /dev/null +++ b/configure/os/CONFIG.darwin-aarch64-debug.Common @@ -0,0 +1,11 @@ +# CONFIG.darwin-aarch64-debug.Common +# +# Definitions for darwin-aarch64-debug host builds - darwin-aarch64 target build with debug compiler flags +# Sites may override these definitions in CONFIG_SITE.darwin-aarch64-debug.Common +#------------------------------------------------------- + +include $(CONFIG)/os/CONFIG.darwin-aarch64.Common + +# Removes -O optimization and adds -g compile option +HOST_OPT=NO + diff --git a/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug b/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug new file mode 100644 index 000000000..25d27b996 --- /dev/null +++ b/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug @@ -0,0 +1,14 @@ +# CONFIG.darwin-aarch64.darwin-aarch64-debug +# +# Definitions for darwin-aarch64 host - darwin-aarch64-debug target build with debug compiler flags +# Sites may override these definitions in CONFIG_SITE.darwin-aarch64.darwin-aarch64-debug +#------------------------------------------------------- + +-include $(CONFIG)/os/CONFIG.Common.darwin-aarch64 +-include $(CONFIG)/os/CONFIG.darwin-aarch64.darwin-aarch64 +-include $(CONFIG)/os/CONFIG_SITE.Common.darwin-aarch64 +-include $(CONFIG)/os/CONFIG_SITE.darwin-aarch64.darwin-aarch64 + + +BUILD_CLASS=HOST +HOST_OPT = NO diff --git a/configure/os/CONFIG.darwin-x86-debug.Common b/configure/os/CONFIG.darwin-x86-debug.Common new file mode 100644 index 000000000..4e9aca82b --- /dev/null +++ b/configure/os/CONFIG.darwin-x86-debug.Common @@ -0,0 +1,11 @@ +# CONFIG.darwin-x86-debug.Common +# +# Definitions for darwin-x86-debug host builds - darwin-x86 target build with debug compiler flags +# Sites may override these definitions in CONFIG_SITE.darwin-x86-debug.Common +#------------------------------------------------------- + +include $(CONFIG)/os/CONFIG.darwin-x86.Common + +# Removes -O optimization and adds -g compile option +HOST_OPT=NO + diff --git a/configure/toolchain.c b/configure/toolchain.c index af03f5246..0a5276045 100644 --- a/configure/toolchain.c +++ b/configure/toolchain.c @@ -64,7 +64,3 @@ COMMANDLINE_LIBRARY ?= EPICS #else COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS)) #endif - -#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE>2 -OP_SYS_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -#endif diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 5f3176b6a..732c98654 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -8,41 +8,142 @@ under the 3.15 release to which they were originally committed.** Thus it is important to read more than just the first section to understand everything that has changed in each release. -The PVA submodules each have their own individual sets of release notes which -should also be read to understand what has changed since earlier releases: +The external PVA submodules each have their own individual release notes files. +However the entries describing changes included in those submodules since EPICS +7.0.5 have now been copied into the appropriate place of this file. -- [normativeTypes](https://github.com/epics-base/normativeTypesCPP/blob/master/documentation/RELEASE_NOTES.md) -- [pvAccess](http://epics-base.github.io/pvAccessCPP/pvarelease_notes.html) -- [pvData](http://epics-base.github.io/pvDataCPP/release_notes.html) -- [pvDatabase](https://github.com/epics-base/pvDatabaseCPP/blob/master/documentation/RELEASE_NOTES.md) -- [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html) -- [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md) +__This version of EPICS has not been released yet.__ -**This version of EPICS has not been released yet.** +## Changes made on the 7.0 branch since 7.0.9 -## Changes made on the 7.0 branch since 7.0.8.1 +__Add new items below here__ -### DBE_PROPERTY event rate changed +----- -Updating property fields now only post DBE_PROPERTY events if the +## EPICS Release 7.0.9 + +### Core documentation published at ReadTheDocs + +The `documentation` directory's `Makefile` can now run various publication scripts including Sphinx and Doxygen to generate formatted documentation that is now being published +[at docs.epics-controls.org](https://docs.epics-controls.org/projects/base/en/latest/index.html) +and integrated into the main [EPICS Documentation website](https://docs.epics-controls.org/en/latest/index.html). +The best place to find out more about these mechanisms is the +[Contribution Guide](https://docs.epics-controls.org/en/latest/CONTRIBUTING.html) +although it doesn't currently cover the new processes added to epics-base. + +Much of the documentation generated from .dbd.pod files at build time is now +also being converted into MarkDown (.md) files and installed into the top-level +`doc` directory. Some users might find it quicker to look up information about a +record type by opening these files in a text editor intead of opening a browser +and loading the HTML versions or finding and opening the files from the EPICS +Documentation site. + +### Post monitors from compress record when it's reset + +Writing into a compress record's `RES` field now posts a monitor event instead +of only changing `VAL`. Monitor clients will therefore receive an empty array. + +### The AMSG error message propagates through MSS links + +A database link with the MSS attribute will now propagate not only SEVR and +STAT, but also AMSG. This field contains additional information that complements +STAT. Links with MS or MSI attributes do not propagate STAT, and therefore do +not propagate AMSG, either. + +Channel Access links do not propagate AMSG, regardless of the MSS attribute, +because the message is not available as Channel metadata. + +### Reloading record aliases + +Aliases can now be defined more than once as long as they still refer to the +same record, unless the global variable `dbRecordsOnceOnly` is non-zero. +This allows database files to be loaded multiple times, even if they contain +alias definitions. + +### `DBE_PROPERTY` event rate changed + +Updating property fields now only posts `DBE_PROPERTY` events if the field actually changed. +### Changes to msi related to include paths + +There are two changes to `msi` included here. + +`msi` now treats files included by .template or .substutiions files in a more +consistent way: for relative paths, it will always look relative to the current +working directory if no `-I` flags are passed, and if they are passed then it +will search for the _relative_ path from each of those flags. That is, the +following will now find the file `bar.template` located at +`/some/path/rel/path/bar.template` +``` +$ cat foo.substitutions +file rel/path/bar.template { + # contents +} +$ msi -I /some/path foo.substitutions +``` + +Note that this does provide one change from previous behaviour: when opening a +file from the command line, `msi` will not use the `-I`-specified paths to +search for the file, but will only work relative to the current working +directory, consistent with most commandline utilities. + ### Allow users to delete previously created records from the database From this release, record instances and aliases that have already been loaded by an IOC can be removed from the database again before the call to iocInit by loading a second instance of the named records but using `"#"` in place of the record type. Values for the fields are not required or advised, just use -an empty record body { }. This is useful when a template defines records that +an empty record body `{}`. This is useful when a template defines records that are not wanted in some IOCs, without having to split or duplicate the original template. For example this will remove the record named "unwanted": ``` -record("#", "unwanted") { } +record("#", "unwanted") {} ``` +### Only keep readline history for interactive sessions + +Previously, all IOCsh commands were persisited in the libreadline history +(when readline support is included). +Going forward, only interactive commands are saved. + +### Type change to asTrap serverSpecific data + +Change `void*` to `dbChannel*` in `asTrapWriteBeforeWithData()` and +`asTrapWriteMessage::serverSpecific` to reflect the reality since +the `dbAddr*` to `dbChannel*` migration. +External code wishing to support both before and after 3.15 should +already be conditionally casting to/from the appropriate type. + +### Fix issues with `_FORTIFY_SOURCE=3` + +This release fixes the false positives failures whhen building with `_FORTIFY_SOURCE` level 3. +The override introduced in 7.0.8.1 has been removed. + +### Other + +- genVersionHeader: work with git submodules and worktrees. +- avoid UB with self `pthread_join()` +- freebsd: Add support for x86 and amd64 builds +- Clear AMSG when SEVR becomes zero. +- `seqRecord` fix support for link `DLY0` +- Add `ABORT_ON_ASSERT` flag to `CONFIG_SITE_ENV` +- rationalize osdMutex + +### Submodule updates + +The pvDatabase module was updated to version 4.7.2: + +* Resolved issue with changed field set in the case where the top level (master) +field ("_") is not requested by the client, but the master field callback causes +all fields to be marked as updated, rather than only those fields that have +actually been modified. + +----- + ## EPICS Release 7.0.8.1 ### Limit to `_FORTIFY_SOURCE=2` @@ -280,6 +381,50 @@ The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC expression engine and is available to all software using that (calc and calcout record types, access security library and some extensions). +### Submodule updates + +The pvData module was updated to version 8.0.6: + +- Compatible changes + - Actually enable JSON-5 output in PVStructure::Formatter::JSON when available. + - Fix unaligned access issues for some ARM/Linux targets. + +The pvAccess module was updated to version 7.1.7: + +- Changes + - Registering the PVA server with the IOC now sets the `PVAS_SERVER_PORT` + variable in the environment. + +The pva2pva module was updated to version 1.4.1: + +- Bug Fixes + - `dbLoadGroup` was fixed +- Additions + - Support for "meta" member at top of array of structs + +The pvDatabase module was updated to version 4.7.1: + +* Added data distributor plugin which can be used for distributing data between + a group of clients. The plugin is triggered by the request string of the + form: + + `_[distributor=group:;set:;trigger:;updates:;mode:]` + + The plugin parameters are optional and are described bellow: + + - group: this parameter indicates a group that client application belongs to (default value: "default"); groups of clients are completely independent of each other + + - set: this parameter designates a client set that application belongs to within its group (default value: "default") + + - trigger: this is the PV structure field that distinguishes different channel updates (default value: "timeStamp"); for example, for area detector images one could use the "uniqueId" field of the NTND structure + + - updates: this parameter configures how many sequential updates a client (or a set of clients) will receive before the data distributor starts updating the next one (default value: "1") + + - mode: this parameter configures how channel updates are to be distributed between clients in a set: + - one: update goes to one client per set + - all: update goes to all clients in a set + - default is "one" if client set id is not specified, and "all" if set id is specified + ----- ## EPICS Release 7.0.7 @@ -358,10 +503,10 @@ changed to `(p)->dtor`. The order over operations when processing a waveformRecord is adjusted so that updates to NORD is posted with the correct timestamp. -### Automatic COMMANDLINE_LIBRARY w/ newer compilers +### Automatic `COMMANDLINE_LIBRARY` with newer compilers When built with a compiler supporting `__has_include<>`, the presence -of the `` will be used to automatically determine +of a `readline/readline.h` header will be used to automatically determine a default value for `COMMANDLINE_LIBRARY`. Mingw builds with readline support now link `-ltermcap` instead of `-lcurses`. @@ -530,6 +675,44 @@ or if unsupported (`$TERM` not set, or Windows < 10). The `dbnd` server side filter now passes through alarm and property change events, even when not exceeding the deadband. +### Submodule updates + +The pvData module was updated to version 8.0.5: + +- Compatible changes + - Internal changes to use the YAJL API for generating JSON and JSON-5 output. + +The pvAccess module was updated to version 7.1.6: + +- Changes to caProvider + - Bug fix related to enum values. + - More internal changes to improve performance when connecting tens of + thousands of CA channels. +- Several minor internal improvements. + +The pva2pva module was updated to version 1.4.0: + +- Bug Fixes + - Apply ACF when writing to atomic group +- Additions + - Add new "structure" to @ref qsrv_group_map_types +- Changes + - Add Access Security hooks for single and group writes. + - Enable "Async Soft Channel" for output links + - When built against Base 7.0.6.1, set timeStamp.userTag from UTAG field. + - Add DTYP="QSRV Set UTag" for longin, which sets UTAG=VAL. + +The pvDatabase module was updated to version 4.7.0: + +* Added support for the whole structure (master field) server side plugins. + The whole structure is identified as the `_` string, and a pvRequest string + that applies a plugin to it takes the form: + + `field(_[XYZ=A:3;B:uniqueId])` + + where `XYZ` is the name of a specific filter plugin that takes parameters + `A` and `B` with values `3` and `uniqueId` respectively. + ----- ## EPICS Release 7.0.6.1 @@ -596,6 +779,15 @@ This was done to simplify the code and may have improved performance slightly fo Many of the built-in record types have had improvements to their documentation with additional fields added to the tables, rewrites of descriptions and links to other documents added or fixed. +### Submodule updates + +The pvAccess module was updated to version 7.1.4: + +- Changes to caProvider + - Resolve issues with pv structures that don't have a value field + - Add NULL checks for handling unusual structures + - Speed up channel creation when using large numbers of channels + ----- ## EPICS Release 7.0.6 @@ -606,7 +798,7 @@ These target architectures have been removed: + darwin-ppc, darwin-ppcx86 + linux-386, linux-486, linux-586, linux-686, linux-athlon (cross-build) -+ linux-cris, linux-cris_v10, linux-cris_v32 (cross-build) ++ linux-cris, linux-cris\_v10, linux-cris\_v32 (cross-build) + RTEMS-at91rm9200ek, RTEMS-gen68360, RTEMS-mcp750, RTEMS-mvme167, RTEMS-psim (cross-build) @@ -624,9 +816,9 @@ running on RTEMS 5: - RTEMS-beagleboneblack - RTEMS-pc686 -- RTEMS-qoriq_e500 (MVME2500) -- RTEMS-xilinx_zynq_a9_qemu -- RTEMS-xilinx_zynq_zedboard +- RTEMS-qoriq\_e500 (MVME2500) +- RTEMS-xilinx\_zynq\_a9\_qemu +- RTEMS-xilinx\_zynq\_zedboard The EPICS support for RTEMS 4 has always relied on RTEMS-specific kernel APIs which cannot be used on an SMP system, so a new port was @@ -638,7 +830,7 @@ to run `make distclean` if switching a single source tree from one to the other (both header files and dependency files are different between the two and must be cleaned out). -The configuration variable RTEMS_VERSION in the EPICS config file +The configuration variable `RTEMS_VERSION` in the EPICS config file `configure/os/CONFIG_SITE.Common.RTEMS` must be set to the full 3- part version number for RTEMS 4 releases, e.g. `4.9.1`, `4.10.2` but for RTEMS 5.1 and later it must only contain the major version @@ -836,6 +1028,39 @@ Test programs written directly in Perl as a `.plt` script should implement a similar timeout for themselves. The "netget" test in Base does this in a way that works on Windows as well as Unix-like hosts. +### Submodule updates + +The pvAccess module was updated to version 7.1.4: + +- Changes + - Adjust argument parsing with pvput (Jesus Vasquez). + +The pva2pva module was updated to version 1.3.1: + +- Bug Fixes + - Correct handling for server side filters. +- Changes + - Syncing softMain.cpp with epics-base + +The pvDatabase module was updated to version 4.6.0: + +* Access Security is now supported. +* special has been revised and extended. +* addRecord, removeRecord, processRecord, and traceRecord are replaced by pvdbcr versions. +* support is DEPRECATED + +The pvaClient module was updated to version 4.8.0: + +* `PvaClientNTMultiData::getChannelChangeFlags` is a new method. It fixes + issue #66. +* Fix for issue #68. Both `PvaClientArray` and `PvaClientField` are not longer + present. Neither was previously implemented. +* Several public methods are now protected. They were never meant to be called + by clients. +* Issue #70 has been fixed. +* Changes was made to increase the performance of `pvaMultiChannel`. +* doxygen changes were made. + ----- ## EPICS Release 7.0.5 @@ -873,7 +1098,7 @@ compile device supports as loadable modules. ### Priority inversion safe Posix mutexes On Posix systems, epicsMutex now support priority inheritance if available. -The IOC needs to run with SCHED_FIFO engaged to use these. +The IOC needs to run with `SCHED_FIFO` engaged to use these. Support for Posix implementations before POSIX.1-2001 (`_XOPEN_SOURCE < 500`, glibc version < 2.3.3) has been dropped. @@ -1006,14 +1231,14 @@ properly handle zero-length arrays. The `caget`, `caput` and `camonitor` client programs are known to work with empty arrays as long as they were built with this or a later version of EPICS. -#### Change to the db_access.h `dbr_size_n(TYPE, COUNT)` macro +#### Change to the db\_access.h `dbr_size_n(TYPE, COUNT)` macro When called with COUNT=0 this macro no longer returns the number of bytes required for a scalar (1 element) but for an empty array (0 elements). Make sure code that uses this doesn't call it with COUNT=0 when it really means COUNT=1. -Note that the db_access.h header file is included by cadef.h so the change +Note that the db\_access.h header file is included by cadef.h so the change can impact Channel Access client programs that use this macro. #### Channel Access support for zero-length arrays @@ -1123,6 +1348,35 @@ GNUmake added the directive `undefine` in version 3.82 to allow variables to be undefined. Support for this has been added to the EPICS Release file parser, so `undefine` can now be used in configure/RELEASE files to unset variables. + +### Submodule updates + +The pvData module was updated to version 8.0.4: + +- Incompatible changes + - Remove `ByteBuffer::align()` +- Compatible changes + - Deprecate `SerializableControl::alignBuffer()` and + `DeserializableControl::alignData()` + - `shared_vector_convert<>()` fix convert of empty, untyped, array + +The pvAccess module was updated to version 7.1.3: + +- Bug fixes + - Increase default TCP timeout to 40 seconds. + Applies a 4/3 multiplier on `$EPICS_PVA_CONN_TMO` for compatibility. + - CA Provider implementation restructured to simplify, reduce duplication + and fix issues #163 and #165. +- Changes + - Enable building of pvtools to all except vxWorks, RTEMS and iOS. + +The pva2pva module was updated to version 1.3.0: + +- Changes + - Add `dbLoadGroup()` iocsh function to read group JSON definitions + from a file. Mappings in files must refer to full record names + instead of fields. eg. 'recname.VAL' instead of 'VAL'. + ----- ## EPICS Release 7.0.4.1 @@ -1188,7 +1442,7 @@ The following launchpad bugs have fixes included in this release: operators on aarch64 - [lp: 1853148](https://bugs.launchpad.net/bugs/1853148), mingw compiler problem with printf/scanf formats -- [lp: 1852653](https://bugs.launchpad.net/bugs/1852653), USE_TYPED_DSET +- [lp: 1852653](https://bugs.launchpad.net/bugs/1852653), `USE_TYPED_DSET` incompatible with C++ - [lp: 1862328](https://bugs.launchpad.net/bugs/1862328), Race condition on IOC start leaves rsrv unresponsive @@ -1198,7 +1452,7 @@ The following launchpad bugs have fixes included in this release: - [lp: 1868680](https://bugs.launchpad.net/bugs/1868680), Access Security file reload (asInit) fails -### \*_API macros in EPICS headers +### `*_API` macros in EPICS headers Internally, the Com and ca libraries now express dllimport/export (Windows) and symbol visibility (GCC) using library-specific macros (eg. `LIBCOM_API`) @@ -1432,7 +1686,7 @@ The API functions `epicsGetExecDir()` and `epicsGetExecName()` are also added to `osiFileName.h` to provide runtime access to the directory or filename of the executable with which the process was started. -### Decouple LINKER_USE_RPATH and STATIC_BUILD +### Decouple `LINKER_USE_RPATH` and `STATIC_BUILD` Previously, setting `STATIC_BUILD=NO` implied `LINKER_USE_RPATH=NO`. This is no longer the case. Setting `LINKER_USE_RPATH=YES` will @@ -2011,7 +2265,7 @@ number instead, like this: Channel Access does not (and probably never will) directly support 64-bit integer types, so the new field types are presented to the CA server as `DBF_DOUBLE` values. This means that field values larger than 2^52 -(0x10_0000_0000_0000 = 4503599627370496) cannot be transported over Channel +(0x10\_0000\_0000\_0000 = 4503599627370496) cannot be transported over Channel Access without their least significant bits being truncated. The EPICS V4 pvAccess network protocol _can_ transport 64-bit data types however, and a future release of the pvaSrv module will connect this ability to the fields of diff --git a/modules/database/src/ioc/db/dbCommon.dbd.pod b/modules/database/src/ioc/db/dbCommon.dbd.pod index fdeefdddd..e05d27c42 100644 --- a/modules/database/src/ioc/db/dbCommon.dbd.pod +++ b/modules/database/src/ioc/db/dbCommon.dbd.pod @@ -286,7 +286,11 @@ Inf (Infinite) value. UDF defaults to TRUE but can be set in a database file. Record and device support routines which write to the VAL field are generally responsible for setting and clearing UDF. -=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF +The B field specifies the alarm severity that the record will be set to +whenever its value is undefined (i.e., the UDF field is 1). This includes the +initial severity of the record being undefined after the IOC boots. + +=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF, UDFS =cut diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c index 619b2ca9e..16cc33279 100644 --- a/modules/database/src/ioc/db/dbDbLink.c +++ b/modules/database/src/ioc/db/dbDbLink.c @@ -226,9 +226,10 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, } if (!status && precord != dbChannelRecord(chan)) - recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode, + recGblInheritSevrMsg(plink->value.pv_link.pvlMask & pvlOptMsMode, plink->precord, - dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr); + dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr, + dbChannelRecord(chan)->amsg); return status; } @@ -378,8 +379,8 @@ static long dbDbPutValue(struct link *plink, short dbrType, dbCommon *pdest = dbChannelRecord(chan); long status = dbPut(paddr, dbrType, pbuffer, nRequest); - recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta, - psrce->nsev); + recGblInheritSevrMsg(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta, + psrce->nsev, psrce->namsg); if (status) return status; diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c index 83a2c9114..9b5085ea0 100644 --- a/modules/database/src/ioc/db/dbIocRegister.c +++ b/modules/database/src/ioc/db/dbIocRegister.c @@ -75,21 +75,21 @@ static const iocshFuncDef dbbFuncDef = {"dbb",1,dbbArgs, "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);} +static void dbbCallFunc(const iocshArgBuf *args) { iocshSetError(dbb(args[0].sval));} /* dbd */ static const iocshArg dbdArg0 = { "record name",iocshArgStringRecord}; static const iocshArg * const dbdArgs[1] = {&dbdArg0}; static const iocshFuncDef dbdFuncDef = {"dbd",1,dbdArgs, "Remove breakpoint from a record.\n"}; -static void dbdCallFunc(const iocshArgBuf *args) { dbd(args[0].sval);} +static void dbdCallFunc(const iocshArgBuf *args) { iocshSetError(dbd(args[0].sval));} /* dbc */ 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 lockset until next breakpoint is found.\n"}; -static void dbcCallFunc(const iocshArgBuf *args) { dbc(args[0].sval);} +static void dbcCallFunc(const iocshArgBuf *args) { iocshSetError(dbc(args[0].sval));} /* dbs */ static const iocshArg dbsArg0 = { "record name",iocshArgStringRecord}; @@ -97,12 +97,12 @@ static const iocshArg * const dbsArgs[1] = {&dbsArg0}; static const iocshFuncDef dbsFuncDef = {"dbs",1,dbsArgs, "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);} +static void dbsCallFunc(const iocshArgBuf *args) { iocshSetError(dbs(args[0].sval));} /* dbstat */ static const iocshFuncDef dbstatFuncDef = {"dbstat",0,0, "Print list of suspended records, and breakpoints set in locksets.\n"}; -static void dbstatCallFunc(const iocshArgBuf *args) { dbstat();} +static void dbstatCallFunc(const iocshArgBuf *args) { iocshSetError(dbstat());} /* dbp */ static const iocshArg dbpArg0 = { "record name",iocshArgStringRecord}; @@ -119,7 +119,9 @@ static const iocshFuncDef dbpFuncDef = { " 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);} +{ + iocshSetError(dbp(args[0].sval,args[1].ival)); +} /* dbap */ static const iocshArg dbapArg0 = { "record name",iocshArgStringRecord}; @@ -127,7 +129,7 @@ static const iocshArg * const dbapArgs[1] = {&dbapArg0}; static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs, "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);} +static void dbapCallFunc(const iocshArgBuf *args) { iocshSetError(dbap(args[0].sval));} /* dbsr */ static const iocshArg dbsrArg0 = { "interest level",iocshArgInt}; @@ -150,7 +152,7 @@ static const iocshFuncDef dbcarFuncDef = {"dbcar",2,dbcarArgs, " 2 - Shows info. for all links.\n"}; static void dbcarCallFunc(const iocshArgBuf *args) { - dbcar(args[0].sval,args[1].ival); + iocshSetError(dbcar(args[0].sval,args[1].ival)); } /* dbjlr */ @@ -162,7 +164,7 @@ static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs, "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); + iocshSetError(dbjlr(args[0].sval,args[1].ival)); } /* dbel */ @@ -176,7 +178,7 @@ static const iocshFuncDef dbelFuncDef = {"dbel",2,dbelArgs, "Example: dbel aitest 2\n"}; static void dbelCallFunc(const iocshArgBuf *args) { - dbel(args[0].sval, args[1].ival); + iocshSetError(dbel(args[0].sval, args[1].ival)); } /* dba */ @@ -187,7 +189,7 @@ static const iocshFuncDef dbaFuncDef = {"dba",1,dbaArgs, "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);} +static void dbaCallFunc(const iocshArgBuf *args) { iocshSetError(dba(args[0].sval));} /* dbl */ static const iocshArg dblArg0 = { "record type",iocshArgString}; @@ -204,7 +206,7 @@ static const iocshFuncDef dblFuncDef = {"dbl",2,dblArgs, " dbl(\"ai\",\"HIGH LOW VAL PREC\")\n"}; static void dblCallFunc(const iocshArgBuf *args) { - dbl(args[0].sval,args[1].sval); + iocshSetError(dbl(args[0].sval,args[1].sval)); } /* dbnr */ @@ -213,7 +215,7 @@ static const iocshArg * const dbnrArgs[1] = {&dbnrArg0}; static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs, "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);} +static void dbnrCallFunc(const iocshArgBuf *args) { iocshSetError(dbnr(args[0].ival));} /* dbli */ static const iocshArg dbliArg0 = { "pattern",iocshArgString}; @@ -221,7 +223,7 @@ static const iocshArg * const dbliArgs[1] = {&dbliArg0}; static const iocshFuncDef dbliFuncDef = {"dbli",1,dbliArgs, "List info() tags with names matching pattern.\n\n" "Example: dbli(\"autosave*\")\n"}; -static void dbliCallFunc(const iocshArgBuf *args) { dbli(args[0].sval);} +static void dbliCallFunc(const iocshArgBuf *args) { iocshSetError(dbli(args[0].sval));} /* dbla */ static const iocshArg dblaArg0 = { "pattern",iocshArgStringRecord}; @@ -229,7 +231,7 @@ static const iocshArg * const dblaArgs[1] = {&dblaArg0}; static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs, "List record alias()s by alias name pattern.\n\n" "Example: dbla(\"alia*\")\n"}; -static void dblaCallFunc(const iocshArgBuf *args) { dbla(args[0].sval);} +static void dblaCallFunc(const iocshArgBuf *args) { iocshSetError(dbla(args[0].sval));} /* dbgrep */ static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord}; @@ -240,7 +242,7 @@ static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs, " - \"?\", 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);} +static void dbgrepCallFunc(const iocshArgBuf *args) { iocshSetError(dbgrep(args[0].sval));} /* dbgf */ static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord}; @@ -250,7 +252,7 @@ static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs, "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);} +static void dbgfCallFunc(const iocshArgBuf *args) { iocshSetError(dbgf(args[0].sval));} /* dbpf */ static const iocshArg dbpfArg0 = { "record name",iocshArgStringRecord}; @@ -261,7 +263,7 @@ static const iocshFuncDef dbpfFuncDef = {"dbpf",2,dbpfArgs, "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);} +{ iocshSetError(dbpf(args[0].sval,args[1].sval));} /* dbpr */ static const iocshArg dbprArg0 = { "record name",iocshArgStringRecord}; @@ -279,14 +281,14 @@ static const iocshFuncDef dbprFuncDef = { "Example: dbpr aitest 3\n" }; static void dbprCallFunc(const iocshArgBuf *args) -{ dbpr(args[0].sval,args[1].ival);} +{ iocshSetError(dbpr(args[0].sval,args[1].ival));} /* dbtr */ static const iocshArg dbtrArg0 = { "record name",iocshArgStringRecord}; static const iocshArg * const dbtrArgs[1] = {&dbtrArg0}; static const iocshFuncDef dbtrFuncDef = {"dbtr",1,dbtrArgs, "Process record and then some fields.\n"}; -static void dbtrCallFunc(const iocshArgBuf *args) { dbtr(args[0].sval);} +static void dbtrCallFunc(const iocshArgBuf *args) { iocshSetError(dbtr(args[0].sval));} /* dbtgf */ static const iocshArg dbtgfArg0 = { "record name",iocshArgStringRecord}; @@ -296,7 +298,7 @@ static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs, "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);} +static void dbtgfCallFunc(const iocshArgBuf *args) { iocshSetError(dbtgf(args[0].sval));} /* dbtpf */ static const iocshArg dbtpfArg0 = { "record name",iocshArgStringRecord}; @@ -308,7 +310,7 @@ static const iocshFuncDef dbtpfFuncDef = {"dbtpf",2,dbtpfArgs, "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);} +{ iocshSetError(dbtpf(args[0].sval,args[1].sval));} /* dbior */ static const iocshArg dbiorArg0 = { "driver name",iocshArgString}; @@ -317,7 +319,7 @@ static const iocshArg * const dbiorArgs[] = {&dbiorArg0,&dbiorArg1}; static const iocshFuncDef dbiorFuncDef = {"dbior",2,dbiorArgs, "Driver Report.\n"}; static void dbiorCallFunc(const iocshArgBuf *args) -{ dbior(args[0].sval,args[1].ival);} +{ iocshSetError(dbior(args[0].sval,args[1].ival));} /* dbhcr */ static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0, @@ -327,7 +329,7 @@ static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0, "Use the UNIX sort command:\n" "dbhcr > report\n" "sort report > report.sorted\n"}; -static void dbhcrCallFunc(const iocshArgBuf *args) { dbhcr();} +static void dbhcrCallFunc(const iocshArgBuf *args) { iocshSetError(dbhcr());} /* gft */ static const iocshArg gftArg0 = { "record name",iocshArgStringRecord}; @@ -336,7 +338,7 @@ static const iocshFuncDef gftFuncDef = {"gft",1,gftArgs, "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);} +static void gftCallFunc(const iocshArgBuf *args) { iocshSetError(gft(args[0].sval));} /* pft */ static const iocshArg pftArg0 = { "record name",iocshArgStringRecord}; @@ -346,7 +348,7 @@ static const iocshFuncDef pftFuncDef = {"pft",2,pftArgs, "dbChannel put value.\n" "Example: pft aitest 5.0\n"}; static void pftCallFunc(const iocshArgBuf *args) -{ pft(args[0].sval,args[1].sval);} +{ iocshSetError(pft(args[0].sval,args[1].sval));} /* dbtpn */ static const iocshArg dbtpnArg0 = { "record name",iocshArgStringRecord}; @@ -359,12 +361,12 @@ static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs, "Example: dbtpn aitest\n" "Example: dbtpn aitest 5.0\n"}; static void dbtpnCallFunc(const iocshArgBuf *args) -{ dbtpn(args[0].sval,args[1].sval);} +{ iocshSetError(dbtpn(args[0].sval,args[1].sval));} /* dbNotifyDump */ static const iocshFuncDef dbNotifyDumpFuncDef = {"dbNotifyDump",0,0, "Report status of any active async processing with completion notification.\n"}; -static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { dbNotifyDump();} +static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { iocshSetError(dbNotifyDump());} /* dbPutAttribute */ static const iocshArg dbPutAttrArg0 = { "record type",iocshArgString}; @@ -375,7 +377,7 @@ static const iocshArg * const dbPutAttrArgs[] = 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);} +{ iocshSetError(dbPutAttribute(args[0].sval,args[1].sval,args[2].sval));} /* tpn */ static const iocshArg tpnArg0 = { "record name",iocshArgStringRecord}; @@ -385,7 +387,7 @@ static const iocshFuncDef tpnFuncDef = {"tpn",2,tpnArgs, "Test Process Notify.\n\n" "Example: tpn aitest 5.0\n"}; static void tpnCallFunc(const iocshArgBuf *args) -{ tpn(args[0].sval,args[1].sval);} +{ iocshSetError(tpn(args[0].sval,args[1].sval));} /* dblsr */ static const iocshArg dblsrArg0 = { "record name",iocshArgStringRecord}; @@ -399,7 +401,7 @@ static const iocshFuncDef dblsrFuncDef = {"dblsr",2,dblsrArgs, " 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);} +{ iocshSetError(dblsr(args[0].sval,args[1].ival));} /* dbLockShowLocked */ static const iocshArg dbLockShowLockedArg0 = { "interest level",iocshArgInt}; @@ -412,7 +414,7 @@ static const iocshFuncDef dbLockShowLockedFuncDef = { "Example: dbLockShowLocked 0\n" }; static void dbLockShowLockedCallFunc(const iocshArgBuf *args) -{ dbLockShowLocked(args[0].ival);} +{ iocshSetError(dbLockShowLocked(args[0].ival));} /* scanOnceSetQueueSize */ static const iocshArg scanOnceSetQueueSizeArg0 = { "size",iocshArgInt}; @@ -423,7 +425,7 @@ static const iocshFuncDef scanOnceSetQueueSizeFuncDef = {"scanOnceSetQueueSize", "Must be called before iocInit().\n"}; static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args) { - scanOnceSetQueueSize(args[0].ival); + iocshSetError(scanOnceSetQueueSize(args[0].ival)); } /* scanOnceQueueShow */ @@ -444,7 +446,7 @@ static const iocshFuncDef scanpplFuncDef = {"scanppl",1,scanpplArgs, "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);} +{ iocshSetError(scanppl(args[0].dval));} /* scanpel */ static const iocshArg scanpelArg0 = { "event name",iocshArgString}; @@ -452,7 +454,7 @@ static const iocshArg * const scanpelArgs[1] = {&scanpelArg0}; static const iocshFuncDef scanpelFuncDef = {"scanpel",1,scanpelArgs, "Print info for records with SCAN = \"Event\".\n"}; static void scanpelCallFunc(const iocshArgBuf *args) -{ scanpel(args[0].sval);} +{ iocshSetError(scanpel(args[0].sval));} /* postEvent */ static const iocshArg postEventArg0 = { "event name",iocshArgString}; @@ -468,7 +470,7 @@ static void postEventCallFunc(const iocshArgBuf *args) /* scanpiol */ static const iocshFuncDef scanpiolFuncDef = {"scanpiol",0,0, "Print info for records with SCAN = \"I/O Intr\".\n"}; -static void scanpiolCallFunc(const iocshArgBuf *args) { scanpiol();} +static void scanpiolCallFunc(const iocshArgBuf *args) { iocshSetError(scanpiol());} /* callbackSetQueueSize */ static const iocshArg callbackSetQueueSizeArg0 = { "bufsize",iocshArgInt}; @@ -479,7 +481,7 @@ static const iocshFuncDef callbackSetQueueSizeFuncDef = {"callbackSetQueueSize", "Must be called before iocInit().\n"}; static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args) { - callbackSetQueueSize(args[0].ival); + iocshSetError(callbackSetQueueSize(args[0].ival)); } /* callbackQueueShow */ @@ -504,7 +506,7 @@ static const iocshFuncDef callbackParallelThreadsFuncDef = {"callbackParallelThr "or one of LOW, MEDIUM, or HIGH.\n"}; static void callbackParallelThreadsCallFunc(const iocshArgBuf *args) { - callbackParallelThreads(args[0].ival, args[1].sval); + iocshSetError(callbackParallelThreads(args[0].ival, args[1].sval)); } /* dbStateCreate */ @@ -514,7 +516,8 @@ static const iocshFuncDef dbStateCreateFuncDef = {"dbStateCreate", 1, dbStateCre "Allocate new state name for \"state\" filter.\n"}; static void dbStateCreateCallFunc (const iocshArgBuf *args) { - dbStateCreate(args[0].sval); + if (!dbStateCreate(args[0].sval)) + iocshSetError(-1); } /* dbStateSet */ @@ -527,6 +530,8 @@ static void dbStateSetCallFunc (const iocshArgBuf *args) if (sid) dbStateSet(sid); + else + iocshSetError(-1); } /* dbStateClear */ @@ -539,6 +544,8 @@ static void dbStateClearCallFunc (const iocshArgBuf *args) if (sid) dbStateClear(sid); + else + iocshSetError(-1); } /* dbStateShow */ @@ -552,6 +559,8 @@ static void dbStateShowCallFunc (const iocshArgBuf *args) if (sid) dbStateShow(sid, args[1].ival); + else + iocshSetError(-1); } /* dbStateShowAll */ diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h index b8a819b98..e53133541 100644 --- a/modules/database/src/ioc/db/dbLink.h +++ b/modules/database/src/ioc/db/dbLink.h @@ -391,6 +391,10 @@ typedef struct lset { #define dbGetSevr(link, sevr) \ dbGetAlarm(link, NULL, sevr) +/** @brief Lookup link field name from pointer. + * Returns only field name. aka. value of ``dbFldDes::name`` + * @since 3.16.2 + */ DBCORE_API const char * dbLinkFieldName(const struct link *plink); DBCORE_API void dbInitLink(struct link *plink, short dbfType); diff --git a/modules/database/src/ioc/db/recGbl.c b/modules/database/src/ioc/db/recGbl.c index bf6ea7e88..002a7aebc 100644 --- a/modules/database/src/ioc/db/recGbl.c +++ b/modules/database/src/ioc/db/recGbl.c @@ -260,8 +260,8 @@ int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr) return recGblSetSevrMsg(precord, new_stat, new_sevr, NULL); } -void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, - epicsEnum16 sevr) +void recGblInheritSevrMsg(int msMode, void *precord, epicsEnum16 stat, + epicsEnum16 sevr, const char *msg) { switch (msMode) { case pvlOptNMS: @@ -274,11 +274,17 @@ void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, recGblSetSevr(precord, LINK_ALARM, sevr); break; case pvlOptMSS: - recGblSetSevr(precord, stat, sevr); + /* Only MSS inherits msg */ + recGblSetSevrMsg(precord, stat, sevr, "%s", msg); break; } } +void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, + epicsEnum16 sevr) +{ + recGblInheritSevrMsg(msMode, precord, stat, sevr, NULL); +} void recGblFwdLink(void *precord) { diff --git a/modules/database/src/ioc/db/recGbl.h b/modules/database/src/ioc/db/recGbl.h index cf3db4bc5..4a21e7f34 100644 --- a/modules/database/src/ioc/db/recGbl.h +++ b/modules/database/src/ioc/db/recGbl.h @@ -73,6 +73,8 @@ DBCORE_API int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr); DBCORE_API void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, epicsEnum16 sevr); +DBCORE_API void recGblInheritSevrMsg(int msMode, void *precord, epicsEnum16 stat, + epicsEnum16 sevr, const char *msg); DBCORE_API int recGblSetSevrMsg(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr, EPICS_PRINTF_FMT(const char *msg), ...) EPICS_PRINTF_STYLE(4,5); diff --git a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c index ff9aafc78..21a34e857 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c +++ b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c @@ -207,7 +207,7 @@ static const iocshFuncDef dbPvdTableSizeFuncDef = { }; static void dbPvdTableSizeCallFunc(const iocshArgBuf *args) { - dbPvdTableSize(args[0].ival); + iocshSetError(dbPvdTableSize(args[0].ival)); } /* dbReportDeviceConfig */ diff --git a/modules/database/src/ioc/dbtemplate/Makefile b/modules/database/src/ioc/dbtemplate/Makefile index 6e7ac1bc0..375c0da92 100644 --- a/modules/database/src/ioc/dbtemplate/Makefile +++ b/modules/database/src/ioc/dbtemplate/Makefile @@ -14,6 +14,7 @@ SRC_DIRS += $(IOCDIR)/dbtemplate PROD_CMD += msi msi_SRCS = msi.cpp +msi_SYS_LIBS_WIN32 = shlwapi DOCS += msi.md INC += dbLoadTemplate.h diff --git a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y index a382459c1..f2fca00f8 100644 --- a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y +++ b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y @@ -41,6 +41,17 @@ static int var_count, sub_count; int dbTemplateMaxVars = 100; epicsExportAddress(int, dbTemplateMaxVars); +static +int msiLoadRecords(const char *fname, const char *subs) +{ + int ret = dbLoadRecords(fname, subs); + if(ret) { + fprintf(stderr, "dbLoadRecords(\"%s\", %s)\n", fname, subs); + yyerror("Error while reading included file"); + } + return ret; +} + %} %start substitution_file @@ -167,7 +178,7 @@ pattern_definition: global_definitions fprintf(stderr, "pattern_definition: pattern_values empty\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; } | O_BRACE pattern_values C_BRACE { @@ -175,7 +186,7 @@ pattern_definition: global_definitions fprintf(stderr, "pattern_definition:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; *sub_locals = '\0'; sub_count = 0; } @@ -190,7 +201,7 @@ pattern_definition: global_definitions fprintf(stderr, "pattern_definition:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; dbmfFree($1); *sub_locals = '\0'; sub_count = 0; @@ -250,7 +261,7 @@ variable_substitution: global_definitions fprintf(stderr, "variable_substitution: variable_definitions empty\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; } | O_BRACE variable_definitions C_BRACE { @@ -258,7 +269,7 @@ variable_substitution: global_definitions fprintf(stderr, "variable_substitution:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; *sub_locals = '\0'; } | WORD O_BRACE variable_definitions C_BRACE @@ -272,7 +283,7 @@ variable_substitution: global_definitions fprintf(stderr, "variable_substitution:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; dbmfFree($1); *sub_locals = '\0'; } @@ -328,6 +339,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) { FILE *fp; int i; + int err; line_num = 1; @@ -377,7 +389,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) yyrestart(fp); } - yyparse(); + err = yyparse(); for (i = 0; i < var_count; i++) { dbmfFree(vars[i]); @@ -390,5 +402,5 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) dbmfFree(db_file_name); db_file_name = NULL; } - return 0; + return err; } diff --git a/modules/database/src/ioc/dbtemplate/msi.cpp b/modules/database/src/ioc/dbtemplate/msi.cpp index 88c5d160d..0da488cba 100644 --- a/modules/database/src/ioc/dbtemplate/msi.cpp +++ b/modules/database/src/ioc/dbtemplate/msi.cpp @@ -27,6 +27,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + #define MAX_BUFFER_SIZE 4096 #define MAX_DEPS 1024 @@ -61,7 +65,7 @@ typedef struct inputData inputData; static void inputConstruct(inputData **ppvt); static void inputDestruct(inputData * const pvt); static void inputAddPath(inputData * const pvt, const char * const pval); -static void inputBegin(inputData * const pvt, const char * const fileName); +static void inputBegin(inputData * const pvt, const char * const fileName, bool fromCmdLine); static char *inputNextLine(inputData * const pvt); static void inputNewIncludeFile(inputData * const pvt, const char * const name); static void inputErrPrint(const inputData * const pvt); @@ -83,7 +87,8 @@ static void addMacroReplacements(MAC_HANDLE * const macPvt, const char * const pval); static void makeSubstitutions(inputData * const inputPvt, MAC_HANDLE * const macPvt, - const char * const templateName); + const char * const templateName, + bool fromCmdLine); /*Global variables */ static int opt_V = 0; @@ -171,7 +176,7 @@ int main(int argc,char **argv) if (substitutionName.empty()) { STEP("Single template+substitutions file"); - makeSubstitutions(inputPvt, macPvt, templateName); + makeSubstitutions(inputPvt, macPvt, templateName, true); } else { subInfo *substitutePvt; @@ -203,7 +208,7 @@ int main(int argc,char **argv) macPushScope(macPvt); addMacroReplacements(macPvt, macStr); - makeSubstitutions(inputPvt, macPvt, filename); + makeSubstitutions(inputPvt, macPvt, filename, false); if (localScope) macPopScope(macPvt); @@ -276,14 +281,15 @@ static const char *cmdNames[] = {"include","substitute"}; static void makeSubstitutions(inputData * const inputPvt, MAC_HANDLE * const macPvt, - const char * const templateName) + const char * const templateName, + bool fromCmdLine) { char *input; static char buffer[MAX_BUFFER_SIZE]; int n; ENTER; - inputBegin(inputPvt, templateName); + inputBegin(inputPvt, templateName, fromCmdLine); while ((input = inputNextLine(inputPvt))) { int expand=1; char *p; @@ -378,7 +384,7 @@ struct inputData { inputData() { memset(inputBuffer, 0, sizeof(inputBuffer) * sizeof(inputBuffer[0])); }; }; -static void inputOpenFile(inputData *pinputData, const char * const filename); +static void inputOpenFile(inputData *pinputData, const char * const filename, bool fromCmdLine); static void inputCloseFile(inputData *pinputData); static void inputCloseAllFiles(inputData *pinputData); @@ -431,11 +437,11 @@ static void inputAddPath(inputData * const pinputData, const char * const path) EXIT; } -static void inputBegin(inputData * const pinputData, const char * const fileName) +static void inputBegin(inputData * const pinputData, const char * const fileName, bool fromCmdLine) { ENTER; inputCloseAllFiles(pinputData); - inputOpenFile(pinputData, fileName); + inputOpenFile(pinputData, fileName, fromCmdLine); EXIT; } @@ -462,7 +468,7 @@ static void inputNewIncludeFile(inputData * const pinputData, const char * const name) { ENTER; - inputOpenFile(pinputData,name); + inputOpenFile(pinputData, name, false); EXIT; } @@ -493,7 +499,15 @@ static void inputErrPrint(const inputData *const pinputData) EXIT; } -static void inputOpenFile(inputData *pinputData, const char * const filename) +static int isPathRelative(const char * const path) { +#ifdef _WIN32 + return path && PathIsRelativeA(path); +#else + return path && path[0] != '/'; +#endif +} + +static void inputOpenFile(inputData *pinputData, const char * const filename, bool fromCmdLine) { std::list& pathList = pinputData->pathList; std::list::iterator pathIt = pathList.end(); @@ -505,7 +519,7 @@ static void inputOpenFile(inputData *pinputData, const char * const filename) STEP("Using stdin"); fp = stdin; } - else if (pathList.empty() || strchr(filename, '/')){ + else if (fromCmdLine || pathList.empty() || !isPathRelative(filename)){ STEPS("Opening ", filename); fp = fopen(filename, "r"); } diff --git a/modules/database/src/ioc/dbtemplate/msi.md b/modules/database/src/ioc/dbtemplate/msi.md index 1b536cb67..bbe5273ef 100644 --- a/modules/database/src/ioc/dbtemplate/msi.md +++ b/modules/database/src/ioc/dbtemplate/msi.md @@ -60,6 +60,18 @@ Switches have the following meanings: 2. . (the current directory) 3. .. (the parent of the current directory) + Note that relative path searching is handled as + + $ cat foo.substitutions + file rel/path/bar.template { + # contents + } + $ msi -I . -I /some/path foo.substitutions + + which will try to find `bar.template` at the path `./rel/path/` followed by + `/some/path/rel/path`. + + - **-M _substitutions_** This parameter specifies macro values for the template instance. diff --git a/modules/database/src/ioc/misc/dlload.c b/modules/database/src/ioc/misc/dlload.c index 8b2a76371..8aea72cb5 100644 --- a/modules/database/src/ioc/misc/dlload.c +++ b/modules/database/src/ioc/misc/dlload.c @@ -10,11 +10,13 @@ #include "iocsh.h" #include "epicsExport.h" -IOCSH_STATIC_FUNC void dlload(const char* name) +IOCSH_STATIC_FUNC int dlload(const char* name) { if (!epicsLoadLibrary(name)) { printf("epicsLoadLibrary failed: %s\n", epicsLoadError()); + return -1; } + return 0; } static const iocshArg dlloadArg0 = { "path/library.so", iocshArgStringPath}; @@ -28,7 +30,7 @@ static const iocshFuncDef dlloadFuncDef = { }; static void dlloadCallFunc(const iocshArgBuf *args) { - dlload(args[0].sval); + iocshSetError(dlload(args[0].sval)); } static void dlloadRegistar(void) { diff --git a/modules/database/src/ioc/misc/iocInit.h b/modules/database/src/ioc/misc/iocInit.h index 6b4c944d4..1acd8ee8f 100644 --- a/modules/database/src/ioc/misc/iocInit.h +++ b/modules/database/src/ioc/misc/iocInit.h @@ -22,6 +22,9 @@ enum iocStateEnum { extern "C" { #endif +/** Query present IOC run state + * @since 3.15.8 + */ DBCORE_API enum iocStateEnum getIocState(void); DBCORE_API int iocInit(void); DBCORE_API int iocBuild(void); diff --git a/modules/database/src/ioc/rsrv/camsgtask.c b/modules/database/src/ioc/rsrv/camsgtask.c index 24df11d39..b69a39458 100644 --- a/modules/database/src/ioc/rsrv/camsgtask.c +++ b/modules/database/src/ioc/rsrv/camsgtask.c @@ -163,9 +163,11 @@ void camsgtask ( void *pParm ) int casClientInitiatingCurrentThread ( char * pBuf, size_t bufSize ) { - struct client * pClient = ( struct client * ) - epicsThreadPrivateGet ( rsrvCurrentClient ); + struct client * pClient; + if ( ! rsrvCurrentClient ) + return RSRV_ERROR; /* not yet initialized, or disabled via dbServer */ + pClient = ( struct client * ) epicsThreadPrivateGet ( rsrvCurrentClient ); if ( ! pClient ) return RSRV_ERROR; diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index f904d3268..a658c3796 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -1536,6 +1536,13 @@ struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr) void casStatsFetch ( unsigned *pChanCount, unsigned *pCircuitCount ) { + if(!clientQlock) { /* not yet initialized, or disabled via dbServer */ + if(pChanCount) + *pChanCount = 0; + if(pCircuitCount) + *pCircuitCount = 0; + return; + } LOCK_CLIENTQ; { int circuitCount = ellCount ( &clientQ ); diff --git a/modules/database/src/std/rec/aiRecord.dbd.pod b/modules/database/src/std/rec/aiRecord.dbd.pod index 4515368b2..83a7c5c26 100644 --- a/modules/database/src/std/rec/aiRecord.dbd.pod +++ b/modules/database/src/std/rec/aiRecord.dbd.pod @@ -33,7 +33,7 @@ These fields control where the record will read data from when it is processed: The DTYP field selects which device support layer should be responsible for providing input data to the record. The ai device support layers provided by EPICS Base are documented in the -L section. +L section. External support modules may provide additional device support for this record type. If not set explicitly, the DTYP value defaults to the first device support that diff --git a/modules/database/src/std/rec/compressRecord.c b/modules/database/src/std/rec/compressRecord.c index 22e804915..844172bf8 100644 --- a/modules/database/src/std/rec/compressRecord.c +++ b/modules/database/src/std/rec/compressRecord.c @@ -384,6 +384,7 @@ static long special(DBADDR *paddr, int after) if (special_type == SPC_RESET) { reset(prec); + monitor(prec); return 0; } diff --git a/modules/database/test/ioc/dbtemplate/msi.plt b/modules/database/test/ioc/dbtemplate/msi.plt index dc466be1f..09835d3ac 100644 --- a/modules/database/test/ioc/dbtemplate/msi.plt +++ b/modules/database/test/ioc/dbtemplate/msi.plt @@ -12,7 +12,7 @@ use strict; use Test; -BEGIN {plan tests => 12} +BEGIN {plan tests => 14} # Check include/substitute command model ok(msi('-I .. ../t1-template.txt'), slurp('../t1-result.txt')); @@ -56,6 +56,12 @@ my %envs = (TEST_NO => 12, PREFIX => 't'); ok(msi('-I. -I.. -S ../t12-substitute.txt'), slurp('../t12-result.txt')); delete @ENV{ keys %envs }; # Not really needed +# Substitution file, relative path includes +ok(msi('-I @TOP@/modules -S ../t13-substitute.txt'), slurp('../t13-result.txt')); + +# Template file, relative path includes +ok(msi('-I @TOP@/modules ../t14-template.txt'), slurp('../t14-result.txt')); + # Test support routines sub slurp { diff --git a/modules/database/test/ioc/dbtemplate/t13-result.txt b/modules/database/test/ioc/dbtemplate/t13-result.txt new file mode 100644 index 000000000..6cfcc57da --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t13-result.txt @@ -0,0 +1,2 @@ +# comment line +a=foo diff --git a/modules/database/test/ioc/dbtemplate/t13-substitute.txt b/modules/database/test/ioc/dbtemplate/t13-substitute.txt new file mode 100644 index 000000000..63d3fca1f --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t13-substitute.txt @@ -0,0 +1,3 @@ +file database/test/ioc/dbtemplate/t13-template.txt { + { a=foo } +} diff --git a/modules/database/test/ioc/dbtemplate/t13-template.txt b/modules/database/test/ioc/dbtemplate/t13-template.txt new file mode 100644 index 000000000..7958885a7 --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t13-template.txt @@ -0,0 +1,2 @@ +# comment line +a=$(a) diff --git a/modules/database/test/ioc/dbtemplate/t14-include.txt b/modules/database/test/ioc/dbtemplate/t14-include.txt new file mode 100644 index 000000000..7f69fca81 --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t14-include.txt @@ -0,0 +1 @@ +I'm a file! diff --git a/modules/database/test/ioc/dbtemplate/t14-result.txt b/modules/database/test/ioc/dbtemplate/t14-result.txt new file mode 100644 index 000000000..5d5dbda1b --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t14-result.txt @@ -0,0 +1,5 @@ +This is t14-template.txt + +I'm a file! + +End of t14-template.txt diff --git a/modules/database/test/ioc/dbtemplate/t14-template.txt b/modules/database/test/ioc/dbtemplate/t14-template.txt new file mode 100644 index 000000000..276663f7a --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t14-template.txt @@ -0,0 +1,5 @@ +This is t14-template.txt + +include "database/test/ioc/dbtemplate/t14-include.txt" + +End of t14-template.txt diff --git a/modules/libcom/RTEMS/posix/rtems_init.c b/modules/libcom/RTEMS/posix/rtems_init.c index 79859724a..0af4fa78f 100644 --- a/modules/libcom/RTEMS/posix/rtems_init.c +++ b/modules/libcom/RTEMS/posix/rtems_init.c @@ -510,6 +510,7 @@ static void rtshellCallFunc(const iocshArgBuf *args) if (!cmd) { fprintf(stderr, "ERR: No such command\n"); + iocshSetError(-1); } else { fflush(stdout); @@ -517,6 +518,7 @@ static void rtshellCallFunc(const iocshArgBuf *args) ret = (*cmd->command)(args[1].aval.ac,args[1].aval.av); fflush(stdout); fflush(stderr); + iocshSetError(ret); if(ret) fprintf(stderr, "ERR: %d\n",ret); } @@ -611,18 +613,27 @@ static void nfsMountCallFunc(const iocshArgBuf *args) } *cp = '/'; } - nfsMount(args[0].sval, args[1].sval, args[2].sval); + iocshSetError(nfsMount(args[0].sval, args[1].sval, args[2].sval)); } #endif -void zoneset(const char *zone) +int zoneset(const char *zone) { - if(zone) - setenv("TZ", zone, 1); - else - unsetenv("TZ"); + int ret; + if(zone) { + if ((ret = setenv("TZ", zone, 1)) < 0) + return ret; + } + #if defined( __NEWLIB_MINOR__ ) /* Added in newlib 2.2.0 */ + else if ((ret = unsetenv("TZ")) < 0) + return ret; + #else + else + unsetenv("TZ"); + #endif tzset(); + return 0; } static const iocshArg zonesetArg0 = {"zone string", iocshArgString}; @@ -634,7 +645,7 @@ static const iocshFuncDef zonesetFuncDef = {"zoneset",1,zonesetArgs }; static void zonesetCallFunc(const iocshArgBuf *args) { - zoneset(args[0].sval); + iocshSetError(zoneset(args[0].sval)); } #ifndef RTEMS_LEGACY_STACK @@ -667,6 +678,7 @@ static void setlogmaskCallFunc(const iocshArgBuf *args) return; } printf("Error: unknown log level.\n"); + iocshSetError(-1); } } static const iocshArg setlogmaskArg0 = {"level name", iocshArgString}; diff --git a/modules/libcom/RTEMS/score/rtems_init.c b/modules/libcom/RTEMS/score/rtems_init.c index f8cd62d5d..d291ea1f9 100644 --- a/modules/libcom/RTEMS/score/rtems_init.c +++ b/modules/libcom/RTEMS/score/rtems_init.c @@ -483,18 +483,27 @@ static void nfsMountCallFunc(const iocshArgBuf *args) } *cp = '/'; } - nfsMount(args[0].sval, args[1].sval, args[2].sval); + iocshSetError(nfsMount(args[0].sval, args[1].sval, args[2].sval)); } #endif -void zoneset(const char *zone) +int zoneset(const char *zone) { - if(zone) - setenv("TZ", zone, 1); - else - unsetenv("TZ"); + int ret; + if(zone) { + if ((ret = setenv("TZ", zone, 1)) < 0) + return ret; + } + #if defined( __NEWLIB_MINOR__ ) /* Added in newlib 2.2.0 */ + else if ((ret = unsetenv("TZ")) < 0) + return ret; + #else + else + unsetenv("TZ"); + #endif tzset(); + return 0; } static const iocshArg zonesetArg0 = {"zone string", iocshArgString}; @@ -502,7 +511,7 @@ static const iocshArg * const zonesetArgs[1] = {&zonesetArg0}; static const iocshFuncDef zonesetFuncDef = {"zoneset",1,zonesetArgs}; static void zonesetCallFunc(const iocshArgBuf *args) { - zoneset(args[0].sval); + iocshSetError(zoneset(args[0].sval)); } diff --git a/modules/libcom/src/cxxTemplates/tsSLList.h b/modules/libcom/src/cxxTemplates/tsSLList.h index 6d375af55..895ec7dde 100644 --- a/modules/libcom/src/cxxTemplates/tsSLList.h +++ b/modules/libcom/src/cxxTemplates/tsSLList.h @@ -311,13 +311,13 @@ inline bool tsSLIterConst::valid () const template < class T > inline bool tsSLIterConst::operator == ( const tsSLIterConst &rhs ) const { - return this->pEntry == rhs.pConstEntry; + return this->pEntry == rhs.pEntry; } template < class T > inline bool tsSLIterConst::operator != (const tsSLIterConst &rhs) const { - return this->pEntry != rhs.pConstEntry; + return this->pEntry != rhs.pEntry; } template < class T > diff --git a/modules/libcom/src/env/envDefs.h b/modules/libcom/src/env/envDefs.h index 159154b99..d59840285 100644 --- a/modules/libcom/src/env/envDefs.h +++ b/modules/libcom/src/env/envDefs.h @@ -77,6 +77,7 @@ LIBCOM_API extern const ENV_PARAM IOCSH_PS1; LIBCOM_API extern const ENV_PARAM IOCSH_HISTSIZE; LIBCOM_API extern const ENV_PARAM IOCSH_HISTEDIT_DISABLE; LIBCOM_API extern const ENV_PARAM EPICS_MUTEX_USE_PRIORITY_INHERITANCE; +LIBCOM_API extern const ENV_PARAM EPICS_ABORT_ON_ASSERT; LIBCOM_API extern const ENV_PARAM *env_param_list[]; struct in_addr; diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 1560a228a..2d3b7da20 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -1329,7 +1329,7 @@ iocshCmd (const char *cmd) int epicsStdCall iocshLoad(const char *pathname, const char *macros) { - if (pathname) + if (pathname && !getenv("IOCSH_STARTUP_SCRIPT")) epicsEnvSet("IOCSH_STARTUP_SCRIPT", pathname); return iocshBody(pathname, NULL, macros); } diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index 5751ad070..9fbf6b850 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -139,10 +139,12 @@ static void epicsEnvSetCallFunc(const iocshArgBuf *args) if (name == NULL) { fprintf(stderr, "Missing environment variable name argument.\n"); + iocshSetError(-1); return; } if (value == NULL) { fprintf(stderr, "Missing environment variable value argument.\n"); + iocshSetError(-1); return; } epicsEnvSet (name, value); @@ -159,6 +161,7 @@ static void epicsEnvUnsetCallFunc(const iocshArgBuf *args) if (name == NULL) { fprintf(stderr, "Missing environment variable name argument.\n"); + iocshSetError(-1); return; } epicsEnvUnset (name); @@ -215,7 +218,7 @@ static const iocshFuncDef iocLogInitFuncDef = {"iocLogInit",0,0, " see 'setIocLogDisable' command\n"}; static void iocLogInitCallFunc(const iocshArgBuf *args) { - iocLogInit (); + iocshSetError(iocLogInit ()); } /* iocLogDisable */ @@ -354,6 +357,7 @@ static void threadCallFunc(const iocshArgBuf *args) tid = epicsThreadGetId (cp); if (!tid) { fprintf(stderr, "\t'%s' is not a known thread name\n", cp); + iocshSetError(-1); continue; } } @@ -429,6 +433,7 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args) tid = epicsThreadGetId(cp); if (!tid) { fprintf(stderr, "'%s' is not a valid thread name\n", cp); + iocshSetError(-1); continue; } } @@ -437,12 +442,14 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args) epicsThreadGetName(tid, nameBuf, sizeof nameBuf); if (nameBuf[0] == '\0') { fprintf(stderr, "'%s' is not a valid thread id\n", cp); + iocshSetError(-1); continue; } } if (!epicsThreadIsSuspended(tid)) { fprintf(stderr, "Thread %s is not suspended\n", cp); + iocshSetError(-1); continue; } epicsThreadResume(tid); @@ -458,7 +465,7 @@ static const iocshFuncDef generalTimeReportFuncDef = {"generalTimeReport",1,gene " 1 - Additionally show current time obtained from each provider.\n"}; static void generalTimeReportCallFunc(const iocshArgBuf *args) { - generalTimeReport(args[0].ival); + iocshSetError(generalTimeReport(args[0].ival)); } /* installLastResortEventProvider */ @@ -467,7 +474,7 @@ static const iocshFuncDef installLastResortEventProviderFuncDef = {"installLastR "which returns the current time for every event number\n"}; static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) { - installLastResortEventProvider(); + iocshSetError(installLastResortEventProvider()); } static iocshVarDef comDefs[] = { diff --git a/modules/libcom/src/misc/cantProceed.c b/modules/libcom/src/misc/cantProceed.c index 80e26f8f6..f66d61bc2 100644 --- a/modules/libcom/src/misc/cantProceed.c +++ b/modules/libcom/src/misc/cantProceed.c @@ -24,7 +24,7 @@ LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg) void * mem = NULL; if (count > 0 && size > 0) { while ((mem = calloc(count, size)) == NULL) { - errlogPrintf("%s: callocMustSucceed(%lu, %lu) - calloc failed\n", + errlogPrintf("%s: callocMustSucceed(%lu, %lu) - " ERL_ERROR " calloc failed\n", msg, (unsigned long)count, (unsigned long)size); errlogPrintf("Thread %s (%p) suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); @@ -40,7 +40,7 @@ LIBCOM_API void * mallocMustSucceed(size_t size, const char *msg) void * mem = NULL; if (size > 0) { while ((mem = malloc(size)) == NULL) { - errlogPrintf("%s: mallocMustSucceed(%lu) - malloc failed\n", + errlogPrintf("%s: mallocMustSucceed(%lu) - " ERL_ERROR " malloc failed\n", msg, (unsigned long)size); errlogPrintf("Thread %s (%p) suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); @@ -59,7 +59,7 @@ LIBCOM_API void cantProceed(const char *msg, ...) errlogVprintf(msg, pvar); va_end(pvar); - errlogPrintf("Thread %s (%p) can't proceed, suspending.\n", + errlogPrintf(ANSI_RED("CRITICAL ERROR") " Thread %s (%p) can't proceed, suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); epicsStackTrace(); diff --git a/modules/libcom/src/misc/cantProceed.h b/modules/libcom/src/misc/cantProceed.h index 0232a8611..f9559b14c 100644 --- a/modules/libcom/src/misc/cantProceed.h +++ b/modules/libcom/src/misc/cantProceed.h @@ -56,18 +56,24 @@ LIBCOM_API void cantProceed( * gracefully when memory runs out. */ /** @{ */ -/** \brief A calloc() that never returns NULL. +/** \brief A calloc() which suspends on error. * \param count Number of objects. * \param size Size of each object. - * \param errorMessage What this memory is needed for. - * \return Pointer to zeroed allocated memory. + * \param errorMessage Context added to logged error message + * \return Pointer to zeroed allocated memory. Should later be free() d + * + * Will always return NULL for a zero length allocation. + * Will never return NULL otherwise. */ LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *errorMessage); -/** \brief A malloc() that never returns NULL. +/** \brief A malloc() which suspends on error. * \param size Size of block to allocate. - * \param errorMessage What this memory is needed for. - * \return Pointer to allocated memory. + * \param errorMessage Context added to logged error message + * \return Pointer to allocated memory. Should later be free() d + * + * Will always return NULL for a zero length allocation. + * Will never return NULL otherwise. */ LIBCOM_API void * mallocMustSucceed(size_t size, const char *errorMessage); /** @} */ diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c b/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c index e91db8a90..9c726ad59 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c @@ -48,7 +48,6 @@ epicsEventCreate(epicsEventInitialState initialState) { rtems_status_code sc; rtems_id sid; - rtems_interrupt_level level; static uint32_t name; sc = rtems_semaphore_create (next_rtems_name ('B', &name), diff --git a/modules/libcom/src/osi/os/default/osdAssert.c b/modules/libcom/src/osi/os/default/osdAssert.c index 2d62bc820..23263df4e 100644 --- a/modules/libcom/src/osi/os/default/osdAssert.c +++ b/modules/libcom/src/osi/os/default/osdAssert.c @@ -20,12 +20,14 @@ #include "epicsTime.h" #include "cantProceed.h" #include "epicsStackTrace.h" +#include "envDefs.h" void epicsAssert (const char *pFile, const unsigned line, const char *pExp, const char *pAuthorName) { epicsTimeStamp current; + int shouldAbort = 0; errlogPrintf("\n\n\n" "A call to 'assert(%s)'\n" @@ -50,6 +52,13 @@ void epicsAssert (const char *pFile, const unsigned line, errlogPrintf("Please E-mail this message to %s or to tech-talk@aps.anl.gov\n", pAuthorName); - errlogPrintf("Calling epicsThreadSuspendSelf()\n"); - epicsThreadSuspendSelf (); + if (envGetBoolConfigParam(&EPICS_ABORT_ON_ASSERT, &shouldAbort) == 0 && shouldAbort) { + errlogPrintf("Calling abort()\n"); + errlogFlush(); + abort(); + } + else { + errlogPrintf("Calling epicsThreadSuspendSelf()\n"); + epicsThreadSuspendSelf (); + } } diff --git a/modules/pvAccess b/modules/pvAccess index f1268adb8..dafb6aad3 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit f1268adb8ecbacbd74bb66c172d02d9d427bedfd +Subproject commit dafb6aad31a99f8d825a1f77aa919c82bb28e0cf diff --git a/modules/pvData b/modules/pvData index 7c10c29c3..2be3bc40e 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 7c10c29c331b8d115e58067629f73edfb30effc6 +Subproject commit 2be3bc40e06429448af0aefc9719c813d3b68096 diff --git a/modules/pvDatabase b/modules/pvDatabase index f207e512d..073d2acaf 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit f207e512d67addab79e33a00b712e3444228ba7c +Subproject commit 073d2acafc7109178d319109ad435131a80fed0e diff --git a/modules/pva2pva b/modules/pva2pva index 949b3f63c..8fa231352 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 949b3f63c2387bb92c1c22ca2f80f8d320805117 +Subproject commit 8fa231352dac32c08734eb04cf4b12e76895a261 diff --git a/modules/pvaClient b/modules/pvaClient index 8ed07fef9..09cf31752 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit 8ed07fef96e41d35d47ab61276e29eb1a81e7fec +Subproject commit 09cf317521bfa172e3e00a5631bf0c70b88157ba