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