fixed enum string table cache update so that it can complete asynchronously

This commit is contained in:
Jeff Hill
2002-08-22 00:00:22 +00:00
parent b566183c2f
commit cb9b81cdad
11 changed files with 306 additions and 273 deletions
+8 -11
View File
@@ -25,22 +25,19 @@
//
// casAsyncIOI::casAsyncIOI()
//
casAsyncIOI::casAsyncIOI ( casCoreClient & clientIn ) :
client ( clientIn ), inTheEventQueue ( false ),
posted ( false ), ioComplete ( false ), serverDelete ( false )
casAsyncIOI::casAsyncIOI ( const casCtx & ctx ) :
client ( *ctx.getClient() ), inTheEventQueue ( false ),
posted ( false ), ioComplete ( false ),
serverDelete ( false ), duplicate ( false )
{
//
// catch situation where they create more than one
// async IO object per request
//
if (client.asyncIOFlag) {
errMessage(S_cas_badParameter,
"- duplicate async IO creation");
this->duplicate = TRUE;
}
else {
client.asyncIOFlag = TRUE;
this->duplicate = FALSE;
if ( ! client.okToStartAsynchIO () ) {
errMessage ( S_cas_badParameter,
"- duplicate async IO creation" );
this->duplicate = true;
}
}
+14 -14
View File
@@ -24,25 +24,25 @@
// casAsyncPVAttachIO::casAsyncPVAttachIO()
//
casAsyncPVAttachIO::casAsyncPVAttachIO (const casCtx &ctx) :
casAsyncIOI (*ctx.getClient()),
msg (*ctx.getMsg()),
retVal (S_cas_badParameter)
casAsyncIOI ( ctx ),
msg ( *ctx.getMsg() ),
retVal ( S_cas_badParameter )
{
this->client.installAsyncIO (*this);
this->client.installAsyncIO ( *this );
}
//
// casAsyncPVAttachIO::~casAsyncPVAttachIO()
//
casAsyncPVAttachIO::~casAsyncPVAttachIO()
casAsyncPVAttachIO::~casAsyncPVAttachIO ()
{
this->client.removeAsyncIO (*this);
this->client.removeAsyncIO ( *this );
}
//
// casAsyncPVAttachIO::postIOCompletion()
//
caStatus casAsyncPVAttachIO::postIOCompletion(const pvAttachReturn &retValIn)
caStatus casAsyncPVAttachIO::postIOCompletion ( const pvAttachReturn & retValIn )
{
this->retVal = retValIn;
return this->postIOCompletionI ();
@@ -56,14 +56,14 @@ epicsShareFunc caStatus casAsyncPVAttachIO::cbFuncAsyncIO()
{
caStatus status;
switch (this->msg.m_cmmd) {
switch ( this->msg.m_cmmd ) {
case CA_PROTO_CLAIM_CIU:
status = this->client.createChanResponse (this->msg, this->retVal);
status = this->client.createChanResponse ( this->msg, this->retVal );
break;
default:
errPrintf (S_cas_invalidAsynchIO, __FILE__, __LINE__,
" - client request type = %u", this->msg.m_cmmd);
errPrintf ( S_cas_invalidAsynchIO, __FILE__, __LINE__,
" - client request type = %u", this->msg.m_cmmd );
status = S_cas_invalidAsynchIO;
break;
}
@@ -82,15 +82,15 @@ void casAsyncPVAttachIO::destroy ()
//
// deprecated
//
casAsyncPVCreateIO::casAsyncPVCreateIO(const casCtx &ctx) :
casAsyncPVAttachIO (ctx)
casAsyncPVCreateIO::casAsyncPVCreateIO ( const casCtx & ctx ) :
casAsyncPVAttachIO ( ctx )
{
}
//
// deprecated
//
epicsShareFunc casAsyncPVCreateIO::~casAsyncPVCreateIO()
epicsShareFunc casAsyncPVCreateIO::~casAsyncPVCreateIO ()
{
}
+1 -1
View File
@@ -25,7 +25,7 @@
// casAsyncPVExistIO::casAsyncPVExistIO()
//
casAsyncPVExistIO::casAsyncPVExistIO (const casCtx &ctx) :
casAsyncIOI ( *ctx.getClient () ),
casAsyncIOI ( ctx ),
msg ( *ctx.getMsg () ),
retVal (pverDoesNotExistHere),
dgOutAddr ( ctx.getClient ()->fetchLastRecvAddr () ),
+32 -8
View File
@@ -15,6 +15,7 @@
* 505 665 1831
*/
#include "dbMapper.h"
#include "server.h"
#include "casChannelIIL.h" // casChannelI in line func
@@ -24,8 +25,8 @@
// casAsyncReadIO::casAsyncReadIO()
//
casAsyncReadIO::casAsyncReadIO ( const casCtx & ctx ) :
casAsyncIOI ( *ctx.getClient() ), msg ( *ctx.getMsg() ),
chan( *ctx.getChannel () ), pDD ( NULL ), completionStatus ( S_cas_internal )
casAsyncIOI ( ctx ), msg ( *ctx.getMsg() ),
chan ( *ctx.getChannel () ), pDD ( NULL ), completionStatus ( S_cas_internal )
{
assert ( & this->chan );
this->chan.installAsyncIO ( *this );
@@ -48,7 +49,7 @@ caStatus casAsyncReadIO::postIOCompletion (caStatus completionStatusIn,
{
{
epicsGuard < casCoreClient > guard ( this->client );
this->pDD = &valueRead;
this->pDD = & valueRead;
this->completionStatus = completionStatusIn;
}
@@ -73,25 +74,48 @@ epicsShareFunc caStatus casAsyncReadIO::cbFuncAsyncIO()
switch ( this->msg.m_cmmd ) {
case CA_PROTO_READ:
status = client.readResponse (&this->chan, this->msg,
status = client.readResponse ( &this->chan, this->msg,
*this->pDD, this->completionStatus);
break;
case CA_PROTO_READ_NOTIFY:
status = client.readNotifyResponse (&this->chan,
status = client.readNotifyResponse ( &this->chan,
this->msg, this->pDD,
this->completionStatus);
break;
case CA_PROTO_EVENT_ADD:
status = client.monitorResponse (this->chan,
status = client.monitorResponse ( this->chan,
this->msg, this->pDD,
this->completionStatus);
break;
case CA_PROTO_CLAIM_CIU:
unsigned nativeTypeDBR;
status = this->chan.getPVI().bestDBRType ( nativeTypeDBR );
if ( status ) {
errMessage ( status, "best external dbr type fetch failed" );
status = client.channelCreateFailedResp ( this->msg, status );
}
else {
// we end up here if the channel claim protocol response is delayed
// by an asynchronous enum string table fetch response
if ( this->completionStatus == S_cas_success && this->pDD.valid() ) {
this->chan.getPVI().updateEnumStringTableAsyncCompletion ( *this->pDD );
}
else {
errMessage ( this->completionStatus,
"unable to read application type \"enums\" string"
" conversion table for enumerated PV" );
}
status = client.enumPostponedCreateChanResponse ( this->chan,
this->msg, nativeTypeDBR );
}
break;
default:
errPrintf (S_cas_invalidAsynchIO, __FILE__, __LINE__,
" - client request type = %u", this->msg.m_cmmd);
errPrintf ( S_cas_invalidAsynchIO, __FILE__, __LINE__,
" - client request type = %u", this->msg.m_cmmd );
status = S_cas_invalidAsynchIO;
break;
}
+19 -19
View File
@@ -23,14 +23,14 @@
//
// casAsyncWriteIO::casAsyncWriteIO()
//
casAsyncWriteIO::casAsyncWriteIO(const casCtx &ctx) :
casAsyncIOI(*ctx.getClient()),
msg(*ctx.getMsg()),
chan(*ctx.getChannel()),
completionStatus(S_cas_internal)
casAsyncWriteIO::casAsyncWriteIO ( const casCtx & ctx ) :
casAsyncIOI ( ctx ),
msg ( *ctx.getMsg() ),
chan ( *ctx.getChannel() ),
completionStatus ( S_cas_internal )
{
assert (&this->chan);
this->chan.installAsyncIO(*this);
assert ( &this->chan );
this->chan.installAsyncIO ( *this );
}
//
@@ -39,40 +39,40 @@ casAsyncWriteIO::casAsyncWriteIO(const casCtx &ctx) :
casAsyncWriteIO::~casAsyncWriteIO()
{
epicsGuard < casCoreClient > guard ( this->client );
this->chan.removeAsyncIO(*this);
this->chan.removeAsyncIO ( *this );
}
//
// casAsyncWriteIO::postIOCompletion()
//
caStatus casAsyncWriteIO::postIOCompletion(caStatus completionStatusIn)
caStatus casAsyncWriteIO::postIOCompletion ( caStatus completionStatusIn )
{
this->completionStatus = completionStatusIn;
return this->postIOCompletionI();
return this->postIOCompletionI ();
}
//
// casAsyncWriteIO::cbFuncAsyncIO()
// (called when IO completion event reaches top of event queue)
//
epicsShareFunc caStatus casAsyncWriteIO::cbFuncAsyncIO()
epicsShareFunc caStatus casAsyncWriteIO::cbFuncAsyncIO ()
{
caStatus status;
caStatus status;
switch (this->msg.m_cmmd) {
switch ( this->msg.m_cmmd ) {
case CA_PROTO_WRITE:
status = client.writeResponse(this->msg,
this->completionStatus);
status = client.writeResponse ( this->msg,
this->completionStatus );
break;
case CA_PROTO_WRITE_NOTIFY:
status = client.writeNotifyResponse(
this->msg, this->completionStatus);
status = client.writeNotifyResponse (
this->msg, this->completionStatus );
break;
default:
errPrintf (S_cas_invalidAsynchIO, __FILE__, __LINE__,
" - client request type = %u", this->msg.m_cmmd);
errPrintf ( S_cas_invalidAsynchIO, __FILE__, __LINE__,
" - client request type = %u", this->msg.m_cmmd );
status = S_cas_invalidAsynchIO;
break;
}
+11 -1
View File
@@ -125,7 +125,17 @@ caStatus casCoreClient::monitorResponse ( casChannelI &, const caHdrLargeArray &
{
return S_casApp_noSupport;
}
caStatus casCoreClient::accessRightsResponse (casChannelI *)
caStatus casCoreClient::accessRightsResponse ( casChannelI * )
{
return S_casApp_noSupport;
}
caStatus casCoreClient::enumPostponedCreateChanResponse ( casChannelI &,
const caHdrLargeArray &, unsigned )
{
return S_casApp_noSupport;
}
caStatus casCoreClient::channelCreateFailedResp ( const caHdrLargeArray &,
caStatus createStatus )
{
return S_casApp_noSupport;
}
+9
View File
@@ -60,5 +60,14 @@ inline void casCoreClient::removeAsyncIO(casAsyncIOI &ioIn)
this->ctx.getServer()->ioBlockedList::signal();
}
inline bool casCoreClient::okToStartAsynchIO ()
{
if ( ! this->asyncIOFlag ) {
this->asyncIOFlag = true;
return true;
}
return false;
}
#endif // casCoreClientIL_h
+23 -63
View File
@@ -221,13 +221,13 @@ class casAsyncPVAttachIO;
class casAsyncIOI : public casEvent, public tsDLNode<casAsyncIOI> {
public:
casAsyncIOI (casCoreClient &client);
epicsShareFunc virtual ~casAsyncIOI();
casAsyncIOI ( const casCtx & ctx );
epicsShareFunc virtual ~casAsyncIOI ();
void serverDestroyIfReadOP ();
void serverDestroy ();
caServer *getCAS() const;
caServer *getCAS () const;
protected:
casCoreClient & client;
@@ -392,88 +392,48 @@ class casPVI :
public:
casPVI ();
epicsShareFunc virtual ~casPVI ();
//
// for use by the server library
//
caServerI *getPCAS () const;
//
// attach to a server
//
caStatus attachToServer (caServerI &cas);
//
// CA only does 1D arrays for now (and the new server
// temporarily does only scalars)
//
caStatus attachToServer ( caServerI & cas );
aitIndex nativeCount ();
//
// only for use by casMonitor
//
caStatus registerEvent ();
void unregisterEvent ();
//
// only for use by casAsyncIOI
//
void unregisterIO ();
//
// only for use by casChannelI
//
void installChannel (casPVListChan &chan);
//
// only for use by casChannelI
//
void removeChannel (casPVListChan &chan);
//
// check for none attached and delete self if so
//
void installChannel ( casPVListChan & chan );
void removeChannel ( casPVListChan & chan );
void deleteSignal ();
void postEvent (const casEventMask &select, const gdd &event);
caServer *getExtServer () const;
//
// bestDBRType()
//
caStatus bestDBRType (unsigned &dbrType);
void postEvent ( const casEventMask & select, const gdd & event );
caServer * getExtServer () const;
caStatus bestDBRType ( unsigned & dbrType );
epicsShareFunc virtual casResType resourceType () const;
const gddEnumStringTable & enumStringTable () const;
void updateEnumStringTable ();
caStatus updateEnumStringTable ( casCtx & );
void updateEnumStringTableAsyncCompletion ( const gdd & resp );
//
// virtual functions in the public interface class
//
epicsShareFunc virtual void show (unsigned level) const;
epicsShareFunc virtual void show ( unsigned level ) const;
epicsShareFunc virtual caStatus interestRegister () = 0;
epicsShareFunc virtual void interestDelete () = 0;
epicsShareFunc virtual caStatus beginTransaction () = 0;
epicsShareFunc virtual void endTransaction () = 0;
epicsShareFunc virtual caStatus read (const casCtx &ctx, gdd &prototype) = 0;
epicsShareFunc virtual caStatus write (const casCtx &ctx, const gdd &value) = 0;
epicsShareFunc virtual casChannel *createChannel (const casCtx &ctx,
const char * const pUserName, const char * const pHostName) = 0;
epicsShareFunc virtual caStatus read ( const casCtx & ctx, gdd & prototype ) = 0;
epicsShareFunc virtual caStatus write ( const casCtx & ctx, const gdd & value ) = 0;
epicsShareFunc virtual casChannel *createChannel (const casCtx & ctx,
const char * const pUserName, const char * const pHostName ) = 0;
epicsShareFunc virtual aitEnum bestExternalType () const = 0;
epicsShareFunc virtual unsigned maxDimension () const = 0;
epicsShareFunc virtual aitIndex maxBound (unsigned dimension) const = 0;
epicsShareFunc virtual aitIndex maxBound ( unsigned dimension ) const = 0;
epicsShareFunc virtual const char *getName () const = 0;
epicsShareFunc casPV *apiPointer (); //retuns NULL if casPVI isnt a base of casPV
private:
tsDLList<casPVListChan> chanList;
gddEnumStringTable enumStrTbl;
caServerI *pCAS;
unsigned nMonAttached;
unsigned nIOAttached;
bool destroyInProgress;
tsDLList < casPVListChan > chanList;
gddEnumStringTable enumStrTbl;
caServerI * pCAS;
unsigned nMonAttached;
unsigned nIOAttached;
bool destroyInProgress;
epicsShareFunc virtual void destroy (); // casPVI destructor noop
casPVI ( const casPVI & );
+73 -69
View File
@@ -102,6 +102,8 @@ void casPVI::deleteSignal ()
if ( this->chanList.count() == 0u ) {
this->pCAS->removeItem ( *this );
this->pCAS = NULL;
// refresh the table whenever the server reattaches to the PV
this->enumStrTbl.clear ();
this->destroy ();
//
// !! dont access self after destroy !!
@@ -124,24 +126,18 @@ void casPVI::destroy ()
//
// casPVI::attachToServer ()
//
caStatus casPVI::attachToServer (caServerI &cas)
caStatus casPVI::attachToServer ( caServerI & cas )
{
if ( this->pCAS ) {
//
// currently we enforce that the PV can be attached to only
// one server at a time
//
if ( this->pCAS != &cas ) {
if ( this->pCAS != & cas ) {
return S_cas_pvAlreadyAttached;
}
}
else {
//
// update only when attaching to the server so
// this does not change while clients are using it
//
this->updateEnumStringTable ();
//
// install the PV into the server
//
@@ -159,137 +155,145 @@ caStatus casPVI::attachToServer (caServerI &cas)
//
// what a API complexity nightmare this GDD is
//
void casPVI::updateEnumStringTable ()
caStatus casPVI::updateEnumStringTable ( casCtx & ctx )
{
static const aitUint32 stringTableTypeStaticInit = 0xffffffff;
static aitUint32 stringTableType = stringTableTypeStaticInit;
//
// reload the enum string table each time that the
// PV is attached to the server
// keep trying to fill in the table if client disconnects
// prevented previous asynchronous IO from finishing, but if
// a previous client has succeeded then dont bother.
//
this->enumStrTbl.clear ();
//
// fetch the native type
//
aitEnum bestAIT = this->bestExternalType ();
//
// empty string table for non-enumerated PVs
//
if ( bestAIT != aitEnumEnum16 ) {
return;
if ( this->enumStrTbl.numberOfStrings () > 0 ) {
return S_cas_success;
}
//
// lazy init
//
if ( stringTableType == stringTableTypeStaticInit ) {
stringTableType = gddApplicationTypeTable::app_table.registerApplicationType ("enums");
stringTableType =
gddApplicationTypeTable::app_table.registerApplicationType ("enums");
}
//
// create a gdd with the "enum string table" application type
//
gdd *pTmp = new gddScalar ( stringTableType );
if (pTmp==NULL) {
if ( pTmp == NULL ) {
errMessage ( S_cas_noMemory,
"unable to read application type \"enums\" string conversion table for enumerated PV" );
return;
"unable to read application type \"enums\" string"
" conversion table for enumerated PV" );
return S_cas_noMemory;
}
//
// create a false context which is guaranteed to cause
// any asynch IO to be ignored
//
casCtx ctx;
//
// read the enum string table
//
caStatus status = this->read ( ctx, *pTmp );
if (status == S_casApp_asyncCompletion || status == S_casApp_postponeAsyncIO) {
if ( status == S_casApp_asyncCompletion ) {
return status;
}
else if ( 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;
return status;
}
else if ( status ) {
pTmp->unreference ();
errMessage (status,
"unable to read application type \"enums\" string conversion table for enumerated PV");
return;
errMessage ( status,
"unable to read application type \"enums\" string"
" conversion table for enumerated PV");
return status;
}
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 ();
updateEnumStringTableAsyncCompletion ( *pTmp );
pTmp->unreference ();
return status;
}
void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
{
//
// keep trying to fill in the table if client disconnects
// prevented previous asynchronous IO from finishing, but if
// a previous client has succeeded then dont bother.
//
if ( this->enumStrTbl.numberOfStrings () > 0 ) {
return;
}
if ( pTmp->dimension() == 0 ) {
if ( pTmp->primitiveType() == aitEnumString ) {
aitString *pStr = (aitString *) pTmp->dataVoid ();
if ( resp.isContainer() ) {
errMessage ( S_cas_badType,
"application type \"enums\" string conversion table for"
" enumerated PV was a container (expected vector of strings)" );
return;
}
if ( resp.dimension() == 0 ) {
if ( resp.primitiveType() == aitEnumString ) {
aitString *pStr = (aitString *) resp.dataVoid ();
if ( ! this->enumStrTbl.setString ( 0, pStr->string() ) ) {
errMessage ( S_cas_noMemory, "no memory to set enumerated PV string cache" );
errMessage ( S_cas_noMemory,
"no memory to set enumerated PV string cache" );
}
}
else if ( pTmp->primitiveType()==aitEnumFixedString ) {
aitFixedString *pStr = (aitFixedString *) pTmp->dataVoid ();
else if ( resp.primitiveType() == aitEnumFixedString ) {
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
if ( ! this->enumStrTbl.setString ( 0, pStr->fixed_string ) ) {
errMessage ( S_cas_noMemory, "no memory to set enumerated PV string cache" );
errMessage ( S_cas_noMemory,
"no memory to set enumerated PV string cache" );
}
}
else {
errMessage ( S_cas_badType,
"application type \"enums\" string conversion table for enumerated PV isnt a string type?" );
"application type \"enums\" string conversion"
" table for enumerated PV isnt a string type?" );
}
}
else if ( pTmp->dimension() == 1 ) {
else if ( resp.dimension() == 1 ) {
gddStatus gdd_status;
aitIndex index, first, count;
gdd_status = pTmp->getBound ( 0, first, count );
assert (gdd_status == 0);
gdd_status = resp.getBound ( 0, first, count );
assert ( gdd_status == 0 );
//
// preallocate the correct amount
//
this->enumStrTbl.reserve ( count );
if ( pTmp->primitiveType() == aitEnumString ) {
aitString *pStr = (aitString *) pTmp->dataVoid ();
if ( resp.primitiveType() == aitEnumString ) {
aitString *pStr = (aitString *) resp.dataVoid ();
for ( index = 0; index<count; index++ ) {
if ( ! this->enumStrTbl.setString ( index, pStr[index].string() ) ) {
errMessage ( S_cas_noMemory, "no memory to set enumerated PV string cache" );
errMessage ( S_cas_noMemory,
"no memory to set enumerated PV string cache" );
}
}
}
else if ( pTmp->primitiveType() == aitEnumFixedString ) {
aitFixedString *pStr = (aitFixedString *) pTmp->dataVoid ();
else if ( resp.primitiveType() == aitEnumFixedString ) {
aitFixedString *pStr = (aitFixedString *) resp.dataVoid ();
for ( index = 0; index<count; index++ ) {
if ( ! this->enumStrTbl.setString ( index, pStr[index].fixed_string ) ) {
errMessage ( S_cas_noMemory, "no memory to set enumerated PV string cache" );
errMessage ( S_cas_noMemory,
"no memory to set enumerated PV string cache" );
}
}
}
else {
errMessage ( S_cas_badType,
"application type \"enums\" string conversion table for enumerated PV isnt a string type?" );
"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)" );
"application type \"enums\" string conversion table"
" for enumerated PV was multi-dimensional"
" (expected vector of strings)" );
}
pTmp->unreference ();
return;
}
//
+89 -56
View File
@@ -1006,46 +1006,94 @@ caStatus casStrmClient::claimChannelAction()
//
// LOCK must be applied
//
caStatus casStrmClient::createChanResponse(const caHdrLargeArray &hdr, const pvAttachReturn &pvar)
caStatus casStrmClient::createChanResponse ( const caHdrLargeArray & hdr, const pvAttachReturn & pvar )
{
casPVI *pPV;
casChannel *pChan;
casChannelI *pChanI;
bufSizeT nBytes;
caStatus status;
if (pvar.getStatus() != S_cas_success) {
return this->channelCreateFailed (&hdr, pvar.getStatus());
if ( pvar.getStatus() != S_cas_success ) {
return this->channelCreateFailedResp ( hdr, pvar.getStatus() );
}
pPV = pvar.getPV();
casPVI * pPV = pvar.getPV();
//
// If status is ok and the PV isnt set then guess that the
// pv isnt in this server
//
if (pPV == NULL) {
return this->channelCreateFailed (&hdr, S_casApp_pvNotFound);
if ( pPV == NULL ) {
return this->channelCreateFailedResp ( hdr, S_casApp_pvNotFound );
}
//
// fetch the native type
//
unsigned nativeType;
status = pPV->bestDBRType(nativeType);
if (status) {
errMessage(status, "best external dbr type fetch failed");
return this->channelCreateFailed (&hdr, status);
unsigned nativeTypeDBR;
caStatus status = pPV->bestDBRType ( nativeTypeDBR );
if ( status ) {
errMessage ( status, "best external dbr type fetch failed" );
return this->channelCreateFailedResp ( hdr, status );
}
//
// attach the PV to this server
//
status = pPV->attachToServer (this->getCAS());
if (status) {
return this->channelCreateFailed (&hdr, status);
status = pPV->attachToServer ( this->getCAS() );
if ( status ) {
return this->channelCreateFailedResp ( hdr, status );
}
//
// create server tool XXX derived from casChannel
//
this->ctx.setPV ( pPV );
casChannel * pChan = pPV->createChannel ( this->ctx, this->pUserName, this->pHostName );
if ( ! pChan ) {
pPV->deleteSignal();
return this->channelCreateFailedResp ( hdr, S_cas_noMemory );
}
pChan->bindToClient ( *this, *pPV, hdr.m_cid );
casChannelI * pChanI = (casChannelI *) pChan;
//
// check to see if the enum table is empty and therefore
// an update is needed every time that a PV attaches
// to the server in case the client disconnected before
// an asynchronous IO to get the table comleted
//
if ( nativeTypeDBR == DBR_ENUM ) {
this->ctx.setPV ( pPV );
this->ctx.setChannel ( pChanI );
this->asyncIOFlag = false;
status = pPV->updateEnumStringTable ( this->ctx );
if ( this->asyncIOFlag ) {
if ( status != S_casApp_asyncCompletion ) {
fprintf ( stderr,
"Application returned %d from casPV::read()"
" - expected S_casApp_asyncCompletion\n", status);
status = S_casApp_asyncCompletion;
}
}
else if ( status == S_casApp_asyncCompletion) {
status = S_cas_badParameter;
errMessage ( status,
"- expected asynch IO creation from casPV::read()");
}
else if ( status == S_casApp_success ) {
status = enumPostponedCreateChanResponse ( *pChan, hdr, nativeTypeDBR );
}
}
else {
status = enumPostponedCreateChanResponse ( *pChan, hdr, nativeTypeDBR );
}
return status;
}
//
// casStrmClient::enumPostponedCreateChanResponse()
//
// LOCK must be applied
//
caStatus casStrmClient::enumPostponedCreateChanResponse (
casChannelI & chan, const caHdrLargeArray & hdr, unsigned nativeTypeDBR )
{
//
// We are allocating enough space for both the claim
// response and the access rights response so that we know for
@@ -1054,36 +1102,21 @@ caStatus casStrmClient::createChanResponse(const caHdrLargeArray &hdr, const pvA
void *pRaw;
const outBufCtx outctx = this->out.pushCtx
( 0, 2 * sizeof ( caHdr ), pRaw );
if (outctx.pushResult()!=outBufCtx::pushCtxSuccess) {
if ( outctx.pushResult() != outBufCtx::pushCtxSuccess ) {
return S_cas_sendBlocked;
}
//
// create server tool XXX derived from casChannel
//
this->ctx.setPV (pPV);
pChan = pPV->createChannel (this->ctx, this->pUserName, this->pHostName);
if (!pChan) {
this->out.popCtx (outctx);
pPV->deleteSignal();
return this->channelCreateFailed (&hdr, S_cas_noMemory);
}
pChan->bindToClient ( *this, *pPV, hdr.m_cid );
pChanI = (casChannelI *) pChan;
//
// 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) {
this->out.popCtx (outctx);
errMessage(status, "incomplete channel create?");
pChanI->destroyNoClientNotify();
return this->channelCreateFailed(&hdr, status);
caStatus status = casStrmClient::accessRightsResponse ( & chan );
if ( status ) {
this->out.popCtx ( outctx );
errMessage ( status, "incomplete channel create?" );
chan.destroyNoClientNotify ();
return this->channelCreateFailedResp ( hdr, status );
}
//
@@ -1095,17 +1128,17 @@ caStatus casStrmClient::createChanResponse(const caHdrLargeArray &hdr, const pvA
// here to be certain that we are at the correct place in
// the protocol buffer.
//
assert ( nativeType <= 0xffff );
unsigned nativeCount = pPV->nativeCount();
assert ( nativeTypeDBR <= 0xffff );
unsigned nativeCount = chan.getPVI().nativeCount();
status = this->out.copyInHeader ( CA_PROTO_CLAIM_CIU, 0,
static_cast <ca_uint16_t> ( nativeType ),
static_cast <ca_uint16_t> ( nativeTypeDBR ),
static_cast <ca_uint16_t> ( nativeCount ),
hdr.m_cid, pChanI->getSID(), 0 );
hdr.m_cid, chan.getSID(), 0 );
if ( status != S_cas_success ) {
this->out.popCtx ( outctx );
errMessage ( status, "incomplete channel create?" );
pChanI->destroyNoClientNotify();
return this->channelCreateFailed ( &hdr, status );
chan.destroyNoClientNotify ();
return this->channelCreateFailedResp ( hdr, status );
}
this->out.commitMsg ();
@@ -1113,7 +1146,7 @@ caStatus casStrmClient::createChanResponse(const caHdrLargeArray &hdr, const pvA
//
// commit the message
//
nBytes = this->out.popCtx (outctx);
bufSizeT nBytes = this->out.popCtx (outctx);
assert ( nBytes == 2*sizeof(caHdr) );
this->out.commitRawMsg (nBytes);
@@ -1126,8 +1159,8 @@ caStatus casStrmClient::createChanResponse(const caHdrLargeArray &hdr, const pvA
* If we are talking to an CA_V46 client then tell them when a channel
* cant be created (instead of just disconnecting)
*/
caStatus casStrmClient::channelCreateFailed (
const caHdrLargeArray *mp, caStatus createStatus )
caStatus casStrmClient::channelCreateFailedResp (
const caHdrLargeArray & hdr, caStatus createStatus )
{
caStatus status;
@@ -1142,7 +1175,7 @@ caStatus casStrmClient::channelCreateFailed (
}
if ( CA_V46( this->minor_version_number ) ) {
status = this->out.copyInHeader ( CA_PROTO_CLAIM_CIU_FAILED, 0,
0, 0, mp->m_cid, 0, 0 );
0, 0, hdr.m_cid, 0, 0 );
if ( status ) {
return status;
}
@@ -1150,7 +1183,7 @@ caStatus casStrmClient::channelCreateFailed (
createStatus = S_cas_success;
}
else {
status = this->sendErrWithEpicsStatus ( mp, createStatus, ECA_ALLOCMEM );
status = this->sendErrWithEpicsStatus ( & hdr, createStatus, ECA_ALLOCMEM );
if ( status ) {
return status;
}
+27 -31
View File
@@ -423,33 +423,22 @@ private:
//
class casCoreClient : public ioBlocked,
public casEventSys {
//
// allows casAsyncIOI constructor to check for asynch IO duplicates
//
friend casAsyncIOI::casAsyncIOI(casCoreClient &clientIn);
public:
casCoreClient(caServerI &serverInternal);
casCoreClient ( caServerI &serverInternal );
virtual ~casCoreClient();
virtual void destroy();
virtual caStatus disconnectChan(caResId id);
virtual void show (unsigned level) const;
virtual void installChannel (casChannelI &);
virtual void removeChannel (casChannelI &);
virtual caStatus disconnectChan( caResId id );
virtual void show (unsigned level ) const;
virtual void installChannel ( casChannelI & );
virtual void removeChannel ( casChannelI & );
void installAsyncIO(casAsyncIOI &ioIn);
void installAsyncIO( casAsyncIOI & ioIn );
void removeAsyncIO(casAsyncIOI &ioIn);
void removeAsyncIO( casAsyncIOI & ioIn );
casRes *lookupRes(const caResId &idIn, casResType type);
casRes * lookupRes ( const caResId &idIn, casResType type );
caServerI &getCAS() const;
virtual caStatus monitorResponse ( casChannelI &chan, const caHdrLargeArray &msg,
const smartConstGDDPointer &pDesc, const caStatus status );
virtual caStatus accessRightsResponse(casChannelI *);
caServerI & getCAS () const;
void lock ();
void unlock ();
@@ -465,13 +454,20 @@ public:
virtual caStatus createChanResponse (
const caHdrLargeArray &, const pvAttachReturn &);
virtual caStatus readResponse (
casChannelI *, const caHdrLargeArray &, const smartConstGDDPointer &, const caStatus);
casChannelI *, const caHdrLargeArray &, const smartConstGDDPointer &, const caStatus );
virtual caStatus readNotifyResponse (
casChannelI *, const caHdrLargeArray &, const smartConstGDDPointer &, const caStatus);
virtual caStatus writeResponse (const caHdrLargeArray &, const caStatus);
virtual caStatus writeNotifyResponse (const caHdrLargeArray &, const caStatus);
casChannelI *, const caHdrLargeArray &, const smartConstGDDPointer &, const caStatus );
virtual caStatus writeResponse ( const caHdrLargeArray &, const caStatus );
virtual caStatus writeNotifyResponse ( const caHdrLargeArray &, const caStatus );
virtual caStatus monitorResponse ( casChannelI &chan, const caHdrLargeArray &msg,
const smartConstGDDPointer & pDesc, const caStatus status );
virtual caStatus accessRightsResponse ( casChannelI * );
virtual caStatus enumPostponedCreateChanResponse ( casChannelI & chan,
const caHdrLargeArray & hdr, unsigned dbrType );
virtual caStatus channelCreateFailedResp ( const caHdrLargeArray &,
caStatus createStatus );
virtual ca_uint16_t protocolRevision() const = 0;
virtual ca_uint16_t protocolRevision () const = 0;
//
// used only with DG clients
@@ -479,6 +475,8 @@ public:
virtual caNetAddr fetchLastRecvAddr () const;
virtual ca_uint32_t datagramSequenceNumber () const;
bool okToStartAsynchIO ();
protected:
epicsMutex mutex;
casCtx ctx;
@@ -486,7 +484,6 @@ protected:
private:
tsDLList < casAsyncIOI > ioInProgList;
casCoreClient ( const casCoreClient & );
casCoreClient & operator = ( const casCoreClient & );
};
@@ -616,6 +613,10 @@ public:
caStatus writeNotifyResponse (const caHdrLargeArray &msg, const caStatus status);
caStatus monitorResponse ( casChannelI & chan, const caHdrLargeArray & msg,
const smartConstGDDPointer & pDesc, const caStatus status );
caStatus enumPostponedCreateChanResponse ( casChannelI & chan,
const caHdrLargeArray & hdr, unsigned dbrType );
caStatus channelCreateFailedResp ( const caHdrLargeArray &,
caStatus createStatus );
caStatus noReadAccessEvent( casClientMon * );
@@ -673,11 +674,6 @@ private:
caStatus read (smartGDDPointer &pDesc);
caStatus write ();
//
// channelCreateFailed()
//
caStatus channelCreateFailed ( const caHdrLargeArray *mp, caStatus createStatus );
caStatus writeArrayData();
caStatus writeScalarData();
caStatus writeString();