From 2015e37f53cf173f57027c8cfca7d43905eb7184 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 4 Oct 2001 17:47:07 +0000 Subject: [PATCH] fixed problems where lock was released but channel was inconsistently attached to an IIU --- src/ca/cac.cpp | 105 ++++++++++++++++++++++++---------------------- src/ca/cac.h | 2 + src/ca/netiiu.cpp | 14 ------- src/ca/netiiu.h | 9 +++- 4 files changed, 63 insertions(+), 67 deletions(-) diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp index 6c8f14e20..61f59baf1 100644 --- a/src/ca/cac.cpp +++ b/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 pNetIO = chan.cacPrivateListOfIO::eventq.firstIter(); while ( pNetIO.valid() ) { tsDLIterBD 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 (); diff --git a/src/ca/cac.h b/src/ca/cac.h index 0d42e20e9..c32219bf4 100644 --- a/src/ca/cac.h +++ b/src/ca/cac.h @@ -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 ); diff --git a/src/ca/netiiu.cpp b/src/ca/netiiu.cpp index 767f68f07..d2f37af68 100644 --- a/src/ca/netiiu.cpp +++ b/src/ca/netiiu.cpp @@ -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 (); diff --git a/src/ca/netiiu.h b/src/ca/netiiu.h index 4f69cca08..3a7918b96 100644 --- a/src/ca/netiiu.h +++ b/src/ca/netiiu.h @@ -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