fixed problems where lock was released but channel was
inconsistently attached to an IIU
This commit is contained in:
105
src/ca/cac.cpp
105
src/ca/cac.cpp
@@ -270,17 +270,10 @@ cac::~cac ()
|
||||
freeListCleanup ( this->tcpLargeRecvBufFreeList );
|
||||
|
||||
{
|
||||
epicsAutoMutex autoMutex ( this->mutex );
|
||||
epicsAutoMutex autoMutexCB ( this->callbackMutex );
|
||||
epicsAutoMutex autoMutexCAC ( this->mutex );
|
||||
if ( this->pudpiiu ) {
|
||||
tsDLList < nciu > tmpList;
|
||||
this->pudpiiu->uninstallAllChan ( tmpList );
|
||||
while ( nciu *pChan = tmpList.get () ) {
|
||||
this->disconnectAllIO ( *pChan, false );
|
||||
pChan->disconnect ( limboIIU );
|
||||
// no need to call disconnect notify or
|
||||
// access rights notify here
|
||||
limboIIU.attachChannel ( *pChan );
|
||||
}
|
||||
this->removeAllChan ( *this->pudpiiu );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +294,21 @@ cac::~cac ()
|
||||
this->timerQueue.release ();
|
||||
}
|
||||
|
||||
// must have callback lock and also cac lock
|
||||
void cac::removeAllChan ( netiiu & srcIIU, netiiu *pDstIIU )
|
||||
{
|
||||
// we are protected here because channel delete takes the callback mutex
|
||||
while ( nciu *pChan = srcIIU.firstChannel() ) {
|
||||
// if the claim reply has not returned then we will issue
|
||||
// the clear channel request to the server when the claim reply
|
||||
// arrives and there is no matching nciu in the client
|
||||
if ( pChan->connected() ) {
|
||||
srcIIU.clearChannelRequest ( pChan->getSID(), pChan->getCID() );
|
||||
}
|
||||
this->disconnectChannelPrivate ( *pChan, pDstIIU );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned cac::lowestPriorityLevelAbove ( unsigned priority )
|
||||
{
|
||||
unsigned abovePriority;
|
||||
@@ -857,7 +865,7 @@ void cac::uninstallChannelPrivate ( nciu & chan )
|
||||
// flush prior to taking the callback lock
|
||||
this->flushIfRequired ( *chan.getPIIU() );
|
||||
// if the claim reply has not returned yet then we will issue
|
||||
// the clear chhannel request to the server when the claim reply
|
||||
// the clear channel request to the server when the claim reply
|
||||
// arrives and there is no matching nciu in the client
|
||||
if ( pChan->connected() ) {
|
||||
chan.getPIIU()->clearChannelRequest ( chan.getSID(), chan.getCID() );
|
||||
@@ -1179,27 +1187,26 @@ void cac::connectAllIO ( nciu & chan )
|
||||
}
|
||||
|
||||
// cancel IO operations and monitor subscriptions
|
||||
// (lock must be applied here)
|
||||
// -- callback lock and cac lock must be applied here
|
||||
void cac::disconnectAllIO ( nciu & chan, bool enableCallbacks )
|
||||
{
|
||||
tsDLIterBD<baseNMIU> pNetIO = chan.cacPrivateListOfIO::eventq.firstIter();
|
||||
while ( pNetIO.valid() ) {
|
||||
tsDLIterBD<baseNMIU> pNext = pNetIO;
|
||||
pNext++;
|
||||
bool isSubscr = pNetIO->isSubscription() ? true : false;
|
||||
if ( ! isSubscr ) {
|
||||
if ( ! pNetIO->isSubscription() ) {
|
||||
// no use after disconnected - so uninstall it
|
||||
this->ioTable.remove ( *pNetIO );
|
||||
chan.cacPrivateListOfIO::eventq.remove ( *pNetIO );
|
||||
}
|
||||
if ( enableCallbacks ) {
|
||||
epicsAutoMutexRelease unlocker ( this->mutex );
|
||||
char buf[128];
|
||||
sprintf ( buf, "host = %100s", chan.pHostName() );
|
||||
// callbacks are locked at a higher level
|
||||
sprintf ( buf, "host = %*s",
|
||||
sizeof(buf)-1, chan.pHostName() );
|
||||
epicsAutoMutexRelease unlocker ( this->mutex );
|
||||
pNetIO->exception ( ECA_DISCONN, buf );
|
||||
}
|
||||
if ( ! isSubscr ) {
|
||||
if ( ! pNetIO->isSubscription() ) {
|
||||
pNetIO->destroy ( *this );
|
||||
}
|
||||
pNetIO = pNext;
|
||||
@@ -1557,29 +1564,36 @@ bool cac::claimCIURespAction ( tcpiiu & iiu,
|
||||
bool cac::verifyAndDisconnectChan ( tcpiiu & /* iiu */,
|
||||
const caHdrLargeArray & hdr, void * /* pMsgBdy */ )
|
||||
{
|
||||
nciu * pChan;
|
||||
|
||||
{
|
||||
epicsAutoMutex autoMutex ( this->mutex );
|
||||
pChan = this->chanTable.lookup ( hdr.m_cid );
|
||||
if ( ! pChan ) {
|
||||
return true;
|
||||
}
|
||||
this->disconnectAllIO ( *pChan, true );
|
||||
pChan->disconnect ( limboIIU );
|
||||
{
|
||||
epicsAutoMutexRelease autoMutexRelease ( this->mutex );
|
||||
pChan->connectStateNotify ();
|
||||
pChan->accessRightsNotify ();
|
||||
}
|
||||
pChan->disconnect ( *this->pudpiiu );
|
||||
this->pudpiiu->attachChannel ( *pChan );
|
||||
this->pSearchTmr->resetPeriod ( 0.0 );
|
||||
epicsAutoMutex autoMutex ( this->mutex );
|
||||
nciu * pChan = this->chanTable.lookup ( hdr.m_cid );
|
||||
if ( ! pChan ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
assert ( this->pudpiiu );
|
||||
this->disconnectChannelPrivate ( *pChan, this->pudpiiu );
|
||||
this->pSearchTmr->resetPeriod ( 0.0 );
|
||||
return true;
|
||||
}
|
||||
|
||||
// callback lock and cac lock must be applied
|
||||
void cac::disconnectChannelPrivate ( nciu & chan, netiiu *pDstIIU )
|
||||
{
|
||||
this->disconnectAllIO ( chan, true );
|
||||
chan.getPIIU()->detachChannel ( chan );
|
||||
chan.disconnect ( limboIIU );
|
||||
limboIIU.attachChannel ( chan );
|
||||
if ( pDstIIU ) {
|
||||
epicsAutoMutexRelease autoMutexRelease ( this->mutex );
|
||||
chan.connectStateNotify ();
|
||||
chan.accessRightsNotify ();
|
||||
}
|
||||
if ( pDstIIU ) {
|
||||
limboIIU.detachChannel ( chan );
|
||||
chan.disconnect ( *pDstIIU );
|
||||
pDstIIU->attachChannel ( chan );
|
||||
}
|
||||
}
|
||||
|
||||
bool cac::badTCPRespAction ( tcpiiu & iiu,
|
||||
const caHdrLargeArray & hdr, void * /* pMsgBdy */ )
|
||||
{
|
||||
@@ -1751,7 +1765,8 @@ void cac::notifyDestroyFD ( SOCKET sock ) const
|
||||
|
||||
void cac::uninstallIIU ( tcpiiu & iiu )
|
||||
{
|
||||
epicsAutoMutex autoMutex ( this->mutex );
|
||||
epicsAutoMutex autoMutexCB ( this->callbackMutex );
|
||||
epicsAutoMutex autoMutexCAC ( this->mutex );
|
||||
if ( iiu.channelCount() ) {
|
||||
char hostNameTmp[64];
|
||||
iiu.hostName ( hostNameTmp, sizeof ( hostNameTmp ) );
|
||||
@@ -1771,19 +1786,7 @@ void cac::uninstallIIU ( tcpiiu & iiu )
|
||||
this->serverTable.remove ( iiu );
|
||||
|
||||
assert ( this->pudpiiu );
|
||||
tsDLList < nciu > tmpList;
|
||||
iiu.uninstallAllChan ( tmpList );
|
||||
while ( nciu *pChan = tmpList.get () ) {
|
||||
this->disconnectAllIO ( *pChan, true );
|
||||
pChan->disconnect ( limboIIU );
|
||||
{
|
||||
epicsAutoMutexRelease autoMutexRelease ( this->mutex );
|
||||
pChan->connectStateNotify ();
|
||||
pChan->accessRightsNotify ();
|
||||
}
|
||||
pChan->disconnect ( *this->pudpiiu );
|
||||
this->pudpiiu->attachChannel ( *pChan );
|
||||
}
|
||||
this->removeAllChan ( iiu, this->pudpiiu );
|
||||
|
||||
iiu.destroy ();
|
||||
|
||||
|
||||
@@ -206,6 +206,8 @@ private:
|
||||
void recycleSubscription ( netSubscription &io );
|
||||
void preemptiveCallbackLock ();
|
||||
void preemptiveCallbackUnlock ();
|
||||
void removeAllChan ( netiiu & srcIIU, netiiu * pDstIIU = 0 );
|
||||
void disconnectChannelPrivate ( nciu & chan, netiiu *pDstIIU );
|
||||
|
||||
void ioCompletionNotify ( unsigned id, unsigned type,
|
||||
arrayElementCount count, const void *pData );
|
||||
|
||||
@@ -43,20 +43,6 @@ void netiiu::show ( unsigned level ) const
|
||||
}
|
||||
}
|
||||
|
||||
// cac lock must also be applied when calling this
|
||||
void netiiu::uninstallAllChan ( tsDLList < nciu > & dstList )
|
||||
{
|
||||
while ( nciu *pChan = this->channelList.get () ) {
|
||||
// if the claim reply has not returned yet then we will issue
|
||||
// the clear chhannel request to the server when the claim reply
|
||||
// arrives and there is no matching nciu in the client
|
||||
if ( pChan->connected() ) {
|
||||
this->clearChannelRequest ( pChan->getSID(), pChan->getCID() );
|
||||
}
|
||||
dstList.add ( *pChan );
|
||||
}
|
||||
}
|
||||
|
||||
void netiiu::connectTimeoutNotify ()
|
||||
{
|
||||
tsDLIterBD < nciu > chan = this->channelList.firstIter ();
|
||||
|
||||
@@ -35,12 +35,12 @@ public:
|
||||
virtual ~netiiu ();
|
||||
void show ( unsigned level ) const;
|
||||
unsigned channelCount () const;
|
||||
void uninstallAllChan ( tsDLList < nciu > & dstList );
|
||||
void connectTimeoutNotify ();
|
||||
bool searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisChannel );
|
||||
void resetChannelRetryCounts ();
|
||||
void attachChannel ( nciu &chan );
|
||||
void detachChannel ( nciu &chan );
|
||||
nciu * firstChannel ();
|
||||
int printf ( const char *pformat, ... );
|
||||
virtual void hostName (char *pBuf, unsigned bufLength) const;
|
||||
virtual const char * pHostName () const; // deprecated - please do not use
|
||||
@@ -92,7 +92,7 @@ inline void netiiu::attachChannel ( class nciu &chan )
|
||||
}
|
||||
|
||||
// cac lock must also be applied when calling this
|
||||
inline void netiiu::detachChannel ( class nciu &chan )
|
||||
inline void netiiu::detachChannel ( class nciu & chan )
|
||||
{
|
||||
this->channelList.remove ( chan );
|
||||
if ( this->channelList.count () == 0u ) {
|
||||
@@ -100,4 +100,9 @@ inline void netiiu::detachChannel ( class nciu &chan )
|
||||
}
|
||||
}
|
||||
|
||||
inline nciu * netiiu::firstChannel ()
|
||||
{
|
||||
return this->channelList.first ();
|
||||
}
|
||||
|
||||
#endif // netiiuh
|
||||
|
||||
Reference in New Issue
Block a user