diff --git a/src/cas/generic/casCoreClient.cc b/src/cas/generic/casCoreClient.cc index cbe32b186..d5c6db5fa 100644 --- a/src/cas/generic/casCoreClient.cc +++ b/src/cas/generic/casCoreClient.cc @@ -122,11 +122,10 @@ caStatus casCoreClient::channelCreateFailedResp ( { return S_casApp_noSupport; } -caStatus casCoreClient::channelDestroyNotify ( +caStatus casCoreClient::channelDestroyEvent ( epicsGuard < casClientMutex > &, - casChannelI &, bool ) + casChannelI * const, ca_uint32_t ) { - assert ( 0 ); return S_casApp_noSupport; } diff --git a/src/cas/generic/casCoreClient.h b/src/cas/generic/casCoreClient.h index 6c6cf09bb..b734d49d1 100644 --- a/src/cas/generic/casCoreClient.h +++ b/src/cas/generic/casCoreClient.h @@ -85,10 +85,10 @@ public: virtual caStatus channelCreateFailedResp ( epicsGuard < casClientMutex > &, const caHdrLargeArray &, const caStatus createStatus ); - virtual caStatus channelDestroyNotify ( - epicsGuard < casClientMutex > &, - casChannelI &, bool uninstallNeeded ); - virtual void casChannelDestroyNotify ( + virtual caStatus channelDestroyEvent ( + epicsGuard < casClientMutex > & guard, + casChannelI * const pChan, ca_uint32_t sid ); + virtual void casChannelDestroyNotify ( casChannelI & chan, bool immediateDestroyNeeded ); virtual ca_uint16_t protocolRevision () const = 0; diff --git a/src/cas/generic/casPVI.cc b/src/cas/generic/casPVI.cc index a9cd084ba..f9b264b46 100644 --- a/src/cas/generic/casPVI.cc +++ b/src/cas/generic/casPVI.cc @@ -68,6 +68,7 @@ casPVI::~casPVI () void casPVI::casPVDestroyNotify () { epicsGuard < epicsMutex > guard ( this->mutex ); + this->pPV = 0; if ( ! this->deletePending ) { tsDLIter < chanIntfForPV > iter = this->chanList.firstIter (); while ( iter.valid() ) { diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index e9b27d43a..3e1d341c4 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -1629,6 +1629,61 @@ caStatus casStrmClient::clearChannelAction ( return status; } +// +// If the channel pointer is nill this indicates that +// the existence of the channel isnt certain because +// it is still installed and the client or the server +// tool might have destroyed it. Therefore, we must +// locate it using the supplied server id. +// +// If the channel pointer isnt nill this indicates +// that the channel has already been uninstalled. +// +// In both situations we need to send a channel +// disconnect message to the client and destroy the +// channel. +// +caStatus casStrmClient::channelDestroyEvent ( + epicsGuard < casClientMutex > & guard, + casChannelI * const pChan, ca_uint32_t sid ) +{ + casChannelI * pChanFound; + if ( pChan ) { + pChanFound = pChan; + } + else { + chronIntId tmpId ( sid ); + pChanFound = + this->chanTable.lookup ( tmpId ); + if ( ! pChanFound ) { + return S_cas_success; + } + } + + if ( CA_V47 ( this->minor_version_number ) ) { + caStatus status = this->out.copyInHeader ( + CA_PROTO_SERVER_DISCONN, 0, + 0, 0, pChanFound->getCID(), 0, 0 ); + if ( status == S_cas_sendBlocked ) { + return status; + } + this->out.commitMsg (); + } + else { + this->forceDisconnect (); + } + + if ( ! pChan ) { + this->chanTable.remove ( * pChanFound ); + this->chanList.remove ( * pChanFound ); + pChanFound->uninstallFromPV ( this->eventSys ); + } + + delete pChanFound; + + return S_cas_success; +} + // casStrmClient::casChannelDestroyNotify() // immediateUninstallNeeded is false when we must avoid // taking the lock insituations where we would compromise @@ -1644,9 +1699,10 @@ void casStrmClient::casChannelDestroyNotify ( chan.uninstallFromPV ( this->eventSys ); } - channelDestroyEvent * pEvent = - new ( std::nothrow ) channelDestroyEvent ( - chan, !immediateUninstallNeeded ); + class channelDestroyEvent * pEvent = + new ( std::nothrow ) class channelDestroyEvent ( + immediateUninstallNeeded ? & chan : 0, + chan.getSID() ); if ( pEvent ) { this->eventSys.addToEventQueue ( *pEvent ); } @@ -1658,34 +1714,6 @@ void casStrmClient::casChannelDestroyNotify ( } } -// casStrmClient::channelDestroyNotify() -caStatus casStrmClient::channelDestroyNotify ( - epicsGuard < casClientMutex > & guard, - casChannelI & chan, bool uninstallNeeded ) -{ - caStatus status = S_cas_success; - if ( CA_V47 ( this->minor_version_number ) ) { - caStatus status = this->out.copyInHeader ( - CA_PROTO_SERVER_DISCONN, 0, - 0, 0, chan.getCID(), 0, 0 ); - if ( status == S_cas_success ) { - this->out.commitMsg (); - } - } - else { - this->forceDisconnect (); - } - if ( status != S_cas_sendBlocked ) { - if ( uninstallNeeded ) { - this->chanTable.remove ( chan ); - this->chanList.remove ( chan ); - chan.uninstallFromPV ( this->eventSys ); - } - delete & chan; - } - return status; -} - // casStrmClient::eventCancelAction() caStatus casStrmClient::eventCancelAction ( epicsGuard < casClientMutex > & guard ) diff --git a/src/cas/generic/casStrmClient.h b/src/cas/generic/casStrmClient.h index a09ada069..423e1ce06 100644 --- a/src/cas/generic/casStrmClient.h +++ b/src/cas/generic/casStrmClient.h @@ -127,10 +127,9 @@ private: casChannelI & chan, const caHdrLargeArray & hdr, unsigned dbrType ); caStatus channelCreateFailedResp ( epicsGuard < casClientMutex > &, const caHdrLargeArray &, const caStatus createStatus ); - caStatus channelDestroyNotify ( + caStatus channelDestroyEvent ( epicsGuard < casClientMutex > & guard, - casChannelI &, bool uninstallNeeded ); - + casChannelI * const pChan, ca_uint32_t sid ); caStatus accessRightsResponse ( casChannelI * pciu ); caStatus accessRightsResponse ( diff --git a/src/cas/generic/channelDestroyEvent.cpp b/src/cas/generic/channelDestroyEvent.cpp index 8140db404..284c07320 100644 --- a/src/cas/generic/channelDestroyEvent.cpp +++ b/src/cas/generic/channelDestroyEvent.cpp @@ -25,8 +25,8 @@ caStatus channelDestroyEvent::cbFunc ( epicsGuard < casClientMutex > & clientGuard, epicsGuard < evSysMutex > & ) { - caStatus status = client.channelDestroyNotify ( - clientGuard, this->chan, this->uninstallNeeded ); + caStatus status = client.channelDestroyEvent ( + clientGuard, this->pChan, this->sid ); if ( status != S_cas_sendBlocked ) { delete this; } diff --git a/src/cas/generic/channelDestroyEvent.h b/src/cas/generic/channelDestroyEvent.h index e009abc79..024eff6f6 100644 --- a/src/cas/generic/channelDestroyEvent.h +++ b/src/cas/generic/channelDestroyEvent.h @@ -37,10 +37,11 @@ class casChannelI; class channelDestroyEvent : public casEvent { public: - channelDestroyEvent ( casChannelI &, bool uninstallNeeded ); + channelDestroyEvent ( + casChannelI * pChan, ca_uint32_t sid ); private: - casChannelI & chan; - bool uninstallNeeded; + casChannelI * pChan; + ca_uint32_t sid; caStatus cbFunc ( casCoreClient &, epicsGuard < casClientMutex > &, @@ -48,8 +49,8 @@ private: }; inline channelDestroyEvent::channelDestroyEvent ( - casChannelI & chanIn, bool uninstallNeededIn ) : - chan ( chanIn ), uninstallNeeded ( uninstallNeededIn ) + casChannelI * pChanIn, ca_uint32_t sidIn ) : + pChan ( pChanIn ), sid ( sidIn ) { }