Merge ~bfrk/epics-base:write-filters into ~epics-core/epics-base/+git/epics-base:7.0

Proposed by Ben Franksen
Status: Superseded
Proposed branch: ~bfrk/epics-base:write-filters
Merge into: ~epics-core/epics-base/+git/epics-base:7.0
Diff against target: 3074 lines (+1008/-798)
27 files modified
documentation/RELEASE_NOTES.md (+9/-0)
modules/database/src/ioc/db/dbAccess.c (+467/-439)
modules/database/src/ioc/db/dbAccessDefs.h (+1/-1)
modules/database/src/ioc/db/dbChannel.c (+2/-59)
modules/database/src/ioc/db/dbChannel.h (+3/-3)
modules/database/src/ioc/db/dbDbLink.c (+86/-53)
modules/database/src/ioc/db/dbDbLink.h (+1/-1)
modules/database/src/ioc/db/dbEvent.c (+73/-40)
modules/database/src/ioc/db/dbEvent.h (+1/-0)
modules/database/src/ioc/db/dbExtractArray.c (+20/-49)
modules/database/src/ioc/db/dbExtractArray.h (+16/-5)
modules/database/src/ioc/db/dbLink.c (+1/-1)
modules/database/src/ioc/db/dbLink.h (+2/-1)
modules/database/src/ioc/db/dbLock.c (+3/-3)
modules/database/src/ioc/db/dbTest.c (+16/-16)
modules/database/src/ioc/db/dbUnitTest.c (+2/-2)
modules/database/src/ioc/db/db_field_log.h (+30/-30)
modules/database/src/std/dev/devAiSoft.c (+2/-1)
modules/database/src/std/filters/arr.c (+52/-70)
modules/database/src/std/filters/ts.c (+27/-9)
modules/database/test/ioc/db/dbChArrTest.cpp (+2/-1)
modules/database/test/std/filters/arrTest.cpp (+8/-7)
modules/database/test/std/filters/dbndTest.c (+3/-6)
modules/database/test/std/rec/Makefile (+7/-0)
modules/database/test/std/rec/linkFilterTest.c (+157/-0)
modules/database/test/std/rec/linkFilterTest.db (+16/-0)
modules/database/test/std/rec/regressTest.c (+1/-1)
Reviewer Review Type Date Requested Status
EPICS Core Developers Pending
Review via email: mp+381125@code.launchpad.net

Description of the change

This is just the initial refactor, no new features yet.

To post a comment you must log in.
Revision history for this message
Ben Franksen (bfrk) wrote :

Note that I have based this on Dirk's addition of filters for DB links.

I wonder if I should have listed Dirk's repo+branch as a requisite when creating the merge request.
Is it possible to do that after the fact or do I have to re-submit?

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

Yes, please hit the "Resubmit proposal" towards the top right of the window and enter Dirk's branch as a prerequisite. That way launchpad doesn't mix your changes in with his and we can review and comment on them separately.

Unmerged commits

13fb313... by Ben Franksen

refactor db_field_log and filters to get rid of dbfl_type_rec

This refactor simplifies and streamlines the code associated with server
side filters. Apart from immediate benefits (clearer code, less duplication)
it is also hoped that this will make it easier to add write filters.

The data pointer dbfl_ref.field can now either point to a copy owned by a
filter, or it can point to the original data owned by a record. In the
latter case, the dbfl_ref.dtor is NULL. This required adding
db_field_log.offset as a new member. It gets initialized, together with the
no_elements member, by a call to the rset.get_array_info, so we can continue
to support the wrap-around/ring-buffer feature for array fields.

It turned out that dbGetField was always called with a NULL pointer as its
db_field_log* argument, which is why I removed this parameter. This makes
sense because the extra db_field_log parameter of dbGet is an internal
implementation detail that should not affect the external API. Nowadays,
even dbGetField is no longer quite appropriate for user code, which should
rather call dbChannelGetField in order to profit from filters and long
strings (the "PV$" notation).

6aeddc3... by Ben Franksen

reformat modules/database/src/ioc/db/dbAccess.c

e2d9953... by Ben Franksen

Merge branch 'dbChannelForDBLinks' into write-filters

e419914... by Dirk Zimoch

Release notes updated

ed0b4d4... by Dirk Zimoch

set number of planned link filter tests

fc61f20... by Dirk Zimoch

removed unnecessary recGblSetSevr call

8a8de85... by Dirk Zimoch

re-order link filter tests to alternate between success and failure

1324246... by Dirk Zimoch

unused variable removed

2986080... by Dirk Zimoch

Revert "fix crash in PINI: use local db_field_log"

This reverts commit a590151accb1d187562c515a48e013244dd98a45.

Conflicts:
 modules/database/src/ioc/db/dbDbLink.c

4960efa... by Dirk Zimoch

initialize free lists when starting dbChannel

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md
index bdd2468..681495e 100644
--- a/documentation/RELEASE_NOTES.md
+++ b/documentation/RELEASE_NOTES.md
@@ -36,6 +36,15 @@ As long as all support modules and IOCs are rebuilt from source after updating
36them to use this release of EPICS Base, these changes should not have any36them to use this release of EPICS Base, these changes should not have any
37affect.37affect.
3838
39### Filters in database links
40
41Input links can now use filters, most importantly array element and sub array
42access, even if they are not channel access links.
43
44### ai Soft Channel support
45
46The Soft Channel device support for ai records now returns failure when
47fetching the INP link fails.
3948
40### logClient reliability49### logClient reliability
4150
diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c
index 19f6038..a6c31f2 100644
--- a/modules/database/src/ioc/db/dbAccess.c
+++ b/modules/database/src/ioc/db/dbAccess.c
@@ -34,7 +34,7 @@
34#include "errlog.h"34#include "errlog.h"
35#include "errMdef.h"35#include "errMdef.h"
3636
37#include "epicsExport.h" /* #define epicsExportSharedSymbols */37#include "epicsExport.h" /* #define epicsExportSharedSymbols */
38#include "caeventmask.h"38#include "caeventmask.h"
39#include "callback.h"39#include "callback.h"
40#include "dbAccessDefs.h"40#include "dbAccessDefs.h"
@@ -63,7 +63,7 @@
63#include "special.h"63#include "special.h"
6464
65epicsShareDef struct dbBase *pdbbase = 0;65epicsShareDef struct dbBase *pdbbase = 0;
66epicsShareDef volatile int interruptAccept=FALSE;66epicsShareDef volatile int interruptAccept = FALSE;
6767
68epicsShareDef int dbAccessDebugPUTF = 0;68epicsShareDef int dbAccessDebugPUTF = 0;
69epicsExportAddress(int, dbAccessDebugPUTF);69epicsExportAddress(int, dbAccessDebugPUTF);
@@ -73,24 +73,24 @@ epicsExportAddress(int, dbAccessDebugPUTF);
73epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;73epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
7474
75static short mapDBFToDBR[DBF_NTYPES] = {75static short mapDBFToDBR[DBF_NTYPES] = {
76 /* DBF_STRING => */ DBR_STRING,76 /* DBF_STRING => */ DBR_STRING,
77 /* DBF_CHAR => */ DBR_CHAR,77 /* DBF_CHAR => */ DBR_CHAR,
78 /* DBF_UCHAR => */ DBR_UCHAR,78 /* DBF_UCHAR => */ DBR_UCHAR,
79 /* DBF_SHORT => */ DBR_SHORT,79 /* DBF_SHORT => */ DBR_SHORT,
80 /* DBF_USHORT => */ DBR_USHORT,80 /* DBF_USHORT => */ DBR_USHORT,
81 /* DBF_LONG => */ DBR_LONG,81 /* DBF_LONG => */ DBR_LONG,
82 /* DBF_ULONG => */ DBR_ULONG,82 /* DBF_ULONG => */ DBR_ULONG,
83 /* DBF_INT64 => */ DBR_INT64,83 /* DBF_INT64 => */ DBR_INT64,
84 /* DBF_UINT64 => */ DBR_UINT64,84 /* DBF_UINT64 => */ DBR_UINT64,
85 /* DBF_FLOAT => */ DBR_FLOAT,85 /* DBF_FLOAT => */ DBR_FLOAT,
86 /* DBF_DOUBLE => */ DBR_DOUBLE,86 /* DBF_DOUBLE => */ DBR_DOUBLE,
87 /* DBF_ENUM, => */ DBR_ENUM,87 /* DBF_ENUM, => */ DBR_ENUM,
88 /* DBF_MENU, => */ DBR_ENUM,88 /* DBF_MENU, => */ DBR_ENUM,
89 /* DBF_DEVICE => */ DBR_ENUM,89 /* DBF_DEVICE => */ DBR_ENUM,
90 /* DBF_INLINK => */ DBR_STRING,90 /* DBF_INLINK => */ DBR_STRING,
91 /* DBF_OUTLINK => */ DBR_STRING,91 /* DBF_OUTLINK => */ DBR_STRING,
92 /* DBF_FWDLINK => */ DBR_STRING,92 /* DBF_FWDLINK => */ DBR_STRING,
93 /* DBF_NOACCESS => */ DBR_NOACCESS93 /* DBF_NOACCESS => */ DBR_NOACCESS
94};94};
9595
96/*96/*
@@ -109,217 +109,219 @@ void dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
109 spcAsCallback = func;109 spcAsCallback = func;
110}110}
111111
112long dbPutSpecial(DBADDR *paddr,int pass)112long dbPutSpecial(DBADDR *paddr, int pass)
113{113{
114 long int (*pspecial)()=NULL;114 long int (*pspecial) () = NULL;
115 rset *prset;115 rset *prset;
116 dbCommon *precord = paddr->precord;116 dbCommon *precord = paddr->precord;
117 long status=0;117 long status = 0;
118 long special=paddr->special;118 long special = paddr->special;
119119
120 prset = dbGetRset(paddr);120 prset = dbGetRset(paddr);
121 if(special<100) { /*global processing*/121 if (special < 100) { /*global processing */
122 if((special==SPC_NOMOD) && (pass==0)) {122 if ((special == SPC_NOMOD) && (pass == 0)) {
123 status = S_db_noMod;123 status = S_db_noMod;
124 recGblDbaddrError(status,paddr,"dbPut");124 recGblDbaddrError(status, paddr, "dbPut");
125 return(status);125 return (status);
126 }else if(special==SPC_SCAN){126 } else if (special == SPC_SCAN) {
127 if(pass==0)127 if (pass == 0)
128 scanDelete(precord);128 scanDelete(precord);
129 else129 else
130 scanAdd(precord);130 scanAdd(precord);
131 }else if((special==SPC_AS) && (pass==1)) {131 } else if ((special == SPC_AS) && (pass == 1)) {
132 if(spcAsCallback) (*spcAsCallback)(precord);132 if (spcAsCallback)
133 }133 (*spcAsCallback) (precord);
134 }else {134 }
135 if( prset && (pspecial = (prset->special))) {135 } else {
136 status=(*pspecial)(paddr,pass);136 if (prset && (pspecial = (prset->special))) {
137 if(status) return(status);137 status = (*pspecial) (paddr, pass);
138 } else if(pass==0){138 if (status)
139 recGblRecSupError(S_db_noSupport,paddr,"dbPut", "special");139 return (status);
140 return(S_db_noSupport);140 } else if (pass == 0) {
141 }141 recGblRecSupError(S_db_noSupport, paddr, "dbPut", "special");
142 return (S_db_noSupport);
143 }
142 }144 }
143 return(0);145 return (0);
144}146}
145147
146static void get_enum_strs(DBADDR *paddr, char **ppbuffer,148static void get_enum_strs(DBADDR *paddr, char **ppbuffer,
147 rset *prset,long *options)149 rset * prset, long *options)
148{150{
149 short field_type=paddr->field_type;151 short field_type = paddr->field_type;
150 dbFldDes *pdbFldDes = paddr->pfldDes;152 dbFldDes *pdbFldDes = paddr->pfldDes;
151 dbMenu *pdbMenu;153 dbMenu *pdbMenu;
152 dbDeviceMenu *pdbDeviceMenu;154 dbDeviceMenu *pdbDeviceMenu;
153 char **papChoice;155 char **papChoice;
154 unsigned long no_str;156 unsigned long no_str;
155 char *ptemp;157 char *ptemp;
156 struct dbr_enumStrs *pdbr_enumStrs=(struct dbr_enumStrs*)(*ppbuffer);158 struct dbr_enumStrs *pdbr_enumStrs = (struct dbr_enumStrs *)(*ppbuffer);
157 unsigned int i;159 unsigned int i;
158160
159 memset(pdbr_enumStrs,'\0',dbr_enumStrs_size);161 memset(pdbr_enumStrs, '\0', dbr_enumStrs_size);
160 switch(field_type) {162 switch (field_type) {
161 case DBF_ENUM:163 case DBF_ENUM:
162 if( prset && prset->get_enum_strs ) {164 if (prset && prset->get_enum_strs) {
163 (*prset->get_enum_strs)(paddr,pdbr_enumStrs);165 (*prset->get_enum_strs) (paddr, pdbr_enumStrs);
164 } else {166 } else {
165 *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/167 *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */
166 }168 }
167 break;169 break;
168 case DBF_MENU:170 case DBF_MENU:
169 pdbMenu = (dbMenu *)pdbFldDes->ftPvt;171 pdbMenu = (dbMenu *) pdbFldDes->ftPvt;
170 no_str = pdbMenu->nChoice;172 no_str = pdbMenu->nChoice;
171 papChoice= pdbMenu->papChoiceValue;173 papChoice = pdbMenu->papChoiceValue;
172 goto choice_common;174 goto choice_common;
173 case DBF_DEVICE:175 case DBF_DEVICE:
174 pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt;176 pdbDeviceMenu = (dbDeviceMenu *) pdbFldDes->ftPvt;
175 if(!pdbDeviceMenu) {177 if (!pdbDeviceMenu) {
176 *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/178 *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */
177 break;179 break;
178 }180 }
179 no_str = pdbDeviceMenu->nChoice;181 no_str = pdbDeviceMenu->nChoice;
180 papChoice = pdbDeviceMenu->papChoice;182 papChoice = pdbDeviceMenu->papChoice;
181 goto choice_common;183 goto choice_common;
182choice_common:184 choice_common:
183 i = sizeof(pdbr_enumStrs->strs)/185 i = sizeof(pdbr_enumStrs->strs) / sizeof(pdbr_enumStrs->strs[0]);
184 sizeof(pdbr_enumStrs->strs[0]);186 if (i < no_str)
185 if(i<no_str) no_str = i;187 no_str = i;
186 pdbr_enumStrs->no_str = no_str;188 pdbr_enumStrs->no_str = no_str;
187 ptemp = &(pdbr_enumStrs->strs[0][0]);189 ptemp = &(pdbr_enumStrs->strs[0][0]);
188 for (i=0; i<no_str; i++) {190 for (i = 0; i < no_str; i++) {
189 if(papChoice[i]==NULL) *ptemp=0;191 if (papChoice[i] == NULL)
190 else {192 *ptemp = 0;
191 strncpy(ptemp,papChoice[i],193 else {
192 sizeof(pdbr_enumStrs->strs[0]));194 strncpy(ptemp, papChoice[i], sizeof(pdbr_enumStrs->strs[0]));
193 *(ptemp+sizeof(pdbr_enumStrs->strs[0])-1) = 0;195 *(ptemp + sizeof(pdbr_enumStrs->strs[0]) - 1) = 0;
194 }196 }
195 ptemp += sizeof(pdbr_enumStrs->strs[0]);197 ptemp += sizeof(pdbr_enumStrs->strs[0]);
196 }198 }
197 break;199 break;
198 default:200 default:
199 *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/201 *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */
200 break;202 break;
201 }203 }
202 *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;204 *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;
203 return;205 return;
204}206}
205207
206static void get_graphics(DBADDR *paddr, char **ppbuffer,208static void get_graphics(DBADDR *paddr, char **ppbuffer,
207 rset *prset,long *options)209 rset * prset, long *options)
208{210{
209 struct dbr_grDouble grd;211 struct dbr_grDouble grd;
210 int got_data=FALSE;212 int got_data = FALSE;
211213
212 grd.upper_disp_limit = grd.lower_disp_limit = 0.0;214 grd.upper_disp_limit = grd.lower_disp_limit = 0.0;
213 if( prset && prset->get_graphic_double ) {215 if (prset && prset->get_graphic_double) {
214 (*prset->get_graphic_double)(paddr,&grd);216 (*prset->get_graphic_double) (paddr, &grd);
215 got_data=TRUE;217 got_data = TRUE;
216 }218 }
217 if( (*options) & (DBR_GR_LONG) ) {219 if ((*options) & (DBR_GR_LONG)) {
218 char *pbuffer=*ppbuffer;220 char *pbuffer = *ppbuffer;
219221
220 if(got_data) {222 if (got_data) {
221 struct dbr_grLong *pgr=(struct dbr_grLong*)pbuffer;223 struct dbr_grLong *pgr = (struct dbr_grLong *)pbuffer;
222 pgr->upper_disp_limit = (epicsInt32)grd.upper_disp_limit;224 pgr->upper_disp_limit = (epicsInt32) grd.upper_disp_limit;
223 pgr->lower_disp_limit = (epicsInt32)grd.lower_disp_limit;225 pgr->lower_disp_limit = (epicsInt32) grd.lower_disp_limit;
224 } else {226 } else {
225 memset(pbuffer,'\0',dbr_grLong_size);227 memset(pbuffer, '\0', dbr_grLong_size);
226 *options = (*options) ^ DBR_GR_LONG; /*Turn off option*/228 *options = (*options) ^ DBR_GR_LONG; /*Turn off option */
227 }229 }
228 *ppbuffer = ((char *)*ppbuffer) + dbr_grLong_size;230 *ppbuffer = ((char *)*ppbuffer) + dbr_grLong_size;
229 }231 }
230 if( (*options) & (DBR_GR_DOUBLE) ) {232 if ((*options) & (DBR_GR_DOUBLE)) {
231 char *pbuffer=*ppbuffer;233 char *pbuffer = *ppbuffer;
232234
233 if(got_data) {235 if (got_data) {
234 struct dbr_grDouble *pgr=(struct dbr_grDouble*)pbuffer;236 struct dbr_grDouble *pgr = (struct dbr_grDouble *)pbuffer;
235 pgr->upper_disp_limit = grd.upper_disp_limit;237 pgr->upper_disp_limit = grd.upper_disp_limit;
236 pgr->lower_disp_limit = grd.lower_disp_limit;238 pgr->lower_disp_limit = grd.lower_disp_limit;
237 } else {239 } else {
238 memset(pbuffer,'\0',dbr_grDouble_size);240 memset(pbuffer, '\0', dbr_grDouble_size);
239 *options = (*options) ^ DBR_GR_DOUBLE; /*Turn off option*/241 *options = (*options) ^ DBR_GR_DOUBLE; /*Turn off option */
240 }242 }
241 *ppbuffer = ((char *)*ppbuffer) + dbr_grDouble_size;243 *ppbuffer = ((char *)*ppbuffer) + dbr_grDouble_size;
242 }244 }
243 return;245 return;
244}246}
245247
246static void get_control(DBADDR *paddr, char **ppbuffer,248static void get_control(DBADDR *paddr, char **ppbuffer,
247 rset *prset,long *options)249 rset * prset, long *options)
248{250{
249 struct dbr_ctrlDouble ctrld;251 struct dbr_ctrlDouble ctrld;
250 int got_data=FALSE;252 int got_data = FALSE;
251253
252 ctrld.upper_ctrl_limit = ctrld.lower_ctrl_limit = 0.0;254 ctrld.upper_ctrl_limit = ctrld.lower_ctrl_limit = 0.0;
253 if( prset && prset->get_control_double ) {255 if (prset && prset->get_control_double) {
254 (*prset->get_control_double)(paddr,&ctrld);256 (*prset->get_control_double) (paddr, &ctrld);
255 got_data=TRUE;257 got_data = TRUE;
256 }258 }
257 if( (*options) & (DBR_CTRL_LONG) ) {259 if ((*options) & (DBR_CTRL_LONG)) {
258 char *pbuffer=*ppbuffer;260 char *pbuffer = *ppbuffer;
259261
260 if(got_data) {262 if (got_data) {
261 struct dbr_ctrlLong *pctrl=(struct dbr_ctrlLong*)pbuffer;263 struct dbr_ctrlLong *pctrl = (struct dbr_ctrlLong *)pbuffer;
262 pctrl->upper_ctrl_limit = (epicsInt32)ctrld.upper_ctrl_limit;264 pctrl->upper_ctrl_limit = (epicsInt32) ctrld.upper_ctrl_limit;
263 pctrl->lower_ctrl_limit = (epicsInt32)ctrld.lower_ctrl_limit;265 pctrl->lower_ctrl_limit = (epicsInt32) ctrld.lower_ctrl_limit;
264 } else {266 } else {
265 memset(pbuffer,'\0',dbr_ctrlLong_size);267 memset(pbuffer, '\0', dbr_ctrlLong_size);
266 *options = (*options) ^ DBR_CTRL_LONG; /*Turn off option*/268 *options = (*options) ^ DBR_CTRL_LONG; /*Turn off option */
267 }269 }
268 *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlLong_size;270 *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlLong_size;
269 }271 }
270 if( (*options) & (DBR_CTRL_DOUBLE) ) {272 if ((*options) & (DBR_CTRL_DOUBLE)) {
271 char *pbuffer=*ppbuffer;273 char *pbuffer = *ppbuffer;
272274
273 if(got_data) {275 if (got_data) {
274 struct dbr_ctrlDouble *pctrl=(struct dbr_ctrlDouble*)pbuffer;276 struct dbr_ctrlDouble *pctrl = (struct dbr_ctrlDouble *)pbuffer;
275 pctrl->upper_ctrl_limit = ctrld.upper_ctrl_limit;277 pctrl->upper_ctrl_limit = ctrld.upper_ctrl_limit;
276 pctrl->lower_ctrl_limit = ctrld.lower_ctrl_limit;278 pctrl->lower_ctrl_limit = ctrld.lower_ctrl_limit;
277 } else {279 } else {
278 memset(pbuffer,'\0',dbr_ctrlDouble_size);280 memset(pbuffer, '\0', dbr_ctrlDouble_size);
279 *options = (*options) ^ DBR_CTRL_DOUBLE; /*Turn off option*/281 *options = (*options) ^ DBR_CTRL_DOUBLE; /*Turn off option */
280 }282 }
281 *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlDouble_size;283 *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlDouble_size;
282 }284 }
283 return;285 return;
284}286}
285287
286static void get_alarm(DBADDR *paddr, char **ppbuffer,288static void get_alarm(DBADDR *paddr, char **ppbuffer,
287 rset *prset, long *options)289 rset * prset, long *options)
288{290{
289 char *pbuffer = *ppbuffer;291 char *pbuffer = *ppbuffer;
290 struct dbr_alDouble ald = {epicsNAN, epicsNAN, epicsNAN, epicsNAN};292 struct dbr_alDouble ald = { epicsNAN, epicsNAN, epicsNAN, epicsNAN };
291 long no_data = TRUE;293 long no_data = TRUE;
292294
293 if (prset && prset->get_alarm_double)295 if (prset && prset->get_alarm_double)
294 no_data = prset->get_alarm_double(paddr, &ald);296 no_data = prset->get_alarm_double(paddr, &ald);
295297
296 if (*options & DBR_AL_LONG) {298 if (*options & DBR_AL_LONG) {
297 struct dbr_alLong *pal = (struct dbr_alLong*) pbuffer;299 struct dbr_alLong *pal = (struct dbr_alLong *)pbuffer;
298300
299 pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?301 pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?
300 (epicsInt32) ald.upper_alarm_limit : 0;302 (epicsInt32) ald.upper_alarm_limit : 0;
301 pal->upper_warning_limit = finite(ald.upper_warning_limit) ?303 pal->upper_warning_limit = finite(ald.upper_warning_limit) ?
302 (epicsInt32) ald.upper_warning_limit : 0;304 (epicsInt32) ald.upper_warning_limit : 0;
303 pal->lower_warning_limit = finite(ald.lower_warning_limit) ?305 pal->lower_warning_limit = finite(ald.lower_warning_limit) ?
304 (epicsInt32) ald.lower_warning_limit : 0;306 (epicsInt32) ald.lower_warning_limit : 0;
305 pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ?307 pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ?
306 (epicsInt32) ald.lower_alarm_limit : 0;308 (epicsInt32) ald.lower_alarm_limit : 0;
307309
308 if (no_data)310 if (no_data)
309 *options ^= DBR_AL_LONG; /*Turn off option*/311 *options ^= DBR_AL_LONG; /*Turn off option */
310312
311 *ppbuffer += dbr_alLong_size;313 *ppbuffer += dbr_alLong_size;
312 }314 }
313 if (*options & DBR_AL_DOUBLE) {315 if (*options & DBR_AL_DOUBLE) {
314 struct dbr_alDouble *pal = (struct dbr_alDouble*) pbuffer;316 struct dbr_alDouble *pal = (struct dbr_alDouble *)pbuffer;
315317
316 pal->upper_alarm_limit = ald.upper_alarm_limit;318 pal->upper_alarm_limit = ald.upper_alarm_limit;
317 pal->upper_warning_limit = ald.upper_warning_limit;319 pal->upper_warning_limit = ald.upper_warning_limit;
318 pal->lower_warning_limit = ald.lower_warning_limit;320 pal->lower_warning_limit = ald.lower_warning_limit;
319 pal->lower_alarm_limit = ald.lower_alarm_limit;321 pal->lower_alarm_limit = ald.lower_alarm_limit;
320322
321 if (no_data)323 if (no_data)
322 *options ^= DBR_AL_DOUBLE; /*Turn off option*/324 *options ^= DBR_AL_DOUBLE; /*Turn off option */
323325
324 *ppbuffer += dbr_alDouble_size;326 *ppbuffer += dbr_alDouble_size;
325 }327 }
@@ -330,88 +332,89 @@ static void get_alarm(DBADDR *paddr, char **ppbuffer,
330 * blocks only changing the buffer pointer in a way that does not break alignment.332 * blocks only changing the buffer pointer in a way that does not break alignment.
331 */333 */
332static void getOptions(DBADDR *paddr, char **poriginal, long *options,334static void getOptions(DBADDR *paddr, char **poriginal, long *options,
333 void *pflin)335 void *pflin)
334{336{
335 db_field_log *pfl= (db_field_log *)pflin;337 db_field_log *pfl = (db_field_log *) pflin;
336 rset *prset;338 rset *prset;
337 short field_type;339 short field_type;
338 dbCommon *pcommon;340 dbCommon *pcommon;
339 char *pbuffer = *poriginal;341 char *pbuffer = *poriginal;
340342
341 if (!pfl || pfl->type == dbfl_type_rec)343 if (!pfl)
342 field_type = paddr->field_type;344 field_type = paddr->field_type;
343 else345 else
344 field_type = pfl->field_type;346 field_type = pfl->field_type;
345 prset=dbGetRset(paddr);347 prset = dbGetRset(paddr);
346 /* Process options */348 /* Process options */
347 pcommon = paddr->precord;349 pcommon = paddr->precord;
348 if( (*options) & DBR_STATUS ) {350 if ((*options) & DBR_STATUS) {
349 unsigned short *pushort = (unsigned short *)pbuffer;351 unsigned short *pushort = (unsigned short *)pbuffer;
350352
351 if (!pfl || pfl->type == dbfl_type_rec) {353 if (!pfl) {
352 *pushort++ = pcommon->stat;354 *pushort++ = pcommon->stat;
353 *pushort++ = pcommon->sevr;355 *pushort++ = pcommon->sevr;
354 } else {356 } else {
355 *pushort++ = pfl->stat;357 *pushort++ = pfl->stat;
356 *pushort++ = pfl->sevr;358 *pushort++ = pfl->sevr;
357 }359 }
358 *pushort++ = pcommon->acks;360 *pushort++ = pcommon->acks;
359 *pushort++ = pcommon->ackt;361 *pushort++ = pcommon->ackt;
360 pbuffer = (char *)pushort;362 pbuffer = (char *)pushort;
361 }363 }
362 if( (*options) & DBR_UNITS ) {364 if ((*options) & DBR_UNITS) {
363 memset(pbuffer,'\0',dbr_units_size);365 memset(pbuffer, '\0', dbr_units_size);
364 if( prset && prset->get_units ){366 if (prset && prset->get_units) {
365 (*prset->get_units)(paddr, pbuffer);367 (*prset->get_units) (paddr, pbuffer);
366 pbuffer[DB_UNITS_SIZE-1] = '\0';368 pbuffer[DB_UNITS_SIZE - 1] = '\0';
367 } else {369 } else {
368 *options ^= DBR_UNITS; /*Turn off DBR_UNITS*/370 *options ^= DBR_UNITS; /*Turn off DBR_UNITS */
369 }371 }
370 pbuffer += dbr_units_size;372 pbuffer += dbr_units_size;
371 }373 }
372 if( (*options) & DBR_PRECISION ) {374 if ((*options) & DBR_PRECISION) {
373 memset(pbuffer, '\0', dbr_precision_size);375 memset(pbuffer, '\0', dbr_precision_size);
374 if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE)376 if ((field_type == DBF_FLOAT || field_type == DBF_DOUBLE)
375 && prset && prset->get_precision ){377 && prset && prset->get_precision) {
376 (*prset->get_precision)(paddr,(long *)pbuffer);378 (*prset->get_precision) (paddr, (long *)pbuffer);
377 } else {379 } else {
378 *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION*/380 *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION */
379 }381 }
380 pbuffer += dbr_precision_size;382 pbuffer += dbr_precision_size;
381 }383 }
382 if( (*options) & DBR_TIME ) {384 if ((*options) & DBR_TIME) {
383 epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;385 epicsUInt32 *ptime = (epicsUInt32 *) pbuffer;
384386
385 if (!pfl || pfl->type == dbfl_type_rec) {387 if (!pfl) {
386 *ptime++ = pcommon->time.secPastEpoch;388 *ptime++ = pcommon->time.secPastEpoch;
387 *ptime++ = pcommon->time.nsec;389 *ptime++ = pcommon->time.nsec;
388 } else {390 } else {
389 *ptime++ = pfl->time.secPastEpoch;391 *ptime++ = pfl->time.secPastEpoch;
390 *ptime++ = pfl->time.nsec;392 *ptime++ = pfl->time.nsec;
391 }393 }
392 pbuffer = (char *)ptime;394 pbuffer = (char *)ptime;
393 }395 }
394 if( (*options) & DBR_ENUM_STRS )396 if ((*options) & DBR_ENUM_STRS)
395 get_enum_strs(paddr, &pbuffer, prset, options);397 get_enum_strs(paddr, &pbuffer, prset, options);
396 if( (*options) & (DBR_GR_LONG|DBR_GR_DOUBLE ))398 if ((*options) & (DBR_GR_LONG | DBR_GR_DOUBLE))
397 get_graphics(paddr, &pbuffer, prset, options);399 get_graphics(paddr, &pbuffer, prset, options);
398 if((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE ))400 if ((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE))
399 get_control(paddr, &pbuffer, prset, options);401 get_control(paddr, &pbuffer, prset, options);
400 if((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE ))402 if ((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE))
401 get_alarm(paddr, &pbuffer, prset, options);403 get_alarm(paddr, &pbuffer, prset, options);
402 *poriginal = pbuffer;404 *poriginal = pbuffer;
403}405}
404406
405rset * dbGetRset(const struct dbAddr *paddr)407rset *dbGetRset(const struct dbAddr *paddr)
406{408{
407 struct dbFldDes *pfldDes = paddr->pfldDes;409 struct dbFldDes *pfldDes = paddr->pfldDes;
408410
409 if(!pfldDes) return(0);411 if (!pfldDes)
410 return(pfldDes->pdbRecordType->prset);412 return (0);
413 return (pfldDes->pdbRecordType->prset);
411}414}
412415
413long dbPutAttribute(416long dbPutAttribute(const char *recordTypename, const char *name,
414 const char *recordTypename, const char *name, const char *value)417 const char *value)
415{418{
416 DBENTRY dbEntry;419 DBENTRY dbEntry;
417 DBENTRY *pdbEntry = &dbEntry;420 DBENTRY *pdbEntry = &dbEntry;
@@ -430,7 +433,7 @@ long dbPutAttribute(
430 if (!status)433 if (!status)
431 status = dbPutRecordAttribute(pdbEntry, name, value);434 status = dbPutRecordAttribute(pdbEntry, name, value);
432 dbFinishEntry(pdbEntry);435 dbFinishEntry(pdbEntry);
433done:436 done:
434 if (status)437 if (status)
435 errMessage(status, "dbPutAttribute failure");438 errMessage(status, "dbPutAttribute failure");
436 return status;439 return status;
@@ -458,7 +461,7 @@ int dbGetFieldIndex(const struct dbAddr *paddr)
458 * 5. Run the process routine specific to the record type.461 * 5. Run the process routine specific to the record type.
459 * 6. Check to see if record contents should be automatically printed.462 * 6. Check to see if record contents should be automatically printed.
460 */463 */
461long dbProcess(dbCommon *precord)464long dbProcess(dbCommon * precord)
462{465{
463 rset *prset = precord->rset;466 rset *prset = precord->rset;
464 dbRecordType *pdbRecordType = precord->rdes;467 dbRecordType *pdbRecordType = precord->rdes;
@@ -466,7 +469,7 @@ long dbProcess(dbCommon *precord)
466 char context[40] = "";469 char context[40] = "";
467 long status = 0;470 long status = 0;
468 int *ptrace;471 int *ptrace;
469 int set_trace = FALSE;472 int set_trace = FALSE;
470 dbFldDes *pdbFldDes;473 dbFldDes *pdbFldDes;
471 int callNotifyCompletion = FALSE;474 int callNotifyCompletion = FALSE;
472475
@@ -492,7 +495,7 @@ long dbProcess(dbCommon *precord)
492 goto all_done;495 goto all_done;
493 }496 }
494497
495 /* check for trace processing*/498 /* check for trace processing */
496 if (tpro) {499 if (tpro) {
497 if (!*ptrace) {500 if (!*ptrace) {
498 *ptrace = 1;501 *ptrace = 1;
@@ -519,19 +522,17 @@ long dbProcess(dbCommon *precord)
519522
520 /* raise scan alarm after MAX_LOCK times */523 /* raise scan alarm after MAX_LOCK times */
521 if ((precord->stat == SCAN_ALARM) ||524 if ((precord->stat == SCAN_ALARM) ||
522 (precord->lcnt++ < MAX_LOCK) ||525 (precord->lcnt++ < MAX_LOCK) || (precord->sevr >= INVALID_ALARM))
523 (precord->sevr >= INVALID_ALARM)) goto all_done;526 goto all_done;
524527
525 recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);528 recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM);
526 monitor_mask = recGblResetAlarms(precord);529 monitor_mask = recGblResetAlarms(precord);
527 monitor_mask |= DBE_VALUE|DBE_LOG;530 monitor_mask |= DBE_VALUE | DBE_LOG;
528 pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];531 pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
529 db_post_events(precord,532 db_post_events(precord,
530 (void *)(((char *)precord) + pdbFldDes->offset),533 (void *)(((char *)precord) + pdbFldDes->offset), monitor_mask);
531 monitor_mask);
532 goto all_done;534 goto all_done;
533 }535 } else
534 else
535 precord->lcnt = 0;536 precord->lcnt = 0;
536537
537 /*538 /*
@@ -547,7 +548,7 @@ long dbProcess(dbCommon *precord)
547 printf("%s: dbProcess of Disabled '%s'\n",548 printf("%s: dbProcess of Disabled '%s'\n",
548 context, precord->name);549 context, precord->name);
549550
550 /*take care of caching and notifyCompletion*/551 /*take care of caching and notifyCompletion */
551 precord->rpro = FALSE;552 precord->rpro = FALSE;
552 precord->putf = FALSE;553 precord->putf = FALSE;
553 callNotifyCompletion = TRUE;554 callNotifyCompletion = TRUE;
@@ -564,8 +565,8 @@ long dbProcess(dbCommon *precord)
564 db_post_events(precord, &precord->sevr, DBE_VALUE);565 db_post_events(precord, &precord->sevr, DBE_VALUE);
565 pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];566 pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes];
566 db_post_events(precord,567 db_post_events(precord,
567 (void *)(((char *)precord) + pdbFldDes->offset),568 (void *)(((char *)precord) + pdbFldDes->offset),
568 DBE_VALUE|DBE_ALARM);569 DBE_VALUE | DBE_ALARM);
569 goto all_done;570 goto all_done;
570 }571 }
571572
@@ -573,7 +574,7 @@ long dbProcess(dbCommon *precord)
573 /* FIXME: put this in iocInit() !!! */574 /* FIXME: put this in iocInit() !!! */
574 if (!prset || !prset->process) {575 if (!prset || !prset->process) {
575 callNotifyCompletion = TRUE;576 callNotifyCompletion = TRUE;
576 precord->pact = 1;/*set pact so error is issued only once*/577 precord->pact = 1; /*set pact so error is issued only once */
577 recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");578 recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess");
578 status = S_db_noRSET;579 status = S_db_noRSET;
579 if (*ptrace)580 if (*ptrace)
@@ -592,7 +593,7 @@ long dbProcess(dbCommon *precord)
592 dbPrint(precord);593 dbPrint(precord);
593 }594 }
594595
595all_done:596 all_done:
596 if (set_trace)597 if (set_trace)
597 *ptrace = 0;598 *ptrace = 0;
598 if (callNotifyCompletion && precord->ppn)599 if (callNotifyCompletion && precord->ppn)
@@ -601,7 +602,7 @@ all_done:
601 return status;602 return status;
602}603}
603604
604long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr)605long dbEntryToAddr(const DBENTRY * pdbentry, DBADDR *paddr)
605{606{
606 dbFldDes *pflddes = pdbentry->pflddes;607 dbFldDes *pflddes = pdbentry->pflddes;
607 short dbfType = pflddes->field_type;608 short dbfType = pflddes->field_type;
@@ -610,9 +611,9 @@ long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr)
610 paddr->pfield = pdbentry->pfield;611 paddr->pfield = pdbentry->pfield;
611 paddr->pfldDes = pflddes;612 paddr->pfldDes = pflddes;
612 paddr->no_elements = 1;613 paddr->no_elements = 1;
613 paddr->field_type = dbfType;614 paddr->field_type = dbfType;
614 paddr->field_size = pflddes->size;615 paddr->field_size = pflddes->size;
615 paddr->special = pflddes->special;616 paddr->special = pflddes->special;
616 paddr->dbr_field_type = mapDBFToDBR[dbfType];617 paddr->dbr_field_type = mapDBFToDBR[dbfType];
617618
618 if (paddr->special == SPC_DBADDR) {619 if (paddr->special == SPC_DBADDR) {
@@ -643,16 +644,20 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
643644
644 dbInitEntry(pdbbase, &dbEntry);645 dbInitEntry(pdbbase, &dbEntry);
645 status = dbFindRecordPart(&dbEntry, &pname);646 status = dbFindRecordPart(&dbEntry, &pname);
646 if (status) goto finish;647 if (status)
648 goto finish;
647649
648 if (*pname == '.') ++pname;650 if (*pname == '.')
651 ++pname;
649 status = dbFindFieldPart(&dbEntry, &pname);652 status = dbFindFieldPart(&dbEntry, &pname);
650 if (status == S_dbLib_fieldNotFound)653 if (status == S_dbLib_fieldNotFound)
651 status = dbGetAttributePart(&dbEntry, &pname);654 status = dbGetAttributePart(&dbEntry, &pname);
652 if (status) goto finish;655 if (status)
656 goto finish;
653657
654 status = dbEntryToAddr(&dbEntry, paddr);658 status = dbEntryToAddr(&dbEntry, paddr);
655 if (status) goto finish;659 if (status)
660 goto finish;
656661
657 /* Handle field modifiers */662 /* Handle field modifiers */
658 if (*pname++ == '$') {663 if (*pname++ == '$') {
@@ -664,29 +669,27 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
664 paddr->field_type = DBF_CHAR;669 paddr->field_type = DBF_CHAR;
665 paddr->field_size = 1;670 paddr->field_size = 1;
666 paddr->dbr_field_type = DBR_CHAR;671 paddr->dbr_field_type = DBR_CHAR;
667 }672 } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
668 else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
669 /* Clients see a char array, but keep original dbfType */673 /* Clients see a char array, but keep original dbfType */
670 paddr->no_elements = PVLINK_STRINGSZ;674 paddr->no_elements = PVLINK_STRINGSZ;
671 paddr->field_size = 1;675 paddr->field_size = 1;
672 paddr->dbr_field_type = DBR_CHAR;676 paddr->dbr_field_type = DBR_CHAR;
673 }677 } else {
674 else {
675 status = S_dbLib_fieldNotFound;678 status = S_dbLib_fieldNotFound;
676 }679 }
677 }680 }
678681
679finish:682 finish:
680 dbFinishEntry(&dbEntry);683 dbFinishEntry(&dbEntry);
681 return status;684 return status;
682}685}
683686
684void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)687void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY * pdbentry)
685{688{
686 struct dbCommon *prec = paddr->precord;689 struct dbCommon *prec = paddr->precord;
687 dbCommonPvt *ppvt = dbRec2Pvt(prec);690 dbCommonPvt *ppvt = dbRec2Pvt(prec);
688691
689 memset((char *)pdbentry,'\0',sizeof(DBENTRY));692 memset((char *)pdbentry, '\0', sizeof(DBENTRY));
690693
691 pdbentry->pdbbase = pdbbase;694 pdbentry->pdbbase = pdbbase;
692 pdbentry->precordType = prec->rdes;695 pdbentry->precordType = prec->rdes;
@@ -696,24 +699,24 @@ void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
696 pdbentry->indfield = paddr->pfldDes->indRecordType;699 pdbentry->indfield = paddr->pfldDes->indRecordType;
697}700}
698701
699void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)702void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY * pdbentry)
700{703{
701 dbCommonPvt *ppvt = dbRec2Pvt(prec);704 dbCommonPvt *ppvt = dbRec2Pvt(prec);
702705
703 memset((char *)pdbentry,'\0',sizeof(DBENTRY));706 memset((char *)pdbentry, '\0', sizeof(DBENTRY));
704707
705 pdbentry->pdbbase = pdbbase;708 pdbentry->pdbbase = pdbbase;
706 pdbentry->precordType = prec->rdes;709 pdbentry->precordType = prec->rdes;
707 pdbentry->precnode = ppvt->recnode;710 pdbentry->precnode = ppvt->recnode;
708}711}
709712
710struct link* dbGetDevLink(struct dbCommon* prec)713struct link *dbGetDevLink(struct dbCommon *prec)
711{714{
712 DBLINK *plink = 0;715 DBLINK *plink = 0;
713 DBENTRY entry;716 DBENTRY entry;
714 dbInitEntryFromRecord(prec, &entry);717 dbInitEntryFromRecord(prec, &entry);
715 if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) {718 if (dbFindField(&entry, "INP") == 0 || dbFindField(&entry, "OUT") == 0) {
716 plink = (DBLINK*)entry.pfield;719 plink = (DBLINK *) entry.pfield;
717 }720 }
718 dbFinishEntry(&entry);721 dbFinishEntry(&entry);
719 return plink;722 return plink;
@@ -723,41 +726,53 @@ long dbValueSize(short dbr_type)
723{726{
724 /* sizes for value associated with each DBR request type */727 /* sizes for value associated with each DBR request type */
725 static long size[] = {728 static long size[] = {
726 MAX_STRING_SIZE, /* STRING */729 MAX_STRING_SIZE, /* STRING */
727 sizeof(epicsInt8), /* CHAR */730 sizeof(epicsInt8), /* CHAR */
728 sizeof(epicsUInt8), /* UCHAR */731 sizeof(epicsUInt8), /* UCHAR */
729 sizeof(epicsInt16), /* SHORT */732 sizeof(epicsInt16), /* SHORT */
730 sizeof(epicsUInt16), /* USHORT */733 sizeof(epicsUInt16), /* USHORT */
731 sizeof(epicsInt32), /* LONG */734 sizeof(epicsInt32), /* LONG */
732 sizeof(epicsUInt32), /* ULONG */735 sizeof(epicsUInt32), /* ULONG */
733 sizeof(epicsInt64), /* INT64 */736 sizeof(epicsInt64), /* INT64 */
734 sizeof(epicsUInt64), /* UINT64 */737 sizeof(epicsUInt64), /* UINT64 */
735 sizeof(epicsFloat32), /* FLOAT */738 sizeof(epicsFloat32), /* FLOAT */
736 sizeof(epicsFloat64), /* DOUBLE */739 sizeof(epicsFloat64), /* DOUBLE */
737 sizeof(epicsEnum16)}; /* ENUM */740 sizeof(epicsEnum16)
738741 }; /* ENUM */
739 return(size[dbr_type]);742
743 return (size[dbr_type]);
740}744}
741745
742
743long dbBufferSize(short dbr_type, long options, long no_elements)746long dbBufferSize(short dbr_type, long options, long no_elements)
744{747{
745 long nbytes=0;748 long nbytes = 0;
746749
747 nbytes += dbValueSize(dbr_type) * no_elements;750 nbytes += dbValueSize(dbr_type) * no_elements;
748 if (options & DBR_STATUS) nbytes += dbr_status_size;751 if (options & DBR_STATUS)
749 if (options & DBR_UNITS) nbytes += dbr_units_size;752 nbytes += dbr_status_size;
750 if (options & DBR_PRECISION) nbytes += dbr_precision_size;753 if (options & DBR_UNITS)
751 if (options & DBR_TIME) nbytes += dbr_time_size;754 nbytes += dbr_units_size;
752 if (options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size;755 if (options & DBR_PRECISION)
753 if (options & DBR_GR_LONG) nbytes += dbr_grLong_size;756 nbytes += dbr_precision_size;
754 if (options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size;757 if (options & DBR_TIME)
755 if (options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size;758 nbytes += dbr_time_size;
756 if (options & DBR_CTRL_DOUBLE) nbytes += dbr_ctrlDouble_size;759 if (options & DBR_ENUM_STRS)
757 if (options & DBR_AL_LONG) nbytes += dbr_alLong_size;760 nbytes += dbr_enumStrs_size;
758 if (options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size;761 if (options & DBR_GR_LONG)
759 return(nbytes);762 nbytes += dbr_grLong_size;
763 if (options & DBR_GR_DOUBLE)
764 nbytes += dbr_grDouble_size;
765 if (options & DBR_CTRL_LONG)
766 nbytes += dbr_ctrlLong_size;
767 if (options & DBR_CTRL_DOUBLE)
768 nbytes += dbr_ctrlDouble_size;
769 if (options & DBR_AL_LONG)
770 nbytes += dbr_alLong_size;
771 if (options & DBR_AL_DOUBLE)
772 nbytes += dbr_alDouble_size;
773 return (nbytes);
760}774}
775
761int dbLoadDatabase(const char *file, const char *path, const char *subs)776int dbLoadDatabase(const char *file, const char *path, const char *subs)
762{777{
763 if (!file) {778 if (!file) {
@@ -767,7 +782,7 @@ int dbLoadDatabase(const char *file, const char *path, const char *subs)
767 return dbReadDatabase(&pdbbase, file, path, subs);782 return dbReadDatabase(&pdbbase, file, path, subs);
768}783}
769784
770int dbLoadRecords(const char* file, const char* subs)785int dbLoadRecords(const char *file, const char *subs)
771{786{
772 int status;787 int status;
773788
@@ -781,7 +796,6 @@ int dbLoadRecords(const char* file, const char* subs)
781 return status;796 return status;
782}797}
783798
784
785static long getLinkValue(DBADDR *paddr, short dbrType,799static long getLinkValue(DBADDR *paddr, short dbrType,
786 char *pbuf, long *nRequest)800 char *pbuf, long *nRequest)
787{801{
@@ -797,7 +811,7 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
797 * valid DBADDR, so no point to check again.811 * valid DBADDR, so no point to check again.
798 * Request for zero elements always succeeds812 * Request for zero elements always succeeds
799 */813 */
800 if(!nReq)814 if (!nReq)
801 return 0;815 return 0;
802816
803 switch (dbrType) {817 switch (dbrType) {
@@ -806,8 +820,9 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
806 nReq = 1;820 nReq = 1;
807 break;821 break;
808822
809 case DBR_DOUBLE: /* Needed for dbCa links */823 case DBR_DOUBLE: /* Needed for dbCa links */
810 if (nRequest) *nRequest = 1;824 if (nRequest)
825 *nRequest = 1;
811 *(double *)pbuf = epicsNAN;826 *(double *)pbuf = epicsNAN;
812 return 0;827 return 0;
813828
@@ -821,27 +836,30 @@ static long getLinkValue(DBADDR *paddr, short dbrType,
821836
822 dbInitEntry(pdbbase, &dbEntry);837 dbInitEntry(pdbbase, &dbEntry);
823 status = dbFindRecord(&dbEntry, precord->name);838 status = dbFindRecord(&dbEntry, precord->name);
824 if (!status) status = dbFindField(&dbEntry, pfldDes->name);839 if (!status)
840 status = dbFindField(&dbEntry, pfldDes->name);
825 if (!status) {841 if (!status) {
826 const char *rtnString = dbGetString(&dbEntry);842 const char *rtnString = dbGetString(&dbEntry);
827843
828 strncpy(pbuf, rtnString, maxlen-1);844 strncpy(pbuf, rtnString, maxlen - 1);
829 pbuf[maxlen-1] = 0;845 pbuf[maxlen - 1] = 0;
830 if(dbrType!=DBR_STRING)846 if (dbrType != DBR_STRING)
831 nReq = strlen(pbuf)+1;847 nReq = strlen(pbuf) + 1;
832 if(nRequest) *nRequest = nReq;848 if (nRequest)
849 *nRequest = nReq;
833 }850 }
834 dbFinishEntry(&dbEntry);851 dbFinishEntry(&dbEntry);
835 return status;852 return status;
836}853}
837854
838static long getAttrValue(DBADDR *paddr, short dbrType,855static long getAttrValue(DBADDR *paddr, short dbrType,
839 char *pbuf, long *nRequest)856 char *pbuf, long *nRequest)
840{857{
841 int maxlen;858 int maxlen;
842 long nReq = nRequest ? *nRequest : 1;859 long nReq = nRequest ? *nRequest : 1;
843860
844 if (!paddr->pfield) return S_db_badField;861 if (!paddr->pfield)
862 return S_db_badField;
845863
846 switch (dbrType) {864 switch (dbrType) {
847 case DBR_STRING:865 case DBR_STRING:
@@ -859,22 +877,23 @@ static long getAttrValue(DBADDR *paddr, short dbrType,
859 return S_db_badDbrtype;877 return S_db_badDbrtype;
860 }878 }
861879
862 strncpy(pbuf, paddr->pfield, maxlen-1);880 strncpy(pbuf, paddr->pfield, maxlen - 1);
863 pbuf[maxlen-1] = 0;881 pbuf[maxlen - 1] = 0;
864 if(dbrType!=DBR_STRING)882 if (dbrType != DBR_STRING)
865 nReq = strlen(pbuf)+1;883 nReq = strlen(pbuf) + 1;
866 if(nRequest) *nRequest = nReq;884 if (nRequest)
885 *nRequest = nReq;
867 return 0;886 return 0;
868}887}
869888
870long dbGetField(DBADDR *paddr,short dbrType,889long dbGetField(DBADDR *paddr, short dbrType,
871 void *pbuffer, long *options, long *nRequest, void *pflin)890 void *pbuffer, long *options, long *nRequest)
872{891{
873 dbCommon *precord = paddr->precord;892 dbCommon *precord = paddr->precord;
874 long status = 0;893 long status = 0;
875894
876 dbScanLock(precord);895 dbScanLock(precord);
877 status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);896 status = dbGet(paddr, dbrType, pbuffer, options, nRequest, NULL);
878 dbScanUnlock(precord);897 dbScanUnlock(precord);
879 return status;898 return status;
880}899}
@@ -884,7 +903,7 @@ long dbGet(DBADDR *paddr, short dbrType,
884{903{
885 char *pbuf = pbuffer;904 char *pbuf = pbuffer;
886 void *pfieldsave = paddr->pfield;905 void *pfieldsave = paddr->pfield;
887 db_field_log *pfl = (db_field_log *)pflin;906 db_field_log *pfl = (db_field_log *) pflin;
888 short field_type;907 short field_type;
889 long capacity, no_elements, offset;908 long capacity, no_elements, offset;
890 rset *prset;909 rset *prset;
@@ -895,7 +914,7 @@ long dbGet(DBADDR *paddr, short dbrType,
895 if (nRequest && *nRequest == 0)914 if (nRequest && *nRequest == 0)
896 return 0;915 return 0;
897916
898 if (!pfl || pfl->type == dbfl_type_rec) {917 if (!pfl) {
899 field_type = paddr->field_type;918 field_type = paddr->field_type;
900 no_elements = capacity = paddr->no_elements;919 no_elements = capacity = paddr->no_elements;
901920
@@ -903,15 +922,14 @@ long dbGet(DBADDR *paddr, short dbrType,
903 * may modify paddr->pfield922 * may modify paddr->pfield
904 */923 */
905 if (paddr->pfldDes->special == SPC_DBADDR &&924 if (paddr->pfldDes->special == SPC_DBADDR &&
906 (prset = dbGetRset(paddr)) &&925 (prset = dbGetRset(paddr)) && prset->get_array_info) {
907 prset->get_array_info) {
908 status = prset->get_array_info(paddr, &no_elements, &offset);926 status = prset->get_array_info(paddr, &no_elements, &offset);
909 } else927 } else
910 offset = 0;928 offset = 0;
911 } else {929 } else {
912 field_type = pfl->field_type;930 field_type = pfl->field_type;
913 no_elements = capacity = pfl->no_elements;931 no_elements = capacity = pfl->no_elements;
914 offset = 0;932 offset = pfl->offset;
915 }933 }
916934
917 if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) {935 if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) {
@@ -937,19 +955,25 @@ long dbGet(DBADDR *paddr, short dbrType,
937 if (offset == 0 && (!nRequest || no_elements == 1)) {955 if (offset == 0 && (!nRequest || no_elements == 1)) {
938 if (nRequest)956 if (nRequest)
939 *nRequest = 1;957 *nRequest = 1;
940 if (!pfl || pfl->type == dbfl_type_rec) {958 if (!pfl) {
941 status = dbFastGetConvertRoutine[field_type][dbrType]959 status = dbFastGetConvertRoutine[field_type][dbrType]
942 (paddr->pfield, pbuf, paddr);960 (paddr->pfield, pbuf, paddr);
943 } else {961 } else {
944 DBADDR localAddr = *paddr; /* Structure copy */962 DBADDR localAddr = *paddr; /* Structure copy */
963
964 if (pfl->no_elements < 1) {
965 status = S_db_badField;
966 goto done;
967 }
945968
946 localAddr.field_type = pfl->field_type;969 localAddr.field_type = pfl->field_type;
947 localAddr.field_size = pfl->field_size;970 localAddr.field_size = pfl->field_size;
971 /* not used by dbFastConvert: */
948 localAddr.no_elements = pfl->no_elements;972 localAddr.no_elements = pfl->no_elements;
949 if (pfl->type == dbfl_type_val)973 if (pfl->type == dbfl_type_val)
950 localAddr.pfield = (char *) &pfl->u.v.field;974 localAddr.pfield = (char *)&pfl->u.v.field;
951 else975 else
952 localAddr.pfield = (char *) pfl->u.r.field;976 localAddr.pfield = (char *)pfl->u.r.field;
953 status = dbFastGetConvertRoutine[field_type][dbrType]977 status = dbFastGetConvertRoutine[field_type][dbrType]
954 (localAddr.pfield, pbuf, &localAddr);978 (localAddr.pfield, pbuf, &localAddr);
955 }979 }
@@ -969,52 +993,55 @@ long dbGet(DBADDR *paddr, short dbrType,
969 char message[80];993 char message[80];
970994
971 sprintf(message, "dbGet: Missing conversion for [%d][%d]\n",995 sprintf(message, "dbGet: Missing conversion for [%d][%d]\n",
972 field_type, dbrType);996 field_type, dbrType);
973 recGblDbaddrError(S_db_badDbrtype, paddr, message);997 recGblDbaddrError(S_db_badDbrtype, paddr, message);
974 status = S_db_badDbrtype;998 status = S_db_badDbrtype;
975 goto done;999 goto done;
976 }1000 }
977 /* convert data into the caller's buffer */1001 /* convert data into the caller's buffer */
978 if (n <= 0) {1002 if (n <= 0) {
979 ;/*do nothing*/1003 ; /*do nothing */
980 } else if (!pfl || pfl->type == dbfl_type_rec) {1004 } else if (!pfl) {
981 status = convert(paddr, pbuf, n, capacity, offset);1005 status = convert(paddr, pbuf, n, capacity, offset);
982 } else {1006 } else {
983 DBADDR localAddr = *paddr; /* Structure copy */1007 DBADDR localAddr = *paddr; /* Structure copy */
9841008
985 localAddr.field_type = pfl->field_type;1009 localAddr.field_type = pfl->field_type;
986 localAddr.field_size = pfl->field_size;1010 localAddr.field_size = pfl->field_size;
1011 /* not used by dbConvert, it uses the passed capacity instead: */
987 localAddr.no_elements = pfl->no_elements;1012 localAddr.no_elements = pfl->no_elements;
988 if (pfl->type == dbfl_type_val)1013 if (pfl->type == dbfl_type_val)
989 localAddr.pfield = (char *) &pfl->u.v.field;1014 localAddr.pfield = (char *)&pfl->u.v.field;
990 else1015 else
991 localAddr.pfield = (char *) pfl->u.r.field;1016 localAddr.pfield = (char *)pfl->u.r.field;
992 status = convert(&localAddr, pbuf, n, capacity, offset);1017 status = convert(&localAddr, pbuf, n, capacity, offset);
993 }1018 }
9941019
995 if(!status && dbrType==DBF_CHAR && nRequest &&1020 if (!status && dbrType == DBF_CHAR && nRequest &&
996 paddr->pfldDes && paddr->pfldDes->field_type==DBF_STRING)1021 paddr->pfldDes && paddr->pfldDes->field_type == DBF_STRING) {
997 {
998 /* long string ensure nil and truncate to actual length */1022 /* long string ensure nil and truncate to actual length */
999 long nReq = *nRequest;1023 long nReq = *nRequest;
1000 pbuf[nReq-1] = '\0';1024 pbuf[nReq - 1] = '\0';
1001 *nRequest = strlen(pbuf)+1;1025 *nRequest = strlen(pbuf) + 1;
1002 }1026 }
1003 }1027 }
1004done:1028 done:
1005 paddr->pfield = pfieldsave;1029 paddr->pfield = pfieldsave;
1006 return status;1030 return status;
1007}1031}
10081032
1009devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) {1033devSup *dbDTYPtoDevSup(dbRecordType * prdes, int dtyp)
1010 return (devSup *)ellNth(&prdes->devList, dtyp+1);1034{
1035 return (devSup *) ellNth(&prdes->devList, dtyp + 1);
1011}1036}
10121037
1013devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) {1038devSup *dbDSETtoDevSup(dbRecordType * prdes, dset * pdset)
1014 devSup *pdevSup = (devSup *)ellFirst(&prdes->devList);1039{
1040 devSup *pdevSup = (devSup *) ellFirst(&prdes->devList);
1015 while (pdevSup) {1041 while (pdevSup) {
1016 if (pdset == pdevSup->pdset) return pdevSup;1042 if (pdset == pdevSup->pdset)
1017 pdevSup = (devSup *)ellNext(&pdevSup->node);1043 return pdevSup;
1044 pdevSup = (devSup *) ellNext(&pdevSup->node);
1018 }1045 }
1019 return NULL;1046 return NULL;
1020}1047}
@@ -1022,24 +1049,24 @@ devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) {
1022static long dbPutFieldLink(DBADDR *paddr,1049static long dbPutFieldLink(DBADDR *paddr,
1023 short dbrType, const void *pbuffer, long nRequest)1050 short dbrType, const void *pbuffer, long nRequest)
1024{1051{
1025 dbLinkInfo link_info;1052 dbLinkInfo link_info;
1026 DBADDR *pdbaddr = NULL;1053 dbChannel *chan = NULL;
1027 dbCommon *precord = paddr->precord;1054 dbCommon *precord = paddr->precord;
1028 dbCommon *lockrecs[2];1055 dbCommon *lockrecs[2];
1029 dbLocker locker;1056 dbLocker locker;
1030 dbFldDes *pfldDes = paddr->pfldDes;1057 dbFldDes *pfldDes = paddr->pfldDes;
1031 long special = paddr->special;1058 long special = paddr->special;
1032 struct link *plink = (struct link *)paddr->pfield;1059 struct link *plink = (struct link *)paddr->pfield;
1033 const char *pstring = (const char *)pbuffer;1060 const char *pstring = (const char *)pbuffer;
1034 struct dsxt *old_dsxt = NULL;1061 struct dsxt *old_dsxt = NULL;
1035 dset *new_dset = NULL;1062 dset *new_dset = NULL;
1036 struct dsxt *new_dsxt = NULL;1063 struct dsxt *new_dsxt = NULL;
1037 devSup *new_devsup = NULL;1064 devSup *new_devsup = NULL;
1038 long status;1065 long status;
1039 int isDevLink;1066 int isDevLink;
1040 short scan;1067 short scan;
10411068
1042 STATIC_ASSERT(DBLOCKER_NALLOC>=2);1069 STATIC_ASSERT(DBLOCKER_NALLOC >= 2);
10431070
1044 switch (dbrType) {1071 switch (dbrType) {
1045 case DBR_CHAR:1072 case DBR_CHAR:
@@ -1061,25 +1088,20 @@ static long dbPutFieldLink(DBADDR *paddr,
10611088
1062 if (link_info.ltype == PV_LINK &&1089 if (link_info.ltype == PV_LINK &&
1063 (link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {1090 (link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
1064 DBADDR tempaddr;1091 chan = dbChannelCreate(link_info.target);
10651092 if (chan && dbChannelOpen(chan) != 0) {
1066 if (dbNameToAddr(link_info.target, &tempaddr)==0) {1093 errlogPrintf
1067 /* This will become a DB link. */1094 ("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n",
1068 pdbaddr = malloc(sizeof(*pdbaddr));1095 precord->name, pfldDes->name, link_info.target);
1069 if (!pdbaddr) {1096 goto cleanup;
1070 status = S_db_noMemory;
1071 goto cleanup;
1072 }
1073 *pdbaddr = tempaddr; /* struct copy */
1074 }1097 }
1075 }1098 }
10761099
1077 isDevLink = ellCount(&precord->rdes->devList) > 0 &&1100 isDevLink = ellCount(&precord->rdes->devList) > 0 && pfldDes->isDevLink;
1078 pfldDes->isDevLink;
10791101
1080 memset(&locker, 0, sizeof(locker));1102 memset(&locker, 0, sizeof(locker));
1081 lockrecs[0] = precord;1103 lockrecs[0] = precord;
1082 lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL;1104 lockrecs[1] = chan ? dbChannelRecord(chan) : NULL;
1083 dbLockerPrepare(&locker, lockrecs, 2);1105 dbLockerPrepare(&locker, lockrecs, 2);
10841106
1085 dbScanLockMany(&locker);1107 dbScanLockMany(&locker);
@@ -1130,17 +1152,19 @@ static long dbPutFieldLink(DBADDR *paddr,
11301152
1131 if (dbLinkIsDefined(plink)) {1153 if (dbLinkIsDefined(plink)) {
1132 dbRemoveLink(&locker, plink); /* Clear out old link */1154 dbRemoveLink(&locker, plink); /* Clear out old link */
1133 }1155 } else if (!isDevLink) {
1134 else if (!isDevLink) {
1135 status = S_db_badHWaddr;1156 status = S_db_badHWaddr;
1136 goto restoreScan;1157 goto restoreScan;
1137 }1158 }
11381159
1139 if (special) status = dbPutSpecial(paddr, 0);1160 if (special)
1161 status = dbPutSpecial(paddr, 0);
11401162
1141 if (!status) status = dbSetLink(plink, &link_info, new_devsup);1163 if (!status)
1164 status = dbSetLink(plink, &link_info, new_devsup);
11421165
1143 if (!status && special) status = dbPutSpecial(paddr, 1);1166 if (!status && special)
1167 status = dbPutSpecial(paddr, 1);
11441168
1145 if (status) {1169 if (status) {
1146 if (isDevLink) {1170 if (isDevLink) {
@@ -1163,19 +1187,20 @@ static long dbPutFieldLink(DBADDR *paddr,
1163 }1187 }
1164 }1188 }
11651189
1166 switch (plink->type) { /* New link type */1190 switch (plink->type) { /* New link type */
1167 case PV_LINK:1191 case PV_LINK:
1168 case CONSTANT:1192 case CONSTANT:
1169 case JSON_LINK:1193 case JSON_LINK:
1170 dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);1194 dbAddLink(&locker, plink, pfldDes->field_type, chan);
1195 chan = NULL; /* don't clean it up */
1171 break;1196 break;
11721197
1173 case DB_LINK:1198 case DB_LINK:
1174 case CA_LINK:1199 case CA_LINK:
1175 case MACRO_LINK:1200 case MACRO_LINK:
1176 break; /* should never get here */1201 break; /* should never get here */
11771202
1178 default: /* Hardware address */1203 default: /* Hardware address */
1179 if (!isDevLink) {1204 if (!isDevLink) {
1180 status = S_db_badHWaddr;1205 status = S_db_badHWaddr;
1181 goto postScanEvent;1206 goto postScanEvent;
@@ -1184,19 +1209,20 @@ static long dbPutFieldLink(DBADDR *paddr,
1184 }1209 }
1185 db_post_events(precord, plink, DBE_VALUE | DBE_LOG);1210 db_post_events(precord, plink, DBE_VALUE | DBE_LOG);
11861211
1187restoreScan:1212 restoreScan:
1188 if (isDevLink &&1213 if (isDevLink && scan == menuScanI_O_Intr) { /* undo scanDelete() */
1189 scan == menuScanI_O_Intr) { /* undo scanDelete() */
1190 precord->scan = scan;1214 precord->scan = scan;
1191 scanAdd(precord);1215 scanAdd(precord);
1192 }1216 }
1193postScanEvent:1217 postScanEvent:
1194 if (scan != precord->scan)1218 if (scan != precord->scan)
1195 db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);1219 db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
1196unlock:1220 unlock:
1197 dbScanUnlockMany(&locker);1221 dbScanUnlockMany(&locker);
1198 dbLockerFinalize(&locker);1222 dbLockerFinalize(&locker);
1199cleanup:1223 cleanup:
1224 if (chan)
1225 dbChannelDelete(chan);
1200 free(link_info.target);1226 free(link_info.target);
1201 return status;1227 return status;
1202}1228}
@@ -1204,16 +1230,16 @@ cleanup:
1204long dbPutField(DBADDR *paddr, short dbrType,1230long dbPutField(DBADDR *paddr, short dbrType,
1205 const void *pbuffer, long nRequest)1231 const void *pbuffer, long nRequest)
1206{1232{
1207 long status = 0;1233 long status = 0;
1208 long special = paddr->special;1234 long special = paddr->special;
1209 dbFldDes *pfldDes = paddr->pfldDes;1235 dbFldDes *pfldDes = paddr->pfldDes;
1210 dbCommon *precord = paddr->precord;1236 dbCommon *precord = paddr->precord;
1211 short dbfType = paddr->field_type;1237 short dbfType = paddr->field_type;
12121238
1213 if (special == SPC_ATTRIBUTE)1239 if (special == SPC_ATTRIBUTE)
1214 return S_db_noMod;1240 return S_db_noMod;
12151241
1216 /*check for putField disabled*/1242 /*check for putField disabled */
1217 if (precord->disp && paddr->pfield != &precord->disp)1243 if (precord->disp && paddr->pfield != &precord->disp)
1218 return S_db_putDisabled;1244 return S_db_putDisabled;
12191245
@@ -1225,8 +1251,7 @@ long dbPutField(DBADDR *paddr, short dbrType,
1225 if (status == 0) {1251 if (status == 0) {
1226 if (paddr->pfield == &precord->proc ||1252 if (paddr->pfield == &precord->proc ||
1227 (pfldDes->process_passive &&1253 (pfldDes->process_passive &&
1228 precord->scan == 0 &&1254 precord->scan == 0 && dbrType < DBR_PUT_ACKT)) {
1229 dbrType < DBR_PUT_ACKT)) {
1230 if (precord->pact) {1255 if (precord->pact) {
1231 if (dbAccessDebugPUTF && precord->tpro)1256 if (dbAccessDebugPUTF && precord->tpro)
1232 printf("%s: dbPutField to Active '%s', setting RPRO=1\n",1257 printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
@@ -1249,11 +1274,11 @@ static long putAckt(DBADDR *paddr, const void *pbuffer, long nRequest,
1249 dbCommon *precord = paddr->precord;1274 dbCommon *precord = paddr->precord;
1250 const unsigned short *ptrans = pbuffer;1275 const unsigned short *ptrans = pbuffer;
12511276
1252 if (*ptrans == precord->ackt) return 0;1277 if (*ptrans == precord->ackt)
1278 return 0;
1253 precord->ackt = *ptrans;1279 precord->ackt = *ptrans;
1254 db_post_events(precord, &precord->ackt, DBE_VALUE | DBE_ALARM);1280 db_post_events(precord, &precord->ackt, DBE_VALUE | DBE_ALARM);
1255 if (!precord->ackt &&1281 if (!precord->ackt && precord->acks > precord->sevr) {
1256 precord->acks > precord->sevr) {
1257 precord->acks = precord->sevr;1282 precord->acks = precord->sevr;
1258 db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);1283 db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM);
1259 }1284 }
@@ -1275,14 +1300,13 @@ static long putAcks(DBADDR *paddr, const void *pbuffer, long nRequest,
1275 return 0;1300 return 0;
1276}1301}
12771302
1278long dbPut(DBADDR *paddr, short dbrType,1303long dbPut(DBADDR *paddr, short dbrType, const void *pbuffer, long nRequest)
1279 const void *pbuffer, long nRequest)
1280{1304{
1281 dbCommon *precord = paddr->precord;1305 dbCommon *precord = paddr->precord;
1282 short field_type = paddr->field_type;1306 short field_type = paddr->field_type;
1283 long no_elements = paddr->no_elements;1307 long no_elements = paddr->no_elements;
1284 long special = paddr->special;1308 long special = paddr->special;
1285 void *pfieldsave = paddr->pfield;1309 void *pfieldsave = paddr->pfield;
1286 rset *prset = dbGetRset(paddr);1310 rset *prset = dbGetRset(paddr);
1287 long status = 0;1311 long status = 0;
1288 long offset;1312 long offset;
@@ -1306,7 +1330,8 @@ long dbPut(DBADDR *paddr, short dbrType,
13061330
1307 if (special) {1331 if (special) {
1308 status = dbPutSpecial(paddr, 0);1332 status = dbPutSpecial(paddr, 0);
1309 if (status) return status;1333 if (status)
1334 return status;
1310 }1335 }
13111336
1312 if (paddr->pfldDes->special == SPC_DBADDR &&1337 if (paddr->pfldDes->special == SPC_DBADDR &&
@@ -1315,18 +1340,19 @@ long dbPut(DBADDR *paddr, short dbrType,
13151340
1316 status = prset->get_array_info(paddr, &dummy, &offset);1341 status = prset->get_array_info(paddr, &dummy, &offset);
1317 /* paddr->pfield may be modified */1342 /* paddr->pfield may be modified */
1318 if (status) goto done;1343 if (status)
1344 goto done;
1319 } else1345 } else
1320 offset = 0;1346 offset = 0;
13211347
1322 if (no_elements <= 1) {1348 if (no_elements <= 1) {
1323 status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,1349 status = dbFastPutConvertRoutine[dbrType][field_type] (pbuffer,
1324 paddr->pfield, paddr);1350 paddr->pfield, paddr);
1325 nRequest = 1;1351 nRequest = 1;
1326 } else {1352 } else {
1327 if (no_elements < nRequest)1353 if (no_elements < nRequest)
1328 nRequest = no_elements;1354 nRequest = no_elements;
1329 status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,1355 status = dbPutConvertRoutine[dbrType][field_type] (paddr, pbuffer,
1330 nRequest, no_elements, offset);1356 nRequest, no_elements, offset);
1331 }1357 }
13321358
@@ -1340,17 +1366,19 @@ long dbPut(DBADDR *paddr, short dbrType,
1340 /* Always do special processing if needed */1366 /* Always do special processing if needed */
1341 if (special) {1367 if (special) {
1342 long status2 = dbPutSpecial(paddr, 1);1368 long status2 = dbPutSpecial(paddr, 1);
1343 if (status2) goto done;1369 if (status2)
1370 goto done;
1344 }1371 }
1345 if (status) goto done;1372 if (status)
1373 goto done;
13461374
1347 /* Propagate monitor events for this field, */1375 /* Propagate monitor events for this field, */
1348 /* unless the field is VAL and PP is true. */1376 /* unless the field is VAL and PP is true. */
1349 pfldDes = paddr->pfldDes;1377 pfldDes = paddr->pfldDes;
1350 isValueField = dbIsValueField(pfldDes);1378 isValueField = dbIsValueField(pfldDes);
1351 if (isValueField) precord->udf = FALSE;1379 if (isValueField)
1352 if (precord->mlis.count &&1380 precord->udf = FALSE;
1353 !(isValueField && pfldDes->process_passive))1381 if (precord->mlis.count && !(isValueField && pfldDes->process_passive))
1354 db_post_events(precord, pfieldsave, DBE_VALUE | DBE_LOG);1382 db_post_events(precord, pfieldsave, DBE_VALUE | DBE_LOG);
1355 /* If this field is a property (metadata) field,1383 /* If this field is a property (metadata) field,
1356 * then post a property change event (even if the field1384 * then post a property change event (even if the field
@@ -1358,7 +1386,7 @@ long dbPut(DBADDR *paddr, short dbrType,
1358 */1386 */
1359 if (precord->mlis.count && pfldDes->prop)1387 if (precord->mlis.count && pfldDes->prop)
1360 db_post_events(precord, NULL, DBE_PROPERTY);1388 db_post_events(precord, NULL, DBE_PROPERTY);
1361done:1389 done:
1362 paddr->pfield = pfieldsave;1390 paddr->pfield = pfieldsave;
1363 return status;1391 return status;
1364}1392}
diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h
index 805dfd4..4a95989 100644
--- a/modules/database/src/ioc/db/dbAccessDefs.h
+++ b/modules/database/src/ioc/db/dbAccessDefs.h
@@ -243,7 +243,7 @@ epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
243epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset);243epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset);
244epicsShareFunc long dbGetField(244epicsShareFunc long dbGetField(
245 struct dbAddr *,short dbrType,void *pbuffer,long *options,245 struct dbAddr *,short dbrType,void *pbuffer,long *options,
246 long *nRequest,void *pfl);246 long *nRequest);
247epicsShareFunc long dbGet(247epicsShareFunc long dbGet(
248 struct dbAddr *,short dbrType,void *pbuffer,long *options,248 struct dbAddr *,short dbrType,void *pbuffer,long *options,
249 long *nRequest,void *pfl);249 long *nRequest,void *pfl);
diff --git a/modules/database/src/ioc/db/dbChannel.c b/modules/database/src/ioc/db/dbChannel.c
index bc3c8e4..e361f3b 100644
--- a/modules/database/src/ioc/db/dbChannel.c
+++ b/modules/database/src/ioc/db/dbChannel.c
@@ -49,14 +49,12 @@ typedef struct parseContext {
4949
50static void *dbChannelFreeList;50static void *dbChannelFreeList;
51static void *chFilterFreeList;51static void *chFilterFreeList;
52static void *dbchStringFreeList;
5352
54void dbChannelExit(void)53void dbChannelExit(void)
55{54{
56 freeListCleanup(dbChannelFreeList);55 freeListCleanup(dbChannelFreeList);
57 freeListCleanup(chFilterFreeList);56 freeListCleanup(chFilterFreeList);
58 freeListCleanup(dbchStringFreeList);57 dbChannelFreeList = chFilterFreeList = NULL;
59 dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL;
60}58}
6159
62void dbChannelInit (void)60void dbChannelInit (void)
@@ -66,7 +64,7 @@ void dbChannelInit (void)
6664
67 freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);65 freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
68 freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);66 freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
69 freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);67 db_init_event_freelists();
70}68}
7169
72static void chf_value(parseContext *parser, parse_result *presult)70static void chf_value(parseContext *parser, parse_result *presult)
@@ -445,28 +443,6 @@ static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppn
445 return status;443 return status;
446}444}
447445
448/* Stolen from dbAccess.c: */
449static short mapDBFToDBR[DBF_NTYPES] =
450 {
451 /* DBF_STRING => */DBR_STRING,
452 /* DBF_CHAR => */DBR_CHAR,
453 /* DBF_UCHAR => */DBR_UCHAR,
454 /* DBF_SHORT => */DBR_SHORT,
455 /* DBF_USHORT => */DBR_USHORT,
456 /* DBF_LONG => */DBR_LONG,
457 /* DBF_ULONG => */DBR_ULONG,
458 /* DBF_INT64 => */DBR_INT64,
459 /* DBF_UINT64 => */DBR_UINT64,
460 /* DBF_FLOAT => */DBR_FLOAT,
461 /* DBF_DOUBLE => */DBR_DOUBLE,
462 /* DBF_ENUM, => */DBR_ENUM,
463 /* DBF_MENU, => */DBR_ENUM,
464 /* DBF_DEVICE => */DBR_ENUM,
465 /* DBF_INLINK => */DBR_STRING,
466 /* DBF_OUTLINK => */DBR_STRING,
467 /* DBF_FWDLINK => */DBR_STRING,
468 /* DBF_NOACCESS => */DBR_NOACCESS };
469
470dbChannel * dbChannelCreate(const char *name)446dbChannel * dbChannelCreate(const char *name)
471{447{
472 const char *pname = name;448 const char *pname = name;
@@ -735,39 +711,6 @@ void dbChannelDelete(dbChannel *chan)
735 freeListFree(dbChannelFreeList, chan);711 freeListFree(dbChannelFreeList, chan);
736}712}
737713
738static void freeArray(db_field_log *pfl) {
739 if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
740 freeListFree(dbchStringFreeList, pfl->u.r.field);
741 } else {
742 free(pfl->u.r.field);
743 }
744}
745
746void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
747{
748 void *p;
749 struct dbCommon *prec = dbChannelRecord(chan);
750
751 if (pfl->type != dbfl_type_rec) return;
752
753 pfl->type = dbfl_type_ref;
754 pfl->stat = prec->stat;
755 pfl->sevr = prec->sevr;
756 pfl->time = prec->time;
757 pfl->field_type = chan->addr.field_type;
758 pfl->no_elements = chan->addr.no_elements;
759 pfl->field_size = chan->addr.field_size;
760 pfl->u.r.dtor = freeArray;
761 pfl->u.r.pvt = pvt;
762 if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
763 p = freeListCalloc(dbchStringFreeList);
764 } else {
765 p = calloc(pfl->no_elements, pfl->field_size);
766 }
767 if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL);
768 pfl->u.r.field = p;
769}
770
771/* FIXME: Do these belong in a different file? */714/* FIXME: Do these belong in a different file? */
772715
773void dbRegisterFilter(const char *name, const chFilterIf *fif, void *puser)716void dbRegisterFilter(const char *name, const chFilterIf *fif, void *puser)
diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h
index fab9c66..6e98dee 100644
--- a/modules/database/src/ioc/db/dbChannel.h
+++ b/modules/database/src/ioc/db/dbChannel.h
@@ -64,8 +64,9 @@ typedef struct dbChannel {
64/* Prototype for the channel event function that is called in filter stacks64/* Prototype for the channel event function that is called in filter stacks
65 *65 *
66 * When invoked the scan lock for the record associated with 'chan' _may_ be locked.66 * When invoked the scan lock for the record associated with 'chan' _may_ be locked.
67 * If pLog->type==dbfl_type_rec then dbScanLock() must be called before copying67 * If pLog->type==dbfl_type_ref and pLog->u.r.dtor is NULL, then dbScanLock() must
68 * data out of the associated record.68 * be called before accessing the data, as this indicates the data is owned by the
69 * record.
69 *70 *
70 * This function has ownership of the field log pLog, if it wishes to discard71 * This function has ownership of the field log pLog, if it wishes to discard
71 * this update it should free the field log with db_delete_field_log() and72 * this update it should free the field log with db_delete_field_log() and
@@ -224,7 +225,6 @@ epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, voi
224epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);225epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
225epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);226epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
226epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);227epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);
227epicsShareFunc void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan);
228228
229#ifdef __cplusplus229#ifdef __cplusplus
230}230}
diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c
index f2cb0c5..8677add 100644
--- a/modules/database/src/ioc/db/dbDbLink.c
+++ b/modules/database/src/ioc/db/dbDbLink.c
@@ -60,6 +60,7 @@
60#include "dbConvertFast.h"60#include "dbConvertFast.h"
61#include "dbConvert.h"61#include "dbConvert.h"
62#include "db_field_log.h"62#include "db_field_log.h"
63#include "db_access_routines.h"
63#include "dbFldTypes.h"64#include "dbFldTypes.h"
64#include "dbLink.h"65#include "dbLink.h"
65#include "dbLockPvt.h"66#include "dbLockPvt.h"
@@ -73,7 +74,7 @@
73#include "recSup.h"74#include "recSup.h"
74#include "special.h"75#include "special.h"
75#include "dbDbLink.h"76#include "dbDbLink.h"
7677#include "dbChannel.h"
7778
78/***************************** Database Links *****************************/79/***************************** Database Links *****************************/
7980
@@ -82,45 +83,51 @@ static lset dbDb_lset;
8283
83static long processTarget(dbCommon *psrc, dbCommon *pdst);84static long processTarget(dbCommon *psrc, dbCommon *pdst);
8485
86#define linkChannel(plink) ((dbChannel *) (plink)->value.pv_link.pvt)
87
85long dbDbInitLink(struct link *plink, short dbfType)88long dbDbInitLink(struct link *plink, short dbfType)
86{89{
87 DBADDR dbaddr;
88 long status;90 long status;
89 DBADDR *pdbAddr;91 dbChannel *chan;
92 dbCommon *precord;
9093
91 status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);94 chan = dbChannelCreate(plink->value.pv_link.pvname);
95 if (!chan)
96 return S_db_notFound;
97 status = dbChannelOpen(chan);
92 if (status)98 if (status)
93 return status;99 return status;
94100
101 precord = dbChannelRecord(chan);
102
95 plink->lset = &dbDb_lset;103 plink->lset = &dbDb_lset;
96 plink->type = DB_LINK;104 plink->type = DB_LINK;
97 pdbAddr = dbCalloc(1, sizeof(struct dbAddr));105 plink->value.pv_link.pvt = chan;
98 *pdbAddr = dbaddr; /* structure copy */106 ellAdd(&precord->bklnk, &plink->value.pv_link.backlinknode);
99 plink->value.pv_link.pvt = pdbAddr;
100 ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
101 /* merging into the same lockset is deferred to the caller.107 /* merging into the same lockset is deferred to the caller.
102 * cf. initPVLinks()108 * cf. initPVLinks()
103 */109 */
104 dbLockSetMerge(NULL, plink->precord, dbaddr.precord);110 dbLockSetMerge(NULL, plink->precord, precord);
105 assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);111 assert(plink->precord->lset->plockSet == precord->lset->plockSet);
106 return 0;112 return 0;
107}113}
108114
109void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,115void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
110 DBADDR *ptarget)116 dbChannel *chan)
111{117{
112 plink->lset = &dbDb_lset;118 plink->lset = &dbDb_lset;
113 plink->type = DB_LINK;119 plink->type = DB_LINK;
114 plink->value.pv_link.pvt = ptarget;120 plink->value.pv_link.pvt = chan;
115 ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);121 ellAdd(&dbChannelRecord(chan)->bklnk, &plink->value.pv_link.backlinknode);
116122
117 /* target record is already locked in dbPutFieldLink() */123 /* target record is already locked in dbPutFieldLink() */
118 dbLockSetMerge(locker, plink->precord, ptarget->precord);124 dbLockSetMerge(locker, plink->precord, dbChannelRecord(chan));
119}125}
120126
121static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)127static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
122{128{
123 DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;129 dbChannel *chan = linkChannel(plink);
130 dbCommon *precord = dbChannelRecord(chan);
124131
125 plink->type = PV_LINK;132 plink->type = PV_LINK;
126133
@@ -130,10 +137,10 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
130 plink->value.pv_link.getCvt = 0;137 plink->value.pv_link.getCvt = 0;
131 plink->value.pv_link.pvlMask = 0;138 plink->value.pv_link.pvlMask = 0;
132 plink->value.pv_link.lastGetdbrType = 0;139 plink->value.pv_link.lastGetdbrType = 0;
133 ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);140 ellDelete(&precord->bklnk, &plink->value.pv_link.backlinknode);
134 dbLockSetSplit(locker, plink->precord, pdbAddr->precord);141 dbLockSetSplit(locker, plink->precord, precord);
135 }142 }
136 free(pdbAddr);143 dbChannelDelete(chan);
137}144}
138145
139static int dbDbIsConnected(const struct link *plink)146static int dbDbIsConnected(const struct link *plink)
@@ -143,16 +150,14 @@ static int dbDbIsConnected(const struct link *plink)
143150
144static int dbDbGetDBFtype(const struct link *plink)151static int dbDbGetDBFtype(const struct link *plink)
145{152{
146 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;153 dbChannel *chan = linkChannel(plink);
147154 return dbChannelFinalFieldType(chan);
148 return paddr->field_type;
149}155}
150156
151static long dbDbGetElements(const struct link *plink, long *nelements)157static long dbDbGetElements(const struct link *plink, long *nelements)
152{158{
153 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;159 dbChannel *chan = linkChannel(plink);
154160 *nelements = dbChannelFinalElements(chan);
155 *nelements = paddr->no_elements;
156 return 0;161 return 0;
157}162}
158163
@@ -160,30 +165,52 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
160 long *pnRequest)165 long *pnRequest)
161{166{
162 struct pv_link *ppv_link = &plink->value.pv_link;167 struct pv_link *ppv_link = &plink->value.pv_link;
163 DBADDR *paddr = ppv_link->pvt;168 dbChannel *chan = linkChannel(plink);
169 DBADDR *paddr = &chan->addr;
164 dbCommon *precord = plink->precord;170 dbCommon *precord = plink->precord;
165 long status;171 long status;
166172
167 /* scan passive records if link is process passive */173 /* scan passive records if link is process passive */
168 if (ppv_link->pvlMask & pvlOptPP) {174 if (ppv_link->pvlMask & pvlOptPP) {
169 status = dbScanPassive(precord, paddr->precord);175 status = dbScanPassive(precord, dbChannelRecord(chan));
170 if (status)176 if (status)
171 return status;177 return status;
172 }178 }
173179
174 if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {180 /* If filters are involved in a read, create field log and run filters */
175 status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);181 if (ellCount(&chan->filters)) {
182 db_field_log *pfl;
183
184 /*
185 * For the moment, empty arrays are not supported by EPICS.
186 * See the remark in src/std/filters/arr.c for details.
187 */
188 if (dbChannelFinalElements(chan) <= 0) /* empty array request */
189 return S_db_badField;
190 pfl = db_create_read_log(chan);
191 if (!pfl)
192 return S_db_noMemory;
193 pfl = dbChannelRunPreChain(chan, pfl);
194 pfl = dbChannelRunPostChain(chan, pfl);
195 status = dbChannelGet(chan, dbrType, pbuffer, NULL, pnRequest, pfl);
196 db_delete_field_log(pfl);
197 if (status)
198 return status;
199 if (pnRequest && *pnRequest <= 0) /* empty array result */
200 return S_db_badField;
201 } else if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
202 status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
176 } else {203 } else {
177 unsigned short dbfType = paddr->field_type;204 unsigned short dbfType = dbChannelFinalFieldType(chan);
178205
179 if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)206 if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
180 return S_db_badDbrtype;207 return S_db_badDbrtype;
181208
182 if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)209 if (dbChannelFinalElements(chan) == 1 && (!pnRequest || *pnRequest == 1)
183 && paddr->special != SPC_DBADDR210 && dbChannelSpecial(chan) != SPC_DBADDR
184 && paddr->special != SPC_ATTRIBUTE) {211 && dbChannelSpecial(chan) != SPC_ATTRIBUTE) {
185 ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];212 ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
186 status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);213 status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
187 } else {214 } else {
188 ppv_link->getCvt = NULL;215 ppv_link->getCvt = NULL;
189 status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);216 status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
@@ -191,16 +218,18 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
191 ppv_link->lastGetdbrType = dbrType;218 ppv_link->lastGetdbrType = dbrType;
192 }219 }
193220
194 if (!status && precord != paddr->precord)221 if (!status && precord != dbChannelRecord(chan))
195 recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,222 recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
196 plink->precord, paddr->precord->stat, paddr->precord->sevr);223 plink->precord,
224 dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr);
197 return status;225 return status;
198}226}
199227
200static long dbDbGetControlLimits(const struct link *plink, double *low,228static long dbDbGetControlLimits(const struct link *plink, double *low,
201 double *high)229 double *high)
202{230{
203 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;231 dbChannel *chan = linkChannel(plink);
232 DBADDR *paddr = &chan->addr;
204 struct buffer {233 struct buffer {
205 DBRctrlDouble234 DBRctrlDouble
206 double value;235 double value;
@@ -221,7 +250,8 @@ static long dbDbGetControlLimits(const struct link *plink, double *low,
221static long dbDbGetGraphicLimits(const struct link *plink, double *low,250static long dbDbGetGraphicLimits(const struct link *plink, double *low,
222 double *high)251 double *high)
223{252{
224 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;253 dbChannel *chan = linkChannel(plink);
254 DBADDR *paddr = &chan->addr;
225 struct buffer {255 struct buffer {
226 DBRgrDouble256 DBRgrDouble
227 double value;257 double value;
@@ -242,7 +272,8 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low,
242static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,272static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
243 double *low, double *high, double *hihi)273 double *low, double *high, double *hihi)
244{274{
245 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;275 dbChannel *chan = linkChannel(plink);
276 DBADDR *paddr = &chan->addr;
246 struct buffer {277 struct buffer {
247 DBRalDouble278 DBRalDouble
248 double value;279 double value;
@@ -264,7 +295,8 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
264295
265static long dbDbGetPrecision(const struct link *plink, short *precision)296static long dbDbGetPrecision(const struct link *plink, short *precision)
266{297{
267 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;298 dbChannel *chan = linkChannel(plink);
299 DBADDR *paddr = &chan->addr;
268 struct buffer {300 struct buffer {
269 DBRprecision301 DBRprecision
270 double value;302 double value;
@@ -283,7 +315,8 @@ static long dbDbGetPrecision(const struct link *plink, short *precision)
283315
284static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)316static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
285{317{
286 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;318 dbChannel *chan = linkChannel(plink);
319 DBADDR *paddr = &chan->addr;
287 struct buffer {320 struct buffer {
288 DBRunits321 DBRunits
289 double value;322 double value;
@@ -303,20 +336,20 @@ static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
303static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,336static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
304 epicsEnum16 *severity)337 epicsEnum16 *severity)
305{338{
306 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;339 dbChannel *chan = linkChannel(plink);
307340 dbCommon *precord = dbChannelRecord(chan);
308 if (status)341 if (status)
309 *status = paddr->precord->stat;342 *status = precord->stat;
310 if (severity)343 if (severity)
311 *severity = paddr->precord->sevr;344 *severity = precord->sevr;
312 return 0;345 return 0;
313}346}
314347
315static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)348static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
316{349{
317 DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;350 dbChannel *chan = linkChannel(plink);
318351 dbCommon *precord = dbChannelRecord(chan);
319 *pstamp = paddr->precord->time;352 *pstamp = precord->time;
320 return 0;353 return 0;
321}354}
322355
@@ -324,9 +357,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
324 const void *pbuffer, long nRequest)357 const void *pbuffer, long nRequest)
325{358{
326 struct pv_link *ppv_link = &plink->value.pv_link;359 struct pv_link *ppv_link = &plink->value.pv_link;
360 dbChannel *chan = linkChannel(plink);
327 struct dbCommon *psrce = plink->precord;361 struct dbCommon *psrce = plink->precord;
328 DBADDR *paddr = (DBADDR *) ppv_link->pvt;362 DBADDR *paddr = &chan->addr;
329 dbCommon *pdest = paddr->precord;363 dbCommon *pdest = dbChannelRecord(chan);
330 long status = dbPut(paddr, dbrType, pbuffer, nRequest);364 long status = dbPut(paddr, dbrType, pbuffer, nRequest);
331365
332 recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,366 recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
@@ -334,7 +368,7 @@ static long dbDbPutValue(struct link *plink, short dbrType,
334 if (status)368 if (status)
335 return status;369 return status;
336370
337 if (paddr->pfield == (void *) &pdest->proc ||371 if (dbChannelField(chan) == (void *) &pdest->proc ||
338 (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {372 (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
339 status = processTarget(psrce, pdest);373 status = processTarget(psrce, pdest);
340 }374 }
@@ -345,9 +379,8 @@ static long dbDbPutValue(struct link *plink, short dbrType,
345static void dbDbScanFwdLink(struct link *plink)379static void dbDbScanFwdLink(struct link *plink)
346{380{
347 dbCommon *precord = plink->precord;381 dbCommon *precord = plink->precord;
348 dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;382 dbChannel *chan = linkChannel(plink);
349383 dbScanPassive(precord, dbChannelRecord(chan));
350 dbScanPassive(precord, paddr->precord);
351}384}
352385
353static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)386static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
diff --git a/modules/database/src/ioc/db/dbDbLink.h b/modules/database/src/ioc/db/dbDbLink.h
index c367720..27972d8 100644
--- a/modules/database/src/ioc/db/dbDbLink.h
+++ b/modules/database/src/ioc/db/dbDbLink.h
@@ -26,7 +26,7 @@ struct dbLocker;
2626
27epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);27epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
28epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,28epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
29 short dbfType, DBADDR *ptarget);29 short dbfType, dbChannel *ptarget);
3030
31#ifdef __cplusplus31#ifdef __cplusplus
32}32}
diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c
index 0d96e12..532c2ba 100644
--- a/modules/database/src/ioc/db/dbEvent.c
+++ b/modules/database/src/ioc/db/dbEvent.c
@@ -251,18 +251,15 @@ int dbel ( const char *pname, unsigned level )
251}251}
252252
253/*253/*
254 * DB_INIT_EVENTS()254 * DB_INIT_EVENT_FREELISTS()
255 *255 *
256 *256 *
257 * Initialize the event facility for this task. Must be called at least once257 * Initialize the free lists used by the event facility.
258 * by each task which uses the db event facility258 * Safe to be called multiple times.
259 *259 *
260 * returns: ptr to event user block or NULL if memory can't be allocated
261 */260 */
262dbEventCtx db_init_events (void)261void db_init_event_freelists (void)
263{262{
264 struct event_user * evUser;
265
266 if (!dbevEventUserFreeList) {263 if (!dbevEventUserFreeList) {
267 freeListInitPvt(&dbevEventUserFreeList,264 freeListInitPvt(&dbevEventUserFreeList,
268 sizeof(struct event_user),8);265 sizeof(struct event_user),8);
@@ -279,6 +276,22 @@ dbEventCtx db_init_events (void)
279 freeListInitPvt(&dbevFieldLogFreeList,276 freeListInitPvt(&dbevFieldLogFreeList,
280 sizeof(struct db_field_log),2048);277 sizeof(struct db_field_log),2048);
281 }278 }
279}
280
281/*
282 * DB_INIT_EVENTS()
283 *
284 *
285 * Initialize the event facility for this task. Must be called at least once
286 * by each task which uses the db event facility
287 *
288 * returns: ptr to event user block or NULL if memory can't be allocated
289 */
290dbEventCtx db_init_events (void)
291{
292 struct event_user * evUser;
293
294 db_init_event_freelists();
282295
283 evUser = (struct event_user *)296 evUser = (struct event_user *)
284 freeListCalloc(dbevEventUserFreeList);297 freeListCalloc(dbevEventUserFreeList);
@@ -654,27 +667,22 @@ int db_post_extra_labor (dbEventCtx ctx)
654 return DB_EVENT_OK;667 return DB_EVENT_OK;
655}668}
656669
657/*670static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
658 * DB_CREATE_EVENT_LOG()
659 *
660 * NOTE: This assumes that the db scan lock is already applied
661 * (as it copies data from the record)
662 */
663db_field_log* db_create_event_log (struct evSubscrip *pevent)
664{671{
665 db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);672 db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
666673
667 if (pLog) {674 if (pLog) {
668 struct dbChannel *chan = pevent->chan;
669 struct dbCommon *prec = dbChannelRecord(chan);675 struct dbCommon *prec = dbChannelRecord(chan);
670 pLog->ctx = dbfl_context_event;676 pLog->stat = prec->stat;
671 if (pevent->useValque) {677 pLog->sevr = prec->sevr;
678 pLog->time = prec->time;
679 pLog->field_type = dbChannelFieldType(chan);
680 pLog->field_size = dbChannelFieldSize(chan);
681 pLog->no_elements = dbChannelElements(chan);
682 pLog->offset = 0;
683
684 if (use_val) {
672 pLog->type = dbfl_type_val;685 pLog->type = dbfl_type_val;
673 pLog->stat = prec->stat;
674 pLog->sevr = prec->sevr;
675 pLog->time = prec->time;
676 pLog->field_type = dbChannelFieldType(chan);
677 pLog->no_elements = dbChannelElements(chan);
678 /*686 /*
679 * use memcpy to avoid a bus error on687 * use memcpy to avoid a bus error on
680 * union copy of char in the db at an odd688 * union copy of char in the db at an odd
@@ -684,23 +692,62 @@ db_field_log* db_create_event_log (struct evSubscrip *pevent)
684 dbChannelField(chan),692 dbChannelField(chan),
685 dbChannelFieldSize(chan));693 dbChannelFieldSize(chan));
686 } else {694 } else {
687 pLog->type = dbfl_type_rec;695 rset *prset;
696
697 pLog->type = dbfl_type_ref;
698
699 if (dbChannelSpecial(chan) == SPC_DBADDR &&
700 (prset = dbGetRset(&chan->addr)) &&
701 prset->get_array_info)
702 /* This condition implies !use_val, see db_add_event */
703 {
704 void *pfieldsave = dbChannelField(chan);
705 prec = dbChannelRecord(chan);
706 prset->get_array_info(&chan->addr, &pLog->no_elements, &pLog->offset);
707 /* don't make a copy yet, just reference the field value */
708 pLog->u.r.field = dbChannelField(chan);
709 dbChannelField(chan) = pfieldsave;
710 }
711 else {
712 /* don't make a copy yet, just reference the field value */
713 pLog->u.r.field = dbChannelField(chan);
714 }
715 /* indicate field value still owned by record */
716 pLog->u.r.dtor = NULL;
717 /* no private data yet, may be set by a filter */
718 pLog->u.r.pvt = NULL;
688 }719 }
689 }720 }
690 return pLog;721 return pLog;
691}722}
692723
693/*724/*
725 * DB_CREATE_EVENT_LOG()
726 *
727 * NOTE: This assumes that the db scan lock is already applied
728 * (as it calls rset->get_array_info)
729 */
730db_field_log* db_create_event_log (struct evSubscrip *pevent)
731{
732 db_field_log *pLog = db_create_field_log(pevent->chan, pevent->useValque);
733 if (pLog) {
734 pLog->ctx = dbfl_context_event;
735 }
736 return pLog;
737}
738
739/*
694 * DB_CREATE_READ_LOG()740 * DB_CREATE_READ_LOG()
695 *741 *
696 */742 */
697db_field_log* db_create_read_log (struct dbChannel *chan)743db_field_log* db_create_read_log (struct dbChannel *chan)
698{744{
699 db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);745 db_field_log *pLog = db_create_field_log(chan,
700746 dbChannelElements(chan) == 1 &&
747 dbChannelSpecial(chan) != SPC_DBADDR &&
748 dbChannelFieldSize(chan) <= sizeof(union native_value));
701 if (pLog) {749 if (pLog) {
702 pLog->ctx = dbfl_context_read;750 pLog->ctx = dbfl_context_read;
703 pLog->type = dbfl_type_rec;
704 }751 }
705 return pLog;752 return pLog;
706}753}
@@ -724,20 +771,6 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
724 LOCKEVQUE (ev_que);771 LOCKEVQUE (ev_que);
725772
726 /*773 /*
727 * if we have an event on the queue and both the last
728 * event on the queue and the current event are emtpy
729 * (i.e. of type dbfl_type_rec), simply ignore duplicate
730 * events (saving empty events serves no purpose)
731 */
732 if (pevent->npend > 0u &&
733 (*pevent->pLastLog)->type == dbfl_type_rec &&
734 pLog->type == dbfl_type_rec) {
735 db_delete_field_log(pLog);
736 UNLOCKEVQUE (ev_que);
737 return;
738 }
739
740 /*
741 * add to task local event que774 * add to task local event que
742 */775 */
743776
diff --git a/modules/database/src/ioc/db/dbEvent.h b/modules/database/src/ioc/db/dbEvent.h
index 374e849..175b0e4 100644
--- a/modules/database/src/ioc/db/dbEvent.h
+++ b/modules/database/src/ioc/db/dbEvent.h
@@ -50,6 +50,7 @@ epicsShareFunc int db_post_events (
50typedef void * dbEventCtx;50typedef void * dbEventCtx;
5151
52typedef void EXTRALABORFUNC (void *extralabor_arg);52typedef void EXTRALABORFUNC (void *extralabor_arg);
53void db_init_event_freelists (void);
53epicsShareFunc dbEventCtx db_init_events (void);54epicsShareFunc dbEventCtx db_init_events (void);
54epicsShareFunc int db_start_events (55epicsShareFunc int db_start_events (
55 dbEventCtx ctx, const char *taskname, void (*init_func)(void *),56 dbEventCtx ctx, const char *taskname, void (*init_func)(void *),
diff --git a/modules/database/src/ioc/db/dbExtractArray.c b/modules/database/src/ioc/db/dbExtractArray.c
index e16ab4c..f0ab281 100644
--- a/modules/database/src/ioc/db/dbExtractArray.c
+++ b/modules/database/src/ioc/db/dbExtractArray.c
@@ -13,11 +13,12 @@
13/*13/*
14 * Author: Ralph Lange <Ralph.Lange@bessy.de>14 * Author: Ralph Lange <Ralph.Lange@bessy.de>
15 *15 *
16 * based on dbConvert.c16 * based on dbConvert.c, see copyNoConvert
17 * written by: Bob Dalesio, Marty Kraimer17 * written by: Bob Dalesio, Marty Kraimer
18 */18 */
1919
20#include <string.h>20#include <string.h>
21#include <assert.h>
2122
22#include "epicsTypes.h"23#include "epicsTypes.h"
2324
@@ -25,61 +26,31 @@
25#include "dbAddr.h"26#include "dbAddr.h"
26#include "dbExtractArray.h"27#include "dbExtractArray.h"
2728
28void dbExtractArrayFromRec(const dbAddr *paddr, void *pto,29void dbExtractArray(const void *pfrom, void *pto,
29 long nRequest, long no_elements, long offset, long increment)30 short field_size, short field_type,
31 long nRequest, long no_elements, long offset, long increment)
30{32{
31 char *pdst = (char *) pto;33 char *pdst = (char *) pto;
32 char *psrc = (char *) paddr->pfield;34 const char *psrc = (char *) pfrom;
33 long nUpperPart;
34 int i;
35 short srcSize = paddr->field_size;
36 short dstSize = srcSize;
37 char isString = (paddr->field_type == DBF_STRING);
3835
39 if (nRequest > no_elements) nRequest = no_elements;36 /* assert preconditions */
40 if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE;37 assert(nRequest >= 0);
38 assert(no_elements >= 0);
39 assert(increment > 0);
40 assert(0 <= offset);
41 assert(offset < no_elements);
4142
42 if (increment == 1 && dstSize == srcSize) {43 if (increment == 1) {
43 nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset;44 long nUpperPart =
44 memcpy(pdst, &psrc[offset * srcSize], dstSize * nUpperPart);45 nRequest < no_elements - offset ? nRequest : no_elements - offset;
46 memcpy(pdst, psrc + (offset * field_size), field_size * nUpperPart);
45 if (nRequest > nUpperPart)47 if (nRequest > nUpperPart)
46 memcpy(&pdst[dstSize * nUpperPart], psrc, dstSize * (nRequest - nUpperPart));48 memcpy(pdst + (field_size * nUpperPart), psrc,
47 if (isString)49 field_size * (nRequest - nUpperPart));
48 for (i = 1; i <= nRequest; i++)
49 pdst[dstSize*i-1] = '\0';
50 } else {50 } else {
51 for (; nRequest > 0; nRequest--, pdst += dstSize, offset += increment) {51 for (; nRequest > 0; nRequest--, pdst += field_size, offset += increment) {
52 offset %= no_elements;52 offset %= no_elements;
53 memcpy(pdst, &psrc[offset*srcSize], dstSize);53 memcpy(pdst, psrc + (offset * field_size), field_size);
54 if (isString) pdst[dstSize-1] = '\0';
55 }
56 }
57}
58
59void dbExtractArrayFromBuf(const void *pfrom, void *pto,
60 short field_size, short field_type,
61 long nRequest, long no_elements, long offset, long increment)
62{
63 char *pdst = (char *) pto;
64 char *psrc = (char *) pfrom;
65 int i;
66 short srcSize = field_size;
67 short dstSize = srcSize;
68 char isString = (field_type == DBF_STRING);
69
70 if (nRequest > no_elements) nRequest = no_elements;
71 if (offset > no_elements - 1) offset = no_elements - 1;
72 if (isString && dstSize >= MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE - 1;
73
74 if (increment == 1) {
75 memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest);
76 if (isString)
77 for (i = 1; i <= nRequest; i++)
78 pdst[dstSize*i] = '\0';
79 } else {
80 for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) {
81 memcpy(pdst, &psrc[offset*srcSize], dstSize);
82 if (isString) pdst[dstSize] = '\0';
83 }54 }
84 }55 }
85}56}
diff --git a/modules/database/src/ioc/db/dbExtractArray.h b/modules/database/src/ioc/db/dbExtractArray.h
index 7ed3584..9680660 100644
--- a/modules/database/src/ioc/db/dbExtractArray.h
+++ b/modules/database/src/ioc/db/dbExtractArray.h
@@ -21,11 +21,22 @@
21extern "C" {21extern "C" {
22#endif22#endif
2323
24epicsShareFunc void dbExtractArrayFromRec(const DBADDR *paddr, void *pto,24/*
25 long nRequest, long no_elements, long offset, long increment);25 * This function does not do any conversion. This means we don't have to
26epicsShareFunc void dbExtractArrayFromBuf(const void *pfrom, void *pto,26 * truncate the field_size to MAX_STRING_SIZE or add extra null terminators
27 short field_size, short field_type,27 * for string values. All of this is done by the dbConvert routines which
28 long nRequest, long no_elements, long offset, long increment);28 * will be called whether or not a filter is active.
29 *
30 * Checked preconditions:
31 * - nRequest >= 0, no_elements >= 0, increment > 0
32 * - 0 <= offset < no_elements
33 * Unchecked preconditions:
34 * - pto points to a buffer with at least field_size*nRequest bytes
35 * - pfrom points to a buffer with at least field_size*no_elements bytes
36 */
37epicsShareFunc void dbExtractArray(const void *pfrom, void *pto,
38 short field_size, short field_type,
39 long nRequest, long no_elements, long offset, long increment);
2940
30#ifdef __cplusplus41#ifdef __cplusplus
31}42}
diff --git a/modules/database/src/ioc/db/dbLink.c b/modules/database/src/ioc/db/dbLink.c
index 7c37058..aa72dc8 100644
--- a/modules/database/src/ioc/db/dbLink.c
+++ b/modules/database/src/ioc/db/dbLink.c
@@ -143,7 +143,7 @@ void dbInitLink(struct link *plink, short dbfType)
143}143}
144144
145void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,145void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
146 DBADDR *ptarget)146 dbChannel *ptarget)
147{147{
148 struct dbCommon *precord = plink->precord;148 struct dbCommon *precord = plink->precord;
149149
diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h
index 94e1f32..4255a56 100644
--- a/modules/database/src/ioc/db/dbLink.h
+++ b/modules/database/src/ioc/db/dbLink.h
@@ -20,6 +20,7 @@
20#include "epicsTypes.h"20#include "epicsTypes.h"
21#include "epicsTime.h"21#include "epicsTime.h"
22#include "dbAddr.h"22#include "dbAddr.h"
23#include "dbChannel.h"
2324
24#ifdef __cplusplus25#ifdef __cplusplus
25extern "C" {26extern "C" {
@@ -368,7 +369,7 @@ epicsShareFunc const char * dbLinkFieldName(const struct link *plink);
368369
369epicsShareFunc void dbInitLink(struct link *plink, short dbfType);370epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
370epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,371epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
371 short dbfType, DBADDR *ptarget);372 short dbfType, dbChannel *ptarget);
372373
373epicsShareFunc void dbLinkOpen(struct link *plink);374epicsShareFunc void dbLinkOpen(struct link *plink);
374epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);375epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
diff --git a/modules/database/src/ioc/db/dbLock.c b/modules/database/src/ioc/db/dbLock.c
index 8df755b..19cb1c0 100644
--- a/modules/database/src/ioc/db/dbLock.c
+++ b/modules/database/src/ioc/db/dbLock.c
@@ -743,14 +743,14 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
743 for(i=0; i<rtype->no_links; i++) {743 for(i=0; i<rtype->no_links; i++) {
744 dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]];744 dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]];
745 DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset);745 DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset);
746 DBADDR *ptarget;746 dbChannel *chan;
747 lockRecord *lr;747 lockRecord *lr;
748748
749 if(plink->type!=DB_LINK)749 if(plink->type!=DB_LINK)
750 continue;750 continue;
751751
752 ptarget = plink->value.pv_link.pvt;752 chan = plink->value.pv_link.pvt;
753 lr = ptarget->precord->lset;753 lr = dbChannelRecord(chan)->lset;
754 assert(lr);754 assert(lr);
755755
756 if(lr->precord==pfirst) {756 if(lr->precord==pfirst) {
diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c
index 1193954..206d6c9 100644
--- a/modules/database/src/ioc/db/dbTest.c
+++ b/modules/database/src/ioc/db/dbTest.c
@@ -341,14 +341,14 @@ long dbgf(const char *pname)
341 no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);341 no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);
342 if (addr.dbr_field_type == DBR_ENUM) {342 if (addr.dbr_field_type == DBR_ENUM) {
343 long status = dbGetField(&addr, DBR_STRING, pbuffer,343 long status = dbGetField(&addr, DBR_STRING, pbuffer,
344 &options, &no_elements, NULL);344 &options, &no_elements);
345345
346 printBuffer(status, DBR_STRING, pbuffer, 0L, 0L,346 printBuffer(status, DBR_STRING, pbuffer, 0L, 0L,
347 no_elements, &msg_Buff, 10);347 no_elements, &msg_Buff, 10);
348 }348 }
349 else {349 else {
350 long status = dbGetField(&addr, addr.dbr_field_type, pbuffer,350 long status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
351 &options, &no_elements, NULL);351 &options, &no_elements);
352352
353 printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,353 printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
354 no_elements, &msg_Buff, 10);354 no_elements, &msg_Buff, 10);
@@ -487,7 +487,7 @@ long dbtgf(const char *pname)
487 ret_options = req_options;487 ret_options = req_options;
488 no_elements = 0;488 no_elements = 0;
489 status = dbGetField(&addr, addr.dbr_field_type, pbuffer,489 status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
490 &ret_options, &no_elements, NULL);490 &ret_options, &no_elements);
491 printBuffer(status, addr.dbr_field_type, pbuffer,491 printBuffer(status, addr.dbr_field_type, pbuffer,
492 req_options, ret_options, no_elements, pMsgBuff, tab_size);492 req_options, ret_options, no_elements, pMsgBuff, tab_size);
493493
@@ -496,62 +496,62 @@ long dbtgf(const char *pname)
496496
497 dbr_type = DBR_STRING;497 dbr_type = DBR_STRING;
498 no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));498 no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));
499 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);499 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
500 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);500 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
501501
502 dbr_type = DBR_CHAR;502 dbr_type = DBR_CHAR;
503 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));503 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));
504 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);504 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
505 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);505 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
506506
507 dbr_type = DBR_UCHAR;507 dbr_type = DBR_UCHAR;
508 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));508 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));
509 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);509 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
510 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);510 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
511511
512 dbr_type = DBR_SHORT;512 dbr_type = DBR_SHORT;
513 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));513 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));
514 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);514 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
515 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);515 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
516516
517 dbr_type = DBR_USHORT;517 dbr_type = DBR_USHORT;
518 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));518 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));
519 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);519 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
520 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);520 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
521521
522 dbr_type = DBR_LONG;522 dbr_type = DBR_LONG;
523 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));523 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));
524 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);524 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
525 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);525 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
526526
527 dbr_type = DBR_ULONG;527 dbr_type = DBR_ULONG;
528 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));528 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));
529 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);529 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
530 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);530 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
531531
532 dbr_type = DBR_INT64;532 dbr_type = DBR_INT64;
533 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));533 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
534 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);534 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
535 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);535 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
536536
537 dbr_type = DBR_UINT64;537 dbr_type = DBR_UINT64;
538 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));538 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
539 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);539 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
540 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);540 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
541541
542 dbr_type = DBR_FLOAT;542 dbr_type = DBR_FLOAT;
543 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));543 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
544 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);544 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
545 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);545 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
546546
547 dbr_type = DBR_DOUBLE;547 dbr_type = DBR_DOUBLE;
548 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));548 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));
549 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);549 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
550 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);550 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
551551
552 dbr_type = DBR_ENUM;552 dbr_type = DBR_ENUM;
553 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));553 no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));
554 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);554 status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
555 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);555 printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
556556
557 pmsg[0] = '\0';557 pmsg[0] = '\0';
@@ -651,7 +651,7 @@ long dbtpf(const char *pname, const char *pvalue)
651651
652 printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);652 printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);
653 status = dbGetField(&addr, addr.dbr_field_type, pbuffer,653 status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
654 &options, &no_elements, NULL);654 &options, &no_elements);
655 printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,655 printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
656 no_elements, pMsgBuff, tab_size);656 no_elements, pMsgBuff, tab_size);
657 }657 }
diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c
index 6846ef5..458a28b 100644
--- a/modules/database/src/ioc/db/dbUnitTest.c
+++ b/modules/database/src/ioc/db/dbUnitTest.c
@@ -197,7 +197,7 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
197 return;197 return;
198 }198 }
199199
200 status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL);200 status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq);
201 if (status) {201 if (status) {
202 testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));202 testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
203 return;203 return;
@@ -270,7 +270,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
270 return;270 return;
271 }271 }
272272
273 status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL);273 status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest);
274 if (status) {274 if (status) {
275 testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);275 testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);
276276
diff --git a/modules/database/src/ioc/db/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h
index 1534517..4b3b82d 100644
--- a/modules/database/src/ioc/db/db_field_log.h
+++ b/modules/database/src/ioc/db/db_field_log.h
@@ -56,20 +56,31 @@ union native_value {
56struct db_field_log;56struct db_field_log;
57typedef void (dbfl_freeFunc)(struct db_field_log *pfl);57typedef void (dbfl_freeFunc)(struct db_field_log *pfl);
5858
59/* Types of db_field_log: rec = use record, val = val inside, ref = reference inside */59/*
60 * A db_field_log has one of two types:
61 *
62 * dbfl_type_ref - Reference to value
63 * Used for variable size (array) data types. Meta-data
64 * is stored in the field log, but value data is stored externally.
65 * Only the dbfl_ref side of the data union is valid.
66 *
67 * dbfl_type_val - Internal value
68 * Used to store small scalar data. Meta-data and value are
69 * present in this structure and no external references are used.
70 * Only the dbfl_val side of the data union is valid.
71 */
60typedef enum dbfl_type {72typedef enum dbfl_type {
61 dbfl_type_rec = 0,
62 dbfl_type_val,73 dbfl_type_val,
63 dbfl_type_ref74 dbfl_type_ref
64} dbfl_type;75} dbfl_type;
6576
66/* Context of db_field_log: event = subscription update, read = read reply */77/* Context of db_field_log: event = subscription update, read = read reply */
67typedef enum dbfl_context {78typedef enum dbfl_context {
68 dbfl_context_read = 0,79 dbfl_context_read,
69 dbfl_context_event80 dbfl_context_event
70} dbfl_context;81} dbfl_context;
7182
72#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref")83#define dbflTypeStr(t) (t==dbfl_type_val?"val":"ref")
7384
74struct dbfl_val {85struct dbfl_val {
75 union native_value field; /* Field value */86 union native_value field; /* Field value */
@@ -81,6 +92,8 @@ struct dbfl_val {
81 * db_delete_field_log(). Any code which changes a dbfl_type_ref92 * db_delete_field_log(). Any code which changes a dbfl_type_ref
82 * field log to another type, or to reference different data,93 * field log to another type, or to reference different data,
83 * must explicitly call the dtor function.94 * must explicitly call the dtor function.
95 * If the dtor is NULL, then this means the array data is still owned
96 * by a record.
84 */97 */
85struct dbfl_ref {98struct dbfl_ref {
86 dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */99 dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
@@ -88,8 +101,17 @@ struct dbfl_ref {
88 void *field; /* Field value */101 void *field; /* Field value */
89};102};
90103
104/*
105 * Note: The offset member is understood to apply an implicit index mapping
106 *
107 * i' = (i + offset) % no_elements
108 *
109 * of request index i. The resulting i' is used to to index into u.r.field.
110 *
111 * Also note that field_size may be larger than MAX_STRING_SIZE.
112 */
91typedef struct db_field_log {113typedef struct db_field_log {
92 unsigned int type:2; /* type (union) selector */114 unsigned int type:1; /* type (union) selector */
93 /* ctx is used for all types */115 /* ctx is used for all types */
94 unsigned int ctx:1; /* context (operation type) */116 unsigned int ctx:1; /* context (operation type) */
95 /* the following are used for value and reference types */117 /* the following are used for value and reference types */
@@ -97,37 +119,15 @@ typedef struct db_field_log {
97 unsigned short stat; /* Alarm Status */119 unsigned short stat; /* Alarm Status */
98 unsigned short sevr; /* Alarm Severity */120 unsigned short sevr; /* Alarm Severity */
99 short field_type; /* DBF type of data */121 short field_type; /* DBF type of data */
100 short field_size; /* Data size */122 short field_size; /* Size of a single element */
101 long no_elements; /* No of array elements */123 long no_elements; /* No of valid array elements */
124 long offset; /* See above */
102 union {125 union {
103 struct dbfl_val v;126 struct dbfl_val v;
104 struct dbfl_ref r;127 struct dbfl_ref r;
105 } u;128 } u;
106} db_field_log;129} db_field_log;
107130
108/*
109 * A db_field_log will in one of three types:
110 *
111 * dbfl_type_rec - Reference to record
112 * The field log stores no data itself. Data must instead be taken
113 * via the dbChannel* which must always be provided when along
114 * with the field log.
115 * For this type only the 'type' and 'ctx' members are used.
116 *
117 * dbfl_type_ref - Reference to outside value
118 * Used for variable size (array) data types. Meta-data
119 * is stored in the field log, but value data is stored externally
120 * (see struct dbfl_ref).
121 * For this type all meta-data members are used. The dbfl_ref side of the
122 * data union is used.
123 *
124 * dbfl_type_val - Internal value
125 * Used to store small scalar data. Meta-data and value are
126 * present in this structure and no external references are used.
127 * For this type all meta-data members are used. The dbfl_val side of the
128 * data union is used.
129 */
130
131#ifdef __cplusplus131#ifdef __cplusplus
132}132}
133#endif133#endif
diff --git a/modules/database/src/std/dev/devAiSoft.c b/modules/database/src/std/dev/devAiSoft.c
index 0ecc1b1..5f9923e 100644
--- a/modules/database/src/std/dev/devAiSoft.c
+++ b/modules/database/src/std/dev/devAiSoft.c
@@ -96,9 +96,10 @@ static long read_ai(aiRecord *prec)
9696
97 prec->udf = FALSE;97 prec->udf = FALSE;
98 prec->dpvt = &devAiSoft; /* Any non-zero value */98 prec->dpvt = &devAiSoft; /* Any non-zero value */
99 return 2;
99 }100 }
100 else101 else
101 prec->dpvt = NULL;102 prec->dpvt = NULL;
102103
103 return 2;104 return status;
104}105}
diff --git a/modules/database/src/std/filters/arr.c b/modules/database/src/std/filters/arr.c
index f91708a..b90335e 100644
--- a/modules/database/src/std/filters/arr.c
+++ b/modules/database/src/std/filters/arr.c
@@ -12,16 +12,13 @@
1212
13#include <stdio.h>13#include <stdio.h>
1414
15#include <freeList.h>15#include "chfPlugin.h"
16#include <dbAccess.h>16#include "dbExtractArray.h"
17#include <dbExtractArray.h>17#include "db_field_log.h"
18#include <db_field_log.h>18#include "dbLock.h"
19#include <dbLock.h>19#include "epicsExit.h"
20#include <recSup.h>20#include "freeList.h"
21#include <epicsExit.h>21#include "epicsExport.h"
22#include <special.h>
23#include <chfPlugin.h>
24#include <epicsExport.h>
2522
26typedef struct myStruct {23typedef struct myStruct {
27 epicsInt32 start;24 epicsInt32 start;
@@ -45,6 +42,8 @@ static void * allocPvt(void)
45 myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);42 myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
46 if (!my) return NULL;43 if (!my) return NULL;
4744
45 /* defaults */
46 my->start = 0;
48 my->incr = 1;47 my->incr = 1;
49 my->end = -1;48 my->end = -1;
50 return (void *) my;49 return (void *) my;
@@ -93,78 +92,61 @@ static long wrapArrayIndices(long *start, const long increment, long *end,
93static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)92static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
94{93{
95 myStruct *my = (myStruct*) pvt;94 myStruct *my = (myStruct*) pvt;
96 struct dbCommon *prec;95 int must_lock;
97 rset *prset;
98 long start = my->start;96 long start = my->start;
99 long end = my->end;97 long end = my->end;
100 long nTarget = 0;98 long nTarget;
101 long offset = 0;99 void *pTarget;
102 long nSource = dbChannelElements(chan);100 /* initial values for the source array */
103 long capacity = nSource;101 long offset = pfl->offset;
104 void *pdst;102 long nSource = pfl->no_elements;
105103
106 switch (pfl->type) {104 switch (pfl->type) {
107 case dbfl_type_val:105 case dbfl_type_val:
108 /* Only filter arrays */106 /* TODO Treat scalars as arrays with 1 element */
109 break;107 break;
110108
111 case dbfl_type_rec:
112 /* Extract from record */
113 if (dbChannelSpecial(chan) == SPC_DBADDR &&
114 nSource > 1 &&
115 (prset = dbGetRset(&chan->addr)) &&
116 prset->get_array_info)
117 {
118 void *pfieldsave = dbChannelField(chan);
119 prec = dbChannelRecord(chan);
120 dbScanLock(prec);
121 prset->get_array_info(&chan->addr, &nSource, &offset);
122 nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
123 pfl->type = dbfl_type_ref;
124 pfl->stat = prec->stat;
125 pfl->sevr = prec->sevr;
126 pfl->time = prec->time;
127 pfl->field_type = dbChannelFieldType(chan);
128 pfl->field_size = dbChannelFieldSize(chan);
129 pfl->no_elements = nTarget;
130 if (nTarget) {
131 pdst = freeListCalloc(my->arrayFreeList);
132 if (pdst) {
133 pfl->u.r.dtor = freeArray;
134 pfl->u.r.pvt = my->arrayFreeList;
135 offset = (offset + start) % dbChannelElements(chan);
136 dbExtractArrayFromRec(&chan->addr, pdst, nTarget, capacity,
137 offset, my->incr);
138 pfl->u.r.field = pdst;
139 }
140 }
141 dbScanUnlock(prec);
142 dbChannelField(chan) = pfieldsave;
143 }
144 break;
145
146 /* Extract from buffer */
147 case dbfl_type_ref:109 case dbfl_type_ref:
148 pdst = NULL;110 must_lock = !pfl->u.r.dtor;
149 nSource = pfl->no_elements;111 if (must_lock)
112 dbScanLock(dbChannelRecord(chan));
150 nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);113 nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
151 pfl->no_elements = nTarget;114 /*
152 if (nTarget) {115 * Side note: it would be nice if we could avoid the copying in
153 /* Copy the data out */116 * the case of my->incr==1. This is currently not possible due to
154 void *psrc = pfl->u.r.field;117 * the way the offset member is interpreted (namely as shifting the
155118 * array in a ring-buffer style).
156 pdst = freeListCalloc(my->arrayFreeList);119 */
157 if (!pdst) break;120 if (nTarget > 0) {
158 offset = start;121 /* copy the data */
159 dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type,122 void *pSource = pfl->u.r.field;
160 nTarget, nSource, offset, my->incr);123 pTarget = freeListCalloc(my->arrayFreeList);
161 }124 if (!pTarget) break;
162 if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);125 offset = (offset + start) % nSource;
163 if (nTarget) {126 dbExtractArray(pSource, pTarget, pfl->field_size,
127 pfl->field_type, nTarget, nSource, offset, my->incr);
128 if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
129 pfl->u.r.field = pTarget;
164 pfl->u.r.dtor = freeArray;130 pfl->u.r.dtor = freeArray;
165 pfl->u.r.pvt = my->arrayFreeList;131 pfl->u.r.pvt = my->arrayFreeList;
166 pfl->u.r.field = pdst;
167 }132 }
133 /* adjust offset and no_elements to refer to the new pTarget */
134 pfl->offset = 0;
135 /*
136 * Setting pfl->no_elements outside of the "if" clause above is
137 * done to make requests fail if nTarget is zero, that is, if all
138 * elements selected by the filter are outside the array bounds.
139 * TODO:
140 * It would be possible to lift this restriction by interpreting
141 * a request with *no* number of elements (NULL pointer) as scalar
142 * (meaning: fail if we get less than one element); in contrast,
143 * a request that explicitly specifies one element would be
144 * interpreted as an array request, for which zero elements would
145 * be a normal expected result.
146 */
147 pfl->no_elements = nTarget;
148 if (must_lock)
149 dbScanUnlock(dbChannelRecord(chan));
168 break;150 break;
169 }151 }
170 return pfl;152 return pfl;
diff --git a/modules/database/src/std/filters/ts.c b/modules/database/src/std/filters/ts.c
index 5925b0b..56c9f5b 100644
--- a/modules/database/src/std/filters/ts.c
+++ b/modules/database/src/std/filters/ts.c
@@ -11,21 +11,39 @@
11 */11 */
1212
13#include <stdio.h>13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
1416
15#include <chfPlugin.h>17#include "chfPlugin.h"
16#include <dbLock.h>18#include "db_field_log.h"
17#include <db_field_log.h>19#include "dbLock.h"
18#include <epicsExport.h>20#include "epicsExport.h"
21
22/*
23 * The size of the data is different for each channel, and can even
24 * change at runtime, so a freeList doesn't make much sense here.
25 */
26static void freeArray(db_field_log *pfl) {
27 free(pfl->u.r.field);
28}
1929
20static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {30static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
21 epicsTimeStamp now;31 epicsTimeStamp now;
22 epicsTimeGetCurrent(&now);32 epicsTimeGetCurrent(&now);
2333
24 /* If string or array, must make a copy (to ensure coherence between time and data) */34 /* If reference and not already copied,
25 if (pfl->type == dbfl_type_rec) {35 must make a copy (to ensure coherence between time and data) */
26 dbScanLock(dbChannelRecord(chan));36 if (pfl->type == dbfl_type_ref && !pfl->u.r.dtor) {
27 dbChannelMakeArrayCopy(pvt, pfl, chan);37 void *pTarget = calloc(pfl->no_elements, pfl->field_size);
28 dbScanUnlock(dbChannelRecord(chan));38 void *pSource = pfl->u.r.field;
39 if (pTarget) {
40 dbScanLock(dbChannelRecord(chan));
41 memcpy(pTarget, pSource, pfl->field_size * pfl->no_elements);
42 pfl->u.r.field = pTarget;
43 pfl->u.r.dtor = freeArray;
44 pfl->u.r.pvt = pvt;
45 dbScanUnlock(dbChannelRecord(chan));
46 }
29 }47 }
3048
31 pfl->time = now;49 pfl->time = now;
diff --git a/modules/database/test/ioc/db/dbChArrTest.cpp b/modules/database/test/ioc/db/dbChArrTest.cpp
index 8255fdc..ff74e01 100644
--- a/modules/database/test/ioc/db/dbChArrTest.cpp
+++ b/modules/database/test/ioc/db/dbChArrTest.cpp
@@ -130,7 +130,7 @@ static void check(short dbr_type) {
130 memset(buf, 0, sizeof(buf)); \130 memset(buf, 0, sizeof(buf)); \
131 (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \131 (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
132 pfl = db_create_read_log(pch); \132 pfl = db_create_read_log(pch); \
133 testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \133 testOk(pfl && pfl->type == dbfl_type_ref, "Valid pfl, type = ref"); \
134 testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \134 testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
135 testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \135 testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
136 if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \136 if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
@@ -178,6 +178,7 @@ static void check(short dbr_type) {
178 pfl->field_type = DBF_CHAR; \178 pfl->field_type = DBF_CHAR; \
179 pfl->field_size = 1; \179 pfl->field_size = 1; \
180 pfl->no_elements = 26; \180 pfl->no_elements = 26; \
181 pfl->offset = 0; \
181 pfl->u.r.dtor = freeArray; \182 pfl->u.r.dtor = freeArray; \
182 pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \183 pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \
183 testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \184 testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
diff --git a/modules/database/test/std/filters/arrTest.cpp b/modules/database/test/std/filters/arrTest.cpp
index 1ec16b3..08ba07b 100644
--- a/modules/database/test/std/filters/arrTest.cpp
+++ b/modules/database/test/std/filters/arrTest.cpp
@@ -56,25 +56,26 @@ const char *server_port = CA_SERVER_PORT;
5656
57static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) {57static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) {
58 for (int i = 0; i < pfl1->no_elements; i++) {58 for (int i = 0; i < pfl1->no_elements; i++) {
59 int j = (i + pfl1->offset) % pfl1->no_elements;
59 switch (type) {60 switch (type) {
60 case DBR_DOUBLE:61 case DBR_DOUBLE:
61 if (((epicsFloat64*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {62 if (((epicsFloat64*)pfl1->u.r.field)[j] != ((epicsInt32*)p2)[i]) {
62 testDiag("at index=%d: field log has %g, should be %d",63 testDiag("at index=%d: field log has %g, should be %d",
63 i, ((epicsFloat64*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);64 i, ((epicsFloat64*)pfl1->u.r.field)[j], ((epicsInt32*)p2)[i]);
64 return 0;65 return 0;
65 }66 }
66 break;67 break;
67 case DBR_LONG:68 case DBR_LONG:
68 if (((epicsInt32*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) {69 if (((epicsInt32*)pfl1->u.r.field)[j] != ((epicsInt32*)p2)[i]) {
69 testDiag("at index=%d: field log has %d, should be %d",70 testDiag("at index=%d: field log has %d, should be %d",
70 i, ((epicsInt32*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]);71 i, ((epicsInt32*)pfl1->u.r.field)[j], ((epicsInt32*)p2)[i]);
71 return 0;72 return 0;
72 }73 }
73 break;74 break;
74 case DBR_STRING:75 case DBR_STRING:
75 if (strtol(&((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], NULL, 0) != ((epicsInt32*)p2)[i]) {76 if (strtol(&((const char*)pfl1->u.r.field)[j*pfl1->field_size], NULL, 0) != ((epicsInt32*)p2)[i]) {
76 testDiag("at index=%d: field log has '%s', should be '%d'",77 testDiag("at index=%d: field log has '%s', should be '%d'",
77 i, &((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], ((epicsInt32*)p2)[i]);78 i, &((const char*)pfl1->u.r.field)[j*pfl1->field_size], ((epicsInt32*)p2)[i]);
78 return 0;79 return 0;
79 }80 }
80 break;81 break;
@@ -119,7 +120,7 @@ static void testHead (const char *title, const char *typ = "") {
119 off = Offset; \120 off = Offset; \
120 (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \121 (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
121 pfl = db_create_read_log(pch); \122 pfl = db_create_read_log(pch); \
122 testOk(pfl->type == dbfl_type_rec, "original field log has type rec"); \123 testOk(pfl->type == dbfl_type_ref, "original field log has type ref"); \
123 pfl2 = dbChannelRunPostChain(pch, pfl); \124 pfl2 = dbChannelRunPostChain(pch, pfl); \
124 testOk(pfl2 == pfl, "call does not drop or replace field_log"); \125 testOk(pfl2 == pfl, "call does not drop or replace field_log"); \
125 testOk(pfl->type == dbfl_type_ref, "filtered field log has type ref"); \126 testOk(pfl->type == dbfl_type_ref, "filtered field log has type ref"); \
diff --git a/modules/database/test/std/filters/dbndTest.c b/modules/database/test/std/filters/dbndTest.c
index 4d70f83..fd4a472 100644
--- a/modules/database/test/std/filters/dbndTest.c
+++ b/modules/database/test/std/filters/dbndTest.c
@@ -129,7 +129,7 @@ MAIN(dbndTest)
129 dbEventCtx evtctx;129 dbEventCtx evtctx;
130 int logsFree, logsFinal;130 int logsFree, logsFinal;
131131
132 testPlan(77);132 testPlan(72);
133133
134 testdbPrepare();134 testdbPrepare();
135135
@@ -170,12 +170,9 @@ MAIN(dbndTest)
170 "dbnd has one filter with argument in pre chain");170 "dbnd has one filter with argument in pre chain");
171 testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain");171 testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain");
172172
173 /* Field logs of type ref and rec: pass any update */173 /* Field logs of type ref: pass any update */
174
175 testHead("Field logs of type ref and rec");
176 fl1.type = dbfl_type_rec;
177 mustPassTwice(pch, &fl1, "abs field_log=rec", 0., 0);
178174
175 testHead("Field logs of type ref");
179 fl1.type = dbfl_type_ref;176 fl1.type = dbfl_type_ref;
180 mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);177 mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);
181178
diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile
index 8c087b3..3d7cff9 100644
--- a/modules/database/test/std/rec/Makefile
+++ b/modules/database/test/std/rec/Makefile
@@ -156,6 +156,13 @@ asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp
156TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db156TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db
157TESTS += asyncproctest157TESTS += asyncproctest
158158
159TESTPROD_HOST += linkFilterTest
160linkFilterTest_SRCS += linkFilterTest.c
161linkFilterTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
162testHarness_SRCS += linkFilterTest.c
163TESTFILES += ../linkFilterTest.db
164TESTS += linkFilterTest
165
159# dbHeader* is only a compile test166# dbHeader* is only a compile test
160# no need to actually run167# no need to actually run
161TESTPROD += dbHeaderTest168TESTPROD += dbHeaderTest
diff --git a/modules/database/test/std/rec/linkFilterTest.c b/modules/database/test/std/rec/linkFilterTest.c
162new file mode 100644169new file mode 100644
index 0000000..6f38d24
--- /dev/null
+++ b/modules/database/test/std/rec/linkFilterTest.c
@@ -0,0 +1,157 @@
1/*************************************************************************\
2* Copyright (c) 2020 Dirk Zimoch
3* EPICS BASE is distributed subject to a Software License Agreement found
4* in file LICENSE that is included with this distribution.
5\*************************************************************************/
6
7#include <string.h>
8
9#include "dbAccess.h"
10#include "devSup.h"
11#include "alarm.h"
12#include "dbUnitTest.h"
13#include "errlog.h"
14#include "epicsThread.h"
15
16#include "longinRecord.h"
17
18#include "testMain.h"
19
20void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
21
22static void startTestIoc(const char *dbfile)
23{
24 testdbPrepare();
25 testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
26 recTestIoc_registerRecordDeviceDriver(pdbbase);
27 testdbReadDatabase(dbfile, NULL, NULL);
28
29 eltc(0);
30 testIocInitOk();
31 eltc(1);
32}
33
34static void expectProcSuccess(const char *rec)
35{
36 char fieldname[20];
37 testDiag("expecting success from %s", rec);
38 sprintf(fieldname, "%s.PROC", rec);
39 testdbPutFieldOk(fieldname, DBF_LONG, 1);
40 sprintf(fieldname, "%s.SEVR", rec);
41 testdbGetFieldEqual(fieldname, DBF_LONG, NO_ALARM);
42 sprintf(fieldname, "%s.STAT", rec);
43 testdbGetFieldEqual(fieldname, DBF_LONG, NO_ALARM);
44}
45
46static void expectProcFailure(const char *rec)
47{
48 char fieldname[20];
49 testDiag("expecting failure S_db_badField %#x from %s", S_db_badField, rec);
50 sprintf(fieldname, "%s.PROC", rec);
51 testdbPutFieldFail(S_db_badField, fieldname, DBF_LONG, 1);
52 sprintf(fieldname, "%s.SEVR", rec);
53 testdbGetFieldEqual(fieldname, DBF_LONG, INVALID_ALARM);
54 sprintf(fieldname, "%s.STAT", rec);
55 testdbGetFieldEqual(fieldname, DBF_LONG, LINK_ALARM);
56}
57
58static void changeRange(long start, long stop, long step)
59{
60 char linkstring[60];
61 if (step)
62 sprintf(linkstring, "src.[%ld:%ld:%ld]", start, step, stop);
63 else if (stop)
64 sprintf(linkstring, "src.[%ld:%ld]", start, stop);
65 else
66 sprintf(linkstring, "src.[%ld]", start);
67 testDiag("modifying link: %s", linkstring);
68 testdbPutFieldOk("ai.INP", DBF_STRING, linkstring);
69 testdbPutFieldOk("wf.INP", DBF_STRING, linkstring);
70}
71
72static double buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 2, 4, 6};
73
74static void expectRange(long start, long end)
75{
76 long n = end-start+1;
77 testdbGetFieldEqual("ai.VAL", DBF_DOUBLE, buf[start]);
78 testdbGetFieldEqual("wf.NORD", DBF_LONG, n);
79 testdbGetArrFieldEqual("wf.VAL", DBF_DOUBLE, n+2, n, buf+start);
80}
81
82#if 0
83static void expectEmptyArray(void)
84{
85 /* empty arrays are now allowed at the moment */
86 testDiag("expecting empty array");
87 testdbGetFieldEqual("wf.NORD", DBF_LONG, 0);
88}
89#endif
90
91MAIN(linkFilterTest)
92{
93 testPlan(98);
94 startTestIoc("linkFilterTest.db");
95
96 testDiag("PINI");
97 expectRange(2,4);
98
99 testDiag("modify range");
100 changeRange(3,6,0);
101 expectProcSuccess("ai");
102 expectProcSuccess("wf");
103 expectRange(3,6);
104
105 testDiag("backward range");
106 changeRange(5,3,0);
107 expectProcFailure("ai");
108 expectProcFailure("wf");
109
110 testDiag("step 2");
111 changeRange(1,6,2);
112 expectProcSuccess("ai");
113 expectProcSuccess("wf");
114 expectRange(10,12);
115
116 testDiag("range start beyond src.NORD");
117 changeRange(8,9,0);
118 expectProcFailure("ai");
119 expectProcFailure("wf");
120
121 testDiag("range end beyond src.NORD");
122 changeRange(3,9,0);
123 expectProcSuccess("ai");
124 expectProcSuccess("wf");
125 expectRange(3,7); /* clipped range */
126
127 testDiag("range start beyond src.NELM");
128 changeRange(11,12,0);
129 expectProcFailure("ai");
130 expectProcFailure("wf");
131
132 testDiag("range end beyond src.NELM");
133 changeRange(4,12,0);
134 expectProcSuccess("ai");
135 expectProcSuccess("wf");
136 expectRange(4,7); /* clipped range */
137
138 testDiag("single value beyond src.NORD");
139 changeRange(8,0,0);
140 expectProcFailure("ai");
141 expectProcFailure("wf");
142
143 testDiag("single value");
144 changeRange(5,0,0);
145 expectProcSuccess("ai");
146 expectProcSuccess("wf");
147 expectRange(5,5);
148
149 testDiag("single beyond rec.NELM");
150 changeRange(12,0,0);
151 expectProcFailure("ai");
152 expectProcFailure("wf");
153
154 testIocShutdownOk();
155 testdbCleanup();
156 return testDone();
157}
diff --git a/modules/database/test/std/rec/linkFilterTest.db b/modules/database/test/std/rec/linkFilterTest.db
0new file mode 100644158new file mode 100644
index 0000000..5ee371e
--- /dev/null
+++ b/modules/database/test/std/rec/linkFilterTest.db
@@ -0,0 +1,16 @@
1record(waveform, "src") {
2 field(NELM, "10")
3 field(FTVL, "SHORT")
4 field(INP, [1, 2, 3, 4, 5, 6, 7, 8])
5}
6record(ai, "ai") {
7 field(INP, "src.[2]") # expect 3
8 field(PINI, "YES")
9}
10record(waveform, "wf") {
11 field(NELM, "5")
12 field(FTVL, "DOUBLE")
13 field(INP, "src.[2:4]") # expect 3,4,5
14 field(PINI, "YES")
15}
16
diff --git a/modules/database/test/std/rec/regressTest.c b/modules/database/test/std/rec/regressTest.c
index 6614639..fd4f0a8 100644
--- a/modules/database/test/std/rec/regressTest.c
+++ b/modules/database/test/std/rec/regressTest.c
@@ -132,7 +132,7 @@ void testCADisconn(void)
132132
133 startRegressTestIoc("badCaLink.db");133 startRegressTestIoc("badCaLink.db");
134134
135 testdbPutFieldOk("ai:disconn.PROC", DBF_LONG, 1);135 testdbPutFieldFail(-1, "ai:disconn.PROC", DBF_LONG, 1);
136 testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM);136 testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM);
137 testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM);137 testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM);
138}138}

Subscribers

People subscribed via source and target branches