diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp index 0317f2145..8a756c746 100644 --- a/src/ca/cac.cpp +++ b/src/ca/cac.cpp @@ -333,6 +333,12 @@ cac::~cac () this->ipToAEngine.release (); + // clean-up the list of un-notified msg objects + while ( msgForMultiplyDefinedPV * msg = this->msgMultiPVList.get() ) { + msg->~msgForMultiplyDefinedPV (); + this->mdpvFreeList.release ( msg ); + } + errlogFlush (); osiSockRelease (); @@ -606,6 +612,8 @@ void cac::transferChanToVirtCircuit ( msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList ) msgForMultiplyDefinedPV ( this->ipToAEngine, *this, pChan->pName ( guard ), acc ); + // cac keeps a list of these objects for proper clean-up in ~cac + this->msgMultiPVList.add ( *pMsg ); // It is possible for the ioInitiate call below to // call the callback directly if queue quota is exceeded. // This callback takes the callback lock and therefore we @@ -1297,6 +1305,8 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, epicsGuard < epicsMutex > guard ( this->mutex ); this->exception ( mgr.cbGuard, guard, ECA_DBLCHNL, buf, __FILE__, __LINE__ ); } + // remove from the list and delete msg object + this->msgMultiPVList.remove ( mfmdpv ); mfmdpv.~msgForMultiplyDefinedPV (); this->mdpvFreeList.release ( & mfmdpv ); } diff --git a/src/ca/cac.h b/src/ca/cac.h index 63acccb6f..96cb19a78 100644 --- a/src/ca/cac.h +++ b/src/ca/cac.h @@ -237,6 +237,7 @@ private: resTable < tcpiiu, caServerID > serverTable; tsDLList < tcpiiu > circuitList; tsDLList < SearchDest > searchDestList; + tsDLList < msgForMultiplyDefinedPV > msgMultiPVList; tsFreeList < class tcpiiu, 32, epicsMutexNOOP > freeListVirtualCircuit; diff --git a/src/ca/msgForMultiplyDefinedPV.cpp b/src/ca/msgForMultiplyDefinedPV.cpp index 2f1a45cde..7002dd4b9 100644 --- a/src/ca/msgForMultiplyDefinedPV.cpp +++ b/src/ca/msgForMultiplyDefinedPV.cpp @@ -55,8 +55,10 @@ msgForMultiplyDefinedPV::~msgForMultiplyDefinedPV () void msgForMultiplyDefinedPV::transactionComplete ( const char * pHostNameRej ) { + // calls into cac for the notification + // the msg object (= this) is being deleted as part of the notification this->cb.pvMultiplyDefinedNotify ( *this, this->channel, this->acc, pHostNameRej ); - // !! dont touch this pointer after this point because object has been deleted !! + // !! dont touch 'this' pointer after this point because object has been deleted !! } void * msgForMultiplyDefinedPV::operator new ( size_t size, diff --git a/src/ca/msgForMultiplyDefinedPV.h b/src/ca/msgForMultiplyDefinedPV.h index 45d3453ac..3f1e771c0 100644 --- a/src/ca/msgForMultiplyDefinedPV.h +++ b/src/ca/msgForMultiplyDefinedPV.h @@ -33,6 +33,7 @@ #include "ipAddrToAsciiAsynchronous.h" #include "tsFreeList.h" +#include "tsDLList.h" #include "compilerDependencies.h" #ifdef msgForMultiplyDefinedPVh_epicsExportSharedSymbols @@ -47,7 +48,9 @@ public: const char * pAcc, const char * pRej ) = 0; }; -class msgForMultiplyDefinedPV : public ipAddrToAsciiCallBack { +class msgForMultiplyDefinedPV : + public ipAddrToAsciiCallBack, + public tsDLNode < msgForMultiplyDefinedPV > { public: msgForMultiplyDefinedPV ( ipAddrToAsciiEngine & engine, callbackForMultiplyDefinedPV &, const char * pChannelName, @@ -62,8 +65,8 @@ private: ipAddrToAsciiTransaction & dnsTransaction; callbackForMultiplyDefinedPV & cb; void transactionComplete ( const char * pHostName ); - msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & ); - msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & ); + msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & ); + msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & ); void operator delete ( void * ); }; diff --git a/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp b/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp index 09742e8a3..6dbdc405e 100644 --- a/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp +++ b/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp @@ -264,12 +264,16 @@ void ipAddrToAsciiEnginePrivate::run () continue; } + // fix for lp:1580623 + // a destructing cac sets pCurrent to NULL, so + // make local copy to avoid race when releasing the guard + ipAddrToAsciiTransactionPrivate *pCur = this->pCurrent; this->callbackInProgress = true; { epicsGuardRelease < epicsMutex > unguard ( guard ); // dont call callback with lock applied - this->pCurrent->pCB->transactionComplete ( this->nameTmp ); + pCur->pCB->transactionComplete ( this->nameTmp ); } this->callbackInProgress = false;