Merge ~anj/epics-base/+git/base-7.0:loadable-err-syms into ~epics-core/epics-base/+git/epics-base:7.0

Proposed by Andrew Johnson
Status: Rejected
Rejected by: Andrew Johnson
Proposed branch: ~anj/epics-base/+git/base-7.0:loadable-err-syms
Merge into: ~epics-core/epics-base/+git/epics-base:7.0
Diff against target: 1562 lines (+606/-297)
28 files modified
configure/CONFIG (+4/-4)
configure/RULES_BUILD (+1/-24)
configure/RULES_FILE_TYPE (+11/-9)
documentation/RELEASE_NOTES.html (+30/-1)
modules/database/src/ioc/Makefile (+5/-0)
modules/database/src/ioc/db/Makefile (+2/-1)
modules/database/src/ioc/db/dbIocRegister.c (+6/-1)
modules/database/src/ioc/dbStatic/Makefile (+6/-1)
modules/libcom/configure/CONFIG_LIBCOM_MODULE (+4/-0)
modules/libcom/configure/Makefile (+1/-0)
modules/libcom/configure/RULES_LIBCOM (+38/-0)
modules/libcom/src/Makefile (+8/-1)
modules/libcom/src/as/Makefile (+3/-1)
modules/libcom/src/env/Makefile (+0/-2)
modules/libcom/src/error/Makefile (+4/-12)
modules/libcom/src/error/RULES (+1/-4)
modules/libcom/src/error/errMdef.h (+4/-6)
modules/libcom/src/error/errSymLib.c (+189/-167)
modules/libcom/src/error/errSymTbl.h (+14/-14)
modules/libcom/src/error/errlog.c (+1/-3)
modules/libcom/src/error/makeStatTbl.pl (+151/-39)
modules/libcom/src/iocsh/libComRegister.c (+18/-3)
modules/libcom/src/misc/Makefile (+3/-1)
modules/libcom/src/osi/Makefile (+4/-1)
modules/libcom/src/pool/Makefile (+3/-2)
modules/libcom/test/Makefile (+5/-0)
modules/libcom/test/epicsRunLibComTests.c (+2/-0)
modules/libcom/test/errSymTest.c (+88/-0)
Reviewer Review Type Date Requested Status
Andrew Johnson Disapprove
mdavidsaver Needs Fixing
Review via email: mp+361344@code.launchpad.net

Description of the change

This branch changes the error symbol registration code in libCom so additional error symbols can be registered by modules and applications as necessary. It also restores the error symbols defined by the IOC subsystems which were lost when we split off the database module, calling the newly-generated registration routine from the same code that registers iocsh commands.

Macros are provided so external code can easily detect whether their libCom version supports this.

Still to do:
* Write release notes.
* Instrument an external module to make use of this (ipac)
* No self-tests yet...

Questions:

There is no unregistration (never has been), but re-registering an existing symbol is (intended to be) silent. Is this acceptable?

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

Modifications needed for drvIpac to register its own symbols were mostly as expected, wrapped in
  ifdef FEATURE_LOADABLE_ERR_SYMS
for backwards compatibility. Had to add comments to my #define M_xxx symbol definitions to ensure they matched what the script was looking for; could make comments optional for M_xxx symbols to avoid having to do that.

91b098c... by Andrew Johnson

To avoid linking issues on Windows, make errSymsAdd() static

The generated errSyms.c file must now be #included by the source
file that calls the now static errSymsAdd() routine.
This also requires a dependency rule to ensure the .c file gets
generated early enough in the build.

6ae8c62... by Andrew Johnson

Release notes and conversion instructions

960c9e7... by Andrew Johnson

Added unit tests in errSymTest.c

Revision history for this message
Andrew Johnson (anj) wrote :

Added basic unit tests for symbol registration and lookup functionality.

I think this is done for now.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

So I have to ask. As this is effectively new functionality as far as external modules are concerned. Do we want to expose another code generator just for error message strings?

As the error code are already hard-coded in headers, why not just add

> void errSymAdd(long status, const char *message);

Which would be called in registrar functions.

Please understand, I'm not saying "no" to this approach. I'd just like to have the design discussion.

Also, the diff shows some seemingly unrelated makefile changes (antelope/flex rules).

Revision history for this message
Ralph Lange (ralph-lange) wrote :

Thanks a lot, Andrew, for jumping in.
I know this was on my list, I had started to work on it, and obviously lost that working copy at some point. (Definitely when my laptop was replaced a month ago.)

IMHO Michael's questions are valid, though.
From a module author perspective, I would start wishing for a code generator as soon as I have to register more than ~5-10 symbols manually in my registrar. How many modules define more? Close to none, I guess.

Also, if we seriously export this mechanism to external modules, I think the module itself should first register with its name and get a module code in return that it uses for registering symbols (to avoid the unavoidable clashes in the hardcoded module numbers).

Revision history for this message
Andrew Johnson (anj) wrote :
Download full text (5.3 KiB)

So the trigger behind this was a question from a colleague here who has been maintaining the epvxi (EPICS VXI) code that we still use here. The epvxi module was originally written by Jeff Hill and was part of Base back in 3.13 days, and as such it has its own series of error status values (34 of them), which were included in the generated errSymTbl.c file. The epvxi code calls the errPrintf() routine to display its errors, which takes a status value and shows the associated message. When we updated our VXI systems from 3.13 to 3.14 they lost the ability to display the epvxi error messages properly.

He asked me more recently how to fix this in 3.14.12.x, and I suggested he try the routine
    int errSymbolAdd(long errNum, const char *name);
which was declared in errMdef.h (although we moved it to errSymTbl.h in 7.0.2). Unfortunately this routine only adds the symbol to an internal linked list and not to the hash table that actually gets used for symbol lookups, so it doesn't do what we'd want it to and there's no way to fix that externally. That prompted me to work on this when I had some time over Christmas.

So my requirement was to be able to support existing header files with error symbol definitions and just require calling a registration routine to add them to the errSym hash-table. I wanted to impose minimal work on the module maintainer without breaking a build against older Base releases that don't have the new APIs. I regarded this more as restoring capabilities that we lost when we unbundled the hardware-specific modules (and again when we split Base into modules) than as adding new functionality.

So why didn't I just fix the above errSymbolAdd() routine? Well nobody can be relying on that API at the moment, since it doesn't actually work, so that gives us license to change the prototype. I also wanted to add a separate string to hold the "S_<module>_<error>" symbol name for display by the errSymDump() routine (the const char *name argument is actually the error message text), which that older interface didn't allow for.

Finally I wanted to try to ensure that all the strings would be stored in the program text and not have to be needlessly copied into RAM at registration time. I decided it would be simpler and faster to use an API that takes a const ERRSYMBOL pointer with all of the information included in that one object (this structure already existed in the old API, I just extended it) and to store that pointer.

I wouldn't object to adding an API for registering an error symbol that would take the 3 arguments separately, but in practice I don't see a great deal of difference:

    static const ERRSYMBOL es_one = {S_x_one, "S_x_one", "Error one"};
    errSymAdd(&es_one);

vs

    errSymAdd(S_x_one, "S_x_one", "Error one");

There's no way to mark that we store the string pointers and force the user to not generate those strings (or the ERRSYMBOL object) in a reusable buffer. I see that as a bit less likely when they have to pass in an object pointer, but I admit that's not guaranteed there either. In most cases you'll be registering multiple symbols so you'd usually call the other API to pass in an ERRSYMTAB which has an array...

Read more...

Revision history for this message
Ralph Lange (ralph-lange) wrote :

Re: module number clashes
I think a run time test for clashes would be good and useful for the existing modules (that blindly claim a number).
We might still want to add a call to get a unique module number, so that new developments (or fixes for discovered clashes) have the chance to handle this issue smarter.
Also, the dump could use module names for those that did register.

Revision history for this message
Ralph Lange (ralph-lange) wrote :

Having every IOC use a different number for the same error would be a debugging nightmare.
Modules should try to register their claimed number, and get a different one back if it is taken. (Maybe on a different "page", e.g. claimed+200 or similar.)

4522666... by Andrew Johnson

errSymAdd: Add duplicate value check, return error on rejection

Also switches to calloc() instead of callocMustSucceed()

6e48e78... by Andrew Johnson

Register M_<module> symbols too

Adds errMDef.h to the headers parsed.

Revision history for this message
Andrew Johnson (anj) wrote :

More commits. I am now checking for duplicate module numbers by registering the M_xxx symbols and their status values too. I added code to errSymAdd() that rejects the re-registration of a status value if the symbol names (i.e. the S_xxx_yyyy identifiers) are different. I assume the message texts for the same symbol name should be interchangeable even it they aren't identical.

I haven't added an API for handing out module numbers, I'm hoping that error messages at registration time will be enough to handle the case of clashing module numbers, e.g:

  errSymAdd: Status value (1234,1) is S_test_bug "Test Bug"
    so can't be registered as S_check_bug "Check bug"

Should the generated registration code abort/suspend if it gets a rejection, preventing IOC startup? It doesn't yet.

If we don't add an API fixing a rejection will require manual intervention (and rebuilding at least one module), but this should be very rare. There aren't many modules that create their own status codes anyway. Maybe we should have an EPICS Module Numbering Authority (like IANA)?

I'm concerned that making module numbers dynamic by changing the M_<module> constants into a read of an extern long might trigger symbol decoration problems on Windows. I don't want to have to fix more of those kinds of problems in other people's downstream code...

Revision history for this message
Ralph Lange (ralph-lange) wrote :

As a lightweight alternative to creating an international institution:
Would adding a column in the EPICS Module database (on epics-controls.org) be a start?

d4ea352... by Andrew Johnson

Cosmetic touches

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

So I wondered, who all is using errSymLookup() outside of Base?
The newer errSymMsg() doesn't yet have any outside users.

A github search shows:

https://github.com/mdavidsaver/catvs
https://github.com/paulscherrerinstitute/regdev
https://github.com/mdavidsaver/pyDevSup
https://github.com/epics-modules/devlib2
https://github.com/epics-modules/mrfioc2

also ca-gateway

So, mostly me.

A google search doesn't turn up anything more.

https://www.google.com/search?q="errSymLookup"+-"errSymLib"+-"makeSymTbl"+-"errSymTbl"+-"epics-base"

Of course this isn't going to find code which isn't public.
I would expect a similar ratio there though.

I see this as a commentary on the utility of these error message strings.

Revision history for this message
Andrew Johnson (anj) wrote :

The main entry points used by older drivers were errMessage() and errPrintf() both of which take a status value argument and display/log the associated string. By having a central registry of message strings a module can display the strings from the modules it calls or pass on the error status values without having to identify them specifically. In C++ code an exception class provides a very similar use-case.

For example in Asyn the ni1014Config() routine (a startup script command for a VME GPIB card) has 3 calls to errMessage(status,"ni1014: <devLib routine name>") that display errors from devLib and are followed by the command aborting. The epvxi module that I was talking about above has a total of 94 calls to the above err(Message|Printf) routines, and replacing them would not be a trivial task.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

I don't like the idea of having to adjudicate error code conflicts between two modules which would otherwise not need to be aware of each other. At minimum, this API needs a redesign to avoid conflicts. Either by choosing codes at runtime (a la. asynPortDriver), or otherwise ensuring uniqueness. (Maybe by using/abusing a pointer address as a code?)

Maybe a reasonable comparison is with the errno codes and perror()/strerror() API. Which looks quite similar. There is no standard way to add custom codes.

I recall reading that some Linux dev. were thinking about ways to provide more info than errno can reasonably contain. This might be worth checking to see if anything came of this.

review: Needs Fixing
Revision history for this message
Andrew Johnson (anj) wrote :

So I discovered that external code built against 3.14 *can* add error symbols at runtime, it just has to do so by calling errSymbolAdd() for each symbol before errlogInit() first gets run, which may be from an explicit call in the startup script, at iocInit, or whenever some code calls one of the errlogPrintf() functions. A C++ static constructor should be fine for registering symbols.

We are now using that approach for the epvxi module, so I am withdrawing this merge proposal.

review: Disapprove

Unmerged commits

d4ea352... by Andrew Johnson

Cosmetic touches

6e48e78... by Andrew Johnson

Register M_<module> symbols too

Adds errMDef.h to the headers parsed.

4522666... by Andrew Johnson

errSymAdd: Add duplicate value check, return error on rejection

Also switches to calloc() instead of callocMustSucceed()

960c9e7... by Andrew Johnson

Added unit tests in errSymTest.c

6ae8c62... by Andrew Johnson

Release notes and conversion instructions

91b098c... by Andrew Johnson

To avoid linking issues on Windows, make errSymsAdd() static

The generated errSyms.c file must now be #included by the source
file that calls the now static errSymsAdd() routine.
This also requires a dependency rule to ensure the .c file gets
generated early enough in the build.

dd2350f... by Andrew Johnson

Define FEATURE_LOADABLE_ERR_SYMS so apps can build conditionally

This both is a macro defined in errMdef.h and a Makefile variable.

9747f48... by Andrew Johnson

Register "errSymDump" as an iocsh command

c381445... by Andrew Johnson

Add error symbol registration for the database module

bf088cd... by Andrew Johnson

Name headers containing error symbols in their Makefile fragment

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/configure/CONFIG b/configure/CONFIG
2index e40d3f5..48acebc 100644
3--- a/configure/CONFIG
4+++ b/configure/CONFIG
5@@ -93,11 +93,13 @@ endif # ifdef T_A
6
7 # Include <top>/cfg/CONFIG* definitions from tops defined in RELEASE* files
8 #
9+TOP_CFG_CONFIGS = $(wildcard $(INSTALL_CFG)/CONFIG*)
10 ifneq ($(CONFIG),$(TOP)/configure)
11 RELEASE_TOPS_REVERSE := $(shell \
12 $(PERL) -e '$$,=" ";print reverse @ARGV' $(RELEASE_TOPS))
13- RELEASE_CFG_CONFIGS = $(foreach top, $(RELEASE_TOPS_REVERSE), \
14- $(wildcard $($(top))/cfg/CONFIG*))
15+ RELEASE_CFG_CONFIGS = $(filter-out $(TOP_CFG_CONFIGS), \
16+ $(foreach top, $(RELEASE_TOPS_REVERSE), \
17+ $(wildcard $($(top))/cfg/CONFIG*)))
18 ifneq ($(RELEASE_CFG_CONFIGS),)
19 include $(RELEASE_CFG_CONFIGS)
20 endif
21@@ -105,7 +107,6 @@ endif
22
23 # Include $(INSTALL_CFG)/CONFIG* definitions
24 #
25-TOP_CFG_CONFIGS = $(wildcard $(INSTALL_CFG)/CONFIG*)
26 ifneq ($(TOP_CFG_CONFIGS),)
27 include $(TOP_CFG_CONFIGS)
28 endif
29@@ -118,4 +119,3 @@ ifdef T_A
30 -include $(HOME)/configure/CONFIG_USER.Common.$(T_A)
31 -include $(HOME)/configure/CONFIG_USER.$(EPICS_HOST_ARCH).$(T_A)
32 endif
33-
34diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD
35index 2dc9dd5..344862d 100644
36--- a/configure/RULES_BUILD
37+++ b/configure/RULES_BUILD
38@@ -23,9 +23,6 @@ vpath %.rc $(USR_VPATH) $(ALL_SRC_DIRS)
39 vpath %.h $(USR_VPATH) $(ALL_SRC_DIRS)
40 vpath %.hpp $(USR_VPATH) $(ALL_SRC_DIRS)
41 vpath %.html $(USR_VPATH) $(ALL_SRC_DIRS)
42-vpath %.skel.static $(USR_VPATH) $(ALL_SRC_DIRS)
43-vpath %.y $(USR_VPATH) $(ALL_SRC_DIRS)
44-vpath %.l $(USR_VPATH) $(ALL_SRC_DIRS)
45
46 #---------------------------------------------------------------
47
48@@ -75,7 +72,7 @@ HTMLS_DIR ?= .
49 # First target
50
51 all: install
52-ifeq ($(EPICS_HOST_ARCH),$T_A)
53+ifeq ($(EPICS_HOST_ARCH),$(T_A))
54 host: install
55 else
56 # Do nothing
57@@ -247,26 +244,6 @@ $(TESTPRODNAME) $(PRODNAME): %$(EXE):
58 @$(RM) $@
59 $(RCCMD)
60
61-YACCOPT ?= $($*_YACCOPT)
62-#
63-# rename the y.tab.h file only if we
64-# are creating it
65-#
66-%.c: %.y
67- @$(RM) $*.tab.c
68- @$(RM) $*.tab.h
69- $(YACC) -b$* $(YACCOPT) $<
70- $(MV) $*.tab.c $*.c
71- $(if $(findstring -d, $(YACCOPT)),$(MV) $*.tab.h $*.h,)
72-
73-# must be a separate rule since when not using '-d' the
74-# prefix for .h will be different then .c
75-%.h : %.c %.y
76-
77-%.c: %.l
78- @$(RM) $@
79- $(LEX) $(LEXOPT) -o$@ $<
80-
81 #---------------------------------------------------------------
82 # Libraries, shared/DLL and stubs
83
84diff --git a/configure/RULES_FILE_TYPE b/configure/RULES_FILE_TYPE
85index 5936fd5..bdec938 100644
86--- a/configure/RULES_FILE_TYPE
87+++ b/configure/RULES_FILE_TYPE
88@@ -17,10 +17,13 @@ ifneq ($(RELEASE_RULES_BUILDS),)
89 include $(RELEASE_RULES_BUILDS)
90 endif
91
92-# Include <top>/cfg/RULES* files from tops defined in RELEASE* files
93+# Include <top>/cfg/RULES* files from tops defined in RELEASE* files,
94+# excluding files in our own INSTALL_LOCATION
95 #
96-RELEASE_CFG_RULES = $(foreach top, $(RELEASE_TOPS), \
97- $(wildcard $($(top))/cfg/RULES*))
98+TOP_CFG_RULES = $(wildcard $(INSTALL_CFG)/RULES*)
99+RELEASE_CFG_RULES = $(filter-out $(TOP_CFG_RULES), \
100+ $(foreach top, $(RELEASE_TOPS) INSTALL_LOCATION, \
101+ $(wildcard $($(top))/cfg/RULES*)))
102 ifneq ($(RELEASE_CFG_RULES),)
103 include $(RELEASE_CFG_RULES)
104 endif
105@@ -28,15 +31,14 @@ endif
106 # If this is not BASE then include <top>/configure/RULES_BUILD
107 #
108 ifeq ($(wildcard $(TOP)/configure/CONFIG_BASE_VERSION),)
109-TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD)
110-ifneq ($(TOP_RULES_BUILDS),)
111- include $(TOP_RULES_BUILDS)
112-endif
113+ TOP_RULES_BUILDS = $(wildcard $(TOP)/configure/RULES_BUILD)
114+ ifneq ($(TOP_RULES_BUILDS),)
115+ include $(TOP_RULES_BUILDS)
116+ endif
117 endif
118
119-# Include our own $(INSTALL_CFG)/RULES* files
120+# Now include our own $(INSTALL_CFG)/RULES* files
121 #
122-TOP_CFG_RULES = $(wildcard $(INSTALL_CFG)/RULES*)
123 ifneq ($(TOP_CFG_RULES),)
124 include $(TOP_CFG_RULES)
125 endif
126diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
127index 004f67b..43ad6aa 100644
128--- a/documentation/RELEASE_NOTES.html
129+++ b/documentation/RELEASE_NOTES.html
130@@ -21,7 +21,7 @@ which should also be read to understand what has changed since an earlier
131 release.</p>
132
133
134-<h1 align="center">EPICS Release 7.0.2</h1>
135+<h1 align="center">EPICS Release 7.0.3</h1>
136
137 <!-- Insert new items immediately below this template ...
138
139@@ -31,6 +31,35 @@ release.</p>
140
141 -->
142
143+<h3>Loadable Error Symbols</h3>
144+
145+<p>The error symbol registry code in libCom has been updated to allow symbols to
146+be added after initialization time, and the Perl parser that generated symbol
147+tables from header files included in EPICS Base has been converted into a
148+generic tool that can be used by other modules to capture their error symbols
149+and register them with the symbol registry. This change also permits error
150+symbols defined by IOC code to be registered again (they had to be removed when
151+Base was split into separate modules for the EPICS 7.0.1 release). A new iocsh
152+command is also provided to display the contents of the symbol table.</p>
153+
154+<p>External modules that define their own error symbols (including modules that
155+were unbundled from Base for the 3.14 release) can now register their own error
156+symbols at initialization time. The recommended approach is for symbols to be
157+defined in one or more header files and parsed by the <tt>makeStatTbl.pl</tt>
158+script, which generates a C source file containing the data structures used for
159+registering those symbols. This file also defines a static routine that must be
160+called to perform the registration.</p>
161+
162+<p>Detailed information on how to add symbol registration to an external module
163+can be obtained by giving the option <tt>-H</tt> to the <tt>makeStatTbl.pl</tt>
164+Perl script found in the Base/bin/<i>host-arch</i> directory. The required
165+changes can be made conditional on a macro that is only defined in EPICS
166+releases that contain the new functionality, so the module will still build and
167+run against older versions of EPICS Base.</p>
168+
169+
170+<h1 align="center">EPICS Release 7.0.2</h1>
171+
172 <h3>Launchpad Bugs</h3>
173
174 <p>The list of tracked bugs fixed in this release can be found on the
175diff --git a/modules/database/src/ioc/Makefile b/modules/database/src/ioc/Makefile
176index 3258728..94a3202 100644
177--- a/modules/database/src/ioc/Makefile
178+++ b/modules/database/src/ioc/Makefile
179@@ -25,6 +25,9 @@ INC += databaseVersionNum.h
180
181 PROD_LIBS = Com
182
183+STAT_TBL = dbIocErrSyms.c
184+CLEANS += $(STAT_TBL)
185+
186 include $(IOCDIR)/as/Makefile
187 include $(IOCDIR)/bpt/Makefile
188 include $(IOCDIR)/db/Makefile
189@@ -53,3 +56,5 @@ include $(IOCDIR)/dbtemplate/RULES
190 ../O.Common/databaseVersionNum.h: ../databaseVersionNum.h@
191 $(MKDIR) $(COMMON_DIR)
192 $(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
193+
194+dbIocRegister$(DEP): $(STAT_TBL)
195diff --git a/modules/database/src/ioc/db/Makefile b/modules/database/src/ioc/db/Makefile
196index 2dc4fec..67e5264 100644
197--- a/modules/database/src/ioc/db/Makefile
198+++ b/modules/database/src/ioc/db/Makefile
199@@ -4,7 +4,7 @@
200 # Copyright (c) 2002 The Regents of the University of California, as
201 # Operator of Los Alamos National Laboratory.
202 # EPICS BASE is distributed subject to a Software License Agreement found
203-# in file LICENSE that is included with this distribution.
204+# in file LICENSE that is included with this distribution.
205 #*************************************************************************
206
207 # This is a Makefile fragment, see src/ioc/Makefile.
208@@ -97,3 +97,4 @@ dbCore_SRCS += dbState.c
209 dbCore_SRCS += dbUnitTest.c
210 dbCore_SRCS += dbServer.c
211
212+ERR_S_FILES += $(IOCDIR)/db/dbAccessDefs.h
213diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c
214index c40af92..e5053ea 100644
215--- a/modules/database/src/ioc/db/dbIocRegister.c
216+++ b/modules/database/src/ioc/db/dbIocRegister.c
217@@ -4,10 +4,11 @@
218 * Copyright (c) 2002 The Regents of the University of California, as
219 * Operator of Los Alamos National Laboratory.
220 * EPICS BASE is distributed subject to a Software License Agreement found
221-* in file LICENSE that is included with this distribution.
222+* in file LICENSE that is included with this distribution.
223 \*************************************************************************/
224
225 #include "iocsh.h"
226+#include "errSymTbl.h"
227
228 #define epicsExportSharedSymbols
229 #include "callback.h"
230@@ -421,8 +422,12 @@ static void dbStateShowAllCallFunc (const iocshArgBuf *args)
231 dbStateShowAll(args[0].ival);
232 }
233
234+#include "dbIocErrSyms.c"
235+
236 void dbIocRegister(void)
237 {
238+ dbIocErrSymsAdd();
239+
240 iocshRegister(&dbbFuncDef,dbbCallFunc);
241 iocshRegister(&dbdFuncDef,dbdCallFunc);
242 iocshRegister(&dbcFuncDef,dbcCallFunc);
243diff --git a/modules/database/src/ioc/dbStatic/Makefile b/modules/database/src/ioc/dbStatic/Makefile
244index c962501..edbb749 100644
245--- a/modules/database/src/ioc/dbStatic/Makefile
246+++ b/modules/database/src/ioc/dbStatic/Makefile
247@@ -4,7 +4,7 @@
248 # Copyright (c) 2002 The Regents of the University of California, as
249 # Operator of Los Alamos National Laboratory.
250 # EPICS BASE is distributed subject to a Software License Agreement found
251-# in file LICENSE that is included with this distribution.
252+# in file LICENSE that is included with this distribution.
253 #*************************************************************************
254
255 # This is a Makefile fragment, see src/ioc/Makefile.
256@@ -29,4 +29,9 @@ dbCore_SRCS += dbPvdLib.c
257 dbCore_SRCS += dbStaticRun.c
258 dbCore_SRCS += dbStaticIocRegister.c
259
260+ERR_S_FILES += $(IOCDIR)/dbStatic/dbStaticLib.h
261+ERR_S_FILES += $(IOCDIR)/dbStatic/devSup.h
262+ERR_S_FILES += $(IOCDIR)/dbStatic/drvSup.h
263+ERR_S_FILES += $(IOCDIR)/dbStatic/recSup.h
264+
265 CLEANS += dbLex.c dbYacc.c
266diff --git a/modules/libcom/configure/CONFIG_LIBCOM_MODULE b/modules/libcom/configure/CONFIG_LIBCOM_MODULE
267index 175606c..1267b2f 100644
268--- a/modules/libcom/configure/CONFIG_LIBCOM_MODULE
269+++ b/modules/libcom/configure/CONFIG_LIBCOM_MODULE
270@@ -17,9 +17,13 @@ endif
271 YACC = $(abspath $(EPICS_LIBCOM_HOST_BIN))/antelope$(HOSTEXE)
272 LEX = $(abspath $(EPICS_LIBCOM_HOST_BIN))/e_flex$(HOSTEXE) \
273 -S$(EPICS_LIBCOM)/include/flex.skel.static
274+MAKE_STAT_TBL = $(abspath $(EPICS_LIBCOM_HOST_BIN))/makeStatTbl.pl
275
276 # Default stack size for osiThread
277 OSITHREAD_USE_DEFAULT_STACK = NO
278 OSITHREAD_DEFAULT_STACK_FLAGS_YES = -DOSITHREAD_USE_DEFAULT_STACK
279
280 BASE_CPPFLAGS += $(OSITHREAD_DEFAULT_STACK_FLAGS_$(OSITHREAD_USE_DEFAULT_STACK))
281+
282+# Features available
283+FEATURE_LOADABLE_ERR_SYMS = 1
284diff --git a/modules/libcom/configure/Makefile b/modules/libcom/configure/Makefile
285index 85a7b58..1fc9889 100644
286--- a/modules/libcom/configure/Makefile
287+++ b/modules/libcom/configure/Makefile
288@@ -11,5 +11,6 @@ CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
289
290 CFG += CONFIG_LIBCOM_MODULE
291 CFG += CONFIG_LIBCOM_VERSION
292+CFG += RULES_LIBCOM
293
294 include $(TOP)/configure/RULES
295diff --git a/modules/libcom/configure/RULES_LIBCOM b/modules/libcom/configure/RULES_LIBCOM
296new file mode 100644
297index 0000000..4f870bf
298--- /dev/null
299+++ b/modules/libcom/configure/RULES_LIBCOM
300@@ -0,0 +1,38 @@
301+#*************************************************************************
302+# EPICS BASE is distributed subject to a Software License Agreement found
303+# in file LICENSE that is included with this distribution.
304+#*************************************************************************
305+
306+vpath %.skel.static $(USR_VPATH) $(ALL_SRC_DIRS)
307+vpath %.y $(USR_VPATH) $(ALL_SRC_DIRS)
308+vpath %.l $(USR_VPATH) $(ALL_SRC_DIRS)
309+
310+# YACC = antelope
311+#
312+YACCOPT ?= $($*_YACCOPT)
313+#
314+# rename the y.tab.h file only if we
315+# are creating it
316+#
317+%.c: %.y
318+ @$(RM) $*.tab.c
319+ @$(RM) $*.tab.h
320+ $(YACC) -b$* $(YACCOPT) $<
321+ $(MV) $*.tab.c $*.c
322+ $(if $(findstring -d, $(YACCOPT)),$(MV) $*.tab.h $*.h,)
323+
324+# must be a separate rule since when not using '-d' the
325+# prefix for .h will be different then .c
326+%.h : %.c %.y
327+
328+# LEX = e_flex
329+#
330+%.c: %.l
331+ @$(RM) $@
332+ $(LEX) $(LEXOPT) -o$@ $<
333+
334+# MAKE_STAT_TBL = makeStatTbl.pl
335+#
336+$(STAT_TBL): $(ERR_S_FILES) $(MAKE_STAT_TBL)
337+ @$(RM) $@
338+ $(PERL) $(MAKE_STAT_TBL) -o $@ $(STAT_TBL_OPTS) $(ERR_S_FILES)
339diff --git a/modules/libcom/src/Makefile b/modules/libcom/src/Makefile
340index d61b268..12ed3c4 100644
341--- a/modules/libcom/src/Makefile
342+++ b/modules/libcom/src/Makefile
343@@ -20,6 +20,9 @@ INC += valgrind/valgrind.h
344 INC += libComVersion.h
345 INC += libComVersionNum.h
346
347+STAT_TBL = libComErrSyms.c
348+CLEANS += $(STAT_TBL)
349+
350 include $(LIBCOM)/as/Makefile
351 include $(LIBCOM)/bucketLib/Makefile
352 include $(LIBCOM)/calc/Makefile
353@@ -46,6 +49,9 @@ include $(LIBCOM)/timer/Makefile
354 include $(LIBCOM)/yacc/Makefile
355 include $(LIBCOM)/yajl/Makefile
356
357+# Find Perl scripts in source subdirectories
358+vpath %.pl $(USR_VPATH) $(SRC_DIRS)
359+
360 # Library to build:
361 LIBRARY=Com
362
363@@ -72,7 +78,6 @@ include $(TOP)/configure/RULES
364
365 include $(LIBCOM)/as/RULES
366 include $(LIBCOM)/env/RULES
367-include $(LIBCOM)/error/RULES
368 include $(LIBCOM)/flex/RULES
369 include $(LIBCOM)/misc/RULES
370 include $(LIBCOM)/osi/RULES
371@@ -82,3 +87,5 @@ include $(LIBCOM)/yajl/RULES
372 # in O.Common, but EXPAND emits rules for O.$(T_A)
373 ../O.Common/libComVersionNum.h: ../libComVersionNum.h@
374 $(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
375+
376+libComRegister$(DEP): $(STAT_TBL)
377diff --git a/modules/libcom/src/as/Makefile b/modules/libcom/src/as/Makefile
378index 65f7520..bb76a4e 100644
379--- a/modules/libcom/src/as/Makefile
380+++ b/modules/libcom/src/as/Makefile
381@@ -6,7 +6,7 @@
382 # Copyright (c) 2002 The Regents of the University of California, as
383 # Operator of Los Alamos National Laboratory.
384 # EPICS BASE is distributed subject to a Software License Agreement found
385-# in file LICENSE that is included with this distribution.
386+# in file LICENSE that is included with this distribution.
387 #************************************************************************
388
389 # This is a Makefile fragment, see src/libCom/Makefile.
390@@ -16,6 +16,8 @@ SRC_DIRS += $(LIBCOM)/as
391 INC += asLib.h
392 INC += asTrapWrite.h
393
394+ERR_S_FILES += $(LIBCOM)/as/asLib.h
395+
396 Com_SRCS += asLib.c
397 Com_SRCS += asTrapWrite.c
398
399diff --git a/modules/libcom/src/env/Makefile b/modules/libcom/src/env/Makefile
400index 804426b..bd23581 100644
401--- a/modules/libcom/src/env/Makefile
402+++ b/modules/libcom/src/env/Makefile
403@@ -9,8 +9,6 @@
404
405 SRC_DIRS += $(LIBCOM)/env
406
407-vpath %.pl $(USR_VPATH) $(SRC_DIRS)
408-
409 PERL_SCRIPTS += bldEnvData.pl
410 PERL_SCRIPTS += libcomModuleDirs.pm
411
412diff --git a/modules/libcom/src/error/Makefile b/modules/libcom/src/error/Makefile
413index c79752c..c56fa33 100644
414--- a/modules/libcom/src/error/Makefile
415+++ b/modules/libcom/src/error/Makefile
416@@ -9,22 +9,14 @@
417
418 SRC_DIRS += $(LIBCOM)/error
419
420+PERL_SCRIPTS += makeStatTbl.pl
421+
422 INC += epicsPrint.h
423 INC += errMdef.h
424 INC += errSymTbl.h
425 INC += errlog.h
426
427-Com_SRCS += errlog.c
428-Com_SRCS += errSymLib.c
429-Com_SRCS += errSymTbl.c
430-
431-# For bldErrSymTbl
432-#
433-ERR_S_FILES += $(LIBCOM)/osi/devLib.h
434-ERR_S_FILES += $(LIBCOM)/osi/epicsTime.h
435-ERR_S_FILES += $(LIBCOM)/as/asLib.h
436-ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h
437-ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h
438 ERR_S_FILES += $(LIBCOM)/error/errMdef.h
439
440-CLEANS += errSymTbl.c
441+Com_SRCS += errlog.c
442+Com_SRCS += errSymLib.c
443diff --git a/modules/libcom/src/error/RULES b/modules/libcom/src/error/RULES
444index dc2926f..0b9318a 100644
445--- a/modules/libcom/src/error/RULES
446+++ b/modules/libcom/src/error/RULES
447@@ -2,10 +2,7 @@
448 # Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
449 # National Laboratory.
450 # EPICS BASE is distributed subject to a Software License Agreement found
451-# in file LICENSE that is included with this distribution.
452+# in file LICENSE that is included with this distribution.
453 #*************************************************************************
454
455 # This is a Makefile fragment, see src/libCom/Makefile.
456-
457-errSymTbl.c: $(ERR_S_FILES) $(LIBCOM)/error/makeStatTbl.pl
458- $(PERL) $(LIBCOM)/error/makeStatTbl.pl $(ERR_S_FILES)
459diff --git a/modules/libcom/src/error/errMdef.h b/modules/libcom/src/error/errMdef.h
460index 4f68f76..21c67c0 100644
461--- a/modules/libcom/src/error/errMdef.h
462+++ b/modules/libcom/src/error/errMdef.h
463@@ -17,12 +17,10 @@
464
465 #define RTN_SUCCESS(STATUS) ((STATUS)==0)
466
467-/* Module numbers start above 500 for compatibility with vxWorks errnoLib */
468+/* Feature detection for applications */
469+#define FEATURE_LOADABLE_ERR_SYMS
470
471-/* FIXME: M_xxx values could be declared as integer variables and set
472- * at runtime from registration routines; the S_xxx definitions would
473- * still work with that change, with careful initialization.
474- */
475+/* Module numbers start above 500 for compatibility with vxWorks errnoLib */
476
477 /* libCom */
478 #define M_asLib (501 << 16) /* Access Security */
479@@ -44,4 +42,4 @@
480 #define M_gddFuncTbl (522 << 16) /* gdd jump table */
481 #define M_casApp (523 << 16) /* CA server application */
482
483-#endif /*INC_errMdef_H*/
484+#endif /* INC_errMdef_H */
485diff --git a/modules/libcom/src/error/errSymLib.c b/modules/libcom/src/error/errSymLib.c
486index b220f2b..5e849a8 100644
487--- a/modules/libcom/src/error/errSymLib.c
488+++ b/modules/libcom/src/error/errSymLib.c
489@@ -1,5 +1,5 @@
490 /*************************************************************************\
491-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
492+* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne
493 * National Laboratory.
494 * Copyright (c) 2002 The Regents of the University of California, as
495 * Operator of Los Alamos National Laboratory.
496@@ -8,8 +8,6 @@
497 \*************************************************************************/
498 /*
499 * errSymLib.c
500- * Author: Marty Kraimer
501- * Date: 6-1-90
502 */
503
504 #include <string.h>
505@@ -21,8 +19,9 @@
506
507 #define epicsExportSharedSymbols
508 #include "cantProceed.h"
509-#include "epicsAssert.h"
510+#include "epicsMutex.h"
511 #include "epicsStdio.h"
512+#include "epicsThread.h"
513 #include "errMdef.h"
514 #include "errSymTbl.h"
515 #include "ellLib.h"
516@@ -30,159 +29,180 @@
517
518 #define NHASH 256
519
520-static epicsUInt16 errhash(long errNum);
521-
522 typedef struct errnumnode {
523- ELLNODE node;
524- long errNum;
525- struct errnumnode *hashnode;
526- const char *message;
527- long pad;
528+ struct errnumnode *next;
529+ const ERRSYMBOL *p;
530 } ERRNUMNODE;
531
532-static ELLLIST errnumlist = ELLLIST_INIT;
533-static ERRNUMNODE **hashtable;
534-static int initialized = 0;
535-extern ERRSYMTAB_ID errSymTbl;
536+static epicsMutexId hashLock; /* protects hashTable */
537+static ERRNUMNODE **hashTable;
538+static int hashEntries;
539+
540+/***************************************************************
541+ * errSymInit
542+ ***************************************************************/
543+
544+static
545+void errSymOnce(void * dummy)
546+{
547+ hashTable = (ERRNUMNODE **)callocMustSucceed
548+ (NHASH, sizeof(ERRNUMNODE *), "errSymOnce");
549+ hashLock = epicsMutexMustCreate();
550+ hashEntries = 0;
551+}
552+
553+static
554+int errSymInit(void)
555+{
556+ static epicsThreadOnceId once = EPICS_THREAD_ONCE_INIT;
557+
558+ epicsThreadOnce(&once, errSymOnce, NULL);
559+ return hashEntries;
560+}
561
562 /****************************************************************
563- * ERRSYMBLD
564- *
565- * Create the normal ell LIST of sorted error messages nodes
566- * Followed by linked hash lists - that link together those
567- * ell nodes that have a common hash number.
568- *
569+ * errSymTabAdd
570+ * adds a list of symbols to hash table
571 ***************************************************************/
572-int errSymBld(void)
573+int errSymTabAdd(ERRSYMTAB *errtab)
574 {
575- ERRSYMBOL *errArray = errSymTbl->symbols;
576- ERRNUMNODE *perrNumNode = NULL;
577- ERRNUMNODE *pNextNode = NULL;
578- ERRNUMNODE **phashnode = NULL;
579- int i;
580- int modnum;
581-
582- if (initialized)
583- return(0);
584-
585- hashtable = (ERRNUMNODE**)callocMustSucceed
586- (NHASH, sizeof(ERRNUMNODE*),"errSymBld");
587- for (i = 0; i < errSymTbl->nsymbols; i++, errArray++) {
588- modnum = errArray->errNum >> 16;
589+ const ERRSYMBOL *symbol = errtab->symbols;
590+ int i;
591+
592+ errSymInit();
593+
594+ for (i = 0; i < errtab->nsymbols; i++, symbol++) {
595+ epicsUInt16 modnum = (symbol->status >> 16) & 0xffff;
596+
597 if (modnum < 501) {
598- fprintf(stderr, "errSymBld: ERROR - Module number in errSymTbl < 501 was Module=%lx Name=%s\n",
599- errArray->errNum, errArray->name);
600- continue;
601- }
602- if ((errSymbolAdd(errArray->errNum, errArray->name)) < 0) {
603- fprintf(stderr, "errSymBld: ERROR - errSymbolAdd() failed \n");
604+ epicsUInt16 errnum = symbol->status & 0xffff;
605+ fprintf(stderr, "errSymTabAdd: Bad module number for\n"
606+ " %-25s = (%3u,%2u) \"%s\"\n",
607+ symbol->sym, modnum, errnum, symbol->msg);
608 continue;
609 }
610+ errSymAdd(symbol);
611 }
612- perrNumNode = (ERRNUMNODE *) ellFirst(&errnumlist);
613- while (perrNumNode) {
614- /* hash each perrNumNode->errNum */
615- epicsUInt16 hashInd = errhash(perrNumNode->errNum);
616-
617- phashnode = (ERRNUMNODE**)&hashtable[hashInd];
618- pNextNode = (ERRNUMNODE*) *phashnode;
619- /* search for last node (NULL) of hashnode linked list */
620- while (pNextNode) {
621- phashnode = &pNextNode->hashnode;
622- pNextNode = *phashnode;
623- }
624- *phashnode = perrNumNode;
625- perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode);
626- }
627- initialized = 1;
628- return(0);
629+ return 0;
630 }
631
632 /****************************************************************
633- * HASH
634- * returns the hash index of errNum
635+ * errHash
636+ * returns the hash index of status
637 ****************************************************************/
638-static epicsUInt16 errhash(long errNum)
639+static
640+epicsUInt16 errHash(long status)
641 {
642- epicsUInt16 modnum;
643- epicsUInt16 errnum;
644+ epicsUInt16 modnum = (status >> 16) & 0xffff;
645+ epicsUInt16 errnum = status & 0xffff;
646
647- modnum = (unsigned short) (errNum >> 16);
648- errnum = (unsigned short) (errNum & 0xffff);
649- return (((modnum - 500) * 20) + errnum) % NHASH;
650+ return ((modnum - 500) * 20 + errnum) % NHASH;
651 }
652
653 /****************************************************************
654- * ERRSYMBOLADD
655- * adds symbols to the master errnumlist as compiled from errSymTbl.c
656+ * errSymAdd
657+ * adds one symbol to hash table
658 ***************************************************************/
659-int errSymbolAdd(long errNum, const char *name)
660+int errSymAdd(const ERRSYMBOL *errsym)
661 {
662- ERRNUMNODE *pNew = (ERRNUMNODE*) callocMustSucceed(1,
663- sizeof(ERRNUMNODE), "errSymbolAdd");
664+ epicsUInt16 bucket = errHash(errsym->status);
665+ ERRNUMNODE **ppNode = &hashTable[bucket];
666+ ERRNUMNODE *pNode, *pNew = (ERRNUMNODE *) calloc(1, sizeof(ERRNUMNODE));
667+ int result = 0;
668+
669+ if (!pNew) {
670+ fprintf(stderr, "errSymAdd: Out of memory\n");
671+ return -1;
672+ }
673+ pNew->p = errsym;
674+
675+ /* Scan the bucket list */
676+ epicsMutexMustLock(hashLock);
677+ while ((pNode = *ppNode)) {
678+ if (pNode->p->status == errsym->status) {
679+ /* We've seen this status value before */
680+ free(pNew);
681+ if (pNode->p != errsym &&
682+ strcmp(pNode->p->sym, errsym->sym)) {
683+ epicsUInt16 modnum = (errsym->status >> 16) & 0xffff;
684+ epicsUInt16 errnum = errsym->status & 0xffff;
685+
686+ /* Same value, different symbol names */
687+ fprintf(stderr, "errSymAdd: Status value (%u,%u) is %s \"%s\"\n"
688+ " so can't be registered as %s \"%s\"\n" ,
689+ modnum, errnum, pNode->p->sym, pNode->p->msg,
690+ errsym->sym, errsym->msg);
691+ result = -1;
692+ }
693+ goto done;
694+ }
695+ ppNode = &pNode->next;
696+ }
697
698- pNew->errNum = errNum;
699- pNew->message = name;
700- ellAdd(&errnumlist, (ELLNODE*)pNew);
701- return 0;
702+ /* Append new node to the list */
703+ *ppNode = pNew;
704+ hashEntries++;
705+done:
706+ epicsMutexUnlock(hashLock);
707+ return result;
708 }
709
710-/****************************************************************
711- * errRawCopy
712+/***************************************************************
713+ * errSymLookupNode
714 ***************************************************************/
715-static void errRawCopy(long statusToDecode, char *pBuf, size_t bufLength)
716+static
717+const ERRNUMNODE * errSymLookupNode(long status)
718 {
719- epicsUInt16 modnum = (statusToDecode >>= 16) & 0xffff;
720- epicsUInt16 errnum = statusToDecode & 0xffff;
721+ unsigned bucket = errHash(status);
722+ ERRNUMNODE *pNode, **ppNode;
723
724- assert(bufLength > 20);
725+ if (errSymInit() == 0)
726+ return NULL;
727
728- if (modnum == 0) {
729- epicsSnprintf(pBuf, bufLength, "Error #%u", errnum);
730- }
731- else {
732- epicsSnprintf(pBuf, bufLength, "Error (%u,%u)", modnum, errnum);
733+ ppNode = &hashTable[bucket];
734+
735+ epicsMutexMustLock(hashLock);
736+ pNode = *ppNode;
737+ while (pNode) {
738+ if (pNode->p->status == status) {
739+ epicsMutexUnlock(hashLock);
740+ return pNode;
741+ }
742+ ppNode = &pNode->next;
743+ pNode = *ppNode;
744 }
745+ epicsMutexUnlock(hashLock);
746+ return NULL;
747 }
748
749+/***************************************************************
750+ * errSymLookupMessage
751+ ***************************************************************/
752 static
753-const char* errSymLookupInternal(long status)
754+const char* errSymLookupMessage(long status)
755 {
756- unsigned modNum;
757- ERRNUMNODE *pNextNode;
758- ERRNUMNODE **phashnode = NULL;
759-
760- if (!initialized)
761- errSymBld();
762-
763- modNum = (unsigned) status;
764- modNum >>= 16;
765- modNum &= 0xffff;
766- if (modNum <= 500) {
767- const char * pStr = strerror ((int) status);
768- if (pStr) {
769- return pStr;
770- }
771+ epicsUInt16 modnum = (status >> 16) & 0xffff;
772+
773+ if (modnum <= 500) {
774+ return strerror((int) status);
775 }
776 else {
777- unsigned hashInd = errhash(status);
778- phashnode = (ERRNUMNODE**)&hashtable[hashInd];
779- pNextNode = *phashnode;
780- while (pNextNode) {
781- if (pNextNode->errNum==status){
782- return pNextNode->message;
783- }
784- phashnode = &pNextNode->hashnode;
785- pNextNode = *phashnode;
786+ const ERRNUMNODE *ppNode = errSymLookupNode(status);
787+ if (ppNode) {
788+ return ppNode->p->msg;
789 }
790 }
791 return NULL;
792 }
793
794-const char* errSymMsg(long status)
795+/****************************************************************
796+ * errSymMsg
797+ ***************************************************************/
798+const char * errSymMsg(long status)
799 {
800- const char* msg = errSymLookupInternal(status);
801- return msg ? msg : "<Unknown code>";
802+ const char *msg = errSymLookupMessage(status);
803+
804+ return msg ? msg : "<Unknown status>";
805 }
806
807 /****************************************************************
808@@ -190,93 +210,95 @@ const char* errSymMsg(long status)
809 ***************************************************************/
810 void errSymLookup(long status, char * pBuf, size_t bufLength)
811 {
812- const char* msg = errSymLookupInternal(status);
813- if(msg) {
814+ const char *msg = errSymLookupMessage(status);
815+
816+ if (msg) {
817 strncpy(pBuf, msg, bufLength);
818 pBuf[bufLength-1] = '\0';
819- return;
820 }
821- errRawCopy(status, pBuf, bufLength);
822+ else {
823+ epicsUInt16 modnum = (status >> 16) & 0xffff;
824+ epicsUInt16 errnum = status & 0xffff;
825+
826+ if (modnum == 0) {
827+ epicsSnprintf(pBuf, bufLength, "Error #%u", errnum);
828+ }
829+ else {
830+ epicsSnprintf(pBuf, bufLength, "Error (%u,%u) <unknown>",
831+ modnum, errnum);
832+ }
833+ }
834 }
835
836 /****************************************************************
837 * errSymDump
838 ***************************************************************/
839-void errSymDump(void)
840+void errSymDump(int level)
841 {
842 int i;
843 int msgcount = 0;
844
845- if (!initialized) errSymBld();
846+ if (errSymInit() == 0) {
847+ puts("Error symbol table empty\n");
848+ return;
849+ }
850+
851+ epicsMutexMustLock(hashLock);
852+ if (level > 0)
853+ printf("errSymDump: %d buckets, added %d symbols\n", NHASH, hashEntries);
854
855- msgcount = 0;
856- printf("errSymDump: number of hash slots = %d\n", NHASH);
857 for (i = 0; i < NHASH; i++) {
858- ERRNUMNODE **phashnode = &hashtable[i];
859- ERRNUMNODE *pNextNode = *phashnode;
860+ ERRNUMNODE **ppNode = &hashTable[i];
861+ ERRNUMNODE *pNode = *ppNode;
862 int count = 0;
863
864- while (pNextNode) {
865- int modnum = pNextNode->errNum >> 16;
866- int errnum = pNextNode->errNum & 0xffff;
867+ while (pNode) {
868+ long status = pNode->p->status;
869+ epicsUInt16 modnum = (status >> 16) & 0xffff;
870+ epicsUInt16 errnum = status & 0xffff;
871
872- if (!count++) {
873- printf("HASHNODE = %d\n", i);
874+ if (!count++ && level > 0) {
875+ printf("Bucket %d:\n", i);
876 }
877- printf("\tmod %d num %d \"%s\"\n",
878- modnum , errnum , pNextNode->message);
879- phashnode = &pNextNode->hashnode;
880- pNextNode = *phashnode;
881+ printf(" %-25s = (%3u,%2u) \"%s\"\n",
882+ pNode->p->sym, modnum, errnum, pNode->p->msg);
883+ ppNode = &pNode->next;
884+ pNode = *ppNode;
885 }
886 msgcount += count;
887 }
888- printf("\nerrSymDump: total number of error messages = %d\n", msgcount);
889+ epicsMutexUnlock(hashLock);
890+ printf("Counted %d error symbols\n", msgcount);
891 }
892
893-
894
895 /****************************************************************
896 * errSymTestPrint
897 ***************************************************************/
898-void errSymTestPrint(long errNum)
899+void errSymTestPrint(long status)
900 {
901- char message[256];
902- epicsUInt16 modnum;
903- epicsUInt16 errnum;
904-
905- if (!initialized) errSymBld();
906+ epicsUInt16 modnum = (status >> 16) & 0xffff;
907+ epicsUInt16 errnum = status & 0xffff;
908+ const ERRNUMNODE *pNode = errSymLookupNode(status);
909
910- message[0] = '\0';
911- modnum = (epicsUInt16) (errNum >> 16);
912- errnum = (epicsUInt16) (errNum & 0xffff);
913- if (modnum < 501) {
914- fprintf(stderr, "Usage: errSymTestPrint(long errNum) \n");
915- fprintf(stderr, "errSymTestPrint: module number < 501 \n");
916- return;
917- }
918- errSymLookup(errNum, message, sizeof(message));
919- if ( message[0] == '\0' ) return;
920- printf("module %hu number %hu message=\"%s\"\n",
921- modnum, errnum, message);
922- return;
923+ if (pNode)
924+ printf(" %-25s = (%3u,%2u) \"%s\"\n",
925+ pNode->p->sym, modnum, errnum, pNode->p->msg);
926 }
927-
928
929+
930 /****************************************************************
931- * ERRSYMTEST
932+ * errSymTest
933 ****************************************************************/
934-void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
935- epicsUInt16 endErrNum)
936+void errSymTest(epicsUInt16 modnum, epicsUInt16 first, epicsUInt16 last)
937 {
938- long errNum;
939- epicsUInt16 errnum;
940+ epicsUInt16 errnum;
941
942- if (!initialized) errSymBld();
943- if (modnum < 501)
944+ if ((modnum < 501) || (first > last))
945 return;
946
947 /* print range of error messages */
948- for (errnum = begErrNum; errnum <= endErrNum; errnum++) {
949- errNum = modnum << 16;
950- errNum |= (errnum & 0xffff);
951- errSymTestPrint(errNum);
952+ for (errnum = first; errnum <= last; errnum++) {
953+ long status = (modnum << 16) | errnum;
954+
955+ errSymTestPrint(status);
956 }
957 }
958diff --git a/modules/libcom/src/error/errSymTbl.h b/modules/libcom/src/error/errSymTbl.h
959index 7fc25f7..c58133d 100644
960--- a/modules/libcom/src/error/errSymTbl.h
961+++ b/modules/libcom/src/error/errSymTbl.h
962@@ -1,10 +1,10 @@
963 /*************************************************************************\
964-* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
965+* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne
966 * National Laboratory.
967 * Copyright (c) 2002 The Regents of the University of California, as
968 * Operator of Los Alamos National Laboratory.
969 * EPICS BASE is distributed subject to a Software License Agreement found
970-* in file LICENSE that is included with this distribution.
971+* in file LICENSE that is included with this distribution.
972 \*************************************************************************/
973
974 #ifndef INC_errSymTbl_H
975@@ -14,34 +14,34 @@
976
977 #include "shareLib.h"
978 #include "epicsTypes.h"
979+#include "dbDefs.h" /* for the generated errSyms.c file */
980
981 /* ERRSYMBOL - entry in symbol table */
982 typedef struct {
983- long errNum; /* errMessage symbol number */
984- const char *name; /* pointer to symbol name */
985+ long status; /* error status code */
986+ const char *sym; /* symbol name */
987+ const char *msg; /* error message text */
988 } ERRSYMBOL;
989
990 /* ERRSYMTAB - symbol table */
991 typedef struct {
992 int nsymbols; /* current number of symbols in table */
993- ERRSYMBOL *symbols; /* ptr to array of symbol entries */
994+ const ERRSYMBOL *symbols; /* ptr to array of symbol entries */
995 } ERRSYMTAB;
996
997-typedef ERRSYMTAB *ERRSYMTAB_ID;
998-
999
1000 #ifdef __cplusplus
1001 extern "C" {
1002 #endif
1003
1004 epicsShareFunc void errSymLookup(long status, char *pBuf, size_t bufLength);
1005-epicsShareFunc const char* errSymMsg(long status);
1006-epicsShareFunc void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
1007- epicsUInt16 endErrNum);
1008-epicsShareFunc void errSymTestPrint(long errNum);
1009-epicsShareFunc int errSymBld(void);
1010-epicsShareFunc int errSymbolAdd(long errNum, const char *name);
1011-epicsShareFunc void errSymDump(void);
1012+epicsShareFunc const char * errSymMsg(long status);
1013+epicsShareFunc void errSymTest(epicsUInt16 modnum, epicsUInt16 first,
1014+ epicsUInt16 last);
1015+epicsShareFunc void errSymTestPrint(long status);
1016+epicsShareFunc int errSymTabAdd(ERRSYMTAB *errtab);
1017+epicsShareFunc int errSymAdd(const ERRSYMBOL *errsym);
1018+epicsShareFunc void errSymDump(int level);
1019
1020 #ifdef __cplusplus
1021 }
1022diff --git a/modules/libcom/src/error/errlog.c b/modules/libcom/src/error/errlog.c
1023index 8445a5a..9ed2ba6 100644
1024--- a/modules/libcom/src/error/errlog.c
1025+++ b/modules/libcom/src/error/errlog.c
1026@@ -4,7 +4,7 @@
1027 * Copyright (c) 2002 The Regents of the University of California, as
1028 * Operator of Los Alamos National Laboratory.
1029 * EPICS BASE is distributed subject to a Software License Agreement found
1030-* in file LICENSE that is included with this distribution.
1031+* in file LICENSE that is included with this distribution.
1032 \*************************************************************************/
1033 /*
1034 * Original Author: Marty Kraimer
1035@@ -487,8 +487,6 @@ static void errlogInitPvt(void *arg)
1036 pvtData.pbuffer = callocMustSucceed(1, pvtData.buffersize,
1037 "errlogInitPvt");
1038
1039- errSymBld(); /* Better not to do this lazily... */
1040-
1041 tid = epicsThreadCreate("errlog", epicsThreadPriorityLow,
1042 epicsThreadGetStackSize(epicsThreadStackSmall),
1043 (EPICSTHREADFUNC)errlogThread, 0);
1044diff --git a/modules/libcom/src/error/makeStatTbl.pl b/modules/libcom/src/error/makeStatTbl.pl
1045index e9ca10e..ed9b2ae 100644
1046--- a/modules/libcom/src/error/makeStatTbl.pl
1047+++ b/modules/libcom/src/error/makeStatTbl.pl
1048@@ -1,50 +1,85 @@
1049 #!/usr/bin/env perl
1050
1051 #*************************************************************************
1052-# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
1053+# Copyright (c) 2018 The University of Chicago, as Operator of Argonne
1054 # National Laboratory.
1055 # Copyright (c) 2014 The Regents of the University of California, as
1056 # Operator of Los Alamos National Laboratory.
1057 # EPICS BASE is distributed subject to a Software License Agreement found
1058-# in file LICENSE that is included with this distribution.
1059+# in file LICENSE that is included with this distribution.
1060 #*************************************************************************
1061 #
1062-# makeStatTbl.pl - Create Error Symbol Table
1063+# makeStatTbl.pl - Register Error Symbols
1064 #
1065 # Original Author: Kay-Uwe Kasemir, 1-31-97
1066-#
1067-# SYNOPSIS
1068-# perl makeStatTbl.pl files.h...
1069-#
1070-# DESCRIPTION
1071-# This tool creates a symbol table (ERRSYMTAB) structure which contains the
1072-# names and values of all the status codes defined in the .h files named in
1073-# its input arguments. The status codes must be prefixed with "S_"
1074-# in order to be included in this table.
1075-# Module numbers definitions prefixed with "M_" are also read from the input
1076-# files and included in the output.
1077-#
1078-# This tool's primary use is for creating an error status table used
1079-# by errPrint, and errSymLookup.
1080-#
1081-# FILES
1082-# errMdef.h Module number file for each h directory
1083-# errSymTbl.c Source file generated by tool in the cwd
1084-#
1085-# SEE ALSO: errnoLib(1), symLib(1)
1086
1087 use strict;
1088 use Getopt::Std;
1089+use Pod::Usage;
1090+
1091+=head1 NAME
1092+
1093+makeStatTbl.pl - Generate code to register error symbols
1094+
1095+=head1 SYNOPSIS
1096+
1097+B<makeStatTbl.pl> [B<-r> errSymsAdd] [B<-o> errSyms.c] file.h ...
1098+
1099+=head1 DESCRIPTION
1100+
1101+This tool parses one or more C header files and extracts any definitions that
1102+match the following formats:
1103+
1104+ #define M_xxx (1234 << 16) /* Module name */
1105+ #define S_xxx_error (M_xxx | 1) /* Error description */
1106+
1107+These definitions are converted into a series of C structures with code that
1108+registers all of the C<S_> symbol values as error status values with the given
1109+descriptions.
1110+
1111+=head1 OPTIONS
1112+
1113+B<makeStatTbl.pl> understands the following options:
1114+
1115+=over 4
1116+
1117+=item B<-h>
1118+
1119+Help, display usage information.
1120+
1121+=item B<-H>
1122+
1123+Conversion help, display detailed information about converting a module to
1124+register its error symbols.
1125+
1126+=item B<-r> errSymsAdd
1127+
1128+Name of the C registration routine to be created in the output file.
1129+
1130+=item B<-o> errSyms.c
1131+
1132+Name of the output file to be created.
1133+
1134+=back
1135+
1136+If no output filename is set, the file created will be named C<errSyms.c>. If no
1137+registration routine name is set, the routine will be named after the output
1138+file with the trailing C<.c> replaced with C<Add>.
1139+
1140+=cut
1141
1142 my $tool = 'makeStatTbl.pl';
1143
1144-our ($opt_h);
1145-our $opt_o = 'errSymTbl.c';
1146+our ($opt_h, $opt_H, $opt_r);
1147+our $opt_o = 'errSyms.c';
1148+
1149+pod2usage(2) unless getopts('hHo:r:');
1150
1151-$Getopt::Std::OUTPUT_HELP_VERSION = 1;
1152+($opt_r = $opt_o) =~ s/\.c$/Add/ unless defined $opt_r;
1153
1154-&HELP_MESSAGE unless getopts('ho:') && @ARGV;
1155-&HELP_MESSAGE if $opt_h;
1156+pod2usage(-verbose => 2) if $opt_H;
1157+pod2usage(1) if $opt_h;
1158+pod2usage("$tool: No input files given.\n") if !@ARGV;
1159
1160 my (@syms, %vals, %msgs);
1161
1162@@ -62,11 +97,12 @@ open my $out, '>', $opt_o or
1163 die "Can't create $opt_o: $!\n";
1164
1165 print $out <<"END";
1166-/* Generated file $opt_o */
1167+/* Generated file $opt_o
1168+ *
1169+ * The source file that includes this must also include errSymTbl.h
1170+ */
1171
1172 #include "errMdef.h"
1173-#include "errSymTbl.h"
1174-#include "dbDefs.h"
1175
1176 END
1177
1178@@ -86,11 +122,16 @@ print $out
1179 "\n",
1180 "static ERRSYMBOL symbols[] = {\n";
1181
1182+foreach my $mod (@mods) {
1183+ my $msg = escape($msgs{$mod});
1184+ print $out
1185+ " { $mod, \"$mod\", \"$msg\"},\n";
1186+}
1187 foreach my $err (@errs) {
1188 my $msg = escape($msgs{$err});
1189 my $val = $vals{$err};
1190 print $out
1191- " { $val, \"$msg\"},\n";
1192+ " { $val, \"$err\", \"$msg\"},\n";
1193 }
1194
1195 print $out <<"END";
1196@@ -100,17 +141,88 @@ static ERRSYMTAB symTbl = {
1197 NELEMENTS(symbols), symbols
1198 };
1199
1200-ERRSYMTAB_ID errSymTbl = &symTbl;
1201-
1202-END
1203-
1204-sub HELP_MESSAGE {
1205- print STDERR "Usage: $tool [-o file.c] files.h ...\n";
1206- exit 2;
1207+static void ${opt_r}(void)
1208+{
1209+ errSymTabAdd(&symTbl);
1210 }
1211+END
1212
1213 sub escape {
1214 $_ = shift;
1215 s/"/\\"/g;
1216 return $_;
1217 }
1218+
1219+=pod
1220+
1221+=head1 Registering Error Symbols
1222+
1223+Small changes are needed to the module's build instructions, and to a module
1224+initialization routine. The examples here show the changes that were required to
1225+the IndustryPack Driver module.
1226+
1227+=head2 Makefile Changes
1228+
1229+In the main part of the C<Makefile> that compiles the module from source, add
1230+all the header files that contain error symbol definitions to the variable
1231+C<ERR_S_FILES> like this:
1232+
1233+ ERR_S_FILES += ../drvIpac.h
1234+
1235+The leading C<../> is required for files that appear in the regular source
1236+directory; all filenames must be specified relative to the target's C<O.arch>
1237+build directory.
1238+
1239+Also in this section of the C<Makefile>, set the variable C<STAT_TBL> to the
1240+name of the file to be generated containing the symbol information:
1241+
1242+ STAT_TBL = ipacErrSyms.c
1243+
1244+Optionally also add this to the C<CLEANS> variable to cause the generated file
1245+to be deleted by a C<make clean> command:
1246+
1247+ CLEANS += $(STAT_TBL)
1248+
1249+Finally in the build rules section of the C<Makefile> (i.e. after the include
1250+line for C<$(TOP)/configure/RULES>) add a dependency rule to ensure the new file
1251+gets generated when it is needed. The file named before the colon is the C
1252+source file that contains the initialization routine that will be edited below,
1253+with its C<.c> filename extension replaced by C<$(DEP)>:
1254+
1255+ drvIpac$(DEP): $(STAT_TBL)
1256+
1257+=head2 Initialization Routine Changes
1258+
1259+Find a suitable routine in the module that gets called to initialize it,
1260+preferably one that is normally only used once, although multiple calls
1261+shouldn't be a problem. A routine that registers commands with the IOC shell
1262+would be ideal.
1263+
1264+The header section of the source file containing this routine must contain the
1265+following include statements exactly as shown:
1266+
1267+ #include <errMdef.h>
1268+ #ifdef FEATURE_LOADABLE_ERR_SYMS
1269+ #include <errSymTbl.h>
1270+ #endif
1271+
1272+To ensure compatibility with Microsoft Windows builds of the module, make sure
1273+these lines appear above the inclusion of C<epicsExport.h> or of any definition
1274+of the macro C<epicsExportSharedSymbols>.
1275+
1276+Just above the initialization routine, add the following code to include the new
1277+file or declare a dummy macro when building older versions of Base (replace the
1278+text C<ipacErrSyms> with your own equivalent in both indented lines):
1279+
1280+ #ifdef FEATURE_LOADABLE_ERR_SYMS
1281+ #include "ipacErrSyms.c"
1282+ #else
1283+ #define ipacErrSymsAdd() (void) 0
1284+ #endif
1285+
1286+Finally, inside the routine itself, add a call to the symbol registration
1287+routine:
1288+
1289+ ipacErrSymsAdd();
1290+
1291+=cut
1292diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c
1293index 737d7e9..851c2ba 100644
1294--- a/modules/libcom/src/iocsh/libComRegister.c
1295+++ b/modules/libcom/src/iocsh/libComRegister.c
1296@@ -5,7 +5,7 @@
1297 * Copyright (c) 2002 The Regents of the University of California, as
1298 * Operator of Los Alamos National Laboratory.
1299 * EPICS BASE is distributed subject to a Software License Agreement found
1300-* in file LICENSE that is included with this distribution.
1301+* in file LICENSE that is included with this distribution.
1302 \*************************************************************************/
1303
1304 #include <stdlib.h>
1305@@ -21,6 +21,7 @@
1306 #include "osiUnistd.h"
1307 #include "logClient.h"
1308 #include "errlog.h"
1309+#include "errSymTbl.h"
1310 #include "taskwd.h"
1311 #include "registry.h"
1312 #include "epicsGeneralTime.h"
1313@@ -163,6 +164,15 @@ static void registryDumpCallFunc(const iocshArgBuf *args)
1314 registryDump ();
1315 }
1316
1317+/* errSymDump */
1318+static const iocshArg errSymDumpArg0 = { "level",iocshArgInt};
1319+static const iocshArg * const errSymDumpArgs[1] = {&errSymDumpArg0};
1320+static const iocshFuncDef errSymDumpFuncDef = {"errSymDump",1,errSymDumpArgs};
1321+static void errSymDumpCallFunc(const iocshArgBuf *args)
1322+{
1323+ errSymDump(args[0].ival);
1324+}
1325+
1326 /* iocLogInit */
1327 static const iocshFuncDef iocLogInitFuncDef = {"iocLogInit",0};
1328 static void iocLogInitCallFunc(const iocshArgBuf *args)
1329@@ -215,7 +225,7 @@ static void errlogInitCallFunc(const iocshArgBuf *args)
1330 /* errlogInit2 */
1331 static const iocshArg errlogInit2Arg0 = { "bufSize",iocshArgInt};
1332 static const iocshArg errlogInit2Arg1 = { "maxMsgSize",iocshArgInt};
1333-static const iocshArg * const errlogInit2Args[] =
1334+static const iocshArg * const errlogInit2Args[] =
1335 {&errlogInit2Arg0, &errlogInit2Arg1};
1336 static const iocshFuncDef errlogInit2FuncDef =
1337 {"errlogInit2", 2, errlogInit2Args};
1338@@ -393,8 +403,12 @@ static void installLastResortEventProviderCallFunc(const iocshArgBuf *args)
1339 installLastResortEventProvider();
1340 }
1341
1342+#include "libComErrSyms.c"
1343+
1344 void epicsShareAPI libComRegister(void)
1345 {
1346+ libComErrSymsAdd();
1347+
1348 iocshRegister(&dateFuncDef, dateCallFunc);
1349 iocshRegister(&echoFuncDef, echoCallFunc);
1350 iocshRegister(&chdirFuncDef, chdirCallFunc);
1351@@ -407,6 +421,7 @@ void epicsShareAPI libComRegister(void)
1352 iocshRegister(&epicsEnvShowFuncDef, epicsEnvShowCallFunc);
1353 iocshRegister(&registryDumpFuncDef, registryDumpCallFunc);
1354
1355+ iocshRegister(&errSymDumpFuncDef, errSymDumpCallFunc);
1356 iocshRegister(&iocLogInitFuncDef, iocLogInitCallFunc);
1357 iocshRegister(&iocLogDisableFuncDef, iocLogDisableCallFunc);
1358 iocshRegister(&iocLogShowFuncDef, iocLogShowCallFunc);
1359@@ -422,7 +437,7 @@ void epicsShareAPI libComRegister(void)
1360 iocshRegister(&epicsMutexShowAllFuncDef,epicsMutexShowAllCallFunc);
1361 iocshRegister(&epicsThreadSleepFuncDef,epicsThreadSleepCallFunc);
1362 iocshRegister(&epicsThreadResumeFuncDef,epicsThreadResumeCallFunc);
1363-
1364+
1365 iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc);
1366 iocshRegister(&installLastResortEventProviderFuncDef, installLastResortEventProviderCallFunc);
1367 }
1368diff --git a/modules/libcom/src/misc/Makefile b/modules/libcom/src/misc/Makefile
1369index 3d5412d..6a4fe11 100644
1370--- a/modules/libcom/src/misc/Makefile
1371+++ b/modules/libcom/src/misc/Makefile
1372@@ -2,7 +2,7 @@
1373 # Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
1374 # National Laboratory.
1375 # EPICS BASE is distributed subject to a Software License Agreement found
1376-# in file LICENSE that is included with this distribution.
1377+# in file LICENSE that is included with this distribution.
1378 #*************************************************************************
1379
1380 # This is a Makefile fragment, see src/libCom/Makefile.
1381@@ -31,6 +31,8 @@ INC += testMain.h
1382 # epicsVersion.h is created by this Makefile
1383 INC += epicsVersion.h
1384
1385+ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h
1386+
1387 Com_SRCS += alarmString.c
1388 Com_SRCS += aToIPAddr.c
1389 Com_SRCS += adjustment.c
1390diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile
1391index ecbf4c2..53167f0 100644
1392--- a/modules/libcom/src/osi/Makefile
1393+++ b/modules/libcom/src/osi/Makefile
1394@@ -2,7 +2,7 @@
1395 # Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
1396 # National Laboratory.
1397 # EPICS BASE is distributed subject to a Software License Agreement found
1398-# in file LICENSE that is included with this distribution.
1399+# in file LICENSE that is included with this distribution.
1400 #*************************************************************************
1401
1402 # This is a Makefile fragment, see src/libCom/Makefile.
1403@@ -65,6 +65,9 @@ INC += osdVME.h
1404 INC += epicsMMIO.h
1405 INC += epicsMMIODef.h
1406
1407+ERR_S_FILES += $(LIBCOM)/osi/devLib.h
1408+ERR_S_FILES += $(LIBCOM)/osi/epicsTime.h
1409+
1410 Com_SRCS += epicsThread.cpp
1411 Com_SRCS += epicsMutex.cpp
1412 Com_SRCS += epicsEvent.cpp
1413diff --git a/modules/libcom/src/pool/Makefile b/modules/libcom/src/pool/Makefile
1414index efaf667..8f33320 100644
1415--- a/modules/libcom/src/pool/Makefile
1416+++ b/modules/libcom/src/pool/Makefile
1417@@ -2,7 +2,7 @@
1418 # Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
1419 # National Laboratory.
1420 # EPICS BASE is distributed subject to a Software License Agreement found
1421-# in file LICENSE that is included with this distribution.
1422+# in file LICENSE that is included with this distribution.
1423 #*************************************************************************
1424
1425 # This is a Makefile fragment, see src/libCom/Makefile.
1426@@ -11,6 +11,7 @@ SRC_DIRS += $(LIBCOM)/pool
1427
1428 INC += epicsThreadPool.h
1429
1430+ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h
1431+
1432 Com_SRCS += poolJob.c
1433 Com_SRCS += threadPool.c
1434-
1435diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile
1436index 1c26c44..7cd1a01 100755
1437--- a/modules/libcom/test/Makefile
1438+++ b/modules/libcom/test/Makefile
1439@@ -79,6 +79,11 @@ epicsErrlogTest_SRCS += epicsErrlogTest.c
1440 testHarness_SRCS += epicsErrlogTest.c
1441 TESTS += epicsErrlogTest
1442
1443+TESTPROD_HOST += errSymTest
1444+errSymTest_SRCS += errSymTest.c
1445+testHarness_SRCS += errSymTest.c
1446+TESTS += errSymTest
1447+
1448 TESTPROD_HOST += epicsStdioTest
1449 epicsStdioTest_SRCS += epicsStdioTest.c
1450 testHarness_SRCS += epicsStdioTest.c
1451diff --git a/modules/libcom/test/epicsRunLibComTests.c b/modules/libcom/test/epicsRunLibComTests.c
1452index 94fe3d7..a51d684 100644
1453--- a/modules/libcom/test/epicsRunLibComTests.c
1454+++ b/modules/libcom/test/epicsRunLibComTests.c
1455@@ -24,6 +24,7 @@ int epicsCalcTest(void);
1456 int epicsEllTest(void);
1457 int epicsEnvTest(void);
1458 int epicsErrlogTest(void);
1459+int errSymLibTest(void);
1460 int epicsEventTest(void);
1461 int epicsExitTest(void);
1462 int epicsMathTest(void);
1463@@ -82,6 +83,7 @@ void epicsRunLibComTests(void)
1464 runTest(epicsEllTest);
1465 runTest(epicsEnvTest);
1466 runTest(epicsErrlogTest);
1467+ runTest(errSymLibTest);
1468 runTest(epicsEventTest);
1469 runTest(epicsInlineTest);
1470 runTest(epicsMathTest);
1471diff --git a/modules/libcom/test/errSymTest.c b/modules/libcom/test/errSymTest.c
1472new file mode 100644
1473index 0000000..1efbe0a
1474--- /dev/null
1475+++ b/modules/libcom/test/errSymTest.c
1476@@ -0,0 +1,88 @@
1477+/*************************************************************************\
1478+* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne
1479+* National Laboratory.
1480+* EPICS BASE is distributed subject to a Software License Agreement found
1481+* in file LICENSE that is included with this distribution.
1482+\*************************************************************************/
1483+/* errSymTest.c
1484+ *
1485+ * Check functionality of the errSym routines
1486+ */
1487+
1488+#include <string.h>
1489+
1490+#include "epicsUnitTest.h"
1491+#include "errSymTbl.h"
1492+#include "testMain.h"
1493+
1494+#define M_test (0x1234 << 16)
1495+#define S_1 M_test | 1
1496+#define S_2 M_test | 2
1497+#define S_3 M_test | 3
1498+
1499+static ERRSYMBOL sym0 = {M_test, "M_test", "Okay"};
1500+static ERRSYMBOL sym1 = {M_test, "M_test", "OK"};
1501+static ERRSYMBOL sym2 = {M_test, "M_err", "Not okay"};
1502+
1503+static ERRSYMBOL syms1[] = {
1504+ { S_1, "S_1", "One"},
1505+};
1506+static ERRSYMTAB tab1 = {
1507+ NELEMENTS(syms1), syms1
1508+};
1509+
1510+static ERRSYMBOL syms2[] = {
1511+ { S_2, "S_2", "Two"},
1512+ { S_3, "S_3", "Three"},
1513+};
1514+static ERRSYMTAB tab2 = {
1515+ NELEMENTS(syms2), syms2
1516+};
1517+
1518+MAIN(errSymLibTest)
1519+{
1520+ const char *unknown = errSymMsg(M_test);
1521+ const char *msg;
1522+ char buf[40];
1523+
1524+ testPlan(14);
1525+
1526+ testOk(!strcmp(unknown, "<Unknown status>"),
1527+ "Got expected 'Unknown status' message");
1528+
1529+ testOk(!errSymAdd(&sym0), "Added symbol M_test");
1530+
1531+ msg = errSymMsg(M_test);
1532+ testOk(msg == sym0.msg, "errSymMsg(M_test) => '%s'", msg);
1533+
1534+ testOk(!errSymTabAdd(&tab1), "Added tab1 symbols");
1535+
1536+ msg = errSymMsg(S_1);
1537+ testOk(msg == syms1[0].msg, "errSymMsg(S_1) => '%s'", msg);
1538+
1539+ msg = errSymMsg(S_2);
1540+ testOk(msg == unknown, "errSymMsg(S_2) => '%s'", msg);
1541+
1542+ testOk(!errSymTabAdd(&tab2), "Added tab2 symbols");
1543+
1544+ msg = errSymMsg(S_2);
1545+ testOk(msg == syms2[0].msg, "errSymMsg(S_2) => '%s'", msg);
1546+
1547+ testOk(!errSymAdd(&sym0), "Added symbol M_test again");
1548+ testOk(!errSymAdd(&sym1), "Added a different M_test");
1549+ testOk( errSymAdd(&sym2), "Added incompatible M_test");
1550+ msg = errSymMsg(M_test);
1551+ testOk(msg == sym0.msg, "errSymMsg(M_test) => '%s'", msg);
1552+
1553+ buf[0] = 0;
1554+ errSymLookup(M_test, buf, sizeof(buf));
1555+ testOk(buf[0] && !strcmp(buf, sym0.msg),
1556+ "errSymLookup(M_test) => '%s'", buf);
1557+
1558+ buf[0] = 0;
1559+ errSymLookup(1024<<16, buf, sizeof(buf));
1560+ testOk(buf[0] && !strcmp(buf, "Error (1024,0) <unknown>"),
1561+ "errSymLookup(1024<<16) => '%s'", buf);
1562+
1563+ return testDone();
1564+}

Subscribers

People subscribed via source and target branches