Merge lp:~epics-core/epics-base/server-side-plugins into lp:~epics-core/epics-base/3.15

Proposed by mdavidsaver
Status: Merged
Merged at revision: 12295
Proposed branch: lp:~epics-core/epics-base/server-side-plugins
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 20253 lines (+11599/-2941) (has conflicts)
101 files modified
.bzrignore (+3/-0)
configure/RULES.Db (+2/-2)
src/Makefile (+4/-0)
src/ioc/as/asDbLib.c (+13/-21)
src/ioc/as/asDbLib.h (+6/-4)
src/ioc/db/Makefile (+11/-0)
src/ioc/db/chfPlugin.c (+649/-0)
src/ioc/db/chfPlugin.h (+280/-0)
src/ioc/db/dbAccess.c (+309/-705)
src/ioc/db/dbAccess.h (+2/-2)
src/ioc/db/dbAccessDefs.h (+8/-53)
src/ioc/db/dbAddr.h (+1/-4)
src/ioc/db/dbBkpt.c (+1/-0)
src/ioc/db/dbCAC.h (+34/-34)
src/ioc/db/dbCa.c (+8/-1)
src/ioc/db/dbCa.h (+1/-0)
src/ioc/db/dbChannel.c (+865/-0)
src/ioc/db/dbChannel.h (+181/-0)
src/ioc/db/dbChannelIO.cpp (+67/-59)
src/ioc/db/dbChannelIO.h (+33/-34)
src/ioc/db/dbContext.cpp (+72/-71)
src/ioc/db/dbContextReadNotifyCache.cpp (+19/-19)
src/ioc/db/dbEvent.c (+277/-235)
src/ioc/db/dbEvent.h (+18/-11)
src/ioc/db/dbExtractArray.c (+84/-0)
src/ioc/db/dbExtractArray.h (+34/-0)
src/ioc/db/dbIocRegister.c (+58/-0)
src/ioc/db/dbLink.c (+648/-0)
src/ioc/db/dbLink.h (+94/-0)
src/ioc/db/dbNotify.c (+197/-194)
src/ioc/db/dbNotify.h (+11/-11)
src/ioc/db/dbPutNotifyBlocker.cpp (+21/-21)
src/ioc/db/dbPutNotifyBlocker.h (+14/-14)
src/ioc/db/dbState.c (+108/-0)
src/ioc/db/dbState.h (+92/-0)
src/ioc/db/dbSubscriptionIO.cpp (+22/-22)
src/ioc/db/db_access.c (+131/-152)
src/ioc/db/db_access_routines.h (+11/-17)
src/ioc/db/db_field_log.h (+56/-13)
src/ioc/db/db_test.c (+191/-661)
src/ioc/db/recGbl.c (+9/-53)
src/ioc/db/test/Makefile (+24/-0)
src/ioc/db/test/arrShorthandTest.c (+139/-0)
src/ioc/db/test/chfPluginTest.c (+832/-0)
src/ioc/db/test/dbChannelTest.c (+261/-0)
src/ioc/db/test/dbChannelTest.db (+2/-0)
src/ioc/db/test/dbStateTest.c (+56/-0)
src/ioc/db/test/xRecord.dbd (+12/-0)
src/ioc/dbStatic/dbBase.h (+5/-4)
src/ioc/dbStatic/dbPvdLib.c (+1/-0)
src/ioc/dbStatic/dbStaticLib.c (+80/-79)
src/ioc/dbStatic/link.h (+23/-26)
src/ioc/misc/iocInit.c (+7/-36)
src/ioc/registry/registerRecordDeviceDriver.pl (+7/-1)
src/ioc/rsrv/camessage.c (+324/-280)
src/ioc/rsrv/caservertask.c (+66/-71)
src/ioc/rsrv/server.h (+15/-15)
src/libCom/Makefile (+1/-0)
src/libCom/ellLib/ellLib.c (+17/-2)
src/libCom/ellLib/ellLib.h (+6/-4)
src/libCom/gpHash/gpHash.h (+3/-1)
src/libCom/gpHash/gpHashLib.c (+15/-9)
src/libCom/yajl/Makefile (+26/-0)
src/libCom/yajl/yajl.c (+160/-0)
src/libCom/yajl/yajl_alloc.c (+67/-0)
src/libCom/yajl/yajl_alloc.h (+50/-0)
src/libCom/yajl/yajl_buf.c (+120/-0)
src/libCom/yajl/yajl_buf.h (+73/-0)
src/libCom/yajl/yajl_bytestack.h (+85/-0)
src/libCom/yajl/yajl_common.h (+76/-0)
src/libCom/yajl/yajl_encode.c (+189/-0)
src/libCom/yajl/yajl_encode.h (+50/-0)
src/libCom/yajl/yajl_gen.c (+317/-0)
src/libCom/yajl/yajl_gen.h (+159/-0)
src/libCom/yajl/yajl_lex.c (+738/-0)
src/libCom/yajl/yajl_lex.h (+133/-0)
src/libCom/yajl/yajl_parse.h (+193/-0)
src/libCom/yajl/yajl_parser.c (+449/-0)
src/libCom/yajl/yajl_parser.h (+82/-0)
src/std/Makefile (+1/-0)
src/std/dev/Makefile (+2/-0)
src/std/dev/devBiDbState.c (+92/-0)
src/std/dev/devBoDbState.c (+86/-0)
src/std/dev/devSoft.dbd (+3/-0)
src/std/filters/Makefile (+18/-0)
src/std/filters/arr.c (+207/-0)
src/std/filters/dbnd.c (+142/-0)
src/std/filters/filters.dbd (+4/-0)
src/std/filters/sync.c (+172/-0)
src/std/filters/test/Makefile (+45/-0)
src/std/filters/test/arrRecord.c (+135/-0)
src/std/filters/test/arrRecord.dbd (+33/-0)
src/std/filters/test/arrTest.cpp (+337/-0)
src/std/filters/test/arrTest.db (+15/-0)
src/std/filters/test/dbChannelTest.db (+2/-0)
src/std/filters/test/dbndTest.c (+235/-0)
src/std/filters/test/syncTest.c (+367/-0)
src/std/filters/test/tsTest.c (+113/-0)
src/std/filters/test/xRecord.dbd (+12/-0)
src/std/filters/ts.c (+67/-0)
src/std/softIoc/base.dbd (+3/-0)
Text conflict in src/ioc/db/db_test.c
To merge this branch: bzr merge lp:~epics-core/epics-base/server-side-plugins
Reviewer Review Type Date Requested Status
Ralph Lange Pending
EPICS Core Developers Pending
Review via email: mp+108028@code.launchpad.net

Description of the change

This branch takes the changes from

lp:~ralph-lange/epics-base/server-side-plugins

And updates them to the current 3.15 branch. So when reviewing the changes please check also for unintentionally reverted changes from the 3.15 branch.

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

I've moved the filter plugins to src/std, which build Ok now, and am making some changes to the filter tests. I've copied the xRecord.dbd file and dbChannelTest.db into the filter/test directory rather than try to use them from some remote directory. Successfully loading the .dbd and .db files should not be counted as tests, they are pre-conditions of the actual tests to be able to run, so if they fail the test code should call call testAbort().

Is chfPluginTest.t supposed to produce these warnings?
  chfPluginTest.t ..... 1/1755
  Plugin buggy: provided storage (2 bytes) for i is too small for long (4)
  Plugin buggy: provided storage (2 bytes) for d is too small for double (8)
  Plugin buggy: provided storage (2 bytes) for s is too small for string (>= 4)
  Plugin buggy: provided storage (2 bytes) for c is too small for enum (4)
  chfPluginTest.t ..... ok

All the tests pass on linux-x86, but when I run them on 64-bit Linux chfPluginTest.t fails lots of tests and then core-dumps. I also get the following warning from arrTest and a similar core-dump:
  Plugin arr: provided storage (4 bytes) for s is too small for long (8)
Looking more deeply, the code inside chfPlugin.c is using long data types when it should be using epicsInt32. I'm working on fixing this, but it might take some time.

12360. By Andrew Johnson

Moved filter plugins, fixed portability issues.

The filter plugins are now in src/std/filters
and their tests in the test subdirectory.

Various portability issues found and fixed:
 * Variable declarations after statements in a block
 * Code assuming that epicsInt32 = long
 * // comments in C files

Removed a number of tests that weren't really tests;
preconditions for future tests that don't actually check
the code being tested should call testAbort() if the
condition fails, which tells the test harness that you
meant to die at that point.

Split up lots of very long source lines.

Probably made a few other changes that I forget about now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2009-12-23 21:06:44 +0000
3+++ .bzrignore 2012-06-21 20:42:45 +0000
4@@ -6,3 +6,6 @@
5 ./include
6 ./templates
7 **/O.*
8+./.cproject
9+./.project
10+./.settings
11
12=== modified file 'configure/RULES.Db'
13--- configure/RULES.Db 2012-05-29 21:44:49 +0000
14+++ configure/RULES.Db 2012-06-21 20:42:45 +0000
15@@ -397,12 +397,12 @@
16
17 %_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
18 @$(RM) $@ $*.tmp
19- $(REGISTERRECORDDEVICEDRIVER) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
20+ $(REGISTERRECORDDEVICEDRIVER) $(DBDFLAGS) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
21 $(MV) $*.tmp $@
22
23 %_registerRecordDeviceDriver.cpp: %.dbd
24 @$(RM) $@ $*.tmp
25- $(REGISTERRECORDDEVICEDRIVER) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
26+ $(REGISTERRECORDDEVICEDRIVER) $(DBDFLAGS) $< $(basename $@) $(IOC_INST_TOP) > $*.tmp
27 $(MV) $*.tmp $@
28
29 .PRECIOUS: %_registerRecordDeviceDriver.cpp
30
31=== modified file 'src/Makefile'
32--- src/Makefile 2012-03-14 20:27:40 +0000
33+++ src/Makefile 2012-06-21 20:42:45 +0000
34@@ -69,6 +69,10 @@
35 DIRS += std
36 std_DEPEND_DIRS = ioc libCom/RTEMS
37
38+DIRS += std/filters/test
39+std/filters/test_DEPEND_DIRS = std
40+
41+
42
43 include $(TOP)/configure/RULES_DIRS
44
45
46=== modified file 'src/ioc/as/asDbLib.c'
47--- src/ioc/as/asDbLib.c 2012-05-03 17:19:34 +0000
48+++ src/ioc/as/asDbLib.c 2012-06-21 20:42:45 +0000
49@@ -6,7 +6,7 @@
50 * Operator of Los Alamos National Laboratory.
51 * EPICS BASE Versions 3.13.7
52 * and higher are distributed subject to a Software License Agreement found
53-* in file LICENSE that is included with this distribution.
54+* in file LICENSE that is included with this distribution.
55 \*************************************************************************/
56 /* Author: Marty Kraimer Date: 02-11-94*/
57
58@@ -27,7 +27,7 @@
59 #include "caeventmask.h"
60 #include "callback.h"
61 #include "dbStaticLib.h"
62-#include "dbAddr.h"
63+#include "dbChannel.h"
64 #include "dbAccess.h"
65 #include "db_field_log.h"
66 #include "dbEvent.h"
67@@ -40,7 +40,7 @@
68 static char *psubstitutions=NULL;
69 static epicsThreadId asInitTheadId=0;
70 static int firstTime = TRUE;
71-
72
73+
74 static long asDbAddRecords(void)
75 {
76 DBENTRY dbentry;
77@@ -98,7 +98,7 @@
78 }
79 return(0);
80 }
81-
82
83+
84 static void asSpcAsCallback(struct dbCommon *precord)
85 {
86 asChangeGroup(&precord->asp, precord->asg);
87@@ -109,7 +109,7 @@
88 int *firstTime = (int *)arg;
89 *firstTime = FALSE;
90 }
91-
92+
93 static long asInitCommon(void)
94 {
95 long status;
96@@ -117,7 +117,7 @@
97 int wasFirstTime = firstTime;
98 static epicsThreadOnceId asInitCommonOnceFlag = EPICS_THREAD_ONCE_INIT;
99
100-
101+
102 epicsThreadOnce(&asInitCommonOnceFlag,asInitCommonOnce,(void *)&firstTime);
103 if(wasFirstTime) {
104 if(!pacf) return(0); /*access security will NEVER be turned on*/
105@@ -148,7 +148,7 @@
106 {
107 return(asInitCommon());
108 }
109-
110
111+
112 static void wdCallback(void *arg)
113 {
114 ASDBCALLBACK *pcallback = (ASDBCALLBACK *)arg;
115@@ -195,23 +195,15 @@
116 }
117 return(0);
118 }
119-
120
121-int epicsShareAPI asDbGetAsl(void *paddress)
122+
123+int epicsShareAPI asDbGetAsl(struct dbChannel *chan)
124 {
125- DBADDR *paddr = paddress;
126- dbFldDes *pflddes;
127-
128- pflddes = paddr->pfldDes;
129- return((int)pflddes->as_level);
130+ return dbChannelFldDes(chan)->as_level;
131 }
132
133-void * epicsShareAPI asDbGetMemberPvt(void *paddress)
134+void * epicsShareAPI asDbGetMemberPvt(struct dbChannel *chan)
135 {
136- DBADDR *paddr = paddress;
137- dbCommon *precord;
138-
139- precord = paddr->precord;
140- return((void *)precord->asp);
141+ return dbChannelRecord(chan)->asp;
142 }
143
144 static void astacCallback(ASCLIENTPVT clientPvt,asClientStatus status)
145@@ -259,7 +251,7 @@
146 }
147 return(0);
148 }
149-
150
151+
152 static void myMemberCallback(ASMEMBERPVT memPvt,FILE *fp)
153 {
154 dbCommon *precord;
155
156=== modified file 'src/ioc/as/asDbLib.h'
157--- src/ioc/as/asDbLib.h 2010-10-05 19:27:37 +0000
158+++ src/ioc/as/asDbLib.h 2012-06-21 20:42:45 +0000
159@@ -5,12 +5,12 @@
160 * Operator of Los Alamos National Laboratory.
161 * EPICS BASE Versions 3.13.7
162 * and higher are distributed subject to a Software License Agreement found
163-* in file LICENSE that is included with this distribution.
164+* in file LICENSE that is included with this distribution.
165 \*************************************************************************/
166 /* share/epicsH/dbAsLib.h */
167 /* $Revision-Id$ */
168 /* Author: Marty Kraimer Date: 02-23-94*/
169-
170
171+
172 #ifndef INCdbAsLibh
173 #define INCdbAsLibh
174
175@@ -22,6 +22,8 @@
176 long status;
177 } ASDBCALLBACK;
178
179+struct dbChannel;
180+
181 #ifdef __cplusplus
182 extern "C" {
183 #endif
184@@ -30,8 +32,8 @@
185 epicsShareFunc int epicsShareAPI asSetSubstitutions(const char *substitutions);
186 epicsShareFunc int epicsShareAPI asInit(void);
187 epicsShareFunc int epicsShareAPI asInitAsyn(ASDBCALLBACK *pcallback);
188-epicsShareFunc int epicsShareAPI asDbGetAsl( void *paddr);
189-epicsShareFunc void * epicsShareAPI asDbGetMemberPvt( void *paddr);
190+epicsShareFunc int epicsShareAPI asDbGetAsl(struct dbChannel *chan);
191+epicsShareFunc void * epicsShareAPI asDbGetMemberPvt(struct dbChannel *chan);
192 epicsShareFunc int epicsShareAPI asdbdump(void);
193 epicsShareFunc int epicsShareAPI asdbdumpFP(FILE *fp);
194 epicsShareFunc int epicsShareAPI aspuag(const char *uagname);
195
196=== modified file 'src/ioc/db/Makefile'
197--- src/ioc/db/Makefile 2011-11-14 23:38:36 +0000
198+++ src/ioc/db/Makefile 2012-06-21 20:42:45 +0000
199@@ -17,9 +17,12 @@
200 INC += dbCa.h
201 INC += dbAddr.h
202 INC += dbBkpt.h
203+INC += dbChannel.h
204 INC += dbConvert.h
205 INC += dbConvertFast.h
206+INC += dbExtractArray.h
207 INC += dbEvent.h
208+INC += dbLink.h
209 INC += dbLock.h
210 INC += dbNotify.h
211 INC += dbScan.h
212@@ -30,6 +33,8 @@
213 INC += initHooks.h
214 INC += recGbl.h
215 INC += dbIocRegister.h
216+INC += chfPlugin.h
217+INC += dbState.h
218 INC += db_access_routines.h
219 INC += db_convert.h
220
221@@ -50,11 +55,15 @@
222 DBDINC += $(basename $(menuGlobal_DBD))
223 DBDINC += dbCommon
224
225+
226 dbCore_SRCS += dbLock.c
227 dbCore_SRCS += dbAccess.c
228 dbCore_SRCS += dbBkpt.c
229+dbCore_SRCS += dbChannel.c
230 dbCore_SRCS += dbConvert.c
231 dbCore_SRCS += dbFastLinkConv.c
232+dbCore_SRCS += dbExtractArray.c
233+dbCore_SRCS += dbLink.c
234 dbCore_SRCS += dbNotify.c
235 dbCore_SRCS += dbScan.c
236 dbCore_SRCS += dbEvent.c
237@@ -74,4 +83,6 @@
238 dbCore_SRCS += dbContextReadNotifyCache.cpp
239 dbCore_SRCS += templateInstances.cpp
240 dbCore_SRCS += dbIocRegister.c
241+dbCore_SRCS += chfPlugin.c
242+dbCore_SRCS += dbState.c
243
244
245=== added file 'src/ioc/db/chfPlugin.c'
246--- src/ioc/db/chfPlugin.c 1970-01-01 00:00:00 +0000
247+++ src/ioc/db/chfPlugin.c 2012-06-21 20:42:45 +0000
248@@ -0,0 +1,649 @@
249+/*************************************************************************\
250+* Copyright (c) 2010 Brookhaven National Laboratory.
251+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
252+* fuer Materialien und Energie GmbH.
253+* EPICS BASE is distributed subject to a Software License Agreement found
254+* in file LICENSE that is included with this distribution.
255+\*************************************************************************/
256+
257+/*
258+ * Author: Ralph Lange <Ralph.Lange@bessy.de>
259+ */
260+
261+/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
262+
263+#include <stdlib.h>
264+#include <errno.h>
265+#include <string.h>
266+#include <limits.h>
267+#include <math.h>
268+
269+#include <dbDefs.h>
270+#include <dbStaticLib.h>
271+#include <epicsTypes.h>
272+#include <epicsStdio.h>
273+#include <epicsString.h>
274+#include <errlog.h>
275+#include <shareLib.h>
276+
277+#define epicsExportSharedSymbols
278+#include "chfPlugin.h"
279+
280+#ifndef HUGE_VALF
281+# define HUGE_VALF HUGE_VAL
282+#endif
283+#ifndef HUGE_VALL
284+# define HUGE_VALL (-(HUGE_VAL))
285+#endif
286+
287+/*
288+ * Data for a chfPlugin
289+ */
290+typedef struct chfPlugin {
291+ const chfPluginArgDef *opts;
292+ size_t nopts;
293+ epicsUInt32 *required;
294+ const chfPluginIf *pif;
295+} chfPlugin;
296+
297+/*
298+ * Parser state data for a chfFilter (chfPlugin instance)
299+ */
300+typedef struct chfFilter {
301+ const chfPlugin *plugin;
302+ epicsUInt32 *found;
303+ void *puser;
304+ epicsInt16 nextParam;
305+} chfFilter;
306+
307+/* Data types we get from the parser */
308+typedef enum chfPluginType {
309+ chfPluginTypeBool,
310+ chfPluginTypeInt,
311+ chfPluginTypeDouble,
312+ chfPluginTypeString
313+} chfPluginType;
314+
315+/*
316+ * Convert the (long) integer value 'val' to the type named in 'opt->optType'
317+ * and store the result at 'user + opt->offset'.
318+ */
319+static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
320+{
321+ epicsInt32 *ival;
322+ int *eval;
323+ const chfPluginEnumType *emap;
324+ double *dval;
325+ char *sval;
326+ char buff[22]; /* 2^64 = 1.8e+19, so 20 digits plus sign max */
327+
328+/* printf("Got an integer for %s (type %d): %ld\n", opt->name, opt->optType, val); */
329+
330+ if (!opt->convert && opt->optType != chfPluginArgInt32) {
331+ return -1;
332+ }
333+
334+ switch (opt->optType) {
335+ case chfPluginArgInt32:
336+ ival = (epicsInt32 *) ((char *)user + opt->offset);
337+ *ival = val;
338+ break;
339+ case chfPluginArgBoolean:
340+ eval = (int*) ((char*)user + opt->offset);
341+ *eval = !!val;
342+ break;
343+ case chfPluginArgDouble:
344+ dval = (double*) ((char*)user + opt->offset);
345+ *dval = (double) val;
346+ break;
347+ case chfPluginArgString:
348+ sval = ((char*)user + opt->offset);
349+ sprintf(buff, "%ld", val);
350+ if (strlen(buff) > opt->size-1) {
351+ return -1;
352+ }
353+ strncpy(sval, buff, opt->size-1);
354+ sval[opt->size-1]='\0';
355+ break;
356+ case chfPluginArgEnum:
357+ eval = (int*) ((char*)user + opt->offset);
358+ for (emap = opt->enums; emap && emap->name; emap++) {
359+ if (val == emap->value) {
360+ *eval = val;
361+ break;
362+ }
363+ }
364+ if (!emap || !emap->name) {
365+ return -1;
366+ }
367+ break;
368+ case chfPluginArgInvalid:
369+ return -1;
370+ }
371+ return 0;
372+}
373+
374+/*
375+ * Convert the (int) boolean value 'val' to the type named in 'opt->optType'
376+ * and store the result at 'user + opt->offset'.
377+ */
378+static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
379+{
380+ epicsInt32 *ival;
381+ int *eval;
382+ double *dval;
383+ char *sval;
384+
385+/* printf("Got a boolean for %s (type %d): %d\n", opt->name, opt->optType, val); */
386+
387+ if (!opt->convert && opt->optType != chfPluginArgBoolean) {
388+ return -1;
389+ }
390+
391+ switch (opt->optType) {
392+ case chfPluginArgInt32:
393+ ival = (epicsInt32 *) ((char*)user + opt->offset);
394+ *ival = val;
395+ break;
396+ case chfPluginArgBoolean:
397+ eval = (int*) ((char*)user + opt->offset);
398+ *eval = val;
399+ break;
400+ case chfPluginArgDouble:
401+ dval = (double*) ((char*)user + opt->offset);
402+ *dval = val ? 1. : 0.;
403+ break;
404+ case chfPluginArgString:
405+ sval = ((char*)user + opt->offset);
406+ if ((val ? 4 : 5) > opt->size-1) {
407+ return -1;
408+ }
409+ strncpy(sval, (val ? "true" : "false"), opt->size-1);
410+ sval[opt->size-1]='\0';
411+ break;
412+ case chfPluginArgEnum:
413+ case chfPluginArgInvalid:
414+ return -1;
415+ }
416+ return 0;
417+}
418+
419+/*
420+ * Convert the double value 'val' to the type named in 'opt->optType'
421+ * and store the result at 'user + opt->offset'.
422+ */
423+static int store_double_value(const chfPluginArgDef *opt, void *user, double val)
424+{
425+ epicsInt32 *ival;
426+ int *eval;
427+ double *dval;
428+ char *sval;
429+ int i;
430+
431+/*
432+ printf("Got a double for %s (type %d, convert: %s): %g\n",
433+ opt->name, opt->optType, opt->convert?"yes":"no", val);
434+*/
435+ if (!opt->convert && opt->optType != chfPluginArgDouble) {
436+ return -1;
437+ }
438+
439+ switch (opt->optType) {
440+ case chfPluginArgInt32:
441+#if (LONG_MAX > 0x7fffffff)
442+ if (val < -0x80000000L || val > 0x7fffffff) {
443+ return -1;
444+ }
445+#endif
446+ ival = (epicsInt32 *) ((char*)user + opt->offset);
447+ *ival = val;
448+ break;
449+ case chfPluginArgBoolean:
450+ eval = (int*) ((char*)user + opt->offset);
451+ *eval = (val != 0.) ? 1 : 0;
452+ break;
453+ case chfPluginArgDouble:
454+ dval = (double*) ((char*)user + opt->offset);
455+ *dval = val;
456+ break;
457+ case chfPluginArgString:
458+ sval = ((char*)user + opt->offset);
459+ if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
460+ return -1;
461+ }
462+ i = epicsSnprintf(sval, opt->size, "%.*g", (int) opt->size - 7, val);
463+ if (i >= opt->size) {
464+ return -1;
465+ }
466+ break;
467+ case chfPluginArgEnum:
468+ case chfPluginArgInvalid:
469+ return -1;
470+ }
471+ return 0;
472+}
473+
474+/*
475+ * Convert the (char*) string value 'val' to the type named in 'opt->optType'
476+ * and store the result at 'user + opt->offset'.
477+ */
478+static int store_string_value(const chfPluginArgDef *opt, void *user, const char *val, size_t len)
479+{
480+ epicsInt32 *ival;
481+ long lval;
482+ int *eval;
483+ const chfPluginEnumType *emap;
484+ double *dval;
485+ char *sval;
486+ char *end;
487+ int i;
488+
489+/* printf("Got a string for %s (type %d): %.*s\n", opt->name, opt->optType, len, val); */
490+
491+ if (!opt->convert && opt->optType != chfPluginArgString && opt->optType != chfPluginArgEnum) {
492+ return -1;
493+ }
494+
495+ switch (opt->optType) {
496+ case chfPluginArgInt32:
497+ lval = strtol(val, &end, 0);
498+ /* test for the myriad error conditions which strtol may use */
499+ if (lval == LONG_MAX || lval == LONG_MIN
500+#if (LONG_MAX > 0x7fffffff)
501+ || lval < -0x80000000L || lval > 0x7fffffff
502+#endif
503+ || end == val) {
504+ return -1;
505+ }
506+ ival = (epicsInt32 *) ((char*)user + opt->offset);
507+ *ival = lval;
508+ break;
509+ case chfPluginArgBoolean:
510+ eval = (int*) ((char*)user + opt->offset);
511+ if (epicsStrnCaseCmp(val, "true", len) == 0) {
512+ *eval = 1;
513+ } else if (epicsStrnCaseCmp(val, "false", len) == 0) {
514+ *eval = 0;
515+ } else {
516+ i = strtol(val, &end, 0);
517+ if (i > INT_MAX || i < INT_MIN || end == val) {
518+ return -1;
519+ }
520+ *eval = !!i;
521+ }
522+ break;
523+ case chfPluginArgDouble:
524+ dval = (double*) ((char*)user + opt->offset);
525+ *dval = strtod(val, &end);
526+ /* Indicates errors in the same manner as strtol */
527+ if (*dval==HUGE_VALF||*dval==HUGE_VALL||end==val )
528+ {
529+ return -1;
530+ }
531+ break;
532+ case chfPluginArgString:
533+ i = opt->size-1 < len ? opt->size-1 : len;
534+ sval = ((char*)user + opt->offset);
535+ strncpy(sval, val, i);
536+ sval[i] = '\0';
537+ break;
538+ case chfPluginArgEnum:
539+ eval = (int*) ((char*)user + opt->offset);
540+ for (emap = opt->enums; emap && emap->name; emap++) {
541+ if (strncmp(emap->name, val, len) == 0) {
542+ *eval = emap->value;
543+ break;
544+ }
545+ }
546+ if( !emap || !emap->name ) {
547+ return -1;
548+ }
549+ break;
550+ case chfPluginArgInvalid:
551+ return -1;
552+ }
553+ return 0;
554+}
555+
556+static void freeInstanceData(chfFilter *f)
557+{
558+ free(f->found); /* FIXME: Use a free-list */
559+ free(f); /* FIXME: Use a free-list */
560+}
561+
562+/*
563+ * chFilterIf callbacks
564+ */
565+
566+/* First entry point when a new filter instance is created.
567+ * All per-instance allocations happen here.
568+ */
569+static parse_result parse_start(chFilter *filter)
570+{
571+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
572+ chfFilter *f;
573+
574+ /* Filter context */
575+ /* FIXME: Use a free-list */
576+ f = calloc(1, sizeof(chfFilter));
577+ if (!f) {
578+ fprintf(stderr,"chfFilterCtx calloc failed\n");
579+ goto errfctx;
580+ }
581+ f->nextParam = -1;
582+
583+ /* Bit array to find missing required keys */
584+ /* FIXME: Use a free-list */
585+ f->found = calloc( (p->nopts/32)+1, sizeof(epicsUInt32) );
586+ if (!f->found) {
587+ fprintf(stderr,"chfConfigParseStart: bit array calloc failed\n");
588+ goto errbitarray;
589+ }
590+
591+ /* Call the plugin to allocate its structure, it returns NULL on error */
592+ if (p->pif->allocPvt) {
593+ if ((f->puser = p->pif->allocPvt()) == NULL)
594+ goto errplugin;
595+ }
596+
597+ filter->puser = (void*) f;
598+
599+ return parse_continue;
600+
601+ errplugin:
602+ free(f->found); /* FIXME: Use a free-list */
603+ errbitarray:
604+ free(f); /* FIXME: Use a free-list */
605+ errfctx:
606+ return parse_stop;
607+}
608+
609+static void parse_abort(chFilter *filter) {
610+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
611+ chfFilter *f = (chfFilter*) filter->puser;
612+
613+ /* Call the plugin to tell it we're aborting */
614+ if (p->pif->parse_error) p->pif->parse_error(f->puser);
615+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
616+ freeInstanceData(f);
617+}
618+
619+static parse_result parse_end(chFilter *filter)
620+{
621+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
622+ chfFilter *f = (chfFilter*) filter->puser;
623+ int i;
624+
625+ /* Check if all required arguments were supplied */
626+ for(i = 0; i < (p->nopts/32)+1; i++) {
627+ if ((f->found[i] & p->required[i]) != p->required[i]) {
628+ if (p->pif->parse_error) p->pif->parse_error(f->puser);
629+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
630+ freeInstanceData(f);
631+ return parse_stop;
632+ }
633+ }
634+
635+ /* Call the plugin to tell it we're done */
636+ if (p->pif->parse_ok) {
637+ if (p->pif->parse_ok(f->puser)) {
638+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
639+ freeInstanceData(f);
640+ return parse_stop;
641+ }
642+ }
643+
644+ return parse_continue;
645+}
646+
647+static parse_result parse_boolean(chFilter *filter, int boolVal)
648+{
649+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
650+ chfFilter *f = (chfFilter*)filter->puser;
651+
652+ if (f->nextParam < 0 || store_boolean_value(&opts[f->nextParam], f->puser, boolVal)) {
653+ return parse_stop;
654+ } else {
655+ return parse_continue;
656+ }
657+}
658+
659+static parse_result parse_integer(chFilter *filter, long integerVal)
660+{
661+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
662+ chfFilter *f = (chfFilter*)filter->puser;
663+
664+ if (f->nextParam < 0 || store_integer_value(&opts[f->nextParam], f->puser, integerVal)) {
665+ return parse_stop;
666+ } else {
667+ return parse_continue;
668+ }
669+}
670+
671+static parse_result parse_double(chFilter *filter, double doubleVal)
672+{
673+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
674+ chfFilter *f = (chfFilter*)filter->puser;
675+
676+ if (f->nextParam < 0 || store_double_value(&opts[f->nextParam], f->puser, doubleVal)) {
677+ return parse_stop;
678+ } else {
679+ return parse_continue;
680+ }
681+}
682+
683+static parse_result parse_string(chFilter *filter, const char *stringVal, size_t stringLen)
684+{
685+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
686+ chfFilter *f = (chfFilter*)filter->puser;
687+
688+ if (f->nextParam < 0 || store_string_value(&opts[f->nextParam], f->puser, stringVal, stringLen)) {
689+ return parse_stop;
690+ } else {
691+ return parse_continue;
692+ }
693+}
694+
695+static parse_result parse_start_map(chFilter *filter)
696+{
697+ return parse_continue;
698+}
699+
700+static parse_result parse_map_key(chFilter *filter, const char *key, size_t stringLen)
701+{
702+ const chfPluginArgDef *cur;
703+ const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
704+ chfFilter *f = (chfFilter*)filter->puser;
705+ int i;
706+
707+ f->nextParam = -1;
708+ for(cur = opts, i = 0; cur && cur->name; cur++, i++) {
709+ if (strncmp(key, cur->name, stringLen) == 0) {
710+ f->nextParam = i;
711+ break;
712+ }
713+ }
714+ if (f->nextParam == -1) {
715+ return parse_stop;
716+ }
717+
718+ f->found[i/32] |= 1<<(i%32);
719+ return parse_continue;
720+}
721+
722+static parse_result parse_end_map(chFilter *filter)
723+{
724+ return parse_continue;
725+}
726+
727+static long channel_open(chFilter *filter)
728+{
729+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
730+ chfFilter *f = (chfFilter*) filter->puser;
731+
732+ if (p->pif->channel_open) return p->pif->channel_open(filter->chan, f->puser);
733+ else return 0;
734+}
735+
736+static void channel_register_pre(chFilter *filter,
737+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
738+{
739+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
740+ chfFilter *f = (chfFilter*) filter->puser;
741+
742+ if (p->pif->channelRegisterPre)
743+ p->pif->channelRegisterPre(filter->chan, f->puser, cb_out, arg_out, probe);
744+}
745+
746+static void channel_register_post(chFilter *filter,
747+ chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
748+{
749+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
750+ chfFilter *f = (chfFilter*) filter->puser;
751+
752+ if (p->pif->channelRegisterPost)
753+ p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out, probe);
754+}
755+
756+static void channel_report(chFilter *filter, int level, const unsigned short indent)
757+{
758+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
759+ chfFilter *f = (chfFilter*) filter->puser;
760+
761+ if (p->pif->channel_report)
762+ p->pif->channel_report(filter->chan, f->puser, level, indent);
763+}
764+
765+static void channel_close(chFilter *filter)
766+{
767+ chfPlugin *p = (chfPlugin*) filter->plug->puser;
768+ chfFilter *f = (chfFilter*) filter->puser;
769+
770+ if (p->pif->channel_close) p->pif->channel_close(filter->chan, f->puser);
771+ if (p->pif->freePvt) p->pif->freePvt(f->puser);
772+ free(f->found); /* FIXME: Use a free-list */
773+ free(f); /* FIXME: Use a free-list */
774+}
775+
776+/*
777+ * chFilterIf for the wrapper
778+ * we just support a simple one-level map, and no arrays
779+ */
780+static chFilterIf wrapper_fif = {
781+ parse_start,
782+ parse_abort,
783+ parse_end,
784+
785+ NULL, /* parse_null, */
786+ parse_boolean,
787+ parse_integer,
788+ parse_double,
789+ parse_string,
790+
791+ parse_start_map,
792+ parse_map_key,
793+ parse_end_map,
794+
795+ NULL, /* parse_start_array, */
796+ NULL, /* parse_end_array, */
797+
798+ channel_open,
799+ channel_register_pre,
800+ channel_register_post,
801+ channel_report,
802+ channel_close
803+};
804+
805+const char* chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
806+{
807+ for(; emap && emap->name; emap++) {
808+ if ( i == emap->value ) {
809+ return emap->name;
810+ }
811+ }
812+ return def;
813+}
814+
815+int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts)
816+{
817+ chfPlugin *p;
818+ size_t i;
819+ const chfPluginArgDef *cur;
820+ epicsUInt32 *reqd;
821+
822+ /* Check and count options */
823+ for (i = 0, cur = opts; cur && cur->name; i++, cur++) {
824+ switch(cur->optType) {
825+ case chfPluginArgInt32:
826+ if (cur->size < sizeof(epicsInt32)) {
827+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for epicsInt32 (%lu)\n",
828+ key, cur->size, cur->name,
829+ (unsigned long) sizeof(epicsInt32));
830+ return -1;
831+ }
832+ break;
833+ case chfPluginArgBoolean:
834+ if (cur->size < 1) {
835+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for boolean (%lu)\n",
836+ key, cur->size, cur->name,
837+ (unsigned long) sizeof(char));
838+ return -1;
839+ }
840+ break;
841+ case chfPluginArgDouble:
842+ if (cur->size < sizeof(double)) {
843+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for double (%lu)\n",
844+ key, cur->size, cur->name,
845+ (unsigned long) sizeof(double));
846+ return -1;
847+ }
848+ break;
849+ case chfPluginArgString:
850+ if (cur->size < sizeof(char*)) {
851+ /* Catch if someone has given us a char* instead of a char[]
852+ * Also means that char buffers must be >=4.
853+ */
854+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for string (>= %lu)\n",
855+ key, cur->size, cur->name,
856+ (unsigned long) sizeof(char*));
857+ return -1;
858+ }
859+ break;
860+ case chfPluginArgEnum:
861+ if (cur->size < sizeof(int)) {
862+ errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for enum (%lu)\n",
863+ key, cur->size, cur->name,
864+ (unsigned long) sizeof(int));
865+ return -1;
866+ }
867+ break;
868+ case chfPluginArgInvalid:
869+ errlogPrintf("Plugin %s: storage type for %s is not defined\n",
870+ key, cur->name);
871+ return -1;
872+ break;
873+ }
874+ }
875+
876+ /* Bit array used to find missing required keys */
877+ reqd = dbCalloc((i/32)+1, sizeof(epicsUInt32));
878+ if (!reqd) {
879+ fprintf(stderr,"Plugin %s: bit array calloc failed\n", key);
880+ return -1;
881+ }
882+
883+ for (i = 0, cur = opts; cur && cur->name; i++, cur++) {
884+ if (cur->required) reqd[i/32] |= 1 << (i%32);
885+ }
886+
887+ /* Plugin data */
888+ p = dbCalloc(1, sizeof(chfPlugin));
889+ p->pif = pif;
890+ p->opts = opts;
891+ p->nopts = i;
892+ p->required = reqd;
893+
894+ dbRegisterFilter(key, &wrapper_fif, p);
895+
896+ return 0;
897+}
898
899=== added file 'src/ioc/db/chfPlugin.h'
900--- src/ioc/db/chfPlugin.h 1970-01-01 00:00:00 +0000
901+++ src/ioc/db/chfPlugin.h 2012-06-21 20:42:45 +0000
902@@ -0,0 +1,280 @@
903+/*************************************************************************\
904+* Copyright (c) 2010 Brookhaven National Laboratory.
905+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
906+* fuer Materialien und Energie GmbH.
907+* EPICS BASE is distributed subject to a Software License Agreement found
908+* in file LICENSE that is included with this distribution.
909+\*************************************************************************/
910+
911+/*
912+ * Author: Ralph Lange <Ralph.Lange@bessy.de>
913+ */
914+
915+/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
916+
917+#ifndef CHFPLUGIN_H
918+#define CHFPLUGIN_H
919+
920+#include <shareLib.h>
921+#include <dbDefs.h>
922+#include <epicsTypes.h>
923+#include <dbChannel.h>
924+
925+struct db_field_log;
926+
927+/** @file chfPlugin.h
928+ * @brief Channel filter simplified plugins.
929+ *
930+ * Utility layer to allow an easier (reduced) interface for
931+ * channel filter plugins.
932+ *
933+ * Parsing the configuration arguments of a channel filter plugin
934+ * is done according to an argument description table provided by the plugin.
935+ * The parser stores the results directly into a user supplied structure
936+ * after appropriate type conversion.
937+ *
938+ * To specify the arguments, a chfPluginArgDef table must be defined
939+ * for the user structure. This table has to be specified when the plugin registers.
940+ *
941+ * The plugin is responsible to register an init function using
942+ * epicsExportRegistrar() and the accompanying registrar() directive in the dbd,
943+ * and call chfPluginRegister() from within the init function.
944+ *
945+ * For example:
946+ *
947+ * typedef struct myStruct {
948+ * ... other stuff
949+ * epicsUInt32 ival;
950+ * double dval;
951+ * epicsUInt32 ival2;
952+ * int enumval;
953+ * char strval[20];
954+ * } myStruct;
955+ *
956+ * static const
957+ * chfPluginEnumType colorEnum[] = { {"Red",1}, {"Green",2}, {"Blue",3}, {NULL,0} };
958+ *
959+ * static const
960+ * chfPluginDef myStructDef[] = {
961+ * chfInt32 (myStruct, ival, "Integer" , 0, 0),
962+ * chfInt32 (myStruct, ival2, "Second" , 1, 0),
963+ * chfDouble(myStruct, dval, "Double" , 1, 0),
964+ * chfString(myStruct, strval , "String" , 1, 0),
965+ * chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
966+ * chfPluginEnd
967+ * };
968+ *
969+ * Note: The 4th argument specifies the parameter to be required (1) or optional (0),
970+ * the 5th whether converting to the required type is allowed (1), or
971+ * type mismatches are an error (0).
972+ *
973+ */
974+
975+#ifdef __cplusplus
976+extern "C" {
977+#endif
978+
979+/** @brief Channel filter simplified plugin interface.
980+ *
981+ * The routines in this structure must be implemented by each filter plugin.
982+ */
983+typedef struct chfPluginIf {
984+
985+ /* Memory management */
986+ /** @brief Allocate private resources.
987+ *
988+ * <em>Called before parsing starts.</em>
989+ * The plugin should allocate its per-instance structures,
990+ * returning a pointer to them or NULL requesting an abort of the operation.
991+ *
992+ * allocPvt may be set to NULL, if no resource allocation is needed.
993+ *
994+ * @return Pointer to private structure, NULL if operation is to be aborted.
995+ */
996+ void * (* allocPvt) (void);
997+
998+ /** @brief Free private resources.
999+ *
1000+ * <em>Called as part of abort or shutdown.</em>
1001+ * The plugin should release any resources allocated for this filter;
1002+ * no further calls through this interface will be made.
1003+ *
1004+ * freePvt may be set to NULL, if no resources need to be released.
1005+ *
1006+ * @param pvt Pointer to private structure.
1007+ */
1008+ void (* freePvt) (void *pvt);
1009+
1010+ /* Parameter parsing results */
1011+ /** @brief A parsing error occurred.
1012+ *
1013+ * <em>Called after parsing failed with an error.</em>
1014+ *
1015+ * @param pvt Pointer to private structure.
1016+ */
1017+ void (* parse_error) (void *pvt);
1018+
1019+ /** @brief Configuration has been parsed successfully.
1020+ *
1021+ * <em>Called after parsing has finished ok.</em>
1022+ * The plugin may check the validity of the parsed data,
1023+ * returning -1 to request an abort of the operation.
1024+ *
1025+ * @param pvt Pointer to private structure.
1026+ * @return 0 for success, -1 if operation is to be aborted.
1027+ */
1028+ int (* parse_ok) (void *pvt);
1029+
1030+ /* Channel operations */
1031+ /** @brief Open channel.
1032+ *
1033+ * <em>Called as part of the channel connection setup.</em>
1034+ *
1035+ * @param chan dbChannel for which the connection is being made.
1036+ * @param pvt Pointer to private structure.
1037+ * @return 0 for success, -1 if operation is to be aborted.
1038+ */
1039+ long (* channel_open) (dbChannel *chan, void *pvt);
1040+
1041+ /** @brief Register callbacks for pre-event-queue operation.
1042+ *
1043+ * <em>Called as part of the channel connection setup.</em>
1044+ *
1045+ * This function is called to establish the stack of plugins that an event
1046+ * is passed through between the database and the event queue.
1047+ *
1048+ * The plugin must set pe_out to point to its own post-event callback in order
1049+ * to be called when a data update is sent from the database towards the
1050+ * event queue.
1051+ *
1052+ * The plugin may find out the type of data it will receive by looking at 'probe'.
1053+ * If the plugin will change the data type and/or size, it must update 'probe'
1054+ * accordingly.
1055+ *
1056+ * @param chan dbChannel for which the connection is being made.
1057+ * @param pvt Pointer to private structure.
1058+ * @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
1059+ * this plugin).
1060+ * @param arg_out Argument that must be supplied when calling
1061+ * this plugin's post-event callback.
1062+ */
1063+ void (* channelRegisterPre) (dbChannel *chan, void *pvt,
1064+ chPostEventFunc **cb_out, void **arg_out,
1065+ db_field_log *probe);
1066+
1067+ /** @brief Register callbacks for post-event-queue operation.
1068+ *
1069+ * <em>Called as part of the channel connection setup.</em>
1070+ *
1071+ * This function is called to establish the stack of plugins that an event
1072+ * is passed through between the event queue and the final user (CA server or
1073+ * database access).
1074+ *
1075+ * The plugin must set pe_out to point to its own post-event callback in order
1076+ * to be called when a data update is sent from the event queue towards the
1077+ * final user.
1078+ *
1079+ * The plugin may find out the type of data it will receive by looking at 'probe'.
1080+ * If the plugin will change the data type and/or size, it must update 'probe'
1081+ * accordingly.
1082+ *
1083+ * @param chan dbChannel for which the connection is being made.
1084+ * @param pvt Pointer to private structure.
1085+ * @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
1086+ * this plugin).
1087+ * @param arg_out Argument that must be supplied when calling
1088+ * this plugin's post-event callback.
1089+ */
1090+ void (* channelRegisterPost) (dbChannel *chan, void *pvt,
1091+ chPostEventFunc **cb_out, void **arg_out,
1092+ db_field_log *probe);
1093+
1094+ /** @brief Channel report request.
1095+ *
1096+ * <em>Called as part of show... routines.</em>
1097+ *
1098+ * @param chan dbChannel for which the report is requested.
1099+ * @param pvt Pointer to private structure.
1100+ * @param level Interest level.
1101+ * @param indent Number of spaces to print before each output line.
1102+ */
1103+ void (* channel_report) (dbChannel *chan, void *pvt, int level, const unsigned short indent);
1104+
1105+ /* FIXME: More filter routines here ... */
1106+
1107+ /** @brief Channel close request.
1108+ *
1109+ * <em>Called as part of connection shutdown.</em>
1110+ * @param chan dbChannel for which the connection is being shut down.
1111+ * @param pvt Pointer to private structure.
1112+ */
1113+ void (* channel_close) (dbChannel *chan, void *pvt);
1114+
1115+} chfPluginIf;
1116+
1117+typedef enum chfPluginArg {
1118+ chfPluginArgInvalid=0,
1119+ chfPluginArgBoolean,
1120+ chfPluginArgInt32,
1121+ chfPluginArgDouble,
1122+ chfPluginArgString,
1123+ chfPluginArgEnum
1124+} chfPluginArg;
1125+
1126+typedef struct chfPluginEnumType {
1127+ const char *name;
1128+ const int value;
1129+} chfPluginEnumType;
1130+
1131+typedef struct chfPluginArgDef {
1132+ const char * name;
1133+ chfPluginArg optType;
1134+ unsigned int required:1;
1135+ unsigned int convert:1;
1136+ epicsUInt32 offset;
1137+ epicsUInt32 size;
1138+ const chfPluginEnumType *enums;
1139+} chfPluginArgDef;
1140+
1141+#define chfInt32(Struct, Member, Name, Req, Conv) \
1142+{Name, chfPluginArgInt32, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
1143+
1144+#define chfBoolean(Struct, Member, Name, Req, Conv) \
1145+{Name, chfPluginArgBoolean, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
1146+
1147+#define chfDouble(Struct, Member, Name, Req, Conv) \
1148+{Name, chfPluginArgDouble, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
1149+
1150+#define chfString(Struct, Member, Name, Req, Conv) \
1151+{Name, chfPluginArgString, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
1152+
1153+#define chfEnum(Struct, Member, Name, Req, Conv, Enums) \
1154+{Name, chfPluginArgEnum, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
1155+
1156+#define chfPluginArgEnd {0}
1157+
1158+/* Extra output when parsing and converting */
1159+#define CHFPLUGINDEBUG 1
1160+
1161+/** @brief Return the string associated with Enum index 'i'.
1162+ *
1163+ * @param Enums A null-terminated array of string/integer pairs.
1164+ * @param i An Enum index.
1165+ * @param def String to be returned when 'i' isn't a valid Enum index.
1166+ * @return The string associated with 'i'.
1167+ */
1168+epicsShareFunc const char* chfPluginEnumString(const chfPluginEnumType *Enums, int i, const char* def);
1169+
1170+/** @brief Register a plugin.
1171+ *
1172+ * @param key The plugin name key that clients will use.
1173+ * @param pif Pointer to the plugin's interface.
1174+ * @param opts Pointer to the configuration argument description table.
1175+ */
1176+epicsShareFunc int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts);
1177+
1178+#ifdef __cplusplus
1179+}
1180+#endif
1181+
1182+#endif // CHFPLUGIN_H
1183
1184=== modified file 'src/ioc/db/dbAccess.c'
1185--- src/ioc/db/dbAccess.c 2012-02-20 16:01:04 +0000
1186+++ src/ioc/db/dbAccess.c 2012-06-21 20:42:45 +0000
1187@@ -1,21 +1,22 @@
1188 /*************************************************************************\
1189+* Copyright (c) 2010 Brookhaven National Laboratory.
1190+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
1191+* fuer Materialien und Energie GmbH.
1192 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
1193 * National Laboratory.
1194 * Copyright (c) 2002 The Regents of the University of California, as
1195 * Operator of Los Alamos National Laboratory.
1196-* EPICS BASE Versions 3.13.7
1197-* and higher are distributed subject to a Software License Agreement found
1198-* in file LICENSE that is included with this distribution.
1199+* EPICS BASE is distributed subject to a Software License Agreement found
1200+* in file LICENSE that is included with this distribution.
1201 \*************************************************************************/
1202-/* dbAccess.c */
1203-/* $Revision-Id$ */
1204+
1205 /*
1206 * Original Author: Bob Dalesio
1207 * Current Author: Marty Kraimer
1208- * Date: 11-7-90
1209-*/
1210+ * Andrew Johnson <anj@aps.anl.gov>
1211+ * Ralph Lange <Ralph.Lange@bessy.de>
1212+ */
1213
1214-
1215
1216 #include <stddef.h>
1217 #include <stdlib.h>
1218 #include <stdarg.h>
1219@@ -46,6 +47,7 @@
1220 #include "dbAddr.h"
1221 #include "callback.h"
1222 #include "dbScan.h"
1223+#include "dbLink.h"
1224 #include "dbLock.h"
1225 #include "dbEvent.h"
1226 #include "dbConvert.h"
1227@@ -89,17 +91,6 @@
1228
1229 /* The following is to handle SPC_AS */
1230 static SPC_ASCALLBACK spcAsCallback = 0;
1231-
1232
1233-static void inherit_severity(const struct pv_link *ppv_link,
1234- dbCommon *pdest, epicsEnum16 stat, epicsEnum16 sevr)
1235-{
1236- switch(ppv_link->pvlMask&pvlOptMsMode) {
1237- case pvlOptNMS: break;
1238- case pvlOptMSI: if (sevr < INVALID_ALARM) break;
1239- case pvlOptMS: recGblSetSevr(pdest,LINK_ALARM,sevr); break;
1240- case pvlOptMSS: recGblSetSevr(pdest,stat,sevr); break;
1241- }
1242-}
1243
1244 void epicsShareAPI dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
1245 {
1246@@ -113,7 +104,7 @@
1247 dbCommon *precord = paddr->precord;
1248 long status=0;
1249 long special=paddr->special;
1250-
1251+
1252 prset = dbGetRset(paddr);
1253 if(special<100) { /*global processing*/
1254 if((special==SPC_NOMOD) && (pass==0)) {
1255@@ -139,7 +130,7 @@
1256 }
1257 return(0);
1258 }
1259-
1260
1261+
1262 static void get_enum_strs(DBADDR *paddr, char **ppbuffer,
1263 struct rset *prset,long *options)
1264 {
1265@@ -199,7 +190,7 @@
1266 *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;
1267 return;
1268 }
1269-
1270
1271+
1272 static void get_graphics(DBADDR *paddr, char **ppbuffer,
1273 struct rset *prset,long *options)
1274 {
1275@@ -239,7 +230,7 @@
1276 }
1277 return;
1278 }
1279-
1280
1281+
1282 static void get_control(DBADDR *paddr, char **ppbuffer,
1283 struct rset *prset,long *options)
1284 {
1285@@ -279,7 +270,7 @@
1286 }
1287 return;
1288 }
1289-
1290
1291+
1292 static void get_alarm(DBADDR *paddr, char **ppbuffer,
1293 struct rset *prset,long *options)
1294 {
1295@@ -324,35 +315,44 @@
1296 }
1297 return;
1298 }
1299-
1300
1301-static void getOptions(DBADDR *paddr,char **poriginal,long *options,void *pflin)
1302+
1303+/*
1304+ * This code relies on *poriginal being aligned and all increments done by the
1305+ * blocks only changing the buffer pointer in a way that does not break alignment.
1306+ */
1307+static void getOptions(DBADDR *paddr, char **poriginal, long *options,
1308+ void *pflin)
1309 {
1310 db_field_log *pfl= (db_field_log *)pflin;
1311 struct rset *prset;
1312- short field_type=paddr->field_type;
1313+ short field_type;
1314 dbCommon *pcommon;
1315 char *pbuffer = *poriginal;
1316
1317+ if (!pfl || pfl->type == dbfl_type_rec)
1318+ field_type = paddr->field_type;
1319+ else
1320+ field_type = pfl->field_type;
1321 prset=dbGetRset(paddr);
1322 /* Process options */
1323 pcommon = paddr->precord;
1324 if( (*options) & DBR_STATUS ) {
1325 unsigned short *pushort = (unsigned short *)pbuffer;
1326
1327- if(pfl!=NULL) {
1328- *pushort++ = pfl->stat;
1329- *pushort++ = pfl->sevr;
1330- } else {
1331- *pushort++ = pcommon->stat;
1332- *pushort++ = pcommon->sevr;
1333- }
1334+ if (!pfl || pfl->type == dbfl_type_rec) {
1335+ *pushort++ = pcommon->stat;
1336+ *pushort++ = pcommon->sevr;
1337+ } else {
1338+ *pushort++ = pfl->stat;
1339+ *pushort++ = pfl->sevr;
1340+ }
1341 *pushort++ = pcommon->acks;
1342 *pushort++ = pcommon->ackt;
1343 pbuffer = (char *)pushort;
1344 }
1345 if( (*options) & DBR_UNITS ) {
1346 memset(pbuffer,'\0',dbr_units_size);
1347- if( prset && prset->get_units ){
1348+ if( prset && prset->get_units ){
1349 (*prset->get_units)(paddr, pbuffer);
1350 pbuffer[DB_UNITS_SIZE-1] = '\0';
1351 } else {
1352@@ -363,7 +363,7 @@
1353 if( (*options) & DBR_PRECISION ) {
1354 memset(pbuffer, '\0', dbr_precision_size);
1355 if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE)
1356- && prset && prset->get_precision ){
1357+ && prset && prset->get_precision ){
1358 (*prset->get_precision)(paddr,pbuffer);
1359 } else {
1360 *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION*/
1361@@ -373,12 +373,12 @@
1362 if( (*options) & DBR_TIME ) {
1363 epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;
1364
1365- if(pfl!=NULL) {
1366- *ptime++ = pfl->time.secPastEpoch;
1367- *ptime++ = pfl->time.nsec;
1368- } else {
1369- *ptime++ = pcommon->time.secPastEpoch;
1370- *ptime++ = pcommon->time.nsec;
1371+ if (!pfl || pfl->type == dbfl_type_rec) {
1372+ *ptime++ = pcommon->time.secPastEpoch;
1373+ *ptime++ = pcommon->time.nsec;
1374+ } else {
1375+ *ptime++ = pfl->time.secPastEpoch;
1376+ *ptime++ = pfl->time.nsec;
1377 }
1378 pbuffer = (char *)ptime;
1379 }
1380@@ -392,7 +392,7 @@
1381 get_alarm(paddr, &pbuffer, prset, options);
1382 *poriginal = pbuffer;
1383 }
1384-
1385
1386+
1387 struct rset * epicsShareAPI dbGetRset(const struct dbAddr *paddr)
1388 {
1389 struct dbFldDes *pfldDes = paddr->pfldDes;
1390@@ -419,10 +419,10 @@
1391
1392 int epicsShareAPI dbIsValueField(const struct dbFldDes *pdbFldDes)
1393 {
1394- if(pdbFldDes->pdbRecordType->indvalFlddes == pdbFldDes->indRecordType)
1395- return(TRUE);
1396+ if (pdbFldDes->pdbRecordType->indvalFlddes == pdbFldDes->indRecordType)
1397+ return TRUE;
1398 else
1399- return(FALSE);
1400+ return FALSE;
1401 }
1402
1403 int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr)
1404@@ -430,50 +430,6 @@
1405 return paddr->pfldDes->indRecordType;
1406 }
1407
1408-long epicsShareAPI dbGetNelements(const struct link *plink,long *nelements)
1409-{
1410- switch(plink->type) {
1411- case CONSTANT:
1412- *nelements = 0;
1413- return(0);
1414- case DB_LINK: {
1415- DBADDR *paddr = (DBADDR *)plink->value.pv_link.pvt;
1416- *nelements = paddr->no_elements;
1417- return(0);
1418- }
1419- case CA_LINK:
1420- return(dbCaGetNelements(plink,nelements));
1421- default:
1422- break;
1423- }
1424- return(S_db_badField);
1425-}
1426-
1427-int epicsShareAPI dbIsLinkConnected(const struct link *plink)
1428-{
1429- switch(plink->type) {
1430- case DB_LINK: return(TRUE);
1431- case CA_LINK: return(dbCaIsLinkConnected(plink));
1432- default: break;
1433- }
1434- return(FALSE);
1435-}
1436-
1437-int epicsShareAPI dbGetLinkDBFtype(const struct link *plink)
1438-{
1439- switch(plink->type) {
1440- case DB_LINK:
1441- {
1442- DBADDR *paddr = (DBADDR *)plink->value.pv_link.pvt;
1443-
1444- return((int)paddr->field_type);
1445- }
1446- case CA_LINK: return(dbCaGetLinkDBFtype(plink));
1447- default: break;
1448- }
1449- return(-1);
1450-}
1451-
1452
1453 /*
1454 * Process a record if its scan field is passive.
1455 * Will notify if processing is complete by callback.
1456@@ -481,50 +437,15 @@
1457 */
1458 long epicsShareAPI dbScanPassive(dbCommon *pfrom, dbCommon *pto)
1459 {
1460- long status;
1461-
1462 /* if not passive just return success */
1463- if(pto->scan != 0) return(0);
1464-
1465- if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto);
1466- status = dbProcess(pto);
1467- return(status);
1468-}
1469-
1470-/*KLUDGE: Following needed so that dbPutLink to PROC field works correctly*/
1471-long epicsShareAPI dbScanLink(dbCommon *pfrom, dbCommon *pto)
1472-{
1473- long status;
1474- unsigned char pact;
1475-
1476- if(pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto);
1477- pact = pfrom->pact;
1478- pfrom->pact = TRUE;
1479- status = dbProcess(pto);
1480- pfrom->pact = pact;
1481- return(status);
1482-}
1483-
1484-void epicsShareAPI dbScanFwdLink(struct link *plink)
1485-{
1486- dbCommon *precord;
1487- struct pv_link *pvlink;
1488- short fwdLinkValue;
1489-
1490- if(plink->type!=DB_LINK && plink->type!=CA_LINK) return;
1491- pvlink = &plink->value.pv_link;
1492- precord = pvlink->precord;
1493- if(plink->type==DB_LINK) {
1494- dbAddr *paddr = (dbAddr *)plink->value.pv_link.pvt;
1495- dbScanPassive(precord,paddr->precord);
1496- return;
1497- }
1498- if(!(pvlink->pvlMask & pvlOptFWD)) return;
1499- fwdLinkValue = 1;
1500- dbCaPutLink(plink,DBR_SHORT,&fwdLinkValue,1);
1501- return;
1502-}
1503-
1504
1505+ if (pto->scan != 0)
1506+ return 0;
1507+
1508+ if (pfrom && pfrom->ppn)
1509+ dbNotifyAdd(pfrom,pto);
1510+ return dbProcess(pto);
1511+}
1512+
1513 /*
1514 * Process the record.
1515 * 1. Check for breakpoints.
1516@@ -536,121 +457,127 @@
1517 */
1518 long epicsShareAPI dbProcess(dbCommon *precord)
1519 {
1520- struct rset *prset = precord->rset;
1521- dbRecordType *pdbRecordType = precord->rdes;
1522- unsigned char tpro=precord->tpro;
1523- long status = 0;
1524- int *ptrace;
1525- int set_trace=FALSE;
1526- dbFldDes *pdbFldDes;
1527- int callNotifyCompletion = FALSE;
1528-
1529- ptrace = dbLockSetAddrTrace(precord);
1530+ struct rset *prset = precord->rset;
1531+ dbRecordType *pdbRecordType = precord->rdes;
1532+ unsigned char tpro = precord->tpro;
1533+ long status = 0;
1534+ int *ptrace;
1535+ int set_trace = FALSE;
1536+ dbFldDes *pdbFldDes;
1537+ int callNotifyCompletion = FALSE;
1538+
1539+ ptrace = dbLockSetAddrTrace(precord);
1540+ /*
1541+ * Note that it is likely that if any changes are made
1542+ * to dbProcess() corresponding changes will have to
1543+ * be made in the breakpoint handler.
1544+ */
1545+
1546+ /* see if there are any stopped records or breakpoints */
1547+ if (lset_stack_count != 0) {
1548 /*
1549- * Note that it is likely that if any changes are made
1550- * to dbProcess() corresponding changes will have to
1551- * be made in the breakpoint handler.
1552+ * Check to see if the record should be processed
1553+ * and activate breakpoint accordingly. If this
1554+ * function call returns non-zero, skip record
1555+ * support and fall out of dbProcess(). This is
1556+ * done so that a dbContTask() can be spawned to
1557+ * take over record processing for the lock set
1558+ * containing a breakpoint.
1559 */
1560-
1561- /* see if there are any stopped records or breakpoints */
1562- if (lset_stack_count != 0) {
1563- /*
1564- * Check to see if the record should be processed
1565- * and activate breakpoint accordingly. If this
1566- * function call returns non-zero, skip record
1567- * support and fall out of dbProcess(). This is
1568- * done so that a dbContTask() can be spawned to
1569- * take over record processing for the lock set
1570- * containing a breakpoint.
1571- */
1572- if (dbBkpt(precord))
1573- goto all_done;
1574- }
1575-
1576- /* check for trace processing*/
1577- if (tpro) {
1578- if(*ptrace==0) {
1579- *ptrace = 1;
1580- set_trace = TRUE;
1581- }
1582- }
1583-
1584- /* If already active dont process */
1585- if (precord->pact) {
1586- unsigned short monitor_mask;
1587-
1588- if (*ptrace) printf("%s: Active %s\n",
1589- epicsThreadGetNameSelf(), precord->name);
1590- /* raise scan alarm after MAX_LOCK times */
1591- if (precord->stat==SCAN_ALARM) goto all_done;
1592- if (precord->lcnt++ !=MAX_LOCK) goto all_done;
1593- if (precord->sevr>=INVALID_ALARM) goto all_done;
1594- recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
1595- monitor_mask = recGblResetAlarms(precord);
1596- monitor_mask |= DBE_VALUE|DBE_LOG;
1597- pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
1598- db_post_events(precord,
1599- (void *)(((char *)precord) + pdbFldDes->offset),
1600- monitor_mask);
1601- goto all_done;
1602- }
1603- else precord->lcnt = 0;
1604-
1605- /*
1606- * Check the record disable link. A record will not be
1607- * processed if the value retrieved through this link
1608- * is equal to constant set in the record's disv field.
1609- */
1610- status = dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0);
1611-
1612- /* if disabled check disable alarm severity and return success */
1613- if (precord->disa == precord->disv) {
1614- if(*ptrace) printf("%s: Disabled %s\n",
1615- epicsThreadGetNameSelf(), precord->name);
1616- /*take care of caching and notifyCompletion*/
1617- precord->rpro = FALSE;
1618- precord->putf = FALSE;
1619- callNotifyCompletion = TRUE;
1620- /* raise disable alarm */
1621- if (precord->stat==DISABLE_ALARM) goto all_done;
1622- precord->sevr = precord->diss;
1623- precord->stat = DISABLE_ALARM;
1624- precord->nsev = 0;
1625- precord->nsta = 0;
1626- db_post_events(precord, &precord->stat, DBE_VALUE);
1627- db_post_events(precord, &precord->sevr, DBE_VALUE);
1628- pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
1629- db_post_events(precord,
1630- (void *)(((char *)precord) + pdbFldDes->offset),
1631- DBE_VALUE|DBE_ALARM);
1632- goto all_done;
1633- }
1634-
1635- /* locate record processing routine */
1636- /* put this in iocInit() !!! */
1637- if (!(prset=precord->rset) || !(prset->process)) {
1638- callNotifyCompletion = TRUE;
1639- precord->pact=1;/*set pact TRUE so error is issued only once*/
1640- recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");
1641- status = S_db_noRSET;
1642- if (*ptrace) printf("%s: No RSET for %s\n",
1643- epicsThreadGetNameSelf(), precord->name);
1644- goto all_done;
1645- }
1646- if(*ptrace) printf("%s: Process %s\n",
1647- epicsThreadGetNameSelf(), precord->name);
1648- /* process record */
1649- status = (*prset->process)(precord);
1650- /* Print record's fields if PRINT_MASK set in breakpoint field */
1651- if (lset_stack_count != 0) {
1652- dbPrint(precord);
1653- }
1654+ if (dbBkpt(precord))
1655+ goto all_done;
1656+ }
1657+
1658+ /* check for trace processing*/
1659+ if (tpro) {
1660+ if(*ptrace==0) {
1661+ *ptrace = 1;
1662+ set_trace = TRUE;
1663+ }
1664+ }
1665+
1666+ /* If already active dont process */
1667+ if (precord->pact) {
1668+ unsigned short monitor_mask;
1669+
1670+ if (*ptrace)
1671+ printf("%s: Active %s\n",
1672+ epicsThreadGetNameSelf(), precord->name);
1673+ /* raise scan alarm after MAX_LOCK times */
1674+ if (precord->stat==SCAN_ALARM) goto all_done;
1675+ if (precord->lcnt++ !=MAX_LOCK) goto all_done;
1676+ if (precord->sevr>=INVALID_ALARM) goto all_done;
1677+ recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
1678+ monitor_mask = recGblResetAlarms(precord);
1679+ monitor_mask |= DBE_VALUE|DBE_LOG;
1680+ pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
1681+ db_post_events(precord,
1682+ (void *)(((char *)precord) + pdbFldDes->offset),
1683+ monitor_mask);
1684+ goto all_done;
1685+ }
1686+ else precord->lcnt = 0;
1687+
1688+ /*
1689+ * Check the record disable link. A record will not be
1690+ * processed if the value retrieved through this link
1691+ * is equal to constant set in the record's disv field.
1692+ */
1693+ status = dbGetLink(&precord->sdis, DBR_SHORT, &precord->disa, 0, 0);
1694+
1695+ /* if disabled check disable alarm severity and return success */
1696+ if (precord->disa == precord->disv) {
1697+ if(*ptrace)
1698+ printf("%s: Disabled %s\n",
1699+ epicsThreadGetNameSelf(), precord->name);
1700+
1701+ /*take care of caching and notifyCompletion*/
1702+ precord->rpro = FALSE;
1703+ precord->putf = FALSE;
1704+ callNotifyCompletion = TRUE;
1705+
1706+ /* raise disable alarm */
1707+ if (precord->stat==DISABLE_ALARM) goto all_done;
1708+ precord->sevr = precord->diss;
1709+ precord->stat = DISABLE_ALARM;
1710+ precord->nsev = 0;
1711+ precord->nsta = 0;
1712+ db_post_events(precord, &precord->stat, DBE_VALUE);
1713+ db_post_events(precord, &precord->sevr, DBE_VALUE);
1714+ pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
1715+ db_post_events(precord,
1716+ (void *)(((char *)precord) + pdbFldDes->offset),
1717+ DBE_VALUE|DBE_ALARM);
1718+ goto all_done;
1719+ }
1720+
1721+ /* locate record processing routine */
1722+ /* FIXME: put this in iocInit() !!! */
1723+ if (!(prset=precord->rset) || !(prset->process)) {
1724+ callNotifyCompletion = TRUE;
1725+ precord->pact=1;/*set pact TRUE so error is issued only once*/
1726+ recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");
1727+ status = S_db_noRSET;
1728+ if (*ptrace)
1729+ printf("%s: No RSET for %s\n",
1730+ epicsThreadGetNameSelf(), precord->name);
1731+ goto all_done;
1732+ }
1733+ if(*ptrace)
1734+ printf("%s: Process %s\n",
1735+ epicsThreadGetNameSelf(), precord->name);
1736+ /* process record */
1737+ status = (*prset->process)(precord);
1738+ /* Print record's fields if PRINT_MASK set in breakpoint field */
1739+ if (lset_stack_count != 0) {
1740+ dbPrint(precord);
1741+ }
1742 all_done:
1743- if (set_trace) *ptrace = 0;
1744- if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord);
1745- return(status);
1746+ if (set_trace) *ptrace = 0;
1747+ if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord);
1748+ return(status);
1749 }
1750-
1751
1752+
1753 /*
1754 * Fill out a database structure (*paddr) for
1755 * a record given by the name "pname."
1756@@ -726,59 +653,7 @@
1757 dbFinishEntry(&dbEntry);
1758 return status;
1759 }
1760-
1761
1762-/* JOH 10-19-04 */
1763-static char * dbCopyInNameComponentOfPV (
1764- char * pBuf, unsigned bufLen, const char * pComponent )
1765-{
1766- unsigned compLen = strlen ( pComponent );
1767- if ( compLen < bufLen ) {
1768- strcpy ( pBuf, pComponent );
1769- return pBuf + compLen;
1770- }
1771- else {
1772- unsigned reducedSize = bufLen - 1u;
1773- strncpy ( pBuf, pComponent, reducedSize );
1774- pBuf[reducedSize] = '\0';
1775- return pBuf + reducedSize;
1776- }
1777-}
1778-/*
1779- * Copies PV name into pBuf of length bufLen
1780- *
1781- * Returns the number of bytes written to pBuf
1782- * not including null termination.
1783- * JOH 10-19-04
1784- */
1785-unsigned dbNameOfPV (
1786- const dbAddr * paddr, char * pBuf, unsigned bufLen )
1787-{
1788- dbFldDes * pfldDes = paddr->pfldDes;
1789- char * pBufTmp = pBuf;
1790- if ( bufLen == 0u ) {
1791- return 0u;
1792- }
1793- pBufTmp = dbCopyInNameComponentOfPV (
1794- pBufTmp, bufLen, paddr->precord->name );
1795- pBufTmp = dbCopyInNameComponentOfPV (
1796- pBufTmp, bufLen - ( pBufTmp - pBuf ), "." );
1797- pBufTmp = dbCopyInNameComponentOfPV (
1798- pBufTmp, bufLen - ( pBufTmp - pBuf ), pfldDes->name );
1799- return pBufTmp - pBuf;
1800-}
1801-/*
1802- * Returns the number of bytes in the PV name
1803- * not including null termination.
1804- * JOH 10-19-04
1805- */
1806-unsigned dbNameSizeOfPV ( const dbAddr * paddr )
1807-{
1808- unsigned recNameLen = strlen ( paddr->precord->name );
1809- dbFldDes * pfldDes = paddr->pfldDes;
1810- unsigned fieldNameLen = strlen ( pfldDes->name );
1811- return recNameLen + fieldNameLen + 1;
1812-}
1813-
1814
1815+
1816 long epicsShareAPI dbValueSize(short dbr_type)
1817 {
1818 /* sizes for value associated with each DBR request type */
1819@@ -826,222 +701,117 @@
1820 return dbReadDatabase(&pdbbase, file, 0, subs);
1821 }
1822
1823-
1824
1825-long epicsShareAPI dbGetLinkValue(struct link *plink, short dbrType,
1826- void *pbuffer, long *poptions, long *pnRequest)
1827-{
1828- long status = 0;
1829-
1830- if (plink->type == CONSTANT) {
1831- if (poptions) *poptions = 0;
1832- if (pnRequest) *pnRequest = 0;
1833- } else if (plink->type == DB_LINK) {
1834- struct pv_link *ppv_link = &(plink->value.pv_link);
1835- DBADDR *paddr = ppv_link->pvt;
1836- dbCommon *precord = plink->value.pv_link.precord;
1837-
1838- /* scan passive records with links that are process passive */
1839- if (ppv_link->pvlMask&pvlOptPP) {
1840- dbCommon *pfrom = paddr->precord;
1841- unsigned char pact;
1842-
1843- pact = precord->pact;
1844- precord->pact = TRUE;
1845- status = dbScanPassive(precord,pfrom);
1846- precord->pact = pact;
1847- if (status) return status;
1848- }
1849- if(precord!= paddr->precord) {
1850- inherit_severity(ppv_link,precord,paddr->precord->stat,paddr->precord->sevr);
1851- }
1852-
1853- if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
1854- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
1855- } else {
1856- unsigned short dbfType = paddr->field_type;
1857- long no_elements = paddr->no_elements;
1858-
1859- if (dbrType < 0 || dbrType > DBR_ENUM ||
1860- dbfType > DBF_DEVICE) {
1861- status = S_db_badDbrtype;
1862- recGblRecordError(status, precord, "GetLinkValue Failed");
1863- recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
1864- return status;
1865- }
1866- /* attempt to make a fast link */
1867- if ((!poptions || *poptions == 0) &&
1868- no_elements == 1 &&
1869- (!pnRequest || *pnRequest == 1) &&
1870- paddr->special != SPC_ATTRIBUTE) {
1871- ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
1872- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
1873- } else {
1874- ppv_link->getCvt = 0;
1875- status = dbGet(paddr, dbrType, pbuffer, poptions, pnRequest, NULL);
1876- }
1877- }
1878- ppv_link->lastGetdbrType = dbrType;
1879- if (status) {
1880- recGblRecordError(status, precord, "dbGetLinkValue");
1881- recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
1882- }
1883- } else if (plink->type == CA_LINK) {
1884- struct dbCommon *precord = plink->value.pv_link.precord;
1885- const struct pv_link *pcalink = &plink->value.pv_link;
1886- epicsEnum16 sevr, stat;
1887-
1888- status=dbCaGetLink(plink,dbrType,pbuffer,&stat,&sevr,pnRequest);
1889- if (status) {
1890- recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
1891- } else {
1892- inherit_severity(pcalink,precord,stat,sevr);
1893- }
1894- if (poptions) *poptions = 0;
1895- } else {
1896- cantProceed("dbGetLinkValue: Illegal link type");
1897- }
1898- return status;
1899-}
1900-
1901
1902-long epicsShareAPI dbPutLinkValue(struct link *plink, short dbrType,
1903- const void *pbuffer, long nRequest)
1904-{
1905- long status = 0;
1906-
1907- if (plink->type == DB_LINK) {
1908- struct dbCommon *psource = plink->value.pv_link.precord;
1909- struct pv_link *ppv_link = &plink->value.pv_link;
1910- DBADDR *paddr = (DBADDR *)ppv_link->pvt;
1911- dbCommon *pdest = paddr->precord;
1912-
1913- status = dbPut(paddr, dbrType, pbuffer, nRequest);
1914- inherit_severity(ppv_link,pdest,psource->nsta,psource->nsev);
1915- if (status) return status;
1916-
1917- if (paddr->pfield == (void *)&pdest->proc ||
1918- (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
1919- /*if dbPutField caused asyn record to process */
1920- /* ask for reprocessing*/
1921- if (pdest->putf) {
1922- pdest->rpro = TRUE;
1923- } else { /* otherwise ask for the record to be processed*/
1924- status = dbScanLink(psource, pdest);
1925- }
1926- }
1927- if (status)
1928- recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM);
1929- } else if (plink->type == CA_LINK) {
1930- struct dbCommon *psource = plink->value.pv_link.precord;
1931-
1932- status = dbCaPutLink(plink, dbrType, pbuffer, nRequest);
1933- if (status < 0)
1934- recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM);
1935- } else {
1936- cantProceed("dbPutLinkValue: Illegal link type");
1937- }
1938- return status;
1939-}
1940-
1941
1942+
1943+static long getLinkValue(DBADDR *paddr, short dbrType,
1944+ char *pbuf, long *nRequest)
1945+{
1946+ dbCommon *precord = paddr->precord;
1947+ dbFldDes *pfldDes = paddr->pfldDes;
1948+ int maxlen;
1949+ DBENTRY dbEntry;
1950+ long status;
1951+
1952+ switch (dbrType) {
1953+ case DBR_STRING:
1954+ maxlen = MAX_STRING_SIZE - 1;
1955+ if (nRequest && *nRequest > 1) *nRequest = 1;
1956+ break;
1957+
1958+ case DBR_CHAR:
1959+ case DBR_UCHAR:
1960+ if (nRequest && *nRequest > 0) {
1961+ maxlen = *nRequest - 1;
1962+ break;
1963+ }
1964+ /* else fall through ... */
1965+ default:
1966+ return S_db_badDbrtype;
1967+ }
1968+
1969+ dbInitEntry(pdbbase, &dbEntry);
1970+ status = dbFindRecord(&dbEntry, precord->name);
1971+ if (!status) status = dbFindField(&dbEntry, pfldDes->name);
1972+ if (!status) {
1973+ char *rtnString = dbGetString(&dbEntry);
1974+
1975+ strncpy(pbuf, rtnString, --maxlen);
1976+ pbuf[maxlen] = 0;
1977+ }
1978+ dbFinishEntry(&dbEntry);
1979+ return status;
1980+}
1981+
1982+static long getAttrValue(DBADDR *paddr, short dbrType,
1983+ char *pbuf, long *nRequest)
1984+{
1985+ int maxlen;
1986+
1987+ if (!paddr->pfield) return S_db_badField;
1988+
1989+ switch (dbrType) {
1990+ case DBR_STRING:
1991+ maxlen = MAX_STRING_SIZE - 1;
1992+ if (nRequest && *nRequest > 1) *nRequest = 1;
1993+ break;
1994+
1995+ case DBR_CHAR:
1996+ case DBR_UCHAR:
1997+ if (nRequest && *nRequest > 0) {
1998+ maxlen = *nRequest - 1;
1999+ break;
2000+ }
2001+ /* else fall through ... */
2002+ default:
2003+ return S_db_badDbrtype;
2004+ }
2005+
2006+ strncpy(pbuf, paddr->pfield, --maxlen);
2007+ pbuf[maxlen] = 0;
2008+ return 0;
2009+}
2010+
2011 long epicsShareAPI dbGetField(DBADDR *paddr,short dbrType,
2012 void *pbuffer, long *options, long *nRequest, void *pflin)
2013 {
2014- short dbfType = paddr->field_type;
2015 dbCommon *precord = paddr->precord;
2016 long status = 0;
2017
2018 dbScanLock(precord);
2019- if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
2020- DBENTRY dbEntry;
2021- dbFldDes *pfldDes = paddr->pfldDes;
2022- char *rtnString;
2023- char *pbuf = (char *)pbuffer;
2024- int maxlen;
2025-
2026- if (options && (*options))
2027- getOptions(paddr, &pbuf, options, pflin);
2028- if (nRequest && *nRequest == 0) goto done;
2029-
2030- switch (dbrType) {
2031- case DBR_STRING:
2032- maxlen = MAX_STRING_SIZE - 1;
2033- if (nRequest && *nRequest > 1) *nRequest = 1;
2034- break;
2035-
2036- case DBR_CHAR:
2037- case DBR_UCHAR:
2038- if (nRequest && *nRequest > 0) {
2039- maxlen = *nRequest - 1;
2040- break;
2041- }
2042- /* else fall through ... */
2043- default:
2044- status = S_db_badDbrtype;
2045- goto done;
2046- }
2047-
2048- dbInitEntry(pdbbase, &dbEntry);
2049- status = dbFindRecord(&dbEntry, precord->name);
2050- if (!status) status = dbFindField(&dbEntry, pfldDes->name);
2051- if (!status) {
2052- rtnString = dbGetString(&dbEntry);
2053- strncpy(pbuf, rtnString, maxlen);
2054- pbuf[maxlen] = 0;
2055- }
2056- dbFinishEntry(&dbEntry);
2057- } else {
2058- status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);
2059- }
2060-done:
2061+ status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);
2062 dbScanUnlock(precord);
2063 return status;
2064 }
2065-
2066
2067+
2068 long epicsShareAPI dbGet(DBADDR *paddr, short dbrType,
2069 void *pbuffer, long *options, long *nRequest, void *pflin)
2070 {
2071+ char *pbuf = pbuffer;
2072 db_field_log *pfl = (db_field_log *)pflin;
2073- short field_type = paddr->field_type;
2074- long no_elements = paddr->no_elements;
2075+ short field_type;
2076+ long no_elements;
2077 long offset;
2078 struct rset *prset;
2079 long status = 0;
2080
2081- if (options && *options) {
2082- char *pbuf = pbuffer;
2083-
2084+ if (options && *options)
2085 getOptions(paddr, &pbuf, options, pflin);
2086- pbuffer = pbuf;
2087- }
2088- if (nRequest && *nRequest == 0) return 0;
2089-
2090- if (paddr->special == SPC_ATTRIBUTE) {
2091- char *pbuf = pbuffer;
2092- int maxlen;
2093-
2094- if (!paddr->pfield) return S_db_badField;
2095-
2096- switch (dbrType) {
2097- case DBR_STRING:
2098- maxlen = MAX_STRING_SIZE - 1;
2099- if (nRequest && *nRequest > 1) *nRequest = 1;
2100- break;
2101-
2102- case DBR_CHAR:
2103- case DBR_UCHAR:
2104- if (nRequest && *nRequest > 0) {
2105- maxlen = *nRequest - 1;
2106- break;
2107- }
2108- /* else fall through ... */
2109- default:
2110- return S_db_badDbrtype;
2111- }
2112-
2113- strncpy(pbuf, (char *)paddr->pfield, maxlen);
2114- pbuf[maxlen] = 0;
2115+ if (nRequest && *nRequest == 0)
2116 return 0;
2117+
2118+ if (!pfl || pfl->type == dbfl_type_rec) {
2119+ field_type = paddr->field_type;
2120+ no_elements = paddr->no_elements;
2121+ } else {
2122+ field_type = pfl->field_type;
2123+ no_elements = pfl->no_elements;
2124 }
2125
2126+ if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK)
2127+ return getLinkValue(paddr, dbrType, pbuf, nRequest);
2128+
2129+ if (paddr->special == SPC_ATTRIBUTE)
2130+ return getAttrValue(paddr, dbrType, pbuf, nRequest);
2131+
2132 /* Check for valid request */
2133 if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
2134 char message[80];
2135@@ -1052,7 +822,8 @@
2136 }
2137
2138 /* check for array */
2139- if (paddr->special == SPC_DBADDR &&
2140+ if ((!pfl || pfl->type == dbfl_type_rec) &&
2141+ paddr->special == SPC_DBADDR &&
2142 no_elements > 1 &&
2143 (prset = dbGetRset(paddr)) &&
2144 prset->get_array_info) {
2145@@ -1062,15 +833,20 @@
2146
2147 if (offset == 0 && (!nRequest || no_elements == 1)) {
2148 if (nRequest) *nRequest = 1;
2149- if (pfl != NULL) {
2150+ if (!pfl || pfl->type == dbfl_type_rec) {
2151+ status = dbFastGetConvertRoutine[field_type][dbrType]
2152+ (paddr->pfield, pbuffer, paddr);
2153+ } else {
2154 DBADDR localAddr = *paddr; /* Structure copy */
2155-
2156- localAddr.pfield = (char *)&pfl->field;
2157+ localAddr.field_type = pfl->field_type;
2158+ localAddr.field_size = pfl->field_size;
2159+ localAddr.no_elements = pfl->no_elements;
2160+ if (pfl->type == dbfl_type_val)
2161+ localAddr.pfield = (char *) &pfl->u.v.field;
2162+ else
2163+ localAddr.pfield = (char *) pfl->u.r.field;
2164 status = dbFastGetConvertRoutine[field_type][dbrType]
2165 (localAddr.pfield, pbuffer, &localAddr);
2166- } else {
2167- status = dbFastGetConvertRoutine[field_type][dbrType]
2168- (paddr->pfield, pbuffer, paddr);
2169 }
2170 } else {
2171 long n;
2172@@ -1094,18 +870,23 @@
2173 /* convert database field and place it in the buffer */
2174 if (n <= 0) {
2175 ;/*do nothing*/
2176- } else if (pfl) {
2177+ } else if (!pfl || pfl->type == dbfl_type_rec) {
2178+ status = convert(paddr, pbuffer, n, no_elements, offset);
2179+ } else {
2180 DBADDR localAddr = *paddr; /* Structure copy */
2181-
2182- localAddr.pfield = (char *)&pfl->field;
2183+ localAddr.field_type = pfl->field_type;
2184+ localAddr.field_size = pfl->field_size;
2185+ localAddr.no_elements = pfl->no_elements;
2186+ if (pfl->type == dbfl_type_val)
2187+ localAddr.pfield = (char *) &pfl->u.v.field;
2188+ else
2189+ localAddr.pfield = (char *) pfl->u.r.field;
2190 status = convert(&localAddr, pbuffer, n, no_elements, offset);
2191- } else {
2192- status = convert(paddr, pbuffer, n, no_elements, offset);
2193 }
2194 }
2195 return status;
2196 }
2197-
2198
2199+
2200 devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) {
2201 return (devSup *)ellNth(&prdes->devList, dtyp+1);
2202 }
2203@@ -1125,10 +906,9 @@
2204 dbCommon *precord = paddr->precord;
2205 dbFldDes *pfldDes = paddr->pfldDes;
2206 long special = paddr->special;
2207- DBLINK *plink = (DBLINK *)paddr->pfield;
2208+ struct link *plink = (struct link *)paddr->pfield;
2209 const char *pstring = (const char *)pbuffer;
2210 DBENTRY dbEntry;
2211- DBADDR dbaddr;
2212 struct dsxt *old_dsxt = NULL;
2213 struct dset *new_dset = NULL;
2214 struct dsxt *new_dsxt = NULL;
2215@@ -1199,21 +979,8 @@
2216
2217 switch (plink->type) { /* Old link type */
2218 case DB_LINK:
2219- free(plink->value.pv_link.pvt);
2220- plink->value.pv_link.pvt = 0;
2221- plink->type = PV_LINK;
2222- plink->value.pv_link.getCvt = 0;
2223- plink->value.pv_link.pvlMask = 0;
2224- plink->value.pv_link.lastGetdbrType = 0;
2225- dbLockSetSplit(precord);
2226- break;
2227-
2228 case CA_LINK:
2229- dbCaRemoveLink(plink);
2230- plink->type = PV_LINK;
2231- plink->value.pv_link.getCvt = 0;
2232- plink->value.pv_link.pvlMask = 0;
2233- plink->value.pv_link.lastGetdbrType = 0;
2234+ dbRemoveLink(plink);
2235 break;
2236
2237 case CONSTANT:
2238@@ -1260,35 +1027,7 @@
2239
2240 switch (plink->type) { /* New link type */
2241 case PV_LINK:
2242- if (plink == &precord->tsel)
2243- recGblTSELwasModified(plink);
2244- plink->value.pv_link.precord = precord;
2245-
2246- if (!(plink->value.pv_link.pvlMask & (pvlOptCA|pvlOptCP|pvlOptCPP)) &&
2247- (dbNameToAddr(plink->value.pv_link.pvname, &dbaddr) == 0)) {
2248- /* It's a DB link */
2249- DBADDR *pdbAddr;
2250-
2251- plink->type = DB_LINK;
2252- pdbAddr = dbMalloc(sizeof(struct dbAddr));
2253- *pdbAddr = dbaddr; /* NB: structure copy */;
2254- plink->value.pv_link.pvt = pdbAddr;
2255- dbLockSetRecordLock(pdbAddr->precord);
2256- dbLockSetMerge(precord, pdbAddr->precord);
2257- } else { /* Make it a CA link */
2258- char *pperiod;
2259-
2260- plink->type = CA_LINK;
2261- if (pfldDes->field_type == DBF_INLINK) {
2262- plink->value.pv_link.pvlMask |= pvlOptInpNative;
2263- }
2264- dbCaAddLink(plink);
2265- if (pfldDes->field_type == DBF_FWDLINK) {
2266- pperiod = strrchr(plink->value.pv_link.pvname, '.');
2267- if (pperiod && strstr(pperiod, "PROC"))
2268- plink->value.pv_link.pvlMask |= pvlOptFWD;
2269- }
2270- }
2271+ dbAddLink(precord, plink, pfldDes->field_type);
2272 break;
2273
2274 case CONSTANT:
2275@@ -1316,7 +1055,7 @@
2276 }
2277 postScanEvent:
2278 if (scan != precord->scan)
2279- db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG);
2280+ db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
2281 unlock:
2282 dbLockSetGblUnlock();
2283 finish:
2284@@ -1337,8 +1076,7 @@
2285 return S_db_noMod;
2286
2287 /*check for putField disabled*/
2288- if (precord->disp &&
2289- (void *)(&precord->disp) != paddr->pfield)
2290+ if (precord->disp && paddr->pfield != &precord->disp)
2291 return S_db_putDisabled;
2292
2293 if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK)
2294@@ -1347,7 +1085,7 @@
2295 dbScanLock(precord);
2296 status = dbPut(paddr, dbrType, pbuffer, nRequest);
2297 if (status == 0) {
2298- if (paddr->pfield == (void *)&precord->proc ||
2299+ if (paddr->pfield == &precord->proc ||
2300 (pfldDes->process_passive &&
2301 precord->scan == 0 &&
2302 dbrType < DBR_PUT_ACKT)) {
2303@@ -1366,16 +1104,18 @@
2304 dbScanUnlock(precord);
2305 return status;
2306 }
2307-
2308
2309-static long putAckt(DBADDR *paddr, const unsigned short *pbuffer, long nRequest,
2310+
2311+static long putAckt(DBADDR *paddr, const void *pbuffer, long nRequest,
2312 long no_elements, long offset)
2313 {
2314 dbCommon *precord = paddr->precord;
2315+ const unsigned short *ptrans = pbuffer;
2316
2317- if (*pbuffer == precord->ackt) return 0;
2318- precord->ackt = *pbuffer;
2319+ if (*ptrans == precord->ackt) return 0;
2320+ precord->ackt = *ptrans;
2321 db_post_events(precord, &precord->ackt, DBE_VALUE | DBE_ALARM);
2322- if (!precord->ackt && precord->acks > precord->sevr) {
2323+ if (!precord->ackt &&
2324+ precord->acks > precord->sevr) {
2325 precord->acks = precord->sevr;
2326 db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
2327 }
2328@@ -1383,19 +1123,20 @@
2329 return 0;
2330 }
2331
2332-static long putAcks(DBADDR *paddr, const unsigned short *pbuffer, long nRequest,
2333+static long putAcks(DBADDR *paddr, const void *pbuffer, long nRequest,
2334 long no_elements, long offset)
2335 {
2336 dbCommon *precord = paddr->precord;
2337+ const unsigned short *psev = pbuffer;
2338
2339- if (*pbuffer >= precord->acks) {
2340+ if (*psev >= precord->acks) {
2341 precord->acks = 0;
2342+ db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
2343 db_post_events(precord, NULL, DBE_ALARM);
2344- db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
2345 }
2346 return 0;
2347 }
2348-
2349
2350+
2351 long epicsShareAPI dbPut(DBADDR *paddr, short dbrType,
2352 const void *pbuffer, long nRequest)
2353 {
2354@@ -1403,17 +1144,17 @@
2355 short field_type = paddr->field_type;
2356 long no_elements = paddr->no_elements;
2357 long special = paddr->special;
2358- long offset;
2359 long status = 0;
2360 dbFldDes *pfldDes;
2361 int isValueField;
2362
2363- if (special == SPC_ATTRIBUTE) return S_db_noMod;
2364+ if (special == SPC_ATTRIBUTE)
2365+ return S_db_noMod;
2366
2367 if (dbrType == DBR_PUT_ACKT && field_type <= DBF_DEVICE) {
2368- return putAckt(paddr, (unsigned short *)pbuffer, 1, 1, 0);
2369+ return putAckt(paddr, pbuffer, 1, 1, 0);
2370 } else if (dbrType == DBR_PUT_ACKS && field_type <= DBF_DEVICE) {
2371- return putAcks(paddr, (unsigned short *)pbuffer, 1, 1, 0);
2372+ return putAcks(paddr, pbuffer, 1, 1, 0);
2373 } else if (INVALID_DB_REQ(dbrType) || field_type > DBF_DEVICE) {
2374 char message[80];
2375
2376@@ -1432,6 +1173,7 @@
2377 paddr->pfield, paddr);
2378 } else {
2379 struct rset *prset = dbGetRset(paddr);
2380+ long offset = 0;
2381
2382 if (paddr->special == SPC_DBADDR &&
2383 prset && prset->get_array_info) {
2384@@ -1439,8 +1181,6 @@
2385
2386 status = prset->get_array_info(paddr, &dummy, &offset);
2387 }
2388- else
2389- offset = 0;
2390 if (no_elements < nRequest) nRequest = no_elements;
2391 status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
2392 nRequest, no_elements, offset);
2393@@ -1471,140 +1211,4 @@
2394
2395 return status;
2396 }
2397-
2398
2399-/* various utility routines */
2400-long epicsShareAPI dbGetControlLimits(
2401- const struct link *plink,double *low, double *high)
2402-{
2403- struct buffer {
2404- DBRctrlDouble
2405- double value;
2406- } buffer;
2407- DBADDR *paddr;
2408- long options = DBR_CTRL_DOUBLE;
2409- long number_elements = 0;
2410- long status;
2411-
2412- if(plink->type == CA_LINK) return(dbCaGetControlLimits(plink,low,high));
2413- if(plink->type !=DB_LINK) return(S_db_notFound);
2414- paddr = (DBADDR *)plink->value.pv_link.pvt;
2415- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
2416- if(status) return(status);
2417- *low = buffer.lower_ctrl_limit;
2418- *high = buffer.upper_ctrl_limit;
2419- return(0);
2420-}
2421-
2422-long epicsShareAPI dbGetGraphicLimits(
2423- const struct link *plink,double *low, double *high)
2424-{
2425- struct buffer {
2426- DBRgrDouble
2427- double value;
2428- } buffer;
2429- DBADDR *paddr;
2430- long options = DBR_GR_DOUBLE;
2431- long number_elements = 0;
2432- long status;
2433-
2434- if(plink->type == CA_LINK) return(dbCaGetGraphicLimits(plink,low,high));
2435- if(plink->type !=DB_LINK) return(S_db_notFound);
2436- paddr = (DBADDR *)plink->value.pv_link.pvt;
2437- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
2438- if(status) return(status);
2439- *low = buffer.lower_disp_limit;
2440- *high = buffer.upper_disp_limit;
2441- return(0);
2442-}
2443-
2444
2445-long epicsShareAPI dbGetAlarmLimits(const struct link *plink,
2446- double *lolo, double *low, double *high, double *hihi)
2447-{
2448- struct buffer {
2449- DBRalDouble
2450- double value;
2451- } buffer;
2452- DBADDR *paddr;
2453- long options = DBR_AL_DOUBLE;
2454- long number_elements = 0;
2455- long status;
2456-
2457- if(plink->type == CA_LINK)
2458- return(dbCaGetAlarmLimits(plink,lolo,low,high,hihi));
2459- if(plink->type !=DB_LINK) return(S_db_notFound);
2460- paddr = (DBADDR *)plink->value.pv_link.pvt;
2461- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
2462- if(status) return(status);
2463- *lolo = buffer.lower_alarm_limit;
2464- *low = buffer.lower_warning_limit;
2465- *high = buffer.upper_warning_limit;
2466- *hihi = buffer.upper_alarm_limit;
2467- return(0);
2468-}
2469-
2470-long epicsShareAPI dbGetPrecision(const struct link *plink,short *precision)
2471-{
2472- struct buffer {
2473- DBRprecision
2474- double value;
2475- } buffer;
2476- DBADDR *paddr;
2477- long options = DBR_PRECISION;
2478- long number_elements = 0;
2479- long status;
2480-
2481- if(plink->type == CA_LINK) return(dbCaGetPrecision(plink,precision));
2482- if(plink->type !=DB_LINK) return(S_db_notFound);
2483- paddr = (DBADDR *)plink->value.pv_link.pvt;
2484- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
2485- if(status) return(status);
2486- *precision = buffer.precision.dp;
2487- return(0);
2488-}
2489-
2490
2491-long epicsShareAPI dbGetUnits(
2492- const struct link *plink,char *units,int unitsSize)
2493-{
2494- struct buffer {
2495- DBRunits
2496- double value;
2497- } buffer;
2498- DBADDR *paddr;
2499- long options = DBR_UNITS;
2500- long number_elements = 0;
2501- long status;
2502-
2503- if(plink->type == CA_LINK) return(dbCaGetUnits(plink,units,unitsSize));
2504- if(plink->type !=DB_LINK) return(S_db_notFound);
2505- paddr = (DBADDR *)plink->value.pv_link.pvt;
2506- status = dbGet(paddr,DBR_DOUBLE,&buffer,&options,&number_elements,0);
2507- if(status) return(status);
2508- strncpy(units,buffer.units,unitsSize);
2509- return(0);
2510-}
2511-
2512-long epicsShareAPI dbGetAlarm(const struct link *plink,
2513- epicsEnum16 *status,epicsEnum16 *severity)
2514-{
2515- DBADDR *paddr;
2516-
2517- if(plink->type == CA_LINK) return(dbCaGetAlarm(plink,status,severity));
2518- if(plink->type !=DB_LINK) return(S_db_notFound);
2519- paddr = (DBADDR *)plink->value.pv_link.pvt;
2520- if (status) *status = paddr->precord->stat;
2521- if (severity) *severity = paddr->precord->sevr;
2522- return(0);
2523-}
2524-
2525-long epicsShareAPI dbGetTimeStamp(const struct link *plink,epicsTimeStamp *pstamp)
2526-{
2527- DBADDR *paddr;
2528-
2529- if (plink->type == CA_LINK)
2530- return dbCaGetTimeStamp(plink,pstamp);
2531- if (plink->type != DB_LINK)
2532- return S_db_notFound;
2533- paddr = (DBADDR *)plink->value.pv_link.pvt;
2534- *pstamp = paddr->precord->time;
2535- return 0;
2536-}
2537+
2538
2539=== modified file 'src/ioc/db/dbAccess.h'
2540--- src/ioc/db/dbAccess.h 2002-07-12 21:35:43 +0000
2541+++ src/ioc/db/dbAccess.h 2012-06-21 20:42:45 +0000
2542@@ -3,8 +3,7 @@
2543 * National Laboratory.
2544 * Copyright (c) 2002 The Regents of the University of California, as
2545 * Operator of Los Alamos National Laboratory.
2546-* EPICS BASE Versions 3.13.7
2547-* and higher are distributed subject to a Software License Agreement found
2548+* EPICS BASE is distributed subject to a Software License Agreement found
2549 * in file LICENSE that is included with this distribution.
2550 \*************************************************************************/
2551 /* dbAccess.h */
2552@@ -22,6 +21,7 @@
2553 #include "dbAddr.h"
2554 #include "dbLock.h"
2555 #include "dbAccessDefs.h"
2556+#include "dbLink.h"
2557 #include "dbCa.h"
2558 #include "dbCommon.h"
2559 #include "db_field_log.h"
2560
2561=== modified file 'src/ioc/db/dbAccessDefs.h'
2562--- src/ioc/db/dbAccessDefs.h 2010-10-05 19:27:37 +0000
2563+++ src/ioc/db/dbAccessDefs.h 2012-06-21 20:42:45 +0000
2564@@ -3,9 +3,8 @@
2565 * National Laboratory.
2566 * Copyright (c) 2002 The Regents of the University of California, as
2567 * Operator of Los Alamos National Laboratory.
2568-* EPICS BASE Versions 3.13.7
2569-* and higher are distributed subject to a Software License Agreement found
2570-* in file LICENSE that is included with this distribution.
2571+* EPICS BASE is distributed subject to a Software License Agreement found
2572+* in file LICENSE that is included with this distribution.
2573 \*************************************************************************/
2574 /* dbAccessDefs.h */
2575 /* $Revision-Id$ */
2576@@ -20,6 +19,8 @@
2577
2578 #include "epicsTypes.h"
2579 #include "epicsTime.h"
2580+#include "dbBase.h"
2581+#include "dbAddr.h"
2582
2583 #ifdef INCLdb_accessh_epicsExportSharedSymbols
2584 # define epicsExportSharedSymbols
2585@@ -47,7 +48,7 @@
2586 #define DBR_CTRL_DOUBLE 0x00000100
2587 #define DBR_AL_LONG 0x00000200
2588 #define DBR_AL_DOUBLE 0x00000400
2589-
2590
2591+
2592 /**********************************************************************
2593 * The next page contains macros for defining requests.
2594 * As an example the following defines a buffer to accept an array
2595@@ -69,7 +70,7 @@
2596 * options = DBR_STATUS|DBR_TIME;
2597 * number_elements = 10;
2598 * rtnval=dbGetField(paddr,DBR_FLOAT,&buffer,&options,&number_elements);
2599- *
2600+ *
2601 * When dbGetField returns:
2602 * rtnval is error status (0 means success)
2603 * options has a bit set for each option that was accepted
2604@@ -97,7 +98,7 @@
2605 * MYBUFFER *pbuf1;
2606 * MYBUFFER buf;
2607 *************************************************************************/
2608-
2609
2610+
2611 /* Macros for defining each option */
2612 #define DBRstatus \
2613 epicsUInt16 status; /* alarm status */\
2614@@ -143,7 +144,7 @@
2615 epicsFloat64 upper_warning_limit;\
2616 epicsFloat64 lower_warning_limit;\
2617 epicsFloat64 lower_alarm_limit;
2618-
2619
2620+
2621 /* structures for each option type */
2622 struct dbr_status {DBRstatus};
2623 struct dbr_units {DBRunits};
2624@@ -198,25 +199,6 @@
2625 #define S_db_cntSpwn (M_dbAccess|63) /*Cannot spawn dbContTask*/
2626 #define S_db_cntCont (M_dbAccess|65) /*Cannot resume dbContTask*/
2627 #define S_db_noMemory (M_dbAccess|66) /*unable to allocate data structure from pool*/
2628-
2629
2630-/* Global Database Access Routines*/
2631-#define dbGetLink(PLNK, DBRTYPE, PBUFFER, OPTIONS, NREQUEST) \
2632- ( ( ( (PLNK)->type == CONSTANT ) && \
2633- ( (NREQUEST) == 0) &&\
2634- ( (OPTIONS) == 0) ) \
2635- ? 0 \
2636- : dbGetLinkValue((PLNK),(DBRTYPE), \
2637- (void *)(PBUFFER), (OPTIONS), (NREQUEST) ) )
2638-#define dbPutLink(PLNK, DBRTYPE, PBUFFER, NREQUEST) \
2639- ( ( (PLNK)->type == CONSTANT) \
2640- ? 0 \
2641- : dbPutLinkValue( (PLNK), (DBRTYPE), (void *)(PBUFFER), (NREQUEST) ) )
2642-#define dbGetPdbAddrFromLink(PLNK) \
2643- ( ( (PLNK)->type != DB_LINK ) \
2644- ? 0 \
2645- : ( ( (struct dbAddr *)( (PLNK)->value.pv_link.pvt) ) ) )
2646-#define dbGetSevr(PLINK,PSEVERITY) \
2647- dbGetAlarm((PLINK),NULL,(PSEVERITY))
2648
2649 epicsShareFunc long epicsShareAPI dbPutSpecial(struct dbAddr *paddr,int pass);
2650 epicsShareFunc struct rset * epicsShareAPI dbGetRset(const struct dbAddr *paddr);
2651@@ -224,51 +206,24 @@
2652 const char *recordTypename,const char *name,const char*value);
2653 epicsShareFunc int epicsShareAPI dbIsValueField(const struct dbFldDes *pdbFldDes);
2654 epicsShareFunc int epicsShareAPI dbGetFieldIndex(const struct dbAddr *paddr);
2655-epicsShareFunc long epicsShareAPI dbGetNelements(
2656- const struct link *plink,long *nelements);
2657-epicsShareFunc int epicsShareAPI dbIsLinkConnected(const struct link *plink);
2658-epicsShareFunc int epicsShareAPI dbGetLinkDBFtype(const struct link *plink);
2659-epicsShareFunc long epicsShareAPI dbScanLink(
2660- struct dbCommon *pfrom, struct dbCommon *pto);
2661 epicsShareFunc long epicsShareAPI dbScanPassive(
2662 struct dbCommon *pfrom,struct dbCommon *pto);
2663-epicsShareFunc void epicsShareAPI dbScanFwdLink(struct link *plink);
2664 epicsShareFunc long epicsShareAPI dbProcess(struct dbCommon *precord);
2665 epicsShareFunc long epicsShareAPI dbNameToAddr(
2666 const char *pname,struct dbAddr *);
2667 epicsShareFunc devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
2668 epicsShareFunc devSup* epicsShareAPI dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset);
2669-epicsShareFunc long epicsShareAPI dbGetLinkValue(
2670- struct link *,short dbrType,void *pbuffer,long *options,long *nRequest);
2671 epicsShareFunc long epicsShareAPI dbGetField(
2672 struct dbAddr *,short dbrType,void *pbuffer,long *options,
2673 long *nRequest,void *pfl);
2674 epicsShareFunc long epicsShareAPI dbGet(
2675 struct dbAddr *,short dbrType,void *pbuffer,long *options,
2676 long *nRequest,void *pfl);
2677-epicsShareFunc long epicsShareAPI dbPutLinkValue(
2678- struct link *,short dbrType,const void *pbuffer,long nRequest);
2679 epicsShareFunc long epicsShareAPI dbPutField(
2680 struct dbAddr *,short dbrType,const void *pbuffer,long nRequest);
2681 epicsShareFunc long epicsShareAPI dbPut(
2682 struct dbAddr *,short dbrType,const void *pbuffer,long nRequest);
2683
2684-/* various utility routines */
2685-epicsShareFunc long epicsShareAPI dbGetControlLimits(
2686- const struct link *plink,double *low, double *high);
2687-epicsShareFunc long epicsShareAPI dbGetGraphicLimits(
2688- const struct link *plink,double *low, double *high);
2689-epicsShareFunc long epicsShareAPI dbGetAlarmLimits(
2690- const struct link *plink,double *lolo, double *low, double *high, double *hihi);
2691-epicsShareFunc long epicsShareAPI dbGetPrecision(
2692- const struct link *plink,short *precision);
2693-epicsShareFunc long epicsShareAPI dbGetUnits(
2694- const struct link *plink,char *units,int unitsSize);
2695-epicsShareFunc long epicsShareAPI dbGetAlarm(
2696- const struct link *plink, epicsEnum16 *status,epicsEnum16 *severity);
2697-epicsShareFunc long epicsShareAPI dbGetTimeStamp(
2698- const struct link *plink,epicsTimeStamp *pstamp);
2699-
2700 typedef void(*SPC_ASCALLBACK)(struct dbCommon *);
2701 /*dbSpcAsRegisterCallback called by access security */
2702 epicsShareFunc void epicsShareAPI dbSpcAsRegisterCallback(SPC_ASCALLBACK func);
2703
2704=== modified file 'src/ioc/db/dbAddr.h'
2705--- src/ioc/db/dbAddr.h 2008-08-15 18:58:18 +0000
2706+++ src/ioc/db/dbAddr.h 2012-06-21 20:42:45 +0000
2707@@ -4,7 +4,7 @@
2708 * Copyright (c) 2002 The Regents of the University of California, as
2709 * Operator of Los Alamos National Laboratory.
2710 * EPICS BASE is distributed subject to a Software License Agreement found
2711-* in file LICENSE that is included with this distribution.
2712+* in file LICENSE that is included with this distribution.
2713 \*************************************************************************/
2714
2715 #ifndef dbAddrh
2716@@ -27,7 +27,4 @@
2717
2718 typedef dbAddr DBADDR;
2719
2720-unsigned dbNameOfPV (const dbAddr * paddr, char * pBuf, unsigned bufLen);
2721-unsigned dbNameSizeOfPV (const dbAddr * paddr);
2722-
2723 #endif /* dbAddrh */
2724
2725=== modified file 'src/ioc/db/dbBkpt.c'
2726--- src/ioc/db/dbBkpt.c 2010-10-05 19:27:37 +0000
2727+++ src/ioc/db/dbBkpt.c 2012-06-21 20:42:45 +0000
2728@@ -65,6 +65,7 @@
2729 #include "dbAddr.h"
2730 #include "dbAccessDefs.h"
2731 #include "dbScan.h"
2732+#include "dbLink.h"
2733 #include "dbLock.h"
2734 #include "recGbl.h"
2735 #include "dbTest.h"
2736
2737=== modified file 'src/ioc/db/dbCAC.h'
2738--- src/ioc/db/dbCAC.h 2011-06-01 22:22:12 +0000
2739+++ src/ioc/db/dbCAC.h 2012-06-21 20:42:45 +0000
2740@@ -5,7 +5,7 @@
2741 * Operator of Los Alamos National Laboratory.
2742 * EPICS BASE Versions 3.13.7
2743 * and higher are distributed subject to a Software License Agreement found
2744-* in file LICENSE that is included with this distribution.
2745+* in file LICENSE that is included with this distribution.
2746 \*************************************************************************/
2747 /*
2748 * $Revision-Id$
2749@@ -49,7 +49,7 @@
2750 #include "db_access.h"
2751 #include "dbNotify.h"
2752 #include "dbEvent.h"
2753-#include "dbAddr.h"
2754+#include "dbChannel.h"
2755 #include "dbLock.h"
2756 #include "dbCommon.h"
2757 #include "db_convert.h"
2758@@ -75,25 +75,25 @@
2759 virtual ~dbBaseIO() {}
2760 };
2761
2762-extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbAddr *paddr,
2763+extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbChannel *dbch,
2764 int eventsRemaining, struct db_field_log *pfl );
2765
2766-class dbSubscriptionIO :
2767- public tsDLNode < dbSubscriptionIO >,
2768+class dbSubscriptionIO :
2769+ public tsDLNode < dbSubscriptionIO >,
2770 public dbBaseIO {
2771 public:
2772- dbSubscriptionIO (
2773+ dbSubscriptionIO (
2774 epicsGuard < epicsMutex > &, epicsMutex &,
2775- dbContext &, dbChannelIO &, struct dbAddr &, cacStateNotify &,
2776+ dbContext &, dbChannelIO &, struct dbChannel *, cacStateNotify &,
2777 unsigned type, unsigned long count, unsigned mask, dbEventCtx );
2778 void destructor ( epicsGuard < epicsMutex > & );
2779 void unsubscribe ( epicsGuard < epicsMutex > & );
2780 void channelDeleteException ( epicsGuard < epicsMutex > & );
2781 void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
2782 void show ( unsigned level ) const;
2783- void * operator new ( size_t size,
2784+ void * operator new ( size_t size,
2785 tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & );
2786- epicsPlacementDeleteOperator (( void *,
2787+ epicsPlacementDeleteOperator (( void *,
2788 tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & ))
2789 private:
2790 epicsMutex & mutex;
2791@@ -104,8 +104,8 @@
2792 unsigned type;
2793 unsigned id;
2794 dbSubscriptionIO * isSubscription ();
2795- friend void dbSubscriptionEventCallback (
2796- void * pPrivate, struct dbAddr * paddr,
2797+ friend void dbSubscriptionEventCallback (
2798+ void * pPrivate, struct dbChannel * dbch,
2799 int eventsRemaining, struct db_field_log * pfl );
2800 dbSubscriptionIO ( const dbSubscriptionIO & );
2801 dbSubscriptionIO & operator = ( const dbSubscriptionIO & );
2802@@ -149,8 +149,8 @@
2803 class dbContextReadNotifyCache {
2804 public:
2805 dbContextReadNotifyCache ( epicsMutex & );
2806- void callReadNotify ( epicsGuard < epicsMutex > &,
2807- struct dbAddr & addr, unsigned type, unsigned long count,
2808+ void callReadNotify ( epicsGuard < epicsMutex > &,
2809+ struct dbChannel * dbch, unsigned type, unsigned long count,
2810 cacReadNotify & notify );
2811 void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
2812 private:
2813@@ -162,29 +162,29 @@
2814
2815 class dbContext : public cacContext {
2816 public:
2817- dbContext ( epicsMutex & cbMutex, epicsMutex & mutex,
2818+ dbContext ( epicsMutex & cbMutex, epicsMutex & mutex,
2819 cacContextNotify & notify );
2820 virtual ~dbContext ();
2821 void destroyChannel ( epicsGuard < epicsMutex > &, dbChannelIO & );
2822- void callReadNotify ( epicsGuard < epicsMutex > &,
2823- struct dbAddr & addr, unsigned type, unsigned long count,
2824+ void callReadNotify ( epicsGuard < epicsMutex > &,
2825+ struct dbChannel * dbch, unsigned type, unsigned long count,
2826 cacReadNotify & notify );
2827- void callStateNotify ( struct dbAddr &addr, unsigned type, unsigned long count,
2828+ void callStateNotify ( struct dbChannel * dbch, unsigned type, unsigned long count,
2829 const struct db_field_log * pfl, cacStateNotify & notify );
2830- void subscribe (
2831+ void subscribe (
2832 epicsGuard < epicsMutex > &,
2833- struct dbAddr & addr, dbChannelIO & chan,
2834- unsigned type, unsigned long count, unsigned mask,
2835+ struct dbChannel * dbch, dbChannelIO & chan,
2836+ unsigned type, unsigned long count, unsigned mask,
2837 cacStateNotify & notify, cacChannel::ioid * pId );
2838- void initiatePutNotify (
2839- epicsGuard < epicsMutex > &, dbChannelIO &, struct dbAddr &,
2840- unsigned type, unsigned long count, const void * pValue,
2841- cacWriteNotify & notify, cacChannel::ioid * pId );
2842+ void initiatePutNotify (
2843+ epicsGuard < epicsMutex > &, dbChannelIO &, struct dbChannel *,
2844+ unsigned type, unsigned long count, const void * pValue,
2845+ cacWriteNotify & notify, cacChannel::ioid * pId );
2846 void show ( unsigned level ) const;
2847 void showAllIO ( const dbChannelIO & chan, unsigned level ) const;
2848- void destroyAllIO (
2849+ void destroyAllIO (
2850 epicsGuard < epicsMutex > &, dbChannelIO & chan );
2851- void ioCancel ( epicsGuard < epicsMutex > &,
2852+ void ioCancel ( epicsGuard < epicsMutex > &,
2853 dbChannelIO & chan, const cacChannel::ioid &id );
2854 void ioShow ( epicsGuard < epicsMutex > &,
2855 const cacChannel::ioid & id, unsigned level ) const;
2856@@ -202,11 +202,11 @@
2857 epics_auto_ptr < cacContext > pNetContext;
2858 char * pStateNotifyCache;
2859
2860- cacChannel & createChannel (
2861+ cacChannel & createChannel (
2862 epicsGuard < epicsMutex > &,
2863- const char * pChannelName, cacChannelNotify &,
2864+ const char * pChannelName, cacChannelNotify &,
2865 cacChannel::priLev );
2866- void flush (
2867+ void flush (
2868 epicsGuard < epicsMutex > & );
2869 unsigned circuitCount (
2870 epicsGuard < epicsMutex > & ) const;
2871@@ -214,7 +214,7 @@
2872 epicsGuard < epicsMutex > & ) const;
2873 unsigned beaconAnomaliesSinceProgramStart (
2874 epicsGuard < epicsMutex > & ) const;
2875- void show (
2876+ void show (
2877 epicsGuard < epicsMutex > &, unsigned level ) const;
2878
2879 dbContext ( const dbContext & );
2880@@ -226,17 +226,17 @@
2881 {
2882 }
2883
2884-inline dbContextPrivateListOfIO::~dbContextPrivateListOfIO ()
2885+inline dbContextPrivateListOfIO::~dbContextPrivateListOfIO ()
2886 {
2887 assert ( ! this->pBlocker );
2888 }
2889
2890-inline void dbContext::callReadNotify (
2891- epicsGuard < epicsMutex > & guard, struct dbAddr &addr,
2892+inline void dbContext::callReadNotify (
2893+ epicsGuard < epicsMutex > & guard, struct dbChannel * dbch,
2894 unsigned type, unsigned long count, cacReadNotify & notifyIn )
2895 {
2896 guard.assertIdenticalMutex ( this-> mutex );
2897- this->readNotifyCache.callReadNotify ( guard, addr, type, count, notifyIn );
2898+ this->readNotifyCache.callReadNotify ( guard, dbch, type, count, notifyIn );
2899 }
2900
2901 #endif // dbCACh
2902
2903=== modified file 'src/ioc/db/dbCa.c'
2904--- src/ioc/db/dbCa.c 2012-05-04 18:38:59 +0000
2905+++ src/ioc/db/dbCa.c 2012-06-21 20:42:45 +0000
2906@@ -411,6 +411,13 @@
2907 return pca->isConnected;
2908 }
2909
2910+void dbCaScanFwdLink(struct link *plink) {
2911+ short fwdLinkValue = 1;
2912+
2913+ if (plink->value.pv_link.pvlMask & pvlOptFWD)
2914+ dbCaPutLink(plink, DBR_SHORT, &fwdLinkValue, 1);
2915+}
2916+
2917 #define pcaGetCheck \
2918 assert(plink); \
2919 if (plink->type != CA_LINK) return -1; \
2920@@ -639,7 +646,7 @@
2921 static void eventCallback(struct event_handler_args arg)
2922 {
2923 caLink *pca = (caLink *)arg.usr;
2924- DBLINK *plink;
2925+ struct link *plink;
2926 size_t size;
2927 dbCommon *precord = 0;
2928 struct dbr_time_double *pdbr_time_double;
2929
2930=== modified file 'src/ioc/db/dbCa.h'
2931--- src/ioc/db/dbCa.h 2009-04-29 18:24:25 +0000
2932+++ src/ioc/db/dbCa.h 2012-06-21 20:42:45 +0000
2933@@ -40,6 +40,7 @@
2934 #define dbCaPutLink(plink, dbrType, pbuffer, nRequest) \
2935 dbCaPutLinkCallback((plink), (dbrType), (pbuffer), (nRequest), 0, 0)
2936 epicsShareFunc int dbCaIsLinkConnected(const struct link *plink);
2937+epicsShareFunc void dbCaScanFwdLink(struct link *plink);
2938
2939 /* The following are available after the link is connected*/
2940 epicsShareFunc long dbCaGetNelements(const struct link *plink,
2941
2942=== added file 'src/ioc/db/dbChannel.c'
2943--- src/ioc/db/dbChannel.c 1970-01-01 00:00:00 +0000
2944+++ src/ioc/db/dbChannel.c 2012-06-21 20:42:45 +0000
2945@@ -0,0 +1,865 @@
2946+/*************************************************************************\
2947+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
2948+* National Laboratory.
2949+* Copyright (c) 2010 Brookhaven National Laboratory.
2950+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
2951+* fuer Materialien und Energie GmbH.
2952+* EPICS BASE is distributed subject to a Software License Agreement found
2953+* in file LICENSE that is included with this distribution.
2954+\*************************************************************************/
2955+
2956+/*
2957+ * Author: Andrew Johnson <anj@aps.anl.gov>
2958+ * Ralph Lange <Ralph.Lange@bessy.de>
2959+ */
2960+
2961+#include <stdio.h>
2962+#include <string.h>
2963+
2964+#include "cantProceed.h"
2965+#include "dbChannel.h"
2966+#include "dbCommon.h"
2967+#include "dbBase.h"
2968+#include "dbEvent.h"
2969+#include "link.h"
2970+#include <freeList.h>
2971+#include "dbAccessDefs.h"
2972+#include "dbLock.h"
2973+#include "dbStaticLib.h"
2974+#include "epicsAssert.h"
2975+#include "epicsString.h"
2976+#include "errlog.h"
2977+#include "gpHash.h"
2978+#include "recSup.h"
2979+#include "special.h"
2980+#include "yajl_parse.h"
2981+
2982+/* The following is defined in db_convert.h */
2983+extern unsigned short dbDBRnewToDBRold[DBR_ENUM+1];
2984+
2985+typedef struct parseContext {
2986+ dbChannel *chan;
2987+ chFilter *filter;
2988+ int depth;
2989+} parseContext;
2990+
2991+#define CALLIF(rtn) !rtn ? parse_stop : rtn
2992+
2993+static void *dbchStringFreeList;
2994+
2995+void dbChannelInit (void)
2996+{
2997+ if (!dbchStringFreeList) {
2998+ freeListInitPvt(&dbchStringFreeList,
2999+ sizeof(epicsOldString), 128);
3000+ }
3001+}
3002+
3003+static void chf_value(parseContext *parser, parse_result *presult)
3004+{
3005+ chFilter *filter = parser->filter;
3006+
3007+ if (*presult == parse_stop || parser->depth > 0)
3008+ return;
3009+
3010+ parser->filter = NULL;
3011+ if (filter->plug->fif->parse_end(filter) == parse_continue) {
3012+ ellAdd(&parser->chan->filters, &filter->list_node);
3013+ } else {
3014+ free(filter); /* FIXME: Use free-list */
3015+ *presult = parse_stop;
3016+ }
3017+}
3018+
3019+static int chf_null(void * ctx)
3020+{
3021+ parseContext *parser = (parseContext *) ctx;
3022+ chFilter *filter = parser->filter;
3023+ parse_result result;
3024+
3025+ assert(filter);
3026+ result = CALLIF(filter->plug->fif->parse_null)(filter );
3027+ chf_value(parser, &result);
3028+ return result;
3029+}
3030+
3031+static int chf_boolean(void * ctx, int boolVal)
3032+{
3033+ parseContext *parser = (parseContext *) ctx;
3034+ chFilter *filter = parser->filter;
3035+ parse_result result;
3036+
3037+ assert(filter);
3038+ result = CALLIF(filter->plug->fif->parse_boolean)(filter , boolVal);
3039+ chf_value(parser, &result);
3040+ return result;
3041+}
3042+
3043+static int chf_integer(void * ctx, long integerVal)
3044+{
3045+ parseContext *parser = (parseContext *) ctx;
3046+ chFilter *filter = parser->filter;
3047+ parse_result result;
3048+
3049+ assert(filter);
3050+ result = CALLIF(filter->plug->fif->parse_integer)(filter , integerVal);
3051+ chf_value(parser, &result);
3052+ return result;
3053+}
3054+
3055+static int chf_double(void * ctx, double doubleVal)
3056+{
3057+ parseContext *parser = (parseContext *) ctx;
3058+ chFilter *filter = parser->filter;
3059+ parse_result result;
3060+
3061+ assert(filter);
3062+ result = CALLIF(filter->plug->fif->parse_double)(filter , doubleVal);
3063+ chf_value(parser, &result);
3064+ return result;
3065+}
3066+
3067+static int chf_string(void * ctx, const unsigned char * stringVal,
3068+ unsigned int stringLen)
3069+{
3070+ parseContext *parser = (parseContext *) ctx;
3071+ chFilter *filter = parser->filter;
3072+ parse_result result;
3073+
3074+ assert(filter);
3075+ result = CALLIF(filter->plug->fif->parse_string)(filter , (const char *) stringVal, stringLen);
3076+ chf_value(parser, &result);
3077+ return result;
3078+}
3079+
3080+static int chf_start_map(void * ctx)
3081+{
3082+ parseContext *parser = (parseContext *) ctx;
3083+ chFilter *filter = parser->filter;
3084+
3085+ if (!filter) {
3086+ assert(parser->depth == 0);
3087+ return parse_continue; /* Opening '{' */
3088+ }
3089+
3090+ ++parser->depth;
3091+ return CALLIF(filter->plug->fif->parse_start_map)(filter );
3092+}
3093+
3094+static int chf_map_key(void * ctx, const unsigned char * key,
3095+ unsigned int stringLen)
3096+{
3097+ parseContext *parser = (parseContext *) ctx;
3098+ chFilter *filter = parser->filter;
3099+ const chFilterPlugin *plug;
3100+ parse_result result;
3101+
3102+ if (filter) {
3103+ assert(parser->depth > 0);
3104+ return CALLIF(filter->plug->fif->parse_map_key)(filter , (const char *) key, stringLen);
3105+ }
3106+
3107+ assert(parser->depth == 0);
3108+ plug = dbFindFilter((const char *) key, stringLen);
3109+ if (!plug) {
3110+ printf("dbChannelCreate: Channel filter '%.*s' not found\n", (int) stringLen, key);
3111+ return parse_stop;
3112+ }
3113+
3114+ /* FIXME: Use a free-list */
3115+ filter = (chFilter *) callocMustSucceed(1, sizeof(*filter), "Creating dbChannel filter");
3116+ filter->chan = parser->chan;
3117+ filter->plug = plug;
3118+ filter->puser = NULL;
3119+
3120+ result = plug->fif->parse_start(filter);
3121+ if (result == parse_continue) {
3122+ parser->filter = filter;
3123+ } else {
3124+ free(filter); /* FIXME: Use free-list */
3125+ }
3126+ return result;
3127+}
3128+
3129+static int chf_end_map(void * ctx)
3130+{
3131+ parseContext *parser = (parseContext *) ctx;
3132+ chFilter *filter = parser->filter;
3133+ parse_result result;
3134+
3135+ if (!filter) {
3136+ assert(parser->depth == 0);
3137+ return parse_continue; /* Final closing '}' */
3138+ }
3139+
3140+ assert(parser->depth > 0);
3141+ result = CALLIF(filter->plug->fif->parse_end_map)(filter );
3142+
3143+ --parser->depth;
3144+ chf_value(parser, &result);
3145+ return result;
3146+}
3147+
3148+static int chf_start_array(void * ctx)
3149+{
3150+ parseContext *parser = (parseContext *) ctx;
3151+ chFilter *filter = parser->filter;
3152+
3153+ assert(filter);
3154+ ++parser->depth;
3155+ return CALLIF(filter->plug->fif->parse_start_array)(filter );
3156+}
3157+
3158+static int chf_end_array(void * ctx)
3159+{
3160+ parseContext *parser = (parseContext *) ctx;
3161+ chFilter *filter = parser->filter;
3162+ parse_result result;
3163+
3164+ assert(filter);
3165+ result = CALLIF(filter->plug->fif->parse_end_array)(filter );
3166+ --parser->depth;
3167+ chf_value(parser, &result);
3168+ return result;
3169+}
3170+
3171+static const yajl_callbacks chf_callbacks =
3172+ { chf_null, chf_boolean, chf_integer, chf_double, NULL, chf_string,
3173+ chf_start_map, chf_map_key, chf_end_map, chf_start_array, chf_end_array };
3174+
3175+static const yajl_parser_config chf_config =
3176+ { 0, 1 }; /* allowComments = NO , checkUTF8 = YES */
3177+
3178+static void * chf_malloc(void *ctx, unsigned int sz)
3179+{
3180+ return malloc(sz); /* FIXME: free-list */
3181+}
3182+
3183+static void * chf_realloc(void *ctx, void *ptr, unsigned int sz)
3184+{
3185+ return realloc(ptr, sz); /* FIXME: free-list */
3186+}
3187+
3188+static void chf_free(void *ctx, void *ptr)
3189+{
3190+ return free(ptr); /* FIXME: free-list */
3191+}
3192+
3193+static const yajl_alloc_funcs chf_alloc =
3194+ { chf_malloc, chf_realloc, chf_free };
3195+
3196+static long chf_parse(dbChannel *chan, const char **pjson)
3197+{
3198+ parseContext parser =
3199+ { chan, NULL, 0 };
3200+ yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_config, &chf_alloc, &parser);
3201+ const char *json = *pjson;
3202+ size_t jlen = strlen(json);
3203+ yajl_status ys;
3204+ long status;
3205+
3206+ if (!yh)
3207+ return S_db_noMemory;
3208+
3209+ ys = yajl_parse(yh, (const unsigned char *) json, jlen);
3210+ if (ys == yajl_status_insufficient_data)
3211+ ys = yajl_parse_complete(yh);
3212+
3213+ switch (ys) {
3214+ case yajl_status_ok:
3215+ status = 0;
3216+ *pjson += yajl_get_bytes_consumed(yh);
3217+ break;
3218+
3219+ case yajl_status_error: {
3220+ unsigned char *err;
3221+
3222+ err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
3223+ printf("dbChannelCreate: %s\n", err);
3224+ yajl_free_error(yh, err);
3225+ } /* fall through */
3226+ default:
3227+ status = S_db_notFound;
3228+ }
3229+
3230+ if (parser.filter) {
3231+ assert(status);
3232+ parser.filter->plug->fif->parse_abort(parser.filter);
3233+ free(parser.filter); /* FIXME: free-list */
3234+ }
3235+ yajl_free(yh);
3236+ return status;
3237+}
3238+
3239+static long pvNameLookup(DBENTRY *pdbe, const char **ppname)
3240+{
3241+ long status;
3242+
3243+ dbInitEntry(pdbbase, pdbe);
3244+
3245+ status = dbFindRecordPart(pdbe, ppname);
3246+ if (status)
3247+ return status;
3248+
3249+ if (**ppname == '.')
3250+ ++*ppname;
3251+
3252+ status = dbFindFieldPart(pdbe, ppname);
3253+ if (status == S_dbLib_fieldNotFound)
3254+ status = dbGetAttributePart(pdbe, ppname);
3255+
3256+ return status;
3257+}
3258+
3259+long dbChannelTest(const char *name)
3260+{
3261+ DBENTRY dbEntry;
3262+ long status;
3263+
3264+ if (!name || !*name || !pdbbase)
3265+ return S_db_notFound;
3266+
3267+ status = pvNameLookup(&dbEntry, &name);
3268+
3269+ dbFinishEntry(&dbEntry);
3270+ return status;
3271+}
3272+
3273+#define TRY(Func, Arg) \
3274+if (Func) { \
3275+ result = Func Arg; \
3276+ if (result != parse_continue) goto failure; \
3277+}
3278+
3279+static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppnext) {
3280+ epicsInt32 start = 0;
3281+ epicsInt32 end = -1;
3282+ epicsInt32 incr = 1;
3283+ epicsInt32 l;
3284+ char *pnext;
3285+ short exist;
3286+ chFilter *filter;
3287+ const chFilterPlugin *plug;
3288+ parse_result result;
3289+ long status = 0;
3290+
3291+ /* If no number is present, strtol() returns 0 and sets pnext=pname,
3292+ else pnext points to the first char after the number */
3293+ pname++;
3294+ l = strtol(pname, &pnext, 0);
3295+ exist = pnext - pname;
3296+ if (exist) start = l;
3297+ pname = pnext;
3298+ if (*pname == ']' && exist) {
3299+ end = start;
3300+ goto insertplug;
3301+ }
3302+ if (*pname != ':') {
3303+ status = S_dbLib_fieldNotFound;
3304+ goto finish;
3305+ }
3306+ pname++;
3307+ l = strtol(pname, &pnext, 0);
3308+ exist = pnext - pname;
3309+ pname = pnext;
3310+ if (*pname == ']') {
3311+ if (exist) end = l;
3312+ goto insertplug;
3313+ }
3314+ if (exist) incr = l;
3315+ if (*pname != ':') {
3316+ status = S_dbLib_fieldNotFound;
3317+ goto finish;
3318+ }
3319+ pname++;
3320+ l = strtol(pname, &pnext, 0);
3321+ exist = pnext - pname;
3322+ if (exist) end = l;
3323+ pname = pnext;
3324+ if (*pname != ']') {
3325+ status = S_dbLib_fieldNotFound;
3326+ goto finish;
3327+ }
3328+
3329+ insertplug:
3330+ pname++;
3331+ *ppnext = pname;
3332+
3333+ plug = dbFindFilter("arr", 3);
3334+ if (!plug) {
3335+ status = S_dbLib_fieldNotFound;
3336+ goto finish;
3337+ }
3338+
3339+ /* FIXME: Use a free-list */
3340+ filter = (chFilter *) callocMustSucceed(1, sizeof(*filter), "Creating 'arr' dbChannel filter");
3341+ filter->chan = chan;
3342+ filter->plug = plug;
3343+ filter->puser = NULL;
3344+
3345+ TRY(filter->plug->fif->parse_start, (filter));
3346+ TRY(filter->plug->fif->parse_start_map, (filter));
3347+ if (start != 0) {
3348+ TRY(filter->plug->fif->parse_map_key, (filter, "s", 1));
3349+ TRY(filter->plug->fif->parse_integer, (filter, start));
3350+ }
3351+ if (incr != 1) {
3352+ TRY(filter->plug->fif->parse_map_key, (filter, "i", 1));
3353+ TRY(filter->plug->fif->parse_integer, (filter, incr));
3354+ }
3355+ if (end != -1) {
3356+ TRY(filter->plug->fif->parse_map_key, (filter, "e", 1));
3357+ TRY(filter->plug->fif->parse_integer, (filter, end));
3358+ }
3359+ TRY(filter->plug->fif->parse_end_map, (filter));
3360+ TRY(filter->plug->fif->parse_end, (filter));
3361+
3362+ ellAdd(&chan->filters, &filter->list_node);
3363+ return 0;
3364+
3365+ failure:
3366+ free(filter); /* FIXME: Use free-list */
3367+ status = S_dbLib_fieldNotFound;
3368+
3369+ finish:
3370+ return status;
3371+}
3372+
3373+/* Stolen from dbAccess.c: */
3374+static short mapDBFToDBR[DBF_NTYPES] =
3375+ {
3376+ /* DBF_STRING => */DBR_STRING,
3377+ /* DBF_CHAR => */DBR_CHAR,
3378+ /* DBF_UCHAR => */DBR_UCHAR,
3379+ /* DBF_SHORT => */DBR_SHORT,
3380+ /* DBF_USHORT => */DBR_USHORT,
3381+ /* DBF_LONG => */DBR_LONG,
3382+ /* DBF_ULONG => */DBR_ULONG,
3383+ /* DBF_FLOAT => */DBR_FLOAT,
3384+ /* DBF_DOUBLE => */DBR_DOUBLE,
3385+ /* DBF_ENUM, => */DBR_ENUM,
3386+ /* DBF_MENU, => */DBR_ENUM,
3387+ /* DBF_DEVICE => */DBR_ENUM,
3388+ /* DBF_INLINK => */DBR_STRING,
3389+ /* DBF_OUTLINK => */DBR_STRING,
3390+ /* DBF_FWDLINK => */DBR_STRING,
3391+ /* DBF_NOACCESS => */DBR_NOACCESS };
3392+
3393+dbChannel * dbChannelCreate(const char *name)
3394+{
3395+ const char *pname = name;
3396+ DBENTRY dbEntry;
3397+ dbChannel *chan = NULL;
3398+ dbAddr *paddr;
3399+ dbFldDes *pflddes;
3400+ long status;
3401+ short dbfType;
3402+
3403+ if (!name || !*name || !pdbbase)
3404+ return NULL;
3405+
3406+ status = pvNameLookup(&dbEntry, &pname);
3407+ if (status)
3408+ goto finish;
3409+
3410+ /* FIXME: Use free-list */
3411+ chan = (dbChannel *) callocMustSucceed(1, sizeof(*chan), "dbChannelCreate");
3412+ chan->name = epicsStrDup(name); /* FIXME: free-list */
3413+ ellInit(&chan->filters);
3414+ ellInit(&chan->pre_chain);
3415+ ellInit(&chan->post_chain);
3416+
3417+ paddr = &chan->addr;
3418+ pflddes = dbEntry.pflddes;
3419+ dbfType = pflddes->field_type;
3420+
3421+ paddr->precord = dbEntry.precnode->precord;
3422+ paddr->pfield = dbEntry.pfield;
3423+ paddr->pfldDes = pflddes;
3424+ paddr->no_elements = 1;
3425+ paddr->field_type = dbfType;
3426+ paddr->field_size = pflddes->size;
3427+ paddr->special = pflddes->special;
3428+ paddr->dbr_field_type = mapDBFToDBR[dbfType];
3429+
3430+ /* Handle field modifiers */
3431+ if (*pname) {
3432+ if (*pname == '$') {
3433+ /* Some field types can be accessed as char arrays */
3434+ if (dbfType == DBF_STRING) {
3435+ paddr->no_elements = pflddes->size;
3436+ paddr->field_type = DBF_CHAR;
3437+ paddr->field_size = 1;
3438+ paddr->dbr_field_type = DBR_CHAR;
3439+ } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
3440+ /* Clients see a char array, but keep original dbfType */
3441+ paddr->no_elements = PVNAME_STRINGSZ + 12;
3442+ paddr->field_size = 1;
3443+ paddr->dbr_field_type = DBR_CHAR;
3444+ } else {
3445+ status = S_dbLib_fieldNotFound;
3446+ goto finish;
3447+ }
3448+ pname++;
3449+ }
3450+
3451+ if (*pname == '[') {
3452+ status = parseArrayRange(chan, pname, &pname);
3453+ if (status) goto finish;
3454+ }
3455+
3456+ /* JSON may follow */
3457+ if (*pname == '{') {
3458+ status = chf_parse(chan, &pname);
3459+ if (status) goto finish;
3460+ }
3461+
3462+ /* Make sure there's nothing else */
3463+ if (*pname) {
3464+ status = S_dbLib_fieldNotFound;
3465+ goto finish;
3466+ }
3467+ }
3468+
3469+ if (paddr->special == SPC_DBADDR) {
3470+ struct rset *prset = dbGetRset(paddr);
3471+
3472+ /* Let record type modify the dbAddr */
3473+ if (prset && prset->cvt_dbaddr) {
3474+ status = prset->cvt_dbaddr(paddr);
3475+ if (status) goto finish;
3476+ }
3477+ }
3478+
3479+finish:
3480+ if (status && chan) {
3481+ dbChannelDelete(chan);
3482+ chan = NULL;
3483+ }
3484+ dbFinishEntry(&dbEntry);
3485+ return chan;
3486+}
3487+
3488+db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn) {
3489+ chFilter *filter;
3490+ ELLNODE *node;
3491+ db_field_log *pLog = pLogIn;
3492+
3493+ for (node = ellFirst(&chan->pre_chain); node && pLog; node = ellNext(node)) {
3494+ filter = CONTAINER(node, chFilter, pre_node);
3495+ pLog = filter->pre_func(filter->pre_arg, chan, pLog);
3496+ }
3497+ return pLog;
3498+}
3499+
3500+db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn) {
3501+ chFilter *filter;
3502+ ELLNODE *node;
3503+ db_field_log *pLog = pLogIn;
3504+
3505+ for (node = ellFirst(&chan->post_chain); node && pLog; node = ellNext(node)) {
3506+ filter = CONTAINER(node, chFilter, post_node);
3507+ pLog = filter->post_func(filter->post_arg, chan, pLog);
3508+ }
3509+ return pLog;
3510+}
3511+
3512+long dbChannelOpen(dbChannel *chan)
3513+{
3514+ chFilter *filter;
3515+ chPostEventFunc *func;
3516+ void *arg;
3517+ long status;
3518+ ELLNODE *node;
3519+ db_field_log probe;
3520+ db_field_log p;
3521+
3522+ for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
3523+ filter = CONTAINER(node, chFilter, list_node);
3524+ /* Call channel_open */
3525+ status = 0;
3526+ if (filter->plug->fif->channel_open)
3527+ status = filter->plug->fif->channel_open(filter);
3528+ if (status) return status;
3529+ }
3530+
3531+ /* Set up type probe */
3532+ probe.field_type = dbChannelFieldType(chan);
3533+ probe.no_elements = dbChannelElements(chan);
3534+ probe.field_size = dbChannelFieldSize(chan);
3535+ p = probe;
3536+
3537+ /*
3538+ * Build up the pre- and post-event-queue filter chains
3539+ * Separate loops because the probe must reach the filters in the right order.
3540+ */
3541+ for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
3542+ filter = CONTAINER(node, chFilter, list_node);
3543+ func = NULL;
3544+ arg = NULL;
3545+ if (filter->plug->fif->channel_register_pre) {
3546+ filter->plug->fif->channel_register_pre(filter, &func, &arg, &p);
3547+ if (func) {
3548+ ellAdd(&chan->pre_chain, &filter->pre_node);
3549+ filter->pre_func = func;
3550+ filter->pre_arg = arg;
3551+ probe = p;
3552+ }
3553+ }
3554+ }
3555+ for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
3556+ filter = CONTAINER(node, chFilter, list_node);
3557+ func = NULL;
3558+ arg = NULL;
3559+ if (filter->plug->fif->channel_register_post) {
3560+ filter->plug->fif->channel_register_post(filter, &func, &arg, &p);
3561+ if (func) {
3562+ ellAdd(&chan->post_chain, &filter->post_node);
3563+ filter->post_func = func;
3564+ filter->post_arg = arg;
3565+ probe = p;
3566+ }
3567+ }
3568+ }
3569+
3570+ /* Save probe results */
3571+ chan->final_no_elements = probe.no_elements;
3572+ chan->final_field_size = probe.field_size;
3573+ chan->final_type = probe.field_type;
3574+ chan->dbr_final_type = dbDBRnewToDBRold[mapDBFToDBR[probe.field_type]];
3575+
3576+ return 0;
3577+}
3578+
3579+/* FIXME: For performance we should make these one-liners into macros,
3580+ * or try to make them inline if all our compilers can do that.
3581+ */
3582+const char * dbChannelName(dbChannel *chan)
3583+{
3584+ return chan->name;
3585+}
3586+
3587+struct dbCommon * dbChannelRecord(dbChannel *chan)
3588+{
3589+ return chan->addr.precord;
3590+}
3591+
3592+struct dbFldDes * dbChannelFldDes(dbChannel *chan)
3593+{
3594+ return chan->addr.pfldDes;
3595+}
3596+
3597+long dbChannelElements(dbChannel *chan)
3598+{
3599+ return chan->addr.no_elements;
3600+}
3601+
3602+short dbChannelFieldType(dbChannel *chan)
3603+{
3604+ return chan->addr.field_type;
3605+}
3606+
3607+short dbChannelExportType(dbChannel *chan)
3608+{
3609+ return chan->addr.dbr_field_type;
3610+}
3611+
3612+short dbChannelFieldSize(dbChannel *chan)
3613+{
3614+ return chan->addr.field_size;
3615+}
3616+
3617+long dbChannelFinalElements(dbChannel *chan)
3618+{
3619+ return chan->final_no_elements;
3620+}
3621+
3622+short dbChannelFinalFieldType(dbChannel *chan)
3623+{
3624+ return chan->final_type;
3625+}
3626+
3627+short dbChannelFinalExportType(dbChannel *chan)
3628+{
3629+ return chan->dbr_final_type;
3630+}
3631+
3632+short dbChannelFinalFieldSize(dbChannel *chan)
3633+{
3634+ return chan->final_field_size;
3635+}
3636+
3637+short dbChannelSpecial(dbChannel *chan)
3638+{
3639+ return chan->addr.special;
3640+}
3641+
3642+void * dbChannelField(dbChannel *chan)
3643+{
3644+ /* Channel filters do not get to interpose here since there are many
3645+ * places where the field pointer is compared with the address of a
3646+ * specific record field, so they can't modify the pointer value.
3647+ */
3648+ return chan->addr.pfield;
3649+}
3650+
3651+/* Only use dbChannelGet() if the record is already locked. */
3652+long dbChannelGet(dbChannel *chan, short type, void *pbuffer,
3653+ long *options, long *nRequest, void *pfl)
3654+{
3655+ /* FIXME: Vector through chan->get() ? */
3656+ return dbGet(&chan->addr, type, pbuffer, options, nRequest, pfl);
3657+}
3658+
3659+long dbChannelGetField(dbChannel *chan, short dbrType, void *pbuffer,
3660+ long *options, long *nRequest, void *pfl)
3661+{
3662+ dbCommon *precord = chan->addr.precord;
3663+ long status = 0;
3664+
3665+ dbScanLock(precord);
3666+ status = dbChannelGet(chan, dbrType, pbuffer, options, nRequest, pfl);
3667+ dbScanUnlock(precord);
3668+ return status;
3669+}
3670+
3671+/* Only use dbChannelPut() if the record is already locked.
3672+ * This routine doesn't work on link fields, ignores DISP, and
3673+ * doesn't trigger record processing on PROC or pp(TRUE).
3674+ */
3675+long dbChannelPut(dbChannel *chan, short type, const void *pbuffer,
3676+ long nRequest)
3677+{
3678+ /* FIXME: Vector through chan->put() ? */
3679+ return dbPut(&chan->addr, type, pbuffer, nRequest);
3680+}
3681+
3682+long dbChannelPutField(dbChannel *chan, short type, const void *pbuffer,
3683+ long nRequest)
3684+{
3685+ /* FIXME: Vector through chan->putField() ? */
3686+ return dbPutField(&chan->addr, type, pbuffer, nRequest);
3687+}
3688+
3689+void dbChannelShow(dbChannel *chan, int level, const unsigned short indent)
3690+{
3691+ long elems = chan->addr.no_elements;
3692+ long felems = chan->final_no_elements;
3693+ int count = ellCount(&chan->filters);
3694+ int pre = ellCount(&chan->pre_chain);
3695+ int post = ellCount(&chan->post_chain);
3696+
3697+ printf("%*schannel name: %s\n", indent, "", chan->name);
3698+ /* FIXME: show field_type as text */
3699+ printf("%*s field_type=%d (%dB), %ld element%s, %d filter%s", indent, "",
3700+ chan->addr.field_type, chan->addr.field_size, elems, elems == 1 ? "" : "s",
3701+ count, count == 1 ? "" : "s");
3702+ if (count)
3703+ printf(" (%d pre eventq, %d post eventq)\n", pre, post);
3704+ else
3705+ printf("\n");
3706+ if (level > 0)
3707+ dbChannelFilterShow(chan, level - 1, indent + 2);
3708+ if (count) {
3709+ /* FIXME: show field_type as text */
3710+ printf("%*s final field_type=%d (%dB), %ld element%s\n", indent, "",
3711+ chan->final_type, chan->final_field_size, felems, felems == 1 ? "" : "s");
3712+ }
3713+}
3714+
3715+void dbChannelFilterShow(dbChannel *chan, int level, const unsigned short indent)
3716+{
3717+ chFilter *filter = (chFilter *) ellFirst(&chan->filters);
3718+ while (filter) {
3719+ filter->plug->fif->channel_report(filter, level, indent);
3720+ filter = (chFilter *) ellNext(&filter->list_node);
3721+ }
3722+}
3723+
3724+void dbChannelDelete(dbChannel *chan)
3725+{
3726+ chFilter *filter;
3727+
3728+ /* Close filters in reverse order */
3729+ while ((filter = (chFilter *) ellPop(&chan->filters))) {
3730+ filter->plug->fif->channel_close(filter);
3731+ free(filter);
3732+ }
3733+ free((char *) chan->name); /* FIXME: Use free-list */
3734+ free(chan); /* FIXME: Use free-list */
3735+}
3736+
3737+static void freeArray(db_field_log *pfl) {
3738+ if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
3739+ freeListFree(dbchStringFreeList, pfl->u.r.field);
3740+ } else {
3741+ free(pfl->u.r.field);
3742+ }
3743+}
3744+
3745+void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
3746+{
3747+ void *p;
3748+ struct dbCommon *prec = dbChannelRecord(chan);
3749+
3750+ if (!pfl->type == dbfl_type_rec) return;
3751+
3752+ pfl->type = dbfl_type_ref;
3753+ pfl->stat = prec->stat;
3754+ pfl->sevr = prec->sevr;
3755+ pfl->time = prec->time;
3756+ pfl->field_type = chan->addr.field_type;
3757+ pfl->no_elements = chan->addr.no_elements;
3758+ pfl->field_size = chan->addr.field_size;
3759+ pfl->u.r.dtor = freeArray;
3760+ pfl->u.r.pvt = pvt;
3761+ if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
3762+ p = freeListCalloc(dbchStringFreeList);
3763+ } else {
3764+ p = calloc(pfl->no_elements, pfl->field_size);
3765+ }
3766+ if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL);
3767+ pfl->u.r.field = p;
3768+}
3769+
3770+/* FIXME: Do these belong in a different file? */
3771+
3772+void dbRegisterFilter(const char *name, const chFilterIf *fif, void *puser)
3773+{
3774+ GPHENTRY *pgph;
3775+ chFilterPlugin *pfilt;
3776+
3777+ if (!pdbbase) {
3778+ printf("dbRegisterFilter: pdbbase not set!\n");
3779+ return;
3780+ }
3781+
3782+ pgph = gphFind(pdbbase->pgpHash, name, &pdbbase->filterList);
3783+ if (pgph)
3784+ return;
3785+
3786+ pfilt = dbCalloc(1, sizeof(chFilterPlugin));
3787+ pfilt->name = epicsStrDup(name);
3788+ pfilt->fif = fif;
3789+ pfilt->puser = puser;
3790+
3791+ ellAdd(&pdbbase->filterList, &pfilt->node);
3792+ pgph = gphAdd(pdbbase->pgpHash, pfilt->name, &pdbbase->filterList);
3793+ if (!pgph) {
3794+ free((void *) pfilt->name);
3795+ free(pfilt);
3796+ printf("dbRegisterFilter: gphAdd failed\n");
3797+ return;
3798+ }
3799+ pgph->userPvt = pfilt;
3800+}
3801+
3802+const chFilterPlugin * dbFindFilter(const char *name, size_t len)
3803+{
3804+ GPHENTRY *pgph = gphFindParse(pdbbase->pgpHash, name, len,
3805+ &pdbbase->filterList);
3806+
3807+ if (!pgph)
3808+ return NULL;
3809+ return (chFilterPlugin *) pgph->userPvt;
3810+}
3811
3812=== added file 'src/ioc/db/dbChannel.h'
3813--- src/ioc/db/dbChannel.h 1970-01-01 00:00:00 +0000
3814+++ src/ioc/db/dbChannel.h 2012-06-21 20:42:45 +0000
3815@@ -0,0 +1,181 @@
3816+/*************************************************************************\
3817+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
3818+* National Laboratory.
3819+* Copyright (c) 2010 Brookhaven National Laboratory.
3820+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
3821+* fuer Materialien und Energie GmbH.
3822+* EPICS BASE is distributed subject to a Software License Agreement found
3823+* in file LICENSE that is included with this distribution.
3824+\*************************************************************************/
3825+
3826+/*
3827+ * Author: Andrew Johnson <anj@aps.anl.gov>
3828+ * Ralph Lange <Ralph.Lange@bessy.de>
3829+ */
3830+
3831+#ifndef INC_dbChannel_H
3832+#define INC_dbChannel_H
3833+
3834+#include "dbDefs.h"
3835+#include "dbAddr.h"
3836+#include "ellLib.h"
3837+#include "epicsTypes.h"
3838+#include "errMdef.h"
3839+#include "shareLib.h"
3840+#include "db_field_log.h"
3841+#include "dbEvent.h"
3842+
3843+#ifdef __cplusplus
3844+extern "C" {
3845+#endif
3846+
3847+/*
3848+ * event subscription
3849+ */
3850+typedef struct evSubscrip {
3851+ ELLNODE node;
3852+ struct dbChannel *chan;
3853+ EVENTFUNC *user_sub;
3854+ void *user_arg;
3855+ struct event_que *ev_que;
3856+ db_field_log **pLastLog;
3857+ unsigned long npend; /* n times this event is on the queue */
3858+ unsigned long nreplace; /* n times replacing event on the queue */
3859+ unsigned char select;
3860+ char useValque;
3861+ char callBackInProgress;
3862+ char enabled;
3863+} evSubscrip;
3864+
3865+typedef struct chFilter chFilter;
3866+
3867+/* A dbChannel points to a record field, and can have multiple filters */
3868+typedef struct dbChannel {
3869+ const char *name;
3870+ dbAddr addr; /* address structure for record/field */
3871+ long final_no_elements; /* final number of elements (arrays) */
3872+ short final_field_size; /* final size of element */
3873+ short final_type; /* final type of database field */
3874+ short dbr_final_type; /* final field type as seen by database request */
3875+ ELLLIST filters; /* list of filters as created from JSON */
3876+ ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
3877+ ELLLIST post_chain; /* list of filters to be called post-event-queue */
3878+} dbChannel;
3879+
3880+/* Prototype for the post event function that is called in filter stacks */
3881+typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
3882+
3883+/* Return values from chFilterIf->parse_* routines: */
3884+typedef enum {
3885+ parse_stop, parse_continue
3886+} parse_result;
3887+
3888+/* These routines must be implemented by each filter plug-in */
3889+typedef struct chFilterIf {
3890+ /* Parsing event handlers: */
3891+ parse_result (* parse_start)(chFilter *filter);
3892+ /* If parse_start() returns parse_continue for a filter, one of
3893+ * parse_abort() or parse_end() will later be called for that same
3894+ * filter.
3895+ */
3896+ void (* parse_abort)(chFilter *filter);
3897+ /* If parse_abort() is called it should release any memory allocated
3898+ * for this filter; no further parse_...() calls will be made;
3899+ */
3900+ parse_result (* parse_end)(chFilter *filter);
3901+ /* If parse_end() returns parse_stop it should have released any
3902+ * memory allocated for this filter; no further parse_...() calls will
3903+ * be made in this case.
3904+ */
3905+
3906+ parse_result (* parse_null)(chFilter *filter);
3907+ parse_result (* parse_boolean)(chFilter *filter, int boolVal);
3908+ parse_result (* parse_integer)(chFilter *filter, long integerVal);
3909+ parse_result (* parse_double)(chFilter *filter, double doubleVal);
3910+ parse_result (* parse_string)(chFilter *filter, const char *stringVal,
3911+ size_t stringLen); /* NB: stringVal is not zero-terminated: */
3912+
3913+ parse_result (* parse_start_map)(chFilter *filter);
3914+ parse_result (* parse_map_key)(chFilter *filter, const char *key,
3915+ size_t stringLen); /* NB: key is not zero-terminated: */
3916+ parse_result (* parse_end_map)(chFilter *filter);
3917+
3918+ parse_result (* parse_start_array)(chFilter *filter);
3919+ parse_result (* parse_end_array)(chFilter *filter);
3920+
3921+ /* Channel operations: */
3922+ long (* channel_open)(chFilter *filter);
3923+ void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
3924+ void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
3925+ void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
3926+ /* FIXME: More filter routines here ... */
3927+ void (* channel_close)(chFilter *filter);
3928+} chFilterIf;
3929+
3930+/* A chFilterPlugin holds data for a filter plugin */
3931+typedef struct chFilterPlugin {
3932+ ELLNODE node;
3933+ const char *name;
3934+ const chFilterIf *fif;
3935+ void *puser;
3936+} chFilterPlugin;
3937+
3938+/* A chFilter holds data for a single filter instance */
3939+struct chFilter {
3940+ ELLNODE list_node;
3941+ ELLNODE pre_node;
3942+ ELLNODE post_node;
3943+ dbChannel *chan;
3944+ const chFilterPlugin *plug;
3945+ chPostEventFunc *pre_func;
3946+ void *pre_arg;
3947+ chPostEventFunc *post_func;
3948+ void *post_arg;
3949+ void *puser;
3950+};
3951+
3952+struct dbCommon;
3953+struct dbFldDes;
3954+
3955+epicsShareFunc void dbChannelInit (void);
3956+epicsShareFunc long dbChannelTest(const char *name);
3957+epicsShareFunc dbChannel * dbChannelCreate(const char *name);
3958+epicsShareFunc long dbChannelOpen(dbChannel *chan);
3959+epicsShareFunc const char * dbChannelName(dbChannel *chan);
3960+epicsShareFunc struct dbCommon * dbChannelRecord(dbChannel *chan);
3961+epicsShareFunc struct dbFldDes * dbChannelFldDes(dbChannel *chan);
3962+epicsShareFunc long dbChannelElements(dbChannel *chan);
3963+epicsShareFunc short dbChannelFieldType(dbChannel *chan);
3964+epicsShareFunc short dbChannelExportType(dbChannel *chan);
3965+epicsShareFunc short dbChannelFieldSize(dbChannel *chan);
3966+epicsShareFunc long dbChannelFinalElements(dbChannel *chan);
3967+epicsShareFunc short dbChannelFinalFieldType(dbChannel *chan);
3968+epicsShareFunc short dbChannelFinalExportType(dbChannel *chan);
3969+epicsShareFunc short dbChannelFinalElementSize(dbChannel *chan);
3970+epicsShareFunc short dbChannelSpecial(dbChannel *chan);
3971+epicsShareFunc void * dbChannelField(dbChannel *chan);
3972+epicsShareFunc long dbChannelGet(dbChannel *chan, short type,
3973+ void *pbuffer, long *options, long *nRequest, void *pfl);
3974+epicsShareFunc long dbChannelGetField(dbChannel *chan, short type,
3975+ void *pbuffer, long *options, long *nRequest, void *pfl);
3976+epicsShareFunc long dbChannelPut(dbChannel *chan, short type,
3977+ const void *pbuffer, long nRequest);
3978+epicsShareFunc long dbChannelPutField(dbChannel *chan, short type,
3979+ const void *pbuffer, long nRequest);
3980+epicsShareFunc void dbChannelShow(dbChannel *chan, int level,
3981+ const unsigned short indent);
3982+epicsShareFunc void dbChannelFilterShow(dbChannel *chan, int level,
3983+ const unsigned short indent);
3984+epicsShareFunc void dbChannelDelete(dbChannel *chan);
3985+
3986+epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
3987+epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
3988+epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
3989+epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);
3990+epicsShareFunc void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan);
3991+
3992+#ifdef __cplusplus
3993+}
3994+#endif
3995+
3996+#endif /* INC_dbChannel_H */
3997
3998=== modified file 'src/ioc/db/dbChannelIO.cpp'
3999--- src/ioc/db/dbChannelIO.cpp 2010-10-05 19:27:37 +0000
4000+++ src/ioc/db/dbChannelIO.cpp 2012-06-21 20:42:45 +0000
4001@@ -4,20 +4,20 @@
4002 * Copyright (c) 2002 The Regents of the University of California, as
4003 * Operator of Los Alamos National Laboratory.
4004 * EPICS BASE is distributed subject to a Software License Agreement found
4005-* in file LICENSE that is included with this distribution.
4006+* in file LICENSE that is included with this distribution.
4007 \*************************************************************************/
4008
4009-/*
4010+/*
4011 * $Revision-Id$
4012 *
4013- *
4014+ *
4015 * L O S A L A M O S
4016 * Los Alamos National Laboratory
4017 * Los Alamos, New Mexico 87545
4018- *
4019+ *
4020 * Copyright, 1986, The Regents of the University of California.
4021- *
4022- *
4023+ *
4024+ *
4025 * Author Jeffrey O. Hill
4026 * johill@lanl.gov
4027 * 505 665 1831
4028@@ -40,15 +40,12 @@
4029 #include "dbChannelIO.h"
4030 #include "dbPutNotifyBlocker.h"
4031
4032-dbChannelIO::dbChannelIO (
4033- epicsMutex & mutexIn, cacChannelNotify & notify,
4034- const dbAddr & addrIn, dbContext & serviceIO ) :
4035- cacChannel ( notify ), mutex ( mutexIn ), serviceIO ( serviceIO ),
4036- addr ( addrIn )
4037+dbChannelIO::dbChannelIO (
4038+ epicsMutex & mutexIn, cacChannelNotify & notify,
4039+ dbChannel * dbchIn, dbContext & serviceIO ) :
4040+ cacChannel ( notify ), mutex ( mutexIn ), serviceIO ( serviceIO ),
4041+ dbch ( dbchIn )
4042 {
4043- unsigned bufLen = dbNameSizeOfPV ( & this->addr ) + 1;
4044- this->pNameStr.reset ( new char [ bufLen ] );
4045- dbNameOfPV ( & this->addr, this->pNameStr.get (), bufLen );
4046 }
4047
4048 void dbChannelIO::initiateConnect ( epicsGuard < epicsMutex > & guard )
4049@@ -57,7 +54,7 @@
4050 this->notify().connectNotify ( guard );
4051 }
4052
4053-dbChannelIO::~dbChannelIO ()
4054+dbChannelIO::~dbChannelIO ()
4055 {
4056 }
4057
4058@@ -65,48 +62,49 @@
4059 {
4060 guard.assertIdenticalMutex ( this->mutex );
4061 this->serviceIO.destroyAllIO ( guard, *this );
4062+ dbChannelDelete ( this->dbch );
4063 this->~dbChannelIO ();
4064 }
4065
4066-void dbChannelIO::destroy (
4067+void dbChannelIO::destroy (
4068 epicsGuard < epicsMutex > & guard )
4069 {
4070 guard.assertIdenticalMutex ( this->mutex );
4071 this->serviceIO.destroyChannel ( guard, *this );
4072- // dont access this pointer after above call because
4073- // object nolonger exists
4074+ // don't access this pointer after above call because
4075+ // object no longer exists
4076 }
4077
4078-cacChannel::ioStatus dbChannelIO::read (
4079- epicsGuard < epicsMutex > & guard, unsigned type,
4080- unsigned long count, cacReadNotify & notify, ioid * )
4081+cacChannel::ioStatus dbChannelIO::read (
4082+ epicsGuard < epicsMutex > & guard, unsigned type,
4083+ unsigned long count, cacReadNotify & notify, ioid * )
4084 {
4085 guard.assertIdenticalMutex ( this->mutex );
4086- this->serviceIO.callReadNotify ( guard, this->addr,
4087+ this->serviceIO.callReadNotify ( guard, this->dbch,
4088 type, count, notify );
4089 return iosSynch;
4090 }
4091
4092-void dbChannelIO::write (
4093- epicsGuard < epicsMutex > & guard, unsigned type,
4094+void dbChannelIO::write (
4095+ epicsGuard < epicsMutex > & guard, unsigned type,
4096 unsigned long count, const void *pValue )
4097 {
4098 epicsGuardRelease < epicsMutex > unguard ( guard );
4099 if ( count > LONG_MAX ) {
4100 throw outOfBounds();
4101 }
4102- int status = db_put_field ( &this->addr, type, pValue,
4103+ int status = dbChannel_put ( this->dbch, type, pValue,
4104 static_cast <long> (count) );
4105 if ( status ) {
4106- throw std::logic_error (
4107+ throw std::logic_error (
4108 "db_put_field() completed unsuccessfully" );
4109 }
4110 }
4111
4112-cacChannel::ioStatus dbChannelIO::write (
4113- epicsGuard < epicsMutex > & guard, unsigned type,
4114- unsigned long count, const void * pValue,
4115- cacWriteNotify & notify, ioid * pId )
4116+cacChannel::ioStatus dbChannelIO::write (
4117+ epicsGuard < epicsMutex > & guard, unsigned type,
4118+ unsigned long count, const void * pValue,
4119+ cacWriteNotify & notify, ioid * pId )
4120 {
4121 guard.assertIdenticalMutex ( this->mutex );
4122
4123@@ -114,24 +112,24 @@
4124 throw outOfBounds();
4125 }
4126
4127- this->serviceIO.initiatePutNotify (
4128- guard, *this, this->addr,
4129+ this->serviceIO.initiatePutNotify (
4130+ guard, *this, this->dbch,
4131 type, count, pValue, notify, pId );
4132
4133 return iosAsynch;
4134 }
4135
4136-void dbChannelIO::subscribe (
4137- epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
4138- unsigned mask, cacStateNotify & notify, ioid * pId )
4139-{
4140+void dbChannelIO::subscribe (
4141+ epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
4142+ unsigned mask, cacStateNotify & notify, ioid * pId )
4143+{
4144 guard.assertIdenticalMutex ( this->mutex );
4145- this->serviceIO.subscribe (
4146- guard, this->addr, *this,
4147+ this->serviceIO.subscribe (
4148+ guard, this->dbch, *this,
4149 type, count, mask, notify, pId );
4150 }
4151
4152-void dbChannelIO::ioCancel (
4153+void dbChannelIO::ioCancel (
4154 epicsGuard < epicsMutex > & mutualExclusionGuard,
4155 const ioid & id )
4156 {
4157@@ -139,7 +137,7 @@
4158 this->serviceIO.ioCancel ( mutualExclusionGuard, *this, id );
4159 }
4160
4161-void dbChannelIO::ioShow (
4162+void dbChannelIO::ioShow (
4163 epicsGuard < epicsMutex > & guard,
4164 const ioid & id, unsigned level ) const
4165 {
4166@@ -147,31 +145,35 @@
4167 this->serviceIO.ioShow ( guard, id, level );
4168 }
4169
4170-void dbChannelIO::show (
4171+void dbChannelIO::show (
4172 epicsGuard < epicsMutex > & guard, unsigned level ) const
4173 {
4174 guard.assertIdenticalMutex ( this->mutex );
4175
4176- printf ("channel at %p attached to local database record %s\n",
4177- static_cast <const void *> ( this ), this->addr.precord->name );
4178+ printf ("channel at %p attached to local database record %s\n",
4179+ static_cast <const void *> ( this ),
4180+ dbChannelRecord ( this->dbch ) -> name );
4181
4182 if ( level > 0u ) {
4183- printf ( "\ttype %s, element count %li, field at %p\n",
4184- dbf_type_to_text ( this->addr.dbr_field_type ), this->addr.no_elements,
4185- this->addr.pfield );
4186- }
4187- if ( level > 1u ) {
4188- this->serviceIO.show ( level - 2u );
4189- this->serviceIO.showAllIO ( *this, level - 2u );
4190+ printf ( " type %s, element count %li, field at %p\n",
4191+ dbf_type_to_text ( dbChannelExportType ( this->dbch ) ),
4192+ dbChannelElements ( this->dbch ),
4193+ dbChannelField ( this->dbch ) );
4194+ if ( level > 1u ) {
4195+ dbChannelFilterShow ( this->dbch, level - 2u, 8 );
4196+ this->serviceIO.show ( level - 2u );
4197+ this->serviceIO.showAllIO ( *this, level - 2u );
4198+ }
4199 }
4200 }
4201
4202 unsigned long dbChannelIO::nativeElementCount (
4203- epicsGuard < epicsMutex > & guard ) const
4204+ epicsGuard < epicsMutex > & guard ) const
4205 {
4206 guard.assertIdenticalMutex ( this->mutex );
4207- if ( this->addr.no_elements >= 0u ) {
4208- return static_cast < unsigned long > ( this->addr.no_elements );
4209+ long elements = dbChannelElements ( this->dbch );
4210+ if ( elements >= 0u ) {
4211+ return static_cast < unsigned long > ( elements );
4212 }
4213 return 0u;
4214 }
4215@@ -181,24 +183,30 @@
4216 epicsGuard < epicsMutex > & guard ) const throw ()
4217 {
4218 guard.assertIdenticalMutex ( this->mutex );
4219- return this->pNameStr.get ();
4220+ return dbChannelName ( this->dbch );
4221 }
4222
4223 unsigned dbChannelIO::getName (
4224 epicsGuard < epicsMutex > &,
4225 char * pBuf, unsigned bufLen ) const throw ()
4226 {
4227- return dbNameOfPV ( & this->addr, pBuf, bufLen );
4228+ const char *name = dbChannelName ( this->dbch );
4229+ size_t len = strlen ( name );
4230+ strncpy ( pBuf, name, bufLen );
4231+ if (len < bufLen)
4232+ return len;
4233+ pBuf[--bufLen] = '\0';
4234+ return bufLen;
4235 }
4236
4237 short dbChannelIO::nativeType (
4238- epicsGuard < epicsMutex > & guard ) const
4239+ epicsGuard < epicsMutex > & guard ) const
4240 {
4241 guard.assertIdenticalMutex ( this->mutex );
4242- return this->addr.dbr_field_type;
4243+ return dbChannelExportType( this->dbch );
4244 }
4245
4246-void * dbChannelIO::operator new ( size_t size,
4247+void * dbChannelIO::operator new ( size_t size,
4248 tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
4249 {
4250 return freeList.allocate ( size );
4251@@ -212,7 +220,7 @@
4252 }
4253
4254 #ifdef CXX_PLACEMENT_DELETE
4255-void dbChannelIO::operator delete ( void *pCadaver,
4256+void dbChannelIO::operator delete ( void *pCadaver,
4257 tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
4258 {
4259 freeList.release ( pCadaver );
4260
4261=== modified file 'src/ioc/db/dbChannelIO.h'
4262--- src/ioc/db/dbChannelIO.h 2010-10-05 19:27:37 +0000
4263+++ src/ioc/db/dbChannelIO.h 2012-06-21 20:42:45 +0000
4264@@ -5,7 +5,7 @@
4265 * Operator of Los Alamos National Laboratory.
4266 * EPICS BASE Versions 3.13.7
4267 * and higher are distributed subject to a Software License Agreement found
4268-* in file LICENSE that is included with this distribution.
4269+* in file LICENSE that is included with this distribution.
4270 \*************************************************************************/
4271
4272 /*
4273@@ -44,65 +44,64 @@
4274
4275 class dbChannelIO : public cacChannel, public dbContextPrivateListOfIO {
4276 public:
4277- dbChannelIO (
4278- epicsMutex &, cacChannelNotify &,
4279- const dbAddr &, dbContext & );
4280- void destructor (
4281+ dbChannelIO (
4282+ epicsMutex &, cacChannelNotify &,
4283+ dbChannel *, dbContext & );
4284+ void destructor (
4285 epicsGuard < epicsMutex > & );
4286 void destroy (
4287 epicsGuard < epicsMutex > & mutualExclusionGuard );
4288- void callReadNotify (
4289- epicsGuard < epicsMutex > &,
4290- unsigned type, unsigned long count,
4291+ void callReadNotify (
4292+ epicsGuard < epicsMutex > &,
4293+ unsigned type, unsigned long count,
4294 cacReadNotify & notify );
4295- void callStateNotify (
4296- unsigned type, unsigned long count,
4297+ void callStateNotify (
4298+ unsigned type, unsigned long count,
4299 const struct db_field_log * pfl, cacStateNotify & notify );
4300- void show (
4301+ void show (
4302 epicsGuard < epicsMutex > &, unsigned level ) const;
4303 unsigned getName (
4304 epicsGuard < epicsMutex > &,
4305 char * pBuf, unsigned bufLen ) const throw ();
4306 const char * pName (
4307 epicsGuard < epicsMutex > & ) const throw ();
4308- void * operator new ( size_t size,
4309+ void * operator new ( size_t size,
4310 tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & );
4311- epicsPlacementDeleteOperator (( void *,
4312+ epicsPlacementDeleteOperator (( void *,
4313 tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & ))
4314 protected:
4315 ~dbChannelIO ();
4316 private:
4317 epicsMutex & mutex;
4318 dbContext & serviceIO;
4319- dbAddr addr;
4320- epics_auto_ptr < char, eapt_array > pNameStr;
4321+ dbChannel * dbch;
4322
4323 void initiateConnect (
4324 epicsGuard < epicsMutex > & );
4325- unsigned requestMessageBytesPending (
4326- epicsGuard < epicsMutex > & );
4327- void flush (
4328- epicsGuard < epicsMutex > & );
4329- ioStatus read (
4330+ unsigned requestMessageBytesPending (
4331+ epicsGuard < epicsMutex > & );
4332+ void flush (
4333+ epicsGuard < epicsMutex > & );
4334+ ioStatus read (
4335 epicsGuard < epicsMutex > &,
4336- unsigned type, unsigned long count,
4337+ unsigned type, unsigned long count,
4338 cacReadNotify &, ioid * );
4339- void write (
4340+ void write (
4341 epicsGuard < epicsMutex > &,
4342- unsigned type, unsigned long count,
4343+ unsigned type, unsigned long count,
4344 const void * pvalue );
4345- ioStatus write (
4346+ ioStatus write (
4347 epicsGuard < epicsMutex > &,
4348- unsigned type, unsigned long count,
4349+ unsigned type, unsigned long count,
4350 const void * pvalue, cacWriteNotify &, ioid * );
4351- void subscribe (
4352+ void subscribe (
4353 epicsGuard < epicsMutex > &,
4354- unsigned type, unsigned long count,
4355+ unsigned type, unsigned long count,
4356 unsigned mask, cacStateNotify &notify, ioid * );
4357- void ioCancel (
4358+ void ioCancel (
4359 epicsGuard < epicsMutex > & mutualExclusionGuard,
4360 const ioid & );
4361- void ioShow (
4362+ void ioShow (
4363 epicsGuard < epicsMutex > &,
4364 const ioid &, unsigned level ) const;
4365 short nativeType (
4366@@ -115,18 +114,18 @@
4367 void operator delete ( void * );
4368 };
4369
4370-inline void dbChannelIO::callReadNotify (
4371- epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
4372+inline void dbChannelIO::callReadNotify (
4373+ epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
4374 cacReadNotify & notify )
4375 {
4376 guard.assertIdenticalMutex ( this->mutex );
4377- this->serviceIO.callReadNotify ( guard, this->addr, type, count, notify );
4378+ this->serviceIO.callReadNotify ( guard, this->dbch, type, count, notify );
4379 }
4380
4381-inline void dbChannelIO::callStateNotify ( unsigned type, unsigned long count,
4382+inline void dbChannelIO::callStateNotify ( unsigned type, unsigned long count,
4383 const struct db_field_log *pfl, cacStateNotify &notify )
4384 {
4385- this->serviceIO.callStateNotify ( this->addr, type, count, pfl, notify );
4386+ this->serviceIO.callStateNotify ( this->dbch, type, count, pfl, notify );
4387 }
4388
4389
4390
4391=== modified file 'src/ioc/db/dbContext.cpp'
4392--- src/ioc/db/dbContext.cpp 2010-10-05 19:27:37 +0000
4393+++ src/ioc/db/dbContext.cpp 2012-06-21 20:42:45 +0000
4394@@ -4,19 +4,19 @@
4395 * Copyright (c) 2002 The Regents of the University of California, as
4396 * Operator of Los Alamos National Laboratory.
4397 * EPICS BASE is distributed subject to a Software License Agreement found
4398-* in file LICENSE that is included with this distribution.
4399+* in file LICENSE that is included with this distribution.
4400 \*************************************************************************/
4401-/*
4402+/*
4403 * $Revision-Id$
4404 *
4405- *
4406+ *
4407 * L O S A L A M O S
4408 * Los Alamos National Laboratory
4409 * Los Alamos, New Mexico 87545
4410- *
4411+ *
4412 * Copyright, 1986, The Regents of the University of California.
4413- *
4414- *
4415+ *
4416+ *
4417 * Author Jeffrey O. Hill
4418 * johill@lanl.gov
4419 * 505 665 1831
4420@@ -33,6 +33,7 @@
4421 #include "epicsEvent.h"
4422 #include "epicsThread.h"
4423 #include "errlog.h"
4424+#include "dbChannel.h"
4425
4426 #define epicsExportSharedSymbols
4427 #include "db_access_routines.h"
4428@@ -43,20 +44,20 @@
4429 class dbService : public cacService {
4430 public:
4431 ~dbService () {}
4432- cacContext & contextCreate (
4433- epicsMutex & mutualExclusion,
4434- epicsMutex & callbackControl,
4435+ cacContext & contextCreate (
4436+ epicsMutex & mutualExclusion,
4437+ epicsMutex & callbackControl,
4438 cacContextNotify & );
4439 };
4440
4441 static dbService dbs;
4442
4443-cacContext & dbService::contextCreate (
4444- epicsMutex & mutualExclusion,
4445- epicsMutex & callbackControl,
4446+cacContext & dbService::contextCreate (
4447+ epicsMutex & mutualExclusion,
4448+ epicsMutex & callbackControl,
4449 cacContextNotify & notify )
4450 {
4451- return * new dbContext ( callbackControl,
4452+ return * new dbContext ( callbackControl,
4453 mutualExclusion, notify );
4454 }
4455
4456@@ -67,9 +68,9 @@
4457
4458 dbBaseIO::dbBaseIO () {}
4459
4460-dbContext::dbContext ( epicsMutex & cbMutexIn,
4461+dbContext::dbContext ( epicsMutex & cbMutexIn,
4462 epicsMutex & mutexIn, cacContextNotify & notifyIn ) :
4463- readNotifyCache ( mutexIn ), ctx ( 0 ),
4464+ readNotifyCache ( mutexIn ), ctx ( 0 ),
4465 stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), cbMutex ( cbMutexIn ),
4466 notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 )
4467 {
4468@@ -84,41 +85,41 @@
4469 }
4470
4471 cacChannel & dbContext::createChannel ( // X aCC 361
4472- epicsGuard < epicsMutex > & guard, const char * pName,
4473+ epicsGuard < epicsMutex > & guard, const char * pName,
4474 cacChannelNotify & notifyIn, cacChannel::priLev priority )
4475 {
4476 guard.assertIdenticalMutex ( this->mutex );
4477
4478- struct dbAddr addr;
4479- int status;
4480- {
4481- // dont know if the database might call a put callback
4482- // while holding its lock ...
4483- epicsGuardRelease < epicsMutex > unguard ( guard );
4484- status = db_name_to_addr ( pName, & addr );
4485- }
4486- if ( status ) {
4487+ dbChannel *dbch = dbChannel_create ( pName );
4488+ if ( ! dbch ) {
4489 if ( ! this->pNetContext.get() ) {
4490 this->pNetContext.reset (
4491- & this->notify.createNetworkContext (
4492+ & this->notify.createNetworkContext (
4493 this->mutex, this->cbMutex ) );
4494 }
4495 return this->pNetContext->createChannel (
4496 guard, pName, notifyIn, priority );
4497 }
4498- else if ( ca_preemtive_callback_is_enabled () ) {
4499- return * new ( this->dbChannelIOFreeList )
4500- dbChannelIO ( this->mutex, notifyIn, addr, *this );
4501- }
4502- else {
4503- errlogPrintf (
4504+
4505+ if ( ! ca_preemtive_callback_is_enabled () ) {
4506+ dbChannelDelete ( dbch );
4507+ errlogPrintf (
4508 "dbContext: preemptive callback required for direct in\n"
4509 "memory interfacing of CA channels to the DB.\n" );
4510 throw cacChannel::unsupportedByService ();
4511 }
4512+
4513+ try {
4514+ return * new ( this->dbChannelIOFreeList )
4515+ dbChannelIO ( this->mutex, notifyIn, dbch, *this );
4516+ }
4517+ catch (...) {
4518+ dbChannelDelete ( dbch );
4519+ throw;
4520+ }
4521 }
4522
4523-void dbContext::destroyChannel (
4524+void dbContext::destroyChannel (
4525 epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
4526 {
4527 guard.assertIdenticalMutex ( this->mutex );
4528@@ -134,30 +135,30 @@
4529 this->dbChannelIOFreeList.release ( & chan );
4530 }
4531
4532-void dbContext::callStateNotify ( struct dbAddr & addr,
4533- unsigned type, unsigned long count,
4534- const struct db_field_log * pfl,
4535+void dbContext::callStateNotify ( struct dbChannel * dbch,
4536+ unsigned type, unsigned long count,
4537+ const struct db_field_log * pfl,
4538 cacStateNotify & notifyIn )
4539 {
4540 unsigned long size = dbr_size_n ( type, count );
4541
4542 if ( type > INT_MAX ) {
4543 epicsGuard < epicsMutex > guard ( this->mutex );
4544- notifyIn.exception ( guard, ECA_BADTYPE,
4545- "type code out of range (high side)",
4546+ notifyIn.exception ( guard, ECA_BADTYPE,
4547+ "type code out of range (high side)",
4548 type, count );
4549 return;
4550 }
4551
4552 if ( count > INT_MAX ) {
4553 epicsGuard < epicsMutex > guard ( this->mutex );
4554- notifyIn.exception ( guard, ECA_BADCOUNT,
4555+ notifyIn.exception ( guard, ECA_BADCOUNT,
4556 "element count out of range (high side)",
4557 type, count);
4558 return;
4559 }
4560
4561- // no need to lock this because state notify is
4562+ // no need to lock this because state notify is
4563 // called from only one event queue consumer thread
4564 if ( this->stateNotifyCacheSize < size) {
4565 char * pTmp = new char [size];
4566@@ -166,14 +167,14 @@
4567 this->stateNotifyCacheSize = size;
4568 }
4569 void *pvfl = (void *) pfl;
4570- int status = db_get_field ( &addr, static_cast <int> ( type ),
4571+ int status = dbChannel_get ( dbch, static_cast <int> ( type ),
4572 this->pStateNotifyCache, static_cast <int> ( count ), pvfl );
4573 if ( status ) {
4574 epicsGuard < epicsMutex > guard ( this->mutex );
4575- notifyIn.exception ( guard, ECA_GETFAIL,
4576- "db_get_field() completed unsuccessfuly", type, count );
4577+ notifyIn.exception ( guard, ECA_GETFAIL,
4578+ "dbChannel_get() completed unsuccessfully", type, count );
4579 }
4580- else {
4581+ else {
4582 epicsGuard < epicsMutex > guard ( this->mutex );
4583 notifyIn.current ( guard, type, count, this->pStateNotifyCache );
4584 }
4585@@ -185,10 +186,10 @@
4586 assert ( status == ECA_NORMAL );
4587 }
4588
4589-void dbContext::subscribe (
4590+void dbContext::subscribe (
4591 epicsGuard < epicsMutex > & guard,
4592- struct dbAddr & addr, dbChannelIO & chan,
4593- unsigned type, unsigned long count, unsigned mask,
4594+ struct dbChannel * dbch, dbChannelIO & chan,
4595+ unsigned type, unsigned long count, unsigned mask,
4596 cacStateNotify & notifyIn, cacChannel::ioid * pId )
4597 {
4598 guard.assertIdenticalMutex ( this->mutex );
4599@@ -214,12 +215,12 @@
4600
4601 unsigned selfPriority = epicsThreadGetPrioritySelf ();
4602 unsigned above;
4603- epicsThreadBooleanStatus tbs =
4604+ epicsThreadBooleanStatus tbs =
4605 epicsThreadLowestPriorityLevelAbove ( selfPriority, &above );
4606 if ( tbs != epicsThreadBooleanStatusSuccess ) {
4607 above = selfPriority;
4608 }
4609- int status = db_start_events ( tmpctx, "CAC-event",
4610+ int status = db_start_events ( tmpctx, "CAC-event",
4611 cacAttachClientCtx, ca_current_context (), above );
4612 if ( status ) {
4613 db_close_events ( tmpctx );
4614@@ -227,7 +228,7 @@
4615 }
4616 }
4617 if ( this->ctx ) {
4618- // another thread tried to simultaneously setup
4619+ // another thread tried to simultaneously setup
4620 // the event system
4621 db_close_events ( tmpctx );
4622 }
4623@@ -237,9 +238,9 @@
4624 }
4625
4626 dbSubscriptionIO & subscr =
4627- * new ( this->dbSubscriptionIOFreeList )
4628- dbSubscriptionIO ( guard, this->mutex, *this, chan,
4629- addr, notifyIn, type, count, mask, this->ctx );
4630+ * new ( this->dbSubscriptionIOFreeList )
4631+ dbSubscriptionIO ( guard, this->mutex, *this, chan,
4632+ dbch, notifyIn, type, count, mask, this->ctx );
4633 chan.dbContextPrivateListOfIO::eventq.add ( subscr );
4634 this->ioTable.idAssignAdd ( subscr );
4635
4636@@ -248,27 +249,27 @@
4637 }
4638 }
4639
4640-void dbContext::initiatePutNotify (
4641+void dbContext::initiatePutNotify (
4642 epicsGuard < epicsMutex > & guard,
4643- dbChannelIO & chan, struct dbAddr & addr,
4644- unsigned type, unsigned long count, const void * pValue,
4645+ dbChannelIO & chan, struct dbChannel * dbch,
4646+ unsigned type, unsigned long count, const void * pValue,
4647 cacWriteNotify & notifyIn, cacChannel::ioid * pId )
4648 {
4649 guard.assertIdenticalMutex ( this->mutex );
4650 if ( ! chan.dbContextPrivateListOfIO::pBlocker ) {
4651- chan.dbContextPrivateListOfIO::pBlocker =
4652- new ( this->dbPutNotifyBlockerFreeList )
4653+ chan.dbContextPrivateListOfIO::pBlocker =
4654+ new ( this->dbPutNotifyBlockerFreeList )
4655 dbPutNotifyBlocker ( this->mutex );
4656 this->ioTable.idAssignAdd ( *chan.dbContextPrivateListOfIO::pBlocker );
4657 }
4658- chan.dbContextPrivateListOfIO::pBlocker->initiatePutNotify (
4659- guard, notifyIn, addr, type, count, pValue );
4660+ chan.dbContextPrivateListOfIO::pBlocker->initiatePutNotify (
4661+ guard, notifyIn, dbch, type, count, pValue );
4662 if ( pId ) {
4663 *pId = chan.dbContextPrivateListOfIO::pBlocker->getId ();
4664 }
4665 }
4666
4667-void dbContext::destroyAllIO (
4668+void dbContext::destroyAllIO (
4669 epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
4670 {
4671 guard.assertIdenticalMutex ( this->mutex );
4672@@ -284,7 +285,7 @@
4673 }
4674
4675 while ( ( pIO = tmp.get() ) ) {
4676- // This prevents a db event callback from coming
4677+ // This prevents a db event callback from coming
4678 // through after the notify IO is deleted
4679 pIO->unsubscribe ( guard );
4680 // If they call ioCancel() here it will be ignored
4681@@ -301,8 +302,8 @@
4682 }
4683 }
4684
4685-void dbContext::ioCancel (
4686- epicsGuard < epicsMutex > & guard, dbChannelIO & chan,
4687+void dbContext::ioCancel (
4688+ epicsGuard < epicsMutex > & guard, dbChannelIO & chan,
4689 const cacChannel::ioid &id )
4690 {
4691 guard.assertIdenticalMutex ( this->mutex );
4692@@ -325,8 +326,8 @@
4693 }
4694 }
4695
4696-void dbContext::ioShow (
4697- epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id,
4698+void dbContext::ioShow (
4699+ epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id,
4700 unsigned level ) const
4701 {
4702 guard.assertIdenticalMutex ( this->mutex );
4703@@ -339,7 +340,7 @@
4704 void dbContext::showAllIO ( const dbChannelIO & chan, unsigned level ) const
4705 {
4706 epicsGuard < epicsMutex > guard ( this->mutex );
4707- tsDLIterConst < dbSubscriptionIO > pItem =
4708+ tsDLIterConst < dbSubscriptionIO > pItem =
4709 chan.dbContextPrivateListOfIO::eventq.firstIter ();
4710 while ( pItem.valid () ) {
4711 pItem->show ( guard, level );
4712@@ -356,14 +357,14 @@
4713 this->show ( guard, level );
4714 }
4715
4716-void dbContext::show (
4717+void dbContext::show (
4718 epicsGuard < epicsMutex > & guard, unsigned level ) const
4719 {
4720 guard.assertIdenticalMutex ( this->mutex );
4721- printf ( "dbContext at %p\n",
4722+ printf ( "dbContext at %p\n",
4723 static_cast <const void *> ( this ) );
4724 if ( level > 0u ) {
4725- printf ( "\tevent call back cache location %p, and its size %lu\n",
4726+ printf ( "\tevent call back cache location %p, and its size %lu\n",
4727 static_cast <void *> ( this->pStateNotifyCache ), this->stateNotifyCacheSize );
4728 this->readNotifyCache.show ( guard, level - 1 );
4729 }
4730@@ -375,7 +376,7 @@
4731 }
4732 }
4733
4734-void dbContext::flush (
4735+void dbContext::flush (
4736 epicsGuard < epicsMutex > & guard )
4737 {
4738 guard.assertIdenticalMutex ( this->mutex );
4739
4740=== modified file 'src/ioc/db/dbContextReadNotifyCache.cpp'
4741--- src/ioc/db/dbContextReadNotifyCache.cpp 2010-10-05 19:27:37 +0000
4742+++ src/ioc/db/dbContextReadNotifyCache.cpp 2012-06-21 20:42:45 +0000
4743@@ -5,7 +5,7 @@
4744 * Operator of Los Alamos National Laboratory.
4745 * EPICS BASE Versions 3.13.7
4746 * and higher are distributed subject to a Software License Agreement found
4747-* in file LICENSE that is included with this distribution.
4748+* in file LICENSE that is included with this distribution.
4749 \*************************************************************************/
4750
4751 /*
4752@@ -30,11 +30,11 @@
4753
4754 class privateAutoDestroyPtr {
4755 public:
4756- privateAutoDestroyPtr (
4757+ privateAutoDestroyPtr (
4758 dbContextReadNotifyCacheAllocator & allocator, unsigned long size ) :
4759 _allocator ( allocator ), _p ( allocator.alloc ( size ) ) {}
4760 ~privateAutoDestroyPtr () { _allocator.free ( _p ); }
4761- char * get () const { return _p; }
4762+ char * get () const { return _p; }
4763 private:
4764 dbContextReadNotifyCacheAllocator & _allocator;
4765 char * _p;
4766@@ -43,28 +43,28 @@
4767 };
4768
4769 // extra effort taken here to not hold the lock when calling the callback
4770-void dbContextReadNotifyCache::callReadNotify (
4771- epicsGuard < epicsMutex > & guard, struct dbAddr & addr,
4772+void dbContextReadNotifyCache::callReadNotify (
4773+ epicsGuard < epicsMutex > & guard, struct dbChannel * dbch,
4774 unsigned type, unsigned long count, cacReadNotify & notify )
4775 {
4776 guard.assertIdenticalMutex ( _mutex );
4777
4778 if ( type > INT_MAX ) {
4779- notify.exception ( guard, ECA_BADTYPE,
4780- "type code out of range (high side)",
4781+ notify.exception ( guard, ECA_BADTYPE,
4782+ "type code out of range (high side)",
4783 type, count );
4784 return;
4785 }
4786
4787- if ( addr.no_elements < 0 ) {
4788- notify.exception ( guard, ECA_BADCOUNT,
4789+ if ( dbChannelElements(dbch) < 0 ) {
4790+ notify.exception ( guard, ECA_BADCOUNT,
4791 "database has negetive element count",
4792 type, count);
4793 return;
4794 }
4795
4796- if ( count > static_cast < unsigned > ( addr.no_elements ) ) {
4797- notify.exception ( guard, ECA_BADCOUNT,
4798+ if ( count > static_cast < unsigned long > ( dbChannelElements(dbch) ) ) {
4799+ notify.exception ( guard, ECA_BADCOUNT,
4800 "element count out of range (high side)",
4801 type, count);
4802 return;
4803@@ -75,21 +75,21 @@
4804 int status;
4805 {
4806 epicsGuardRelease < epicsMutex > unguard ( guard );
4807- status = db_get_field ( &addr, static_cast <int> ( type ),
4808- ptr.get (), static_cast <int> ( count ), 0 );
4809+ status = dbChannel_get ( dbch, static_cast <int> ( type ),
4810+ ptr.get (), static_cast <long> ( count ), 0 );
4811 }
4812 if ( status ) {
4813- notify.exception ( guard, ECA_GETFAIL,
4814+ notify.exception ( guard, ECA_GETFAIL,
4815 "db_get_field() completed unsuccessfuly",
4816 type, count );
4817 }
4818- else {
4819- notify.completion (
4820+ else {
4821+ notify.completion (
4822 guard, type, count, ptr.get () );
4823 }
4824 }
4825
4826-void dbContextReadNotifyCache::show (
4827+void dbContextReadNotifyCache::show (
4828 epicsGuard < epicsMutex > & guard, unsigned level ) const
4829 {
4830 guard.assertIdenticalMutex ( _mutex );
4831@@ -155,8 +155,8 @@
4832 pNext = _pReadNotifyCache->pNext;
4833 count++;
4834 }
4835- printf ( "\tcount %lu and size %lu\n",
4836- static_cast < unsigned long > ( count ),
4837+ printf ( "\tcount %lu and size %lu\n",
4838+ static_cast < unsigned long > ( count ),
4839 _readNotifyCacheSize );
4840 }
4841 }
4842
4843=== modified file 'src/ioc/db/dbEvent.c'
4844--- src/ioc/db/dbEvent.c 2011-10-19 18:07:00 +0000
4845+++ src/ioc/db/dbEvent.c 2012-06-21 20:42:45 +0000
4846@@ -1,19 +1,20 @@
4847 /*************************************************************************\
4848+* Copyright (c) 2010 Brookhaven National Laboratory.
4849+* Copyright (c) 2010 Helmholtz-Zentrum Berlin
4850+* fuer Materialien und Energie GmbH.
4851 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
4852 * National Laboratory.
4853 * Copyright (c) 2002 The Regents of the University of California, as
4854 * Operator of Los Alamos National Laboratory.
4855-* EPICS BASE Versions 3.13.7
4856-* and higher are distributed subject to a Software License Agreement found
4857-* in file LICENSE that is included with this distribution.
4858+* EPICS BASE is distributed subject to a Software License Agreement found
4859+* in file LICENSE that is included with this distribution.
4860 \*************************************************************************/
4861-/* dbEvent.c */
4862-/* $Revision-Id$ */
4863-/* routines for scheduling events to lower priority tasks via the RT kernel */
4864+
4865 /*
4866- * Author: Jeffrey O. Hill
4867- * Date: 4-1-89
4868-*/
4869+ * Author: Jeffrey O. Hill <johill@lanl.gov>
4870+ *
4871+ * Ralph Lange <Ralph.Lange@bessy.de>
4872+ */
4873
4874 #include <stddef.h>
4875 #include <stdlib.h>
4876@@ -39,6 +40,7 @@
4877 #include "db_field_log.h"
4878 #define epicsExportSharedSymbols
4879 #include "dbAddr.h"
4880+#include "dbChannel.h"
4881 #include "dbLock.h"
4882 #include "dbAccessDefs.h"
4883 #include "dbEvent.h"
4884@@ -49,51 +51,33 @@
4885 #define EVENTQEMPTY ((struct evSubscrip *)NULL)
4886
4887 /*
4888- * event subscruiption
4889- */
4890-struct evSubscrip {
4891- ELLNODE node;
4892- struct dbAddr *paddr;
4893- EVENTFUNC *user_sub;
4894- void *user_arg;
4895- struct event_que *ev_que;
4896- db_field_log *pLastLog;
4897- unsigned long npend; /* n times this event is on the queue */
4898- unsigned long nreplace; /* n times replacing event on the queue */
4899- unsigned char select;
4900- char valque;
4901- char callBackInProgress;
4902- char enabled;
4903-};
4904-
4905-/*
4906 * really a ring buffer
4907 */
4908 struct event_que {
4909 /* lock writers to the ring buffer only */
4910 /* readers must never slow up writers */
4911 epicsMutexId writelock;
4912- db_field_log valque[EVENTQUESIZE];
4913+ db_field_log *valque[EVENTQUESIZE];
4914 struct evSubscrip *evque[EVENTQUESIZE];
4915 struct event_que *nextque; /* in case que quota exceeded */
4916 struct event_user *evUser; /* event user parent struct */
4917 unsigned short putix;
4918 unsigned short getix;
4919 unsigned short quota; /* the number of assigned entries*/
4920- unsigned short nDuplicates; /* N events duplicated on this q */
4921+ unsigned short nDuplicates; /* N events duplicated on this q */
4922 unsigned short nCanceled; /* the number of canceled entries */
4923 };
4924
4925 struct event_user {
4926 struct event_que firstque; /* the first event que */
4927-
4928+
4929 epicsMutexId lock;
4930 epicsEventId ppendsem; /* Wait while empty */
4931 epicsEventId pflush_sem; /* wait for flush */
4932-
4933+
4934 EXTRALABORFUNC *extralabor_sub;/* off load to event task */
4935 void *extralabor_arg;/* parameter to above */
4936-
4937+
4938 epicsThreadId taskid; /* event handler task id */
4939 struct evSubscrip *pSuicideEvent; /* event that is deleteing itself */
4940 unsigned queovr; /* event que overflow count */
4941@@ -114,34 +98,28 @@
4942 #define RNGINC(OLD)\
4943 ( (unsigned short) ( (OLD) >= (EVENTQUESIZE-1) ? 0 : (OLD)+1 ) )
4944
4945-#define LOCKEVQUE(EV_QUE)\
4946-epicsMutexMustLock((EV_QUE)->writelock);
4947-
4948-#define UNLOCKEVQUE(EV_QUE)\
4949-epicsMutexUnlock((EV_QUE)->writelock);
4950-
4951-#define LOCKREC(RECPTR)\
4952-epicsMutexMustLock((RECPTR)->mlok);
4953-
4954-#define UNLOCKREC(RECPTR)\
4955-epicsMutexUnlock((RECPTR)->mlok);
4956+#define LOCKEVQUE(EV_QUE) epicsMutexMustLock((EV_QUE)->writelock)
4957+#define UNLOCKEVQUE(EV_QUE) epicsMutexUnlock((EV_QUE)->writelock)
4958+#define LOCKREC(RECPTR) epicsMutexMustLock((RECPTR)->mlok)
4959+#define UNLOCKREC(RECPTR) epicsMutexUnlock((RECPTR)->mlok)
4960
4961 static void *dbevEventUserFreeList;
4962 static void *dbevEventQueueFreeList;
4963-static void *dbevEventBlockFreeList;
4964+static void *dbevEventSubscriptionFreeList;
4965+static void *dbevFieldLogFreeList;
4966
4967 static char *EVENT_PEND_NAME = "eventTask";
4968
4969 static struct evSubscrip canceledEvent;
4970
4971-static unsigned short ringSpace ( const struct event_que *pevq )
4972+static unsigned short ringSpace ( const struct event_que *pevq )
4973 {
4974 if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
4975 if ( pevq->getix > pevq->putix ) {
4976 return ( unsigned short ) ( pevq->getix - pevq->putix );
4977 }
4978 else {
4979- return ( unsigned short ) ( ( EVENTQUESIZE + pevq->getix ) - pevq->putix );
4980+ return ( unsigned short ) ( ( EVENTQUESIZE + pevq->getix ) - pevq->putix );
4981 }
4982 }
4983 return 0;
4984@@ -163,7 +141,7 @@
4985 DBADDR addr;
4986 long status;
4987 struct evSubscrip *pevent;
4988- dbFldDes *pdbFldDes;
4989+ dbFldDes *pdbFldDes;
4990
4991 if ( ! pname ) return DB_EVENT_OK;
4992 status = dbNameToAddr ( pname, &addr );
4993@@ -172,7 +150,7 @@
4994 return DB_EVENT_ERROR;
4995 }
4996
4997- LOCKREC ( addr.precord );
4998+ LOCKREC (addr.precord);
4999
5000 pevent = (struct evSubscrip *) ellFirst ( &addr.precord->mlis );
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: