From a461bb853532eae9403796344fcd983d2164c942 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 28 Oct 1999 18:53:56 +0000 Subject: [PATCH] added enum string table cache to PV class --- src/cas/generic/casInternal.h | 9 ++- src/cas/generic/casPVI.cc | 126 ++++++++++++++++++++++++++++++- src/cas/generic/casPVIIL.h | 8 ++ src/cas/generic/casStrmClient.cc | 67 +++++++++++----- 4 files changed, 188 insertions(+), 22 deletions(-) diff --git a/src/cas/generic/casInternal.h b/src/cas/generic/casInternal.h index d1cc9997f..8dfffbbc7 100644 --- a/src/cas/generic/casInternal.h +++ b/src/cas/generic/casInternal.h @@ -344,6 +344,8 @@ public: void postAccessRightsEvent (); + const vector enumStringTable () const; + // // virtual functions // @@ -444,7 +446,10 @@ public: caStatus bestDBRType (unsigned &dbrType); epicsShareFunc virtual casResType resourceType () const; - + + const vector enumStringTable () const; + void updateEnumStringTable (unsigned nativeType); + // // virtual functions in the public interface class // @@ -465,6 +470,7 @@ public: private: tsDLList chanList; + vector enumStrTbl; caServerI *pCAS; unsigned nMonAttached; unsigned nIOAttached; @@ -472,7 +478,6 @@ private: inline void lock () const; inline void unlock () const; - epicsShareFunc virtual void destroy (); // casPVI destructor noop }; diff --git a/src/cas/generic/casPVI.cc b/src/cas/generic/casPVI.cc index 5d19b5715..5e59657b8 100644 --- a/src/cas/generic/casPVI.cc +++ b/src/cas/generic/casPVI.cc @@ -28,6 +28,7 @@ * */ +#include "gddAppTable.h" // EPICS application type table #include "server.h" #include "casPVIIL.h" // casPVI inline func @@ -104,7 +105,6 @@ void casPVI::destroy () // caStatus casPVI::attachToServer (caServerI &cas) { - if (this->pCAS) { // // currently we enforce that the PV can be attached to only @@ -115,6 +115,7 @@ caStatus casPVI::attachToServer (caServerI &cas) } } else { + // // install the PV into the server // @@ -124,6 +125,129 @@ caStatus casPVI::attachToServer (caServerI &cas) return S_cas_success; } +// +// casPVI::updateEnumStringTable () +// +// fetch string conversion table so that we can perform proper conversion +// of enumerated PVs to strings during reads +// +// what a API complexity nightmare this GDD is +// +void casPVI::updateEnumStringTable (unsigned nativeType) +{ + static const aitUint32 stringTableTypeStaticInit = 0xffffffff; + static aitUint32 stringTableType = stringTableTypeStaticInit; + caStatus status; + gdd *pTmp; + + // + // reload the enum string table each time that the + // PV is attached to the server + // + this->enumStrTbl.clear (); + + // + // empty string table for non-enumerated PVs + // + if (nativeType!=aitEnumEnum16) { + this->enumStrTbl.clear (); + return; + } + + // + // lazy init + // + if (stringTableType==stringTableTypeStaticInit) { + stringTableType = gddApplicationTypeTable::app_table.registerApplicationType ("enums"); + } + + // + // create a gdd with the "enum string table" application type + // + pTmp = new gddScalar (stringTableType); + if (pTmp==NULL) { + errMessage (S_cas_noMemory, "unable to read application type \"enums\" string conversion table for enumerated PV"); + return; + } + + // + // create a false context which is guaranteed to cause + // any asynch IO to be ignored + // + casCtx ctx; + + // + // read the enum string table + // + status = this->read (ctx, *pTmp); + if (status == S_casApp_asyncCompletion || status == S_casApp_postponeAsyncIO) { + pTmp->unreference (); + errMessage (status, " sorry, no support in server library for asynchronous completion of \"enums\" string conversion table for enumerated PV"); + errMessage (status, " please fetch \"enums\" string conversion table into cache during asychronous PV attach IO completion"); + return; + } + else if (status) { + pTmp->unreference (); + errMessage (status, "unable to read application type \"enums\" string conversion table for enumerated PV"); + return; + } + + if (pTmp->isContainer()) { + errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV was a container (expected vector of strings)"); + pTmp->unreference (); + return; + } + + if (pTmp->dimension()==0) { + if (pTmp->primitiveType()==aitEnumString) { + aitString *pStr = (aitString *) pTmp->dataVoid (); + this->enumStrTbl[0].assign (pStr->string()); + } + else if (pTmp->primitiveType()==aitEnumFixedString) { + aitFixedString *pStr = (aitFixedString *) pTmp->dataVoid (); + this->enumStrTbl[0].assign (pStr->fixed_string); + } + else { + errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV isnt a string type?"); + } + } + else if (pTmp->dimension()==1) { + gddStatus status; + aitIndex index, first, count; + + status = pTmp->getBound (0, first, count); + assert (status == 0); + + // + // preallocate the correct amount + // + this->enumStrTbl.reserve (count); + + if (pTmp->primitiveType()==aitEnumString) { + aitString *pStr = (aitString *) pTmp->dataVoid (); + for (index = 0; indexenumStrTbl[index].assign (pStr[index].string()); + } + } + else if (pTmp->primitiveType()==aitEnumFixedString) { + aitFixedString *pStr = (aitFixedString *) pTmp->dataVoid (); + for (index = 0; indexenumStrTbl[index].assign (pStr[index].fixed_string); + } + } + else { + errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV isnt a string type?"); + } + } + else { + errMessage (S_cas_badType, "application type \"enums\" string conversion table for enumerated PV was multi-dimensional (expected vector of strings)"); + } + + pTmp->unreference (); + + return; +} + // // casPVI::registerEvent() // diff --git a/src/cas/generic/casPVIIL.h b/src/cas/generic/casPVIIL.h index 5c6b1fc9a..efcf8b674 100644 --- a/src/cas/generic/casPVIIL.h +++ b/src/cas/generic/casPVIIL.h @@ -198,6 +198,14 @@ inline aitIndex casPVI::nativeCount () return this->maxBound(0u); } +// +// casPVI::enumStringTable () +// +inline const vector casPVI::enumStringTable () const +{ + return this->enumStrTbl; +} + #endif // casPVIIL_h diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index 1df50221c..02cf5d3c7 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -109,6 +109,31 @@ casStrmClient::~casStrmClient() this->unlock(); } +// +// casStrmClient::uknownMessageAction() +// +caStatus casStrmClient::uknownMessageAction () +{ + const caHdr *mp = this->ctx.getMsg(); + caStatus status; + + ca_printf ("CAS: bad request code from virtual circuit=%u\n", mp->m_cmmd); + this->dumpMsg (mp, this->ctx.getData()); + + /* + * most clients dont recover from this + */ + status = this->sendErr (mp, ECA_INTERNAL, "Invalid Request Code"); + if (status) { + return status; + } + + /* + * returning S_cas_internal here disconnects + * the client with the bad message + */ + return S_cas_internal; +} // // casStrmClient::verifyRequest() @@ -171,7 +196,6 @@ void casStrmClient::show (unsigned level) const this->outBuf::show(level); } - /* * casStrmClient::readAction() */ @@ -215,7 +239,7 @@ caStatus casStrmClient::readAction () pChan->getPVI().addItemToIOBLockedList(*this); } else { - status = this->sendErrWithEpicsStatus(mp, status, ECA_GETFAIL); + status = this->sendErrWithEpicsStatus (mp, status, ECA_GETFAIL); } return status; @@ -257,7 +281,7 @@ caStatus casStrmClient::readResponse (casChannelI *pChan, const caHdr &msg, // convert gdd to db_access type // (places the data in network format) // - mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, desc); + mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, desc, pChan->enumStringTable()); if (mapDBRStatus<0) { desc.dump(); errPrintf (S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u", @@ -419,7 +443,7 @@ caStatus casStrmClient::readNotifyResponseECA_XXX (casChannelI *pChan, // convert gdd to db_access type // (places the data in network format) // - mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, *pDesc); + mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr((reply+1), msg.m_count, *pDesc, pChan->enumStringTable()); if (mapDBRStatus<0) { pDesc->dump(); errPrintf (S_cas_badBounds, __FILE__, __LINE__, "- get notify with PV=%s type=%u count=%u", @@ -555,7 +579,7 @@ caStatus casStrmClient::monitorResponse(casChannelI &chan, const caHdr &msg, // there appears to be no success/fail // status from this routine // - gddMapDbr[msg.m_dataType].conv_dbr ((pReply+1), msg.m_count, *pDBRDD); + gddMapDbr[msg.m_dataType].conv_dbr ((pReply+1), msg.m_count, *pDBRDD, chan.enumStringTable()); #ifdef CONVERSION_REQUIRED /* use type as index into conversion jumptable */ @@ -980,7 +1004,7 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur casChannel *pChan; casChannelI *pChanI; caHdr *claim_reply; - unsigned dbrType; + unsigned nativeType; bufSizeT nBytes; caStatus status; @@ -998,6 +1022,21 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur return this->channelCreateFailed (&hdr, S_casApp_pvNotFound); } + // + // fetch the native type + // + status = pPV->bestDBRType(nativeType); + if (status) { + errMessage(status, "best external dbr type fetch failed"); + return this->channelCreateFailed (&hdr, status); + } + + // + // fetch string conversion table so that we can perform proper conversion + // of enumerated PVs to strings during reads + // + pPV->updateEnumStringTable (nativeType); + // // attach the PV to this server // @@ -1046,14 +1085,6 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur return this->channelCreateFailed(&hdr, status); } - status = pPV->bestDBRType(dbrType); - if (status) { - this->outBuf::popCtx (outctx); - errMessage(status, "best external dbr type fetch failed"); - pChanI->destroyNoClientNotify(); - return this->channelCreateFailed(&hdr, status); - } - // // NOTE: // We are allocated enough space for both the claim @@ -1069,7 +1100,7 @@ caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvAttachRetur *claim_reply = nill_msg; claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU; - claim_reply->m_dataType = dbrType; + claim_reply->m_dataType = nativeType; claim_reply->m_count = pPV->nativeCount(); claim_reply->m_cid = hdr.m_cid; claim_reply->m_available = pChanI->getSID(); @@ -1752,14 +1783,13 @@ caStatus casStrmClient::writeArrayData() return status; } - // // casStrmClient::read() // caStatus casStrmClient::read(smartGDDPointer &pDescRet) { - const caHdr *pHdr = this->ctx.getMsg(); - caStatus status; + const caHdr *pHdr = this->ctx.getMsg(); + caStatus status; pDescRet = NULL; status = createDBRDD (pHdr->m_dataType, pHdr->m_count, pDescRet); @@ -1955,7 +1985,6 @@ caStatus createDBRDD (unsigned dbrType, aitIndex dbrCount, smartGDDPointer &pDes } - // // casStrmClient::userName() //