Merge lp:~michael-abbott/epics-base/dynamic-array into lp:~epics-core/epics-base/3.14

Proposed by Michael Abbott
Status: Merged
Merge reported by: Andrew Johnson
Merged at revision: not available
Proposed branch: lp:~michael-abbott/epics-base/dynamic-array
Merge into: lp:~epics-core/epics-base/3.14
Diff against target: 1647 lines (+406/-538)
17 files modified
.bzrignore (+2/-0)
src/ca/caProto.h (+3/-0)
src/ca/db_access.h (+3/-3)
src/ca/nciu.cpp (+0/-3)
src/ca/nciu.h (+2/-1)
src/ca/netIO.h (+3/-3)
src/ca/oldChannelNotify.cpp (+3/-0)
src/ca/tcpiiu.cpp (+8/-3)
src/catools/caget.c (+16/-14)
src/catools/camonitor.c (+5/-6)
src/catools/tool_lib.c (+3/-3)
src/catools/tool_lib.h (+2/-2)
src/db/db_access.c (+259/-432)
src/db/db_access_routines.h (+3/-0)
src/rsrv/camessage.c (+44/-41)
src/rsrv/caserverio.c (+48/-26)
src/rsrv/server.h (+2/-1)
To merge this branch: bzr merge lp:~michael-abbott/epics-base/dynamic-array
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Review via email: mp+26796@code.launchpad.net

Description of the change

This is the dynamic array functionality already described in an earlier e-mail to epics-core.

I hope I'm doing this right. Hugely underwhelmed by bzr+launchpad so far...

To post a comment you must log in.
Revision history for this message
Michael Abbott (michael-abbott) wrote :

Oh crap. Commit 12071 isn't meant to be part of this patch series. Rebase it out if bzr lets you.

Also, ideally, patches 12075 and 12076 should be treated quite separately, as they've little or nothing to do with the core of this work which is just patches 12072 & 12073, plus an application in 12074.

Revision history for this message
Michael Abbott (michael-abbott) wrote :
Download full text (3.1 KiB)

Here's the original message I sent with the motivation for this change.

Subject: [PATCH 0/4] Adding dynamic arrays to EPICS Channel Access

Following on from last week's EPICS codeathon at Diamond I have
prepared the attached series of patches for review.

The basic idea is to extend the server's understanding of the EPICS CA
protocol with one further idea: a request for a zero length array is
interpreted as, instead, a request for an autoresizing array, where
the server sends the true "intrinsic" length of the data with each
update.

The motivation is to efficiently support the handling of large
waveforms such as images or long oscilloscope waveforms, where it is
undesirable to have to always send the entire data. There are
workarounds involving monitoring the .NORD field and resubscribing on
changes, but I believe the approach described here is preferable.
Also, this new functionality opens up the possiblity of sending
complex structured data of unpredictable length packaged as EPICS
waveforms -- something that has already been started with support for
long strings.

It turns out that the implementation of this extension is reasonably
straightforward and that EPICS is mostly already ready for it. The
following detailed changes are implemented:

* A zero length Data Count in a CA_PROTO_EVENT_ADD or CA_PROTO_READ
message is now interpreted so that the "intrinsic" data count is sent
in all replies. A new minor protocol version, V4.12, is defined to
enable this behaviour.

* When processing the request for dynamically sized data the server is
able to make use of two items of information for each value: its
dynamic size, as returned by dbGetField(), and its maximum field size,
as stored in the no_elements field of the associated dbAddr structure.

* The channel access client now passes through a zero length request
to the server (if the server reports minor protocol >= 4.12), and the
true data size is now reported in the associated callbacks. This
means that ca_array_get_callback and ca_create_subscription may now
receive variable size updates in response to a zero length request
count.

I have also updated the caget and camonitor tools to support this new
functionality.

The attached patches are based on bzr revision 12070.

Michael Abbott (4):
  Client side support for automatic resizing arrays.
  Update rsrv to support V4.12 protocol extension.
  Add autosizing array support for caget and camonitor.
  Drive-by refactoring in caserverio.c
 src/ca/caProto.h | 3 +
 src/ca/db_access.h | 6 +-
 src/ca/nciu.cpp | 3 -
 src/ca/nciu.h | 3 +-
 src/ca/netIO.h | 6 +-
 src/ca/oldChannelNotify.cpp | 3 +
 src/ca/tcpiiu.cpp | 11 +-
 src/catools/caget.c | 30 ++--
 src/catools/camonitor.c | 11 +-
 src/catools/tool_lib.c | 6 +-
 src/catools/tool_lib.h | 4 +-
 src/db/db_access.c | 345 +++++++++++--------------------------------
 src/db/db_access_routines.h | 3 +
 src/rsrv/camessage.c | 85 ++++++-----
 src/rsrv/caserverio.c | 55 ++++---
 src/rsrv/server.h | 3 +-
 16 files changed, 214 insertions(+...

Read more...

Revision history for this message
Jeff Hill (johill-lanl) wrote :

Hi Michael,

Thanks for your help.

Please add a client side initiated regression test to acctst.c that verifies that the new feature works properly. Sorry, that acctst.c is a messy code for certain but it does serve its purpose of preventing introduction of bugs that have been seen before. This will also have the benefit of not allowing my neglect of parallel changes for these features in the new server :^). Also, running acctst might even help to test the features you have added.

changes in ca/caProto.h
> +# define CA_V412(MINOR) ((MINOR)>=12u) /* Allow zero length in
> requests. */

The following is what I have on the Bazaar branch which was based on the cvs main trunk (this is where I have always added new features in the past so that I didn't mix together patch level changes in the R3.14 branch (i.e. fixes) with feature upgrades).

# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
# define CA_V413(MINOR) ((MINOR)>=13u) /* channel connectivity response messages */

So we have some conflicts with the new TCP search protocol and some capabilities I have in the new server which allow the service to report the current state of the connectivity it has with its channel.

I propose the following based on the order (in time) that each upgrade might be installed into base (the TCP based search request changes were completed a long time ago):

o V412 - TCP based search requests
o V413 - dynamic payload sized subscription / get callback response message
o V414 - connectivity response messages

I am confused about the purpose of this change (presumably the old code was safer because the client code's compiler can check for access past the end of the array)?

diff --git a/src/ca/db_access.h b/src/ca/db_access.h
-epicsShareExtern const unsigned short dbr_size[LAST_BUFFER_TYPE+1];
+epicsShareExtern const unsigned short dbr_size[];

 /* size for each type's value - array indexed by the DBR_ type code */
-epicsShareExtern const unsigned short dbr_value_size[LAST_BUFFER_TYPE+1];
+epicsShareExtern const unsigned short dbr_value_size[];

Changes to rssrv/camessage.c

I am a bit concerned that if for whatever reason db_get_field_and_count returns an item_count greater than requested then we could have data_size greater than payload_size which could cause the unsigned subtract to overflow here. That could cause memset to copy many (way too many) elements which would almost certainly profoundly crash the IOC. Can we afford the risk? I would add an "if (payload_size - data_size)" sanity check here. Yes, nannying but robust.

returns data_size greater
+ memset(
+ (char *) pPayload + data_size, 0, payload_size - data_size);

Otherwise, I did finally have a very close look today, and it looks good.

Revision history for this message
Michael Abbott (michael-abbott) wrote :
Download full text (3.8 KiB)

A first response before I dig into the code.

From: <email address hidden> [mailto:<email address hidden>] On Behalf Of Jeff Hill
> Please add a client side initiated regression test to
> acctst.c that verifies that the new feature works properly.
> Sorry, that acctst.c is a messy code for certain but it does
> serve its purpose of preventing introduction of bugs that
> have been seen before. This will also have the benefit of not
> allowing my neglect of parallel changes for these features in
> the new server :^). Also, running acctst might even help to
> test the features you have added.

Good idea. Ouch, though. Guess it's not going to be a small amount of work...

> changes in ca/caProto.h
> > +# define CA_V412(MINOR) ((MINOR)>=12u) /* Allow zero length in requests. */
>
> I propose the following based on the order (in time) that
> each upgrade might be installed into base (the TCP based
> search request changes were completed a long time ago):
>
> o V412 - TCP based search requests
> o V413 - dynamic payload sized subscription / get callback response message
> o V414 - connectivity response messages

Ok, so I'll just change my CA_V412 tests to CA_V413.

It's a slight nuisance now that we're going by version number rather than using capability bits, but at the end of the day the history of the code will have to be serialised and presumably as you say the 4.12 stuff is ready to be merged with mainstream?

> I am confused about the purpose of this change (presumably
> the old code was safer because the client code's compiler can
> check for access past the end of the array)?
>
> diff --git a/src/ca/db_access.h b/src/ca/db_access.h
> -epicsShareExtern const unsigned short dbr_size[LAST_BUFFER_TYPE+1];
> +epicsShareExtern const unsigned short dbr_size[];
>
> /* size for each type's value - array indexed by the DBR_ type code */
> -epicsShareExtern const unsigned short dbr_value_size[LAST_BUFFER_TYPE+1];
> +epicsShareExtern const unsigned short dbr_value_size[];

I'll hunt out the precise detail, but basically what happened here was that I needed to import db_access.h into a C file where LAST_BUFFER_TYPE wasn't defined (there are all sorts of exciting definition conflicts around in this area) -- indeed, I think I moved the definition out of a #ifdef block. So rather than fight further with more potential conflicts I removed the size definition which, as far as I can tell, would only affect applications of sizeof(dbr_size), which there aren't any -- I don't think leaving these out has any other effect.

I'm pretty sure that the C compiler never checks array sizes when generating access code, so I can't think of any impact apart from making sizeof(dbr_size) fail.

> Changes to rssrv/camessage.c
>
> I am a bit concerned that if for whatever reason
> db_get_field_and_count returns an item_count greater than
> requested then we could have data_size greater than
> payload_size which could cause the unsigned subtract to
> overflow here. That could cause memset to copy many (way too
> many) elements which would almost certainly profoundly crash
> the IOC. Can we aff...

Read more...

12077. By Michael Abbott

Apply responses to code review

Advance associated EPICS protocol revision from 4.12 to 4.13 leaving room
for TCP based search requests to occupy revision 12.

Guard memset in camessage.c to prevent wild memory overrun if mismatch
between payload and data size.

12078. By Michael Abbott

Merged with EPICS base as of 2010/07/05

Removed gratuitous renames in db_access.c as resulted in massive merge
conflict.

Revision history for this message
Michael Abbott (michael-abbott) wrote :

Well, I've responded to Jeff's review comments.

* I've updated the version number and guard from 4.12 to 4.13. Of course, this means that this branch really does need to be merged after the TCP-based search requests feature.

* Rather than think very hard (and maybe make a stupid mistake) I've just guarded the memset() that Jeff flagged with the obvious sanity test.

* I've re-merged with EPICS base. As I noted on the mailing list, this introduced a massive merge conflict with the variable renaming in db_access.c, but as the renaming is quite gratuitous I simply dropped that part of the merge.

* I'm sorry, I've not done anything to acctst.c. As far as I can see it's client side only, and I don't really see where to get started without spending a *lot* of time on it. I'll try and look at this again another time.

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

Hi Michael,

I have rebased your dynamic-array commits from 12072 to 12077 onto the latest 3.14 branch, dropping 12071 and handling the db_access.c renames from 12078 properly in the earlier commits. I also changed all references to the CA minor version number from 12 to 13 in the earlier commits. You are still credited as the author in the Bazaar history, although your original commit dates were lost in the manual rebase. There are a few changes I'll need to work on before I can merge it into 3.14 though:
 * Update the Perl5 interface to provide dynamic array support from Perl (almost complete)
 * Make src/catools/caput.c use dynamic arrays for before & after value displays
 * Documentation in both the CAref.html and RELEASE_NOTES.html files

Would you prefer that I publish my branch for public examination while I'm working on it, or just merge the result without referring back to you?

- Andrew

review: Approve
Revision history for this message
Michael Abbott (michael-abbott) wrote :

Hi Andrew,

I'm on holiday until the start of September, so just a quick reply. I'll try and catch up when I get back.

If you're happy to merge, please go ahead. I though I'd already changed the minor version to 13, but maybe I messed up my update?

From: <email address hidden> [mailto:<email address hidden>] On Behalf Of Andrew Johnson
> I have rebased your dynamic-array commits from 12072 to 12077
> onto the latest 3.14 branch, dropping 12071 and handling the
> db_access.c renames from 12078 properly in the earlier
> commits. I also changed all references to the CA minor
> version number from 12 to 13 in the earlier commits. You are
> still credited as the author in the Bazaar history, although
> your original commit dates were lost in the manual rebase.
> There are a few changes I'll need to work on before I can
> merge it into 3.14 though:
> * Update the Perl5 interface to provide dynamic array
> support from Perl (almost complete)
> * Make src/catools/caput.c use dynamic arrays for before &
> after value displays
> * Documentation in both the CAref.html and RELEASE_NOTES.html files
>
> Would you prefer that I publish my branch for public
> examination while I'm working on it, or just merge the result
> without referring back to you?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2009-12-23 21:06:44 +0000
3+++ .bzrignore 2010-07-05 08:47:25 +0000
4@@ -1,3 +1,5 @@
5+./.git
6+./.gitignore
7 ./bin
8 ./lib
9 ./db
10
11=== modified file 'src/ca/caProto.h'
12--- src/ca/caProto.h 2004-10-04 18:55:40 +0000
13+++ src/ca/caProto.h 2010-07-05 08:47:25 +0000
14@@ -40,6 +40,7 @@
15 # define CA_V49(MINOR) ((MINOR)>=9u) /* large arrays, dispatch priorities */
16 # define CA_V410(MINOR) ((MINOR)>=10u) /* beacon counter */
17 # define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
18+# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
19 #elif CA_MAJOR_PROTOCOL_REVISION > 4u
20 # define CA_V41(MINOR) ( 1u )
21 # define CA_V42(MINOR) ( 1u )
22@@ -52,6 +53,7 @@
23 # define CA_V49(MINOR) ( 1u )
24 # define CA_V410(MINOR) ( 1u )
25 # define CA_V411(MINOR) ( 1u )
26+# define CA_V413(MINOR) ( 1u )
27 #else
28 # define CA_V41(MINOR) ( 0u )
29 # define CA_V42(MINOR) ( 0u )
30@@ -64,6 +66,7 @@
31 # define CA_V49(MINOR) ( 0u )
32 # define CA_V410(MINOR) ( 0u )
33 # define CA_V411(MINOR) ( 0u )
34+# define CA_V413(MINOR) ( 0u )
35 #endif
36
37 /*
38
39=== modified file 'src/ca/db_access.h'
40--- src/ca/db_access.h 2009-08-14 00:29:56 +0000
41+++ src/ca/db_access.h 2010-07-05 08:47:25 +0000
42@@ -524,16 +524,16 @@
43 dbr_double_t value; /* current value */
44 };
45
46-#ifndef db_accessHFORdb_accessC
47 #define dbr_size_n(TYPE,COUNT)\
48 ((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
49
50 /* size for each type - array indexed by the DBR_ type code */
51-epicsShareExtern const unsigned short dbr_size[LAST_BUFFER_TYPE+1];
52+epicsShareExtern const unsigned short dbr_size[];
53
54 /* size for each type's value - array indexed by the DBR_ type code */
55-epicsShareExtern const unsigned short dbr_value_size[LAST_BUFFER_TYPE+1];
56+epicsShareExtern const unsigned short dbr_value_size[];
57
58+#ifndef db_accessHFORdb_accessC
59 /* class for each type's value */
60 enum dbr_value_class {
61 dbr_class_int,
62
63=== modified file 'src/ca/nciu.cpp'
64--- src/ca/nciu.cpp 2009-08-24 17:03:17 +0000
65+++ src/ca/nciu.cpp 2010-07-05 08:47:25 +0000
66@@ -291,9 +291,6 @@
67 if ( countIn > this->count ) {
68 throw cacChannel::outOfBounds ();
69 }
70- if ( countIn == 0 ) {
71- countIn = this->count;
72- }
73
74 //
75 // fail out if their arguments are invalid
76
77=== modified file 'src/ca/nciu.h'
78--- src/ca/nciu.h 2008-07-28 16:19:50 +0000
79+++ src/ca/nciu.h 2010-07-05 08:47:25 +0000
80@@ -41,7 +41,7 @@
81 # include "shareLib.h"
82 #endif
83
84-#define CA_MINOR_PROTOCOL_REVISION 11
85+#define CA_MINOR_PROTOCOL_REVISION 13
86 #include "caProto.h"
87
88 #include "cacIO.h"
89@@ -205,6 +205,7 @@
90 void disconnectAllIO (
91 epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & );
92 bool connected ( epicsGuard < epicsMutex > & ) const;
93+ unsigned getcount() const { return count; }
94
95 private:
96 tsDLList < class baseNMIU > eventq;
97
98=== modified file 'src/ca/netIO.h'
99--- src/ca/netIO.h 2004-10-04 18:55:40 +0000
100+++ src/ca/netIO.h 2010-07-05 08:47:25 +0000
101@@ -83,7 +83,7 @@
102 void show (
103 epicsGuard < epicsMutex > &, unsigned level ) const;
104 arrayElementCount getCount (
105- epicsGuard < epicsMutex > & ) const;
106+ epicsGuard < epicsMutex > &, bool allow_zero ) const;
107 unsigned getType (
108 epicsGuard < epicsMutex > & ) const;
109 unsigned getMask (
110@@ -242,11 +242,11 @@
111 }
112
113 inline arrayElementCount netSubscription::getCount (
114- epicsGuard < epicsMutex > & guard ) const // X aCC 361
115+ epicsGuard < epicsMutex > & guard, bool allow_zero ) const // X aCC 361
116 {
117 //guard.assertIdenticalMutex ( this->mutex );
118 arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard );
119- if ( this->count == 0u || this->count > nativeCount ) {
120+ if ( (this->count == 0u && !allow_zero) || this->count > nativeCount ) {
121 return nativeCount;
122 }
123 else {
124
125=== modified file 'src/ca/oldChannelNotify.cpp'
126--- src/ca/oldChannelNotify.cpp 2007-01-11 21:45:58 +0000
127+++ src/ca/oldChannelNotify.cpp 2010-07-05 08:47:25 +0000
128@@ -280,6 +280,9 @@
129 if ( type < 0 ) {
130 return ECA_BADTYPE;
131 }
132+ if ( count == 0 )
133+ return ECA_BADCOUNT;
134+
135 unsigned tmpType = static_cast < unsigned > ( type );
136 epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
137 pChan->eliminateExcessiveSendBacklog ( guard );
138
139=== modified file 'src/ca/tcpiiu.cpp'
140--- src/ca/tcpiiu.cpp 2009-09-11 00:49:02 +0000
141+++ src/ca/tcpiiu.cpp 2010-07-05 08:47:25 +0000
142@@ -1443,6 +1443,8 @@
143 if ( nElem > maxElem ) {
144 throw cacChannel::msgBodyCacheTooSmall ();
145 }
146+ if (nElem == 0 && !CA_V413(this->minorProtocolVersion))
147+ nElem = chan.getcount();
148 comQueSendMsgMinder minder ( this->sendQue, guard );
149 this->sendQue.insertRequestHeader (
150 CA_PROTO_READ_NOTIFY, 0u,
151@@ -1538,7 +1540,8 @@
152 if ( mask > 0xffff ) {
153 throw cacChannel::badEventSelection ();
154 }
155- arrayElementCount nElem = subscr.getCount ( guard );
156+ arrayElementCount nElem = subscr.getCount (
157+ guard, CA_V413(this->minorProtocolVersion) );
158 arrayElementCount maxBytes;
159 if ( CA_V49 ( this->minorProtocolVersion ) ) {
160 maxBytes = this->cacRef.largeBufferSizeTCP ();
161@@ -1584,7 +1587,8 @@
162 if ( this->state != iiucs_connected ) {
163 return;
164 }
165- arrayElementCount nElem = subscr.getCount ( guard );
166+ arrayElementCount nElem = subscr.getCount (
167+ guard, CA_V413(this->minorProtocolVersion) );
168 arrayElementCount maxBytes;
169 if ( CA_V49 ( this->minorProtocolVersion ) ) {
170 maxBytes = this->cacRef.largeBufferSizeTCP ();
171@@ -1622,7 +1626,8 @@
172 this->sendQue.insertRequestHeader (
173 CA_PROTO_EVENT_CANCEL, 0u,
174 static_cast < ca_uint16_t > ( subscr.getType ( guard ) ),
175- static_cast < ca_uint16_t > ( subscr.getCount ( guard ) ),
176+ static_cast < ca_uint16_t > ( subscr.getCount (
177+ guard, CA_V413(this->minorProtocolVersion) ) ),
178 chan.getSID(guard), subscr.getId(),
179 CA_V49 ( this->minorProtocolVersion ) );
180 minder.commit ();
181
182=== modified file 'src/catools/caget.c'
183--- src/catools/caget.c 2009-12-15 22:05:55 +0000
184+++ src/catools/caget.c 2010-07-05 08:47:25 +0000
185@@ -127,6 +127,7 @@
186 ppv->value = calloc(1, dbr_size_n(args.type, args.count));
187 memcpy(ppv->value, args.dbr, dbr_size_n(args.type, args.count));
188 ppv->onceConnected = 1;
189+ ppv->nElems = args.count;
190 nRead++;
191 }
192 }
193@@ -183,11 +184,9 @@
194 }
195 }
196 /* Adjust array count */
197- if (reqElems == 0 || pvs[n].nElems < reqElems){
198- pvs[n].reqElems = pvs[n].nElems; /* Use full number of points */
199- } else {
200- pvs[n].reqElems = reqElems; /* Limit to specified number */
201- }
202+ if (reqElems > pvs[n].nElems)
203+ reqElems = pvs[n].nElems;
204+ pvs[n].reqElems = reqElems;
205
206 /* Issue CA request */
207 /* ---------------- */
208@@ -205,13 +204,13 @@
209 (void*)&pvs[n]);
210 } else {
211 /* Allocate value structure */
212- pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].reqElems));
213+ pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].nElems));
214 if(!pvs[n].value) {
215 fprintf(stderr,"Allocation failed\n");
216 return 1;
217 }
218 result = ca_array_get(pvs[n].dbrType,
219- pvs[n].reqElems,
220+ pvs[n].nElems,
221 pvs[n].chid,
222 pvs[n].value);
223 }
224@@ -253,10 +252,13 @@
225 /* -------------- */
226
227 for (n = 0; n < nPvs; n++) {
228+ /* Truncate the data printed to what was requested. */
229+ if (pvs[n].reqElems != 0 && pvs[n].nElems > pvs[n].reqElems)
230+ pvs[n].nElems = pvs[n].reqElems;
231
232 switch (format) {
233 case plain: /* Emulate old caget behaviour */
234- if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
235+ if (pvs[n].nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
236 else printf("%s", pvs[n].name);
237 printf("%c", fieldSeparator);
238 case terse:
239@@ -270,7 +272,7 @@
240 printf("*** no data available (timeout)\n");
241 else
242 {
243- if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
244+ if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].nElems > 1)) {
245 dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
246 int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
247 char *d = calloc(dlen+1, sizeof(char));
248@@ -282,8 +284,8 @@
249 fprintf(stderr,"Failed to allocate space for escaped string\n");
250 }
251 } else {
252- if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].reqElems, fieldSeparator);
253- for (i=0; i<pvs[n].reqElems; ++i) {
254+ if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].nElems, fieldSeparator);
255+ for (i=0; i<pvs[n].nElems; ++i) {
256 if (i) printf ("%c", fieldSeparator);
257 printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
258 }
259@@ -315,8 +317,8 @@
260 else {
261 printf(" Element count: %lu\n"
262 " Value: ",
263- pvs[n].reqElems);
264- if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
265+ pvs[n].nElems);
266+ if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].nElems > 1)) {
267 dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
268 int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
269 char *d = calloc(dlen+1, sizeof(char));
270@@ -328,7 +330,7 @@
271 fprintf(stderr,"Failed to allocate space for escaped string\n");
272 }
273 } else {
274- for (i=0; i<pvs[n].reqElems; ++i) {
275+ for (i=0; i<pvs[n].nElems; ++i) {
276 if (i) printf ("%c", fieldSeparator);
277 printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
278 }
279
280=== modified file 'src/catools/camonitor.c'
281--- src/catools/camonitor.c 2009-12-15 22:05:55 +0000
282+++ src/catools/camonitor.c 2010-07-05 08:47:25 +0000
283@@ -107,6 +107,7 @@
284 if (args.status == ECA_NORMAL)
285 {
286 pv->dbrType = args.type;
287+ pv->nElems = args.count;
288 memcpy(pv->value, args.dbr, dbr_size_n(args.type, args.count));
289
290 print_time_val_sts(pv, reqElems);
291@@ -150,11 +151,9 @@
292 ppv->dbrType = DBR_TIME_STRING;
293 }
294 /* Adjust array count */
295- if (reqElems == 0 || ppv->nElems < reqElems){
296- ppv->reqElems = ppv->nElems; /* Use full number of points */
297- } else {
298- ppv->reqElems = reqElems; /* Limit to specified number */
299- }
300+ if (reqElems > ppv->nElems)
301+ reqElems = ppv->nElems;
302+ ppv->reqElems = reqElems;
303
304 ppv->onceConnected = 1;
305 nConn++;
306@@ -163,7 +162,7 @@
307 /* install monitor once with first connect */
308 if ( ! ppv->value ) {
309 /* Allocate value structure */
310- ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->reqElems));
311+ ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->nElems));
312 if ( ppv->value ) {
313 ppv->status = ca_create_subscription(ppv->dbrType,
314 ppv->reqElems,
315
316=== modified file 'src/catools/tool_lib.c'
317--- src/catools/tool_lib.c 2009-12-15 22:05:55 +0000
318+++ src/catools/tool_lib.c 2010-07-05 08:47:25 +0000
319@@ -455,8 +455,8 @@
320 printf("Failed to allocate for print_time_val_sts\n"); \
321 } \
322 } else { \
323- if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->reqElems); \
324- for (i=0; i<pv->reqElems; ++i) { \
325+ if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->nElems); \
326+ for (i=0; i<pv->nElems; ++i) { \
327 printf("%c%s", fieldSeparator, val2str(value, TYPE_ENUM, i)); \
328 } \
329 } \
330@@ -492,7 +492,7 @@
331 tsInitS = 1;
332 }
333
334- if (pv->reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
335+ if (pv->nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
336 else printf("%s", pv->name);
337 printf("%c", fieldSeparator);
338 if (!pv->onceConnected)
339
340=== modified file 'src/catools/tool_lib.h'
341--- src/catools/tool_lib.h 2009-12-15 22:05:55 +0000
342+++ src/catools/tool_lib.h 2010-07-05 08:47:25 +0000
343@@ -64,8 +64,8 @@
344 chid chid;
345 long dbfType;
346 long dbrType;
347- unsigned long nElems;
348- unsigned long reqElems;
349+ unsigned long nElems; // True length of data in value
350+ unsigned long reqElems; // Requested length of data
351 int status;
352 void* value;
353 epicsTimeStamp tsPreviousC;
354
355=== modified file 'src/db/db_access.c'
356--- src/db/db_access.c 2010-06-16 19:58:00 +0000
357+++ src/db/db_access.c 2010-07-05 08:47:25 +0000
358@@ -149,10 +149,29 @@
359 int epicsShareAPI db_get_field(struct dbAddr *paddr,
360 int buffer_type, void *pbuffer, int no_elements, void *pfl)
361 {
362+ long nRequest = no_elements;
363+ int result = db_get_field_and_count(
364+ paddr, buffer_type, pbuffer, &nRequest, pfl);
365+ if (nRequest < no_elements)
366+ /* If the database request returned fewer elements than requested then
367+ * fill out the remainder of the array with zeros. */
368+ memset(
369+ (char *)pbuffer + dbr_size_n(buffer_type, nRequest), 0,
370+ (no_elements - nRequest) * dbr_value_size[buffer_type]);
371+ return result;
372+}
373+
374+/* Performs the work of the public db_get_field API, but also returns the number
375+ * of elements actually copied to the buffer. The caller is responsible for
376+ * zeroing the remaining part of the buffer. */
377+int epicsShareAPI db_get_field_and_count(
378+ struct dbAddr *paddr, int buffer_type,
379+ void *pbuffer, long *nRequest, void *pfl)
380+{
381 long status;
382 long options;
383- long nRequest;
384 long i;
385+ long zero = 0;
386
387 /* The order of the DBR* elements in the "new" structures below is
388 * very important and must correspond to the order of processing
389@@ -161,82 +180,26 @@
390
391 switch(buffer_type) {
392 case(oldDBR_STRING):
393- {
394- DBSTRING *pvalue = (DBSTRING *)pbuffer;
395-
396- options = 0;
397- nRequest = no_elements;
398- status = dbGetField(paddr, DBR_STRING, pbuffer, &options, &nRequest,
399- pfl);
400- for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
401- }
402+ status = dbGetField(paddr, DBR_STRING, pbuffer, &zero, nRequest, pfl);
403 break;
404 /* case(oldDBR_INT): */
405 case(oldDBR_SHORT):
406- {
407- dbr_short_t *pvalue = (dbr_short_t *)pbuffer;
408-
409- options = 0;
410- nRequest = no_elements;
411- status = dbGetField(paddr, DBR_SHORT, pbuffer, &options, &nRequest,
412- pfl);
413- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
414- }
415+ status = dbGetField(paddr, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
416 break;
417 case(oldDBR_FLOAT):
418- {
419- dbr_float_t *pvalue = (dbr_float_t *)pbuffer;
420-
421- options = 0;
422- nRequest = no_elements;
423- status = dbGetField(paddr, DBR_FLOAT, pbuffer, &options, &nRequest,
424- pfl);
425- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
426- }
427+ status = dbGetField(paddr, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
428 break;
429 case(oldDBR_ENUM):
430- {
431- dbr_enum_t *pvalue = (dbr_enum_t *)pbuffer;
432-
433- options = 0;
434- nRequest = no_elements;
435- status = dbGetField(paddr, DBR_ENUM, pbuffer, &options, &nRequest,
436- pfl);
437- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
438- }
439+ status = dbGetField(paddr, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
440 break;
441 case(oldDBR_CHAR):
442- {
443- dbr_char_t *pvalue = (dbr_char_t *)pbuffer;
444-
445- options = 0;
446- nRequest = no_elements;
447- status = dbGetField(paddr, DBR_CHAR, pbuffer, &options, &nRequest,
448- pfl);
449- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
450- }
451+ status = dbGetField(paddr, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
452 break;
453 case(oldDBR_LONG):
454- {
455- dbr_long_t *pvalue = (dbr_long_t *)pbuffer;
456-
457- options = 0;
458- nRequest = no_elements;
459- status = dbGetField(paddr, DBR_LONG, pbuffer, &options, &nRequest,
460- pfl);
461- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
462- }
463+ status = dbGetField(paddr, DBR_LONG, pbuffer, &zero, nRequest, pfl);
464 break;
465 case(oldDBR_DOUBLE):
466- {
467- dbr_double_t *pvalue = (dbr_double_t *)pbuffer;
468-
469- options = 0;
470- nRequest = no_elements;
471- status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &options, &nRequest,
472- pfl);
473- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
474- }
475+ status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
476 break;
477
478 case(oldDBR_STS_STRING):
479@@ -246,20 +209,14 @@
480 struct dbr_sts_string *pold = (struct dbr_sts_string *)pbuffer;
481 struct {
482 DBRstatus
483- } newSt;
484- DBSTRING *pvalue = (DBSTRING *)pold->value;
485+ } new;
486
487 options = DBR_STATUS;
488- nRequest = 0;
489- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
490- pfl);
491- pold->status = newSt.status;
492- pold->severity = newSt.severity;
493- options = 0;
494- nRequest = no_elements;
495- status = dbGetField(paddr, DBR_STRING, pold->value, &options,
496- &nRequest, pfl);
497- for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
498+ status = dbGetField(paddr, DBR_STRING, &new, &options, &zero, pfl);
499+ pold->status = new.status;
500+ pold->severity = new.severity;
501+ status = dbGetField(paddr, DBR_STRING, pold->value, &zero,
502+ nRequest, pfl);
503 }
504 break;
505 /* case(oldDBR_STS_INT): */
506@@ -268,20 +225,14 @@
507 struct dbr_sts_int *pold = (struct dbr_sts_int *)pbuffer;
508 struct {
509 DBRstatus
510- } newSt;
511- dbr_short_t *pvalue = &pold->value;
512+ } new;
513
514 options = DBR_STATUS;
515- nRequest = 0;
516- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
517- pfl);
518- pold->status = newSt.status;
519- pold->severity = newSt.severity;
520- options = 0;
521- nRequest = no_elements;
522- status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
523- &nRequest, pfl);
524- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
525+ status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
526+ pold->status = new.status;
527+ pold->severity = new.severity;
528+ status = dbGetField(paddr, DBR_SHORT, &pold->value, &zero,
529+ nRequest, pfl);
530 }
531 break;
532 case(oldDBR_STS_FLOAT):
533@@ -289,20 +240,14 @@
534 struct dbr_sts_float *pold = (struct dbr_sts_float *)pbuffer;
535 struct {
536 DBRstatus
537- } newSt;
538- dbr_float_t *pvalue = &pold->value;
539+ } new;
540
541 options = DBR_STATUS;
542- nRequest = 0;
543- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
544- pfl);
545- pold->status = newSt.status;
546- pold->severity = newSt.severity;
547- options = 0;
548- nRequest = no_elements;
549- status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
550- &nRequest, pfl);
551- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
552+ status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
553+ pold->status = new.status;
554+ pold->severity = new.severity;
555+ status = dbGetField(paddr, DBR_FLOAT, &pold->value, &zero,
556+ nRequest, pfl);
557 }
558 break;
559 case(oldDBR_STS_ENUM):
560@@ -310,20 +255,14 @@
561 struct dbr_sts_enum *pold = (struct dbr_sts_enum *)pbuffer;
562 struct {
563 DBRstatus
564- } newSt;
565- dbr_enum_t *pvalue = &pold->value;
566+ } new;
567
568 options = DBR_STATUS;
569- nRequest = 0;
570- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
571- pfl);
572- pold->status = newSt.status;
573- pold->severity = newSt.severity;
574- options = 0;
575- nRequest = no_elements;
576- status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
577- &nRequest, pfl);
578- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
579+ status = dbGetField(paddr, DBR_ENUM, &new, &options, &zero, pfl);
580+ pold->status = new.status;
581+ pold->severity = new.severity;
582+ status = dbGetField(paddr, DBR_ENUM, &pold->value, &zero,
583+ nRequest, pfl);
584 }
585 break;
586 case(oldDBR_STS_CHAR):
587@@ -331,20 +270,14 @@
588 struct dbr_sts_char *pold = (struct dbr_sts_char *)pbuffer;
589 struct {
590 DBRstatus
591- } newSt;
592- dbr_char_t *pvalue = &pold->value;
593+ } new;
594
595 options = DBR_STATUS;
596- nRequest = 0;
597- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
598- pfl);
599- pold->status = newSt.status;
600- pold->severity = newSt.severity;
601- options = 0;
602- nRequest = no_elements;
603- status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
604- &nRequest, pfl);
605- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
606+ status = dbGetField(paddr, DBR_UCHAR, &new, &options, &zero, pfl);
607+ pold->status = new.status;
608+ pold->severity = new.severity;
609+ status = dbGetField(paddr, DBR_UCHAR, &pold->value, &zero,
610+ nRequest, pfl);
611 }
612 break;
613 case(oldDBR_STS_LONG):
614@@ -352,20 +285,14 @@
615 struct dbr_sts_long *pold = (struct dbr_sts_long *)pbuffer;
616 struct {
617 DBRstatus
618- } newSt;
619- dbr_long_t *pvalue = &pold->value;
620+ } new;
621
622 options = DBR_STATUS;
623- nRequest = 0;
624- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
625- pfl);
626- pold->status = newSt.status;
627- pold->severity = newSt.severity;
628- options = 0;
629- nRequest = no_elements;
630- status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
631- &nRequest, pfl);
632- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
633+ status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
634+ pold->status = new.status;
635+ pold->severity = new.severity;
636+ status = dbGetField(paddr, DBR_LONG, &pold->value, &zero,
637+ nRequest, pfl);
638 }
639 break;
640 case(oldDBR_STS_DOUBLE):
641@@ -373,20 +300,15 @@
642 struct dbr_sts_double *pold = (struct dbr_sts_double *)pbuffer;
643 struct {
644 DBRstatus
645- } newSt;
646- dbr_double_t *pvalue = &pold->value;
647+ } new;
648
649 options = DBR_STATUS;
650- nRequest = 0;
651- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
652- pfl);
653- pold->status = newSt.status;
654- pold->severity = newSt.severity;
655+ status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
656+ pold->status = new.status;
657+ pold->severity = new.severity;
658 options = 0;
659- nRequest = no_elements;
660 status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
661- &nRequest, pfl);
662- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
663+ nRequest, pfl);
664 }
665 break;
666
667@@ -396,21 +318,16 @@
668 struct {
669 DBRstatus
670 DBRtime
671- } newSt;
672- DBSTRING *pvalue = (DBSTRING *)(pold->value);
673+ } new;
674
675 options = DBR_STATUS | DBR_TIME;
676- nRequest = 0;
677- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
678- pfl);
679- pold->status = newSt.status;
680- pold->severity = newSt.severity;
681- pold->stamp = newSt.time; /* structure copy */
682+ status = dbGetField(paddr, DBR_STRING, &new, &options, &zero, pfl);
683+ pold->status = new.status;
684+ pold->severity = new.severity;
685+ pold->stamp = new.time; /* structure copy */
686 options = 0;
687- nRequest = no_elements;
688- status = dbGetField(paddr, DBR_STRING, pold->value, &options,
689- &nRequest, pfl);
690- for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
691+ status = dbGetField(paddr, DBR_STRING, pold->value, &options,
692+ nRequest, pfl);
693 }
694 break;
695 /* case(oldDBR_TIME_INT): */
696@@ -420,21 +337,16 @@
697 struct {
698 DBRstatus
699 DBRtime
700- } newSt;
701- dbr_short_t *pvalue = &pold->value;
702+ } new;
703
704 options = DBR_STATUS | DBR_TIME;
705- nRequest = 0;
706- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
707- pfl);
708- pold->status = newSt.status;
709- pold->severity = newSt.severity;
710- pold->stamp = newSt.time; /* structure copy */
711+ status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
712+ pold->status = new.status;
713+ pold->severity = new.severity;
714+ pold->stamp = new.time; /* structure copy */
715 options = 0;
716- nRequest = no_elements;
717 status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
718- &nRequest, pfl);
719- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
720+ nRequest, pfl);
721 }
722 break;
723 case(oldDBR_TIME_FLOAT):
724@@ -443,21 +355,16 @@
725 struct {
726 DBRstatus
727 DBRtime
728- } newSt;
729- dbr_float_t *pvalue = &pold->value;
730+ } new;
731
732 options = DBR_STATUS | DBR_TIME;
733- nRequest = 0;
734- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
735- pfl);
736- pold->status = newSt.status;
737- pold->severity = newSt.severity;
738- pold->stamp = newSt.time; /* structure copy */
739+ status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
740+ pold->status = new.status;
741+ pold->severity = new.severity;
742+ pold->stamp = new.time; /* structure copy */
743 options = 0;
744- nRequest = no_elements;
745 status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
746- &nRequest, pfl);
747- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
748+ nRequest, pfl);
749 }
750 break;
751 case(oldDBR_TIME_ENUM):
752@@ -466,21 +373,16 @@
753 struct {
754 DBRstatus
755 DBRtime
756- } newSt;
757- dbr_enum_t *pvalue = &pold->value;
758+ } new;
759
760 options = DBR_STATUS | DBR_TIME;
761- nRequest = 0;
762- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
763- pfl);
764- pold->status = newSt.status;
765- pold->severity = newSt.severity;
766- pold->stamp = newSt.time; /* structure copy */
767+ status = dbGetField(paddr, DBR_ENUM, &new, &options, &zero, pfl);
768+ pold->status = new.status;
769+ pold->severity = new.severity;
770+ pold->stamp = new.time; /* structure copy */
771 options = 0;
772- nRequest = no_elements;
773 status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
774- &nRequest, pfl);
775- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
776+ nRequest, pfl);
777 }
778 break;
779 case(oldDBR_TIME_CHAR):
780@@ -489,21 +391,16 @@
781 struct {
782 DBRstatus
783 DBRtime
784- } newSt;
785- dbr_char_t *pvalue = &pold->value;
786+ } new;
787
788 options = DBR_STATUS | DBR_TIME;
789- nRequest = 0;
790- status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &nRequest,
791- pfl);
792- pold->status = newSt.status;
793- pold->severity = newSt.severity;
794- pold->stamp = newSt.time; /* structure copy */
795+ status = dbGetField(paddr, DBR_CHAR, &new, &options, &zero, pfl);
796+ pold->status = new.status;
797+ pold->severity = new.severity;
798+ pold->stamp = new.time; /* structure copy */
799 options = 0;
800- nRequest = no_elements;
801 status = dbGetField(paddr, DBR_CHAR, &pold->value, &options,
802- &nRequest, pfl);
803- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
804+ nRequest, pfl);
805 }
806 break;
807 case(oldDBR_TIME_LONG):
808@@ -512,21 +409,16 @@
809 struct {
810 DBRstatus
811 DBRtime
812- } newSt;
813- dbr_long_t *pvalue = &pold->value;
814+ } new;
815
816 options = DBR_STATUS | DBR_TIME;
817- nRequest = 0;
818- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
819- pfl);
820- pold->status = newSt.status;
821- pold->severity = newSt.severity;
822- pold->stamp = newSt.time; /* structure copy */
823+ status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
824+ pold->status = new.status;
825+ pold->severity = new.severity;
826+ pold->stamp = new.time; /* structure copy */
827 options = 0;
828- nRequest = no_elements;
829 status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
830- &nRequest, pfl);
831- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
832+ nRequest, pfl);
833 }
834 break;
835 case(oldDBR_TIME_DOUBLE):
836@@ -535,21 +427,16 @@
837 struct {
838 DBRstatus
839 DBRtime
840- } newSt;
841- dbr_double_t *pvalue = &pold->value;
842+ } new;
843
844 options = DBR_STATUS | DBR_TIME;
845- nRequest = 0;
846- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
847- pfl);
848- pold->status = newSt.status;
849- pold->severity = newSt.severity;
850- pold->stamp = newSt.time; /* structure copy */
851+ status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
852+ pold->status = new.status;
853+ pold->severity = new.severity;
854+ pold->stamp = new.time; /* structure copy */
855 options = 0;
856- nRequest = no_elements;
857 status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
858- &nRequest, pfl);
859- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
860+ nRequest, pfl);
861 }
862 break;
863
864@@ -563,28 +450,23 @@
865 DBRunits
866 DBRgrLong
867 DBRalLong
868- } newSt;
869- dbr_short_t *pvalue = &pold->value;
870+ } new;
871
872 options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
873- nRequest = 0;
874- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
875- pfl);
876- pold->status = newSt.status;
877- pold->severity = newSt.severity;
878- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
879+ status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
880+ pold->status = new.status;
881+ pold->severity = new.severity;
882+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
883 pold->units[MAX_UNITS_SIZE-1] = '\0';
884- pold->upper_disp_limit = newSt.upper_disp_limit;
885- pold->lower_disp_limit = newSt.lower_disp_limit;
886- pold->upper_alarm_limit = newSt.upper_alarm_limit;
887- pold->upper_warning_limit = newSt.upper_warning_limit;
888- pold->lower_warning_limit = newSt.lower_warning_limit;
889- pold->lower_alarm_limit = newSt.lower_alarm_limit;
890+ pold->upper_disp_limit = new.upper_disp_limit;
891+ pold->lower_disp_limit = new.lower_disp_limit;
892+ pold->upper_alarm_limit = new.upper_alarm_limit;
893+ pold->upper_warning_limit = new.upper_warning_limit;
894+ pold->lower_warning_limit = new.lower_warning_limit;
895+ pold->lower_alarm_limit = new.lower_alarm_limit;
896 options = 0;
897- nRequest = no_elements;
898 status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
899- &nRequest, pfl);
900- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
901+ nRequest, pfl);
902 }
903 break;
904 case(oldDBR_GR_FLOAT):
905@@ -596,30 +478,25 @@
906 DBRprecision
907 DBRgrDouble
908 DBRalDouble
909- } newSt;
910- dbr_float_t *pvalue = &pold->value;
911+ } new;
912
913 options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
914 DBR_AL_DOUBLE;
915- nRequest = 0;
916- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
917- pfl);
918- pold->status = newSt.status;
919- pold->severity = newSt.severity;
920- pold->precision = newSt.precision.dp;
921- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
922+ status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
923+ pold->status = new.status;
924+ pold->severity = new.severity;
925+ pold->precision = new.precision.dp;
926+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
927 pold->units[MAX_UNITS_SIZE-1] = '\0';
928- pold->upper_disp_limit = epicsConvertDoubleToFloat(newSt.upper_disp_limit);
929- pold->lower_disp_limit = epicsConvertDoubleToFloat(newSt.lower_disp_limit);
930- pold->upper_alarm_limit = epicsConvertDoubleToFloat(newSt.upper_alarm_limit);
931- pold->lower_alarm_limit = epicsConvertDoubleToFloat(newSt.lower_alarm_limit);
932- pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
933- pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
934+ pold->upper_disp_limit = epicsConvertDoubleToFloat(new.upper_disp_limit);
935+ pold->lower_disp_limit = epicsConvertDoubleToFloat(new.lower_disp_limit);
936+ pold->upper_alarm_limit = epicsConvertDoubleToFloat(new.upper_alarm_limit);
937+ pold->lower_alarm_limit = epicsConvertDoubleToFloat(new.lower_alarm_limit);
938+ pold->upper_warning_limit = epicsConvertDoubleToFloat(new.upper_warning_limit);
939+ pold->lower_warning_limit = epicsConvertDoubleToFloat(new.lower_warning_limit);
940 options = 0;
941- nRequest = no_elements;
942 status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
943- &nRequest, pfl);
944- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
945+ nRequest, pfl);
946 }
947 break;
948 /* case(oldDBR_GR_ENUM): see oldDBR_CTRL_ENUM */
949@@ -631,28 +508,23 @@
950 DBRunits
951 DBRgrLong
952 DBRalLong
953- } newSt;
954- dbr_char_t *pvalue = &pold->value;
955+ } new;
956
957 options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
958- nRequest = 0;
959- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
960- pfl);
961- pold->status = newSt.status;
962- pold->severity = newSt.severity;
963- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
964+ status = dbGetField(paddr, DBR_UCHAR, &new, &options, &zero, pfl);
965+ pold->status = new.status;
966+ pold->severity = new.severity;
967+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
968 pold->units[MAX_UNITS_SIZE-1] = '\0';
969- pold->upper_disp_limit = newSt.upper_disp_limit;
970- pold->lower_disp_limit = newSt.lower_disp_limit;
971- pold->upper_alarm_limit = newSt.upper_alarm_limit;
972- pold->upper_warning_limit = newSt.upper_warning_limit;
973- pold->lower_warning_limit = newSt.lower_warning_limit;
974- pold->lower_alarm_limit = newSt.lower_alarm_limit;
975+ pold->upper_disp_limit = new.upper_disp_limit;
976+ pold->lower_disp_limit = new.lower_disp_limit;
977+ pold->upper_alarm_limit = new.upper_alarm_limit;
978+ pold->upper_warning_limit = new.upper_warning_limit;
979+ pold->lower_warning_limit = new.lower_warning_limit;
980+ pold->lower_alarm_limit = new.lower_alarm_limit;
981 options = 0;
982- nRequest = no_elements;
983 status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
984- &nRequest, pfl);
985- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
986+ nRequest, pfl);
987 }
988 break;
989 case(oldDBR_GR_LONG):
990@@ -663,28 +535,23 @@
991 DBRunits
992 DBRgrLong
993 DBRalLong
994- } newSt;
995- dbr_long_t *pvalue = &pold->value;
996+ } new;
997
998 options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
999- nRequest = 0;
1000- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
1001- pfl);
1002- pold->status = newSt.status;
1003- pold->severity = newSt.severity;
1004- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1005+ status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
1006+ pold->status = new.status;
1007+ pold->severity = new.severity;
1008+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1009 pold->units[MAX_UNITS_SIZE-1] = '\0';
1010- pold->upper_disp_limit = newSt.upper_disp_limit;
1011- pold->lower_disp_limit = newSt.lower_disp_limit;
1012- pold->upper_alarm_limit = newSt.upper_alarm_limit;
1013- pold->upper_warning_limit = newSt.upper_warning_limit;
1014- pold->lower_warning_limit = newSt.lower_warning_limit;
1015- pold->lower_alarm_limit = newSt.lower_alarm_limit;
1016+ pold->upper_disp_limit = new.upper_disp_limit;
1017+ pold->lower_disp_limit = new.lower_disp_limit;
1018+ pold->upper_alarm_limit = new.upper_alarm_limit;
1019+ pold->upper_warning_limit = new.upper_warning_limit;
1020+ pold->lower_warning_limit = new.lower_warning_limit;
1021+ pold->lower_alarm_limit = new.lower_alarm_limit;
1022 options = 0;
1023- nRequest = no_elements;
1024 status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
1025- &nRequest, pfl);
1026- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1027+ nRequest, pfl);
1028 }
1029 break;
1030 case(oldDBR_GR_DOUBLE):
1031@@ -696,30 +563,25 @@
1032 DBRprecision
1033 DBRgrDouble
1034 DBRalDouble
1035- } newSt;
1036- dbr_double_t *pvalue = &pold->value;
1037+ } new;
1038
1039 options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
1040 DBR_AL_DOUBLE;
1041- nRequest = 0;
1042- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
1043- pfl);
1044- pold->status = newSt.status;
1045- pold->severity = newSt.severity;
1046- pold->precision = newSt.precision.dp;
1047- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1048+ status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
1049+ pold->status = new.status;
1050+ pold->severity = new.severity;
1051+ pold->precision = new.precision.dp;
1052+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1053 pold->units[MAX_UNITS_SIZE-1] = '\0';
1054- pold->upper_disp_limit = newSt.upper_disp_limit;
1055- pold->lower_disp_limit = newSt.lower_disp_limit;
1056- pold->upper_alarm_limit = newSt.upper_alarm_limit;
1057- pold->upper_warning_limit = newSt.upper_warning_limit;
1058- pold->lower_warning_limit = newSt.lower_warning_limit;
1059- pold->lower_alarm_limit = newSt.lower_alarm_limit;
1060+ pold->upper_disp_limit = new.upper_disp_limit;
1061+ pold->lower_disp_limit = new.lower_disp_limit;
1062+ pold->upper_alarm_limit = new.upper_alarm_limit;
1063+ pold->upper_warning_limit = new.upper_warning_limit;
1064+ pold->lower_warning_limit = new.lower_warning_limit;
1065+ pold->lower_alarm_limit = new.lower_alarm_limit;
1066 options = 0;
1067- nRequest = no_elements;
1068 status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
1069- &nRequest, pfl);
1070- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1071+ nRequest, pfl);
1072 }
1073 break;
1074
1075@@ -733,31 +595,26 @@
1076 DBRgrLong
1077 DBRctrlLong
1078 DBRalLong
1079- } newSt;
1080- dbr_short_t *pvalue = &pold->value;
1081+ } new;
1082
1083 options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
1084 DBR_AL_LONG;
1085- nRequest = 0;
1086- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
1087- pfl);
1088- pold->status = newSt.status;
1089- pold->severity = newSt.severity;
1090- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1091+ status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
1092+ pold->status = new.status;
1093+ pold->severity = new.severity;
1094+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1095 pold->units[MAX_UNITS_SIZE-1] = '\0';
1096- pold->upper_disp_limit = newSt.upper_disp_limit;
1097- pold->lower_disp_limit = newSt.lower_disp_limit;
1098- pold->upper_alarm_limit = newSt.upper_alarm_limit;
1099- pold->upper_warning_limit = newSt.upper_warning_limit;
1100- pold->lower_warning_limit = newSt.lower_warning_limit;
1101- pold->lower_alarm_limit = newSt.lower_alarm_limit;
1102- pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
1103- pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
1104+ pold->upper_disp_limit = new.upper_disp_limit;
1105+ pold->lower_disp_limit = new.lower_disp_limit;
1106+ pold->upper_alarm_limit = new.upper_alarm_limit;
1107+ pold->upper_warning_limit = new.upper_warning_limit;
1108+ pold->lower_warning_limit = new.lower_warning_limit;
1109+ pold->lower_alarm_limit = new.lower_alarm_limit;
1110+ pold->upper_ctrl_limit = new.upper_ctrl_limit;
1111+ pold->lower_ctrl_limit = new.lower_ctrl_limit;
1112 options = 0;
1113- nRequest = no_elements;
1114 status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
1115- &nRequest, pfl);
1116- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1117+ nRequest, pfl);
1118 }
1119 break;
1120 case(oldDBR_CTRL_FLOAT):
1121@@ -770,32 +627,27 @@
1122 DBRgrDouble
1123 DBRctrlDouble
1124 DBRalDouble
1125- } newSt;
1126- dbr_float_t *pvalue = &pold->value;
1127+ } new;
1128
1129 options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
1130 DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
1131- nRequest = 0;
1132- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
1133- pfl);
1134- pold->status = newSt.status;
1135- pold->severity = newSt.severity;
1136- pold->precision = newSt.precision.dp;
1137- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1138+ status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
1139+ pold->status = new.status;
1140+ pold->severity = new.severity;
1141+ pold->precision = new.precision.dp;
1142+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1143 pold->units[MAX_UNITS_SIZE-1] = '\0';
1144- pold->upper_disp_limit = epicsConvertDoubleToFloat(newSt.upper_disp_limit);
1145- pold->lower_disp_limit = epicsConvertDoubleToFloat(newSt.lower_disp_limit);
1146- pold->upper_alarm_limit = epicsConvertDoubleToFloat(newSt.upper_alarm_limit);
1147- pold->lower_alarm_limit = epicsConvertDoubleToFloat(newSt.lower_alarm_limit);
1148- pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
1149- pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit);
1150- pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
1151- pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit);
1152+ pold->upper_disp_limit = epicsConvertDoubleToFloat(new.upper_disp_limit);
1153+ pold->lower_disp_limit = epicsConvertDoubleToFloat(new.lower_disp_limit);
1154+ pold->upper_alarm_limit = epicsConvertDoubleToFloat(new.upper_alarm_limit);
1155+ pold->lower_alarm_limit = epicsConvertDoubleToFloat(new.lower_alarm_limit);
1156+ pold->upper_warning_limit = epicsConvertDoubleToFloat(new.upper_warning_limit);
1157+ pold->lower_warning_limit = epicsConvertDoubleToFloat(new.lower_warning_limit);
1158+ pold->upper_ctrl_limit = epicsConvertDoubleToFloat(new.upper_ctrl_limit);
1159+ pold->lower_ctrl_limit = epicsConvertDoubleToFloat(new.lower_ctrl_limit);
1160 options = 0;
1161- nRequest = no_elements;
1162 status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
1163- &nRequest, pfl);
1164- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1165+ nRequest, pfl);
1166 }
1167 break;
1168 case(oldDBR_GR_ENUM):
1169@@ -805,29 +657,24 @@
1170 struct {
1171 DBRstatus
1172 DBRenumStrs
1173- } newSt;
1174+ } new;
1175 short no_str;
1176- dbr_enum_t *pvalue = &pold->value;
1177
1178 memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
1179 /* first get status and severity */
1180 options = DBR_STATUS | DBR_ENUM_STRS;
1181- nRequest = 0;
1182- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
1183- pfl);
1184- pold->status = newSt.status;
1185- pold->severity = newSt.severity;
1186- no_str = newSt.no_str;
1187+ status = dbGetField(paddr, DBR_ENUM, &new, &options, &zero, pfl);
1188+ pold->status = new.status;
1189+ pold->severity = new.severity;
1190+ no_str = new.no_str;
1191 if (no_str>16) no_str=16;
1192 pold->no_str = no_str;
1193 for (i = 0; i < no_str; i++)
1194- strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i]));
1195+ strncpy(pold->strs[i], new.strs[i], sizeof(pold->strs[i]));
1196 /*now get values*/
1197 options = 0;
1198- nRequest = no_elements;
1199 status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
1200- &nRequest, pfl);
1201- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1202+ nRequest, pfl);
1203 }
1204 break;
1205 case(oldDBR_CTRL_CHAR):
1206@@ -839,31 +686,26 @@
1207 DBRgrLong
1208 DBRctrlLong
1209 DBRalLong
1210- } newSt;
1211- dbr_char_t *pvalue = &pold->value;
1212+ } new;
1213
1214 options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
1215 DBR_AL_LONG;
1216- nRequest = 0;
1217- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
1218- pfl);
1219- pold->status = newSt.status;
1220- pold->severity = newSt.severity;
1221- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1222+ status = dbGetField(paddr, DBR_UCHAR, &new, &options, &zero, pfl);
1223+ pold->status = new.status;
1224+ pold->severity = new.severity;
1225+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1226 pold->units[MAX_UNITS_SIZE-1] = '\0';
1227- pold->upper_disp_limit = newSt.upper_disp_limit;
1228- pold->lower_disp_limit = newSt.lower_disp_limit;
1229- pold->upper_alarm_limit = newSt.upper_alarm_limit;
1230- pold->upper_warning_limit = newSt.upper_warning_limit;
1231- pold->lower_warning_limit = newSt.lower_warning_limit;
1232- pold->lower_alarm_limit = newSt.lower_alarm_limit;
1233- pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
1234- pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
1235+ pold->upper_disp_limit = new.upper_disp_limit;
1236+ pold->lower_disp_limit = new.lower_disp_limit;
1237+ pold->upper_alarm_limit = new.upper_alarm_limit;
1238+ pold->upper_warning_limit = new.upper_warning_limit;
1239+ pold->lower_warning_limit = new.lower_warning_limit;
1240+ pold->lower_alarm_limit = new.lower_alarm_limit;
1241+ pold->upper_ctrl_limit = new.upper_ctrl_limit;
1242+ pold->lower_ctrl_limit = new.lower_ctrl_limit;
1243 options = 0;
1244- nRequest = no_elements;
1245 status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
1246- &nRequest, pfl);
1247- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1248+ nRequest, pfl);
1249 }
1250 break;
1251 case(oldDBR_CTRL_LONG):
1252@@ -875,31 +717,26 @@
1253 DBRgrLong
1254 DBRctrlLong
1255 DBRalLong
1256- } newSt;
1257- dbr_long_t *pvalue = &pold->value;
1258+ } new;
1259
1260 options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
1261 DBR_AL_LONG;
1262- nRequest = 0;
1263- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
1264- pfl);
1265- pold->status = newSt.status;
1266- pold->severity = newSt.severity;
1267- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1268+ status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
1269+ pold->status = new.status;
1270+ pold->severity = new.severity;
1271+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1272 pold->units[MAX_UNITS_SIZE-1] = '\0';
1273- pold->upper_disp_limit = newSt.upper_disp_limit;
1274- pold->lower_disp_limit = newSt.lower_disp_limit;
1275- pold->upper_alarm_limit = newSt.upper_alarm_limit;
1276- pold->upper_warning_limit = newSt.upper_warning_limit;
1277- pold->lower_warning_limit = newSt.lower_warning_limit;
1278- pold->lower_alarm_limit = newSt.lower_alarm_limit;
1279- pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
1280- pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
1281+ pold->upper_disp_limit = new.upper_disp_limit;
1282+ pold->lower_disp_limit = new.lower_disp_limit;
1283+ pold->upper_alarm_limit = new.upper_alarm_limit;
1284+ pold->upper_warning_limit = new.upper_warning_limit;
1285+ pold->lower_warning_limit = new.lower_warning_limit;
1286+ pold->lower_alarm_limit = new.lower_alarm_limit;
1287+ pold->upper_ctrl_limit = new.upper_ctrl_limit;
1288+ pold->lower_ctrl_limit = new.lower_ctrl_limit;
1289 options = 0;
1290- nRequest = no_elements;
1291 status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
1292- &nRequest, pfl);
1293- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1294+ nRequest, pfl);
1295 }
1296 break;
1297 case(oldDBR_CTRL_DOUBLE):
1298@@ -912,32 +749,27 @@
1299 DBRgrDouble
1300 DBRctrlDouble
1301 DBRalDouble
1302- } newSt;
1303- dbr_double_t *pvalue = &pold->value;
1304+ } new;
1305
1306 options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
1307 DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
1308- nRequest = 0;
1309- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
1310- pfl);
1311- pold->status = newSt.status;
1312- pold->severity = newSt.severity;
1313- pold->precision = newSt.precision.dp;
1314- strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
1315+ status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
1316+ pold->status = new.status;
1317+ pold->severity = new.severity;
1318+ pold->precision = new.precision.dp;
1319+ strncpy(pold->units, new.units, MAX_UNITS_SIZE);
1320 pold->units[MAX_UNITS_SIZE-1] = '\0';
1321- pold->upper_disp_limit = newSt.upper_disp_limit;
1322- pold->lower_disp_limit = newSt.lower_disp_limit;
1323- pold->upper_alarm_limit = newSt.upper_alarm_limit;
1324- pold->upper_warning_limit = newSt.upper_warning_limit;
1325- pold->lower_warning_limit = newSt.lower_warning_limit;
1326- pold->lower_alarm_limit = newSt.lower_alarm_limit;
1327- pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
1328- pold->lower_ctrl_limit = newSt.lower_ctrl_limit;
1329+ pold->upper_disp_limit = new.upper_disp_limit;
1330+ pold->lower_disp_limit = new.lower_disp_limit;
1331+ pold->upper_alarm_limit = new.upper_alarm_limit;
1332+ pold->upper_warning_limit = new.upper_warning_limit;
1333+ pold->lower_warning_limit = new.lower_warning_limit;
1334+ pold->lower_alarm_limit = new.lower_alarm_limit;
1335+ pold->upper_ctrl_limit = new.upper_ctrl_limit;
1336+ pold->lower_ctrl_limit = new.lower_ctrl_limit;
1337 options = 0;
1338- nRequest = no_elements;
1339 status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
1340- &nRequest, pfl);
1341- for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
1342+ nRequest, pfl);
1343 }
1344 break;
1345
1346@@ -946,22 +778,17 @@
1347 struct dbr_stsack_string *pold = (struct dbr_stsack_string *)pbuffer;
1348 struct {
1349 DBRstatus
1350- } newSt;
1351- DBSTRING *pvalue = (DBSTRING *)(pold->value);
1352+ } new;
1353
1354 options = DBR_STATUS;
1355- nRequest = 0;
1356- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
1357- pfl);
1358- pold->status = newSt.status;
1359- pold->severity = newSt.severity;
1360- pold->ackt = newSt.ackt;
1361- pold->acks = newSt.acks;
1362+ status = dbGetField(paddr, DBR_STRING, &new, &options, &zero, pfl);
1363+ pold->status = new.status;
1364+ pold->severity = new.severity;
1365+ pold->ackt = new.ackt;
1366+ pold->acks = new.acks;
1367 options = 0;
1368- nRequest = no_elements;
1369 status = dbGetField(paddr, DBR_STRING, pold->value,
1370- &options, &nRequest, pfl);
1371- for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
1372+ &options, nRequest, pfl);
1373 }
1374 break;
1375
1376
1377=== modified file 'src/db/db_access_routines.h'
1378--- src/db/db_access_routines.h 2002-07-12 21:35:43 +0000
1379+++ src/db/db_access_routines.h 2010-07-05 08:47:25 +0000
1380@@ -39,6 +39,9 @@
1381 DBADDR *paddr, int src_type,const void *psrc, int no_elements);
1382 epicsShareFunc int epicsShareAPI db_get_field(
1383 DBADDR *paddr, int dest_type,void *pdest, int no_elements, void *pfl);
1384+epicsShareFunc int db_get_field_and_count(
1385+ struct dbAddr *paddr, int buffer_type,
1386+ void *pbuffer, long *nRequest, void *pfl);
1387
1388
1389 #ifdef __cplusplus
1390
1391=== modified file 'src/rsrv/camessage.c'
1392--- src/rsrv/camessage.c 2009-07-09 16:37:24 +0000
1393+++ src/rsrv/camessage.c 2010-07-05 08:47:25 +0000
1394@@ -530,12 +530,21 @@
1395 cid = pciu->cid;
1396 }
1397
1398- status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size,
1399- pevext->msg.m_dataType, pevext->msg.m_count, cid, pevext->msg.m_available,
1400+ /* If the client has requested a zero element count we interpret this as a
1401+ * request for all avaiable elements. In this case we initialise the
1402+ * header with the maximum element size specified by the database. */
1403+ int autosize = pevext->msg.m_count == 0;
1404+ long item_count =
1405+ autosize ? paddr->no_elements : pevext->msg.m_count;
1406+ ca_uint32_t payload_size = dbr_size_n(pevext->msg.m_dataType, item_count);
1407+ status = cas_copy_in_header(
1408+ pClient, pevext->msg.m_cmmd, payload_size,
1409+ pevext->msg.m_dataType, item_count, cid, pevext->msg.m_available,
1410 &pPayload );
1411 if ( status != ECA_NORMAL ) {
1412 send_err ( &pevext->msg, status, pClient,
1413- "server unable to load read (or subscription update) response into protocol buffer PV=\"%s\" max bytes=%u",
1414+ "server unable to load read (or subscription update) response "
1415+ "into protocol buffer PV=\"%s\" max bytes=%u",
1416 RECORD_NAME ( paddr ), rsrvSizeofLargeBufTCP );
1417 if ( ! eventsRemaining )
1418 cas_send_bs_msg ( pClient, FALSE );
1419@@ -554,8 +563,8 @@
1420 return;
1421 }
1422
1423- status = db_get_field ( paddr, pevext->msg.m_dataType,
1424- pPayload, pevext->msg.m_count, pfl);
1425+ status = db_get_field_and_count(
1426+ paddr, pevext->msg.m_dataType, pPayload, &item_count, pfl);
1427 if ( status < 0 ) {
1428 /*
1429 * I cant wait to redesign this protocol from scratch!
1430@@ -569,58 +578,52 @@
1431 send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( paddr ) );
1432 }
1433 else {
1434- /*
1435- * New clients recv the status of the
1436- * operation directly to the
1437+ /* New clients recv the status of the operation directly to the
1438 * event/put/get callback.
1439 *
1440- * Fetched value is set to zero in case they
1441- * use it even when the status indicates
1442- * failure.
1443+ * Fetched value is set to zero in case they use it even when the
1444+ * status indicates failure -- unless the client selected autosizing
1445+ * data, in which case they'd better know what they're doing!
1446 *
1447- * The m_cid field in the protocol
1448- * header is abused to carry the status
1449- */
1450- memset ( pPayload, 0, pevext->size );
1451+ * The m_cid field in the protocol header is abused to carry the
1452+ * status */
1453+ if (autosize) {
1454+ payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
1455+ cas_set_header_count(pClient, 0);
1456+ }
1457+ memset ( pPayload, 0, payload_size );
1458 cas_set_header_cid ( pClient, ECA_GETFAIL );
1459- cas_commit_msg ( pClient, pevext->size );
1460+ cas_commit_msg ( pClient, payload_size );
1461 }
1462 }
1463 else {
1464- ca_uint32_t payloadSize = pevext->size;
1465 int cacStatus = caNetConvert (
1466 pevext->msg.m_dataType, pPayload, pPayload,
1467- TRUE /* host -> net format */, pevext->msg.m_count );
1468- if ( cacStatus == ECA_NORMAL ) {
1469- /*
1470- * force string message size to be the true size rounded to even
1471- * boundary
1472- */
1473- if ( pevext->msg.m_dataType == DBR_STRING
1474- && pevext->msg.m_count == 1 ) {
1475- char * pStr = (char *) pPayload;
1476- size_t strcnt = strlen ( pStr );
1477- if ( strcnt < payloadSize ) {
1478- payloadSize = ( ca_uint32_t ) ( strcnt + 1u );
1479- }
1480- else {
1481- pStr[payloadSize-1] = '\0';
1482- errlogPrintf (
1483- "caserver: read_reply: detected DBR_STRING w/o nill termination "
1484- "in response from db_get_field, pPayload = \"%s\"\n",
1485- pStr );
1486- }
1487+ TRUE /* host -> net format */, item_count );
1488+ if ( cacStatus == ECA_NORMAL ) {
1489+ ca_uint32_t data_size =
1490+ dbr_size_n(pevext->msg.m_dataType, item_count);
1491+ if (autosize) {
1492+ payload_size = data_size;
1493+ cas_set_header_count(pClient, item_count);
1494 }
1495+ else if (payload_size > data_size)
1496+ memset(
1497+ (char *) pPayload + data_size, 0, payload_size - data_size);
1498 }
1499 else {
1500- memset ( pPayload, 0, payloadSize );
1501+ if (autosize) {
1502+ payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
1503+ cas_set_header_count(pClient, 0);
1504+ }
1505+ memset ( pPayload, 0, payload_size );
1506 cas_set_header_cid ( pClient, cacStatus );
1507- }
1508- cas_commit_msg ( pClient, payloadSize );
1509+ }
1510+ cas_commit_msg ( pClient, payload_size );
1511 }
1512
1513 /*
1514- * Ensures timely response for events, but does que
1515+ * Ensures timely response for events, but does queue
1516 * them up like db requests when the OPI does not keep up.
1517 */
1518 if ( ! eventsRemaining )
1519
1520=== modified file 'src/rsrv/caserverio.c'
1521--- src/rsrv/caserverio.c 2006-11-20 16:10:02 +0000
1522+++ src/rsrv/caserverio.c 2010-07-05 08:47:25 +0000
1523@@ -33,6 +33,10 @@
1524 #define epicsExportSharedSymbols
1525 #include "server.h"
1526
1527+/* As an optimisation, any message allocated with a large header is resized to
1528+ * use a small header if the payload size is below this threshold. */
1529+#define SMALL_MESSAGE_THRESHOLD 65
1530+
1531 /*
1532 * cas_send_bs_msg()
1533 *
1534@@ -292,32 +296,25 @@
1535 }
1536 }
1537
1538- if ( alignedPayloadSize < 0xffff && nElem < 0xffff ) {
1539- caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
1540- pMsg->m_cmmd = htons ( response );
1541- pMsg->m_postsize = htons ( ( ( ca_uint16_t ) alignedPayloadSize ) );
1542- pMsg->m_dataType = htons ( dataType );
1543- pMsg->m_count = htons ( ( ( ca_uint16_t ) nElem ) );
1544- pMsg->m_cid = htonl ( cid );
1545- pMsg->m_available = htonl ( responseSpecific );
1546- if ( ppPayload ) {
1547- *ppPayload = ( void * ) ( pMsg + 1 );
1548- }
1549+ caHdr *pMsg = (caHdr *) &pclient->send.buf[pclient->send.stk];
1550+ pMsg->m_cmmd = htons(response);
1551+ pMsg->m_dataType = htons(dataType);
1552+ pMsg->m_cid = htonl(cid);
1553+ pMsg->m_available = htonl(responseSpecific);
1554+ if (alignedPayloadSize < 0xffff && nElem < 0xffff) {
1555+ pMsg->m_postsize = htons(((ca_uint16_t) alignedPayloadSize));
1556+ pMsg->m_count = htons(((ca_uint16_t) nElem));
1557+ if (ppPayload)
1558+ *ppPayload = (void *) (pMsg + 1);
1559 }
1560 else {
1561- caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
1562- ca_uint32_t *pW32 = ( ca_uint32_t * ) ( pMsg + 1 );
1563- pMsg->m_cmmd = htons ( response );
1564- pMsg->m_postsize = htons ( 0xffff );
1565- pMsg->m_dataType = htons ( dataType );
1566- pMsg->m_count = htons ( 0u );
1567- pMsg->m_cid = htonl ( cid );
1568- pMsg->m_available = htonl ( responseSpecific );
1569- pW32[0] = htonl ( alignedPayloadSize );
1570- pW32[1] = htonl ( nElem );
1571- if ( ppPayload ) {
1572- *ppPayload = ( void * ) ( pW32 + 2 );
1573- }
1574+ ca_uint32_t *pW32 = (ca_uint32_t *) (pMsg + 1);
1575+ pMsg->m_postsize = htons(0xffff);
1576+ pMsg->m_count = htons(0u);
1577+ pW32[0] = htonl(alignedPayloadSize);
1578+ pW32[1] = htonl(nElem);
1579+ if (ppPayload)
1580+ *ppPayload = (void *) (pW32 + 2);
1581 }
1582
1583 /* zero out pad bytes */
1584@@ -336,6 +333,20 @@
1585 pMsg->m_cid = htonl ( cid );
1586 }
1587
1588+void cas_set_header_count (struct client *pClient, ca_uint32_t count)
1589+{
1590+ caHdr *pMsg = (caHdr *) &pClient->send.buf[pClient->send.stk];
1591+ if (pMsg->m_postsize == htons(0xffff)) {
1592+ assert(pMsg->m_count == 0);
1593+ ca_uint32_t *pLW = (ca_uint32_t *) (pMsg + 1);
1594+ pLW[1] = htonl(count);
1595+ }
1596+ else {
1597+ assert(count < 65536);
1598+ pMsg->m_count = htons((ca_uint16_t) count);
1599+ }
1600+}
1601+
1602 void cas_commit_msg ( struct client *pClient, ca_uint32_t size )
1603 {
1604 caHdr * pMsg = ( caHdr * ) &pClient->send.buf[pClient->send.stk];
1605@@ -343,8 +354,19 @@
1606 if ( pMsg->m_postsize == htons ( 0xffff ) ) {
1607 ca_uint32_t * pLW = ( ca_uint32_t * ) ( pMsg + 1 );
1608 assert ( size <= ntohl ( *pLW ) );
1609- pLW[0] = htonl ( size );
1610- size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
1611+ if (size < SMALL_MESSAGE_THRESHOLD) {
1612+ /* If the message is sufficiently small it can be worth converting a
1613+ * large message header into a small header. This saves us all of 8
1614+ * bytes over the wire, so it's not such a big deal. */
1615+ pMsg->m_postsize = htons((ca_uint16_t) size);
1616+ pMsg->m_count = htons((ca_uint16_t) ntohl(pLW[1]));
1617+ memmove(pLW, pLW + 2, size);
1618+ size += sizeof(caHdr);
1619+ }
1620+ else {
1621+ pLW[0] = htonl ( size );
1622+ size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
1623+ }
1624 }
1625 else {
1626 assert ( size <= ntohs ( pMsg->m_postsize ) );
1627
1628=== modified file 'src/rsrv/server.h'
1629--- src/rsrv/server.h 2009-07-09 16:37:24 +0000
1630+++ src/rsrv/server.h 2010-07-05 08:47:25 +0000
1631@@ -29,7 +29,7 @@
1632 #include "asLib.h"
1633 #include "dbAddr.h"
1634 #include "dbNotify.h"
1635-#define CA_MINOR_PROTOCOL_REVISION 11
1636+#define CA_MINOR_PROTOCOL_REVISION 13
1637 #include "caProto.h"
1638 #include "ellLib.h"
1639 #include "epicsTime.h"
1640@@ -228,6 +228,7 @@
1641 ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
1642 ca_uint32_t responseSpecific, void **pPayload );
1643 void cas_set_header_cid ( struct client *pClient, ca_uint32_t );
1644+void cas_set_header_count (struct client *pClient, ca_uint32_t count);
1645 void cas_commit_msg ( struct client *pClient, ca_uint32_t size );
1646
1647 #endif /*INCLserverh*/

Subscribers

People subscribed via source and target branches