Compare commits

...

434 Commits

Author SHA1 Message Date
Andrew Johnson
57c930fbee Release R7.0.8.1
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-06-27 20:55:03 -05:00
Andrew Johnson
785b777baf Update Release Notes, set version numbers 2024-06-26 14:59:18 -05:00
Andrew Johnson
d0d15ee911 Replace UNRELEASED with 7.0.8.1 2024-06-26 14:59:18 -05:00
Andrew Johnson
5af9c7e50d Revert submodules to versions at R7.0.8 2024-06-26 14:59:18 -05:00
Andrew Johnson
5fe563bed8 Limit _FORTIFY_SOURCE <= 2 2024-06-26 14:58:53 -05:00
DW
11fba63d18 Fix histogram doc 2024-05-29 09:17:03 -05:00
Simon Rose
1db37bcd91 Update release notes 2024-05-29 09:15:35 -05:00
Simon Rose
beec00b403 Fix issue with compress record
The handling of N-to-M array compression was broken with the addition
of the partial buffer option, which broke the bounds check that was
being used.

Note that this also makes the partial buffer option more consistent;
if, for example, you have
```
record(compress, foo) {
  field(ALG, "N to 1 Average")
  field(INP, "bar NPP")
  field(NSAM, 2)
  field(N, 2)
  field(PBUF, YES)
}
```
(with `bar` having, e.g. length 3), then this will now behave as
expected on both of the samples.
2024-05-29 09:15:35 -05:00
DW
4966baf423 fix sizv for printf & fix doc 2024-05-20 09:18:26 -04:00
Michael Davidsaver
e5b4829074 bound lso/lsi to limit of dbAddr::field_size 2024-05-19 11:57:19 -04:00
Ralph Lange
d8b5616772 ci: bump checkout to v4 in check-editorconfig.yml
- fix node16.js usage warning
2024-05-16 10:07:12 +02:00
Ralph Lange
92615a77fe ci: fix last commit (GHA workaround) 2024-05-15 18:04:58 +02:00
Ralph Lange
b3f92d81db ci: add workaround for GHA node20@centos7 failures 2024-05-15 16:57:34 +02:00
Simon Rose
839f764bcb Clean up some potential memory leaks
The watchdog tasks are allocated, but not consistently removed. In
general this doesn't matter: they run in threads that will only
end when the process actually quits. For consistency and for the
purpose of future-proofing, I think there is value in having the
cleanup added in each case.
2024-05-15 09:26:09 -05:00
Simon Rose
4bb50fe664 Memory leak in caservertask.c 2024-05-15 09:26:09 -05:00
Ralph Lange
c77f32b19c Merge pull request #482 from ericonr/calcout-docs
Fix calcout doc typo.
2024-05-03 04:04:41 +09:00
Érico Nogueira
66ce1c2076 Fix calcout doc typo. 2024-05-02 15:29:22 -03:00
Érico Nogueira
1a9dc993c1 Fix gmtime messages in epicsTimeZoneTest. 2024-04-29 15:10:47 -07:00
Michael Davidsaver
cb1571783b link.h wrong type
Change to unsigned incorrectly increased size.

e88a186fc3
2024-04-02 08:35:25 -07:00
Freddie Akeroyd
5dfc6caf3c Accept should return SOCKET rather than int 2024-03-06 09:48:26 -06:00
Ralph Lange
cb49bd0133 Update ci-scripts to 3.4.1
Builds on AppVeyor (VS2019) started to fail
because of the Python version/distutils
2024-03-01 18:00:40 +01:00
Freddie Akeroyd
4720b61c1f Move call to setThreadName()
The call to setThreadName() is moved to avoid a race condition that
can happen with very short lived processes. If the process terminates
very quickly e.g. is a google test runner or the msi.exe command
called from a Makefile during a build, then very occasionally a
crash can occur during process termination if setThreadName() when called
from the newly created thread. This looks to be becauae the DLL it is
trying to call gets unloaded between it getting a handle to the DLL
and making the call. Moving the setThreadName() call to the creating
thread avoids this problem. The issue was only ever seen with statically
linked epics executables, I am unsure if the way a DLL based epics
program unloads might avoid this, or just make it less likely but
still possible. As mentioned above, the issue will only ever occur
to threads that are created during process termination and so would
not affect running IOCs
2024-02-21 09:59:36 -06:00
4383cf291e allow macros with defaults in dbLoadRecords without substitutions 2024-02-21 09:50:03 -06:00
Simon Rose
a6977ae731 Fix issue where VSCode makefile extension can delete files
The problem is that VSCode's make extension, in order to determine
some information about the project, runs
```
make --dry-run --always-make
```
which despite its name will actually try to remake the configure/*
files. Running `installEpics.pl` on these will delete them first,
then try copy them, resulting in an error.
2024-02-21 09:45:14 -06:00
Michael Davidsaver
07cbf00187 posix: warn on epicsSocketCreate() without osiSockAttach() 2023-12-22 10:26:28 -08:00
Michael Davidsaver
c75b9ad0be add dbRecordNode::order
Keep track of parse order of record instances.
2023-12-22 10:26:28 -08:00
Michael Davidsaver
87acb98d1e ca: remove hostname length limit when parsing address lists 2023-12-22 10:26:28 -08:00
Michael Davidsaver
403e203325 quieting clang-tidy, use unsigned
places where we shouldn't be negative anyway
2023-12-22 10:26:28 -08:00
Michael Davidsaver
a7a56912eb default/epicsMessageQueue: initialize threadNode 2023-12-22 10:26:28 -08:00
Michael Davidsaver
fe4a32e425 default/epicsMessageQueue: avoid volatile flag
Only one place where eventSent was accessed
without locking.  Move this load earlier.
2023-12-22 10:26:28 -08:00
Michael Davidsaver
823386573f ipAddrToAsciiGlobal::run() keep scratch buffer as local 2023-12-22 10:26:28 -08:00
Michael Davidsaver
ea8247586f adjustToWorstCaseAlignment() simplify
Add some STATIC_ASSERT to check assumptions.

Only in-tree use is freeListLib to ensure chunks in
a malloc()'d block are aligned.
2023-12-22 10:26:28 -08:00
Michael Davidsaver
e88a186fc3 make link::flags bit field unsigned 2023-12-22 10:26:28 -08:00
Michael Davidsaver
20f32068c3 gha add workflow_dispatch 2023-12-22 10:26:28 -08:00
Andrew Johnson
8998341588 Update version numbers and submodules after release 2023-12-15 13:03:57 -06:00
Andrew Johnson
448fde0671 Set release version numbers
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 / 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
2023-12-14 16:42:10 -06:00
Andrew Johnson
477e36b1f0 Update submodules to tagged versions 2023-12-14 16:42:10 -06:00
Andrew Johnson
fad830bd14 Remove example sub-module 2023-12-14 16:42:10 -06:00
Andrew Johnson
331df3d7e4 UNRELEASED => 7.0.8 2023-12-14 16:42:10 -06:00
Andrew Johnson
4a53713f37 Update Release Procedures/Checklist 2023-12-14 16:31:42 -06:00
Andrew Johnson
2e6fd505d2 Use epicsSnprintf() for old MSVC compilers 2023-12-14 11:31:36 -06:00
Andrew Johnson
5ecf7d18a8 Clean up Clang 15 sprintf() warnings in libcom and ca 2023-12-13 13:34:25 -06:00
Andrew Johnson
56dbc949ff Add declarations to flex, cleans up Clang 15 warnings. 2023-12-12 13:44:08 -06:00
Simon Rose
6a369acd0b Add newline to help text 2023-12-05 08:05:12 -08:00
Simon Rose
d9d35a4eab Allow auto-declarations for dbdExpand.pl 2023-12-01 09:19:03 -06:00
Ralph Lange
116881ad87 Use split() for fetching last tag with darcs
(setting $/='' breaks reading multi-line into an array)
2023-11-29 09:53:24 -06:00
96857d92bc fix problem with commands returning multiple trailing newlines 2023-11-29 09:53:24 -06:00
Érico Nogueira
0cf8c934f9 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-11-29 09:44:03 -06:00
Michael Davidsaver
69d05fe5b0 Add ERROR to error messages 2023-11-26 15:25:09 -08:00
Michael Davidsaver
511bf1ffca const-ify dbLink arrays
external code really should never be modifying pamaplinkType[]
2023-11-25 14:52:16 -08:00
Uchenna Ezeobi
7a7028de56 Config: Fixed Hard coded LDFLAGS in MVME2500 2023-11-17 15:20:32 -06:00
Michael Davidsaver
7a65c001ce update submodules 2023-11-15 07:31:53 -08:00
Michael Davidsaver
0bc6ff3d4c release notes 2023-11-07 16:00:46 -08:00
Michael Davidsaver
f2fe9d1203 bi "Raw Soft Channel" use MASK
If set, apply MASK to value read into RVAL.
2023-11-07 15:53:41 -08:00
Michael Davidsaver
ffc2d0f23a incorrect error check on GetStdHandle()
Likely inconsequential as GetConsoleMode() should
return 0 when given an invalid handle.
2023-11-07 15:53:41 -08:00
Michael Davidsaver
a352865df9 print ANSI escapes to stderr
unconditionally print ANSI some escapes (to colorize errors)
to the stderr stream.
2023-11-07 15:53:22 -08:00
Michael Davidsaver
63740f2edd colorize more errlog messages 2023-11-07 15:53:22 -08:00
Jeremy Lorelli
f4be9daf4d 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-11-07 15:17:04 -08:00
Michael Davidsaver
3fa1932345 update ci-scripts 2023-11-07 15:14:09 -08:00
Michael Davidsaver
95bd5453d9 dbRecordField() add "did you mean..." hint for unknown field 2023-11-01 09:52:32 -05:00
Michael Davidsaver
eb3f8a004c const-ify dbCopyEntry() and dbCopyEntryContents() 2023-11-01 09:52:32 -05:00
Michael Davidsaver
9f868a1074 avoid hang during concurrent db_cancel_event()
cf. fab8fd7102
2023-11-01 09:24:44 -05:00
Michael Davidsaver
b41787b6bf doc 2023-10-22 17:42:36 -07:00
19b232545c gha: turn most warnings into errors in github build 2023-10-22 17:42:36 -07:00
Michael Davidsaver
2ca70d3aa2 iocsh: keep history file 2023-10-22 17:42:36 -07:00
JJL772
395015aac4 Com: Make STATIC_ASSERT macro typedefs unique 2023-10-22 17:42:36 -07:00
Michael Davidsaver
92cae86ff2 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-10-22 17:42:36 -07:00
Jack Harper
49ea46ee5e iocsh: add comment to cvtArg explaining default iocsharg behaviour 2023-10-22 17:42:36 -07:00
Michael Davidsaver
df908f299b remove unused local 2023-10-22 17:42:36 -07:00
AlexWells
6dec68554c 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-10-22 17:42:36 -07:00
Michael Davidsaver
badd8f518d update modules/pvData 2023-10-22 17:42:35 -07:00
Michael Davidsaver
766c9906b5 update ci-scripts 2023-10-22 14:46:28 -07:00
Jeremy Lorelli
60fa2d31da libCom: Fix buggy pointer dereference in postfix() 2023-09-26 09:52:13 -07:00
Michael Davidsaver
88ea1507f4 Fix compile w/ vs2012 2023-09-22 08:20:27 -07:00
Emilio Perez
8c08c57247 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-09-22 08:20:19 -07:00
Michael Davidsaver
45b3bce515 epicsThreadShow() zombies
Flag when the thread has returned, but the tracking
struct is still around.  eg. in need of joining.
2023-09-22 08:19:25 -07:00
Érico Nogueira
7c4a21eab4 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-09-21 08:18:49 -07:00
Michael Davidsaver
fab8fd7102 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-09-21 08:18:49 -07:00
Michael Davidsaver
3d25756065 privatize evSubscrip 2023-09-21 08:18:49 -07:00
Michael Davidsaver
5aca4c684c dbEvent minor 2023-09-14 08:54:40 +02:00
Michael Davidsaver
39b5c01c5d minor 2023-09-14 08:54:40 +02:00
Michael Davidsaver
3b22e5f710 doc dbLock.h 2023-09-14 08:54:40 +02:00
Michael Davidsaver
9f660f2238 add initHookAtPrepare 2023-09-05 08:54:48 +02: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
Ralph Lange
00dc55b8a2 Fix usage info in .tools/make-tar.sh 2023-08-08 10:29:09 +02:00
Rolf Keitel
524f81b8bd Doc updates to PINI, PHAS & EVNT 2023-07-25 11:36:44 -05:00
Michael Davidsaver
80e62031e9 doc 2023-07-23 08:43:32 -07:00
Minijackson
d87fd0db01 Fix MAKEFLAGS parsing with Make 4.4+
Since Make version 4.4, MAKEFLAGS also contains long options and
overridden variables on the command-line[1].

[1]: https://git.savannah.gnu.org/cgit/make.git/tree/NEWS?h=4.4#n67

This means that parsing by filtering out '--%' doesn't work reliably
anymore, since it doesn't remove overrides:

Running 'make VAR=quacks' gives 'MAKEFLAGS=" -- VAR=quacks"', and
'checkflags' would understand that flags -q, -s, ... were set.

This would get transmitted below into 'QUIET_FLAGS' and
'QUESTION_FLAG', then passed to the 'genVersionHeader.pl' as '-i' and
'-q'.

The result would be that 'genVersionHeader.pl' would never create the
version header (only check for its up-to-date status), leading to
confusing errors:

  ../misc/epicsRelease.c:25:32: error: expected ')' before 'EPICS_VCS_VERSION'
     25 |     printf ( "## %s\n", "Rev. " EPICS_VCS_VERSION );
        |            ~                   ^~~~~~~~~~~~~~~~~~

The NEWS file[1] recommends using 'firstword', but unfortunately this is
not compatible with GNUMake < 3.82.
2023-07-22 08:36:43 -07:00
Ralph Lange
6636b4b9e7 libCom: check calloc() failure in RTEMS-posix/osdMessageQueue.c 2023-07-22 08:35:59 -07:00
Ralph Lange
b51d1de283 libCom: fix possible memory leak in RTEMS-posix/osdMessageQueue.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
38c99df2e0 libCom: fix possible memory leaks in iocLogServer.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
688195a273 libCom: handle realloc() failures correctly in macEnv.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
d691acc001 ca: init local variable in catime.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Ralph Lange
059d32a975 db: init struct members in dbChannel.c
found by static code analysis (cppcheck @ sonarqube)
2023-07-22 08:35:59 -07:00
Henrique Silva
5c99031157 Add missing AFTC documentation to records
Fixes #313
2023-07-22 08:33:19 -07:00
Henrique Silva
a01c671399 Add missing HYST field documentation to longin record 2023-07-22 08:33:19 -07:00
Minijackson
b2c80efd33 release notes: link release notes from submodules'
fixes #226
2023-07-22 08:33:08 -07:00
Karl Vestin
39b6fa26da Added unit test for binary output record type 2023-07-22 08:32:16 -07:00
Karl Vestin
3ee6097ab7 Fixes #361 2023-07-22 08:30:44 -07:00
Emilio Perez
500a57738b Validate target record name when creating an alias
This fixes issue #312 by printing an error when a field is specified
2023-07-22 08:29:09 -07:00
AlexWells
f488765631 Add tests for PR#310
Also add missing NULL/empty checks
2023-07-22 08:28:25 -07:00
Sebastian Marsching
3a2d225682 Detect error in fprintf and return (fixes #309).
fprintf returns a negative value in order to signal an error. We have to
detect this situation in epicsStrPrintEscaped and return a negative
when fprintf returns a negative value in order to give the calling code
a chance to detect this situation.

The old implementation (of simply accumulating the return values of
fprintf) was wrong anyway, because it would not only lead to an error in
fprintf to be lost but would also cause the returned number to be too
small (not representing the actual number of bytes written) in such a
case.

The only case where the old implementation would work correctly was when
all calls to fprintf succeeded or all these calls failed.
2023-07-22 08:27:32 -07:00
Doug Murray
1d056c6fe4 Add support for CA tools timeout from environment variable EPICS_CLI_TIMEOUT 2023-07-22 08:24:22 -07:00
Michael Davidsaver
42604fc794 Allow clang with GCC compilerSpecific.h
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 / Ub-20 gcc-9 + RT-4.10 (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 / 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.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 / 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
Makes it easier to run clang derivative analysis tools
on builds configured for GCC.
2023-06-13 08:47:13 -07:00
Michael Davidsaver
4ecc0daa79 make mapDBFToDBR[] const 2023-06-13 08:47:13 -07:00
Michael Davidsaver
5a1f3ecc8b doc: note when some record types were introduced 2023-05-18 11:57:41 -07:00
Michael Davidsaver
cb97d662a7 doc 2023-05-01 10:31:01 -07:00
Michael Davidsaver
d4fab0d20e iocsh: dbCompleteRecord() missing NULL check 2023-05-01 10:31:01 -07:00
Michael Davidsaver
0c13e6ba6c iocsh: tab completion handle iocshArgArgv 2023-05-01 10:31:01 -07:00
Michael Davidsaver
8f1243da40 epicsSingleton: eliminate global ctor with >= c++11 2023-05-01 10:25:29 -07:00
Michael Davidsaver
fe9995c0b5 Update recommendation for CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 2023-05-01 09:06:59 -07:00
Freddie Akeroyd
f56412d6a5 WIN32: use FlsAlloc() to cleanup epicsThreadOSD
Adjust macros for compiling for older MSVC/Win SDK versions

Try to cover missing fibres include in 7.0 SDK

Support Windows XP and above.
Also removed explicit define of _WIN32_WINNT in code if it has not
been passed on compile line. This is possibly a matter for
further discussion
2023-05-01 09:03:52 -07:00
Érico Nogueira
07d18c55ba Clean whitespace in makeBaseApp template README 2023-05-01 09:03:52 -07:00
Minijackson
9f97f25669 ci: add cross-compilation tests for aarch64, arm soft and hard float 2023-05-01 09:03:52 -07:00
912a82c0b5 replace deprecated decrementing volatile with atomic decrement 2023-05-01 09:03:52 -07:00
acf2241fd0 Some archs define ECHO in termios.h 2023-05-01 09:03:52 -07:00
Eva Lott
b878295d06 Added the new annotation EPICS_PRINTF_FMT 2023-05-01 09:03:45 -07:00
f41f11c7f6 fix compiler warning on 32 bit systems 2023-04-28 09:35:49 -05:00
Michael Davidsaver
216359974c update release notes 2023-04-18 13:11:59 -05:00
Torsten Bögershausen
17ad04505e Change compiler for FreeBSD 13: Use clang
FreeBSD 13 uses clang, not gcc, any more.
GNU_DIR must be set to /usr/local

Note: This change touches both the x86 and the x86_64 files.
It was tested on 'amd64' system only, which is x86_64
2023-04-18 09:51:33 -05:00
Michael Davidsaver
3500a02034 iocsh: expose dbCreateAlias 2023-04-18 09:51:28 -05:00
Michael Davidsaver
52b18d56a0 dbCreateAlias fixup error handling 2023-04-18 09:51:28 -05:00
Michael Davidsaver
5507646ce7 posix: optimize epicsThreadOnce()
Use atomic ops to short circuit when already initialized
2023-04-18 09:51:24 -05:00
Michael Davidsaver
625c2ef159 epicsThreadPerform: time epicsThreadOnce() 2023-04-18 09:51:24 -05:00
Jure Varlec
bdaca51d96 Update shareLib API docs, directing the reader to makeAPIheader.pl 2023-04-18 09:51:21 -05:00
Jure Varlec
9655b78e11 Update release notes: ts filter 2023-04-18 09:51:07 -05:00
Jure Varlec
e11f88017d ts filter: port to the new db_field_log 2023-04-18 09:51:07 -05:00
Jure Varlec
8a3020033e ts filter: replace cantProceed with a non-fatal error msg 2023-04-18 09:51:07 -05:00
Jure Varlec
bd1af9ac95 ts filter: fix unused variable warnings 2023-04-18 09:51:07 -05:00
Jure Varlec
d5959ca20a ts filter: handle calloc failures 2023-04-18 09:51:07 -05:00
Jure Varlec
e10dcede7d ts filter: clear the dtor field after destruction 2023-04-18 09:51:07 -05:00
Jure Varlec
c042b08ab0 Extend timestamp filter, giving access to the record timestamp 2023-04-18 09:51:07 -05:00
Michael Davidsaver
5eff3803a8 update release notes 2023-03-10 12:02:29 +00:00
Michael Davidsaver
151256533f renamed hidden pdbbase in dbd parser
avoid confusion with non-static pdbbase global
2023-03-10 11:00:58 +00:00
Michael Davidsaver
3b484f58d3 for links, treat "" the same as unset. 2023-03-10 11:00:58 +00:00
Michael Davidsaver
d3f93746a8 1<<31 upsets ubsan 2023-03-10 10:57:35 +00:00
Michael Davidsaver
f99a1cb0f3 dbdToRecordtypeH use offsetof()
quiets UB sanitizer
2023-03-10 10:57:35 +00:00
Michael Davidsaver
531a769007 fix rtems_ne2kpci_driver_attach prototype 2023-03-10 10:57:35 +00:00
Henrique Silva
3e51491628 Fix generalTimeReport interest_level argument type
Setting to iocshArgInt actually makes the function verbosity to be able
to be controlled by the value
2023-03-10 10:56:58 +00:00
0b01fb20db make buffer large enough for any argument value 2023-03-10 10:56:58 +00:00
Minijackson
c7a769e5da editorconfig: add workflow to check if config is upheld 2023-03-10 10:56:58 +00:00
Minijackson
a9fd57a865 editorconfig: add initial version forcing final newlines
See #337
2023-03-10 10:56:58 +00:00
e862f0e95f fix warning "if clause does not guard..." 2023-03-10 10:56:58 +00:00
172597e0e6 avoid accessing dbr_text[type] when type is out of range 2023-03-10 10:56:58 +00:00
bcdeeed206 fix missing newline at end of file 2023-03-10 10:56:58 +00:00
Michael Davidsaver
b6626e4f60 dbEvent: try to detect possible "stall"
event_read() should not return if the last callback
was delivered with eventsRemaining!=0
2023-03-10 10:56:58 +00:00
Michael Davidsaver
e1c1bb8b1b dbEvent: correct eventsRemaining
Only pass eventsRemaining when no queued events have been canceled.
Also possible race bt accessing ev_que with locking.
2023-03-10 10:56:58 +00:00
Torsten Bögershausen
90ae51e8f2 MacOs: Use readline from MacPorts
Commit b38ff09f6e and
commit d9ca8a70f0 introduced the TAB
completion in iocsh.

Commit 1f75813a4d enabled it for MacOs
having readline installed via HomeBrew.

This commit enables it for MacPorts.
2023-03-10 10:56:58 +00:00
Brendan Chandler
832abbd3b1 Return an error if subrecord processing fails due to bad INP links
If a sub record has an invalid INPx link, it was silently failing (and
not running the proc function).  This change plumbs in the error, so
the put fails and the user knows something went wrong.
2023-03-10 10:56:58 +00:00
Michael Davidsaver
52cc68433f COMMANDLINE_LIBRARY fallback to $(wildcard $(GNU_DIR) 2023-03-10 09:52:30 +00:00
Michael Davidsaver
f430389ee7 iocShutdown(): Always stop worker threads 2023-03-10 09:52:08 +00:00
Michael Davidsaver
bded79f14d dbScan join threads 2023-03-10 09:52:08 +00:00
Michael Davidsaver
2ff44cb386 callback join threads 2023-03-10 09:52:08 +00:00
Michael Davidsaver
a9ade9669a switch dbScan to epicsThreadCreateOpt() 2023-03-10 09:52:08 +00:00
Michael Davidsaver
f902d70006 switch callback to epicsThreadCreateOpt() 2023-03-10 09:52:08 +00:00
Michael Davidsaver
e22d74310b RTEMS: ensure epicsThreadMustJoin() short-circuits 2023-03-10 09:52:08 +00:00
Simon Rose
e5ad12e638 Updated RELEASE_NOTES 2023-03-10 09:51:08 +00:00
Simon Rose
b963a4564e Added commend about PBUF having no effect on 'Average' algorithm 2023-03-10 09:51:08 +00:00
Simon Rose
579c125b01 Updated documentation 2023-03-10 09:51:08 +00:00
Simon Rose
84d9617375 Added one more put/process to go over the buffer length
Note that it is not really a circular buffer in this case, but
a full reset of the buffer to the beginning. This matches the
documentation, but it seems valuable to add an explicit test for
this case.
2023-03-10 09:51:08 +00:00
Simon Rose
d66e90a016 Fixing 'error C2057: expected constant expression' error 2023-03-10 09:51:08 +00:00
Simon Rose
373e5440ac General cleanup 2023-03-10 09:51:08 +00:00
Simon Rose
dec23501e1 Added test for array_average 2023-03-10 09:51:08 +00:00
Simon Rose
11a4bed9aa compress_scalar for average works correctly now 2023-03-10 09:51:08 +00:00
Simon Rose
bf4a4c6b78 Added failing test for partial ai average 2023-03-10 09:51:08 +00:00
Simon Rose
b54d4b9a24 Added test for low value 2023-03-10 09:51:08 +00:00
Simon Rose
84f4771691 Single input data test passes 2023-03-10 09:51:08 +00:00
Simon Rose
1dc34a02e2 Add test path for single input data 2023-03-10 09:51:08 +00:00
Simon Rose
3ab22818da Added failing test for partially filled buffer average 2023-03-10 09:51:08 +00:00
Simon Rose
1ab474638d Initial test for averaging 2023-03-10 09:51:08 +00:00
Michael Davidsaver
eea361bf5e Com: Allow runtime bypass of freeListLib
By environment or iocsh variable.
2023-03-10 09:48:27 +00:00
Michael Davidsaver
d9052f7105 update ci-scripts 2023-03-09 14:26:45 +00:00
Michael Davidsaver
fa00572780 update pvData 2023-03-06 15:54:34 +00:00
Ralph Lange
636f5517b2 Add QT Creator 9.x dir to .gitignore 2023-03-06 09:30:02 +00:00
Andrew Johnson
718da5c9be Convert RecordReference.md to ComponentReference.pod
That .pod file will now be converted to .html using the same style as
the individual local documents that it links to.

The dbdToHtml output files now include a header and footer that link to
the ComponentReference.html file (they started pointing to the original
RecordReference.html but that was broken on most people's builds because
we weren't converting that from the original Markdown version).

This commit also adjusts documentation/Makefile to use the build system
properly, and reorders the Doxygen main page index.
2023-02-04 22:56:19 -06:00
Michael Davidsaver
e5335ce760 GHA: Add -funsigned-char build 2023-02-01 09:25:10 -08:00
3dbc9ea264 iocsh: fix argument splitting
Since commit 60128ee9 "Com: separate iocsh argument splitting",
iocsh is broken on VxWorks (tested with version 6.9.4.12)

Any command prints the error "Unbalanced quote."

> iocsh
epics> echo
Unbalanced quote.
epics> "echo"
Unbalanced quote.
epics> "echo
Unbalanced quote.
epics> echo bla
Unbalanced quote.
epics> echo 1 2 3
Unbalanced quote.
epics> exit
Unbalanced quote.
2023-02-01 09:25:10 -08:00
Michael Davidsaver
80da400f9c dbLock: avoid possibly lost log prior to cantProceed 2023-02-01 09:25:10 -08:00
Michael Davidsaver
5787125bbb doc 2023-02-01 09:25:10 -08:00
Andrew Johnson
bc54524270 Fix bad JSON char detection in dbStatic
Thanks to Dirk Zimoch for pointing this out.
2023-01-24 11:08:13 -06:00
Andrew Johnson
a2d53c05f6 Explain SNC registration in template 2023-01-24 11:06:48 -06:00
Andrew Johnson
3293a29d59 Darwin: Remove '-undefined dynamic_lookup' from SHRLIB_LDFLAGS
It's been deprecated by Apple in latest XCode and generates warning
messages when creating .dylib libraries, but they don't yet have a
solution for use when creating loadable libraries (.bundle files).
2023-01-19 11:05:21 -06:00
Andrew Johnson
550e902bf3 iocLogPrefix: skip "already set" warning if prefix identical 2023-01-19 11:00:14 -06:00
Andrew Johnson
84e5cc0b69 softIoc -v -x prefix should show loading exit_file 2023-01-19 10:56:46 -06:00
Andrew Johnson
4b63882f28 Appveyor config fixes 2023-01-06 15:28:15 -06:00
Andrew Johnson
fb742beae3 Fix epicsThreadOnceTest.c
Replace epicsThreadSleep() with proper thread synchronization.
The main thread was reading runCount without taking lock first.
Taking the lock before accessing doneCount might not be necessary
given the epicsEventMustWait(), but not 100% sure.
2023-01-06 15:24:56 -06:00
Andrew Johnson
7ef0c80630 errSymLib: status 0 => "Ok" 2022-12-31 19:14:57 -06:00
Andrew Johnson
1f75813a4d Have macOS builds use Homebrew's GNU readline if present 2022-12-31 19:12:49 -06:00
Andrew Johnson
34ad8e2347 Edits to Release Notes and postfix.h documentation 2022-12-31 19:10:49 -06:00
Andrew Johnson
413f14e4ae Remove now-unused pdset variable. 2022-12-29 18:10:38 -06:00
Andrew Johnson
c22895d499 Adjust documentation about longout feature 2022-12-29 18:04:48 -06:00
Andrew Johnson
e63184e518 Merge PR #63, longout.OOPT 2022-12-29 16:31:42 -06:00
Andrew Johnson
755a4541c5 Update the RecordReference.md index; add links and filters. 2022-12-28 15:53:48 -06:00
Andrew Johnson
05cd7edf71 Update channel filter documentation, adding $ syntax 2022-12-28 15:52:30 -06:00
Andrew Johnson
5759726a89 Update link documentation 2022-12-28 15:43:35 -06:00
Andrew Johnson
14e7926d22 Add RecRef links to the top & bottom of each reference page 2022-12-28 15:30:25 -06:00
Andrew Johnson
c068fe3525 capr.pl: Fetch link fields as long strings 2022-12-28 12:43:38 -06:00
Andrew Johnson
c2364d9d1c Add license header to new epicsReadlinePvt.h 2022-12-28 12:42:51 -06:00
Michael Davidsaver
6be0372257 doc 2022-12-21 09:50:07 -08:00
Michael Davidsaver
e994ad78db GHA update 2022-12-21 08:15:26 -08:00
Michael Davidsaver
49fddaa13e errlogRemoveListeners() handle self-removal
Handle errlogRemoveListeners() during a callback.
2022-12-20 20:12:04 -08:00
Michael Davidsaver
7448a8bfa9 errlog: worker exit when buffer is empty
Allow the worker to flush any buffered messages.
After pvt.atExit, further logging will be synchronous.
Ensure any flusher gets a final wakeup.
2022-12-20 20:12:04 -08:00
Michael Davidsaver
166267a32f ringPointerTest in thread 2022-12-20 20:12:04 -08:00
Andrew Johnson
b460c2659e Fix for GH issue #219, menu fields with non-choice values
It's rare, but menu fields may hold a value that does not correspond
to one of the menu choices; the default value of the SSCN fields is
the most common example (65535). Change the type conversion routines
to return a numeric string instead of giving an error.

DBF_DEVICE was fixed in dbFastLinkConv.c before the 7.0.7 release.
2022-12-20 20:12:04 -08:00
Michael Skoufis
7ccc3ab82d Modify pointer type in example to match options from epicsTypes.h 2022-12-20 20:12:04 -08:00
Michael Davidsaver
adb0c898a6 doc 2022-12-20 20:12:04 -08:00
Michael Davidsaver
b38ff09f6e Com: iocsh: Tab completion of variable names for "var" 2022-12-20 20:12:04 -08:00
Michael Davidsaver
d9ca8a70f0 Com: iocsh: Tab completion
Add tab completion for "help ...", record names, and "pdbbase"
2022-12-20 20:12:04 -08:00
Michael Davidsaver
60128ee924 Com: separate iocsh argument splitting 2022-12-20 20:12:04 -08:00
Michael Davidsaver
b189991f9d Com: iocsh: add tab completion for command names 2022-12-20 20:12:04 -08:00
Michael Davidsaver
07ffc1ffae Com: introduce epicsReadlinePvt.h
Helping IDEs understand gnuReadline.c and osdReadline.c
2022-12-20 20:11:45 -08:00
Michael Davidsaver
a6afef4850 calc: add FMOD 2022-12-20 20:11:44 -08:00
Michael Davidsaver
9c0c486111 appveyor: bypass auto-detect of readline 2022-12-08 09:12:45 -08:00
Michael Davidsaver
3f5cf61fb6 update pvData 2022-12-05 10:51:47 -08:00
Andrew Johnson
6222902688 Update pva2pva module 2022-12-01 12:43:18 -06:00
Andrew Johnson
7febee04fa More & better Perl script dependencies 2022-11-30 13:35:56 -06:00
Andrew Johnson
4640f0a8ae Fix dbdExpand.pl issue 2022-11-30 13:34:22 -06:00
Andrew Johnson
8969a952e4 configure: Make Perl-generated files dependent on their .pl script 2022-11-24 17:57:05 -06:00
Michael Davidsaver
bc9415bb10 epicsErrlogTest: osiSockAttach() 2022-11-15 10:07:26 -08:00
Andrew Johnson
cbd86ada20 regRecDevDrv.pl: Don't break long symbol names in DBD files
Makes a test symbol name long enough to trigger the problem.

Fixes lp: #1995728
2022-11-04 11:09:06 -05:00
Michael Davidsaver
0f8ea3aa36 doc update dbUnitTest.h 2022-09-25 09:34:13 -07:00
Andrew Johnson
f62f68fd66 Update all submodules for future development 2022-09-07 17:00:45 -05:00
Andrew Johnson
eddafd2827 Release Checklist used for 7.0.7 2022-09-07 16:58:21 -05:00
Andrew Johnson
e3ce9d7f1a Adjustments to the make-tar.sh script 2022-09-07 16:57:09 -05:00
Andrew Johnson
df96e6df0f Set next development versions 2022-09-07 13:54:12 -05:00
Andrew Johnson
6fab3cafc5 Release notes and version number updates
Some checks failed
Base / CentOS-7 (push) Failing after 1s
Base / Fedora-33 (push) Failing after 2s
Base / Fedora-latest (push) Failing after 1s
Base / MacOS clang-12 (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 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19 (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 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (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 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
2022-09-07 13:50:35 -05:00
Andrew Johnson
e4811d5a28 Documentation updates UNRELEASED => 7.0.7 2022-09-07 12:46:21 -05:00
Andrew Johnson
34af1a12bc Submodule updates for the 7.0.7 release 2022-09-07 12:17:32 -05:00
Andrew Johnson
0301e60629 Expanded on Oksana's annotations 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
759a737983 moved code tags to exclude comments, as suggested 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
eeddf54b84 in file initHooks.h changed brief sytax to make comment appear next to the field, used \code {.cpp} as suggested for the example 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
6f6ab3b758 codeathon 2022 Added doxygen formatting to initHooks.h 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
59d16c56a1 codeathon 2022. Added missing comments with \brief, updated other notation for consistency 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
58edb984c9 codeathone 2022, added doxygen syntax to all comments in dbChannel.h 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
eb3207ee21 Codeathon 2022 Header annotations project dbChannel.h 2022-09-05 21:58:34 -05:00
Andrew Johnson
098ee6c063 Oops: Fix to RULES_MODULES 2022-09-03 10:59:26 -05:00
Andrew Johnson
54c02e2c24 Fix for GitHub issue #293
Ensure local build targets are up to date before running tests.
2022-09-03 10:47:58 -05:00
Andrew Johnson
efc7cbaf7f Build system fixes related to INSTALL_LOCATION
* The build can't descend into external submodules when there is no
configure/RULES_TOP file present in $(INSTALL_LOCATION).
* Recreate modules/RELEASE.<host>.local if configure/CONFIG_SITE or
configure/CONFIG_SITE.local have changed.
* Move the distclean of modules/RELEASE.<host>.local to RULES_TOP
* Several comment and white-space changes
2022-09-03 10:47:58 -05:00
Andrew Johnson
ede35aa152 Add .gitignore files to the makeBase{App,Ext} templates 2022-09-03 10:47:58 -05:00
Torsten Bögershausen
a8e8d22c31 iocinf.cpp: Hostnames may be longer than 32 bytes
Found here at ESS:

(all in one line)
EPICS_CA_ADDR_LIST=averylonghostname.mylabnetwork.technicalnetwork.example.com
EPICS_CA_AUTO_ADDR_LIST=NO
caget somePVnam

leads to something like this:
CA.Client.Exception...............................................
    Warning: "Empty PV search address list"
    Source File: ../udpiiu.cpp line 403
    Current Time: Thu Jun 09 2022 10:10:47.804161447

Problem desription:
addAddrToChannelAccessAddressList() will collect what ever we specify in
EPICS_CA_ADDR_LIST for channel access.
That function will add IP-addresses to the search list.
hostnames are possible, but are ignored if longer than 32 bytes,
because buf is too short.

If a hostname can be resolved into an IP, that is fine,
if not that is "fine as well" (better say: silently ignored):
If, and only if, EPICS_CA_AUTO_ADDR_LIST=NO is given then the one
and only too long hostname will be ignored and lead to an
"Empty PV search address list".

If EPICS_CA_AUTO_ADDR_LIST=YES (or nothing) is specified, the search list
is not empty, and EPICS will search all broadcast addresses.
This will eventually lead into a timout.

Solution:
Increase the buf size in addAddrToChannelAccessAddressList() from 32 to 256

The maximum length for a hostname is 255:
https://www.ietf.org/rfc/rfc1034.txt

If we add one byte for the string terminating '\0', we need 256 bytes.

And yes, this patch neglets the fact that a user can specify HOSTNAME:PORT,
which may need another 6 bytes. To put it the other way around:
In this case the hostname length is limited to 250 bytes,
which is still long enough in practice.
2022-09-02 18:28:34 -07:00
c2df1c6fe5 string waveform init test added 2022-09-02 08:33:32 -07:00
c5a7548526 eliminated unnecessary code 2022-09-02 08:33:32 -07:00
dc70dfd625 escape non-printable chars in dbgf output of CHAR arrays 2022-09-02 08:33:32 -07:00
20e20cbf2b improved JSON parser error messages 2022-09-02 08:33:32 -07:00
2e44ca586f using the same error printing function consistently 2022-09-02 08:33:32 -07:00
c9619d013a printing some context 2022-09-02 08:33:32 -07:00
ec650e8c3f allow empty array input links 2022-09-02 08:33:32 -07:00
Michael Davidsaver
d47fa4caa4 fix aSub with constant input links 2022-09-02 08:09:51 -07:00
Michael Davidsaver
f0369058bb dbReadCOM missing newline in error 2022-09-02 08:08:27 -07:00
Andrew Johnson
df96c0170a Minor changes to makeBaseApp templates 2022-08-30 14:06:30 -05:00
Andrew Johnson
a411a19b2a Updates to makeBaseExt templates
Removed RULES_PYTHON (swig and Python 2.2!)
Removed CONFIG_SITE files for cygwin, solaris & darwin-ppc & ppcx86
Added CONFIG_SITE files for linux-aarch64 and darwin-aarch64
Removed pointers to many ancient packages
2022-08-30 14:05:15 -05:00
Andrew Johnson
c0db7a0beb Fix ECHO, QUIET_FLAG and QUESTION_FLAG 2022-08-26 15:22:30 -05:00
Andrew Johnson
52dfb89741 PRINT.var targets work under make -q 2022-08-26 12:32:04 -05:00
Andrew Johnson
b652e8230a Improve expandVars.pl debug output 2022-08-26 12:16:09 -05:00
Andrew Johnson
0efffc1bcb expandVars.pl now only writes output when it changes 2022-08-26 12:12:14 -05:00
Andrew Johnson
d7030ae8a5 Adjust for Perls without \N in regex. 2022-08-23 15:15:41 -05:00
Andrew Johnson
24f30ede22 Portability: Don't use bash/shell operations 2022-08-23 13:35:40 -05:00
Andrew Johnson
04ee3f2888 hg and svn have been tested 2022-08-23 13:07:06 -05:00
Andrew Johnson
a373327b59 Get revision date from Darcs 2022-08-23 13:06:44 -05:00
Andrew Johnson
1fa98d489f Merge Pierrick's VersionHeaderDate branch into 7.0 2022-08-23 11:54:07 -05:00
Andrew Johnson
5cef60a3e4 Clear unused var warning 2022-08-21 16:51:17 -05:00
Andrew Johnson
20fb6b9ef5 Merge 3.15 changes into 7.0 2022-08-21 16:44:38 -05:00
Andrew Johnson
a249561677 Added darwin-aarch64 support from 7.0 branch 2022-08-21 16:17:29 -05:00
Andrew Johnson
96887926bf Merge Freddie's set_thread_descriptions branch
PR #270
2022-08-21 16:01:51 -05:00
Andrew Johnson
c8647ffab7 Added Release Note 2022-08-21 16:00:30 -05:00
Michael Davidsaver
e28c914966 dbDumpRecordType show field offset/size 2022-08-20 13:53:03 -07:00
Michael Davidsaver
f086be93a9 add OPT_LDFLAGS and pass -g when linking 2022-08-20 13:53:03 -07:00
Michael Davidsaver
6feaaebd75 test epicsStrtok_r 2022-08-20 11:47:41 -07:00
Andrew Johnson
5d92d406a1 Darwin: Resolve soft-links in epicsGetExecName() 2022-08-18 12:17:06 -05:00
Andrew Johnson
ad1a13730a Remove unused var 2022-08-16 15:08:23 -05:00
Andrew Johnson
a24a84c315 Replace errPrintf() in recGbl.c 2022-08-16 15:07:49 -05:00
Andrew Johnson
6e7a715380 Getting .DTYP from rectype with no devSup now returns '' 2022-08-16 13:33:11 -05:00
Andrew Johnson
b88b35d117 Enhancements to the capr.pl script 2022-08-16 11:58:35 -05:00
Andrew Johnson
0a20825c6e NTPTimeSync: Show when NTP sync failed, recovered 2022-08-15 19:12:05 -05:00
Michael Davidsaver
424d678abf linkTest_registerRecordDeviceDriver() fix return type 2022-07-29 07:45:23 -07:00
Andrew Johnson
007279cf29 Release notes updated 2022-07-28 13:25:14 -07:00
Andrew Johnson
752ca97f7e VxWorks: Stop VxWorks clock sync if EPICS_TS_FORCE_NTPTIME
Use ipcom_ipd_kill() to do it properly, announce when doing it.
Suspending the ipsntps task is dangerous, can hang the OS so
don't try to kill it if user already suspended the task.
Also drops checks for the "ipntpd" thread, not used.
2022-07-28 13:11:59 -07:00
Andrew Johnson
bf0b4d2f61 VxWorks: Re-run tz2timezone() whenever the year increases
In the event that it then goes backwards we won't run it again; that
should never happen, but if it did we should prefer stability!
2022-07-28 13:11:59 -07:00
Andrew Johnson
87d5c01853 Set useNTP if VxWorks sync task is suspended
Also report that state instead of "running".
2022-07-28 13:11:59 -07:00
Andrew Johnson
956af730a9 osiClockTime.c: Clarify message wording
Distinguish between IOC's clock sync thread and OS's one.
Show our sync interval even when not synchronized.
Only mention the clock sync thread where there can be one.
2022-07-28 13:11:59 -07:00
Andrew Johnson
32564b1a94 osiClockTime.c: Move some things around
Group the private variables, note which are mutex-protected.
Reset the sync interval to 1 second if sync is restarted.
Initialize the syncFromPriority variable.
2022-07-28 13:11:59 -07:00
Andrew Johnson
5b690d5467 VxWorks: Pass interest level into osdClockReport 2022-07-28 13:11:59 -07:00
Andrew Johnson
9efebb6d3d osiClock: Register ClockTime_Init with iocsh
ClockTime_Init and ClockTime_Shutdown are only on VxWorks & RTEMS.
Adjust help text to match.
ClockTime_Init can be re-run later to start or stop the sync thread.
2022-07-28 13:11:59 -07:00
Andrew Johnson
1df973b234 VxWorks: Provide osdClockReport() for OS clock sync tasks. 2022-07-28 13:11:59 -07:00
Andrew Johnson
c71ebd1221 VxWorks: Set timezone when using OS own time-sync tasks 2022-07-28 13:11:59 -07:00
Andrew Johnson
167807f0c4 Rename OS Clock provider on macOS, uses a different implementation. 2022-07-28 13:11:59 -07:00
Jure Varlec
e6b8ecd55e Add space to the message printed by errMessage() 2022-07-28 13:11:29 -07:00
Michael Davidsaver
9048aa3438 db: move db_field_log dtor out of union 2022-07-28 13:10:59 -07:00
Bruce Hill
5ba8080f6e Fix undef ts on first camonitor update of NORD
Moves db_post_events() calls for NORD to process() function
after it updates the timestamp.
2022-07-28 13:09:27 -07:00
Michael Davidsaver
a0a7a94944 mingw fix -lreadline
Override of OP_SYS_LDLIBS prevented LDLIBS_READLINE
from having an effect.

Recent readline doesn't need curses
2022-07-28 13:07:34 -07:00
Michael Davidsaver
42c7dbcd21 remove Makefile readline.h detection logic 2022-07-28 13:07:34 -07:00
Michael Davidsaver
4b8edd2b6f automatic COMMANDLINE_LIBRARY w/ newer compilers 2022-07-28 13:07:34 -07:00
Andrew Johnson
d82ab819ef Cap5 support for zero-length long strings 2022-07-13 13:24:54 -05:00
Andrew Johnson
5f02bad3fc Fix decimate filter for testing on VxWorks
Also adds checks to all filter tests to abort if they
can't continue because their filter wasn't registered.
2022-07-08 15:55:14 -05:00
Andrew Johnson
83a685867c Merged 'roehrig-7.0' into 7.0 2022-07-04 20:53:47 -05:00
Christian Roehrig
05311e0c94 Added Doxygen annotations to modules/libcom/src/iocsh/iocsh.h 2022-07-04 20:45:51 -05:00
Andrew Johnson
35f4d3f8dd Merged 'brendanchandler:annotations2' into 7.0 2022-07-04 20:34:24 -05:00
Brendan Chandler
9864f79d67 Update doxygen for ipAddrToAsciiAsynchronous 2022-07-04 20:28:43 -05:00
Brendan Chandler
91800787ed Doxygen support for ipAddrToAsciiAsynchronous.h 2022-07-04 20:28:43 -05:00
Andrew Johnson
05b27067cf Merged 'echandler-anl:doxygen_comments2' into 7.0 2022-07-04 20:23:24 -05:00
Elaine Chandler
ccdd2808d9 add doxygen comments for epicsAtomic.h 2022-07-04 20:19:45 -05:00
Andrew Johnson
00183fcd4b Merged 'brendanchandler:annotations' into 7.0 2022-07-04 19:58:30 -05:00
Brendan Chandler
1be06fc0e9 Fix doxygen annotations in epicsGuard and osiSock
Change addresses some review feedback kindly given by @minijackson
2022-07-04 19:38:15 -05:00
Brendan Chandler
7cdc44434c Doxygen annotation proofreading fixes in osiSock.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
f3dfb36117 Update doxygen annotations on osiSock.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
500e901e3d Change @param to \param in epicsGuard.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
a3b09ef1b8 Add doxygen annotations for osiSock.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
55d4801eb0 Fix a couple doxygen warnings
Warnings complained about undocumented parameters.
2022-07-04 19:37:57 -05:00
Brendan Chandler
af41b95b98 Fix a few formatting and doxygen conversion issues 2022-07-04 19:29:10 -05:00
Brendan Chandler
c6605b5d87 Update doxygen annotations in testMain.h
There were already some comments here, but they were missing a doxygen
\file declaration, so the annotations weren't shown in the doxygen
output.

Also added some formatting for the code example and definition of MAIN macro.
2022-07-04 19:29:10 -05:00
Brendan Chandler
9b9ed04ae2 Add doxygen annotations for epicsGuard.h 2022-07-04 19:29:09 -05:00
Andrew Johnson
50f9b12e7d Merged 'echandler-anl:doxygen_comments' into 7.0 2022-07-04 19:16:28 -05:00
Andrew Johnson
bfd2684e58 Minor fixes to Elaine's annotations 2022-07-04 16:47:44 -05:00
Elaine Chandler
95fcf690ad add doxygen comments for epicsStackTrace 2022-07-04 16:27:48 -05:00
Elaine Chandler
0fa3337404 add doxygen comments for epicsSpin.h 2022-07-04 16:27:48 -05:00
Elaine Chandler
e5b6ef9893 Fix doxygen comments to epicsString.h 2022-07-04 16:27:48 -05:00
Elaine Chandler
5b64eaac73 add doxygen comments for osiProcess.h 2022-07-04 16:27:48 -05:00
Elaine Chandler
30d4a583d0 add doxygen comments for logClient 2022-07-04 16:27:48 -05:00
Elaine Chandler
6249ef08f7 Added doxygen comments to epicsString.h 2022-07-04 16:27:48 -05:00
Andrew Johnson
b5105740e6 Fix warnings from Doxygen 2022-07-04 16:18:46 -05:00
Andrew Johnson
818f33e78f Update submodules 2022-07-04 16:04:56 -05:00
Andrew Johnson
571165df26 Stop Clang-12 warnings from Perl XS code 2022-07-04 15:55:18 -05:00
Michael Davidsaver
4df48c91f4 dbEvent: re-add compaction of duplicate "empty" events 2022-06-29 07:23:36 -07:00
Michael Davidsaver
32652414b3 update release notes 2022-06-20 08:20:40 -07:00
Michael Davidsaver
9c8aaa93cd Set RSRV_SERVER_PORT
Publish actual TCP port used.
2022-06-20 08:11:09 -07:00
Andrew Johnson
abe819b51d Release notes for dbdExpand.pl changes 2022-06-20 08:10:46 -07:00
Andrew Johnson
cf278b4159 Sort other DBD entries for output
This should solve all DBD-related reproduceable build issues.
2022-06-20 08:10:46 -07:00
Andrew Johnson
50594a8cc3 Release notes entry for dbExpand.pl -s 2022-06-20 08:10:46 -07:00
Andrew Johnson
ce420588db Have dbExpand.pl sort records by name, unless -s used 2022-06-20 08:10:46 -07:00
Andrew Johnson
4d3a27fdb0 Keep a separate list of record names 2022-06-20 08:10:46 -07:00
Jure Varlec
6176a81a76 Update docs for compress record's run-time parameters 2022-06-20 08:10:01 -07:00
Minijackson
a722bb9289 treewide: add usage help to various iocsh functions 2022-06-20 08:09:42 -07:00
Michael Davidsaver
19daf6136f ioc template avoid passing "0"
> dbLoadDatabase("../../dbd/_APPNAME_.dbd",0,0)

is being interpreted as

> dbLoadDatabase("../../dbd/_APPNAME_.dbd","0","0")

If "../../dbd/_APPNAME_.dbd" doesn't exist, this will
next attempt to open "0/../../dbd/_APPNAME_.dbd",
which added to my confusion...
2022-06-20 08:09:08 -07:00
Michael Davidsaver
0552f2bb72 aao: add OMSL and DOL 2022-06-20 08:08:50 -07:00
Andrew Johnson
9bb11e6e88 Fix VxWorks time sync initialization bug 2022-06-14 16:07:39 -05:00
Michael Davidsaver
2f8272d3a1 doc for: posix: use pthread_key_create() to cleanup epicsThreadOSD 2022-06-08 09:40:12 -07:00
Michael Davidsaver
7cf2a1daca epicsThreadTest: check that joined threads disappear 2022-06-08 09:40:12 -07:00
Michael Davidsaver
d019e9787a posix: use pthread_key_create() to cleanup epicsThreadOSD
Ensure that cleanup happens for all threads,
including implicitly created.
2022-06-08 09:40:12 -07:00
Freddie Akeroyd
4b884c15b1 SetThreadName: Add WINAPI (correctly) for 32bit builds 2022-05-24 14:40:46 +01:00
Freddie Akeroyd
0ace4e4a30 SetThreadName: Add WINAPI for 32bit builds 2022-05-24 14:21:12 +01:00
Freddie Akeroyd
3cf2d3737f Use SetThreadDescription(), if available, to set thread name 2022-05-24 13:24:42 +01:00
hanlet
5997018fb0 Made changes suggested by Michael:
- removed unused/misused $opc_X
- modified command line repo calls
- fixed ifndef block
2022-05-17 12:14:29 -05:00
hanlet
2afa4ea390 Cosmetic change. 2022-05-13 13:32:35 -07:00
hanlet
f0c86c5cb3 Added repository name
Changed git date from epoch to present commit date
2022-05-13 13:25:47 -07:00
hanlet
8e4ffd46a0 Changed descriptive text to identify new commit date information. 2022-05-13 11:38:32 -07:00
hanlet
f109371268 Added revision release time to ioc startup message. 2022-05-13 11:30:26 -07:00
hanlet
e566c52a78 Simplified to remove "use" cases and settling for string for versions of commit date/time. 2022-05-13 10:46:17 -07:00
hanlet
8d0bfcbc5b Modify genVersionHeader.pl to add commit time (in epoch).
Tested for git.
Not tested: darcs, mercurial, or svn
Skipping: bzr
2022-05-13 09:31:01 -07:00
Michael Davidsaver
3fadf4a26c add missing registerRecordDeviceDriver.pl dependency 2022-05-12 10:47:44 -07:00
Michael Davidsaver
9ebd841738 update doc in epicsStdio.h 2022-05-12 10:47:44 -07:00
Michael Davidsaver
94b0e2621f iocsh: more helpful help
For plain "help", move the hint text to the end.
For "help ..." make the command names bold.
2022-05-12 09:01:36 -07:00
Michael Davidsaver
a44ddd586e errlog: add ANSI_BOLD 2022-05-12 09:01:36 -07:00
Minijackson
6fbf95ab18 make Perl hash iteration reproducible
By default Perl doesn't iterate over hashes in a reproducible manner,
to avoid DDoS. Since we aren't providing untrusted inputs, it is fine to
disable this behaviour.

Among other things, this makes the .dbd and some .h generation reproducible.

More information here:

- https://reproducible-builds.org/docs/stable-outputs/
- https://perldoc.perl.org/perlrun#PERL_HASH_SEED
2022-05-11 11:44:00 -07:00
Michael Davidsaver
5485adacb9 make epicsNAN and epicsINF constants really constant 2022-05-11 11:44:00 -07:00
Florian Feldbauer
6ecc384116 fix failing STATIC_BUILD on linux-arm
On linux-arm STATIC_BUILD used the `-static` flag
which leads for some reason to the executables being
linked against `/lib/ld.so.1` which does not exists.

Setting `STATIC_LDFLAGS_YES= -Wl,-Bstatic` in CONFIG.linux-arm.linux-arm
fixed this issue for me.
2022-05-11 11:44:00 -07:00
Matt-E7R5
66537d01bd Patch for RTEMS-mvme2700 2022-05-11 11:44:00 -07:00
Ralph Lange
b6f69241e1 Merge 'evan@gh/add-simm-to-ao-records' into 7.0
(closes #144)
2022-05-11 10:56:37 -07:00
Ralph Lange
4fc549234c Merge branch '7.0' into add-simm-to-ao-records 2022-05-11 10:47:12 -07:00
Ralph Lange
0bcffb56bb Add mention to RELEASE_NOTES 2022-05-11 10:44:53 -07:00
Ralph Lange
60001c0571 Add SIMM=RAW for mbboDirect record 2022-05-10 16:33:28 -07:00
Ralph Lange
37b95bc242 Add SIMM=RAW for mbbo record 2022-05-10 16:33:28 -07:00
Ralph Lange
4e9bb9fe50 Add SIMM=RAW to bo record 2022-05-10 16:33:27 -07:00
Ralph Lange
371cdde6df Trivial fixes to simmRAW for ao 2022-05-10 16:33:27 -07:00
Andrew Johnson
cbae8d37b3 Improve wording of seqRecord doc 2022-04-26 21:07:27 -05:00
wtup
9eb88f27d9 Fixed direction of SHIFT to match implementation 2022-04-26 20:56:43 -05:00
Andrew Johnson
e329fa3296 CA Client: Protect against epicsTime::strftime() throwing
libCa shouldn't cause an application to abort with an uncaught
exception on a machine that has timezone problems just because
we can't convert the current time into a string.
2022-04-24 12:50:40 -05:00
Michael Davidsaver
492672c718 Revert "ci: GHA follow 'make' with 'make -q'"
Stupid make...

This reverts commit b4d7ebd648.
This reverts commit 0f0f9f49d6.
2022-04-23 10:19:00 -07:00
Michael Davidsaver
b4d7ebd648 cue.py workaround limitation
The first argument after "build" can't be an option.
cf. python argparse limitations of add_parser() + REMAINDER
2022-04-23 08:49:35 -07:00
Michael Davidsaver
0f0f9f49d6 ci: GHA follow 'make' with 'make -q'
Detect situations where 'make' was somehow incomplete,
or where an incorrect dependency leaves some step
perpetually out-of-date and repeated every time.
2022-04-19 10:22:54 -07:00
Andrew Johnson
6d3821adb8 Soft-links to capr.pl and makeBaseApp.pl scripts now work
The other Perl scripts that use FindBin for their lib path could
have the same changes applied, but these two scripts are the ones
normally run by hand so might get soft-linked by an installer.
Without this change these scripts don't actually work if run from
a soft-link instead of directly.
2022-04-18 20:46:48 -05:00
Michael Davidsaver
92e97af610 softMain: handle rRDD error 2022-04-16 13:23:58 -07:00
Michael Davidsaver
b0e2e8426f Quiet warning 2022-04-16 13:23:58 -07:00
Andrew Johnson
3e371da8ec RULES_EXPAND: Keep intermediate files
This prevents GNUmake from recreating expanded files
such as databaseVersion.h at every build.
2022-03-28 00:07:21 -05:00
Michael Davidsaver
91941af992 quiet warnings 2022-03-04 10:00:12 -08:00
Michael Davidsaver
d2644baf38 minor 2022-03-03 13:16:57 -08:00
Michael Davidsaver
62092d4399 test dbReadDatabaseFP() 2022-03-03 13:16:53 -08:00
Michael Davidsaver
6c5d56688d help out IDEs 2022-03-03 13:16:50 -08:00
Michael Davidsaver
a6779df21c dbReadDatabaseFP() always fclose() 2022-03-03 13:16:45 -08:00
Andrew Johnson
d8c5379453 Configure builds for lgtm.com 2022-02-15 13:26:43 -06:00
Andrew Johnson
7a9801a4cb Add vxWorks-e500v2 target (MVME2500, APS only) 2022-02-15 13:08:51 -06:00
Andrew Johnson
f33add020e Update Release notes 2022-02-15 11:15:04 -06:00
Andrew Johnson
3bebe6e873 Revert "configure: Don't hide any perl scripts being run"
This reverts commit 3e8f3a1ee9
which was wrong - recipes that start with '-' are still echoed,
they just don't fail the build if they don't succeed.

This fixes setting CHECK_RELEASE = WARN in configure/Makefile
2022-02-15 10:49:37 -06:00
Andrew Johnson
2fbaa7f926 Improve POD documentation of the TSE and TSEL fields 2022-02-08 15:29:05 -06:00
Andrew Johnson
e55e4d7646 Make DISP field DCT=Yes 2022-02-08 15:29:05 -06:00
Andrew Johnson
5efc0cbfce Echo message when running makeBpt 2022-02-08 15:29:05 -06:00
Andrew Johnson
3a182a9eea "Quote" exe program paths for Windows
Clean up old EPICS_DATABASE var's (pre-7.0?)
2022-02-08 15:29:05 -06:00
Michael Davidsaver
0e56e202fc ci: drop CentOS-8
The centos:8 docker image has disappeared.
2022-02-01 12:53:55 -08:00
Michael Davidsaver
d9fd73a850 yajl: doc 2022-01-28 11:23:16 -08:00
Andrew Johnson
d508962211 Breaktable.pm: Add missing declaration 2022-01-24 15:30:23 -06:00
Andrew Johnson
7cb80d5a17 Merge Dirk's fix_epicsInt8 branch into 7.0 2022-01-24 13:32:16 -06:00
Andrew Johnson
051e3f3bc3 Merge Michael's fork-warn branch into 7.0 2022-01-24 13:02:22 -06:00
Andrew Johnson
db216e63a7 Merge Dirk's hex_in_hw_links branch into 7.0 2022-01-24 12:57:53 -06:00
Andrew Johnson
7a3c9eaaa0 Merge Michael's linux-mcast-all branch into 7.0 2022-01-24 12:51:09 -06:00
Andrew Johnson
4bece4ad92 Merge Heinz & Andrew's rtems-osd-event branch into 7.0 2022-01-24 12:44:17 -06:00
Andrew Johnson
36f11fba95 Release Notes update for epicsEvent 2022-01-24 12:43:36 -06:00
Andrew Johnson
7017e54930 Allow more char's in breaktable names 2022-01-24 12:25:57 -06:00
Andrew Johnson
43b623d80e Markdown issue in RELEASE_NOTES 2022-01-13 17:14:00 -06:00
Andrew Johnson
132f9105d0 Fix filenames in CONFIG_SITE file comments 2022-01-13 17:13:25 -06:00
Andrew Johnson
1655d68ec4 Fix for NaN/overflow timeout in RTEMS-score osdEvent 2022-01-05 12:04:02 -06:00
Andrew Johnson
e4a81bb361 Document zero and NaN timeout values
Rename parameter timeOut => timeout everywhere
2022-01-04 17:16:59 -06:00
Andrew Johnson
d1094ee787 Fix timeout values in epicsEventWaitWithTimeout()
isnan(timeOut) => wait forever
0 < timeOut < 1/rate => 1 tick
rtems_interval is a typedef for uint32_t
2022-01-04 13:07:30 -06:00
Andrew Johnson
34baa485bc Fix timeout values in epicsEventWaitWithTimeout()
isnan(timeOut) => wait forever
0 < timeOut < 1/rate => 1 tick
2022-01-04 13:05:21 -06:00
c5012d9f73 Make sure epicsInt8 is signed on all architectures 2021-12-17 09:42:04 +01:00
Ralph Lange
7c168f20f4 Fix gdd string to double conversion
This is an alternative fix for the issue described in
https://github.com/epics-modules/pcas/issues/4 and
https://github.com/epics-extensions/ca-gateway/issues/37
that keeps the call to epicsScanDouble() before trying
sscanf() first with "%lf" (ignoring extra characters)
then with "%x" (to catch hex numbers).
(closes #216)
2021-12-08 17:07:11 +01:00
Michael Davidsaver
de7ad13b3c Com: posix warn of use of epicsThread from child after fork() 2021-11-15 10:09:52 -08:00
Michael Davidsaver
5e2a52401f Com: avoid implicit use of epicsStdio in posix epicsThread.c 2021-11-13 11:47:15 -08:00
6173baed1e mention hex numbers for HW links in release notes 2021-11-10 10:49:23 +01:00
71efed8c1b extend link test to hex numbers 2021-11-10 10:15:56 +01:00
9a09436ac8 allow hex (and octal) in hardware links
Conflicts:
	modules/database/src/ioc/dbStatic/dbStaticLib.c
2021-11-10 10:15:39 +01:00
Andrew Johnson
6063de9a8b Added Heinz new osdEvent.c to RTEMS-posix 2021-10-12 12:37:57 -05:00
Michael Davidsaver
51191e6155 Com: clear IP_MULTICAST_ALL on Linux
The default, non-compliant, behavior will pass all multicast packets
to any socket bound to 0.0.0.0 or the mcast address, regardless
of which groups, on which interfaces, that socket has joined.
2021-08-05 08:51:02 -07:00
Evan Daykin
2f0a7c7342 Merge branch 'epics-base:7.0' into add-simm-to-ao-records 2021-06-09 10:19:01 -04:00
Evan Daykin
edb9208b01 correct number of simm tests 2021-03-12 17:06:35 -05:00
Evan Daykin
4f0cc20e2b Feature: add SIMM=RAW to ao records 2021-03-12 16:31:10 -05:00
Joao Paulo Martins
6c573b496a longout rec: fix behaviour when record is processed for the first time and OOPT is On Change 2021-03-10 18:50:42 +01:00
Joao Paulo Martins
1d85bc7424 longout record: detect OUT link change using special function AFTER put, better documentation 2021-03-10 11:07:30 +01:00
Joao Paulo Martins
f4d94b9725 Longout OOPT field refactoring and updated documentation; Release notes additions 2021-03-09 16:31:54 +01:00
Joao Paulo Martins
4e7a18bfb4 Adding test routines for longout record with OOPT field 2021-03-09 16:31:54 +01:00
Joao Paulo Martins
c1ae5064b8 Added OOPT to longout record 2021-03-09 16:31:54 +01:00
408 changed files with 11080 additions and 3613 deletions

View File

@@ -25,17 +25,6 @@ init:
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skipping commits affecting only specific files
skip_commits:
files:
- 'documentation/*'
- 'startup/*'
- '.github/*'
- '.tools/*'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
#---------------------------------#
# build matrix configuration #
#---------------------------------#
@@ -67,6 +56,8 @@ environment:
- CMP: vs2010
- CMP: gcc
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
# TODO: static linking w/ readline isn't working. Bypass auto-detect
COMMANDLINE_LIBRARY: EPICS
# Platform: processor architecture
platform:

View File

@@ -32,17 +32,6 @@ init:
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skipping commits affecting only specific files
skip_commits:
files:
- 'documentation/*'
- 'startup/*'
- '.github/*'
- '.tools/*'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
#---------------------------------#
# build matrix configuration #
#---------------------------------#
@@ -73,6 +62,9 @@ environment:
- CMP: vs2012
- CMP: vs2010
- CMP: gcc
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
# TODO: static linking w/ readline isn't working. Bypass auto-detect
COMMANDLINE_LIBRARY: EPICS
# Platform: processor architecture
platform:

2
.ci

Submodule .ci updated: 75bae77c1d...20f8e05393

8
.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
# Documentation for this file: https://EditorConfig.org
root = true
# Unix-style newlines ending every file,
# as some compilers complain about files not ending in newline
[*]
insert_final_newline = true

View File

@@ -0,0 +1,13 @@
name: Check EditorConfig
on:
push:
pull_request:
jobs:
editorconfig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: EditorConfig-Action
uses: greut/eclint-action@v0

View File

@@ -15,6 +15,7 @@ on:
- 'startup/*'
- '.appveyor/*'
- '.tools/*'
- '.lgtm.yml'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
@@ -24,9 +25,11 @@ on:
- 'startup/*'
- '.appveyor/*'
- '.tools/*'
- '.lgtm.yml'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
workflow_dispatch:
env:
SETUP_PATH: .ci-local:.ci
@@ -41,9 +44,7 @@ jobs:
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
WINE: ${{ matrix.wine }}
RTEMS: ${{ matrix.rtems }}
RTEMS_TARGET: ${{ matrix.rtems_target }}
CI_CROSS_TARGETS: ${{ matrix.cross }}
EXTRA: ${{ matrix.extra }}
TEST: ${{ matrix.test }}
strategy:
@@ -51,16 +52,35 @@ 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
wine: "64"
cross: "windows-x64-mingw"
name: "Ub-20 gcc-9 + MinGW"
- os: ubuntu-20.04
cmp: gcc
configuration: static
wine: "64"
cross: "windows-x64-mingw"
name: "Ub-20 gcc-9 + MinGW, static"
- os: ubuntu-20.04
@@ -69,6 +89,12 @@ jobs:
extra: "CMD_CXXFLAGS=-std=c++11"
name: "Ub-20 gcc-9 C++11, static"
- os: ubuntu-20.04
cmp: gcc
configuration: static
extra: "CMD_CFLAGS=-funsigned-char CMD_CXXFLAGS=-funsigned-char"
name: "Ub-20 gcc-9 unsigned char"
- os: ubuntu-20.04
cmp: clang
configuration: default
@@ -83,67 +109,42 @@ jobs:
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-pc686-qemu
cross: "RTEMS-pc686-qemu@5"
name: "Ub-20 gcc-9 + RT-5.1 pc686"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-beatnik
cross: "RTEMS-beatnik@5"
test: NO
name: "Ub-20 gcc-9 + RT-5.1 beatnik"
# Only build one RTEMS target per CPU family
# unless it's running the tests
#
# - os: ubuntu-20.04
# cmp: gcc
# configuration: default
# rtems: "5"
# rtems_target: RTEMS-mvme3100
# test: NO
# name: "Ub-20 gcc-9 + RT-5.1 mvme3100"
#
# - os: ubuntu-20.04
# cmp: gcc
# configuration: default
# rtems: "5"
# rtems_target: RTEMS-qoriq_e500
# test: NO
# name: "Ub-20 gcc-9 + RT-5.1 qoriq_e500"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-xilinx_zynq_a9_qemu
cross: "RTEMS-xilinx_zynq_a9_qemu@5"
test: NO
name: "Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-uC5282
cross: "RTEMS-uC5282@5"
test: NO
name: "Ub-20 gcc-9 + RT-5.1 uC5282"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "4.10"
name: "Ub-20 gcc-9 + RT-4.10"
rtems_target: RTEMS-pc386-qemu
cross: "RTEMS-pc386-qemu@4.10"
test: NO
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "4.9"
name: "Ub-20 gcc-9 + RT-4.9"
rtems_target: RTEMS-pc386-qemu
cross: "RTEMS-pc386-qemu@4.9"
- os: macos-latest
cmp: clang
@@ -152,13 +153,15 @@ jobs:
- os: windows-2019
cmp: vs2019
configuration: default
configuration: debug
name: "Win2019 MSC-19"
extra: "CMD_CXXFLAGS=-analysis"
- os: windows-2019
cmp: vs2019
configuration: static
configuration: static-debug
name: "Win2019 MSC-19, static"
extra: "CMD_CXXFLAGS=-analysis"
- os: windows-2019
cmp: vs2019
@@ -170,8 +173,28 @@ jobs:
configuration: default
name: "Win2019 mingw"
# Cross builds
- os: ubuntu-latest
cmp: gcc
configuration: default
name: "Cross linux-aarch64"
cross: linux-aarch64
- os: ubuntu-latest
cmp: gcc
configuration: default
name: "Cross linux-arm gnueabi"
cross: linux-arm@arm-linux-gnueabi
- os: ubuntu-latest
cmp: gcc
configuration: default
name: "Cross linux-arm gnueabihf"
cross: linux-arm@arm-linux-gnueabihf
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Automatic core dumper analysis
@@ -189,7 +212,7 @@ jobs:
run: python .ci/cue.py -T 60M test
- name: Upload tapfiles Artifact
if: ${{ always() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: tapfiles ${{ matrix.name }}
path: '**/O.*/*.tap'
@@ -219,11 +242,6 @@ jobs:
cmp: gcc
configuration: default
- name: "CentOS-8"
image: centos:8
cmp: gcc
configuration: default
- name: "Fedora-33"
image: fedora:33
cmp: gcc
@@ -261,11 +279,15 @@ jobs:
# people would rather just break all existing scripts...
[ -e /usr/bin/python ] || ln -sf python3 /usr/bin/python
python --version
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
if: matrix.image!='centos:7'
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@node16
if: matrix.image=='centos:7'
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: Build main module
@@ -274,7 +296,7 @@ jobs:
run: python .ci/cue.py -T 20M test
- name: Upload tapfiles Artifact
if: ${{ always() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: tapfiles ${{ matrix.name }}
path: '**/O.*/*.tap'

2
.gitignore vendored
View File

@@ -11,8 +11,10 @@
/modules/Makefile.local
O.*/
/QtC-*
/.qtc_*
/.vscode/
*.orig
*.log
.*.swp
.DS_Store
.iocsh_history

50
.lgtm.yml Normal file
View File

@@ -0,0 +1,50 @@
# Configuration for lgtm.com
#
path_classifiers:
test:
- exclude: /
- test
- "modules/*/test*"
library:
- modules/libcom/src/yacc
- modules/libcom/src/flex
template:
- src/template
- modules/ca/src/template
- modules/database/src/template
extraction:
cpp:
prepare:
packages:
- "libreadline-dev"
index:
build_command:
- "g++ --version"
- "make --version"
- "perl --version"
- "make -sj2 || echo '*** Build failed, ignored for lgtm ***'"
python:
index:
include:
- src/tools
# Interpreted languages to be excluded
javascript:
index:
exclude:
- "*"
# Compiled languages to be excluded
java:
index:
build_command: "echo No Java code in this project"
csharp:
index:
build_command: "echo No C# code in this project"
go:
index:
build_command: "echo No Go code in this project"

View File

@@ -20,9 +20,9 @@ maybedie() {
usage() {
cat <<EOF >&2
usage: $0 [-v] [-s] <rev> [<outfile> [<prefix>]]
usage: $0 [-v] [-d] <rev> [<outfile> [<prefix>]]
<rev> may be any git revision spec. (tag, branch, or commit id).
<rev> may be any git revision spec. (tag or, using -d, branch or commit id).
If provided, <outfile> must end with ".tar", ".tar.gz" or ".tar.bz2".
If <outfile> is omitted, "base-<rev>.tar.gz" will be used.
@@ -140,10 +140,12 @@ sed \
-e '/\/\.ci-local\//d' \
-e '/\/\.tools\//d' \
-e '/\/jenkins\//d' \
-e '/\/\.git/d' \
-e '/\/\.github\//d' \
-e '/\/\.gitmodules$/d' \
-e '/\/\.hgtags$/d' \
-e '/\/\.cproject$/d' \
-e '/\/\.project$/d' \
-e '/\/\.lgtm\.yml$/d' \
-e '/\/\.travis\.yml$/d' \
-e '/\/\.appveyor\.yml$/d' \
-e '/\/\.readthedocs\.yml$/d' \

View File

@@ -34,6 +34,11 @@ ifeq ($(origin EPICS_HOST_ARCH), undefined)
EHA :=
endif
# Make Perl hash iteration reproducible.
# See: https://reproducible-builds.org/docs/stable-outputs/
#
export PERL_HASH_SEED = 0
-include $(CONFIG)/RELEASE
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH).Common

View File

@@ -47,6 +47,7 @@ OPT_CXXFLAGS_NO = -g
CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
OPT_LDFLAGS_NO = -g
PIPE_CFLAGS_YES_YES = -pipe
PIPE_CFLAGS = $(PIPE_CFLAGS_$(GCC_PIPE)_$(GNU))

View File

@@ -38,10 +38,16 @@ TOOLS = $(abspath $(EPICS_BASE_HOST_BIN))
FIND_TOOL = $(firstword $(wildcard $(TOOLS)/$(1) \
$(TOP)/src/tools/$(1)) $(EPICS_BASE)/src/tools/$(1))
#---------------------------------------------------------------
# Find Perl modules for dependencies
FIND_PM = $(wildcard $(EPICS_BASE)/lib/perl/$(1))
#---------------------------------------------------------------
# EPICS Base build tools and tool flags
PODTOHTML = $(PERL) $(TOOLS)/podToHtml.pl
PODTOHTML_pl = $(TOOLS)/podToHtml.pl
PODTOHTML_dep = $(PODTOHTML_pl) $(call FIND_PM,EPICS/PodHtml.pm)
PODTOHTML = $(PERL) $(PODTOHTML_pl)
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG)

View File

@@ -48,15 +48,15 @@ EPICS_VERSION = 7
EPICS_REVISION = 0
# EPICS_MODIFICATION must be a number >=0 and <256
EPICS_MODIFICATION = 6
EPICS_MODIFICATION = 8
# 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)
EPICS_DEV_SNAPSHOT=-DEV
EPICS_DEV_SNAPSHOT=
# No changes should be needed below here

View File

@@ -2,11 +2,11 @@
EPICS_CA_MAJOR_VERSION = 4
EPICS_CA_MINOR_VERSION = 14
EPICS_CA_MAINTENANCE_VERSION = 2
EPICS_CA_MAINTENANCE_VERSION = 4
# Development flag, set to zero for release versions
EPICS_CA_DEVELOPMENT_FLAG = 1
EPICS_CA_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -82,14 +82,21 @@ FINAL_LOCATION = $(INSTALL_ABSOLUTE)
IOCS_APPL_TOP = $(INSTALL_ABSOLUTE)
#-------------------------------------------------------
# Silencing the build - suppress messages during 'make -s'
NOP = :
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
QUIET_FLAG := $(if $(filter -s,$(MFLAGS)),-q,)
# How to portably check the flags to make
makeflags := $(firstword $(filter-out -,$(filter-out --%,$(MAKEFLAGS))))
define checkflags
make-$1 := $(findstring $1,$(makeflags))
endef
# This is extensible to most single letter flags:
$(foreach flag,s q, $(eval $(call checkflags,$(flag))))
# Silent builds - suppress messages during 'make -s'
NOP = :
ECHO = @$(if $(make-s),$(NOP),echo)
QUIET_FLAG := $(if $(make-s),-q,)
#-------------------------------------------------------
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
QUESTION_FLAG := $(if $(filter -q,$(MFLAGS)),-i,)
QUESTION_FLAG := $(if $(make-q),-i,)
#-------------------------------------------------------
ifdef T_A
@@ -267,6 +274,7 @@ WARN_CXXFLAGS = $(WARN_CXXFLAGS_$($(BUILD_CLASS)_WARN))
OPT_CPPFLAGS = $(OPT_CPPFLAGS_$($(BUILD_CLASS)_OPT))
OPT_CFLAGS = $(OPT_CFLAGS_$($(BUILD_CLASS)_OPT))
OPT_CXXFLAGS = $(OPT_CXXFLAGS_$($(BUILD_CLASS)_OPT))
OPT_LDFLAGS = $(OPT_LDFLAGS_$($(BUILD_CLASS)_OPT))
# Static build flags
STATIC_CFLAGS = $(STATIC_CFLAGS_$(STATIC_BUILD))
@@ -288,7 +296,6 @@ TARGET_LIB_LDFLAGS = $(if $(findstring $*, $(LOADABLE_LIBRARY)), \
#--------------------------------------------------
# Command-line input support default
COMMANDLINE_LIBRARY = EPICS
OP_SYS_LDLIBS += $(LDLIBS_$(COMMANDLINE_LIBRARY))
OP_SYS_LDFLAGS += $(LDFLAGS_$(COMMANDLINE_LIBRARY))
RUNTIME_LDFLAGS += $(RUNTIME_LDFLAGS_$(COMMANDLINE_LIBRARY))

View File

@@ -5,22 +5,28 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
# Set EPICS_DATABASE if necessary
ifndef EPICS_DATABASE
EPICS_DATABASE = $(if $(BUILDING_DATABASE),$(INSTALL_LOCATION),$(EPICS_BASE))
# Installed perl scripts and dependent modules that have
# a significant effect on the script's output
DBDEXPAND_pl = $(EPICS_BASE_HOST_BIN)/dbdExpand.pl
DBDTORECTYPEH_pl = $(EPICS_BASE_HOST_BIN)/dbdToRecordtypeH.pl
DBDTORECTYPEH_dep = $(DBDTORECTYPEH_pl) $(call FIND_PM,DBD/Rec*.pm)
DBDTOMENUH_pl = $(EPICS_BASE_HOST_BIN)/dbdToMenuH.pl
DBDTOMENUH_dep = $(DBDTOMENUH_pl) $(call FIND_PM,DBD/Menu.pm)
DBDTOHTML_pl = $(EPICS_BASE_HOST_BIN)/dbdToHtml.pl
DBDTOHTML_dep = $(DBDTOHTML_pl) $(call FIND_PM,EPICS/Pod*Html.pm)
REGRECDEVDRV_pl = $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
REGRECDEVDRV_dep = $(REGRECDEVDRV_pl)
# Paths to tools built here
EPICS_DATABASE_HOST_BIN = $(EPICS_DATABASE)/bin/$(EPICS_HOST_ARCH)
endif
# Commands for running scripts in recipes
DBEXPAND = $(PERL) $(DBDEXPAND_pl)
DBTORECORDTYPEH = $(PERL) $(DBDTORECTYPEH_pl)
DBTOMENUH = $(PERL) $(DBDTOMENUH_pl)
DBDTOHTML = $(PERL) $(DBDTOHTML_pl)
REGISTERRECORDDEVICEDRIVER = $(PERL) $(REGRECDEVDRV_pl)
# Set location of locally-built tools
MAKEBPT = $(EPICS_DATABASE_HOST_BIN)/makeBpt$(HOSTEXE)
DBEXPAND = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdExpand.pl
DBTORECORDTYPEH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToRecordtypeH.pl
DBTOMENUH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToMenuH.pl
DBDTOHTML = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToHtml.pl
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_DATABASE_HOST_BIN)/registerRecordDeviceDriver.pl
MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
# Installed binary executables, quoted for running on Windows
MAKEBPT = "$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)"
MSI3_15 = "$(EPICS_BASE_HOST_BIN)/msi$(HOSTEXE)"
# Libraries needed to link a basic IOC
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com

View File

@@ -1,12 +1,12 @@
# Version number for the database APIs and shared library
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 21
EPICS_DATABASE_MINOR_VERSION = 23
EPICS_DATABASE_MAINTENANCE_VERSION = 1
# Development flag, set to zero for release versions
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -5,9 +5,10 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
# Set location of locally generated tools
YACC = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/antelope$(HOSTEXE)
LEX = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/e_flex$(HOSTEXE) \
# Our locally-built tools
# Windows can need these paths to be quoted
YACC = "$(EPICS_BASE_HOST_BIN)/antelope$(HOSTEXE)"
LEX = "$(EPICS_BASE_HOST_BIN)/e_flex$(HOSTEXE)" \
-S$(EPICS_BASE)/include/flex.skel.static
# Default stack size for osiThread

View File

@@ -1,12 +1,12 @@
# Version number for the libcom APIs and shared library
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 21
EPICS_LIBCOM_MINOR_VERSION = 23
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
# Development flag, set to zero for release versions
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -34,5 +34,9 @@ CFG += TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A)
include $(TOP)/configure/RULES
ifeq ($(GNU),YES)
# Pass compiler flags to preprocessor to enable _FORTIFY_SOURCE
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): CPPFLAGS += $(CFLAGS)
endif
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): toolchain.c
$(PREPROCESS.cpp)

View File

@@ -17,7 +17,7 @@ TEMPL_SUFFIX ?= .template
# vpath
vpath %.pm $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
vpath %.pod $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
vpath %.pod $(USR_VPATH) $(SRC_DIRS) .. $(dir $(DBD))
vpath %.dbd $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
vpath %.db $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
vpath %.vdb $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
@@ -217,32 +217,32 @@ realclean: clean
#---------------------------------------------------------------
# Dependency files
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
%Record.h$(DEP): %Record.dbd
%Record.h$(DEP): %Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
%Record.h$(DEP): ../%Record.dbd
%Record.h$(DEP): ../%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
menu%.h$(DEP): $(COMMON_DIR)/menu%.dbd
menu%.h$(DEP): $(COMMON_DIR)/menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $@
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
menu%.h$(DEP): menu%.dbd
menu%.h$(DEP): menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $@
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
menu%.h$(DEP): ../menu%.dbd
menu%.h$(DEP): ../menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $@
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
@@ -261,7 +261,7 @@ menu%.h$(DEP): ../menu%.dbd
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
%.dbd$(DEP):
%.dbd$(DEP): $($*_DBD)
@$(RM) $@
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $($*_DBD) > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
@@ -330,32 +330,32 @@ $(INSTALL_DB)/%$(TEMPL_SUFFIX): ../%$(TEMPL_SUFFIX)
#---------------------------------------------------------------
# INC files
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%Record.h: %Record.dbd
$(COMMON_DIR)/%Record.h: %Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%Record.h: ../%Record.dbd
$(COMMON_DIR)/%Record.h: ../%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $(notdir $@)
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menu%.h: menu%.dbd
$(COMMON_DIR)/menu%.h: menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $(notdir $@)
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menu%.h: ../menu%.dbd
$(COMMON_DIR)/menu%.h: ../menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $(notdir $@)
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
@@ -366,6 +366,7 @@ $(COMMON_DIR)/menu%.h: ../menu%.dbd
# DBD files
$(COMMON_DIR)/bpt%.dbd: bpt%.data
$(ECHO) "Converting data from $<"
@$(RM) $(notdir $@)
$(MAKEBPT) $< $(notdir $@)
@$(MV) $(notdir $@) $@
@@ -399,7 +400,7 @@ $(COMMON_DBDCATS):$(COMMON_DIR)/%.dbd:
$(DBDCAT_COMMAND)
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.dbd:
$(COMMON_DIR)/%.dbd: $($*_DBD)
$(ECHO) "Creating dbd file $(notdir $@)"
@$(RM) $(notdir $@)
$(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $($*_DBD)
@@ -429,28 +430,28 @@ $(foreach file, $(DBD_INSTALLS), $(eval $(call DBD_INSTALLS_template, $(file))))
#---------------------------------------------------------------
# HTML files
$(COMMON_DIR)/%.html: %.dbd.pod
$(COMMON_DIR)/%.html: %.dbd.pod $(DBDTOHTML_pl)
@$(RM) $(notdir $@)
$(DBDTOHTML) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: %.pod
$(COMMON_DIR)/%.html: %.pod $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -s -s -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: %.pm
$(COMMON_DIR)/%.html: %.pm $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: ../%.pm
$(COMMON_DIR)/%.html: ../%.pm $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -s -o $(notdir $@) $<
@$(MKDIR) $(dir $@)
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: ../%.pl
$(COMMON_DIR)/%.html: ../%.pl $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -s -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
@@ -526,16 +527,19 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
#---------------------------------------------------------------
# register record,device,driver support
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd $(REGRECDEVDRV_dep)
@$(RM) $@
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
$< $(basename $@) $(IOCS_APPL_TOP)
%_registerRecordDeviceDriver.cpp: %.dbd
%_registerRecordDeviceDriver.cpp: %.dbd $(REGRECDEVDRV_dep)
@$(RM) $@
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
$< $(basename $@) $(IOCS_APPL_TOP)
%_registerRecordDeviceDriver.cpp: ../%.dbd
%_registerRecordDeviceDriver.cpp: ../%.dbd $(REGRECDEVDRV_dep)
@$(RM) $@
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
$< $(basename $@) $(IOCS_APPL_TOP)
.PRECIOUS: %_registerRecordDeviceDriver.cpp

View File

@@ -207,7 +207,7 @@ endif
checkRelease:
+$(CONVERTRELEASE) checkRelease
warnRelease:
$(CONVERTRELEASE) checkRelease
-$(CONVERTRELEASE) checkRelease
noCheckRelease:
ifeq ($(EPICS_HOST_ARCH),$(T_A))
$(info Warning: RELEASE file consistency checks have been disabled)
@@ -373,11 +373,11 @@ $(MODNAME): %$(MODEXT): %$(EXE)
# Automated testing
runtests: run-tap-tests
run-tap-tests: $(TESTSCRIPTS.t)
run-tap-tests: | build
ifneq ($(TESTSCRIPTS.t),)
ifdef RUNTESTS_ENABLED
$(ECHO) "$(PROVE) $^"
@$(PROVE) $^ || $(PROVE_FAILURE)
$(ECHO) "$(PROVE) $(TESTSCRIPTS.t)"
@$(PROVE) $(TESTSCRIPTS.t) || $(PROVE_FAILURE)
endif
endif
@@ -390,8 +390,8 @@ test-results: tap-results
tap-results: $(TAPFILES)
ifneq ($(strip $(TAPFILES)),)
ifdef RUNTESTS_ENABLED
$(ECHO) "$(PROVE.tap) $^"
@$(PROVE.tap) $^ || $(PROVE_FAILURE)
$(ECHO) "$(PROVE.tap) $(TAPFILES)"
@$(PROVE.tap) $(TAPFILES) || $(PROVE_FAILURE)
endif
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
@@ -407,7 +407,7 @@ ifneq ($(CURRENT_JUNITFILES),)
endif
# A .tap file is the output from running the associated test script
$(TAPFILES.t): %.tap: %.t
$(TAPFILES.t): %.tap: %.t | build
ifdef RUNTESTS_ENABLED
$(ECHO) "$(PERL) $< -tap > $@"
@$(PERL) $< -tap > $@ || $(TAPFILE_FAILURE)
@@ -532,11 +532,11 @@ endif # LOADABLE_SHRLIB_SUFFIX
ifneq ($(INSTALL_CONFIGS),)
$(INSTALL_CONFIG)/%: %
$(ECHO) "Installing config file $@"
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D))
$(INSTALL_CONFIG)/%: ../%
$(ECHO) "Installing config file $@"
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D))
endif
$(INSTALL_INCLUDE)/%: $(COMMON_DIR)/%

View File

@@ -27,7 +27,7 @@ $(foreach file,$(MAKEFILE_LIST), \
PRINT_Var = $(@:PRINT.%=%)
PRINT.%:
@echo $(PRINT_Var) = '$($(PRINT_Var))'
@+echo $(PRINT_Var) = '$($(PRINT_Var))'
.PHONY: PRINT PRINT.%

View File

@@ -47,7 +47,7 @@ vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
# INC += myVersion.h
# Default settings
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl $(QUIET_FLAG)
EXPANDARCH = -a $(T_A)
EXPANDFLAGS += -t $(INSTALL_LOCATION)
@@ -55,22 +55,17 @@ EXPANDFLAGS += $(addprefix -D ,$(EXPAND_VARS) $($@_EXPAND_VARS))
EXPANDFLAGS += $(foreach var, $(EXPAND_ME) $($@_EXPAND_ME), \
-D$(var)="$(strip $($(var)))")
# The names of files to be expanded must end with '@'
# Output files
EXPANDED = $(EXPAND:%@=%)
EXPANDED_COM = $(EXPAND_COMMON:%@=%)
EXPANDED_COMMON = $(EXPANDED_COM:%=$(COMMON_DIR)/%)
EXPANDED_COMMON = $(EXPAND_COMMON:%@=$(COMMON_DIR)/%)
$(EXPANDED): %: %@
$(ECHO) "Expanding $< to $@"
@$(RM) $@
$(EXPAND_TOOL) $(EXPANDARCH) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
$(EXPANDED_COM): %: %@
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %@
$(ECHO) "Expanding $< to $(COMMON_DIR)/$@"
@$(RM) $@
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %
@$(MV) $< $@
clean: expand_clean

View File

@@ -22,9 +22,11 @@
# 7. Submodules must have a configure/CONFIG_SITE file that contains
# -include $(TOP)/../CONFIG_SITE.local
# Add checked-out submodules to DIRS
LIVE_SUBMODULES = $(subst /Makefile,,$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
DIRS += $(LIVE_SUBMODULES)
# Add checked-out submodules to DIRS, unless INSTALL_LOCATION is empty
LIVE_SUBMODULES = $(subst /Makefile,, \
$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
live = $(if $(wildcard $(INSTALL_CONFIG)/RULES_TOP),LIVE,DEAD)
DIRS += $($(live)_SUBMODULES)
include $(CONFIG)/RULES_DIRS
@@ -37,14 +39,13 @@ all host $(DIRS) $(ARCHS) $(ACTIONS) $(dirActionTargets) $(dirArchTargets) \
# Convenience target
RELEASE.host: $(RELEASE_LOCAL)
$(RELEASE_LOCAL): Makefile CONFIG_SITE.local
$(RELEASE_LOCAL): Makefile $(CONFIG)/CONFIG_SITE \
$(wildcard $(CONFIG)/CONFIG_SITE.local)
$(ECHO) Creating $@ with
$(ECHO) " $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)"
@echo $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)> $@
realclean:
$(RM) $(wildcard RELEASE.*.local)
.PHONY: RELEASE.host realclean
.PHONY: RELEASE.host
# Testing: Combine test failure logs from the live submodules
TESTS_FAILED_LOGS = $(wildcard $(addsuffix /$(TESTS_FAILED_LOG), \

View File

@@ -23,35 +23,42 @@ ifndef DISABLE_TOP_RULES
# Rules for a regular application top directory
#
distclean: realclean cvsclean realuninstall
# When run by 'make distclean' the realuninstall target also
# removes any modules/RELEASE.<host>.local files
distclean: realclean cvsclean realuninstall
realuninstall: uninstallDirs
realuninstall: uninstallDirs
$(RMDIR) $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB)
ifeq (modules,$(filter modules,$(DIRS)))
ifeq (distclean,$(filter distclean,$(MAKECMDGOALS)))
$(RM) $(wildcard modules/RELEASE.*.local)
endif
endif
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
uninstallDirs: | clean
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
uninstallDirs:
$(RMDIR) $(UNINSTALL_DIRS)
# Remove the bin and lib directories if they have no sub-directories
#
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs | clean
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs
$(RMDIR) $(EMPTY_INSTALL_DIRS)
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
uninstall$(DIVIDER)%: | clean
uninstall$(DIVIDER)%:
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))
# Only run this at the top of the parent
runtests test-results:
# Only run this at the top of the parent
runtests test-results:
@$(SHOWTESTFAILURES)
else
@@ -76,7 +83,6 @@ help:
@echo " inc - Installs header, dbd and html files"
@echo " build - Builds and installs all targets"
@echo " install - Builds and installs all targets"
@echo " buildInstall - Same as install (deprecated)"
@echo " clean - Removes the O.<arch> dirs created by running make"
@echo " In O.<arch> dir, clean removes build created files"
@echo " realclean - Removes ALL O.<arch> dirs"
@@ -101,7 +107,8 @@ ifndef DISABLE_TOP_RULES
@echo " uninstall$(DIVIDER)<arch> - Remove bin & lib directories for <arch> only."
@echo " uninstall - Remove install directories created by this hostarch."
@echo " realuninstall - Removes ALL install dirs"
@echo " distclean - Same as realclean cvsclean realuninstall."
@echo " distclean - Does realclean cvsclean realuninstall and deletes any"
@echo " generated modules/RELEASE.<host>.local files"
endif
@echo " help - Prints this list of valid make targets "
@echo "Object targets are supported by the O.<arch> level Makefile .e.g"

View File

@@ -77,7 +77,7 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
ECHO = @$(if $(make-s),$(NOP),echo)
# Originally set in os/CONFIG.UnixCommon.Common
MKDIR = mkdir -p

View File

@@ -11,14 +11,15 @@ MUNCH_SUFFIX = .boot
define MUNCH_CMD
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
gzip -f9 rtems
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@ \
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@.elf \
$(PROJECT_RELEASE)/lib/bootloader.o \
--just-symbols=$< \
-b binary rtems.gz \
--no-warn-mismatch \
--no-warn-mismatch \
-T $(PROJECT_RELEASE)/lib/ppcboot.lds \
-Map $<.map
rm -f rtems.gz
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $@.elf $@
rm -f rtems.gz $@.elf
endef
include $(CONFIG)/os/CONFIG.Common.RTEMS

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

@@ -7,6 +7,10 @@
# Include definitions common to all Unix targets
include $(CONFIG)/os/CONFIG.Common.UnixCommon
GNU = NO
CMPLR_CLASS = clang
CC = clang
CCC = clang++
OS_CLASS = freebsd

View File

@@ -0,0 +1,21 @@
# CONFIG.Common.vxWorks-e500v2
#
# Definitions for vxWorks-e500v2 target archs (MVME2500)
# Sites may override these definitions in CONFIG_SITE.Common.vxWorks-e500v2
#-------------------------------------------------------
# Include definitions common to all vxWorks target archs
include $(CONFIG)/os/CONFIG.Common.vxWorksCommon
# Vx GNU cross compiler suffix
CMPLR_SUFFIX = ppc
ARCH_CLASS = ppc
# Architecture specific build flags
ARCH_DEP_CFLAGS += -te500v2 -mhard-float
ARCH_DEP_CPPFLAGS += -DCPU=PPC85XX
ARCH_DEP_CFLAGS += -DCPU_VARIANT=_ppc85XX_e500v2
ARCH_DEP_CFLAGS += -mlongcall
GNU_TARGET = powerpc-wrs-vxworks

View File

@@ -12,7 +12,7 @@ ARCH_CLASS = x86
POSIX = NO
# Definitions used when COMMANDLINE_LIBRARY is READLINE
LDLIBS_READLINE = -lreadline -lcurses
LDLIBS_READLINE = -lreadline -ltermcap
ARCH_DEP_CFLAGS += -m32
ARCH_DEP_LDFLAGS += -m32

View File

@@ -66,7 +66,7 @@ GNU = NO
#
# Darwin shared libraries
#
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined dynamic_lookup \
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace \
-install_name $(abspath $(INSTALL_LIB))/$@ \
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
$(addprefix -current_version , $(SHRLIB_VERSION))

View File

@@ -5,3 +5,4 @@
#Include definitions common to unix hosts
include $(CONFIG)/os/CONFIG.UnixCommon.Common
CMPLR_CLASS = clang

View File

@@ -2,6 +2,7 @@
# Definitions for freebsd-x86 host - freebsd-x86 target builds
# Sites may override these definitions in CONFIG_SITE.freebsd-x86.freebsd-x86
#-------------------------------------------------------
GNU_DIR=/usr/local
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon

View File

@@ -2,6 +2,7 @@
# Definitions for freebsd-x86_64 host - freebsd-x86_64 target builds
# Sites may override these definitions in CONFIG_SITE.freebsd-x86_64.freebsd-x86_64
#-------------------------------------------------------
GNU_DIR=/usr/local
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon

View File

@@ -6,3 +6,8 @@
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon
STATIC_LDFLAGS_YES= -Wl,-Bstatic
STATIC_LDFLAGS_NO=
STATIC_LDLIBS_YES= -Wl,-Bdynamic
STATIC_LDLIBS_NO=

View File

@@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
GNU_LDLIBS_YES =
# Link with system libraries
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp

View File

@@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
GNU_LDLIBS_YES =
# Link with system libraries
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp

View File

@@ -34,5 +34,6 @@
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 instead.
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 or for
# cross-builds in CONFIG_SITE.<host-arch>.linux-aarch64 instead.

View File

@@ -15,11 +15,6 @@
# to inform the system of the shared library location.
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \
READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -12,10 +12,6 @@
GNU_DIR = /usr/local/vw/microblaze-2.0/microblazeel-unknown-linux-gnu
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -15,10 +15,6 @@
# to inform the system of the shared library location.
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -15,10 +15,6 @@
# to inform the system of the shared library location.
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -3,11 +3,6 @@
# Site-specific settings for the linux-xscale_be target
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \
READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -3,21 +3,27 @@
# Site specific definitions for darwin builds
#-------------------------------------------------------
# Note the dir/firstword/wildcard functions below are used
# to avoid warnings about missing directories.
# These settings are designed for users of Homebrew.
# Users of other third-party package managers are welcome to
# provide patches appropriate for their manager.
ifneq (,$(wildcard /opt/homebrew))
# Default location on aarch64
HOMEBREW_DIR = /opt/homebrew
else ifneq (,$(wildcard /usr/local/Homebrew))
# Default location on x86_64
HOMEBREW_DIR = /usr/local
else ifneq (,$(wildcard /opt/local/include/readline))
# MacPorts
READLINE_DIR = /opt/local
endif
# Mix-and-match of different package systems is probably not advisable,
# but you can try that if you like...
# Uncomment these definitions when using Homebrew packages:
#OP_SYS_INCLUDES += -I/usr/local/include
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /usr/local/lib/*))))
# Uncomment these definitions when using DarwinPorts packages:
#OP_SYS_INCLUDES += -I/opt/local/include
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /opt/local/lib/*))))
# Uncomment these definitions when using Fink packages:
#OP_SYS_INCLUDES += -I/sw/include
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /sw/lib/*))))
# Look for Homebrew's readline
ifneq (,$(wildcard $(HOMEBREW_DIR)/opt/readline))
READLINE_DIR = $(HOMEBREW_DIR)/opt/readline
endif
# Use GNU readline if it's avaiilable
ifneq (,$(wildcard $(READLINE_DIR)/include/readline/readline.h))
INCLUDES_READLINE = -I$(READLINE_DIR)/include
LDFLAGS_READLINE = -L$(READLINE_DIR)/lib
endif

View File

@@ -1,6 +1,6 @@
# CONFIG_SITE.linux-x86.linux-aarch64
# CONFIG_SITE.linux-x86_64.linux-aarch64
#
# Site specific definitions for linux-x86 host - linux-aarch64 target builds
# Site specific definitions for linux-x86_64 host - linux-aarch64 target builds
#-------------------------------------------------------
# Set GNU crosscompiler target name

View File

@@ -35,3 +35,20 @@ OS_API = posix
OS_API = score
# endif
#endif
#ifdef __has_include
# if defined(__rtems__) && __RTEMS_MAJOR__<5 && __has_include(<libtecla.h>)
COMMANDLINE_LIBRARY ?= LIBTECLA
# elif __has_include(<readline/readline.h>)
COMMANDLINE_LIBRARY ?= READLINE
# else
COMMANDLINE_LIBRARY ?= EPICS
# endif
#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

View File

@@ -0,0 +1,170 @@
=head1 EPICS Component Reference Manual
This document provides reference information about the record types,
menus, link types and channel filters included with EPICS Base.
Many details about the record and menu definitions are derived automatically
from the source code at build time.
=head2 Introduction and IOC Concepts
These links point to an external website where introductory and overview
documentation is now being published.
=over
=item * L<Introduction to EPICS|https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html>
=item * L<Process Database Concepts|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html>
=back
=head2 Record Type Definitions
These sections describe common aspects of the record types:
=over
=item * L<Fields Common to All Record Types|dbCommonRecord>
=item * L<Fields Common to Input Record Types|dbCommonInput>
=item * L<Fields Common to Output Record Types|dbCommonOutput>
=back
These are the record types supplied with EPICS Base:
=over
=item * L<Analog Array Input Record (aai)|aaiRecord>
=item * L<Analog Array Output Record (aao)|aaoRecord>
=item * L<Analog Input Record (ai)|aiRecord>
=item * L<Analog Output Record (ao)|aoRecord>
=item * L<Array Subroutine Record (aSub)|aSubRecord>
=item * L<Binary Input Record (bi)|biRecord>
=item * L<Binary Output Record (bo)|boRecord>
=item * L<Calculation Output Record (calcout)|calcoutRecord>
=item * L<Calculation Record (calc)|calcRecord>
=item * L<Compression Record (compress)|compressRecord>
=item * L<Data Fanout Record (dfanout)|dfanoutRecord>
=item * L<Event Record (event)|eventRecord>
=item * L<Fanout Record (fanout)|fanoutRecord>
=item * L<Histogram Record (histogram)|histogramRecord>
=item * L<64-bit Integer Input Record (int64in)|int64inRecord>
=item * L<64-bit Integer Output Record (int64out)|int64outRecord>
=item * L<Long Input Record (longin)|longinRecord>
=item * L<Long Output Record (longout)|longoutRecord>
=item * L<Long String Input Record (lsi)|lsiRecord>
=item * L<Long String Output Record (lso)|lsoRecord>
=item * L<Multi-Bit Binary Input Direct Record (mbbiDirect)|mbbiDirectRecord>
=item * L<Multi-Bit Binary Input Record (mbbi)|mbbiRecord>
=item * L<Multi-Bit Binary Output Direct Record (mbboDirect)|mbboDirectRecord>
=item * L<Multi-Bit Binary Output Record (mbbo)|mbboRecord>
=item * L<Permissive Record (permissive)|permissiveRecord>
=item * L<Printf Record (printf)|printfRecord>
=item * L<Select Record (sel)|selRecord>
=item * L<Sequence Record (seq)|seqRecord>
=item * L<State Record (state)|stateRecord>
=item * L<String Input Record (stringin)|stringinRecord>
=item * L<String Output Record (stringout)|stringoutRecord>
=item * L<Sub-Array Record (subArray)|subArrayRecord>
=item * L<Subroutine Record (sub)|subRecord>
=item * L<Waveform Record (waveform)|waveformRecord>
=back
=head2 Menu Definitions
Menu field choices are documented with the record type that defines them, or
here for the global menus that are used by multiple record types:
=over
=item * L<Alarm Severity Menu|menuAlarmSevr>
=item * L<Alarm Status Menu|menuAlarmStat>
=item * L<Analog Conversions Menu|menuConvert>
=item * L<Field Type Menu|menuFtype>
=item * L<Invalid Value Output Action Menu|menuIvoa>
=item * L<Output Mode Select Menu|menuOmsl>
=item * L<Process at iocInit Menu|menuPini>
=item * L<Post Monitors Menu|menuPost>
=item * L<Priority Menu|menuPriority>
=item * L<Scan Menu|menuScan>
=item * L<Simulation Mode Menu|menuSimm>
=item * L<YesE<sol>No Menu|menuYesNo>
=back
=head2 Other Components
EPICS Base also comes with extensible sets of server Channel Filters and IOC
Database Link types, which are documented here:
=over
=item * L<Channel Filters|filters>
=item * L<IOC Database Link Types|links>
=back
=head2 Corrections and Updates
Corrections to these documents can be submitted as patch files to the EPICS
core developers, or as GitHub pull requests to the 7.0 branch of Base.
These document sources can be found under `modules/database/src` tree, mostly
in the `std/rec` and `ioc/db` directories in files with extension `.dbd.pod`.
The documentation source format is a combination of the EPICS DBD file format
with an extended version of Perl's POD (plain old documentation); run `perldoc
pod` for details of POD.

View File

@@ -762,7 +762,6 @@ WARN_LOGFILE =
INPUT = ../mainpage.dox \
../RELEASE_NOTES.md \
../README.md \
../RecordReference.md \
@TOP@/include
# This tag can be used to specify the character encoding of the source files

View File

@@ -1,24 +1,24 @@
TOP = ..
include $(TOP)/configure/CONFIG
ifeq ($(T_A),$(EPICS_HOST_ARCH))
DOXYGEN=doxygen
EXPAND = Doxyfile@
EXPAND_ME += EPICS_VERSION
EXPAND_ME += EPICS_REVISION
EXPAND_ME += EPICS_MODIFICATION
EXPAND_ME += EPICS_PATCH_LEVEL
EXPAND_ME += OS_CLASS CMPLR_CLASS
HTMLS += ComponentReference.html
TARGETS += doxygen
DOXYGEN = doxygen
ME = documentation/O.$(T_A)/html
GH_FILES = $(ME)/ $(ME)/.nojekyll $(ME)/*.* $(ME)/*/*.*
install: doxygen
include $(TOP)/configure/RULES
doxygen: Doxyfile ../mainpage.dox
doxygen: Doxyfile ../mainpage.dox $(INSTALL_HTMLS)
$(DOXYGEN)
rsync -av $(TOP)/html/ html/
@@ -29,7 +29,3 @@ commit: doxygen
(cd $(TOP) && $(CURDIR)/../commit-gh.sh $(GH_FILES))
.PHONY: commit
endif # EPICS_HOST_ARCH
include $(TOP)/configure/RULES

View File

@@ -387,7 +387,7 @@ install directories.
EPICS executables and perl scripts are installed into the
`$(INSTALL_LOCATION)/bin/<arch>` directories. Libraries are installed
into $`(INSTALL_LOCATION)/lib/<arch>`. The default definition for
into `$(INSTALL_LOCATION)/lib/<arch>`. The default definition for
`$(INSTALL_LOCATION)` is `$(TOP)` which is the root directory in the
distribution directory structure, `base`. Intermediate object files
are stored in `O.<arch>` source subdirectories during the build

View File

@@ -2,19 +2,476 @@
These release notes describe changes that have been made since the previous
release of this series of EPICS Base. **Note that changes which were merged up
from commits to the 3.15 branch are not described at the top of this file but
lower down, 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.
from commits to the 3.15 branch are described
[further down this file](#changes-incorporated-from-the-315-branch)
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.
should also be read to understand what has changed since earlier releases:
**This version of EPICS has not been released yet.**
- [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)
## Changes made on the 7.0 branch since 7.0.6.1
## EPICS Release 7.0.8.1
<!-- Insert new items immediately below here ... -->
### Limit to `_FORTIFY_SOURCE=2`
GCC versions 12 and beyond and glibc have added some aggressive runtime
checks for buffer overflows in libc functions at runtime, and the
[Ubuntu 2024.04](https://wiki.ubuntu.com/ToolChain/CompilerFlags) release
increased their default gcc fortification level from 2 to 3.
This has started causing EPICS Base builds to fail on that version, and
other OS releases may make that configuration change with similar results.
This release detects a compiler configured with `_FORTIFY_SOURCE=3` and
overrides it to 2.
Later releases of Base will adjust the code, providing information to the
compiler to avoid triggering these incorrect protections.
### Fix issue with compress record
In Base 7.0.8, an update to the compress record was added to allow for certain
algorithms to use partially filled buffers in their computations. Unfortunately,
this broke the behaviour of the records in certain cases. This has been fixed.
### Various minor changes
These included fixing minor memory leaks and documentation corrections. The
`SIZV` field of lsi, lso and printf record VAL fields now can't exceed 32767
characters, to match an internal limit.
### `epicsSocketAccept()` now returns `SOCKET`, not `int`
This might have some effect on downstream modules still using `int`, but the
OS-specific osdSock.h headers which osiSock.h includes have all declared
`SOCKET` (in most casese as a typedef for `int`) for many releases.
This change removes a compiler warning on WIN32.
Further details and the discussion about this change can be found
[here](https://github.com/epics-base/epics-base/pull/458).
### `dbLoadRecords` allows macros with default values
Previously the parser assumed that files containing macro substitutions were
bad if no macro definitions were provided; that assumption was made incorrect
once macro substitutions were allowed to provide a default value.
### Hostname length limit in CA removed
Before this release, the CA client library only handled hostnames in address
list environment variables up to 255 characters long.
This limit has been removed.
-----
## EPICS Release 7.0.8
### bi "Raw Soft Channel" use MASK
If MASK is non-zero, The raw device support will now apply MASK to the
value read into RVAL.
eg. allows extraction of a bit from an input integer.
```
record(longin, "integer") {
field(VAL, "0xff")
}
record(bi, "bit1") {
field(DESC, "extract bit 1")
field(DTYP, "Raw Soft Channel")
field(INP , "integer")
field(MASK, "0x2")
field(ZNAM, "Clear")
field(ONAM, "Set")
}
```
### ANSI escapes in stderr
ANSI escape charactor sequences may now be printed to the stderr stream.
These escapes will appear in logs captured from that stream.
Tools which parse and/or render these logs may need to be adjusted to
either strip out the escapes, or to translate them into markup.
(see [ansi2html](https://pypi.org/project/ansi2html/) for example)
### Allow explicit append with `dbRecordsOnceOnly!=0`
Previously setting `dbRecordsOnceOnly!=0` prevented any further changes to a record via a .db file. eg.
```
record(ai, "myrec") {}
```
`dbRecordsOnceOnly!=0` previously disallowed appending fields with either form:
```
record("*", "myrec") {} # error
record(ai, "myrec") {} # error
```
Beginning with this release, `dbRecordsOnceOnly!=0` allows appending when explicitly intended (when record type is `"*"`).
```
record("*", "myrec") {} # allowed
record(ai, "myrec") {} # error
```
### Add `$EPICS_CLI_TIMEOUT`
Add support for CA tools timeout from environment variable `$EPICS_CLI_TIMEOUT`
which sets the default the default timeout for `caget` et al.
The `-w` argument continues to take precedence.
### Fixed leak from a non-EPICS thread on WIN32
On Windows targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated. Prior to this release the allocation would not be `free()`d,
resulting in a memory leak.
A similar issue on POSIX targets was previously fixed.
### Change compiler for FreeBSD to clang
The default compiler for FreeBSD targets changes from GCC to clang.
### Expose `dbCreateAlias` in IOC shell
Add a new IOC shell command `dbCreateAlias` allow record aliases to be added.
Intended for use before `iocInit`. eg. to add an alias "bar" for a record "foo".
```
dbLoadRecords("some.db") # includes: record(ai, "foo") { ...
dbCreateAlias("foo", "bar")
iocInit()
```
### dbEvent eventsRemaining missed on cancel
In some cases, RSRV may queue a subscription update, but not flush it.
This partially addresses this issue.
### subRecord on bad INP links
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
Fall back to the previous behavior when searching for `readline.h` with older compilers.
### Search for readline installed via HomeBrew.
Look for `/opt/local/include/readline` on OSX.
### Always stop worker threads
The SCAN and callback threads are now stopped during normal IOC shutdown.
### Allow runtime bypass of free list allocator
The environment variable `$EPICS_FREELIST_BYPASS` may be set to `YES` to cause the `freeListLib` functions to always call directly to `malloc()`/`free()`. May be useful when troubleshooting some kinds of memory allocation bugs which would otherwise be "hidden". eg. use-after-free data races. This may also improve the results of dynamic analysis tools which are not aware of this internal free list.
### `compress` record enhancement
The compress record now supports the use of partially-filled buffers when using
any of the N-to-one algorithms. This is achieved by setting the new field `PBUF`
to `YES`.
### Extended timestamp channel filter
The `"ts"` filter can now retrieve the record's timestamp in several numeric
and string formats, some of which support full nanosecond precision.
Hal$ caget -a test:channel
test:channel 2021-03-11 18:23:48.265386 42
Hal$ caget -f9 'test:channel.{"ts": {"num": "dbl"}}'
test:channel.{"ts": {"num": "dbl"}} 984331428.265386105
Hal$ caget 'test:channel.{"ts": {"str": "iso"}}'
test:channel.{"ts": {"str": "iso"}} 2021-03-11T18:23:48.265386+0100
Hal$ caget -f1 'test:channel.{"ts": {"num": "ts"}}'
test:channel.{"ts": {"num": "ts"}} 2 984331428.0 265386163.0
More information is included in the filters documentation, which can be found in
the `html/filters.html` document that is generated during the build
### Allow adding new error symbols at any time
`errSymbolAdd` can now be called after early initialization.
### Add conditional output (OOPT) to the longout record
The longout record can now be configured using its new OOPT and OOCH fields
to (not) write to its output link depending on the contents of VAL, in a
similar manner to the calcout record. More information can be found on the
reference page for the longout record type that accompanies this release.
This functionality was suggested in
[lp# 1398215](https://bugs.launchpad.net/epics-base/+bug/1398215) and may
be added to other output record types if the community finds it useful,
please send feedback about the feature to tech-talk.
### 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
of the built-in commands. For example, the record name argument of `dbpr`,
and the path name argument of `cd`.
Externally defined commands have a limited ability to opt into completion by
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
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
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
expression engine and is available to all software using that (calc and calcout
record types, access security library and some extensions).
-----
## EPICS Release 7.0.7
### Doxygen Annotations
Thanks to several attendees at the 2022 EPICS Codeathon the number of header
files with Doxygen annotations in the EPICS Core has again increased.
### Build System updates
The top-level make targets `uninstall`, `archuninstall` and similar no
longer trigger the `clean` target which empties build directories, this
was a bug introduced in 7.0.5.
The `make distclean` target now properly deletes the generated file(s)
`modules/RELEASE.<host>.local` which are essential to build the external
submodules under the `modules` directory, and should not crash if the
build is configured with `INSTALL_LOCATION` pointing to an empty external directory (i.e. if you run `make distclean` twice in succession). When
`INSTALL_LOCATION` is set in the files `configure/CONFIG_SITE` or
`configure/CONFIG_SITE.local` the `modules/RELEASE.<host>.local` file
will now be regenerated in case the install path has been modified.
Note that passing `INSTALL_LOCATION=<path>` on the make command-line will
only work if you have run `make distclean` immediately beforehand, as the
`modules/RELEASE.<host>.local` file must be recreated using the new path.
### Enhancements to `capr.pl`
The `capr.pl` script can now display records from older Base versions to
which fields have since been added, and shows long strings and array data
up to 10 elements, use the new `-n` option to increase that number.
The script is fully event-driven and prints all the field data received by
the end of the CA wait time (`-w` option which defaults to 2 seconds).
The interest level can now be specified using the `-l` option before the
PV name, and the new `-D` flag outputs debugging information.
### Time Synchronization on VxWorks
VxWorks 6.9 can do its own OS clock time synchronization, if it has been
configured by setting `SNTPC_PRIMARY_IPV4_ADDR`. Since EPICS 3.15.3 the
IOC time support code has checked for the existence of the VxWorks time
synchronization task and avoided starting the EPICS one if the OS task
exists and the OS clock gives a "recent" time (i.e. after when EPICS was
compiled), unless the environment variable `EPICS_TS_FORCE_NTPTIME` is
also set. However a logic error in that code required the environment
variable to be set in more cases than it should have.
This error has been fixed and the IOC should work normally if the VxWorks
task is configured and running. The `TIMEZONE` value for the year is also
now calculated at initialization in this configuration, previously it was
only done when the IOC synchronzation task was used. Setting the above
environment variable will now cause the IOC support code to shut down the
VxWorks synchronization thread (if running) before starting the EPICS one.
Running the iocsh command `ClockTime_Report` now shows whether the VxWorks
task is running as well as giving the state of the IOC synchronization task.
The `ClockTime_Init` command can also be used to stop or restart the IOC
time synchronization task while the IOC is running, depending on the `0` or
`1` parameter passed to it. This last change also applies to RTEMS IOCs.
### Incompatible change to `struct db_field_log`
This change may cause channel filters which manipulate array updates
to fail to compile.
To avoid potential speculation issues arising from overlapping code pointers
with data values, `union dbfl_ref` is modified to remove the `dtor` member.
`dtor` is moved out into the enclosing `struct db_field_log`.
So eg. using a `db_field_log* p`, the expression `p->u.r.dtor` must be
changed to `(p)->dtor`.
### Fix undef ts on first camonitor update of NORD from waveformRecord
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
When built with a compiler supporting `__has_include<>`, the presence
of the `<readline/readline.h>` will be used to automatically determine
a default value for `COMMANDLINE_LIBRARY`.
Mingw builds with readline support now link `-ltermcap` instead of `-lcurses`.
This should not effect sites which set explicitly set `COMMANDLINE_LIBRARY`
as the only definition in Base now has the form `COMMANDLINE_LIBRARY ?= ...`.
### Perl CA support for empty long strings
The Perl CA bindings have been fixed to handle zero-length long string data
properly.
### `aao` gains `OMSL` and `DOL`
The `aao` record types gains the same `DOL` functionality found
in other output record types (`ao`, `longout`, etc.)
### Server exports `RSRV_SERVER_PORT`
During `iocInit()`, the environment variable `RSRV_SERVER_PORT` is set
with the TCP port number selected.
### `dbdExpand.pl` sorts all items by name
DBD files generated by the `dbdExpand.pl` script are now sorted within each
item type by the primary name of the item. The result should resolve any
issues with reproducable builds. No option is provided to prevent the sorting,
previously the order was essentially random and varied each time.
### `dbExpand.pl` sorts records by name
Records are now output by this program in order, sorted by name. The new flag
`-s` can be given to output the records in the same order they were read in,
instead of sorting them.
Note that there are currently no build rules provided with Base which make use
of this program.
### Simulation Mode RAW Support for Output Record Types
SIMM=RAW support has been added for the relevant output record types
(ao, bo, mbbo, mbboDirect).
RAW simulation mode will have those records do the appropriate conversion
and write RVAL to the location pointed to by SIOL.
### Fixed leak from a non-EPICS thread
On some targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated.
Prior to this release, on POSIX and WIN32 targets, this
struct would not be `free()`d, resulting in a memory leak.
This release fixed the leak on POSIX targets.
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
for WIN32 status.
### Fixed leak from a non-EPICS thread
On some targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated.
Prior to this release, on POSIX and WIN32 targets, this
allocation would not be `free()`d, resulting in a memory leak.
This release fixed the leak on POSIX and WIN32 targets (excluding
MSVC before vs2012, and the WINE runtime).
### Fixed leak from a non-EPICS thread
On some targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated.
Prior to this release, on POSIX and WIN32 targets, this
struct would not be `free()`d, resulting in a memory leak.
This release fixed the leak on POSIX targets.
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
for WIN32 status.
### Fix `CHECK_RELEASE = WARN`
This now works again, it was broken in 2019 (7.0.3.1) by an errant commit.
### Document `DISP` as design-time field
The DISP field can be set to a non-zero value to prevent records being changed
from outside the IOC (this is ancient behavior), but has never been documented
as being usable at design-time (DCT=Yes in the Record Reference tables). This
has now been changed.
### Make `epicsInt8` signed on all architectures
The `epicsInt8` and thus `DBF_CHAR` types have always been unsigned on
architectures where `char` is unsigned, for example on many PowerPC CPU
architectures. This was counter-intuitive, and resulted in IOC behavior
differing between architectures when converting `DBF_CHAR` values into a
signed integer or floating point type.
**WARNING**: This fix may change behavior of existing databases on target
architectures with unsigned `char` (mainly PowerPC) when using input links to
read from `CHAR` arrays. Architectures with signed `char` (usually x86) should
be unaffected, although some compilers might generate new warnings.
### Allow hexadecimal and octal numbers in hardware links
[GH:213](https://github.com/epics-base/epics-base/pull/213)
Several types of hardware links (`VME_IO`, `CAMAC_IO`, etc) now accept
hexadecimal and octal numbers. (Hexadecimal numbers had already been valid
up to EPICS R3.15.) This change may introduce incompatibilities when using
numbers with leading `0` as they will now be parsed as octal.
### Fix embedded implementations of `epicsEvent`
[GH:202](https://github.com/epics-base/epics-base/issues/202) and
[GH:206](https://github.com/epics-base/epics-base/pull/206)
Heinz Junkes provided a new implementation of the `epicsEvent` API suitable for
RTEMS Posix targets (RTEMS 5.1 and later). In review a few issues related to
overflow of timeout values surfaced in this and other embedded implementations,
and these were also been fixed in this Pull Request. The API documentation for
this and some other routines has also been updated.
### Breakpoint Table Names
The names of breakpoint tables were made unnecessarily strict when DBD file
processing was moved to Perl for the 3.15 release series. Table names may now
contain the special characters `_` `-` `:` `;` `.` `[` `]` `<` `>` in addition
to letters and digits.
### Fix for `undefined` in configure/RELEASE files
@@ -67,7 +524,7 @@ monitors posted on the bit fields.
Some scripts now make use of features that were introduced to this Perl version
that was released in 2009.
### DB Links to DBF_MENU fields fixed
### DB Links to `DBF_MENU` fields fixed
[GH:183](https://github.com/epics-base/epics-base/issues/183)
These were broken in a previous release, but now work again.
@@ -409,10 +866,10 @@ broken.
This fixes [lauchpad bug #1896295](https://bugs.launchpad.net/bugs/1896295).
### Support for Apple M1 (arm64) Processors
### Support for Apple M1/M2 (arm64) Processors
Thanks to Jeong Han Lee this release comes with build support for Apple's new
M1 CPUs running macOS, using the target name `darwin-aarch64`.
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
It should also be possible to build universal binaries containing code for
both the Intel and arm64 processors under either target name: In the
@@ -1428,7 +1885,7 @@ editing and history. This functionality has now been restored, see Launchpad
### Constant link types
Constant links can now hold 64-bit integer values, either as scalars or
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
doesn't allow for hexadecimal numbers.
### Upgraded the YAJL JSON Library
@@ -2026,6 +2483,17 @@ header and removed the need for dbScan.c to reach into the internals of its
## Changes from the 3.15 branch since 3.15.9
### Support for Apple M1/M2 (arm64) Processors
Thanks to Jeong Han Lee this release comes with build support for Apple's new
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
### Set thread names on Windows
On MS Windows, epicsThread names are made available to the OS and debugger
using `SetThreadDescription()` if available as well as using the older
exception mechanism.
### Fix timers on MS Windows for non-EPICS threads
The waitable timer changes in 3.15.9 broke calls to `epicsThreadSleep()` and

View File

@@ -1,74 +0,0 @@
# Record Reference Documentation {#recordrefmanual}
The documentation below for the record types and menus included with Base was
converted from the old EPICS Wiki pages and updated. This list only includes the
record types supplied with Base. The first two links below are to an external
website where these original reference chapters are now being published.
* [Introduction to EPICS](https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html)
* [Process Database Concepts](https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html)
* [Fields Common to All Record Types](dbCommonRecord.html)
* [Fields Common to Input Record Types](dbCommonInput.html)
* [Fields Common to Output Record Types](dbCommonOutput.html)
## Record Types
* [Analog Array Input Record (aai)](aaiRecord.html)
* [Analog Array Output Record (aao)](aaoRecord.html)
* [Analog Input Record (ai)](aiRecord.html)
* [Analog Output Record (ao)](aoRecord.html)
* [Array Subroutine Record (aSub)](aSubRecord.html)
* [Binary Input Record (bi)](biRecord.html)
* [Binary Output Record (bo)](boRecord.html)
* [Calculation Output Record (calcout)](calcoutRecord.html)
* [Calculation Record (calc)](calcRecord.html)
* [Compression Record (compress)](compressRecord.html)
* [Data Fanout Record (dfanout)](dfanoutRecord.html)
* [Event Record (event)](eventRecord.html)
* [Fanout Record (fanout)](fanoutRecord.html)
* [Histogram Record (histogram)](histogramRecord.html)
* [64bit Integer Input Record (int64in)](int64inRecord.html)
* [64bit Integer Output Record (int64out)](int64outRecord.html)
* [Long Input Record (longin)](longinRecord.html)
* [Long Output Record (longout)](longoutRecord.html)
* [Long String Input Record (lsi)](lsiRecord.html)
* [Long String Output Record (lso)](lsoRecord.html)
* [Multi-Bit Binary Input Direct Record (mbbiDirect)](mbbiDirectRecord.html)
* [Multi-Bit Binary Input Record (mbbi)](mbbiRecord.html)
* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html)
* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html)
* [Permissive Record (permissive)](permissiveRecord.html)
* [Printf Record (printf)](printfRecord.html)
* [Select Record (sel)](selRecord.html)
* [Sequence Record (seq)](seqRecord.html)
* [State Record (state)](stateRecord.html)
* [String Input Record (stringin)](stringinRecord.html)
* [String Output Record (stringout)](stringoutRecord.html)
* [Sub-Array Record (subArray)](subArrayRecord.html)
* [Subroutine Record (sub)](subRecord.html)
* [Waveform Record (waveform)](waveformRecord.html)
## Menu Definitions
* [Alarm Severity Menu](menuAlarmSevr.html)
* [Alarm Status Menu](menuAlarmStat.html)
* [Analog Conversions Menu](menuConvert.html)
* [Field Type Menu](menuFtype.html)
* [Invalid Value Output Action Menu](menuIvoa.html)
* [Output Mode Select Menu](menuOmsl.html)
* [Process at iocInit Menu](menuPini.html)
* [Post Monitors Menu](menuPost.html)
* [Priority Menu](menuPriority.html)
* [Scan Menu](menuScan.html)
* [Simulation Mode Menu](menuSimm.html)
* [Yes/No Menu](menuYesNo.html)
## Corrections and Updates
Corrections to these documents can be submitted as patch files to the EPICS core
developers, or as merge requests or pull requests to the 7.0 branch of Base.
The document sources can be found in the `modules/database/src/std/rec` and
`modules/database/src/ioc/db` directories in files with extension `.dbd.pod`.
The documentation source format is a combination of the EPICS DBD file format
with an extended version of Perl's POD (plain old documentation); run `perldoc
pod` for details of POD.

View File

@@ -48,14 +48,14 @@ everything that has to be done since it's so easy to miss steps.</p>
<p>The following roles are used below:</p>
<dl>
<dt><strong>Release Manager</strong> ()</dt>
<dt><strong>Release Manager</strong></dt>
<dd>Responsible for managing and tagging the release</dd>
<dt><strong>Platform Developers</strong> (informal)</dt>
<dd>Responsible for individual operating system platforms</dd>
<dt><strong>Core Developers</strong></dt>
<dd>Responsible for maintaining the EPICS software</dd>
<dt><strong>Application Developers</strong></dt>
<dd>Responsible for support modules that depend on EPICS Base.</dd>
<dt><strong>Website Editor</strong> (Andrew Johnson)</dt>
<dd>Responsible for the EPICS website</dd>
<dt><strong>Website Editors</strong></dt>
<dd>Responsible for the EPICS websites</dd>
</dl>
<form>
@@ -72,23 +72,22 @@ everything that has to be done since it's so easy to miss steps.</p>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Email all developers about the upcoming release and ask for a list
of remaining tasks that must be finished.</td>
<td>Notify core developers about the upcoming release and ask about any
remaining tasks that must be finished.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>All developers</td>
<td>Check the bug tracker for any outstanding items and handle
appropriately. All bugs that have been fixed should have been marked
as Fix Committed.</td>
appropriately.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Set the Feature Freeze date, by which time all Git commits for
enhancements and new functionality should have been completed. After
this date, commits should only be made to fix problems that show up
during testing.</td>
<td>Set a Feature Freeze date, by which time all Git branches for
enhancements and new functionality should have been merged. After this
date, commits and merges should only be made to fix problems that show
up during testing.</td>
</tr>
<tr>
<td>&nbsp;</td>
@@ -97,6 +96,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Ensure that documentation will be updated before the release date:
<ul>
<li>Release Notes</li>
<li>Doxygen annotations</li>
<li>Other documents</li>
</ul>
</td>
@@ -104,13 +104,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Review and update this checklist for the upcoming release.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Release Manager</td>
<td>Create a release milestone on Launchpad. If a target release date is
known set "Date Targeted" to the expected release date.</td>
<td>Review and update this checklist for the upcoming release.
Update the release version number in the tags and messages below.</td>
</tr>
<tr>
<th colspan="3">Testing</th>
@@ -118,7 +113,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<tr>
<td>&nbsp;</td>
<td>Platform Developers</td>
<td>Run the built-in test programs on all available host platforms using
<td>Run the internal test programs on all available host platforms using
<blockquote><tt>
make -s runtests
</tt></blockquote></td>
@@ -156,6 +151,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Check that documentation has been updated:
<ul>
<li>Release Notes</li>
<li>Doxygen annotations</li>
<li>Other documents</li>
</ul>
</td>
@@ -167,8 +163,8 @@ everything that has to be done since it's so easy to miss steps.</p>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Obtain a positive <q>Ok to release</q> from developers.</td>
<td>Core Developers</td>
<td>Reach a consensus that the software is ready to release.</td>
</tr>
<tr>
<th colspan="3">Creating the final release version</th>
@@ -180,6 +176,9 @@ everything that has to be done since it's so easy to miss steps.</p>
<p><b>For each external submodule</b> in turn (assuming it has not been
tagged yet):</p>
<ol>
<li><tt>git grep UNRELEASED</tt> and insert the module version to any
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
Commit (don't push yet).</li>
<li>Check that the module's Release Notes have been updated to cover
all changes; add items as necessary, and set the module version
number and release date if appropriate. Convert to HTML and view in
@@ -188,27 +187,29 @@ everything that has to be done since it's so easy to miss steps.</p>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
Commit changes (don't push yet).</li>
Commit these changes (don't push).</li>
<li>Edit the module's release version file
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and its top-level
<tt>Doxyfile</tt>; set the <tt>DEVELOPMENT_FLAG</tt> value to 0 and
remove <tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string.
Commit changes (don't push).</li>
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and the
<tt>Doxyfile</tt>s in the top-level and/or documentation
directories. In these, set <tt>DEVELOPMENT_FLAG</tt> to 0 and remove
<tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string. Commit these
changes (don't push).</li>
<li>Tag the module:
<blockquote><tt>
git tag -m 'ANJ: Tag for EPICS 7.0.6.1' &lt;module-version&gt;
git tag -m 'ANJ: Tag for EPICS 7.0.8.1' &lt;module-version&gt;
</tt></blockquote>
</li>
<li>Update the git submodule on the Base-7.0 branch to the
newly-tagged version, but don't commit yet:
newly-tagged version, check the module's status matches the tag:
<blockquote><tt>
cd base-7.0/modules<br />
git add &lt;module&gt;<br />
git submodule status --cached
</tt></blockquote>
Don't commit the submodule updates yet.
</li>
<li>Edit the module's release version file
@@ -218,7 +219,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<tt>PROJECT_NUMBER</tt> string, appending <tt>-dev</tt> to the new
module version number. Commit changes.</li>
<li>Push commits and the new tag to the submodule's GitHub repository:
<li>Push commits and the new tag to the submodule's GitHub repository
(assumed to be the <tt>upstream</tt> remote):
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;<br />
git push --follow-tags upstream master
@@ -267,10 +269,9 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Tag the epics-base module in Git:
<blockquote><tt>
cd base-7.0<br />
git tag -m 'ANJ: Tagged for release' R7.0.6.1
git tag -m 'ANJ: Tagged for release' R7.0.8.1
</tt></blockquote>
<p>Don't push anything to the Launchpad repository
yet.</p>
<p>Don't push to GitHub yet.</p>
</td>
</tr>
<tr>
@@ -302,12 +303,12 @@ everything that has to be done since it's so easy to miss steps.</p>
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.0<br />
./.tools/make-tar.sh R7.0.6.1 ../base-7.0.6.1.tar.gz base-7.0.6.1/
./.tools/make-tar.sh R7.0.8.1 ../base-7.0.8.1.tar.gz base-7.0.8.1/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
cd ..<br />
gpg --armor --sign --detach-sig base-7.0.6.1.tar.gz
gpg --armor --sign --detach-sig base-7.0.8.1.tar.gz
</tt></blockquote>
</td>
</tr>
@@ -315,8 +316,9 @@ everything that has to be done since it's so easy to miss steps.</p>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Test the tar file by extracting its contents and building it on at
least one supported platform. When this succeeds the commits and new git
tag can be pushed to the Launchpad repository:
least one supported platform. If this succeeds the commits and new git
tag can be pushed to the GitHub repository's 7.0 branch (assumed to be
the <tt>upstream</tt> remote):
<blockquote><tt>
git push --follow-tags upstream 7.0
</tt></blockquote>
@@ -364,7 +366,7 @@ everything that has to be done since it's so easy to miss steps.</p>
</tr>
<tr>
<th colspan="3">Publish to epics-controls</th>
<th colspan="3">Publish to epics-controls.org</th>
</tr>
<tr>
<td><input type="checkbox"></td>
@@ -372,7 +374,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
epics-controls web-server.
<blockquote><tt>
scp base-7.0.6.1.tar.gz base-7.0.6.1.tar.gz.asc epics-controls:download/base<br />
scp base-7.0.8.1.tar.gz base-7.0.8.1.tar.gz.asc epics-controls:download/base<br />
</tt></blockquote>
</td>
</tr>
@@ -389,22 +391,22 @@ everything that has to be done since it's so easy to miss steps.</p>
</tr>
<tr>
<th colspan="3">Publish to Launchpad</th>
<th colspan="3">Publish to GitHub</th>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Go to the Launchpad milestone for this release. Click the Create
release button and add the release date. Put a URL for the release page
in the Release notes box, and click the Create release button. Upload
the tar file and its <tt>.asc</tt> signature file to the new Launchpad
release page.</td>
<td>Go to the GitHub
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8.1">
Create release from tag R7.0.8.1</a> page.
Upload the tar file and its <tt>.asc</tt> signature file to the new
GitHub release page.</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Find all Launchpad bug reports with the status Fix Committed which
have been fixed in this release and mark them Fix Released.</td>
<td>We used to close out bug reports in Launchpad at release-time, this
would be the time to do that if we have an equivalent on GitHub.</td>
</tr>
<tr>

View File

@@ -5,11 +5,11 @@ Documentation index
@li @ref releasenotes
@li @ref install
@li @ref recordrefmanual
@li <a href="ComponentReference.html">EPICS Component Reference Manual</a>
@li <a href="filters.html">Field Modifiers and Channel Filters</a>
@li <a href="links.html">Extensible IOC Database Links</a>
@li <a href="CAref.html">Channel Access Reference Manual</a>
@li <a href="filters.html">Server Side Filters Reference</a>
@li <a href="msi.html">msi: Macro Substitution and Include Tool</a>
@li <a href="links.html">JSON Link Types</a>
@li <a href="CA.html">Perl 5 Interface to Channel Access</a>
*/

View File

@@ -2,6 +2,16 @@
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
#
# modules/CONFIG_SITE.local
#
# Despite the .local in its name, this file *is* included in EPICS Base
# sources and should *not* be modified by sites. This trick is necessary
# to allow external submodules to be placed inside the modules directory
# without having to modify them, as long as their configure/CONFIG_SITE
# file includes the standard line
# -include $(TOP)/../CONFIG_SITE.local
# that causes this file to be read in during submodule builds.
# The name our submodules know us by:
PARENT_MODULE = EPICS_BASE

View File

@@ -34,9 +34,6 @@ pvDatabase_DEPEND_DIRS = pvAccess
SUBMODULES += pva2pva
pva2pva_DEPEND_DIRS = pvAccess
SUBMODULES += example
example_DEPEND_DIRS = pva2pva pvaClient
# Allow sites to add extra submodules
-include Makefile.local

View File

@@ -2575,7 +2575,8 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel )
SEVCHK ( ca_get ( DBR_FLOAT, chan, &temp ), NULL );
SEVCHK ( ca_pend_io ( timeoutToPendIO ), NULL );
/* printf ( "flow control bypassed %u events\n", flowCtrlCount ); */
if (0)
printf ( "flow control bypassed %u events\n", flowCtrlCount );
showProgressEnd ( interestLevel );
}

View File

@@ -32,7 +32,13 @@ static const iocshArg *acctstArgs[] =
&acctstArg3,
&acctstArg4
};
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
static const iocshFuncDef acctstFuncDef = {
"acctst",
5,
acctstArgs,
"Execute a Channel Access regression test.\n\n"
"For more information, see the 'acctst' documentation in the Channel Access reference.\n",
};
/* Wrapper called by iocsh, selects the argument types that print needs */

View File

@@ -392,9 +392,19 @@ void ca_client_context :: vSignal (
}
epicsTime current = epicsTime::getCurrent ();
char date[64];
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
this->printFormated ( " Current Time: %s\n", date );
try {
char date[64];
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
this->printFormated ( " Current Time: %s\n", date );
}
catch ( std::exception & except ) {
errlogPrintf (
"CA client library thread \"%s\" caught C++ exception \"%s\"\n",
epicsThreadGetNameSelf (), except.what () );
epicsTimeStamp now = current;
this->printFormated ( " Current Time: %u.%u\n",
now.secPastEpoch, now.nsec );
}
/*
* Terminate execution if unsuccessful

View File

@@ -25,6 +25,7 @@
#include <stdexcept>
#include <string> // vxWorks 6.0 requires this include
#include "epicsStdio.h"
#include "dbDefs.h"
#include "epicsGuard.h"
#include "epicsVersion.h"
@@ -1008,7 +1009,7 @@ bool cac::defaultExcep (
char buf[512];
char hostName[64];
iiu.getHostName ( guard, hostName, sizeof ( hostName ) );
sprintf ( buf, "host=%s ctx=%.400s", hostName, pCtx );
epicsSnprintf( buf, sizeof(buf), "host=%s ctx=%.400s", hostName, pCtx );
this->notify.exception ( guard, status, buf, 0, 0u );
return true;
}
@@ -1312,7 +1313,7 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
const char * pChannelName, const char * pAcc, const char * pRej )
{
char buf[256];
sprintf ( buf, "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
epicsSnprintf( buf, sizeof(buf), "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
pChannelName, pAcc, pRej );
{
callbackManager mgr ( this->notify, this->cbMutex );

View File

@@ -559,19 +559,19 @@ LIBCA_API chid epicsStdCall ca_evid_to_chid ( evid id );
/*
* ca_pend_event()
*
* timeOut R wait for this delay in seconds
* timeout R wait for this delay in seconds
*/
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeOut);
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeout);
#define ca_poll() ca_pend_event(1e-12)
/*
* ca_pend_io()
*
* timeOut R wait for this delay in seconds but return early
* timeout R wait for this delay in seconds but return early
* if all get requests (or search requests with null
* connection handler pointer have completed)
*/
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeOut);
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeout);
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
LIBCA_API int epicsStdCall ca_pend (ca_real timeout, int early);

View File

@@ -450,7 +450,7 @@ void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
epicsTimeStamp end_time;
epicsTimeStamp start_time;
double delay;
unsigned inlineIter;
unsigned inlineIter = 0;
epicsTimeGetCurrent ( &start_time );
(*pfunc) ( pItems, iterations, &inlineIter );

View File

@@ -88,6 +88,7 @@ public:
bool push ( const T & value );
template < class T >
unsigned push ( const T * pValue, unsigned nElem );
unsigned push ( const char * pValue, unsigned nElem );
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
unsigned push ( const epicsOldString * pValue, unsigned nElem );
@@ -208,6 +209,11 @@ inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf :: push ( const char *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
{
unsigned index = this->nextWriteIndex;

View File

@@ -46,7 +46,7 @@ void comQueRecv::clear ()
this->nBytesPending = 0u;
}
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
unsigned comQueRecv::copyOutBytes ( char *pBuf, unsigned nBytes )
{
unsigned totalBytes = 0u;
do {

View File

@@ -33,7 +33,7 @@ public:
comQueRecv ( comBufMemoryManager & );
~comQueRecv ();
unsigned occupiedBytes () const;
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
unsigned copyOutBytes ( char *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
void pushLastComBufReceived ( comBuf & );
void clear ();

View File

@@ -21,6 +21,9 @@
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include <vector>
#include <exception>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
@@ -28,6 +31,7 @@
#include "envDefs.h"
#include "epicsAssert.h"
#include "epicsString.h"
#include "epicsStdioRedirect.h"
#include "errlog.h"
#include "osiWireFormat.h"
@@ -35,39 +39,6 @@
#include "addrList.h"
#include "iocinf.h"
/*
* getToken()
*/
static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
{
bool tokenFound = false;
const char *pToken;
unsigned i;
pToken = *ppString;
while ( isspace (*pToken) && *pToken ){
pToken++;
}
for ( i=0u; i<bufSIze; i++ ) {
if ( isspace (pToken[i]) || pToken[i]=='\0' ) {
pBuf[i] = '\0';
*ppString = &pToken[i];
if ( i != 0 ) {
tokenFound = true;
}
break;
}
pBuf[i] = pToken[i];
}
if ( tokenFound ) {
pBuf[bufSIze-1] = '\0';
return pBuf;
}
return NULL;
}
/*
* addAddrToChannelAccessAddressList ()
*/
@@ -77,9 +48,7 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
{
osiSockAddrNode *pNewNode;
const char *pStr;
const char *pToken;
struct sockaddr_in addr;
char buf[32u]; /* large enough to hold an IP address */
int status, ret = -1;
pStr = envGetConfigParamPtr (pEnv);
@@ -87,31 +56,45 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
return ret;
}
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
status = aToIPAddr ( pToken, port, &addr );
if (status<0) {
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
continue;
try {
std::vector<char> scratch(pStr, pStr+strlen(pStr)+1); // copy chars and trailing nil
char *save = NULL;
for(const char *pToken = epicsStrtok_r(&scratch[0], " \t\n\r", &save);
pToken;
pToken = epicsStrtok_r(NULL, " \t\n\r", &save))
{
if(!pToken[0]) {
continue;
}
status = aToIPAddr ( pToken, port, &addr );
if (status<0) {
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
continue;
}
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
continue;
}
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
if (pNewNode==NULL) {
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
break;
}
pNewNode->addr.ia = addr;
/*
* LOCK applied externally
*/
ellAdd (pList, &pNewNode->node);
ret = 0; /* success if anything is added to the list */
}
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
continue;
}
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
if (pNewNode==NULL) {
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
break;
}
pNewNode->addr.ia = addr;
/*
* LOCK applied externally
*/
ellAdd (pList, &pNewNode->node);
ret = 0; /* success if anything is added to the list */
} catch(std::exception&) { // only bad_alloc currently possible
ret = -1;
}
return ret;

View File

@@ -56,6 +56,7 @@ extern "C" void epicsStdCall ca_dump_dbr (
if ( INVALID_DB_REQ ( type ) ) {
printf ( "bad DBR type %ld\n", type );
return;
}
printf ( "%s\t", dbr_text[type] );

View File

@@ -202,7 +202,7 @@ udpiiu::udpiiu (
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf("CAC: failed to set mcast ttl %d\n", ttl);
errlogPrintf("CAC: failed to set mcast ttl %d\n", (int)ttl);
}
}
#endif
@@ -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

@@ -12,6 +12,13 @@
* here and just generates unnecessary compiler warnings. */
#define REENTRINC
/* Clang-12 and later generates many warnings about compound token */
#ifdef __has_warning
# if __has_warning("-Wcompound-token-split-by-macro")
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
# endif
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
@@ -201,6 +208,8 @@ SV * newSVdbr(struct event_handler_args *peha) {
if (is_primitive) {
if (value_type == DBR_CHAR) {
/* Long string => Perl scalar */
if (peha->count == 0)
return newSVpvn(peha->dbr, 0);
((char *)peha->dbr) [peha->count - 1] = 0;
return newSVpv(peha->dbr, 0);
}
@@ -271,8 +280,12 @@ SV * newSVdbr(struct event_handler_args *peha) {
char *str = dbr_value_ptr(peha->dbr, peha->type);
/* Long string => Perl scalar */
str[peha->count - 1] = 0;
val = newSVpv(str, 0);
if (peha->count == 0)
val = newSVpvn(str, 0);
else {
str[peha->count - 1] = 0;
val = newSVpv(str, 0);
}
} else if (peha->count == 1) {
/* Single value => Perl scalar */
val = newSVdbf(value_type,

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env perl
#*************************************************************************
# Copyright (c) 2005 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2022 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# SPDX-License-Identifier: EPICS
# EPICS BASE is distributed subject to a Software License Agreement found
@@ -14,26 +14,24 @@
#
#######################################################################
use 5.10.1;
use strict;
use FindBin qw($Bin);
use lib ("$Bin/../../lib/perl");
use FindBin qw($RealBin);
use lib ("$RealBin/../../lib/perl");
use Getopt::Std;
use EPICS::Path;
use Cwd 'abs_path';
use CA;
######### Globals ##########
our ($opt_h, $opt_f, $opt_r);
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} || "$Bin/../../dbd/softIoc.dbd";
our $opt_w = 1;
our ($opt_h, $opt_f, $opt_l, $opt_r, $opt_D);
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} // abs_path("$RealBin/../../dbd/softIoc.dbd");
our $opt_w = 2;
our $opt_n = 10;
my %record = (); # Empty hash to put dbd data in
my $iIdx = 0; # Array indexes for interest, data type and base
my $tIdx = 1;
my $bIdx = 2;
my %device = (); # Empty hash to record which rec types have device support
# EPICS field types
my %fieldType = (
@@ -58,13 +56,14 @@ my %fieldType = (
);
# globals for sub caget
my %connected;
my $unconnected_count;
my %callback_data;
my %timed_out;
my $callback_incomplete;
######### Main program ############
HELP_MESSAGE() unless getopts('hd:f:rw:');
HELP_MESSAGE() unless getopts('hDd:f:l:n:rw:');
HELP_MESSAGE() if $opt_h;
die "File $opt_d not found. (\"capr.pl -h\" gives help)\n"
@@ -76,7 +75,7 @@ print "Using $opt_d\n\n";
# Print a list of record types
if ($opt_r) {
print ("Record types found:\n");
printList(0);
printList($opt_l);
exit;
}
@@ -100,7 +99,7 @@ if (@ARGV) {
} else {
# Drop any ".FIELD" part
s/\. \w+ $//x;
printRecord($_, 0);
printRecord($_, $opt_l);
}
}
@@ -130,9 +129,11 @@ sub parseDbd {
my $thisRecord;
my $thisField;
my $thisType;
my $thisSize = 0;
my $field = {};
my $interest = 0;
my $thisBase = 'DECIMAL';
my $special = '';
while (@dbd) {
$_ = shift @dbd;
@@ -149,35 +150,47 @@ sub parseDbd {
$thisField = $1;
$thisType = $2;
$isAfield = 1;
$thisSize = 1024 if $thisType =~ m/^ DBF_(IN|OUT|FWD)LINK $/x;
}
elsif ( m/interest \s* \( \s* (\w+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$interest = $1;
}
elsif ( m/size \s* \( \s* ([0-9]+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$thisSize = $1;
}
elsif ( m/special \s* \( \s* (\w+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$special = $1;
}
elsif ( m/base \s* \( \s* (\w+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$thisBase = $1;
}
elsif ( m/device \s* \( (\w+) \s* ,/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 0;
$device{$1}++;
}
if ( m/\{/ ) {
$level++;
}
if ( m/\}/ ) {
if ($level == 2 && $isAfield) {
my $params = [];
$params->[$iIdx] = $interest;
$params->[$tIdx] = $thisType;
$params->[$bIdx] = $thisBase;
my $params = {};
$params->{interest} = $interest;
$params->{dbfType} = $thisType;
$params->{base} = $thisBase;
$params->{special} = $special;
$params->{size} = $thisSize;
$field->{$thisField} = $params;
# Reset default values
$isAfield = 0;
$interest = 0; # reset default
$thisBase = 'DECIMAL'; # reset default
$interest = 0;
$thisBase = 'DECIMAL';
$special = '';
$thisSize = 0;
}
elsif ($level == 1 && $isArecord) {
$isArecord = 0;
@@ -207,21 +220,23 @@ sub getRecType {
# Given the record type and field, returns the interest level, data type
# and number base for the field
# Usage: ($dataType, $interest, $base) = getFieldParams($recType, $field);
# Usage: ($dataType, $interest, $base, $special, $size) = getFieldParams($recType, $field);
sub getFieldParams {
my ($recType, $field) = @_;
my $params = $record{$recType}{$field} or
die "Can't find params for $recType.$field";
exists($fieldType{$params->[$tIdx]}) ||
exists($fieldType{$params->{dbfType}}) ||
die "Field data type $field for $recType not found in dbd file --";
exists($params->[$iIdx]) ||
exists($params->{interest}) ||
die "Interest level for $field in $recType not found in dbd file --";
my $fType = $fieldType{$params->[$tIdx]};
my $fInterest = $params->[$iIdx];
my $fBase = $params->[$bIdx];
return ($fType, $fInterest, $fBase);
my $fType = $fieldType{$params->{dbfType}};
my $fInterest = $params->{interest};
my $fBase = $params->{base};
my $fSpecial = $params->{special};
my $fSize = $params->{size};
return ($fType, $fInterest, $fBase, $fSpecial, $fSize);
}
# Prints field name and data for given field. Formats output so
@@ -233,27 +248,37 @@ sub printField {
my $screenWidth = 80;
my ($outStr, $wide);
my $field = "$fieldName:";
if ( $dataType eq 'DBF_STRING' ) {
$outStr = sprintf('%-5s %s', $field, $fieldData);
} elsif ( $base eq 'HEX' ) {
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
$outStr = sprintf('%-5s 0x%x', $field, $val);
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
} elsif ( $dataType eq 'DBF_CHAR' ) {
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
} else {
# DBF_INT64, DBF_LONG, DBF_SHORT,
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
$outStr = sprintf('%-5s %d', $field, $fieldData);
if (ref $fieldData eq 'ARRAY') {
my $elems = scalar @{$fieldData};
my $field = "$fieldName\[$elems\]:";
my $count = $elems > $opt_n ? $opt_n : $elems;
my @show = @{$fieldData}[0 .. $count - 1];
$outStr = sprintf('%-5s %s', $field, join(', ', @show));
$outStr .= ", ..." if $elems > $count;
}
else {
my $field = "$fieldName:";
if ( $dataType eq 'DBF_STRING' ) {
$outStr = sprintf('%-5s %s', $field, $fieldData);
} elsif ( $base eq 'HEX' ) {
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
$outStr = sprintf('%-5s 0x%x', $field, $val);
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
} elsif ( $dataType eq 'DBF_UCHAR' ) {
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
} else {
# DBF_INT64, DBF_LONG, DBF_SHORT,
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
$outStr = sprintf('%-5s %d', $field, $fieldData);
}
}
my $len = length($outStr);
if ($len <= 20) { $wide = 20; }
elsif ( $len <= 40 ) { $wide = 40; }
elsif ( $len <= 60 ) { $wide = 60; }
if ($len < 20) { $wide = 20; }
elsif ( $len < 40 ) { $wide = 40; }
elsif ( $len < 60 ) { $wide = 60; }
else { $wide = 80;}
my $pad = $wide - $len;
@@ -269,49 +294,64 @@ sub printField {
return $col;
}
# Query for a list of fields simultaneously.
# The results are filled in the the %callback_data global hash
# and the result of the operation is the number of read pvs
# Query the native values of a list of PVs simultaneously.
# The data is returned in the the %callback_data global hash.
# The return value is the number of read pvs
#
# NOTE: Not re-entrant because results are written to global hash
# %callback_data
#
# Usage: $fields_read = caget( @pvlist )
sub caget {
my @chans = map { CA->new($_); } @_;
#clear any previous results;
%connected = ();
$unconnected_count = scalar @_;
%callback_data = ();
%timed_out = ();
$callback_incomplete = 0;
eval { CA->pend_io($opt_w); };
if ($@) {
if ($@ =~ m/^ECA_TIMEOUT/) {
my $name = $chans[0]->name;
my $err = (@chans > 1) ? 'some fields' : "'$name'";
print "Channel connect timed out: $err not found.\n";
foreach my $chan (@chans) {
$timed_out{$chan->name} = !$chan->is_connected;
}
@chans = grep { $_->is_connected } @chans;
} else {
die $@;
}
}
my @chans = map {
print " Creating channel for $_\n" if $opt_D;
CA->new($_, \&canew_callback);
} @_;
my $channel_count = scalar @chans;
return 0 unless $channel_count gt 0;
map {
$_->get_callback(\&caget_callback, $_->field_type);
} @chans;
print " $channel_count channels created.\n" if $opt_D;
my $fields_read = $callback_incomplete = @chans;
CA->pend_event(0.1)
while $callback_incomplete;
return $fields_read;
my $elapsed = 0;
do {
print " Waiting for $unconnected_count channels to connect\n"
if $unconnected_count && $opt_D;
print " Waiting for data from $callback_incomplete channels\n"
if $callback_incomplete && $opt_D;
CA->pend_event(0.1);
$elapsed += 0.1;
} until (($elapsed > $opt_w) or
(scalar %connected && $callback_incomplete == 0));
my $data_count = scalar keys %callback_data;
printf " Got data from %d of %d channels\n", $data_count, $channel_count
if $opt_D;
return $data_count;
}
sub canew_callback {
my ($chan, $up) = @_;
return unless $up;
$connected{$chan->name} = $chan;
$unconnected_count--;
my $ftype = $chan->field_type;
my $count = $chan->element_count;
$ftype = 'DBR_LONG' if $ftype eq 'DBR_CHAR' && $count == 1;
print " Getting ${\$chan->name} as $ftype\n" if $opt_D;
# We have to fetch all elements so we can show how many there are
$chan->get_callback(\&caget_callback, $ftype);
$callback_incomplete++;
}
sub caget_callback {
my ($chan, $status, $data) = @_;
die $status if $status;
print " Got ${\$chan->name} = '$data'\n" if $opt_D;
$callback_data{$chan->name} = $data;
$callback_incomplete--;
}
@@ -333,69 +373,83 @@ sub printRecord {
my @ftypes = (); #types, from parser
my @bases = (); #bases, from parser
foreach my $field (sort keys %{$record{$recType}}) {
# Skip DTYP field if this rec type doesn't have device support defined
next if $field eq 'DTYP' && !exists($device{$recType});
my ($fType, $fInterest, $base) = getFieldParams($recType, $field);
# FIXME: Support waveform.VAL fields etc.
unless( $fType eq 'DBF_NOACCESS' ) {
if ($interest >= $fInterest ) {
my $fToGet = "$name.$field";
push @fields_pr, $field;
push @readlist, $fToGet;
push @ftypes, $fType;
push @bases, $base;
}
my ($fType, $fInterest, $base, $special, $size) =
getFieldParams($recType, $field);
next if $fInterest > $interest;
my $fToGet = "$name.$field";
if ($fType eq 'DBF_NOACCESS') {
next unless $special eq 'SPC_DBADDR';
$fType = 'DBF_STRING';
}
elsif ($fType eq 'DBF_STRING' && $size >= 40) {
$fToGet .= '$';
}
push @fields_pr, $field;
push @readlist, $fToGet;
push @ftypes, $fType;
push @bases, $base;
}
my $fields_read = caget( @readlist );
my @missing;
# print while iterating over lists gathered
my $col = 0;
for (my $i=0; $i < scalar @readlist; $i++) {
my $field = $fields_pr[$i];
my $fToGet = $readlist[$i];
my ($fType, $data, $base);
next if $timed_out{$fToGet};
push @missing, $field unless exists $callback_data{$fToGet};
next unless exists $callback_data{$fToGet};
$fType = $ftypes[$i];
$base = $bases[$i];
$data = $callback_data{$fToGet};
$col = printField($field, $data, $fType, $base, $col);
}
print("\n"); # Final newline
printf "\nUnreadable fields: %s\n", join(', ', @missing) if @missing && $opt_D;
}
# Prints list of record types found in dbd file. If level > 0
# then the fields of that record type, their interest levels and types are
# also printed.
# Diagnostic routine, usage: void printList(level);
# then uses printRecordList to display all fields in each record type.
sub printList {
my $level = shift;
foreach my $rkey (sort keys(%record)) {
print(" $rkey\n");
if ($level > 0) {
foreach my $fkey (keys %{$record{$rkey}}) {
print("\tField $fkey - interest $record{$rkey}{$fkey}[$iIdx] ");
print("- type $record{$rkey}{$fkey}[$tIdx] ");
print("- base $record{$rkey}{$fkey}[$bIdx]\n");
}
printRecordList($rkey);
}
else {
print(" $rkey\n");
}
}
}
# Prints list of fields with interest levels for given record type
# Diagnostic routine, usage: void printRecordList("recordType");
# Prints list of fields and metadata for given record type
sub printRecordList {
my $type = shift;
if (exists($record{$type}) ) {
print("Record type - $type\n");
foreach my $fkey (sort keys %{$record{$type}}) {
printf('%-8s', $fkey);
printf(" interest = $record{$type}{$fkey}[$iIdx]");
printf(" type = %-12s ",$record{$type}{$fkey}[$tIdx]);
print (" base = $record{$type}{$fkey}[$bIdx]\n");
my $param = $record{$type}{$fkey};
my $dbfType = $param->{dbfType};
printf " %-8s", $fkey;
printf " interest = %d", $param->{interest};
printf " type = %-12s", $dbfType;
if ($dbfType eq 'DBF_STRING') {
printf " size = %s\n", $param->{size};
}
elsif ($dbfType =~ m/DBF_U?(CHAR|SHORT|INT|LONG|INT64)/) {
printf " base = %s\n", $param->{base};
}
elsif ($dbfType eq 'DBF_NOACCESS') {
printf " special = %s\n", $param->{special};
}
else {
print "\n";
}
}
}
else {
@@ -411,16 +465,20 @@ sub HELP_MESSAGE {
" capr.pl [options] <record name> [<interest>]\n",
"\n",
" -h Print this help message.\n",
" -D Print debug messages.\n",
"Channel Access options:\n",
" -w <sec>: Wait time, specifies CA timeout, default is $opt_w second\n",
"Database Definitions:\n",
" -d <file.dbd>: The file containing record type definitions.\n",
" This can be set using the EPICS_CAPR_DBD_FILE environment variable.\n",
" Default: ", AbsPath($opt_d), "\n",
" Default: ", abs_path($opt_d), "\n",
"Output Options:\n",
" -r Lists all record types in the selected dbd file.\n",
" -f <record type>: Lists all fields with their interest level, data type\n",
" and number base for the given record_type.\n",
" -f <record type>: Lists all fields with interest level, data type\n",
" and other information for the given record_type.\n",
" -l <interest>: interest level\n",
" -n <elems>: Maximum number of array elements to display\n",
" Default: $opt_n\n",
"\n",
"Base version: ", CA->version, "\n";
exit 1;

View File

@@ -392,6 +392,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":taicnhsSVe:f:g:l:#:d:0:w:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -437,8 +439,8 @@ int main (int argc, char *argv[])
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('caget -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('caget -h' for help.)\n",
optarg, caTimeout);
}
break;
case '#': /* Array count */

View File

@@ -141,6 +141,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":nhVw:s:p:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -150,11 +152,16 @@ int main (int argc, char *argv[])
printf( "\nEPICS Version %s, CA Protocol version %s\n", EPICS_VERSION_STRING, ca_version() );
return 0;
case 'w': /* Set CA timeout value */
/*
* epicsScanDouble is a macro defined as epicsParseDouble,
* (found in modules/libcom/src/misc) which will only
* change caTimeout here if it finds an acceptable value.
*/
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('cainfo -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('cainfo -h' for help.)\n",
optarg, caTimeout);
}
break;
case 's': /* ca_client_status interest level */

View File

@@ -219,6 +219,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":nhVm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -251,11 +253,16 @@ int main (int argc, char *argv[])
}
break;
case 'w': /* Set CA timeout value */
/*
* epicsScanDouble is a macro defined as epicsParseDouble,
* (found in modules/libcom/src/misc) which will only
* change caTimeout here if it finds an acceptable value.
*/
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('camonitor -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('camonitor -h' for help.)\n",
optarg, caTimeout);
}
break;
case '#': /* Array count */

View File

@@ -35,6 +35,7 @@
#include <epicsStdlib.h>
#include <cadef.h>
#include <errlog.h>
#include <epicsGetopt.h>
#include <epicsEvent.h>
#include <epicsString.h>
@@ -284,6 +285,8 @@ int main (int argc, char *argv[])
LINE_BUFFER(stdout); /* Configure stdout buffering */
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
use_ca_timeout_env ( &caTimeout);
while ((opt = getopt(argc, argv, ":cnlhatsVS#:w:p:F:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
@@ -318,11 +321,16 @@ int main (int argc, char *argv[])
request = callback;
break;
case 'w': /* Set CA timeout value */
/*
* epicsScanDouble is a macro defined as epicsParseDouble,
* (found in modules/libcom/src/misc) which will only
* change caTimeout here if it finds an acceptable value.
*/
if(epicsScanDouble(optarg, &caTimeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('caput -h' for help.)\n", optarg);
caTimeout = DEFAULT_TIMEOUT;
"- ignored, using '%.1f'. ('caput -h' for help.)\n",
optarg, caTimeout);
}
break;
case '#': /* Array count */
@@ -337,7 +345,7 @@ int main (int argc, char *argv[])
if (sscanf(optarg,"%u", &caPriority) != 1)
{
fprintf(stderr, "'%s' is not a valid CA priority "
"- ignored. ('caget -h' for help.)\n", optarg);
"- ignored. ('caput -h' for help.)\n", optarg);
caPriority = DEFAULT_CA_PRIORITY;
}
if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX;
@@ -542,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;
}
@@ -563,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

@@ -28,6 +28,7 @@
#include <alarm.h>
#include <epicsTime.h>
#include <epicsStdlib.h>
#include <epicsString.h>
#include <cadef.h>
@@ -53,7 +54,7 @@ char fieldSeparator = ' '; /* OFS default is whitespace */
int enumAsNr = 0; /* used for -n option - get DBF_ENUM as number */
int charArrAsStr = 0; /* used for -S option - treat char array as (long) string */
double caTimeout = 1.0; /* wait time default (see -w option) */
double caTimeout = DEFAULT_TIMEOUT; /* wait time default (see -w option) */
capri caPriority = DEFAULT_CA_PRIORITY; /* CA Priority */
#define TIMETEXTLEN 28 /* Length of timestamp text buffer */
@@ -639,3 +640,22 @@ int connect_pvs (pv* pvs, int nPvs)
}
return returncode;
}
/* Set the timeout to EPICS_CLI_TIMEOUT */
void use_ca_timeout_env ( double* timeout)
{
const char* tmoStr; /* contents of environment var */
if ((tmoStr = getenv("EPICS_CLI_TIMEOUT")) != NULL && timeout != NULL)
{
if(epicsScanDouble(tmoStr, timeout) != 1)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"(from 'EPICS_CLI_TIMEOUT' in the environment) - "
"ignored. (use '-h' for help.)\n", tmoStr);
*timeout = DEFAULT_TIMEOUT;
}
}
}

View File

@@ -100,6 +100,7 @@ extern char *dbr2str (const void *value, unsigned type);
extern void print_time_val_sts (pv *pv, unsigned long reqElems);
extern int create_pvs (pv *pvs, int nPvs, caCh *pCB );
extern int connect_pvs (pv *pvs, int nPvs );
extern void use_ca_timeout_env (double* timeout);
/*
* no additions below this endif

View File

@@ -225,6 +225,11 @@ static void asCaTask(void)
if(asCaDebug) printf("asCaTask has cleared all channels\n");
epicsEventSignal(asCaTaskWait);
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
taskwdRemove(0);
}
void asCaStart(void)
@@ -241,7 +246,7 @@ void asCaStart(void)
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)asCaTask,0);
if(threadid==0) {
errMessage(0,"asCaStart: taskSpawn Failure\n");
errMessage(0,"asCaStart: taskSpawn Failure");
}
}
epicsMutexMustLock(asCaTaskLock);

View File

@@ -16,12 +16,13 @@
#include "asIocRegister.h"
/* asSetFilename */
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgString};
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgStringPath};
static const iocshArg * const asSetFilenameArgs[] = {&asSetFilenameArg0};
static const iocshFuncDef asSetFilenameFuncDef =
{"asSetFilename",1,asSetFilenameArgs,
"Set path+file name of ACF file.\n"
"No immediate effect. Run as asInit() to (re)load.\n"};
"No immediate effect. Run asInit to (re)load.\n"
"Example: asSetFilename /full/path/to/accessSecurityFile\n"};
static void asSetFilenameCallFunc(const iocshArgBuf *args)
{
asSetFilename(args[0].sval);
@@ -33,7 +34,8 @@ static const iocshArg * const asSetSubstitutionsArgs[] = {&asSetSubstitutionsArg
static const iocshFuncDef asSetSubstitutionsFuncDef =
{"asSetSubstitutions",1,asSetSubstitutionsArgs,
"Set subtitutions used when reading ACF file.\n"
"No immediate effect. Run as asInit() to (re)load.\n"};
"No immediate effect. Run asInit to (re)load.\n"
"Example: asSetSubstitutions var1=5,var2=hello\n"};
static void asSetSubstitutionsCallFunc(const iocshArgBuf *args)
{
asSetSubstitutions(args[0].sval);
@@ -59,7 +61,10 @@ static void asdbdumpCallFunc(const iocshArgBuf *args)
static const iocshArg aspuagArg0 = { "uagname",iocshArgString};
static const iocshArg * const aspuagArgs[] = {&aspuagArg0};
static const iocshFuncDef aspuagFuncDef = {"aspuag",1,aspuagArgs,
"Show members of User Access Group.\n"};
"Show members of the User Access Group.\n"
"If no Group is specified then the members\n"
"of all user access groups are displayed.\n"
"Example: aspuag mygroup\n"};
static void aspuagCallFunc(const iocshArgBuf *args)
{
aspuag(args[0].sval);
@@ -69,7 +74,10 @@ static void aspuagCallFunc(const iocshArgBuf *args)
static const iocshArg asphagArg0 = { "hagname",iocshArgString};
static const iocshArg * const asphagArgs[] = {&asphagArg0};
static const iocshFuncDef asphagFuncDef = {"asphag",1,asphagArgs,
"Show members of Host Access Group.\n"};
"Show members of the Host Access Group.\n"
"If no Group is specified then the members\n"
"of all host access groups are displayed\n"
"Example: asphag mygroup\n"};
static void asphagCallFunc(const iocshArgBuf *args)
{
asphag(args[0].sval);
@@ -78,8 +86,12 @@ static void asphagCallFunc(const iocshArgBuf *args)
/* asprules */
static const iocshArg asprulesArg0 = { "asgname",iocshArgString};
static const iocshArg * const asprulesArgs[] = {&asprulesArg0};
static const iocshFuncDef asprulesFuncDef = {"asprules",1,asprulesArgs,
"List rules of an Access Security Group.\n"};
static const iocshFuncDef asprulesFuncDef = {
"asprules",1,asprulesArgs,
"List rules of an Access Security Group.\n"
"If no Group is specified then list the rules for all groups\n"
"Example: asprules mygroup\n"
};
static void asprulesCallFunc(const iocshArgBuf *args)
{
asprules(args[0].sval);
@@ -89,20 +101,28 @@ 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);
}
/* astac */
static const iocshArg astacArg0 = { "recordname",iocshArgString};
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

@@ -11,5 +11,6 @@
# This is a Makefile fragment, see src/ioc/Makefile.
$(patsubst %,$(COMMON_DIR)/%,$(BPT_DBD)) : \
$(COMMON_DIR)/bpt%.dbd : $(MAKEBPT)
$(addprefix $(COMMON_DIR)/,$(BPT_DBD)) : $(COMMON_DIR)/bpt%.dbd : \
$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)
# Don't try to use $(MAKEBPT) above

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

@@ -13,13 +13,15 @@
THESE_RULES := $(IOCDIR)/db/RULES
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES) \
$(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -I $(COMMON_DIR) -o $(COMMONDEP_TARGET) $< > $@
$(COMMON_DIR)/dbCommonRecord.html: ../db/dbCommon.dbd.pod
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES) \
$(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) -I ../db -I $(COMMON_DIR) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@

View File

@@ -58,6 +58,7 @@ typedef struct cbQueueSet {
int shutdown; // use atomic
int threadsConfigured;
int threadsRunning;
epicsThreadId *threads;
} cbQueueSet;
static cbQueueSet callbackQueue[NUM_CALLBACK_PRIORITIES];
@@ -242,11 +243,15 @@ void callbackStop(void)
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
int j;
while (epicsAtomicGetIntT(&mySet->threadsRunning)) {
epicsEventSignal(mySet->semWakeUp);
epicsEventWaitWithTimeout(startStopEvent, 0.1);
}
for(j=0; j<mySet->threadsConfigured; j++) {
epicsThreadMustJoin(mySet->threads[j]);
}
}
}
@@ -266,6 +271,8 @@ void callbackCleanup(void)
mySet->semWakeUp = NULL;
epicsRingPointerDelete(mySet->queue);
mySet->queue = NULL;
free(mySet->threads);
mySet->threads = NULL;
}
epicsTimerQueueRelease(timerQueue);
@@ -297,17 +304,25 @@ void callbackInit(void)
cantProceed("epicsRingPointerLockedCreate failed for %s\n",
threadNamePrefix[i]);
callbackQueue[i].queueOverflow = FALSE;
if (callbackQueue[i].threadsConfigured == 0)
callbackQueue[i].threadsConfigured = callbackThreadsDefault;
callbackQueue[i].threads = callocMustSucceed(callbackQueue[i].threadsConfigured,
sizeof(*callbackQueue[i].threads),
"callbackInit");
for (j = 0; j < callbackQueue[i].threadsConfigured; j++) {
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = threadPriority[i];
opts.stackSize = epicsThreadStackBig;
if (callbackQueue[i].threadsConfigured > 1 )
sprintf(threadName, "%s-%d", threadNamePrefix[i], j);
else
strcpy(threadName, threadNamePrefix[i]);
tid = epicsThreadCreate(threadName, threadPriority[i],
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)callbackTask, &priorityValue[i]);
callbackQueue[i].threads[j] = tid = epicsThreadCreateOpt(threadName,
(EPICSTHREADFUNC)callbackTask, &priorityValue[i], &opts);
if (tid == 0) {
cantProceed("Failed to spawn callback thread %s\n", threadName);
} else {
@@ -329,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

@@ -73,7 +73,7 @@ epicsExportAddress(int, dbAccessDebugPUTF);
DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
static short mapDBFToDBR[DBF_NTYPES] = {
static const short mapDBFToDBR[DBF_NTYPES] = {
/* DBF_STRING => */ DBR_STRING,
/* DBF_CHAR => */ DBR_CHAR,
/* DBF_UCHAR => */ DBR_UCHAR,
@@ -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

@@ -220,6 +220,8 @@ DBCORE_API long dbNameToAddr(const char *pname, struct dbAddr *paddr);
/** Initialize DBADDR from a dbEntry
* Also handles SPC_DBADDR processing. This is really an internal
* routine for use by dbNameToAddr() and dbChannelCreate().
*
* \since 7.0.2.1
*/
DBCORE_API long dbEntryToAddr(const struct dbEntry *pdbentry,
struct dbAddr *paddr);
@@ -227,6 +229,8 @@ DBCORE_API long dbEntryToAddr(const struct dbEntry *pdbentry,
/** Initialize DBENTRY from a valid dbAddr*
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias().
*
* \since 3.16.1
*/
DBCORE_API void dbInitEntryFromAddr(struct dbAddr *paddr,
struct dbEntry *pdbentry);
@@ -234,6 +238,8 @@ DBCORE_API void dbInitEntryFromAddr(struct dbAddr *paddr,
/** Initialize DBENTRY from a valid record (dbCommon*)
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias() when no field is specified.
*
* \since 3.16.1
*/
DBCORE_API void dbInitEntryFromRecord(struct dbCommon *prec,
struct dbEntry *pdbentry);

View File

@@ -575,15 +575,10 @@ long dbChannelOpen(dbChannel *chan)
}
/* Set up type probe */
probe.type = dbfl_type_val;
probe.ctx = dbfl_context_read;
memset(&probe, 0, sizeof(probe));
probe.field_type = dbChannelExportType(chan);
probe.no_elements = dbChannelElements(chan);
probe.field_size = dbChannelFieldSize(chan);
probe.sevr = NO_ALARM;
probe.stat = NO_ALARM;
probe.time.secPastEpoch = 0;
probe.time.nsec = 0;
p = probe;

View File

@@ -9,14 +9,22 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#ifndef INC_dbChannel_H
#define INC_dbChannel_H
/** \file dbChannel.h
*
* \author Andrew Johnson (ANL)
* \author Ralph Lange (BESSY)
*
* \brief The dbChannel API gives access to record fields.
*
* The dbChannel API is used internally by the IOC and by link types, device
* support and IOC servers (RSRV and QSRV) to access record fields, either
* directly or through one or more server-side filters as specified in the
* channel name used when creating the channel.
*/
#include "dbDefs.h"
#include "dbAddr.h"
#include "ellLib.h"
@@ -30,200 +38,546 @@
extern "C" {
#endif
/*
/**
* event subscription
*/
typedef struct evSubscrip {
ELLNODE node;
struct dbChannel *chan;
EVENTFUNC *user_sub;
void *user_arg;
struct event_que *ev_que;
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 */
unsigned char select;
char useValque;
char callBackInProgress;
char enabled;
} 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;
/* 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;
};
#endif
typedef struct chFilter chFilter;
/* A dbChannel points to a record field, and can have multiple filters */
/** \brief A Database Channel object
*
* A dbChannel is created from a user-supplied channel name, and holds
* pointers to the record & field and information about any filters that
* were specified with it. The dbChannel macros defined in this header
* file should always be used to read data from a dbChannel object, the
* internal implementation may change without notice.
*/
typedef struct dbChannel {
const char *name;
dbAddr addr; /* address structure for record/field */
long final_no_elements; /* final number of elements (arrays) */
short final_field_size; /* final size of element */
short final_type; /* final type of database field */
ELLLIST filters; /* list of filters as created from JSON */
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
ELLLIST post_chain; /* list of filters to be called post-event-queue */
const char *name; /**< Channel name */
dbAddr addr; /**< Pointers to record & field */
long final_no_elements; /**< Final number of array elements */
short final_field_size; /**< Final size of each element */
short final_type; /**< Final type of database field */
ELLLIST filters; /**< Filters used by dbChannel */
ELLLIST pre_chain; /**< Filters on pre-event-queue chain */
ELLLIST post_chain; /**< Filters on post-event-queue chain */
} dbChannel;
/* Prototype for the channel event function that is called in filter stacks
/** \brief Event filter function type
*
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
* Unless dbfl_has_copy(pLog), it must call dbScanLock before accessing the data,
* as this indicates the data is still owned by the record.
* Prototype for channel event filter functions.
*
* This function has ownership of the field log pLog, if it wishes to discard
* this update it should free the field log with db_delete_field_log() and
* then return NULL.
* When these functions are called the scan lock for the record associated
* with \p chan _may_ already be locked, but they must use dbfl_has_copy()
* to determine whether the data in \p pLog belongs to the record. If that
* returns 0 the function must call dbScanLock() before accessing the data.
*
* A filter function owns the field log \p pLog when called. To discard an
* update it should free the field log using db_delete_field_log() and
* return NULL.
*/
typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
/* Return values from chFilterIf->parse_* routines: */
/** \brief Result returned by chFilterIf parse routines.
*
* The parsing functions from a chFilterIf must return either \p parse_stop
* (in event of an error) or \p parse_continue.
*/
typedef enum {
parse_stop, parse_continue
} parse_result;
/* These routines must be implemented by each filter plug-in */
/** \brief Channel Filter Interface
*
* Routines to be implemented by each Channel Filter.
*/
typedef struct chFilterIf {
/* cleanup pointer passed to dbRegisterFilter().
* Called during DB shutdown
/** \brief Release private filter data.
*
* Called during database shutdown to release resources allocated by
* the filter.
* \param puser The user-pointer passed into dbRegisterFilter().
*/
void (* priv_free)(void *puser);
/* Parsing event handlers: */
parse_result (* parse_start)(chFilter *filter);
/* If parse_start() returns parse_continue for a filter, one of
/** \name Parsing event handlers
*
* A filter that doesn't accept a particular JSON value type may use a
* \p NULL pointer to the parsing handler for that value type, which is
* equivalent to a routine that always returns \p parse_stop.
*/
/** \brief Create new filter instance.
*
* Called when a new filter instance is requested. Filter may allocate
* resources for this instance and store in \p filter->puser.
* If parse_start() returns \p parse_continue for a filter, one of
* parse_abort() or parse_end() will later be called for that same
* filter.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_start)(chFilter *filter);
/** \brief Parsing of filter instance is being cancelled.
*
* This function should release any memory allocated for the given
* \p filter instance; no further parsing handlers will be called for it.
* \param filter Pointer to instance data.
*/
void (* parse_abort)(chFilter *filter);
/* If parse_abort() is called it should release any memory allocated
* for this filter; no further parse_...() calls will be made;
/** \brief Parsing of filter instance has completed successfully.
*
* The parser has reached the end of this instance and no further parsing
* handlers will be called for it. The filter must check the instance
* data and indicate whether it was complete or not.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_end)(chFilter *filter);
/* If parse_end() returns parse_stop it should have released any
* memory allocated for this filter; no further parse_...() calls will
* be made in this case.
/** \brief Parser saw \p null value.
*
* Optional.
* Null values are rarely accepted by channel filters.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_null)(chFilter *filter);
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
parse_result (* parse_integer)(chFilter *filter, long integerVal);
parse_result (* parse_double)(chFilter *filter, double doubleVal);
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
size_t stringLen); /* NB: stringVal is not zero-terminated: */
/** \brief Parser saw boolean value.
*
* Optional.
* \param filter Pointer to instance data.
* \param boolVal true/false Value.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
/** \brief Parser saw integer value.
*
* Optional.
* \param filter Pointer to instance data.
* \param integerVal Value.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_integer)(chFilter *filter, long integerVal);
/** \brief Parser saw double value.
*
* Optional.
* \param filter Pointer to instance data.
* \param doubleVal Value.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_double)(chFilter *filter, double doubleVal);
/** \brief Parser saw string value.
*
* Optional.
* \param filter Pointer to instance data.
* \param stringVal Value, not zero-terminated.
* \param stringLen Number of chars in \p stringVal.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
size_t stringLen);
/** \brief Parser saw start of a JSON map value.
*
* Optional.
* Inside a JSON map all data consists of key/value pairs.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_start_map)(chFilter *filter);
/** \brief Parser saw a JSON map key.
*
* Optional.
* \param filter Pointer to instance data.
* \param key Value not zero-terminated.
* \param stringLen Number of chars in \p key
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_map_key)(chFilter *filter, const char *key,
size_t stringLen); /* NB: key is not zero-terminated: */
size_t stringLen);
/** \brief Parser saw end of a JSON map value.
*
* Optional.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_end_map)(chFilter *filter);
/** \brief Parser saw start of a JSON array value.
*
* Optional.
* Data inside a JSON array doesn't have to be all of the same type.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_start_array)(chFilter *filter);
/** \brief Parser saw end of a JSON array value.
*
* Optional.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_end_array)(chFilter *filter);
/* Channel operations: */
/** \name Channel operations */
/** \brief Open filter on channel.
*
* Optional, initialize instance.
* \param filter Pointer to instance data.
* \returns 0, or an error status value.
*/
long (* channel_open)(chFilter *filter);
void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
/** \brief Get pre-chain filter function.
*
* Optional.
* Returns pre-chain filter function and context.
* \param[in] filter Pointer to instance data.
* \param[out] cb_out Write filter function pointer here.
* \param[out] arg_out Write private data pointer here.
* \param[in,out] probe db_field_log with metadata for adjusting.
*/
void (* channel_register_pre) (chFilter *filter,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
/** \brief Get post-chain filter function.
*
* Optional, return post-chain filter function and context.
* \param[in] filter Pointer to instance data.
* \param[out] cb_out Write filter function pointer here.
* \param[out] arg_out Write private data pointer here.
* \param[in,out] probe db_field_log with metadata for adjusting.
*/
void (* channel_register_post)(chFilter *filter,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
/** \brief Print information about filter to stdout.
*
* Optional.
* \param filter Pointer to instance data.
* \param level Higher levels may provide more detail.
* \param indent Indent all lines by this many spaces.
*/
void (* channel_report)(chFilter *filter,
int level, const unsigned short indent);
/** \brief Close filter.
*
* Optional, releases resources allocated for this instance.
* \param filter Pointer to instance data.
*/
void (* channel_close)(chFilter *filter);
} chFilterIf;
/* A chFilterPlugin holds data for a filter plugin */
/** \brief Filter plugin data
*
* A chFilterPlugin object holds data about a filter plugin.
*/
typedef struct chFilterPlugin {
ELLNODE node;
const char *name;
const chFilterIf *fif;
void *puser;
ELLNODE node; /**< \brief List node (dbBase->filterList) */
const char *name; /**< \brief Filter name */
const chFilterIf *fif; /**< \brief Filter interface routines */
void *puser; /**< \brief For use by the plugin */
} chFilterPlugin;
/* A chFilter holds data for a single filter instance */
/** \brief Filter instance data
*
* A chFilter holds data about a single filter instance.
*/
struct chFilter {
ELLNODE list_node;
ELLNODE pre_node;
ELLNODE post_node;
dbChannel *chan;
const chFilterPlugin *plug;
chPostEventFunc *pre_func;
void *pre_arg;
chPostEventFunc *post_func;
void *post_arg;
void *puser;
ELLNODE list_node; /**< \brief List node (dbChannel->filters) */
ELLNODE pre_node; /**< \brief List node (dbChannel->pre_chain) */
ELLNODE post_node; /**< \brief List node (dbChannel->post_chain) */
dbChannel *chan; /**< \brief The dbChannel we belong to */
const chFilterPlugin *plug; /**< \brief The plugin that created us */
chPostEventFunc *pre_func; /**< \brief pre-chain filter function */
void *pre_arg; /**< \brief pre-chain context pointer */
chPostEventFunc *post_func; /**< \brief post-chain filter function */
void *post_arg; /**< \brief post-chain context pointer */
void *puser; /**< \brief For use by the plugin */
};
struct dbCommon;
struct dbFldDes;
DBCORE_API void dbChannelInit (void);
/** \brief Initialize the dbChannel subsystem. */
DBCORE_API void dbChannelInit(void);
/** \brief Cleanup the dbChannel subsystem. */
DBCORE_API void dbChannelExit(void);
/** \brief Test the given PV name for existance.
*
* This routine looks up the given record and field name, but does not check
* whether any field modifiers given after the field name are correct.
* This is sufficient for the correct server to quickly direct searches to the
* IOC that owns that PV name. Field modifiers will be checked when
* dbChannelCreate() is later called with the same name.
* \param name Channel name.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelTest(const char *name);
/** \brief Create a dbChannel object for the given PV name.
*
* \param name Channel name.
* \return Pointer to dbChannel object, or NULL if invalid.
*/
DBCORE_API dbChannel * dbChannelCreate(const char *name);
/** \brief Open a dbChannel for doing I/O.
*
* \param chan Pointer to the dbChannel object.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelOpen(dbChannel *chan);
/*Following is also defined in db_convert.h*/
/** \brief Request (DBR) type conversion array.
*
* This converter array is declared in db_convert.h but redeclared
* here as it is needed by the dbChannel...CAType macros defined here.
*/
DBCORE_API extern unsigned short dbDBRnewToDBRold[];
/* In the following macros pChan is dbChannel* */
/** \name dbChannel Inspection Macros */
/* evaluates to const char* */
/** \brief Name that defined the channel.
*
* \param pChan Pointer to the dbChannel object.
* \returns const char*
*/
#define dbChannelName(pChan) ((pChan)->name)
/* evaluates to struct dbCommon* */
/** \brief Record the channel connects to.
*
* \param pChan Pointer to the dbChannel object.
* \returns struct dbCommon*
*/
#define dbChannelRecord(pChan) ((pChan)->addr.precord)
/* evaluates to struct dbFldDes* */
/** \brief Field descriptor for the field pointed to.
*
* \param pChan Pointer to the dbChannel object.
* \returns struct dbFldDes*
*/
#define dbChannelFldDes(pChan) ((pChan)->addr.pfldDes)
/* evaluates to long */
/** \brief Number of array elements in the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns long
*/
#define dbChannelElements(pChan) ((pChan)->addr.no_elements)
/* evaluates to short */
/** \brief Data type (DBF type) of the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFieldType(pChan) ((pChan)->addr.field_type)
/* evaluates to short */
/** \brief Request type (DBR type) of the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelExportType(pChan) ((pChan)->addr.dbr_field_type)
/* evaluates to short */
/** \brief CA data type of the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelExportCAType(pChan) (dbDBRnewToDBRold[dbChannelExportType(pChan)])
/* evaluates to short */
/** \brief Field (element if array) size in bytes.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFieldSize(pChan) ((pChan)->addr.field_size)
/* evaluates to long */
/** \brief Array length after filtering.
*
* \param pChan Pointer to the dbChannel object.
* \returns long
*/
#define dbChannelFinalElements(pChan) ((pChan)->final_no_elements)
/* evaluates to short */
/** \brief Data type after filtering.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFinalFieldType(pChan) ((pChan)->final_type)
/* evaluates to short */
/** \brief Channel CA data type after filtering.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFinalCAType(pChan) (dbDBRnewToDBRold[(pChan)->final_type])
/* evaluates to short */
/** \brief Field/element size after filtering, in bytes.
*
* \param pChan Pointer to the dbChannel object.
* \returns short */
#define dbChannelFinalFieldSize(pChan) ((pChan)->final_field_size)
/* evaluates to short */
/** \brief Field special attribute.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelSpecial(pChan) ((pChan)->addr.special)
/* Channel filters do not get to interpose here since there are many
/** \brief Pointer to the record field.
*
* Channel filters do not get to interpose here since there are many
* places where the field pointer is compared with the address of a
* specific record field, so they can't modify the pointer value.
* \param pChan Pointer to the dbChannel object.
* \returns void *
*/
/* evaluates to void* */
#define dbChannelField(pChan) ((pChan)->addr.pfield)
/** \name dbChannel Operation Functions */
/** \brief dbGet() through a dbChannel.
*
* Calls dbGet() for the field that \p chan refers to.
* Only call this routine if the record is already locked.
* \param[in] chan Pointer to the dbChannel object.
* \param[in] type Request type from dbFldTypes.h.
* \param[out] pbuffer Pointer to data buffer.
* \param[in,out] options Request options from dbAccessDefs.h.
* \param[in,out] nRequest Pointer to the element count.
* \param[in] pfl Pointer to a db_field_log or NULL.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelGet(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
/** \brief dbGetField() through a dbChannel.
*
* Get values from a PV through a channel.
* This routine locks the record, calls
* dbChannelGet(), then unlocks the record again.
* \param[in] chan Pointer to the dbChannel object.
* \param[in] type Request type from dbFldTypes.h.
* \param[out] pbuffer Pointer to data buffer.
* \param[in,out] options Request options from dbAccessDefs.h.
* \param[in,out] nRequest Pointer to the element count.
* \param[in] pfl Pointer to a db_field_log or NULL.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelGetField(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
/** \brief dbPut() through a dbChannel.
*
* Put values to a PV through a channel. Only call this routine if the
* record is already locked.
* Calls dbPut() for the field that \p chan refers to.
* \param chan[in] Pointer to the dbChannel object.
* \param type[in] Request type from dbFldTypes.h.
* \param pbuffer[in] Pointer to data buffer.
* \param nRequest[in] Number of elements in pbuffer.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelPut(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
/** \brief dbPutField() through a dbChannel.
*
* Put values to a PV through a channel.
* This routine calls dbPutField() for the field that \p chan refers to.
* \param chan[in] Pointer to the dbChannel object.
* \param type[in] Request type from dbFldTypes.h.
* \param pbuffer[in] Pointer to data buffer.
* \param nRequest[in] Number of elements in pbuffer.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelPutField(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
/** \brief Print report on a channel.
*
* Print information about the channel to stdout.
* \param chan Pointer to the dbChannel object.
* \param level Higher levels may provide more detail.
* \param indent Indent all lines by this many spaces.
*/
DBCORE_API void dbChannelShow(dbChannel *chan, int level,
const unsigned short indent);
/** \brief Print report on a channel's filters.
*
* Print information about the channel's filters to stdout.
* \param chan Pointer to the dbChannel object.
* \param level Higher levels may provide more detail.
* \param indent Indent all lines by this many spaces.
*/
DBCORE_API void dbChannelFilterShow(dbChannel *chan, int level,
const unsigned short indent);
/** \brief Delete a channel.
*
* Releases resources owned by this channel and its filters.
* \param chan Pointer to the dbChannel object.
*/
DBCORE_API void dbChannelDelete(dbChannel *chan);
DBCORE_API void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
/** \name Other routines */
DBCORE_API void dbRegisterFilter(const char *key,
const chFilterIf *fif, void *puser);
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan,
db_field_log *pLogIn);
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan,
db_field_log *pLogIn);
DBCORE_API const chFilterPlugin * dbFindFilter(const char *key, size_t len);
DBCORE_API void dbChannelGetArrayInfo(dbChannel *chan,
void **pfield, long *no_elements, long *offset);

View File

@@ -91,20 +91,25 @@ For example these rates are all valid:
1 second
2 Hertz
The B<PINI> field specifies record processing at initialization. If it is set
to YES during database configuration, the record is processed once at IOC
initialization (before the normal scan tasks are started).
The B<PINI> field specifies record processing at initialization. It can have the
values NO, YES, RUN, RUNNING, PAUSE, and PAUSED. If it is set to YES during
database configuration, the record is processed once at IOC initialization
(before the normal scan tasks are started). For the other values see
L<menuPini.dbd|menuPini> for more details.
The B<PHAS> field orders the records within a specific SCAN group. This is not
meaningful for passive records. All records of a specified phase are processed
before those with higher phase number. It is generally better practice to use
linked passive records to enforce the order of processing rather than a phase
number.
The B<PHAS> field orders the records processed within a specific SCAN group or
PINI processing phase. All records of a specified phase are processed before
those with higher phase number. It is generally better practice to use linked
passive records to enforce the order of processing rather than a phase number.
If the PINI field is set to NO, the PHAS field is not meaningful for passive
records.
The B<EVNT> field specifies an event number. This event number is used if the
SCAN field is set to C<Event>. All records with scan type C<Event> and the
same EVNT value will be processed when a call to post_event for EVNT is made.
The call to post_event is: post_event(short event_number).
The B<EVNT> field specifies an event name or number. This event identifier is
used if the SCAN field is set to C<Event>. All records with scan type C<Event>
and the same EVNT value will be processed when that event is signalled by other
software running in the IOC, either by calling C<post_event(int event)> for
numeric events, or by calling C<postEvent()> with an event handle previously
looked up using C<eventNameToHandle()> for named events.
The B<PRIO> field specifies the scheduling priority for processing records
with SCAN=C<I/O Event> and asynchronous record completion tasks.
@@ -230,6 +235,8 @@ The B<SPVT> field is for internal use by the scanning system.
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
promptgroup("10 - Common")
interest(1)
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
@@ -456,9 +463,10 @@ record. If left empty, the record is placed in group C<DEFAULT>.
The B<ASP> field is private for use by the access security system.
The B<DISP> field controls whether puts from outside the IOC are allowed to
modify the fields of this record at all. If the field is set to TRUE all puts
directed to this record are ignored, except for puts to the field DISP itself.
The B<DISP> field can be set to a non-zero value to reject puts from outside of
the IOC (i.e. via Channel Access or PV Access) to any field of the record other
than to the DISP field itself. Field changes and record processing can still be
instigated from inside the IOC using DB links and the IOC scan mechanisms.
The B<DTYP> field specifies the device type for the record. Most record types
have their own set of device types which are specified in the IOC's database
@@ -489,17 +497,37 @@ The B<TIME> field holds the time stamp when this record was last processed.
The B<UTAG> field can be used to hold a site-specific 64-bit User Tag value
that is associated with the record's time stamp.
The B<TSE> field indicates the mechanism to use to get the time stamp. '0' -
call get time as before '-1' - call the time stamp driver and use the best
source available. '-2' - the device support sets the time stamp and optional
user tag from the hardware. Values between 1-255 request the time of the last
occurance of a generalTime event.
The B<TSE> field value indicates the mechanism to use to get the time stamp:
=over
=item *
C< 0> E<mdash> Get the current time as normal
=item *
C<-1> E<mdash> Ask the time stamp driver for its best source of the current time, if
available.
=item *
C<-2> E<mdash> Device support sets the time stamp and the optional User Tag from the
hardware.
=item *
Positive values (normally between 1-255) get the time of the last occurance of
the numbered generalTime event.
=back
The B<TSEL> field contains an input link for obtaining the time stamp. If this
link points to the TIME field of a record then the time stamp and user tag of
link points to the TIME field of a record then the time stamp and User Tag of
that record are copied directly into this record (Channel Access links can only
copy the time stamp). If the link points to any other field, that field's value
is read and stored in the TSE field which is then used to acquire a time stamp.
copy the time stamp, not the User Tag). If the link points to any other field,
that field's value is read and stored in the TSE field which is then used to
provide the time stamp as described above.
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, UTAG, TSE, TSEL

View File

@@ -3,7 +3,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Input Record Types
=title Fields Common to Input Record Types
This section describes fields that are found in many input record types.
These fields usually have the same meaning whenever they are used.
@@ -206,3 +206,5 @@ If SIMM is not YES, NO or RAW, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back
=cut

View File

@@ -3,7 +3,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Output Record Types
=title Fields Common to Output Record Types
This section describes fields that are found in many output record types.
These fields usually have the same meaning whenever they are used.
@@ -237,3 +237,5 @@ If SIMM is not YES or NO, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back
=cut

View File

@@ -3,7 +3,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to All Record Types
=title Fields Common to All Record Types
This section contains a description of the fields that are common to all record
types. These fields are defined in dbCommon.dbd.

View File

@@ -27,6 +27,7 @@
#include "dbFldTypes.h"
#include "dbLink.h"
#include "link.h"
#include "errlog.h"
/**************************** Convert functions ****************************/
@@ -153,7 +154,7 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
const char *pstr = plink->value.constantStr;
size_t len;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
len = strlen(pstr);
@@ -178,26 +179,36 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
const char *pstr = plink->value.constantStr;
long status;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
return dbLSConvertJSON(pstr, pbuffer, size, plen);
status = dbLSConvertJSON(pstr, pbuffer, size, plen);
if (status)
errlogPrintf("... while parsing link %s.%s\n",
plink->precord->name, dbLinkFieldName(plink));
return status;
}
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
const char *pstr = plink->value.constantStr;
long status;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
/* Choice values must be numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
dbrType = DBF_USHORT;
return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
status = dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
if (status)
errlogPrintf("... while parsing link %s.%s\n",
plink->precord->name, dbLinkFieldName(plink));
return status;
}
static long dbConstGetNelements(const struct link *plink, long *nelements)

View File

@@ -30,10 +30,12 @@ typedef struct parseContext {
} parseContext;
static int dbcj_null(void *ctx) {
errlogPrintf("dbConvertJSON: Null objects not supported\n");
return 0; /* Illegal */
}
static int dbcj_boolean(void *ctx, int val) {
errlogPrintf("dbConvertJSON: Boolean not supported\n");
return 0; /* Illegal */
}
@@ -50,10 +52,6 @@ static int dbcj_integer(void *ctx, long long num) {
return 1;
}
static int dblsj_integer(void *ctx, long long num) {
return 0; /* Illegal */
}
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
@@ -66,7 +64,9 @@ static int dbcj_double(void *ctx, double num) {
return 1;
}
static int dblsj_double(void *ctx, double num) {
static int dblsj_number(void *ctx, const char *val, size_t len) {
errlogPrintf("dbLSConvertJSON: Numeric value %.*s provided, string expected\n",
(int)len, val);
return 0; /* Illegal */
}
@@ -78,7 +78,8 @@ static int dbcj_string(void *ctx, const unsigned char *val, size_t len) {
* metadata about the field than we have available at the moment.
*/
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
errlogPrintf("dbConvertJSON: String \"%.*s\" provided, numeric value expected\n",
(int)len, val);
return 0; /* Illegal */
}
@@ -97,11 +98,6 @@ static int dblsj_string(void *ctx, const unsigned char *val, size_t len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: dblsj_string dbrType " ERL_ERROR "\n");
return 0; /* Illegal */
}
if (parser->elems > 0) {
if (len > parser->dbrSize - 1)
len = parser->dbrSize - 1;
@@ -118,14 +114,6 @@ static int dbcj_start_map(void *ctx) {
return 0; /* Illegal */
}
static int dbcj_map_key(void *ctx, const unsigned char *key, size_t len) {
return 0; /* Illegal */
}
static int dbcj_end_map(void *ctx) {
return 0; /* Illegal */
}
static int dbcj_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
@@ -135,32 +123,30 @@ static int dbcj_start_array(void *ctx) {
return (parser->depth == 1);
}
static int dbcj_end_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
parser->depth--;
return (parser->depth == 0);
}
static yajl_callbacks dbcj_callbacks = {
dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
dbcj_start_map, NULL, NULL,
dbcj_start_array, NULL
};
long dbPutConvertJSON(const char *json, short dbrType,
void *pdest, long *pnRequest)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
long status;
if(INVALID_DB_REQ(dbrType))
if (INVALID_DB_REQ(dbrType)) {
errlogPrintf("dbConvertJSON: Invalid dbrType %d\n", dbrType);
return S_db_badDbrtype;
}
if (!jlen) {
*pnRequest = 0;
return 0;
}
parser->depth = 0;
parser->dbrType = dbrType;
@@ -168,10 +154,11 @@ long dbPutConvertJSON(const char *json, short dbrType,
parser->pdest = pdest;
parser->elems = *pnRequest;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dbcj_callbacks, &dbcj_alloc, parser);
if (!yh)
yh = yajl_alloc(&dbcj_callbacks, NULL, parser);
if (!yh) {
errlogPrintf("dbConvertJSON: out of memory\n");
return S_db_noMemory;
}
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
if (ys == yajl_status_ok)
@@ -183,15 +170,13 @@ long dbPutConvertJSON(const char *json, short dbrType,
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
fprintf(stderr, "dbConvertJSON: %s\n", err);
yajl_free_error(yh, err);
default: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
errlogPrintf("dbConvertJSON: %s", err);
yajl_free_error(yh, err);
status = S_db_badField;
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);
@@ -200,16 +185,15 @@ long dbPutConvertJSON(const char *json, short dbrType,
static yajl_callbacks dblsj_callbacks = {
dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
dbcj_null, dbcj_boolean, NULL, NULL, dblsj_number, dblsj_string,
dbcj_start_map, NULL, NULL,
dbcj_start_array, NULL
};
long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
epicsUInt32 *plen)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
@@ -226,10 +210,11 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
parser->pdest = pdest;
parser->elems = 1;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dblsj_callbacks, &dbcj_alloc, parser);
if (!yh)
yh = yajl_alloc(&dblsj_callbacks, NULL, parser);
if (!yh) {
errlogPrintf("dbLSConvertJSON: out of memory\n");
return S_db_noMemory;
}
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
@@ -239,15 +224,13 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
yajl_free_error(yh, err);
default: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
errlogPrintf("dbLSConvertJSON: %s", err);
yajl_free_error(yh, err);
status = S_db_badField;
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);

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,22 +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 */
@@ -100,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
@@ -121,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 ) {
@@ -138,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;
@@ -216,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);
}
@@ -225,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 ) {
@@ -317,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;
@@ -329,7 +321,6 @@ dbEventCtx db_init_events (void)
evUser->flowCtrlMode = FALSE;
evUser->extraLaborBusy = FALSE;
evUser->pSuicideEvent = NULL;
return (dbEventCtx) evUser;
fail:
if(evUser->lock)
@@ -338,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);
@@ -403,7 +392,6 @@ void db_close_events (dbEventCtx ctx)
epicsEventDestroy(evUser->pexitsem);
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
epicsMutexUnlock (stopSync);
@@ -460,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;
}
@@ -578,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 );
}
}
/*
@@ -731,7 +718,7 @@ static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
/* don't make a copy yet, just reference the field value */
pLog->u.r.field = dbChannelField(chan);
/* indicate field value still owned by record */
pLog->u.r.dtor = NULL;
pLog->dtor = NULL;
/* no private data yet, may be set by a filter */
pLog->u.r.pvt = NULL;
}
@@ -789,6 +776,18 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
LOCKEVQUE (ev_que);
/* if we have an event on the queue and both the last
* event on the queue and the current event reference
* a record field, simply ignore duplicate events.
*/
if (pevent->npend > 0u
&& !dbfl_has_copy(*pevent->pLastLog)
&& !dbfl_has_copy(pLog)) {
db_delete_field_log(pLog);
UNLOCKEVQUE (ev_que);
return;
}
/*
* add to task local event que
*/
@@ -921,9 +920,7 @@ void db_post_single_event (dbEventSubscription event)
*/
static int event_read ( struct event_que *ev_que )
{
db_field_log *pfl;
void ( *user_sub ) ( void *user_arg, struct dbChannel *chan,
int eventsRemaining, db_field_log *pfl );
int notifiedRemaining = 0;
/*
* evUser ring buffer must be locked for the multiple
@@ -943,19 +940,8 @@ 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];
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;
}
int eventsRemaining;
db_field_log *pfl = ev_que->valque[ev_que->getix];
/*
* Simple type values queued up for reliable interprocess
@@ -965,12 +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 );
/*
* 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
@@ -982,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);
@@ -997,41 +976,32 @@ static int event_read ( struct event_que *ev_que )
if (pfl) {
/* Issue user callback */
( *user_sub ) ( pevent->user_arg, pevent->chan,
ev_que->evque[ev_que->getix] != EVENTQEMPTY, pfl );
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);
}
if(notifiedRemaining && !ev_que->possibleStall) {
ev_que->possibleStall = 1;
errlogPrintf(ERL_WARNING " dbEvent possible queue stall\n");
}
UNLOCKEVQUE (ev_que);
return DB_EVENT_OK;
}
/*
* EVENT_TASK()
*/
static void event_task (void *pParm)
{
struct event_user * const evUser = (struct event_user *) pParm;
@@ -1072,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 );
@@ -1201,7 +1183,7 @@ void db_delete_field_log (db_field_log *pfl)
{
if (pfl) {
/* Free field if reference type field log and dtor is set */
if (pfl->type == dbfl_type_ref && pfl->u.r.dtor) pfl->u.r.dtor(pfl);
if (pfl->type == dbfl_type_ref && pfl->dtor) pfl->dtor(pfl);
/* Free the field log chunk */
freeListFree(dbevFieldLogFreeList, pfl);
}

View File

@@ -14,7 +14,6 @@
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
@@ -24,6 +23,7 @@
#include "dbDefs.h"
#include "epicsConvert.h"
#include "epicsStdlib.h"
#include "epicsStdio.h"
#include "errlog.h"
#include "errMdef.h"
@@ -1335,24 +1335,26 @@ static long cvt_menu_st(
epicsEnum16 *from,
char *to,
const dbAddr *paddr)
{
dbFldDes *pdbFldDes;
dbMenu *pdbMenu;
char **papChoiceValue;
char *pchoice;
{
dbFldDes *pdbFldDes;
dbMenu *pdbMenu;
if(! paddr
|| !(pdbFldDes = paddr->pfldDes)
|| !(pdbMenu = (dbMenu *)pdbFldDes->ftPvt)
|| *from>=pdbMenu->nChoice
|| !(papChoiceValue = pdbMenu->papChoiceValue)
|| !(pchoice=papChoiceValue[*from])) {
recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_menu_st)");
return(S_db_badChoice);
if (!paddr ||
!(pdbFldDes = paddr->pfldDes) ||
!(pdbMenu = (dbMenu *)pdbFldDes->ftPvt)) {
recGblDbaddrError(S_db_badChoice, paddr, "dbFastLinkConv(cvt_menu_st)");
return S_db_badChoice;
}
strncpy(to,pchoice,MAX_STRING_SIZE);
return(0);
}
if (*from < pdbMenu->nChoice) {
strncpy(to, pdbMenu->papChoiceValue[*from], MAX_STRING_SIZE);
}
else {
/* Convert out-of-range values to numeric strings */
epicsSnprintf(to, MAX_STRING_SIZE, "%u", *from);
}
return 0;
}
/* Get Device to String */
@@ -1366,10 +1368,17 @@ static long cvt_device_st(
char **papChoice;
char *pchoice;
if(!paddr
|| !(pdbFldDes = paddr->pfldDes)
|| !(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt)
|| *from>=pdbDeviceMenu->nChoice
if (!paddr
|| !(pdbFldDes = paddr->pfldDes)) {
recGblDbaddrError(S_db_errArg, paddr, "dbFastLinkConv(cvt_device_st)");
return S_db_errArg;
}
if (!(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt)) {
/* Valid, record type has no device support */
*to = '\0';
return 0;
}
if (*from >= pdbDeviceMenu->nChoice
|| !(papChoice= pdbDeviceMenu->papChoice)
|| !(pchoice=papChoice[*from])) {
recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_device_st)");

View File

@@ -8,10 +8,13 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include "iocsh.h"
#include "callback.h"
#include "dbAccess.h"
#include "dbStaticPvt.h"
#include "dbBkpt.h"
#include "dbCaTest.h"
#include "dbEvent.h"
@@ -28,129 +31,162 @@
DBCORE_API extern int callbackParallelThreadsDefault;
/* dbLoadDatabase */
static const iocshArg dbLoadDatabaseArg0 = { "file name",iocshArgString};
static const iocshArg dbLoadDatabaseArg1 = { "path",iocshArgString};
static const iocshArg dbLoadDatabaseArg0 = { "file name",iocshArgStringPath};
static const iocshArg dbLoadDatabaseArg1 = { "path",iocshArgStringPath};
static const iocshArg dbLoadDatabaseArg2 = { "substitutions",iocshArgString};
static const iocshArg * const dbLoadDatabaseArgs[3] =
{
&dbLoadDatabaseArg0,&dbLoadDatabaseArg1,&dbLoadDatabaseArg2
};
static const iocshFuncDef dbLoadDatabaseFuncDef =
{"dbLoadDatabase",3,dbLoadDatabaseArgs};
static const iocshFuncDef dbLoadDatabaseFuncDef = {
"dbLoadDatabase",
3,
dbLoadDatabaseArgs,
"Load the given .dbd file, with 'path' added as a search path, with the given substitutions.\n\n"
"Substitutions are usually not needed for .dbd files.\n\n"
"Example: dbLoadDatabase dbd/my.dbd\n",
};
static void dbLoadDatabaseCallFunc(const iocshArgBuf *args)
{
iocshSetError(dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval));
}
/* dbLoadRecords */
static const iocshArg dbLoadRecordsArg0 = { "file name",iocshArgString};
static const iocshArg dbLoadRecordsArg0 = { "file name",iocshArgStringPath};
static const iocshArg dbLoadRecordsArg1 = { "substitutions",iocshArgString};
static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoadRecordsArg1};
static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs};
static const iocshFuncDef dbLoadRecordsFuncDef = {
"dbLoadRecords",
2,
dbLoadRecordsArgs,
"Load the given .db file, with the given substitutions.\n\n"
"Substitutions should be given in the format 'var1=value1,var2=value2'.\n\n"
"Example: dbLoadRecords db/myRecords.db 'user=myself,host=myhost'\n",
};
static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
{
iocshSetError(dbLoadRecords(args[0].sval,args[1].sval));
}
/* dbb */
static const iocshArg dbbArg0 = { "record name",iocshArgString};
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 */
static const iocshArg dbdArg0 = { "record name",iocshArgString};
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);}
/* dbc */
static const iocshArg dbcArg0 = { "record name",iocshArgString};
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",iocshArgString};
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",iocshArgString};
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);}
/* dbap */
static const iocshArg dbapArg0 = { "record name",iocshArgString};
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 */
static const iocshArg dbcarArg0 = { "record name",iocshArgString};
static const iocshArg dbcarArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbcarArg1 = { "level",iocshArgInt};
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);
}
/* dbjlr */
static const iocshArg dbjlrArg0 = { "record name",iocshArgString};
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);
}
/* dbel */
static const iocshArg dbelArg0 = { "record name",iocshArgString};
static const iocshArg dbelArg0 = { "record name",iocshArgStringRecord};
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);
}
/* dba */
static const iocshArg dbaArg0 = { "record name",iocshArgString};
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 */
@@ -160,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);
@@ -170,79 +211,102 @@ 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",iocshArgString};
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",iocshArgString};
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 */
static const iocshArg dbgfArg0 = { "record name",iocshArgString};
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 */
static const iocshArg dbpfArg0 = { "record name",iocshArgString};
static const iocshArg dbpfArg0 = { "record name",iocshArgStringRecord};
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);}
/* dbpr */
static const iocshArg dbprArg0 = { "record name",iocshArgString};
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);}
/* dbtr */
static const iocshArg dbtrArg0 = { "record name",iocshArgString};
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);}
/* dbtgf */
static const iocshArg dbtgfArg0 = { "record name",iocshArgString};
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 */
static const iocshArg dbtpfArg0 = { "record name",iocshArgString};
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);}
@@ -257,33 +321,43 @@ 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",iocshArgString};
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 */
static const iocshArg pftArg0 = { "record name",iocshArgString};
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);}
/* dbtpn */
static const iocshArg dbtpnArg0 = { "record name",iocshArgString};
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);}
@@ -298,36 +372,45 @@ 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);}
/* tpn */
static const iocshArg tpnArg0 = { "record name",iocshArgString};
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);}
/* dblsr */
static const iocshArg dblsrArg0 = { "record name",iocshArgString};
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);}
@@ -335,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);
@@ -348,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);
@@ -360,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);}
@@ -392,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);
@@ -405,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);
@@ -418,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);
@@ -431,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);
@@ -440,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);
@@ -452,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);
@@ -465,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);
@@ -478,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);
@@ -487,6 +566,8 @@ static void dbStateShowAllCallFunc (const iocshArgBuf *args)
void dbIocRegister(void)
{
iocshCompleteRecord = &dbCompleteRecord;
iocshRegister(&dbbFuncDef,dbbCallFunc);
iocshRegister(&dbdFuncDef,dbdCallFunc);
iocshRegister(&dbcFuncDef,dbcCallFunc);

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);
@@ -410,8 +412,21 @@ DBCORE_API long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
DBCORE_API long dbGetNelements(const struct link *plink, long *pnElements);
DBCORE_API int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
DBCORE_API int dbGetLinkDBFtype(const struct link *plink);
/** \brief Fetch current value from link.
* \param dbrType Database DBR code
* \param pbuffer Destination buffer
* \param nRequest If !NULL. Caller initializes with number of elements requested,
* On success, set to number of elements written to pbuffer.
* \return 0 on success
*
* When called with `nRequest==NULL`, treated as a request for one (1)
* element.
*
* see lset::getValue
*/
DBCORE_API long dbTryGetLink(struct link *, short dbrType, void *pbuffer,
long *nRequest);
/** see dbTryGetLink() */
DBCORE_API long dbGetLink(struct link *, short dbrType, void *pbuffer,
long *options, long *nRequest);
DBCORE_API long dbGetControlLimits(const struct link *plink, double *low,

View File

@@ -121,8 +121,7 @@ void dbLockIncRef(lockSet* ls)
{
int cnt = epicsAtomicIncrIntT(&ls->refcount);
if(cnt<=1) {
errlogPrintf("dbLockIncRef(%p) on dead lockSet. refs: %d\n", ls, cnt);
cantProceed(NULL);
cantProceed("dbLockIncRef(%p) on dead lockSet. refs: %d\n", ls, cnt);
}
}
@@ -145,9 +144,8 @@ void dbLockDecRef(lockSet *ls)
epicsMutexMustLock(ls->lock);
if(ellCount(&ls->lockRecordList)!=0) {
errlogPrintf("dbLockDecRef(%p) would free lockSet with %d records\n",
ls, ellCount(&ls->lockRecordList));
cantProceed(NULL);
cantProceed("dbLockDecRef(%p) would free lockSet with %d records\n",
ls, ellCount(&ls->lockRecordList));
}
epicsMutexUnlock(ls->lock);
@@ -421,9 +419,8 @@ retry:
#ifdef LOCKSET_DEBUG
if(plock->owner) {
if(plock->owner!=myself || plock->ownercount<1) {
errlogPrintf("dbScanLockMany(%p) ownership violation %p (%p) %u\n",
locker, plock->owner, myself, plock->ownercount);
cantProceed(NULL);
cantProceed("dbScanLockMany(%p) ownership violation %p (%p) %u\n",
locker, plock->owner, myself, plock->ownercount);
}
plock->ownercount++;
} else {
@@ -444,8 +441,7 @@ retry:
/* if we have at least one lockRecord, then we will always lock
* at least its present lockSet
*/
errlogPrintf("dbScanLockMany(%p) didn't lock anything\n", locker);
cantProceed(NULL);
cantProceed("dbScanLockMany(%p) didn't lock anything\n", locker);
}
}
@@ -602,17 +598,15 @@ void dbLockSetMerge(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
#ifdef LOCKSET_DEBUG
if(locker && (A->owner!=myself || B->owner!=myself)) {
errlogPrintf("dbLockSetMerge(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->owner, B->owner, myself);
cantProceed(NULL);
cantProceed("dbLockSetMerge(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->owner, B->owner, myself);
}
#endif
if(locker && (A->ownerlocker!=locker || B->ownerlocker!=locker)) {
errlogPrintf("dbLockSetMerge(%p,\"%s\",\"%s\") locker ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->ownerlocker, B->ownerlocker, locker);
cantProceed(NULL);
cantProceed("dbLockSetMerge(%p,\"%s\",\"%s\") locker ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->ownerlocker, B->ownerlocker, locker);
}
if(A==B)
@@ -688,19 +682,17 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
#ifdef LOCKSET_DEBUG
if(ls->owner!=myself || psecond->lset->plockSet->owner!=myself) {
errlogPrintf("dbLockSetSplit(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
ls->owner, psecond->lset->plockSet->owner, myself);
cantProceed(NULL);
cantProceed("dbLockSetSplit(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
ls->owner, psecond->lset->plockSet->owner, myself);
}
#endif
/* lockset consistency violation */
if(ls!=psecond->lset->plockSet) {
errlogPrintf("dbLockSetSplit(%p,\"%s\",\"%s\") consistency violation %p %p\n",
locker, pfirst->name, psecond->name,
pfirst->lset->plockSet, psecond->lset->plockSet);
cantProceed(NULL);
cantProceed("dbLockSetSplit(%p,\"%s\",\"%s\") consistency violation %p %p\n",
locker, pfirst->name, psecond->name,
pfirst->lset->plockSet, psecond->lset->plockSet);
}
@@ -877,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(

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