diff --git a/src/cas/generic/casPVIIL.h b/src/cas/generic/casPVIIL.h index a7fcbbbe3..752345a02 100644 --- a/src/cas/generic/casPVIIL.h +++ b/src/cas/generic/casPVIIL.h @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.7 1996/11/02 00:54:23 jhill + * many improvements + * * Revision 1.6 1996/09/16 18:24:05 jhill * vxWorks port changes * @@ -56,6 +59,13 @@ #include "dbMapper.h" +// +// casPVI::getCAS() +// +inline caServerI &casPVI::getCAS() +{ + return this->cas; +} // // casPVI::interfaceObjectPointer() @@ -175,7 +185,7 @@ inline void casPVI::deleteSignal() // localCASRef.osiLock(); - if (this->chanList.count()==0u) { + if (this->chanList.count()==0u && !this->destroyInProgress) { (*this)->destroy(); // // !! dont access self after destroy !! @@ -230,6 +240,17 @@ inline void casPVI::postEvent (const casEventMask &select, gdd &event) this->unlock(); } +// +// CA only does 1D arrays for now +// +inline aitIndex casPVI::nativeCount() +{ + if ((*this)->maxDimension()==0u) { + return 1u; // scaler + } + return (*this)->maxBound(0u); +} + #endif // casPVIIL_h diff --git a/src/cas/generic/casPVListChan.cc b/src/cas/generic/casPVListChan.cc new file mode 100644 index 000000000..a9b170c37 --- /dev/null +++ b/src/cas/generic/casPVListChan.cc @@ -0,0 +1,51 @@ + +/* + * $Id$ + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * + * History + * $Log$ + * + * + */ + +#include +#include + +// +// casPVListChan::~casPVListChan() +// +casPVListChan::~casPVListChan() +{ + this->pv.removeChannel(*this); + // + // delete signal to PV occurs in + // casChannelI::~casChannelI + // +} + diff --git a/src/cas/generic/casPVListChanIL.h b/src/cas/generic/casPVListChanIL.h index 16ab38ae7..eabc6a01a 100644 --- a/src/cas/generic/casPVListChanIL.h +++ b/src/cas/generic/casPVListChanIL.h @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.1.1.1 1996/06/20 00:28:16 jhill + * ca server installation + * * */ @@ -46,17 +49,5 @@ inline casPVListChan::casPVListChan this->pv.installChannel(*this); } -// -// casPVListChan::~casPVListChan() -// -inline casPVListChan::~casPVListChan() -{ - this->pv.removeChannel(*this); - // - // delete signal to PV occurs in - // casChannelI::~casChannelI - // -} - #endif // casPVListChanIL_h diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index a2f4b2c41..708e46f18 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.11 1996/11/02 00:54:24 jhill + * many improvements + * * Revision 1.10 1996/09/16 18:24:05 jhill * vxWorks port changes * @@ -150,7 +153,7 @@ inline caStatus casStrmClient::createChannel (const char *pName) // copied (not referenced) so we are ok if they wrap // pName through into retVal // - status = createChanResponse (*this->ctx.getMsg(), retVal); + status = this->createChanResponse (*this->ctx.getMsg(), retVal); } return status; } @@ -1311,9 +1314,13 @@ caStatus casStrmClient::readSyncAction() -/* - * caStatus casStrmClient::accessRightsResponse() - */ + // + // casStrmClient::accessRightsResponse() + // + // NOTE: + // Do not change the size of this response without making + // parallel changes in createChanResp + // caStatus casStrmClient::accessRightsResponse(casChannelI *pciu) { caHdr *reply; @@ -1575,6 +1582,7 @@ caStatus createDBRDD (unsigned dbrType, aitIndex dbrCount, gdd *&pDescRet) aitUint32 valIndex; aitUint32 gddStatus; aitUint16 appType; + gdd *pVal; appType = gddDbrToAit[dbrType].app; @@ -1586,40 +1594,92 @@ caStatus createDBRDD (unsigned dbrType, aitIndex dbrCount, gdd *&pDescRet) return S_cas_noMemory; } - // - // set bounds for the value member - // - if (dbrCount != 1u) { - if (pDescRet->isContainer()) { - gddContainer *pCont = (gddContainer *) pDescRet; - gdd *pVal; + if (pDescRet->isContainer()) { + gddContainer *pCont = (gddContainer *) pDescRet; - gddStatus = + // + // All DBR types have a value member + // + gddStatus = gddApplicationTypeTable::app_table.mapAppToIndex (appType, gddAppType_value, valIndex); - if (gddStatus) { - pDescRet->unreference(); - pDescRet = NULL; - return S_cas_badType; - } - pVal = pCont->getDD(valIndex); - assert (pVal); - gddStatus = pVal->setBound (0, 0u, dbrCount); - assert (gddStatus==0); + if (gddStatus) { + pDescRet->unreference(); + pDescRet = NULL; + return S_cas_internal; } - else if (pDescRet->isAtomic()) { - gddAtomic *pAtomic = (gddAtomic *) pDescRet; - gddStatus = pAtomic->setBound(0, 0u, dbrCount); - assert (gddStatus==0); + pVal = pCont->getDD(valIndex); + if (!pVal) { + pDescRet->unreference(); + pDescRet = NULL; + return S_cas_internal; + } + } + else { + pVal = pDescRet; + } + + if (pVal->isScalar()) { + if (dbrCount<=1u) { + return S_cas_success; + } + + // + // scaler and managed (and need to set the bounds) + // => out of luck (cant modify bounds) + // + if (pDescRet->isManaged()) { + pDescRet->unreference(); + pDescRet = NULL; + return S_cas_internal; + } + + // + // convert to atomic + // + pVal->setDimension(1); + pVal->setBound(0, 0u, dbrCount); + } + else if (pVal->isAtomic()) { + const gddBounds* pB = pVal->getBounds(); + aitIndex bound = dbrCount; + unsigned dim; + int modAllowed; + + if (pDescRet->isManaged() || pDescRet->isFlat()) { + modAllowed = FALSE; } else { - assert (dbrCount==1u); + modAllowed = TRUE; } + + for (dim=0u; dim<(unsigned)pVal->dimension(); dim++) { + if (pB->first()!=0u && pB->size()!=bound) { + if (modAllowed) { + pVal->setBound(dim, 0u, bound); + } + else { + pDescRet->unreference(); + pDescRet = NULL; + return S_cas_internal; + } + } + bound = 0u; + } + } + else { + // + // the GDD is container or isnt any of the normal types + // + pDescRet->unreference(); + pDescRet = NULL; + return S_cas_internal; } return S_cas_success; } + // // casStrmClient::userName() @@ -1648,6 +1708,7 @@ caStatus casStrmClient::createChanResponse(const caHdr &msg, casChannelI *pChanI; casPVI *pPV; caHdr *claim_reply; + caHdr *dummy; unsigned dbrType; caStatus status; @@ -1665,7 +1726,13 @@ caStatus casStrmClient::createChanResponse(const caHdr &msg, return this->channelCreateFailed(&msg, S_cas_badParameter); } - status = allocMsg (0u, &claim_reply); + // + // NOTE: + // We are allocating enough space for both the claim + // response and the access response so that we know for + // certain that they will both be sent together. + // + status = this->allocMsg (sizeof(caHdr), &dummy); if (status) { return status; } @@ -1698,6 +1765,19 @@ caStatus casStrmClient::createChanResponse(const caHdr &msg, pChanI = (casChannelI *) pChan; + // + // NOTE: + // We are certain that the request will complete + // here because we allocated enough space for this + // and the claim response above. + // + status = casStrmClient::accessRightsResponse(pChanI); + if (status) { + errMessage(status, "incompplete channel create?"); + pChanI->clientDestroy(); + return this->channelCreateFailed(&msg, status); + } + status = pPV->bestDBRType(dbrType); if (status) { errMessage(status, "best external dbr type fetch failed"); @@ -1705,12 +1785,35 @@ caStatus casStrmClient::createChanResponse(const caHdr &msg, return this->channelCreateFailed(&msg, status); } + // + // NOTE: + // We are allocated enough space for both the claim + // response and the access response so that we know for + // certain that they will both be sent together. + // Nevertheles, some (old) clients do not receive + // an access rights response so we allocate again + // here to be certain that we are at the correct place in + // the protocol buffer. + // + status = this->allocMsg (sizeof(caHdr), &claim_reply, + FALSE /* dont lock the out buffer again*/); + // + // Not sending the access rights response and the claim + // response is a severe error which is avoided by + // the first (oversize) allocMsg + // + assert (status==S_cas_success); + *claim_reply = nill_msg; claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU; claim_reply->m_type = dbrType; claim_reply->m_count = pPV->nativeCount(); claim_reply->m_cid = msg.m_cid; claim_reply->m_available = pChanI->getSID(); + + // + // Unlock the buffer (and convert it to network format + // this->commitMsg(); return status; diff --git a/src/cas/generic/casdef.h b/src/cas/generic/casdef.h index d87db21cb..4bdbd8039 100644 --- a/src/cas/generic/casdef.h +++ b/src/cas/generic/casdef.h @@ -30,6 +30,9 @@ * Modification Log: * ----------------- * $Log$ + * Revision 1.9 1996/11/22 19:52:24 jhill + * doc + * * Revision 1.8 1996/11/22 19:22:53 jhill * doc * @@ -375,7 +378,7 @@ public: // where no clients are attached. // 2) once for all PVs that exist when the server is deleted // - // the default destroy() executes "delete this" + // the default (base) "destroy()" executes "delete this" // virtual void destroy (); @@ -383,7 +386,52 @@ public: // tbe best type for clients to use when accessing the // value of the PV // - virtual aitEnum bestExternalType (); + virtual aitEnum bestExternalType () const; + + // + // Returns the maximum bounding box for all present and + // future data stored within the PV. + // + // The routine "dimension()" returns the maximum + // number of dimensions in the hypercube (0=scaler, + // 1=array, 2=plane, 3=cube ...}. + // + // The routine "maxBound(dimension)" returns the + // maximum length of a particular dimension of the + // hypercube as follows: + // + // dim equal to 0 1 3 ... + // ------------------------------------------- + // hypercube + // type + // --------- + // + // array array + // length + // + // plane x y + // + // cube x y z + // + // . + // . + // . + // + // The default (base) "dimension()" returns zero (scaler). + // The default (base) "maxBound()" returns scaler bounds + // for all dimensions. + // + // Clients will see that the PV's data is scaler if + // these routines are not supplied in the derived class. + // + // If the "dimension" argument to maxBounds() is set to + // zero then the bound on the first dimension is being + // fetched. If the "dimension" argument to maxBound() is + // set to one then the bound on the second dimension + // are being fetched... + // + virtual unsigned maxDimension() const; // return zero if scaler + virtual aitIndex maxBound (unsigned dimension) const; // // Server tool calls this function to post a PV event. diff --git a/src/cas/generic/outBuf.cc b/src/cas/generic/outBuf.cc index 449d75ce8..d7b8ccbe4 100644 --- a/src/cas/generic/outBuf.cc +++ b/src/cas/generic/outBuf.cc @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.5 1996/11/02 00:54:30 jhill + * many improvements + * * Revision 1.4 1996/09/16 18:24:07 jhill * vxWorks port changes * @@ -91,7 +94,8 @@ outBuf::~outBuf() // caStatus outBuf::allocMsg ( bufSizeT extsize, // extension size -caHdr **ppMsg +caHdr **ppMsg, +int lockRequired ) { bufSizeT msgsize; @@ -106,7 +110,14 @@ caHdr **ppMsg stackNeeded = this->bufSize - msgsize; - this->mutex.osiLock(); + // + // In some special situations we preallocate space for + // two messages and prefer not to lock twice + // (so that lock/unlock pairs will match) + // + if (lockRequired) { + this->mutex.osiLock(); + } if (this->stack > stackNeeded) { diff --git a/src/cas/generic/server.h b/src/cas/generic/server.h index 28bb8189e..d65590568 100644 --- a/src/cas/generic/server.h +++ b/src/cas/generic/server.h @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.12 1996/11/02 00:54:31 jhill + * many improvements + * * Revision 1.11 1996/09/16 18:24:09 jhill * vxWorks port changes * @@ -353,7 +356,7 @@ public: // allocate message buffer space // (leaves message buffer locked) // - caStatus allocMsg (unsigned extsize, caHdr **ppMsg); + caStatus allocMsg (unsigned extsize, caHdr **ppMsg, int lockRequired=1); // // commits message allocated with allocMsg()