From a0c0c553477d402ed775687a4573cedc1d0b7551 Mon Sep 17 00:00:00 2001
From: Michael Abbott
Date: Wed, 11 Aug 2010 16:22:54 -0500
Subject: [PATCH 01/10] Client side support for automatic resizing arrays.
In this commit the channel access client is modified to allow a zero
size request in a caget or camonitor call. This is passed through to
the corresponding CA_PROTO_READ_NOTIFY or CA_PROTO_EVENT__ADD message,
but only if the minor version of the protocol is >=13.
This commit also adds a new protocol test, CA_V413(), which detects a
server which claims to understand the new zero length request.
Finally, this commit prepares for a subtle change in the CA protocol.
A request for a zero length subscription or data request, which will
only be made for protocol version 4.13 and above, is interpreted as a
request for autosized data, where the intrinsic dynamic length of the
requested waveform should be returned.
With the synchronous ca_array_get() call there is no mechanism available
to pass back the size of the retrieved data if it is different from
the requested count, so the simplest thing is to ensure we don't
request autosizing data through this api.
---
src/ca/caProto.h | 3 +++
src/ca/nciu.cpp | 3 ---
src/ca/nciu.h | 1 +
src/ca/netIO.h | 6 +++---
src/ca/oldChannelNotify.cpp | 3 +++
src/ca/tcpiiu.cpp | 11 ++++++++---
6 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/ca/caProto.h b/src/ca/caProto.h
index 84190bf56..f61f52e08 100644
--- a/src/ca/caProto.h
+++ b/src/ca/caProto.h
@@ -41,6 +41,7 @@
# 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) /* TCP-based search requests */
+# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
#elif CA_MAJOR_PROTOCOL_REVISION > 4u
# define CA_V41(MINOR) ( 1u )
# define CA_V42(MINOR) ( 1u )
@@ -54,6 +55,7 @@
# define CA_V410(MINOR) ( 1u )
# define CA_V411(MINOR) ( 1u )
# define CA_V412(MINOR) ( 1u )
+# define CA_V413(MINOR) ( 1u )
#else
# define CA_V41(MINOR) ( 0u )
# define CA_V42(MINOR) ( 0u )
@@ -67,6 +69,7 @@
# define CA_V410(MINOR) ( 0u )
# define CA_V411(MINOR) ( 0u )
# define CA_V412(MINOR) ( 0u )
+# define CA_V413(MINOR) ( 0u )
#endif
/*
diff --git a/src/ca/nciu.cpp b/src/ca/nciu.cpp
index f61172808..c5ae941b2 100644
--- a/src/ca/nciu.cpp
+++ b/src/ca/nciu.cpp
@@ -291,9 +291,6 @@ cacChannel::ioStatus nciu::read (
if ( countIn > this->count ) {
throw cacChannel::outOfBounds ();
}
- if ( countIn == 0 ) {
- countIn = this->count;
- }
//
// fail out if their arguments are invalid
diff --git a/src/ca/nciu.h b/src/ca/nciu.h
index 5660a8c85..f05a13b96 100644
--- a/src/ca/nciu.h
+++ b/src/ca/nciu.h
@@ -205,6 +205,7 @@ public:
void disconnectAllIO (
epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & );
bool connected ( epicsGuard < epicsMutex > & ) const;
+ unsigned getcount() const { return count; }
private:
tsDLList < class baseNMIU > eventq;
diff --git a/src/ca/netIO.h b/src/ca/netIO.h
index b694bc141..57273427a 100644
--- a/src/ca/netIO.h
+++ b/src/ca/netIO.h
@@ -83,7 +83,7 @@ public:
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 netSubscription * netSubscription::factory (
}
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 {
diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp
index 48ddde124..8865f8d63 100644
--- a/src/ca/oldChannelNotify.cpp
+++ b/src/ca/oldChannelNotify.cpp
@@ -280,6 +280,9 @@ int epicsShareAPI ca_array_get ( chtype type,
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 );
diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp
index 214b0687c..20e2abc3b 100644
--- a/src/ca/tcpiiu.cpp
+++ b/src/ca/tcpiiu.cpp
@@ -1464,6 +1464,8 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
if ( nElem > maxElem ) {
throw cacChannel::msgBodyCacheTooSmall ();
}
+ if (nElem == 0 && !CA_V413(this->minorProtocolVersion))
+ nElem = chan.getcount();
comQueSendMsgMinder minder ( this->sendQue, guard );
this->sendQue.insertRequestHeader (
CA_PROTO_READ_NOTIFY, 0u,
@@ -1559,7 +1561,8 @@ void tcpiiu::subscriptionRequest (
if ( mask > 0xffff ) {
throw cacChannel::badEventSelection ();
}
- arrayElementCount nElem = subscr.getCount ( guard );
+ arrayElementCount nElem = subscr.getCount (
+ guard, CA_V413(this->minorProtocolVersion) );
arrayElementCount maxBytes;
if ( CA_V49 ( this->minorProtocolVersion ) ) {
maxBytes = this->cacRef.largeBufferSizeTCP ();
@@ -1605,7 +1608,8 @@ void tcpiiu::subscriptionUpdateRequest (
if ( this->state != iiucs_connected ) {
return;
}
- arrayElementCount nElem = subscr.getCount ( guard );
+ arrayElementCount nElem = subscr.getCount (
+ guard, CA_V413(this->minorProtocolVersion) );
arrayElementCount maxBytes;
if ( CA_V49 ( this->minorProtocolVersion ) ) {
maxBytes = this->cacRef.largeBufferSizeTCP ();
@@ -1643,7 +1647,8 @@ void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, // X
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_V413(this->minorProtocolVersion) ) ),
chan.getSID(guard), subscr.getId(),
CA_V49 ( this->minorProtocolVersion ) );
minder.commit ();
From e87bbef75c0ac0f281842d3a7efd043fb21c9014 Mon Sep 17 00:00:00 2001
From: Michael Abbott
Date: Wed, 11 Aug 2010 16:38:49 -0500
Subject: [PATCH 02/10] Update rsrv to support V4.13 protocol extension.
The rsrv server is updated in this commit to deliver variable sized
waveforms in response to a zero length request, implementing an
extension to the v4 EPICS protocol tied to minor version 13.
The core of the changes are in read_reply, rsrv/camessage.c, which first
reserves packet space for the largest possible response, but then resizes
the packet according to how much data is actually returned from the
database.
---
src/ca/db_access.h | 6 +-
src/db/db_access.c | 347 +++++++++---------------------------
src/db/db_access_routines.h | 3 +
src/rsrv/camessage.c | 85 ++++-----
src/rsrv/caserverio.c | 14 ++
src/rsrv/server.h | 3 +-
6 files changed, 153 insertions(+), 305 deletions(-)
diff --git a/src/ca/db_access.h b/src/ca/db_access.h
index e88a929d0..92aa5d011 100644
--- a/src/ca/db_access.h
+++ b/src/ca/db_access.h
@@ -524,16 +524,16 @@ struct dbr_ctrl_double{
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,
diff --git a/src/db/db_access.c b/src/db/db_access.c
index 6f389257f..98ff26361 100644
--- a/src/db/db_access.c
+++ b/src/db/db_access.c
@@ -148,95 +148,58 @@ int epicsShareAPI db_name_to_addr(const char *pname, struct dbAddr *paddr)
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
+ /* The order of the DBR* elements in the "newSt" structures below is
* very important and must correspond to the order of processing
* in the dbAccess.c dbGet() and getOptions() routines.
*/
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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- DBSTRING *pvalue = (DBSTRING *)pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- dbr_float_t *pvalue = &pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- dbr_enum_t *pvalue = &pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- dbr_double_t *pvalue = &pold->value;
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- DBSTRING *pvalue = (DBSTRING *)(pold->value);
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- dbr_float_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- dbr_enum_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_CHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRstatus
DBRtime
} newSt;
- dbr_double_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_TIME;
- nRequest = 0;
- status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->stamp = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrLong
DBRalLong
} newSt;
- dbr_short_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
- nRequest = 0;
- status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -581,10 +465,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrDouble
DBRalDouble
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -616,10 +495,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit);
pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrLong
DBRalLong
} newSt;
- dbr_char_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
- nRequest = 0;
- status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -649,10 +523,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrLong
DBRalLong
} newSt;
- dbr_long_t *pvalue = &pold->value;
options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG;
- nRequest = 0;
- status = dbGetField(paddr, DBR_LONG, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -681,10 +550,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRgrDouble
DBRalDouble
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -716,10 +580,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->lower_warning_limit = newSt.lower_warning_limit;
pold->lower_alarm_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlLong
DBRalLong
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_SHORT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -754,10 +613,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlDouble
DBRalDouble
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_FLOAT, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -792,10 +646,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit);
pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRenumStrs
} newSt;
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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_ENUM, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
no_str = newSt.no_str;
@@ -824,10 +673,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
strncpy(pold->strs[i], newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlLong
DBRalLong
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_UCHAR, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -860,10 +704,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlLong
DBRalLong
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_LONG, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
strncpy(pold->units, newSt.units, MAX_UNITS_SIZE);
@@ -896,10 +735,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
DBRctrlDouble
DBRalDouble
} newSt;
- 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, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_DOUBLE, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->precision = newSt.precision.dp;
@@ -934,10 +768,8 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
pold->upper_ctrl_limit = newSt.upper_ctrl_limit;
pold->lower_ctrl_limit = newSt.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 @@ int epicsShareAPI db_get_field(struct dbAddr *paddr,
struct {
DBRstatus
} newSt;
- DBSTRING *pvalue = (DBSTRING *)(pold->value);
options = DBR_STATUS;
- nRequest = 0;
- status = dbGetField(paddr, DBR_STRING, &newSt, &options, &nRequest,
- pfl);
+ status = dbGetField(paddr, DBR_STRING, &newSt, &options, &zero, pfl);
pold->status = newSt.status;
pold->severity = newSt.severity;
pold->ackt = newSt.ackt;
pold->acks = newSt.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;
diff --git a/src/db/db_access_routines.h b/src/db/db_access_routines.h
index 4dde58fb7..a45c24e29 100644
--- a/src/db/db_access_routines.h
+++ b/src/db/db_access_routines.h
@@ -39,6 +39,9 @@ epicsShareFunc int epicsShareAPI db_put_field(
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
diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c
index 984d04cfb..8542becb8 100644
--- a/src/rsrv/camessage.c
+++ b/src/rsrv/camessage.c
@@ -528,12 +528,21 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
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 );
@@ -552,8 +561,8 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
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!
@@ -567,58 +576,52 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
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 )
diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c
index 34ead95e1..4d8b77385 100644
--- a/src/rsrv/caserverio.c
+++ b/src/rsrv/caserverio.c
@@ -336,6 +336,20 @@ void cas_set_header_cid ( struct client *pClient, ca_uint32_t cid )
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];
diff --git a/src/rsrv/server.h b/src/rsrv/server.h
index 5fe69c638..6d1dfc38f 100644
--- a/src/rsrv/server.h
+++ b/src/rsrv/server.h
@@ -27,7 +27,7 @@
#include "asLib.h"
#include "dbAddr.h"
#include "dbNotify.h"
-#define CA_MINOR_PROTOCOL_REVISION 12
+#define CA_MINOR_PROTOCOL_REVISION 13
#include "caProto.h"
#include "ellLib.h"
#include "epicsTime.h"
@@ -226,6 +226,7 @@ int cas_copy_in_header (
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*/
From aa23ab63f19ea3b836c7cd974bd4c67b6d635c0a Mon Sep 17 00:00:00 2001
From: Michael Abbott
Date: Wed, 11 Aug 2010 16:39:52 -0500
Subject: [PATCH 03/10] Add autosizing array support for caget and camonitor.
---
src/catools/caget.c | 30 ++++++++++++++++--------------
src/catools/camonitor.c | 11 +++++------
src/catools/tool_lib.c | 6 +++---
src/catools/tool_lib.h | 4 ++--
4 files changed, 26 insertions(+), 25 deletions(-)
diff --git a/src/catools/caget.c b/src/catools/caget.c
index bae87e7b5..573ae85a7 100644
--- a/src/catools/caget.c
+++ b/src/catools/caget.c
@@ -127,6 +127,7 @@ static void event_handler (evargs args)
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 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
}
}
/* 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 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
(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 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
/* -------------- */
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 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
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 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
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 1) printf("%lu%c", pvs[n].nElems, fieldSeparator);
+ for (i=0; i 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 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
fprintf(stderr,"Failed to allocate space for escaped string\n");
}
} else {
- for (i=0; idbrType = 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 @@ static void connection_handler ( struct connection_handler_args args )
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 @@ static void connection_handler ( struct connection_handler_args args )
/* 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,
diff --git a/src/catools/tool_lib.c b/src/catools/tool_lib.c
index 0bfcab3a3..13d6330cf 100644
--- a/src/catools/tool_lib.c
+++ b/src/catools/tool_lib.c
@@ -455,8 +455,8 @@ char *dbr2str (const void *value, unsigned type)
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; ireqElems; ++i) { \
+ if (reqElems || pv->nElems > 1) printf("%c%lu", fieldSeparator, pv->nElems); \
+ for (i=0; inElems; ++i) { \
printf("%c%s", fieldSeparator, val2str(value, TYPE_ENUM, i)); \
} \
} \
@@ -492,7 +492,7 @@ void print_time_val_sts (pv* pv, unsigned long reqElems)
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)
diff --git a/src/catools/tool_lib.h b/src/catools/tool_lib.h
index 5bb6b5ddd..baebf7939 100644
--- a/src/catools/tool_lib.h
+++ b/src/catools/tool_lib.h
@@ -64,8 +64,8 @@ typedef struct
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;
From 30f0871c2b0633575e64a0052f2bb10f993235aa Mon Sep 17 00:00:00 2001
From: Michael Abbott
Date: Wed, 11 Aug 2010 16:41:15 -0500
Subject: [PATCH 04/10] Drive-by refactoring in caserverio.c
Minor refactoring of code block in cas_copy_in_header() to gather
common header code.
---
src/rsrv/caserverio.c | 41 +++++++++++++++++------------------------
1 file changed, 17 insertions(+), 24 deletions(-)
diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c
index 4d8b77385..a073f4283 100644
--- a/src/rsrv/caserverio.c
+++ b/src/rsrv/caserverio.c
@@ -292,32 +292,25 @@ int cas_copy_in_header (
}
}
- 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 */
From 9d9ba1a442485c1b77de45c04162a88039ff6d1f Mon Sep 17 00:00:00 2001
From: Michael Abbott
Date: Wed, 11 Aug 2010 16:42:44 -0500
Subject: [PATCH 05/10] Add CA message header size optimisation.
If a packet is sufficiently small it can be worth the small
optimisation of saving the 8 bytes in a large packet header.
---
src/rsrv/caserverio.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c
index a073f4283..a01d4fe3c 100644
--- a/src/rsrv/caserverio.c
+++ b/src/rsrv/caserverio.c
@@ -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()
*
@@ -350,8 +354,19 @@ void cas_commit_msg ( struct client *pClient, ca_uint32_t size )
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 ) );
From e54b631b8d04fb18078e47228e281b6b2f5e48ad Mon Sep 17 00:00:00 2001
From: Michael Abbott
Date: Wed, 11 Aug 2010 16:49:46 -0500
Subject: [PATCH 06/10] Guard memset in camessage.c to prevent wild memory
overrun if mismatch between payload and data size.
---
src/ca/nciu.h | 2 +-
src/rsrv/camessage.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ca/nciu.h b/src/ca/nciu.h
index f05a13b96..de070dcea 100644
--- a/src/ca/nciu.h
+++ b/src/ca/nciu.h
@@ -41,7 +41,7 @@
# include "shareLib.h"
#endif
-#define CA_MINOR_PROTOCOL_REVISION 12
+#define CA_MINOR_PROTOCOL_REVISION 13
#include "caProto.h"
#include "cacIO.h"
diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c
index 8542becb8..963561461 100644
--- a/src/rsrv/camessage.c
+++ b/src/rsrv/camessage.c
@@ -605,7 +605,7 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
payload_size = data_size;
cas_set_header_count(pClient, item_count);
}
- else
+ else if (payload_size > data_size)
memset(
(char *) pPayload + data_size, 0, payload_size - data_size);
}
From 0c4746dd666e11fa8774f216e5f4b857dbf2e0ec Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 13 Aug 2010 12:59:50 -0500
Subject: [PATCH 07/10] Moved new variable definitions to the beginning of
their block. Older C compilers such as vxWorks 5.x insist on this.
---
src/rsrv/camessage.c | 9 ++++++---
src/rsrv/caserverio.c | 7 +++++--
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c
index 963561461..4888a2aa8 100644
--- a/src/rsrv/camessage.c
+++ b/src/rsrv/camessage.c
@@ -507,6 +507,9 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
const int readAccess = asCheckGet ( pciu->asClientPVT );
int status;
int v41;
+ int autosize;
+ long item_count;
+ ca_uint32_t payload_size;
SEND_LOCK ( pClient );
@@ -531,10 +534,10 @@ static void read_reply ( void *pArg, struct dbAddr *paddr,
/* 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 = pevext->msg.m_count == 0;
+ item_count =
autosize ? paddr->no_elements : pevext->msg.m_count;
- ca_uint32_t payload_size = dbr_size_n(pevext->msg.m_dataType, item_count);
+ 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,
diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c
index a01d4fe3c..119ad5e3a 100644
--- a/src/rsrv/caserverio.c
+++ b/src/rsrv/caserverio.c
@@ -257,6 +257,7 @@ int cas_copy_in_header (
{
unsigned msgSize;
ca_uint32_t alignedPayloadSize;
+ caHdr *pMsg;
if ( payloadSize > UINT_MAX - sizeof ( caHdr ) - 8u ) {
return ECA_TOLARGE;
@@ -296,7 +297,7 @@ int cas_copy_in_header (
}
}
- caHdr *pMsg = (caHdr *) &pclient->send.buf[pclient->send.stk];
+ pMsg = (caHdr *) &pclient->send.buf[pclient->send.stk];
pMsg->m_cmmd = htons(response);
pMsg->m_dataType = htons(dataType);
pMsg->m_cid = htonl(cid);
@@ -337,8 +338,10 @@ 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)) {
+ ca_uint32_t *pLW;
+
assert(pMsg->m_count == 0);
- ca_uint32_t *pLW = (ca_uint32_t *) (pMsg + 1);
+ pLW = (ca_uint32_t *) (pMsg + 1);
pLW[1] = htonl(count);
}
else {
From 85c287774659cb32b1007cce018bc338aea7908f Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 17 Aug 2010 18:06:19 -0500
Subject: [PATCH 08/10] Document the dynamic-array changes.
---
documentation/RELEASE_NOTES.html | 25 +++++++++++++++++++++++++
src/ca/CAref.html | 23 ++++++++++++-----------
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 3b0058a87..af7c595a4 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -12,6 +12,31 @@
Changes between 3.14.11 and 3.14.12
+Dynamic arrays over CA
+
+Dymanic array sizing was developed by Michael Abbott at the 2010 EPICS
+Codeathon. It permits a CA client to fetch only the currently valid elements of
+an array by specifying a COUNT of zero to either of the ca_array_get_callback()
+or ca_create_subscription() routines. It has never before been legal to pass a
+COUNT of zero to the ca_array_get_callback() routine, but this development does
+introduce a subtle change to the published API of the ca_create_subscription()
+routine.
+
+In previous releases a COUNT of zero for a subscription meant use the
+ca_element_count() for the channel, but from this release it can return fewer
+elements (never more), at the behest of the server. The number of elements can
+vary with subsequent array update events, so a client that uses this technique
+must use the count field of the event_handler_args in its callback function each
+time it is called to obtain the correct element count from the server. Note that
+the ca_element_count() value for a channel is only updated at connection time,
+and supplies the maximum number of elements that the server array variable can
+hold.
+
+Dynamic arrays are currently only supported by the CA client library and IOC
+server RSRV; the portable CAS does not understand them in this release. Newer
+clients using this feature with an older server will revert to the previous
+behavior.
+
CA over TCP connections
Merged the CA-over-TCP changes developed by Ralph and Jeff at the 2008 EPICS
diff --git a/src/ca/CAref.html b/src/ca/CAref.html
index 13e6cc61e..4f156b25a 100644
--- a/src/ca/CAref.html
+++ b/src/ca/CAref.html
@@ -2297,11 +2297,11 @@ ca_put_callback, ca_get_callback, and ca_add_event all request notification of
asynchronous completion via this mechanism. The event_handler_args
structure is passed by value to the application supplied
callback. In this structure the dbr field is a void pointer to any
-data that might be returned. The status field will be
+data that might be returned. The status field will be
set to one of the CA error codes in caerr.h and will indicate the status of the
operation performed in the IOC. If the status field isn't set to ECA_NORMAL or
data isn't normally returned from the operation (i.e. put call back) then you
-should expect that the dbr field will be set to a nill pointer
+should expect that the dbr field will be set to a nill pointer
(zero). The fields usr, chid, and type
are set to the values specified when the request was made by the application.
The "dbr" pointer, and any data that it points to, are valid only when
@@ -2352,8 +2352,8 @@ library functions that request them.
For routines that require an argument specifying the number of array
elements, no more than the process variable's maximum native element count may
be requested. The process variable's maximum native element count is available
-from ca_element_count() when the channel is connected. If less elements than
-the process variable's native element count are requested the requested values
+from ca_element_count() when the channel is connected. If fewer elements than
+the process variable's native element count are requested, the requested values
will be fetched beginning at element zero. By default CA limits the number of
elements in an array to be no more than approximately 16k divided by the size
of one element in the array. Starting with EPICS R3.14 the maximum array size
@@ -2381,12 +2381,12 @@ href="#ca_create_channel">ca_create_channel. The ca_pend_io approach is best suited to simple
command line programs with short runtime duration, and the connection callback
method is best suited to toolkit components with long runtime duration. Use of
-ca_state is appropriate only in programs
+ca_state is appropriate only in programs
that prefer to poll for connection state changes instead of opting for
asynchronous notification. The ca_pend_io function blocks only for
channels created specifying a nill connection handler callback function. The
user's connection state change function will be run immediately from within
-ca_create_channel if the CA
+ca_create_channel if the CA
client and CA server are both hosted within the same address space (within the
same process).
@@ -2709,9 +2709,9 @@ time.
The following structure is passed by value to the user's
connection connection callback function. The op field will
be set by the CA client library to CA_OP_CONN_UP when the
- channel connects, and to CA_OP_CONN_DOWN when the channel
+ channel connects, and to CA_OP_CONN_DOWN when the channel
disconnects. See ca_puser if the
- PUSER argument is required in your callback
+ PUSER argument is required in your callback
handler.
struct ca_connection_handler_args {
chanId chid; /* channel id */
@@ -2973,7 +2973,8 @@ when a CA get request is initiated.
COUNT
- Element count to be read from the specified channel. Must match the
- array pointed to by PVALUE.
+ array pointed to by PVALUE. For ca_array_get_callback a count of zero
+ means use the current element count from the server.
CHID
@@ -3081,7 +3082,7 @@ indicating the current state of the channel.
COUNT
- The element count to be read from the specified channel. A count of
- zero specifies the native elemnt count.
+ zero means use the current element count from the server.
CHID
@@ -3391,7 +3392,7 @@ field should not be used.
- Address of user callback function to be executed when an exceptions
occur. Passing a nil value causes the default exception handler to be
reinstalled. The following structure is passed by value to the user's
- callback function. Currently, the
op field can be one of
+ callback function. Currently, the op field can be one of
CA_OP_GET, CA_OP_PUT, CA_OP_CREATE_CHANNEL, CA_OP_ADD_EVENT,
CA_OP_CLEAR_EVENT, or CA_OP_OTHER.
struct exception_handler_args {
From 7ce4eb96ea5492dcf1969c19e01c9a392608c6a2 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 17 Sep 2010 14:11:00 -0500
Subject: [PATCH 09/10] cap5: Support dynamic array sizes through the Perl API.
---
src/cap5/CA.pm | 5 ++++-
src/cap5/Cap5.xs | 10 +++++-----
src/cap5/caget.pl | 11 +++++++----
src/cap5/camonitor.pl | 12 +++++++-----
4 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/src/cap5/CA.pm b/src/cap5/CA.pm
index b6abee296..19d9f95ae 100644
--- a/src/cap5/CA.pm
+++ b/src/cap5/CA.pm
@@ -210,7 +210,10 @@ data type requested will be the widened form of the channel's native type
fetch all available elements.
The element count can be overridden by providing an integer argument in the
-range 1 .. C. The data type can also be given as a string naming
+range 0 .. C, where zero means use the current length from the
+server. Note that the count argument must be an integer; add 0 to it if it is
+necessary to convert it from a string.
+The optional data type I should be a string naming
the desired C type; the actual type used will have the C part
widened to one of C, C, C or C. The valid type
names are listed in the L under the
diff --git a/src/cap5/Cap5.xs b/src/cap5/Cap5.xs
index d83674855..c3e4d0e50 100644
--- a/src/cap5/Cap5.xs
+++ b/src/cap5/Cap5.xs
@@ -782,7 +782,7 @@ void CA_get(SV *ca_ref) {
New(0, pch->sdata, count + 1, char);
pch->ssize = count;
}
- status = ca_array_get(DBF_CHAR, count, pch->chan, pch->sdata);
+ status = ca_array_get(DBF_CHAR, 0, pch->chan, pch->sdata);
} else {
status = ca_get(best_type(pch), pch->chan, &pch->data);
}
@@ -818,16 +818,16 @@ void CA_get_callback(SV *ca_ref, SV *sub, ...) {
SV *get_sub = newSVsv(sub);
int status;
chtype type = best_type(pch);
- int count = ca_element_count(pch->chan);
+ int count = 0;
int i = 2;
const char *croak_msg;
while (items > i
&& SvOK(ST(i))) {
if (SvIOK(ST(i))) {
- /* Interger => Count arg */
+ /* Interger => Count arg, zero means current size */
count = SvIV(ST(i));
- if (count < 1 || count > ca_element_count(pch->chan)) {
+ if (count < 0 || count > ca_element_count(pch->chan)) {
croak_msg = "Requested array size is out of range";
goto exit_croak;
}
@@ -901,7 +901,7 @@ SV * CA_create_subscription(SV *ca_ref, const char *mask_str, SV *sub, ...) {
while (items > i
&& SvOK(ST(i))) {
if (SvIOK(ST(i))) {
- /* Interger => Count arg, zero means native size */
+ /* Interger => Count arg, zero means current size */
count = SvIV(ST(i));
if (count < 0 || count > ca_element_count(pch->chan)) {
croak_msg = "Requested array size is out of range";
diff --git a/src/cap5/caget.pl b/src/cap5/caget.pl
index 2e6639179..4f835348a 100644
--- a/src/cap5/caget.pl
+++ b/src/cap5/caget.pl
@@ -6,10 +6,12 @@ use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use Getopt::Std;
+use Scalar::Util qw(looks_like_number);
use CA;
-our ($opt_0, $opt_a, $opt_c, $opt_d, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n);
+our ($opt_0, $opt_a, $opt_d, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n);
our ($opt_s, $opt_S, $opt_t);
+our $opt_c = 0;
our $opt_F = ' ';
our $opt_w = 1;
@@ -18,6 +20,9 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
HELP_MESSAGE() unless getopts('0:ac:d:e:f:F:g:hnsStw:');
HELP_MESSAGE() if $opt_h;
+die "caget: -c option takes a positive number\n"
+ unless looks_like_number($opt_c) && $opt_c >= 0;
+
die "No pv name specified. ('caget -h' gives help.)\n"
unless @ARGV;
@@ -51,9 +56,7 @@ map {
if $opt_a;
}
$rtype{$_} = $type;
- my $count = $_->element_count;
- $count = +$opt_c if $opt_c && $opt_c <= $count;
- $_->get_callback(\&get_callback, $type, $count);
+ $_->get_callback(\&get_callback, $type, 0+$opt_c);
} @chans;
my $incomplete = @chans;
diff --git a/src/cap5/camonitor.pl b/src/cap5/camonitor.pl
index 56c609141..559ec1233 100644
--- a/src/cap5/camonitor.pl
+++ b/src/cap5/camonitor.pl
@@ -6,9 +6,11 @@ use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use Getopt::Std;
+use Scalar::Util qw(looks_like_number);
use CA;
-our ($opt_0, $opt_c, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n, $opt_s, $opt_S);
+our ($opt_0, $opt_e, $opt_f, $opt_g, $opt_h, $opt_n, $opt_s, $opt_S);
+our $opt_c = 0;
our $opt_F = ' ';
our $opt_w = 1;
our $opt_m = 'va';
@@ -18,6 +20,9 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
HELP_MESSAGE() unless getopts('0:c:e:f:F:g:hm:nsSw:');
HELP_MESSAGE() if $opt_h;
+die "caget: -c option takes a positive number\n"
+ unless looks_like_number($opt_c) && $opt_c >= 0;
+
die "No pv name specified. ('camonitor -h' gives help.)\n"
unless @ARGV;
@@ -45,11 +50,8 @@ sub conn_callback {
|| (!$opt_S && $type eq 'DBR_CHAR');
$type =~ s/^DBR_/DBR_TIME_/;
- my $count = $chan->element_count;
- $count = +$opt_c if $opt_c && $opt_c <= $count;
-
$monitors{$chan} =
- $chan->create_subscription($opt_m, \&mon_callback, $type, $count);
+ $chan->create_subscription($opt_m, \&mon_callback, $type, 0+$opt_c);
}
}
From dea1b9df3bf2410ec9a6f9efd0719338643acfdc Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 20 Sep 2010 14:41:33 -0500
Subject: [PATCH 10/10] Tweaked the release notes to describe which areas were
not changed.
---
documentation/RELEASE_NOTES.html | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index af7c595a4..2b8e9337b 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -33,9 +33,11 @@ and supplies the maximum number of elements that the server array variable can
hold.
Dynamic arrays are currently only supported by the CA client library and IOC
-server RSRV; the portable CAS does not understand them in this release. Newer
-clients using this feature with an older server will revert to the previous
-behavior.
+server RSRV, the Perl CA library and the catools programs. The portable CAS does
+not understand them, and database links that connect over CA do not attempt to
+use them either. CA clients that try to use this functionality with a server
+that does not support it will receive the same full-sized zero-filled arrays
+that previous releases supported.
CA over TCP connections