EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base
From: Michael Abbott <[email protected]>
To: [email protected]
Date: Fri, 04 Jun 2010 11:46:22 -0000
Michael Abbott has proposed merging lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)


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...
-- 
https://code.launchpad.net/~michael-abbott/epics-base/dynamic-array/+merge/26796
Your team EPICS Core Developers is requested to review the proposed merge of lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base.
=== modified file '.bzrignore'
--- .bzrignore	2009-12-23 21:06:44 +0000
+++ .bzrignore	2010-06-04 11:46:21 +0000
@@ -1,3 +1,5 @@
+./.git
+./.gitignore
 ./bin
 ./lib
 ./db

=== modified file 'src/ca/caProto.h'
--- src/ca/caProto.h	2004-10-04 18:55:40 +0000
+++ src/ca/caProto.h	2010-06-04 11:46:21 +0000
@@ -40,6 +40,7 @@
 #   define CA_V49(MINOR) ((MINOR)>=9u)    /* large arrays, dispatch priorities */
 #   define CA_V410(MINOR) ((MINOR)>=10u)  /* beacon counter */
 #   define CA_V411(MINOR) ((MINOR)>=11u)  /* sequence numbers in UDP version command */
+#   define CA_V412(MINOR) ((MINOR)>=12u)  /* Allow zero length in requests. */
 #elif CA_MAJOR_PROTOCOL_REVISION > 4u
 #   define CA_V41(MINOR) ( 1u )
 #   define CA_V42(MINOR) ( 1u )
@@ -52,6 +53,7 @@
 #   define CA_V49(MINOR) ( 1u )
 #   define CA_V410(MINOR) ( 1u )
 #   define CA_V411(MINOR) ( 1u )
+#   define CA_V412(MINOR) ( 1u )
 #else
 #   define CA_V41(MINOR) ( 0u )
 #   define CA_V42(MINOR) ( 0u )
@@ -64,6 +66,7 @@
 #   define CA_V49(MINOR) ( 0u )
 #   define CA_V410(MINOR) ( 0u )
 #   define CA_V411(MINOR) ( 0u )
+#   define CA_V412(MINOR) ( 0u )
 #endif 
 
 /*

=== modified file 'src/ca/db_access.h'
--- src/ca/db_access.h	2009-08-14 00:29:56 +0000
+++ src/ca/db_access.h	2010-06-04 11:46:21 +0000
@@ -524,16 +524,16 @@
 	dbr_double_t	value;			/* current value */
 };
 
-#ifndef db_accessHFORdb_accessC
 #define dbr_size_n(TYPE,COUNT)\
 ((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
 
 /* size for each type - array indexed by the DBR_ type code */
-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[];
 
+#ifndef db_accessHFORdb_accessC
 /* class for each type's value */
 enum dbr_value_class { 
 		dbr_class_int, 

=== modified file 'src/ca/nciu.cpp'
--- src/ca/nciu.cpp	2009-08-24 17:03:17 +0000
+++ src/ca/nciu.cpp	2010-06-04 11:46:21 +0000
@@ -291,9 +291,6 @@
     if ( countIn > this->count ) {
         throw cacChannel::outOfBounds ();
     }
-    if ( countIn == 0 ) {
-        countIn = this->count;
-    }
 
     //
     // fail out if their arguments are invalid

=== modified file 'src/ca/nciu.h'
--- src/ca/nciu.h	2008-07-28 16:19:50 +0000
+++ src/ca/nciu.h	2010-06-04 11:46:21 +0000
@@ -41,7 +41,7 @@
 #   include "shareLib.h"
 #endif
 
-#define CA_MINOR_PROTOCOL_REVISION 11
+#define CA_MINOR_PROTOCOL_REVISION 12
 #include "caProto.h"
 
 #include "cacIO.h"
@@ -205,6 +205,7 @@
     void disconnectAllIO ( 
         epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & );
     bool connected ( epicsGuard < epicsMutex > & ) const; 
+    unsigned getcount() const { return count; }
 
 private:
     tsDLList < class baseNMIU > eventq;

=== modified file 'src/ca/netIO.h'
--- src/ca/netIO.h	2004-10-04 18:55:40 +0000
+++ src/ca/netIO.h	2010-06-04 11:46:21 +0000
@@ -83,7 +83,7 @@
     void show ( 
         epicsGuard < epicsMutex > &, unsigned level ) const;
     arrayElementCount getCount (
-        epicsGuard < epicsMutex > & ) const;
+        epicsGuard < epicsMutex > &, bool allow_zero ) const;
     unsigned getType (
         epicsGuard < epicsMutex > & ) const;
     unsigned getMask (
@@ -242,11 +242,11 @@
 }
 
 inline arrayElementCount netSubscription::getCount (
-    epicsGuard < epicsMutex > & guard ) const // X aCC 361
+    epicsGuard < epicsMutex > & guard, bool allow_zero ) const // X aCC 361
 {
     //guard.assertIdenticalMutex ( this->mutex );
     arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard );
-    if ( this->count == 0u || this->count > nativeCount ) {
+    if ( (this->count == 0u && !allow_zero) || this->count > nativeCount ) {
         return nativeCount;
     }
     else {

=== modified file 'src/ca/oldChannelNotify.cpp'
--- src/ca/oldChannelNotify.cpp	2007-01-11 21:45:58 +0000
+++ src/ca/oldChannelNotify.cpp	2010-06-04 11:46:21 +0000
@@ -280,6 +280,9 @@
         if ( type < 0 ) {
             return ECA_BADTYPE;
         }
+        if ( count == 0 )
+            return ECA_BADCOUNT;
+
         unsigned tmpType = static_cast < unsigned > ( type );
         epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
         pChan->eliminateExcessiveSendBacklog ( guard );

=== modified file 'src/ca/tcpiiu.cpp'
--- src/ca/tcpiiu.cpp	2009-09-11 00:49:02 +0000
+++ src/ca/tcpiiu.cpp	2010-06-04 11:46:21 +0000
@@ -1443,6 +1443,8 @@
     if ( nElem > maxElem ) {
         throw cacChannel::msgBodyCacheTooSmall ();
     }
+    if (nElem == 0 && !CA_V412(this->minorProtocolVersion))
+       nElem = chan.getcount();
     comQueSendMsgMinder minder ( this->sendQue, guard );
     this->sendQue.insertRequestHeader ( 
         CA_PROTO_READ_NOTIFY, 0u, 
@@ -1538,7 +1540,8 @@
     if ( mask > 0xffff ) {
         throw cacChannel::badEventSelection ();
     }
-    arrayElementCount nElem = subscr.getCount ( guard );
+    arrayElementCount nElem = subscr.getCount (
+        guard, CA_V412(this->minorProtocolVersion) );
     arrayElementCount maxBytes;
     if ( CA_V49 ( this->minorProtocolVersion ) ) {
         maxBytes = this->cacRef.largeBufferSizeTCP ();
@@ -1584,7 +1587,8 @@
     if ( this->state != iiucs_connected ) {
         return;
     }
-    arrayElementCount nElem = subscr.getCount ( guard );
+    arrayElementCount nElem = subscr.getCount (
+        guard, CA_V412(this->minorProtocolVersion) );
     arrayElementCount maxBytes;
     if ( CA_V49 ( this->minorProtocolVersion ) ) {
         maxBytes = this->cacRef.largeBufferSizeTCP ();
@@ -1622,7 +1626,8 @@
     this->sendQue.insertRequestHeader ( 
         CA_PROTO_EVENT_CANCEL, 0u, 
         static_cast < ca_uint16_t > ( subscr.getType ( guard ) ), 
-        static_cast < ca_uint16_t > ( subscr.getCount ( guard ) ), 
+        static_cast < ca_uint16_t > ( subscr.getCount (
+            guard, CA_V412(this->minorProtocolVersion) ) ),
         chan.getSID(guard), subscr.getId(), 
         CA_V49 ( this->minorProtocolVersion ) );
     minder.commit ();

=== modified file 'src/catools/caget.c'
--- src/catools/caget.c	2009-12-15 22:05:55 +0000
+++ src/catools/caget.c	2010-06-04 11:46:21 +0000
@@ -127,6 +127,7 @@
         ppv->value   = calloc(1, dbr_size_n(args.type, args.count));
         memcpy(ppv->value, args.dbr, dbr_size_n(args.type, args.count));
         ppv->onceConnected = 1;
+        ppv->nElems = args.count;
         nRead++;
     }
 }
@@ -183,11 +184,9 @@
             }
         }
                                 /* Adjust array count */
-        if (reqElems == 0 || pvs[n].nElems < reqElems){
-            pvs[n].reqElems = pvs[n].nElems; /* Use full number of points */
-        } else {
-            pvs[n].reqElems = reqElems;      /* Limit to specified number */
-        }
+        if (reqElems > pvs[n].nElems)
+            reqElems = pvs[n].nElems;
+        pvs[n].reqElems = reqElems;
 
                                 /* Issue CA request */
                                 /* ---------------- */
@@ -205,13 +204,13 @@
                                                (void*)&pvs[n]);
             } else {
                                        /* Allocate value structure */
-                pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].reqElems));
+                pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].nElems));
                 if(!pvs[n].value) {
                     fprintf(stderr,"Allocation failed\n");
                     return 1;
                 }
                 result = ca_array_get(pvs[n].dbrType,
-                                      pvs[n].reqElems,
+                                      pvs[n].nElems,
                                       pvs[n].chid,
                                       pvs[n].value);
             }
@@ -253,10 +252,13 @@
                                 /* -------------- */
 
     for (n = 0; n < nPvs; n++) {
+        /* Truncate the data printed to what was requested. */
+        if (pvs[n].reqElems != 0  && pvs[n].nElems > pvs[n].reqElems)
+            pvs[n].nElems = pvs[n].reqElems;
 
         switch (format) {
         case plain:             /* Emulate old caget behaviour */
-            if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
+            if (pvs[n].nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
             else                                               printf("%s", pvs[n].name);
             printf("%c", fieldSeparator);
         case terse:
@@ -270,7 +272,7 @@
                 printf("*** no data available (timeout)\n");
             else
             {
-                if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
+                if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].nElems > 1)) {
                     dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
                     int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
                     char *d = calloc(dlen+1, sizeof(char));
@@ -282,8 +284,8 @@
                         fprintf(stderr,"Failed to allocate space for escaped string\n");
                     }
                 } else {
-                    if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].reqElems, fieldSeparator);
-                    for (i=0; i<pvs[n].reqElems; ++i) {
+                    if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].nElems, fieldSeparator);
+                    for (i=0; i<pvs[n].nElems; ++i) {
                         if (i) printf ("%c", fieldSeparator);
                         printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
                     }
@@ -315,8 +317,8 @@
                 else {
                     printf("    Element count:    %lu\n"
                            "    Value:            ",
-                           pvs[n].reqElems);
-                    if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
+                           pvs[n].nElems);
+                    if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].nElems > 1)) {
                         dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
                         int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
                         char *d = calloc(dlen+1, sizeof(char));
@@ -328,7 +330,7 @@
                             fprintf(stderr,"Failed to allocate space for escaped string\n");
                         }
                     } else {
-                        for (i=0; i<pvs[n].reqElems; ++i) {
+                        for (i=0; i<pvs[n].nElems; ++i) {
                             if (i) printf ("%c", fieldSeparator);
                             printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
                         }

=== modified file 'src/catools/camonitor.c'
--- src/catools/camonitor.c	2009-12-15 22:05:55 +0000
+++ src/catools/camonitor.c	2010-06-04 11:46:21 +0000
@@ -107,6 +107,7 @@
     if (args.status == ECA_NORMAL)
     {
         pv->dbrType = args.type;
+        pv->nElems = args.count;
         memcpy(pv->value, args.dbr, dbr_size_n(args.type, args.count));
 
         print_time_val_sts(pv, reqElems);
@@ -150,11 +151,9 @@
             ppv->dbrType = DBR_TIME_STRING;
         }
                                 /* Adjust array count */
-        if (reqElems == 0 || ppv->nElems < reqElems){
-            ppv->reqElems = ppv->nElems; /* Use full number of points */
-        } else {
-            ppv->reqElems = reqElems; /* Limit to specified number */
-        }
+        if (reqElems > ppv->nElems)
+            reqElems = ppv->nElems;
+        ppv->reqElems = reqElems;
 
         ppv->onceConnected = 1;
         nConn++;
@@ -163,7 +162,7 @@
         /* install monitor once with first connect */
         if ( ! ppv->value ) {
                                     /* Allocate value structure */
-            ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->reqElems));
+            ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->nElems));
             if ( ppv->value ) {
                 ppv->status = ca_create_subscription(ppv->dbrType,
                                                 ppv->reqElems,

=== modified file 'src/catools/tool_lib.c'
--- src/catools/tool_lib.c	2009-12-15 22:05:55 +0000
+++ src/catools/tool_lib.c	2010-06-04 11:46:21 +0000
@@ -455,8 +455,8 @@
             printf("Failed to allocate for print_time_val_sts\n");      \
         }                                                               \
     } else {                                                            \
-        if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->reqElems); \
-        for (i=0; i<pv->reqElems; ++i) {                                \
+        if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->nElems); \
+        for (i=0; i<pv->nElems; ++i) {                                \
             printf("%c%s", fieldSeparator, val2str(value, TYPE_ENUM, i)); \
         }                                                               \
     }                                                                   \
@@ -492,7 +492,7 @@
         tsInitS = 1;
     }
 
-    if (pv->reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
+    if (pv->nElems <= 1 && fieldSeparator == ' ') printf("%-30s", pv->name);
     else                                            printf("%s", pv->name);
     printf("%c", fieldSeparator);
     if (!pv->onceConnected)

=== modified file 'src/catools/tool_lib.h'
--- src/catools/tool_lib.h	2009-12-15 22:05:55 +0000
+++ src/catools/tool_lib.h	2010-06-04 11:46:21 +0000
@@ -64,8 +64,8 @@
     chid  chid;
     long  dbfType;
     long  dbrType;
-    unsigned long nElems;
-    unsigned long reqElems;
+    unsigned long nElems;       // True length of data in value
+    unsigned long reqElems;     // Requested length of data
     int status;
     void* value;
     epicsTimeStamp tsPreviousC;

=== modified file 'src/db/db_access.c'
--- src/db/db_access.c	2009-03-10 18:51:03 +0000
+++ src/db/db_access.c	2010-06-04 11:46:21 +0000
@@ -149,10 +149,29 @@
 int epicsShareAPI db_get_field(struct dbAddr *paddr,
     int buffer_type, void *pbuffer, int no_elements, void *pfl)
 {
+    long nRequest = no_elements;
+    int result = db_get_field_and_count(
+        paddr, buffer_type, pbuffer, &nRequest, pfl);
+    if (nRequest < no_elements)
+        /* If the database request returned fewer elements than requested then
+         * fill out the remainder of the array with zeros. */
+        memset(
+            (char *)pbuffer + dbr_size_n(buffer_type, nRequest), 0,
+            (no_elements - nRequest) * dbr_value_size[buffer_type]);
+    return result;
+}
+
+/* Performs the work of the public db_get_field API, but also returns the number
+ * of elements actually copied to the buffer.  The caller is responsible for
+ * zeroing the remaining part of the buffer. */
+int epicsShareAPI db_get_field_and_count(
+    struct dbAddr *paddr, int buffer_type,
+    void *pbuffer, long *nRequest, void *pfl)
+{
     long status;
     long options;
-    long nRequest;
     long i;
+    long zero = 0;
 
    /* The order of the DBR* elements in the "new" structures below is
     * very important and must correspond to the order of processing
@@ -161,82 +180,26 @@
 
     switch(buffer_type) {
     case(oldDBR_STRING):
-        {
-            DBSTRING *pvalue = (DBSTRING *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_STRING, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
-        }
+        status = dbGetField(paddr, DBR_STRING, pbuffer, &zero, nRequest, pfl);
         break;
 /*  case(oldDBR_INT): */
     case(oldDBR_SHORT):
-        {
-            dbr_short_t *pvalue = (dbr_short_t *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_SHORT, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
-        }
+        status = dbGetField(paddr, DBR_SHORT, pbuffer, &zero, nRequest, pfl);
         break;
     case(oldDBR_FLOAT):
-        {
-            dbr_float_t *pvalue = (dbr_float_t *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_FLOAT, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
-        }
+        status = dbGetField(paddr, DBR_FLOAT, pbuffer, &zero, nRequest, pfl);
         break;
     case(oldDBR_ENUM):
-        {
-            dbr_enum_t *pvalue = (dbr_enum_t *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_ENUM, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
-        }
+        status = dbGetField(paddr, DBR_ENUM, pbuffer, &zero, nRequest, pfl);
         break;
     case(oldDBR_CHAR):
-        {
-            dbr_char_t *pvalue = (dbr_char_t *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_CHAR, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
-        }
+        status = dbGetField(paddr, DBR_CHAR, pbuffer, &zero, nRequest, pfl);
         break;
     case(oldDBR_LONG):
-        {
-            dbr_long_t *pvalue = (dbr_long_t *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_LONG, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
-        }
+        status = dbGetField(paddr, DBR_LONG, pbuffer, &zero, nRequest, pfl);
         break;
     case(oldDBR_DOUBLE):
-        {
-            dbr_double_t *pvalue = (dbr_double_t *)pbuffer;
-
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &options, &nRequest,
-                pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
-        }
+        status = dbGetField(paddr, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl);
         break;
 
     case(oldDBR_STS_STRING):
@@ -247,19 +210,13 @@
             struct {
                 DBRstatus
             } new;
-            DBSTRING *pvalue = (DBSTRING *)pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_STRING, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_STRING, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_STRING, pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
+            status = dbGetField(paddr, DBR_STRING, pold->value, &zero,
+                nRequest, pfl);
         }
         break;
 /*  case(oldDBR_STS_INT): */
@@ -269,19 +226,13 @@
             struct {
                 DBRstatus
             } new;
-            dbr_short_t *pvalue = &pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_SHORT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+            status = dbGetField(paddr, DBR_SHORT, &pold->value, &zero,
+                nRequest, pfl);
         }
         break;
     case(oldDBR_STS_FLOAT):
@@ -290,19 +241,13 @@
             struct {
                 DBRstatus
             } new;
-            dbr_float_t *pvalue = &pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+            status = dbGetField(paddr, DBR_FLOAT, &pold->value, &zero,
+                nRequest, pfl);
         }
         break;
     case(oldDBR_STS_ENUM):
@@ -311,19 +256,13 @@
             struct {
                 DBRstatus
             } new;
-            dbr_enum_t *pvalue = &pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_ENUM, &new, &options, &nRequest,
-                    pfl);
+            status = dbGetField(paddr, DBR_ENUM, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+            status = dbGetField(paddr, DBR_ENUM, &pold->value, &zero,
+                nRequest, pfl);
         }
         break;
     case(oldDBR_STS_CHAR):
@@ -332,19 +271,13 @@
             struct {
                 DBRstatus
             } new;
-            dbr_char_t *pvalue = &pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_UCHAR, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_UCHAR, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+            status = dbGetField(paddr, DBR_UCHAR, &pold->value, &zero,
+                nRequest, pfl);
         }
         break;
     case(oldDBR_STS_LONG):
@@ -353,19 +286,13 @@
             struct {
                 DBRstatus
             } new;
-            dbr_long_t *pvalue = &pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_LONG, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
-            options = 0;
-            nRequest = no_elements;
-            status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+            status = dbGetField(paddr, DBR_LONG, &pold->value, &zero,
+                nRequest, pfl);
         }
         break;
     case(oldDBR_STS_DOUBLE):
@@ -374,19 +301,14 @@
             struct {
                 DBRstatus
             } new;
-            dbr_double_t *pvalue = &pold->value;
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
 
@@ -397,20 +319,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            DBSTRING *pvalue = (DBSTRING *)(pold->value);
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_STRING, &new, &options, &nRequest,
-                    pfl);
+            status = dbGetField(paddr, DBR_STRING, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
-                status = dbGetField(paddr, DBR_STRING, pold->value, &options,
-                        &nRequest, pfl);
-                for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
+            status = dbGetField(paddr, DBR_STRING, pold->value, &options,
+                    nRequest, pfl);
         }
         break;
 /*  case(oldDBR_TIME_INT): */
@@ -421,20 +338,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            dbr_short_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_SHORT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_TIME_FLOAT):
@@ -444,20 +356,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            dbr_float_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_TIME_ENUM):
@@ -467,20 +374,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            dbr_enum_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_ENUM, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_ENUM, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_TIME_CHAR):
@@ -490,20 +392,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            dbr_char_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_CHAR, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_CHAR, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_CHAR, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_TIME_LONG):
@@ -513,20 +410,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            dbr_long_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_LONG, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_TIME_DOUBLE):
@@ -536,20 +428,15 @@
                 DBRstatus
                 DBRtime
             } new;
-            dbr_double_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_TIME;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->stamp = new.time;         /* structure copy */
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
 
@@ -564,12 +451,9 @@
                 DBRgrLong
                 DBRalLong
             } new;
-            dbr_short_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_SHORT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             strncpy(pold->units, new.units, MAX_UNITS_SIZE);
@@ -581,10 +465,8 @@
             pold->lower_warning_limit = new.lower_warning_limit;
             pold->lower_alarm_limit = new.lower_alarm_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_GR_FLOAT):
@@ -597,13 +479,10 @@
                 DBRgrDouble
                 DBRalDouble
             } new;
-            dbr_float_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
                 DBR_AL_DOUBLE;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->precision = new.precision.dp;
@@ -616,10 +495,8 @@
             pold->upper_warning_limit = epicsConvertDoubleToFloat(new.upper_warning_limit);
             pold->lower_warning_limit = epicsConvertDoubleToFloat(new.lower_warning_limit);
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
 /*  case(oldDBR_GR_ENUM): see oldDBR_CTRL_ENUM */
@@ -632,12 +509,9 @@
                 DBRgrLong
                 DBRalLong
             } new;
-            dbr_char_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_UCHAR, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_UCHAR, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             strncpy(pold->units, new.units, MAX_UNITS_SIZE);
@@ -649,10 +523,8 @@
             pold->lower_warning_limit = new.lower_warning_limit;
             pold->lower_alarm_limit = new.lower_alarm_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_GR_LONG):
@@ -664,12 +536,9 @@
                 DBRgrLong
                 DBRalLong
             } new;
-            dbr_long_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_LONG, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             strncpy(pold->units, new.units, MAX_UNITS_SIZE);
@@ -681,10 +550,8 @@
             pold->lower_warning_limit = new.lower_warning_limit;
             pold->lower_alarm_limit = new.lower_alarm_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_GR_DOUBLE):
@@ -697,13 +564,10 @@
                 DBRgrDouble
                 DBRalDouble
             } new;
-            dbr_double_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
                 DBR_AL_DOUBLE;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->precision = new.precision.dp;
@@ -716,10 +580,8 @@
             pold->lower_warning_limit = new.lower_warning_limit;
             pold->lower_alarm_limit = new.lower_alarm_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
 
@@ -734,13 +596,10 @@
                 DBRctrlLong
                 DBRalLong
             } new;
-            dbr_short_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
                 DBR_AL_LONG;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_SHORT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_SHORT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             strncpy(pold->units, new.units, MAX_UNITS_SIZE);
@@ -754,10 +613,8 @@
             pold->upper_ctrl_limit = new.upper_ctrl_limit;
             pold->lower_ctrl_limit = new.lower_ctrl_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_SHORT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_CTRL_FLOAT):
@@ -771,13 +628,10 @@
                 DBRctrlDouble
                 DBRalDouble
             } new;
-            dbr_float_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
                 DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_FLOAT, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->precision = new.precision.dp;
@@ -792,10 +646,8 @@
             pold->upper_ctrl_limit = epicsConvertDoubleToFloat(new.upper_ctrl_limit);
             pold->lower_ctrl_limit = epicsConvertDoubleToFloat(new.lower_ctrl_limit);
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_FLOAT, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_GR_ENUM):
@@ -807,14 +659,11 @@
                 DBRenumStrs
             } new;
             short no_str;
-            dbr_enum_t *pvalue = &pold->value;
 
             memset(pold, '\0', sizeof(struct dbr_ctrl_enum));
             /* first get status and severity */
             options = DBR_STATUS | DBR_ENUM_STRS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_ENUM, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_ENUM, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             no_str = new.no_str;
@@ -824,10 +673,8 @@
                 strncpy(pold->strs[i], new.strs[i], sizeof(pold->strs[i]));
             /*now get values*/
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_ENUM, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_CTRL_CHAR):
@@ -840,13 +687,10 @@
                 DBRctrlLong
                 DBRalLong
             } new;
-            dbr_char_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
                 DBR_AL_LONG;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_UCHAR, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_UCHAR, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             strncpy(pold->units, new.units, MAX_UNITS_SIZE);
@@ -860,10 +704,8 @@
             pold->upper_ctrl_limit = new.upper_ctrl_limit;
             pold->lower_ctrl_limit = new.lower_ctrl_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_UCHAR, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_CTRL_LONG):
@@ -876,13 +718,10 @@
                 DBRctrlLong
                 DBRalLong
             } new;
-            dbr_long_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG |
                 DBR_AL_LONG;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_LONG, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_LONG, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             strncpy(pold->units, new.units, MAX_UNITS_SIZE);
@@ -896,10 +735,8 @@
             pold->upper_ctrl_limit = new.upper_ctrl_limit;
             pold->lower_ctrl_limit = new.lower_ctrl_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_LONG, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
     case(oldDBR_CTRL_DOUBLE):
@@ -913,13 +750,10 @@
                 DBRctrlDouble
                 DBRalDouble
             } new;
-            dbr_double_t *pvalue = &pold->value;
 
             options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE |
                 DBR_CTRL_DOUBLE | DBR_AL_DOUBLE;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_DOUBLE, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->precision = new.precision.dp;
@@ -934,10 +768,8 @@
             pold->upper_ctrl_limit = new.upper_ctrl_limit;
             pold->lower_ctrl_limit = new.lower_ctrl_limit;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_DOUBLE, &pold->value, &options,
-                &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i] = 0;
+                nRequest, pfl);
         }
         break;
 
@@ -947,21 +779,16 @@
             struct {
                 DBRstatus
             } new;
-            DBSTRING *pvalue = (DBSTRING *)(pold->value);
 
             options = DBR_STATUS;
-            nRequest = 0;
-            status = dbGetField(paddr, DBR_STRING, &new, &options, &nRequest,
-                pfl);
+            status = dbGetField(paddr, DBR_STRING, &new, &options, &zero, pfl);
             pold->status = new.status;
             pold->severity = new.severity;
             pold->ackt = new.ackt;
             pold->acks = new.acks;
             options = 0;
-            nRequest = no_elements;
             status = dbGetField(paddr, DBR_STRING, pold->value,
-                &options, &nRequest, pfl);
-            for (i = nRequest; i < no_elements; i++) pvalue[i][0] = 0;
+                &options, nRequest, pfl);
         }
         break;
 

=== modified file 'src/db/db_access_routines.h'
--- src/db/db_access_routines.h	2002-07-12 21:35:43 +0000
+++ src/db/db_access_routines.h	2010-06-04 11:46:21 +0000
@@ -39,6 +39,9 @@
     DBADDR *paddr, int src_type,const void *psrc, int no_elements);
 epicsShareFunc int epicsShareAPI db_get_field(
     DBADDR *paddr, int dest_type,void *pdest, int no_elements, void *pfl);
+epicsShareFunc int db_get_field_and_count(
+    struct dbAddr *paddr, int buffer_type,
+    void *pbuffer, long *nRequest, void *pfl);
 
 
 #ifdef __cplusplus

=== modified file 'src/rsrv/camessage.c'
--- src/rsrv/camessage.c	2009-07-09 16:37:24 +0000
+++ src/rsrv/camessage.c	2010-06-04 11:46:21 +0000
@@ -530,12 +530,21 @@
         cid = pciu->cid;
     }
 
-    status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size, 
-        pevext->msg.m_dataType, pevext->msg.m_count, cid, pevext->msg.m_available,
+    /* If the client has requested a zero element count we interpret this as a
+     * request for all avaiable elements.  In this case we initialise the
+     * header with the maximum element size specified by the database. */
+    int autosize = pevext->msg.m_count == 0;
+    long item_count =
+        autosize ? paddr->no_elements : pevext->msg.m_count;
+    ca_uint32_t payload_size = dbr_size_n(pevext->msg.m_dataType, item_count);
+    status = cas_copy_in_header(
+        pClient, pevext->msg.m_cmmd, payload_size,
+        pevext->msg.m_dataType, item_count, cid, pevext->msg.m_available,
         &pPayload );
     if ( status != ECA_NORMAL ) {
         send_err ( &pevext->msg, status, pClient, 
-            "server unable to load read (or subscription update) response into protocol buffer PV=\"%s\" max bytes=%u",
+            "server unable to load read (or subscription update) response "
+            "into protocol buffer PV=\"%s\" max bytes=%u",
             RECORD_NAME ( paddr ), rsrvSizeofLargeBufTCP );
         if ( ! eventsRemaining )
             cas_send_bs_msg ( pClient, FALSE );
@@ -554,8 +563,8 @@
         return;
     }
 
-    status = db_get_field ( paddr, pevext->msg.m_dataType,
-                  pPayload, pevext->msg.m_count, pfl);
+    status = db_get_field_and_count(
+        paddr, pevext->msg.m_dataType, pPayload, &item_count, pfl);
     if ( status < 0 ) {
         /*
          * I cant wait to redesign this protocol from scratch!
@@ -569,58 +578,52 @@
             send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( paddr ) );
         }
         else {
-            /*
-             * New clients recv the status of the
-             * operation directly to the
+            /* New clients recv the status of the operation directly to the
              * event/put/get callback.
              *
-             * Fetched value is set to zero in case they
-             * use it even when the status indicates 
-             * failure.
+             * Fetched value is set to zero in case they use it even when the
+             * status indicates failure -- unless the client selected autosizing
+             * data, in which case they'd better know what they're doing!
              *
-             * The m_cid field in the protocol
-             * header is abused to carry the status
-             */
-            memset ( pPayload, 0, pevext->size );
+             * The m_cid field in the protocol header is abused to carry the
+             * status */
+            if (autosize) {
+                payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
+                cas_set_header_count(pClient, 0);
+            }
+            memset ( pPayload, 0, payload_size );
             cas_set_header_cid ( pClient, ECA_GETFAIL );
-            cas_commit_msg ( pClient, pevext->size );
+            cas_commit_msg ( pClient, payload_size );
         }
     }
     else {
-        ca_uint32_t payloadSize = pevext->size;
         int cacStatus = caNetConvert ( 
             pevext->msg.m_dataType, pPayload, pPayload, 
-            TRUE /* host -> net format */, pevext->msg.m_count );
-	    if ( cacStatus == ECA_NORMAL ) {
-            /*
-            * force string message size to be the true size rounded to even
-            * boundary
-            */
-            if ( pevext->msg.m_dataType == DBR_STRING 
-                && pevext->msg.m_count == 1 ) {
-                char * pStr = (char *) pPayload;
-                size_t strcnt = strlen ( pStr );
-                if ( strcnt < payloadSize ) {
-                    payloadSize = ( ca_uint32_t ) ( strcnt + 1u );
-                }
-                else {
-                    pStr[payloadSize-1] = '\0';
-                    errlogPrintf ( 
-                        "caserver: read_reply: detected DBR_STRING w/o nill termination "
-                        "in response from db_get_field, pPayload = \"%s\"\n",
-                        pStr );
-                }
+            TRUE /* host -> net format */, item_count );
+        if ( cacStatus == ECA_NORMAL ) {
+            ca_uint32_t data_size =
+                dbr_size_n(pevext->msg.m_dataType, item_count);
+            if (autosize) {
+                payload_size = data_size;
+                cas_set_header_count(pClient, item_count);
             }
+            else
+                memset(
+                    (char *) pPayload + data_size, 0, payload_size - data_size);
         }
         else {
-            memset ( pPayload, 0, payloadSize );
+            if (autosize) {
+                payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
+                cas_set_header_count(pClient, 0);
+            }
+            memset ( pPayload, 0, payload_size );
             cas_set_header_cid ( pClient, cacStatus );
-	    }
-        cas_commit_msg ( pClient, payloadSize );
+        }
+        cas_commit_msg ( pClient, payload_size );
     }
 
     /*
-     * Ensures timely response for events, but does que 
+     * Ensures timely response for events, but does queue 
      * them up like db requests when the OPI does not keep up.
      */
     if ( ! eventsRemaining )

=== modified file 'src/rsrv/caserverio.c'
--- src/rsrv/caserverio.c	2006-11-20 16:10:02 +0000
+++ src/rsrv/caserverio.c	2010-06-04 11:46:21 +0000
@@ -33,6 +33,10 @@
 #define epicsExportSharedSymbols
 #include "server.h"
 
+/* As an optimisation, any message allocated with a large header is resized to
+ * use a small header if the payload size is below this threshold. */
+#define SMALL_MESSAGE_THRESHOLD     65
+
 /*
  *  cas_send_bs_msg()
  *
@@ -292,32 +296,25 @@
         }
     }
 
-    if ( alignedPayloadSize < 0xffff && nElem < 0xffff ) {
-        caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];        
-        pMsg->m_cmmd = htons ( response );   
-        pMsg->m_postsize = htons ( ( ( ca_uint16_t ) alignedPayloadSize ) ); 
-        pMsg->m_dataType = htons ( dataType );  
-        pMsg->m_count = htons ( ( ( ca_uint16_t ) nElem ) );      
-        pMsg->m_cid = htonl ( cid );          
-        pMsg->m_available = htonl ( responseSpecific );  
-        if ( ppPayload ) {
-            *ppPayload = ( void * ) ( pMsg + 1 );
-        }
+    caHdr *pMsg = (caHdr *) &pclient->send.buf[pclient->send.stk];
+    pMsg->m_cmmd = htons(response);
+    pMsg->m_dataType = htons(dataType);
+    pMsg->m_cid = htonl(cid);
+    pMsg->m_available = htonl(responseSpecific);
+    if (alignedPayloadSize < 0xffff && nElem < 0xffff) {
+        pMsg->m_postsize = htons(((ca_uint16_t) alignedPayloadSize));
+        pMsg->m_count = htons(((ca_uint16_t) nElem));
+        if (ppPayload)
+            *ppPayload = (void *) (pMsg + 1);
     }
     else {
-        caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
-        ca_uint32_t *pW32 = ( ca_uint32_t * ) ( pMsg + 1 );
-        pMsg->m_cmmd = htons ( response );   
-        pMsg->m_postsize = htons ( 0xffff ); 
-        pMsg->m_dataType = htons ( dataType );  
-        pMsg->m_count = htons ( 0u );      
-        pMsg->m_cid = htonl ( cid );          
-        pMsg->m_available = htonl ( responseSpecific ); 
-        pW32[0] = htonl ( alignedPayloadSize );
-        pW32[1] = htonl ( nElem );
-        if ( ppPayload ) {
-            *ppPayload = ( void * ) ( pW32 + 2 );
-        }
+        ca_uint32_t *pW32 = (ca_uint32_t *) (pMsg + 1);
+        pMsg->m_postsize = htons(0xffff);
+        pMsg->m_count = htons(0u);
+        pW32[0] = htonl(alignedPayloadSize);
+        pW32[1] = htonl(nElem);
+        if (ppPayload)
+            *ppPayload = (void *) (pW32 + 2);
     }
 
     /* zero out pad bytes */
@@ -336,6 +333,20 @@
     pMsg->m_cid = htonl ( cid );
 }
 
+void cas_set_header_count (struct client *pClient, ca_uint32_t count)
+{
+    caHdr *pMsg = (caHdr *) &pClient->send.buf[pClient->send.stk];
+    if (pMsg->m_postsize == htons(0xffff)) {
+        assert(pMsg->m_count == 0);
+        ca_uint32_t *pLW = (ca_uint32_t *) (pMsg + 1);
+        pLW[1] = htonl(count);
+    }
+    else {
+        assert(count < 65536);
+        pMsg->m_count = htons((ca_uint16_t) count);
+    }
+}
+
 void cas_commit_msg ( struct client *pClient, ca_uint32_t size )
 {
     caHdr * pMsg = ( caHdr * ) &pClient->send.buf[pClient->send.stk];
@@ -343,8 +354,19 @@
     if ( pMsg->m_postsize == htons ( 0xffff ) ) {
         ca_uint32_t * pLW = ( ca_uint32_t * ) ( pMsg + 1 );
         assert ( size <= ntohl ( *pLW ) );
-        pLW[0] = htonl ( size );
-        size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
+        if (size < SMALL_MESSAGE_THRESHOLD) {
+            /* If the message is sufficiently small it can be worth converting a
+             * large message header into a small header.  This saves us all of 8
+             * bytes over the wire, so it's not such a big deal. */
+            pMsg->m_postsize = htons((ca_uint16_t) size);
+            pMsg->m_count = htons((ca_uint16_t) ntohl(pLW[1]));
+            memmove(pLW, pLW + 2, size);
+            size += sizeof(caHdr);
+        }
+        else {
+            pLW[0] = htonl ( size );
+            size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
+        }
     }
     else {
         assert ( size <= ntohs ( pMsg->m_postsize ) );

=== modified file 'src/rsrv/server.h'
--- src/rsrv/server.h	2009-07-09 16:37:24 +0000
+++ src/rsrv/server.h	2010-06-04 11:46:21 +0000
@@ -29,7 +29,7 @@
 #include "asLib.h"
 #include "dbAddr.h"
 #include "dbNotify.h"
-#define CA_MINOR_PROTOCOL_REVISION 11
+#define CA_MINOR_PROTOCOL_REVISION 12
 #include "caProto.h"
 #include "ellLib.h"
 #include "epicsTime.h"
@@ -228,6 +228,7 @@
     ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid, 
     ca_uint32_t responseSpecific, void **pPayload );
 void cas_set_header_cid ( struct client *pClient, ca_uint32_t );
+void cas_set_header_count (struct client *pClient, ca_uint32_t count);
 void cas_commit_msg ( struct client *pClient, ca_uint32_t size );
 
 #endif /*INCLserverh*/


Replies:
Re: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base Michael Abbott
Re: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base Michael Abbott
Re: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base Jeff Hill
Re: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base Michael Abbott

Navigate by Date:
Prev: RE: Hacking rsrv/camessage.c michael.abbott
Next: Re: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base Michael Abbott
Index: 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: [PATCH 3/4] Add autosizing array support for caget and camonitor. Michael Abbott
Next: Re: [Merge] lp:~michael-abbott/epics-base/dynamic-array into lp:epics-base Michael Abbott
Index: 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·