fixed enum string table cache update so that it can complete asynchronously
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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 () ),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user