From 9ac237b3dee4e9e1a023970304d7ca821a1c5ff3 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 12 Oct 2016 13:41:55 +0200 Subject: [PATCH 1/4] cas: Add real implementation for variable length arrays (Bruce Hill, Matej Sekoranja) --- src/cas/generic/casStrmClient.cc | 69 +++++++++++++++++--------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index 468aa17a5..b1e321120 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -411,17 +411,8 @@ caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn) // // element count out of range ? // - if ( allowdyn && ctx.msg.m_count==0 && - CA_V413 ( this->minor_version_number ) ) { - // Hack - // Since GDD interface doesn't support variable sized arrays - // we present dynamic requests as max size. - // This allows PCAS to claim support for dynamic arrays w/o - // going to the trouble of fixing GDD. - ctx.msg.m_count = pChan->getPVI().nativeCount(); - } - else if ( ctx.msg.m_count > pChan->getPVI().nativeCount() || - ctx.msg.m_count == 0u ) { + if ( ctx.msg.m_count > pChan->getPVI().nativeCount() || + ( !allowdyn && ctx.msg.m_count == 0u ) ) { return ECA_BADCOUNT; } @@ -454,7 +445,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard ) casChannelI * pChan; { - caStatus status = this->verifyRequest ( pChan, true ); + caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) ); if ( status != ECA_NORMAL ) { if ( pChan ) { return this->sendErr ( guard, mp, pChan->getCID(), @@ -541,11 +532,15 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard, pChan->getCID(), status, ECA_GETFAIL ); } + ca_uint32_t count = (msg.m_count == 0) ? + (ca_uint32_t)desc.getDataSizeElements() : + msg.m_count; + void * pPayload; { - unsigned payloadSize = dbr_size_n ( msg.m_dataType, msg.m_count ); + unsigned payloadSize = dbr_size_n ( msg.m_dataType, count ); caStatus localStatus = this->out.copyInHeader ( msg.m_cmmd, payloadSize, - msg.m_dataType, msg.m_count, pChan->getCID (), + msg.m_dataType, count, pChan->getCID (), msg.m_available, & pPayload ); if ( localStatus ) { if ( localStatus==S_cas_hugeRequest ) { @@ -561,21 +556,21 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard, // (places the data in network format) // int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr( - pPayload, msg.m_count, desc, pChan->enumStringTable() ); + pPayload, count, desc, pChan->enumStringTable() ); if ( mapDBRStatus < 0 ) { desc.dump (); errPrintf ( S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u", - pChan->getPVI().getName(), msg.m_dataType, msg.m_count ); + pChan->getPVI().getName(), msg.m_dataType, count ); return this->sendErrWithEpicsStatus ( guard, & msg, pChan->getCID(), S_cas_badBounds, ECA_GETFAIL ); } int cacStatus = caNetConvert ( - msg.m_dataType, pPayload, pPayload, true, msg.m_count ); + msg.m_dataType, pPayload, pPayload, true, count ); if ( cacStatus != ECA_NORMAL ) { return this->sendErrWithEpicsStatus ( guard, & msg, pChan->getCID(), S_cas_internal, cacStatus ); } - if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) { + if ( msg.m_dataType == DBR_STRING && count == 1u ) { unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u; this->out.commitMsg ( reducedPayloadSize ); } @@ -595,7 +590,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard casChannelI * pChan; { - caStatus status = this->verifyRequest ( pChan, true ); + caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) ); if ( status != ECA_NORMAL ) { return this->readNotifyFailureResponse ( guard, * mp, status ); } @@ -666,11 +661,15 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua return ecaStatus; } + ca_uint32_t count = (msg.m_count == 0) ? + (ca_uint32_t)desc.getDataSizeElements() : + msg.m_count; + void *pPayload; { - unsigned size = dbr_size_n ( msg.m_dataType, msg.m_count ); + unsigned size = dbr_size_n ( msg.m_dataType, count ); caStatus status = this->out.copyInHeader ( msg.m_cmmd, size, - msg.m_dataType, msg.m_count, ECA_NORMAL, + msg.m_dataType, count, ECA_NORMAL, msg.m_available, & pPayload ); if ( status ) { if ( status == S_cas_hugeRequest ) { @@ -685,23 +684,23 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua // convert gdd to db_access type // int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr ( pPayload, - msg.m_count, desc, pChan->enumStringTable() ); + count, desc, pChan->enumStringTable() ); if ( mapDBRStatus < 0 ) { desc.dump(); errPrintf ( S_cas_badBounds, __FILE__, __LINE__, "- get notify with PV=%s type=%u count=%u", - pChan->getPVI().getName(), msg.m_dataType, msg.m_count ); + pChan->getPVI().getName(), msg.m_dataType, count ); return this->readNotifyFailureResponse ( guard, msg, ECA_NOCONVERT ); } int cacStatus = caNetConvert ( - msg.m_dataType, pPayload, pPayload, true, msg.m_count ); + msg.m_dataType, pPayload, pPayload, true, count ); if ( cacStatus != ECA_NORMAL ) { return this->sendErrWithEpicsStatus ( guard, & msg, pChan->getCID(), S_cas_internal, cacStatus ); } - if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) { + if ( msg.m_dataType == DBR_STRING && count == 1u ) { unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u; this->out.commitMsg ( reducedPayloadSize ); } @@ -859,11 +858,15 @@ caStatus casStrmClient::monitorResponse ( casChannelI & chan, const caHdrLargeArray & msg, const gdd & desc, const caStatus completionStatus ) { + ca_uint32_t count = (msg.m_count == 0) ? + (ca_uint32_t)desc.getDataSizeElements() : + msg.m_count; + void * pPayload = 0; { - ca_uint32_t size = dbr_size_n ( msg.m_dataType, msg.m_count ); + ca_uint32_t size = dbr_size_n ( msg.m_dataType, count ); caStatus status = out.copyInHeader ( msg.m_cmmd, size, - msg.m_dataType, msg.m_count, ECA_NORMAL, + msg.m_dataType, count, ECA_NORMAL, msg.m_available, & pPayload ); if ( status ) { if ( status == S_cas_hugeRequest ) { @@ -881,7 +884,7 @@ caStatus casStrmClient::monitorResponse ( gdd * pDBRDD = 0; if ( completionStatus == S_cas_success ) { - caStatus status = createDBRDD ( msg.m_dataType, msg.m_count, pDBRDD ); + caStatus status = createDBRDD ( msg.m_dataType, count, pDBRDD ); if ( status != S_cas_success ) { caStatus ecaStatus; if ( status == S_cas_badType ) { @@ -902,7 +905,7 @@ caStatus casStrmClient::monitorResponse ( pDBRDD->unreference (); errPrintf ( S_cas_noConvert, __FILE__, __LINE__, "no conversion between event app type=%d and DBR type=%d Element count=%d", - desc.applicationType (), msg.m_dataType, msg.m_count); + desc.applicationType (), msg.m_dataType, count); return monitorFailureResponse ( guard, msg, ECA_NOCONVERT ); } } @@ -925,14 +928,14 @@ caStatus casStrmClient::monitorResponse ( } int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr ( - pPayload, msg.m_count, *pDBRDD, chan.enumStringTable() ); + pPayload, count, *pDBRDD, chan.enumStringTable() ); if ( mapDBRStatus < 0 ) { pDBRDD->unreference (); return monitorFailureResponse ( guard, msg, ECA_NOCONVERT ); } int cacStatus = caNetConvert ( - msg.m_dataType, pPayload, pPayload, true, msg.m_count ); + msg.m_dataType, pPayload, pPayload, true, count ); if ( cacStatus != ECA_NORMAL ) { pDBRDD->unreference (); return this->sendErrWithEpicsStatus ( @@ -942,7 +945,7 @@ caStatus casStrmClient::monitorResponse ( // // force string message size to be the true size // - if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) { + if ( msg.m_dataType == DBR_STRING && count == 1u ) { ca_uint32_t reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u; this->out.commitMsg ( reducedPayloadSize ); } @@ -1950,7 +1953,7 @@ caStatus casStrmClient::eventAddAction ( casChannelI *pciu; { - caStatus status = casStrmClient::verifyRequest ( pciu, true ); + caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) ); if ( status != ECA_NORMAL ) { if ( pciu ) { return this->sendErr ( guard, mp, From 92ffe1d7267970ac392d770a071c858dc671a14f Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 18 Oct 2016 11:39:38 +0200 Subject: [PATCH 2/4] cas: fix first subscription update returning only 1 element when 0 were requested --- src/cas/generic/caServerI.h | 9 +++++++-- src/cas/generic/casStrmClient.cc | 25 +++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/cas/generic/caServerI.h b/src/cas/generic/caServerI.h index 6037d8c20..b45d9373a 100644 --- a/src/cas/generic/caServerI.h +++ b/src/cas/generic/caServerI.h @@ -40,8 +40,13 @@ class casIntfOS; class casMonitor; class casChannelI; -caStatus convertContainerMemberToAtomic ( class gdd & dd, - aitUint32 appType, aitUint32 elemCount ); +caStatus convertContainerMemberToAtomic (class gdd & dd, + aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount); + +// Keep the old signature for backward compatibility +inline caStatus convertContainerMemberToAtomic (class gdd & dd, + aitUint32 appType, aitUint32 elemCount) +{ return convertContainerMemberToAtomic(dd, appType, elemCount, elemCount); } class caServerI : public caServerIO, diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index b1e321120..d8d36d926 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -737,7 +737,9 @@ caStatus casStrmClient::readNotifyFailureResponse ( // than the destination) // caStatus convertContainerMemberToAtomic ( gdd & dd, - aitUint32 appType, aitUint32 elemCount ) + aitUint32 appType, + aitUint32 requestedCount, + aitUint32 nativeCount ) { gdd * pVal; if ( dd.isContainer() ) { @@ -764,13 +766,13 @@ caStatus convertContainerMemberToAtomic ( gdd & dd, return S_cas_badType; } - if ( elemCount <= 1 ) { + if ( nativeCount <= 1 ) { return S_cas_success; } // convert to atomic gddBounds bds; - bds.setSize ( elemCount ); + bds.setSize ( requestedCount ); bds.setFirst ( 0u ); pVal->setDimension ( 1u, & bds ); return S_cas_success; @@ -780,7 +782,9 @@ caStatus convertContainerMemberToAtomic ( gdd & dd, // createDBRDD () // static caStatus createDBRDD ( unsigned dbrType, - unsigned elemCount, gdd * & pDD ) + unsigned requestedCount, + unsigned nativeCount, + gdd * & pDD ) { /* * DBR type has already been checked, but it is possible @@ -808,7 +812,7 @@ static caStatus createDBRDD ( unsigned dbrType, // fix the value element count caStatus status = convertContainerMemberToAtomic ( - *pDescRet, gddAppType_value, elemCount ); + *pDescRet, gddAppType_value, requestedCount, nativeCount ); if ( status != S_cas_success ) { pDescRet->unreference (); return status; @@ -884,7 +888,10 @@ caStatus casStrmClient::monitorResponse ( gdd * pDBRDD = 0; if ( completionStatus == S_cas_success ) { - caStatus status = createDBRDD ( msg.m_dataType, count, pDBRDD ); + caStatus status = createDBRDD ( msg.m_dataType, + count, + chan.getPVI().nativeCount(), + pDBRDD ); if ( status != S_cas_success ) { caStatus ecaStatus; if ( status == S_cas_badType ) { @@ -2614,8 +2621,10 @@ caStatus casStrmClient::read () { gdd * pDD = 0; - caStatus status = createDBRDD ( pHdr->m_dataType, - pHdr->m_count, pDD ); + caStatus status = createDBRDD ( pHdr->m_dataType, + pHdr->m_count, + this->ctx.getChannel()->getPVI().nativeCount(), + pDD ); if ( status != S_cas_success ) { return status; } From 5d5cc1029ef9d181db23ca3b0053656eda8f73be Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 19 Oct 2016 11:57:13 +0200 Subject: [PATCH 3/4] gdd: make put() write full array if requested size=0 --- src/gdd/gdd.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/gdd/gdd.cc b/src/gdd/gdd.cc index 1a84808c6..438986ad1 100644 --- a/src/gdd/gdd.cc +++ b/src/gdd/gdd.cc @@ -1355,11 +1355,14 @@ gddStatus gdd::put ( const gdd * dd ) } aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow; - if ( srcAvailSize > this->getBounds()->size() ) { - srcCopySize = this->getBounds()->size(); - } - else { - srcCopySize = srcAvailSize; + { + aitUint32 destSize = this->getBounds()->size(); + if ( destSize > 0 && srcAvailSize > destSize ) { + srcCopySize = destSize; + } + else { + srcCopySize = srcAvailSize; + } } if ( dataVoid() == NULL ) From ac6b8bfcc77d3077f2013b0b83874f910b183b9a Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 19 Oct 2016 14:22:25 +0200 Subject: [PATCH 4/4] templates: make caServerApp use variable size vectors --- src/makeBaseApp/top/caServerApp/exPV.cc | 2 +- src/makeBaseApp/top/caServerApp/exServer.h | 35 +++++++++++------ src/makeBaseApp/top/caServerApp/exVectorPV.cc | 39 ++++++++++--------- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/makeBaseApp/top/caServerApp/exPV.cc b/src/makeBaseApp/top/caServerApp/exPV.cc index bc88b15bb..d35a4dbfa 100644 --- a/src/makeBaseApp/top/caServerApp/exPV.cc +++ b/src/makeBaseApp/top/caServerApp/exPV.cc @@ -42,7 +42,7 @@ exPV::exPV ( exServer & casIn, pvInfo & setup, // // no dataless PV allowed // - assert (this->info.getElementCount()>=1u); + assert (this->info.getCapacity()>=1u); // // start a very slow background scan diff --git a/src/makeBaseApp/top/caServerApp/exServer.h b/src/makeBaseApp/top/caServerApp/exServer.h index 5fb6adaf7..8336fda1a 100644 --- a/src/makeBaseApp/top/caServerApp/exServer.h +++ b/src/makeBaseApp/top/caServerApp/exServer.h @@ -76,8 +76,10 @@ public: double getLopr () const; aitEnum getType () const; excasIoType getIOType () const; - unsigned getElementCount () const; - void unlinkPV (); + unsigned getCapacity () const; + unsigned getElementCount () const; + void setElementCount (unsigned); + void unlinkPV (); exPV *createPV ( exServer & exCAS, bool preCreateFlag, bool scanOn, double asyncDelay ); void deletePV (); @@ -88,7 +90,8 @@ private: const double lopr; aitEnum type; const excasIoType ioType; - const unsigned elementCount; + const unsigned capacity; + unsigned elementCount; exPV * pPV; pvInfo & operator = ( const pvInfo & ); }; @@ -441,8 +444,8 @@ inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn, scanPeriod ( scanPeriodIn ), pName ( pNameIn ), hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ), - ioType ( ioTypeIn ), elementCount ( countIn ), - pPV ( 0 ) + ioType ( ioTypeIn ), capacity ( countIn ), + elementCount ( 0 ), pPV ( 0 ) { } @@ -454,8 +457,8 @@ inline pvInfo::pvInfo ( const pvInfo & copyIn ) : scanPeriod ( copyIn.scanPeriod ), pName ( copyIn.pName ), hopr ( copyIn.hopr ), lopr ( copyIn.lopr ), type ( copyIn.type ), - ioType ( copyIn.ioType ), elementCount ( copyIn.elementCount ), - pPV ( copyIn.pPV ) + ioType ( copyIn.ioType ), capacity ( copyIn.capacity ), + elementCount ( copyIn.elementCount ), pPV ( copyIn.pPV ) { } @@ -509,12 +512,22 @@ inline excasIoType pvInfo::getIOType () const return this->ioType; } -inline unsigned pvInfo::getElementCount () const -{ - return this->elementCount; +inline unsigned pvInfo::getCapacity () const +{ + return this->capacity; } -inline void pvInfo::unlinkPV () +inline unsigned pvInfo::getElementCount () const +{ + return this->elementCount; +} + +inline void pvInfo::setElementCount (unsigned newCount) +{ + this->elementCount = newCount; +} + +inline void pvInfo::unlinkPV () { this->pPV = NULL; } diff --git a/src/makeBaseApp/top/caServerApp/exVectorPV.cc b/src/makeBaseApp/top/caServerApp/exVectorPV.cc index da357831f..3308f8b20 100644 --- a/src/makeBaseApp/top/caServerApp/exVectorPV.cc +++ b/src/makeBaseApp/top/caServerApp/exVectorPV.cc @@ -48,7 +48,7 @@ unsigned exVectorPV::maxDimension() const aitIndex exVectorPV::maxBound (unsigned dimension) const // X aCC 361 { if (dimension==0u) { - return this->info.getElementCount(); + return this->info.getCapacity(); } else { return 0u; @@ -79,7 +79,7 @@ void exVectorPV::scan() this->currentTime = epicsTime::getCurrent(); pDD = new gddAtomic (gddAppType_value, aitEnumFloat64, - 1u, this->info.getElementCount()); + 1u, this->info.getCapacity()); if ( ! pDD.valid () ) { return; } @@ -93,7 +93,7 @@ void exVectorPV::scan() // // allocate array buffer // - pF = new aitFloat32 [this->info.getElementCount()]; + pF = new aitFloat32 [this->info.getCapacity()]; if (!pF) { return; } @@ -118,13 +118,13 @@ void exVectorPV::scan() if ( this->pValue.valid () ) { if (this->pValue->dimension()==1u) { const gddBounds *pB = this->pValue->getBounds(); - if (pB[0u].size()==this->info.getElementCount()) { + if (pB[0u].size()==this->info.getCapacity()) { pCF = *this->pValue; } } } - pFE = &pF[this->info.getElementCount()]; + pFE = &pF[this->info.getCapacity()]; while (pFsetTimeStamp ( & gddts ); status = this->update ( *pDD ); + this->info.setElementCount(this->info.getCapacity()); + if ( status != S_casApp_success ) { errMessage (status, "vector scan update failed\n"); } @@ -166,7 +168,7 @@ void exVectorPV::scan() // caStatus exVectorPV::updateValue ( const gdd & value ) { - + aitUint32 newSize = 0; // // Check bounds of incoming request // (and see if we are replacing all elements - @@ -180,10 +182,11 @@ caStatus exVectorPV::updateValue ( const gdd & value ) return S_casApp_badDimension; } const gddBounds* pb = value.getBounds (); + newSize = pb[0u].size(); if ( pb[0u].first() != 0u ) { return S_casApp_outOfBounds; } - else if ( pb[0u].size() > this->info.getElementCount() ) { + else if ( newSize > this->info.getCapacity() ) { return S_casApp_outOfBounds; } } @@ -193,14 +196,14 @@ caStatus exVectorPV::updateValue ( const gdd & value ) // return S_casApp_outOfBounds; } - + // // Create a new array data descriptor // (so that old values that may be referenced on the // event queue are not replaced) // - smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64, - 1u, this->info.getElementCount() ) ); + smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64, + 1u, newSize ) ); if ( ! pNewValue.valid() ) { return S_casApp_noMemory; } @@ -211,21 +214,20 @@ caStatus exVectorPV::updateValue ( const gdd & value ) // gddStatus gdds = pNewValue->unreference( ); assert ( ! gdds ); - + // // allocate array buffer // - aitFloat64 * pF = new aitFloat64 [this->info.getElementCount()]; + aitFloat64 * pF = new aitFloat64 [newSize]; if (!pF) { return S_casApp_noMemory; } - + // // Install (and initialize) array buffer // if no old values exist // - unsigned count = this->info.getElementCount(); - for ( unsigned i = 0u; i < count; i++ ) { + for ( unsigned i = 0u; i < newSize; i++ ) { pF[i] = 0.0f; } @@ -240,7 +242,7 @@ caStatus exVectorPV::updateValue ( const gdd & value ) // (do this before we increment pF) // pNewValue->putRef ( pF, pDest ); - + // // copy in the values that they are writing // @@ -248,9 +250,10 @@ caStatus exVectorPV::updateValue ( const gdd & value ) if ( gdds ) { return S_cas_noConvert; } - + this->pValue = pNewValue; - + this->info.setElementCount(newSize); + return S_casApp_success; }