diff --git a/src/ca/CASG.cpp b/src/ca/CASG.cpp index 0c26d87f0..85fbfecbd 100644 --- a/src/ca/CASG.cpp +++ b/src/ca/CASG.cpp @@ -38,10 +38,12 @@ CASG::~CASG () { } -void CASG::destructor ( epicsGuard < epicsMutex > & guard ) +void CASG::destructor ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) { if ( this->verify ( guard ) ) { - this->reset ( guard ); + this->reset ( cbGuard, guard ); this->client.uninstallCASG ( guard, *this ); this->magic = 0; } @@ -59,7 +61,10 @@ bool CASG::verify ( epicsGuard < epicsMutex > & ) const /* * CASG::block () */ -int CASG::block ( epicsGuard < epicsMutex > & guard, double timeout ) +int CASG::block ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, + double timeout ) { epicsTime cur_time; epicsTime beg_time; @@ -102,8 +107,8 @@ int CASG::block ( epicsGuard < epicsMutex > & guard, double timeout ) { epicsGuardRelease < epicsMutex > unguard ( guard ); - this->client.blockForEventAndEnableCallbacks ( - this->sem, remaining ); + epicsGuardRelease < epicsMutex > uncbGuard ( cbGuard ); + this->sem.wait ( remaining ); } /* @@ -114,16 +119,17 @@ int CASG::block ( epicsGuard < epicsMutex > & guard, double timeout ) delay = cur_time - beg_time; } - this->reset ( guard ); + this->reset ( cbGuard, guard ); return status; } void CASG::reset ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { this->destroyCompletedIO ( guard ); - this->destroyPendingIO ( guard ); + this->destroyPendingIO ( cbGuard, guard ); } // lock must be applied @@ -136,13 +142,23 @@ void CASG::destroyCompletedIO ( } } -// lock must be applied void CASG::destroyPendingIO ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { - syncGroupNotify *pNotify; - while ( ( pNotify = this->ioPendingList.get () ) ) { - pNotify->destroy ( guard, * this ); + syncGroupNotify * pNotify; + while ( ( pNotify = this->ioPendingList.first () ) ) { + pNotify->cancel ( cbGuard, guard ); + // cancel must release the guard while + // canceling put callbacks so we + // must double check list membership + if ( pNotify->ioPending ( guard ) ) { + this->ioPendingList.remove ( *pNotify ); + } + else { + this->ioCompletedList.remove ( *pNotify ); + } + pNotify->destroy ( guard, *this ); } } @@ -176,6 +192,7 @@ void CASG::show ( } bool CASG::ioComplete ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { this->destroyCompletedIO ( guard ); @@ -185,17 +202,9 @@ bool CASG::ioComplete ( void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan, unsigned type, arrayElementCount count, const void * pValue ) { - sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this ); - { - pNotify = syncGroupWriteNotify::factory ( - this->freeListWriteOP, *this, pChan ); - if ( pNotify.get () ) { - this->ioPendingList.add ( *pNotify ); - } - else { - return; - } - } + sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this, this->ioPendingList ); + pNotify = syncGroupWriteNotify::factory ( + this->freeListWriteOP, *this, pChan ); pNotify->begin ( guard, type, count, pValue ); pNotify.release (); } @@ -203,30 +212,13 @@ void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan, void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan, unsigned type, arrayElementCount count, void *pValue ) { - sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this ); - { - pNotify = syncGroupReadNotify::factory ( - this->freeListReadOP, *this, pChan, pValue ); - if ( pNotify.get () ) { - this->ioPendingList.add ( *pNotify ); - } - else { - return; - } - } + sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this, this->ioPendingList ); + pNotify = syncGroupReadNotify::factory ( + this->freeListReadOP, *this, pChan, pValue ); pNotify->begin ( guard, type, count ); pNotify.release (); } -void CASG::destroyPendingIO ( - epicsGuard < epicsMutex > & guard, syncGroupNotify * pNotify ) -{ - if ( pNotify ) { - this->ioPendingList.remove ( *pNotify ); - pNotify->destroy ( guard, *this ); - } -} - void CASG::completionNotify ( epicsGuard < epicsMutex > & guard, syncGroupNotify & notify ) { diff --git a/src/ca/access.cpp b/src/ca/access.cpp index 6b956a89e..b75b0280a 100644 --- a/src/ca/access.cpp +++ b/src/ca/access.cpp @@ -687,11 +687,11 @@ int epicsShareAPI ca_create_subscription ( new ( pChan->getClientCtx().subscriptionFreeList ) oldSubscription ( *pChan, pCallBack, pCallBackArg ) ); - evid pTmp = pSubsr.release (); + pSubsr->begin ( guard, tmpType, count, mask ); if ( monixptr ) { - *monixptr = pTmp; + *monixptr = pSubsr.get (); } - pTmp->begin ( guard, tmpType, count, mask ); + pSubsr.release (); // dont touch pTmp after this because // the first callback might have canceled it return ECA_NORMAL; @@ -746,8 +746,15 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon ) { oldChannelNotify & chan = pMon->channel (); ca_client_context & cac = chan.getClientCtx (); - epicsGuard < epicsMutex > guard ( cac.mutex ); - pMon->ioCancel ( guard ); + if ( cac.pCallbackGuard.get() ) { + epicsGuard < epicsMutex > guard ( cac.mutex ); + pMon->ioCancel ( *cac.pCallbackGuard, guard ); + } + else { + epicsGuard < epicsMutex > cbGuard ( cac.cbMutex ); + epicsGuard < epicsMutex > guard ( cac.mutex ); + pMon->ioCancel ( cbGuard, guard ); + } return ECA_NORMAL; } diff --git a/src/ca/acctst.c b/src/ca/acctst.c index b2b98c049..cfacc81e9 100644 --- a/src/ca/acctst.c +++ b/src/ca/acctst.c @@ -2444,6 +2444,8 @@ void verifyImmediateTearDown ( const char * pName, } status = ca_put ( DBR_LONG, chan, & value ); SEVCHK ( status, "immediate tear down channel put failed" ); + status = ca_clear_channel ( chan ); + SEVCHK ( status, "immediate tear down channel clear failed" ); ca_task_exit (); epicsThreadSleep ( 1e-15 ); if ( i % 100 == 0 ) { diff --git a/src/ca/ca_client_context.cpp b/src/ca/ca_client_context.cpp index f2d6bf3bf..1c66719c7 100644 --- a/src/ca/ca_client_context.cpp +++ b/src/ca/ca_client_context.cpp @@ -36,6 +36,23 @@ #include "oldAccess.h" #include "cac.h" +epicsShareDef epicsThreadPrivateId caClientCallbackThreadId; + +static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT; + +extern "C" void cacExitHandler () +{ + epicsThreadPrivateDelete ( caClientCallbackThreadId ); +} + +// runs once only for each process +extern "C" void cacOnceFunc ( void * ) +{ + caClientCallbackThreadId = epicsThreadPrivateCreate (); + assert ( caClientCallbackThreadId ); + atexit ( cacExitHandler ); +} + extern epicsThreadPrivateId caClientContextId; cacService * ca_client_context::pDefaultService = 0; @@ -54,15 +71,18 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : throwWithLocation ( noSocket () ); } + epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 ); + { // this wont consistently work if called from file scope constructor epicsGuard < epicsMutex > guard ( ca_client_context::defaultServiceInstallMutex ); if ( ca_client_context::pDefaultService ) { this->pServiceContext.reset ( - & ca_client_context::pDefaultService->contextCreate ( this->mutex, *this ) ); + & ca_client_context::pDefaultService->contextCreate ( + this->mutex, this->cbMutex, *this ) ); } else { - this->pServiceContext.reset ( new cac ( this->mutex, *this ) ); + this->pServiceContext.reset ( new cac ( this->mutex, this->cbMutex, *this ) ); } } @@ -134,7 +154,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : epics_auto_ptr < epicsGuard < epicsMutex > > pCBGuard; if ( ! enablePreemptiveCallback ) { - pCBGuard.reset ( new epicsGuard < epicsMutex > ( this->callbackMutex ) ); + pCBGuard.reset ( new epicsGuard < epicsMutex > ( this->cbMutex ) ); } // multiple steps ensure exception safety @@ -167,9 +187,17 @@ ca_client_context::~ca_client_context () void ca_client_context::destroyChannel ( oldChannelNotify & chan ) { - epicsGuard < epicsMutex > guard ( this->mutex ); - chan.destructor ( guard ); - this->oldChannelNotifyFreeList.release ( & chan ); + if ( this->pCallbackGuard.get() ) { + epicsGuard < epicsMutex > guard ( this->mutex ); + chan.destructor ( *this->pCallbackGuard.get(), guard ); + this->oldChannelNotifyFreeList.release ( & chan ); + } + else { + epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); + epicsGuard < epicsMutex > guard ( this->mutex ); + chan.destructor ( cbGuard, guard ); + this->oldChannelNotifyFreeList.release ( & chan ); + } } void ca_client_context::destroyGetCopy ( @@ -578,9 +606,8 @@ void ca_client_context::blockForEventAndEnableCallbacks ( } } -void ca_client_context::callbackLock () +void ca_client_context::callbackProcessingInitiateNotify () { - // if preemptive callback is enabled then this is a noop if ( this->pCallbackGuard.get() ) { bool sendNeeded = false; @@ -604,14 +631,10 @@ void ca_client_context::callbackLock () 0, & tmpAddr.sa, sizeof ( tmpAddr.sa ) ); } } - - this->callbackMutex.lock (); } -void ca_client_context::callbackUnlock () +void ca_client_context::callbackProcessingCompleteNotify () { - this->callbackMutex.unlock (); - // if preemptive callback is enabled then this is a noop if ( this->pCallbackGuard.get() ) { bool signalNeeded = false; @@ -717,12 +740,12 @@ epicsMutex & ca_client_context::mutexRef () const return this->mutex; } -cacContext & ca_client_context::createNetworkContext ( epicsMutex & mutex ) +cacContext & ca_client_context::createNetworkContext ( + epicsMutex & mutex, epicsMutex & cbMutex ) { - return * new cac ( mutex, *this ); + return * new cac ( mutex, cbMutex, *this ); } - void epicsShareAPI caInstallDefaultService ( cacService & service ) { // this wont consistently work if called from file scope constructor diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp index d8aeaeb18..7777a5faf 100644 --- a/src/ca/cac.cpp +++ b/src/ca/cac.cpp @@ -22,6 +22,7 @@ #define epicsAssertAuthor "Jeff Hill johill@lanl.gov" #include +#include #include "epicsGuard.h" #include "epicsVersion.h" @@ -114,31 +115,17 @@ const cac::pExcepProtoStubTCP cac::tcpExcepJumpTableCAC [] = &cac::defaultExcep // CA_PROTO_SERVER_DISCONN }; -epicsThreadPrivateId caClientCallbackThreadId; - -static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT; - -extern "C" void cacExitHandler () -{ - epicsThreadPrivateDelete ( caClientCallbackThreadId ); -} - -// runs once only for each process -extern "C" void cacOnceFunc ( void * ) -{ - caClientCallbackThreadId = epicsThreadPrivateCreate (); - assert ( caClientCallbackThreadId ); - atexit ( cacExitHandler ); -} - // // cac::cac () // -cac::cac ( epicsMutex & mutexIn, cacContextNotify & notifyIn ) : +cac::cac ( + epicsMutex & mutualExclusionIn, + epicsMutex & callbackControlIn, + cacContextNotify & notifyIn ) : programBeginTime ( epicsTime::getCurrent() ), connTMO ( CA_CONN_VERIFY_PERIOD ), - cbMutex ( notifyIn ), - mutex ( mutexIn ), + mutex ( mutualExclusionIn ), + cbMutex ( callbackControlIn ), ipToAEngine ( ipAddrToAsciiEngine::allocate () ), timerQueue ( epicsTimerQueueActive::allocate ( false, lowestPriorityLevelAbove(epicsThreadGetPrioritySelf()) ) ), @@ -156,8 +143,6 @@ cac::cac ( epicsMutex & mutexIn, cacContextNotify & notifyIn ) : throwWithLocation ( caErrorCode (ECA_INTERNAL) ); } - epicsThreadOnce ( &cacOnce, cacOnceFunc, 0 ); - try { long status; @@ -187,8 +172,9 @@ cac::cac ( epicsMutex & mutexIn, cacContextNotify & notifyIn ) : status = envGetDoubleConfigParam ( &EPICS_CA_CONN_TMO, &this->connTMO ); if ( status ) { this->connTMO = CA_CONN_VERIFY_PERIOD; - this->printf ( "EPICS \"%s\" double fetch failed\n", EPICS_CA_CONN_TMO.name); - this->printf ( "Defaulting \"%s\" = %f\n", EPICS_CA_CONN_TMO.name, this->connTMO); + epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); + errlogPrintf ( "EPICS \"%s\" double fetch failed\n", EPICS_CA_CONN_TMO.name ); + errlogPrintf ( "Defaulting \"%s\" = %f\n", EPICS_CA_CONN_TMO.name, this->connTMO ); } long maxBytesAsALong; @@ -251,7 +237,7 @@ cac::~cac () // // shutdown all tcp circuits // - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); + epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); epicsGuard < epicsMutex > guard ( this->mutex ); tsDLIter < tcpiiu > iter = this->serverList.firstIter (); while ( iter.valid() ) { @@ -467,7 +453,8 @@ cacChannel & cac::createChannel ( if ( ! this->pudpiiu ) { this->pudpiiu = new udpiiu ( - this->timerQueue, this->cbMutex, *this ); + this->timerQueue, this->cbMutex, + this->mutex, this->notify, *this ); } nciu * pNetChan = new ( this->channelFreeList ) @@ -484,7 +471,7 @@ void cac::repeaterSubscribeConfirmNotify () } bool cac::transferChanToVirtCircuit ( - epicsGuard < callbackMutex > & cbGuard, unsigned cid, unsigned sid, // X aCC 431 + epicsGuard < epicsMutex > & cbGuard, unsigned cid, unsigned sid, // X aCC 431 ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber, const osiSockAddr & addr ) { @@ -535,10 +522,10 @@ bool cac::transferChanToVirtCircuit ( else { try { autoPtrFreeList < tcpiiu, 32, epicsMutexNOOP > pnewiiu ( - this->freeListVirtualCircuit, - new ( this->freeListVirtualCircuit ) tcpiiu ( - *this, this->cbMutex, this->connTMO, this->timerQueue, - addr, this->comBufMemMgr, minorVersionNumber, + this->freeListVirtualCircuit, + new ( this->freeListVirtualCircuit ) tcpiiu ( + *this, this->mutex, this->cbMutex, this->notify, this->connTMO, + this->timerQueue, addr, this->comBufMemMgr, minorVersionNumber, this->ipToAEngine, pChan->getPriority() ) ); bhe * pBHE = this->beaconTable.lookup ( addr.ia ); if ( ! pBHE ) { @@ -558,12 +545,13 @@ bool cac::transferChanToVirtCircuit ( return false; } catch ( ... ) { - this->printf ( "CAC: Unexpected exception during virtual circuit creation\n" ); + errlogPrintf ( + "CAC: Unexpected exception during virtual circuit creation\n" ); return false; } } - this->pudpiiu->uninstallChan ( guard, *pChan ); + this->pudpiiu->uninstallChan ( cbGuard, guard, *pChan ); piiu->installChannel ( cbGuard, guard, *pChan, sid, typeCode, count ); if ( ! piiu->ca_v42_ok () ) { @@ -580,48 +568,28 @@ bool cac::transferChanToVirtCircuit ( } void cac::destroyChannel ( - epicsGuard < epicsMutex > & guard, nciu & chan ) + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, + nciu & chan ) { guard.assertIdenticalMutex ( this->mutex ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); // uninstall channel so that recv threads // will not start a new callback for this channel's IO. if ( this->chanTable.remove ( chan ) != & chan ) { - errlogPrintf ( - "CAC: Attemt to uninstall unregisterred channel ID=%u ignored.\n", - chan.getId () ); - return; + throw std::logic_error ( "Invalid channel identifier" ); } - // if the claim reply has not returned yet 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 ( chan.connected ( guard ) ) { - chan.getPIIU()->clearChannelRequest ( - guard, chan.getSID(), chan.getCID() ); - } - - { - // reverse the lock order so that we dont botch the lock hierarchy - epicsGuardRelease < epicsMutex > unguard ( guard ); - { - // taking the callback mutex prior to deleting the channel - // guarantees that we will not delete a channel out from under a callback - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); - } - } - - // run channel's destructor and return it to the free list - chan.destructor ( guard ); - - // IIU must be valid until after IO is destroyed in the destructor - chan.getPIIU()->uninstallChan ( guard, chan ); + chan.getPIIU()->uninstallChan ( cbGuard, guard, chan ); + + chan.destructor ( cbGuard, guard ); this->channelFreeList.release ( & chan ); } void cac::disconnectAllIO ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, nciu & chan, tsDLList < baseNMIU > & ioList ) { @@ -643,17 +611,13 @@ void cac::disconnectAllIO ( } } -int cac::printf ( const char *pformat, ... ) const +int cac::printf ( epicsGuard < epicsMutex > & callbackControl, + const char *pformat, ... ) const { va_list theArgs; - int status; - va_start ( theArgs, pformat ); - - status = this->vPrintf ( pformat, theArgs ); - + int status = this->vPrintf ( callbackControl, pformat, theArgs ); va_end ( theArgs ); - return status; } @@ -720,10 +684,13 @@ netReadNotifyIO & cac::readNotifyRequest ( } baseNMIU * cac::destroyIO ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, const cacChannel::ioid & idIn, nciu & chan ) { + cbGuard.assertIdenticalMutex ( this->cbMutex ); guard.assertIdenticalMutex ( this->mutex ); + // unistall the IO object so that a receive thread will not find it, // but do _not_ hold the callback lock here because this could result // in deadlock @@ -735,19 +702,9 @@ baseNMIU * cac::destroyIO ( guard, chan, *pSubscr ); } - { - // reverse the lock order so that we dont botch the lock hierarchy - epicsGuardRelease < epicsMutex > unguard ( guard ); - { - // taking the callback mutex prior to deleting the IO and channel - // guarantees that we will not delete a channel out from under a callback - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); - epicsGuard < epicsMutex > tmpGuard ( this->mutexRef () ); - // this uninstalls from the list and destroys the IO - pIO->exception ( tmpGuard, *this, - ECA_CHANDESTROY, chan.pName() ); - } - } + // this uninstalls from the list and destroys the IO + pIO->exception ( guard, *this, + ECA_CHANDESTROY, chan.pName() ); } return pIO; } @@ -824,22 +781,22 @@ netSubscription & cac::subscriptionRequest ( return *pIO.release (); } -bool cac::versionAction ( epicsGuard < callbackMutex > &, tcpiiu &, +bool cac::versionAction ( callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray &, void * ) { return true; } bool cac::echoRespAction ( - epicsGuard < callbackMutex > & cbGuard, tcpiiu & iiu, + callbackManager & mgr, tcpiiu & iiu, const epicsTime & current, const caHdrLargeArray &, void * ) { - iiu.probeResponseNotify ( cbGuard, current ); + iiu.probeResponseNotify ( mgr.cbGuard, current ); return true; } bool cac::writeNotifyRespAction ( - epicsGuard < callbackMutex > &, tcpiiu &, + callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray & hdr, void * ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -856,7 +813,7 @@ bool cac::writeNotifyRespAction ( return true; } -bool cac::readNotifyRespAction ( epicsGuard < callbackMutex > &, tcpiiu & iiu, +bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) { /* @@ -913,7 +870,7 @@ bool cac::readNotifyRespAction ( epicsGuard < callbackMutex > &, tcpiiu & iiu, return true; } -bool cac::eventRespAction ( epicsGuard < callbackMutex > &, tcpiiu &iiu, +bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) { int caStatus; @@ -972,7 +929,7 @@ bool cac::eventRespAction ( epicsGuard < callbackMutex > &, tcpiiu &iiu, return true; } -bool cac::readRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, +bool cac::readRespAction ( callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -990,14 +947,14 @@ bool cac::readRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, return true; } -bool cac::clearChannelRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, +bool cac::clearChannelRespAction ( callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray &, void * /* pMsgBdy */ ) { return true; // currently a noop } bool cac::defaultExcep ( - epicsGuard < callbackMutex > &, tcpiiu & iiu, + callbackManager &, tcpiiu & iiu, const caHdrLargeArray &, const char * pCtx, unsigned status ) { char buf[512]; @@ -1012,16 +969,18 @@ bool cac::defaultExcep ( } void cac::exception ( - epicsGuard < callbackMutex > & cbGuard, int status, - const char *pContext, const char *pFileName, unsigned lineNo ) + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, int status, + const char * pContext, const char * pFileName, unsigned lineNo ) { - epicsGuard < epicsMutex > guard ( this->mutex ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); this->notify.exception ( guard, status, pContext, pFileName, lineNo ); } bool cac::eventAddExcep ( - epicsGuard < callbackMutex > &, tcpiiu & /* iiu */, + callbackManager &, tcpiiu & /* iiu */, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ) { @@ -1030,7 +989,7 @@ bool cac::eventAddExcep ( return true; } -bool cac::readExcep ( epicsGuard < callbackMutex > &, tcpiiu &, +bool cac::readExcep ( callbackManager &, tcpiiu &, const caHdrLargeArray & hdr, const char * pCtx, unsigned status ) { @@ -1040,20 +999,20 @@ bool cac::readExcep ( epicsGuard < callbackMutex > &, tcpiiu &, } bool cac::writeExcep ( - epicsGuard < callbackMutex > & cbGuard, // X aCC 431 + callbackManager & mgr, // X aCC 431 tcpiiu &, const caHdrLargeArray & hdr, const char * pCtx, unsigned status ) { epicsGuard < epicsMutex > guard ( this->mutex ); nciu * pChan = this->chanTable.lookup ( hdr.m_available ); if ( pChan ) { - pChan->writeException ( cbGuard, guard, status, pCtx, + pChan->writeException ( mgr.cbGuard, guard, status, pCtx, hdr.m_dataType, hdr.m_count ); } return true; } -bool cac::readNotifyExcep ( epicsGuard < callbackMutex > &, tcpiiu &, +bool cac::readNotifyExcep ( callbackManager &, tcpiiu &, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ) { @@ -1062,7 +1021,7 @@ bool cac::readNotifyExcep ( epicsGuard < callbackMutex > &, tcpiiu &, return true; } -bool cac::writeNotifyExcep ( epicsGuard < callbackMutex > &, tcpiiu &, +bool cac::writeNotifyExcep ( callbackManager &, tcpiiu &, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ) { @@ -1071,7 +1030,7 @@ bool cac::writeNotifyExcep ( epicsGuard < callbackMutex > &, tcpiiu &, return true; } -bool cac::exceptionRespAction ( epicsGuard < callbackMutex > & cbMutexIn, tcpiiu & iiu, +bool cac::exceptionRespAction ( callbackManager & cbMutexIn, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) { const caHdr * pReq = reinterpret_cast < const caHdr * > ( pMsgBdy ); @@ -1112,7 +1071,7 @@ bool cac::exceptionRespAction ( epicsGuard < callbackMutex > & cbMutexIn, tcpiiu } bool cac::accessRightsRespAction ( - epicsGuard < callbackMutex > & cbGuard, tcpiiu &, // X aCC 431 + callbackManager & mgr, tcpiiu &, // X aCC 431 const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBdy */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -1122,14 +1081,14 @@ bool cac::accessRightsRespAction ( caAccessRights accessRights ( ( ar & CA_PROTO_ACCESS_RIGHT_READ ) ? true : false, ( ar & CA_PROTO_ACCESS_RIGHT_WRITE ) ? true : false); - pChan->accessRightsStateChange ( accessRights, cbGuard, guard ); + pChan->accessRightsStateChange ( accessRights, mgr.cbGuard, guard ); } return true; } bool cac::createChannelRespAction ( - epicsGuard < callbackMutex > &cbGuard, tcpiiu & iiu, // X aCC 431 + callbackManager & mgr, tcpiiu & iiu, // X aCC 431 const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBdy */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -1144,7 +1103,7 @@ bool cac::createChannelRespAction ( } iiu.connectNotify ( guard, *pChan ); pChan->connect ( hdr.m_dataType, hdr.m_count, sidTmp, - cbGuard, guard ); + mgr.cbGuard, guard ); } else if ( iiu.ca_v44_ok() ) { // this indicates a claim response for a resource that does @@ -1156,7 +1115,7 @@ bool cac::createChannelRespAction ( } bool cac::verifyAndDisconnectChan ( - epicsGuard < callbackMutex > & cbGuard, tcpiiu & /* iiu */, + callbackManager & mgr, tcpiiu & /* iiu */, const epicsTime & currentTime, const caHdrLargeArray & hdr, void * /* pMsgBdy */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -1164,35 +1123,35 @@ bool cac::verifyAndDisconnectChan ( if ( ! pChan ) { return true; } - this->disconnectChannel ( currentTime, cbGuard, guard, *pChan ); + this->disconnectChannel ( currentTime, mgr.cbGuard, guard, *pChan ); return true; } void cac::disconnectChannel ( const epicsTime & currentTime, - epicsGuard < callbackMutex > & cbGuard, // X aCC 431 + epicsGuard < epicsMutex > & cbGuard, // X aCC 431 epicsGuard < epicsMutex > & guard, nciu & chan ) { guard.assertIdenticalMutex ( this->mutex ); assert ( this->pudpiiu ); chan.disconnectAllIO ( cbGuard, guard ); - chan.getPIIU()->uninstallChan ( guard, chan ); + chan.getPIIU()->uninstallChan ( cbGuard, guard, chan ); this->pudpiiu->installDisconnectedChannel ( chan ); chan.setServerAddressUnknown ( *this->pudpiiu, guard ); chan.unresponsiveCircuitNotify ( cbGuard, guard ); } -bool cac::badTCPRespAction ( epicsGuard < callbackMutex > &, tcpiiu & iiu, +bool cac::badTCPRespAction ( callbackManager &, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBdy */ ) { char hostName[64]; iiu.hostName ( hostName, sizeof ( hostName ) ); - this->printf ( "CAC: Undecipherable TCP message ( bad response type %u ) from %s\n", + errlogPrintf ( "CAC: Undecipherable TCP message ( bad response type %u ) from %s\n", hdr.m_cmmd, hostName ); return false; } -bool cac::executeResponse ( epicsGuard < callbackMutex > & cbLocker, tcpiiu & iiu, +bool cac::executeResponse ( callbackManager & mgr, tcpiiu & iiu, const epicsTime & currentTime, caHdrLargeArray & hdr, char * pMshBody ) { // execute the response message @@ -1203,7 +1162,7 @@ bool cac::executeResponse ( epicsGuard < callbackMutex > & cbLocker, tcpiiu & ii else { pStub = cac::tcpJumpTableCAC [hdr.m_cmmd]; } - return ( this->*pStub ) ( cbLocker, iiu, currentTime, hdr, pMshBody ); + return ( this->*pStub ) ( mgr, iiu, currentTime, hdr, pMshBody ); } void cac::selfTest ( @@ -1215,46 +1174,15 @@ void cac::selfTest ( this->beaconTable.verify (); } -void cac::initiateAbortShutdown ( tcpiiu & iiu ) -{ - int exception = ECA_DISCONN; - char hostNameTmp[64]; - bool exceptionNeeded = false; - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); - { - epicsGuard < epicsMutex > guard ( this->mutex ); - - if ( iiu.channelCount( cbGuard ) ) { - iiu.hostName ( hostNameTmp, sizeof ( hostNameTmp ) ); - if ( iiu.connecting () ) { - exception = ECA_CONNSEQTMO; - } - exceptionNeeded = true; - } - - iiu.initiateAbortShutdown ( cbGuard, guard ); - - // Disconnect all channels immediately from the timer thread - // because on certain OS such as HPUX it's difficult to - // unblock a blocking send() call, and we need immediate - // disconnect notification. - iiu.removeAllChannels ( cbGuard, guard, *this->pudpiiu ); - } - - if ( exceptionNeeded ) { - genLocalExcep ( cbGuard, *this, exception, hostNameTmp ); - } -} - void cac::destroyIIU ( tcpiiu & iiu ) { { - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); + epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); epicsGuard < epicsMutex > guard ( this->mutex ); - if ( iiu.channelCount ( cbGuard ) ) { + if ( iiu.channelCount ( guard ) ) { char hostNameTmp[64]; iiu.hostName ( hostNameTmp, sizeof ( hostNameTmp ) ); - genLocalExcep ( cbGuard, *this, ECA_DISCONN, hostNameTmp ); + genLocalExcep ( cbGuard, guard, *this, ECA_DISCONN, hostNameTmp ); } osiSockAddr addr = iiu.getNetworkAddress(); if ( addr.sa.sa_family == AF_INET ) { @@ -1331,8 +1259,9 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, sprintf ( buf, "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s", pChannelName, pAcc, pRej ); { - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); - this->exception ( cbGuard, ECA_DBLCHNL, buf, __FILE__, __LINE__ ); + callbackManager mgr ( this->notify, this->cbMutex ); + epicsGuard < epicsMutex > guard ( this->mutex ); + this->exception ( mgr.cbGuard, guard, ECA_DBLCHNL, buf, __FILE__, __LINE__ ); } mfmdpv.~msgForMultiplyDefinedPV (); this->mdpvFreeList.release ( & mfmdpv ); diff --git a/src/ca/cac.h b/src/ca/cac.h index f55262080..bed44185e 100644 --- a/src/ca/cac.h +++ b/src/ca/cac.h @@ -73,8 +73,6 @@ class inetAddrID; class caServerID; struct caHdrLargeArray; -extern epicsThreadPrivateId caClientCallbackThreadId; - class cacComBufMemoryManager : public comBufMemoryManager { public: @@ -88,20 +86,24 @@ class cacDisconnectChannelPrivate { // X aCC 655 public: virtual void disconnectChannel ( const epicsTime & currentTime, - epicsGuard < callbackMutex > &, - epicsGuard < epicsMutex > &, nciu & chan ) = 0; + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, nciu & chan ) = 0; }; -class callbackMutex { +class notifyGuard { public: - callbackMutex ( cacContextNotify & ); - ~callbackMutex (); - void lock (); - void unlock (); + notifyGuard ( cacContextNotify & ); + ~notifyGuard (); private: cacContextNotify & notify; - callbackMutex ( callbackMutex & ); - callbackMutex & operator = ( callbackMutex & ); +}; + +class callbackManager : public notifyGuard { +public: + callbackManager ( + cacContextNotify &, + epicsMutex & callbackControl ); + epicsGuard < epicsMutex > cbGuard; }; class cac : @@ -111,7 +113,10 @@ class cac : private callbackForMultiplyDefinedPV { public: - cac ( epicsMutex &, cacContextNotify & ); + cac ( + epicsMutex & mutualExclusion, + epicsMutex & callbackControl, + cacContextNotify & ); virtual ~cac (); // beacon management @@ -123,20 +128,26 @@ public: // IO management void flush ( epicsGuard < epicsMutex > & guard ); - bool executeResponse ( epicsGuard < callbackMutex > &, tcpiiu &, + bool executeResponse ( callbackManager &, tcpiiu &, const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody ); // channel routines bool transferChanToVirtCircuit ( - epicsGuard < callbackMutex > &, + epicsGuard < epicsMutex > &, unsigned cid, unsigned sid, ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber, const osiSockAddr & ); + void disconnectAllChannels ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + tcpiiu & ); cacChannel & createChannel ( epicsGuard < epicsMutex > & guard, const char * pChannelName, cacChannelNotify &, cacChannel::priLev ); void destroyChannel ( - epicsGuard < epicsMutex > &, nciu & ); + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + nciu & ); void initiateConnect ( epicsGuard < epicsMutex > &, nciu & ); @@ -156,12 +167,13 @@ public: unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify & ); baseNMIU * destroyIO ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, const cacChannel::ioid & idIn, nciu & chan ); void disconnectAllIO ( - epicsGuard < callbackMutex > &, - epicsGuard < epicsMutex > &, + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, nciu &, tsDLList < baseNMIU > & ioList ); void ioShow ( const cacChannel::ioid &id, unsigned level ) const; @@ -172,15 +184,19 @@ public: void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & ); // exception generation - void exception ( epicsGuard < callbackMutex > &, + void exception ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, int status, const char * pContext, const char * pFileName, unsigned lineNo ); // diagnostics unsigned circuitCount ( epicsGuard < epicsMutex > & ) const; void show ( epicsGuard < epicsMutex > &, unsigned level ) const; - int printf ( const char *pformat, ... ) const; - int vPrintf ( const char *pformat, va_list args ) const; + int printf ( epicsGuard < epicsMutex > & callbackControl, + const char *pformat, ... ) const; + int vPrintf ( epicsGuard < epicsMutex > & callbackControl, + const char *pformat, va_list args ) const; // buffer management char * allocateSmallBufferTCP (); @@ -198,7 +214,6 @@ public: double beaconPeriod ( const nciu & chan ) const; static unsigned lowestPriorityLevelAbove ( unsigned priority ); static unsigned highestPriorityLevelBelow ( unsigned priority ); - void initiateAbortShutdown ( tcpiiu & ); void destroyIIU ( tcpiiu & iiu ); void flushIfRequired ( epicsGuard < epicsMutex > &, netiiu & ); @@ -246,8 +261,8 @@ private: // **** lock hierarchy **** // callback lock must always be acquired before // the primary mutex if both locks are needed - callbackMutex cbMutex; mutable epicsMutex & mutex; + mutable epicsMutex & cbMutex; epicsEvent iiuUninstall; ipAddrToAsciiEngine & ipToAEngine; epicsTimerQueueActive & timerQueue; @@ -271,8 +286,8 @@ private: void disconnectChannel ( const epicsTime & currentTime, - epicsGuard < callbackMutex > &, - epicsGuard < epicsMutex > &, nciu & chan ); + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, nciu & chan ); void ioExceptionNotify ( unsigned id, int status, const char * pContext, unsigned type, arrayElementCount count ); @@ -283,52 +298,52 @@ private: const char * pChannelName, const char * pAcc, const char * pRej ); // recv protocol stubs - bool versionAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool versionAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool echoRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool echoRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool writeNotifyRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool writeNotifyRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool readNotifyRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool readNotifyRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool eventRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool eventRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool readRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool readRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool clearChannelRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool clearChannelRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool exceptionRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool exceptionRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool accessRightsRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool accessRightsRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool createChannelRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool createChannelRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool verifyAndDisconnectChan ( epicsGuard < callbackMutex > &, tcpiiu &, + bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool badTCPRespAction ( epicsGuard < callbackMutex > &, tcpiiu &, + bool badTCPRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); typedef bool ( cac::*pProtoStubTCP ) ( - epicsGuard < callbackMutex > &, tcpiiu &, + callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); static const pProtoStubTCP tcpJumpTableCAC []; - bool defaultExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool eventAddExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool readExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool writeExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool clearChanExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool readNotifyExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool writeNotifyExcep ( epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); typedef bool ( cac::*pExcepProtoStubTCP ) ( - epicsGuard < callbackMutex > &, tcpiiu &iiu, const caHdrLargeArray &hdr, + callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); static const pExcepProtoStubTCP tcpExcepJumpTableCAC []; @@ -351,8 +366,11 @@ inline epicsMutex & cac::mutexRef () return this->mutex; } -inline int cac::vPrintf ( const char *pformat, va_list args ) const +inline int cac::vPrintf ( + epicsGuard < epicsMutex > & callbackControl, + const char *pformat, va_list args ) const { + callbackControl.assertIdenticalMutex ( this->cbMutex ); return this->notify.vPrintf ( pformat, args ); } @@ -397,23 +415,31 @@ inline unsigned cac::beaconAnomaliesSinceProgramStart ( return this->beaconAnomalyCount; } -inline callbackMutex::callbackMutex ( cacContextNotify & notifyIn ) : +inline void cac::disconnectAllChannels ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, + tcpiiu & iiu ) +{ + cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); + iiu.removeAllChannels ( cbGuard, guard, *this->pudpiiu ); +} + +inline notifyGuard::notifyGuard ( cacContextNotify & notifyIn ) : notify ( notifyIn ) { + this->notify.callbackProcessingInitiateNotify (); } -inline callbackMutex::~callbackMutex () +inline notifyGuard::~notifyGuard () { + this->notify.callbackProcessingCompleteNotify (); } -inline void callbackMutex::lock () +inline callbackManager::callbackManager ( + cacContextNotify & notify, epicsMutex & callbackControl ) : + notifyGuard ( notify ), cbGuard ( callbackControl ) { - this->notify.callbackLock (); -} - -inline void callbackMutex::unlock () -{ - this->notify.callbackUnlock (); } #endif // ifdef cach diff --git a/src/ca/cacContextNotify.cpp b/src/ca/cacContextNotify.cpp index 8a31416c6..df47168d5 100644 --- a/src/ca/cacContextNotify.cpp +++ b/src/ca/cacContextNotify.cpp @@ -31,11 +31,11 @@ cacContextNotify::~cacContextNotify () { } -void cacContextNotify::callbackLock () +void cacContextNotify::callbackProcessingInitiateNotify () { } -void cacContextNotify::callbackUnlock () +void cacContextNotify::callbackProcessingCompleteNotify () { } diff --git a/src/ca/cacIO.h b/src/ca/cacIO.h index 6819449ce..0bf448644 100644 --- a/src/ca/cacIO.h +++ b/src/ca/cacIO.h @@ -173,9 +173,10 @@ public: enum ioStatus { iosSynch, iosAsynch }; cacChannel ( cacChannelNotify & ); - cacChannelNotify & notify () const; virtual void destroy ( - epicsGuard < epicsMutex > & ) = 0; + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; + cacChannelNotify & notify () const; virtual const char * pName () const = 0; // not thread safe virtual void show ( unsigned level ) const = 0; @@ -198,7 +199,9 @@ public: arrayElementCount count, unsigned mask, cacStateNotify &, ioid * = 0 ) = 0; virtual void ioCancel ( - epicsGuard < epicsMutex > &, const ioid & ) = 0; + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const ioid & ) = 0; virtual void ioShow ( const ioid &, unsigned level ) const = 0; virtual short nativeType () const = 0; @@ -259,7 +262,8 @@ public: class epicsShareClass cacContextNotify { // X aCC 655 public: virtual ~cacContextNotify () = 0; - virtual cacContext & createNetworkContext ( epicsMutex & ) = 0; + virtual cacContext & createNetworkContext ( + epicsMutex & mutualExclusion, epicsMutex & callbackControl ) = 0; // we should probably have a different vf for each type of exception ???? virtual void exception ( epicsGuard < epicsMutex > &, int status, const char * pContext, @@ -270,19 +274,26 @@ public: virtual void attachToClientCtx () = 0; virtual void blockForEventAndEnableCallbacks ( class epicsEvent & event, const double & timeout ) = 0; - virtual void callbackLock () = 0; - virtual void callbackUnlock () = 0; + virtual void callbackProcessingInitiateNotify () = 0; + virtual void callbackProcessingCompleteNotify () = 0; }; +// **** Lock Hierarchy **** +// callbackControl must be taken before mutualExclusion if both are held at +// the same time class epicsShareClass cacService { public: virtual ~cacService () = 0; virtual cacContext & contextCreate ( - epicsMutex &, cacContextNotify & ) = 0; + epicsMutex & mutualExclusion, + epicsMutex & callbackControl, + cacContextNotify & ) = 0; }; epicsShareFunc void epicsShareAPI caInstallDefaultService ( cacService & service ); +epicsShareExtern epicsThreadPrivateId caClientCallbackThreadId; + inline cacChannel::cacChannel ( cacChannelNotify & notify ) : callback ( notify ) { diff --git a/src/ca/comBuf.h b/src/ca/comBuf.h index ae5bf9212..2bdfee8c3 100644 --- a/src/ca/comBuf.h +++ b/src/ca/comBuf.h @@ -53,10 +53,22 @@ public: const class epicsTime & currentTime ) = 0; }; +enum swioCircuitState { + swioConnected, + swioPeerHangup, + swioPeerAbort, + swioLinkFailure, + swioLocalAbort +}; +struct statusWireIO { + unsigned bytesCopied; + swioCircuitState circuitState; +}; + class wireRecvAdapter { // X aCC 655 public: - virtual unsigned recvBytes ( void *pBuf, - unsigned nBytesInBuf ) = 0; + virtual void recvBytes ( void * pBuf, + unsigned nBytesInBuf, statusWireIO & ) = 0; }; class comBuf : public tsDLNode < comBuf > { @@ -95,7 +107,7 @@ public: bool copyOutAllBytes ( void *pBuf, unsigned nBytes ); unsigned removeBytes ( unsigned nBytes ); bool flushToWire ( wireSendAdapter &, const epicsTime & currentTime ); - unsigned fillFromWire ( wireRecvAdapter & ); + void fillFromWire ( wireRecvAdapter &, statusWireIO & ); struct popStatus { bool success; bool nowEmpty; @@ -171,13 +183,15 @@ inline unsigned comBuf::capacityBytes () return comBufSize; } -inline unsigned comBuf::fillFromWire ( wireRecvAdapter & wire ) +inline void comBuf::fillFromWire ( + wireRecvAdapter & wire, statusWireIO & stat ) { - unsigned nNewBytes = wire.recvBytes ( + wire.recvBytes ( & this->buf[this->nextWriteIndex], - sizeof ( this->buf ) - this->nextWriteIndex ); - this->nextWriteIndex += nNewBytes; - return nNewBytes; + sizeof ( this->buf ) - this->nextWriteIndex, stat ); + if ( stat.circuitState == swioConnected ) { + this->nextWriteIndex += stat.bytesCopied; + } } inline bool comBuf::push ( const epicsInt8 value ) diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h index 7276c5f01..e20d64ef0 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -76,7 +76,7 @@ private: /* * CA internal functions */ -#define genLocalExcep( GUARD, CAC, STAT, PCTX ) \ -(CAC).exception ( GUARD, STAT, PCTX, __FILE__, __LINE__ ) +#define genLocalExcep( CBGUARD, GUARD, CAC, STAT, PCTX ) \ +(CAC).exception ( CBGUARD, GUARD, STAT, PCTX, __FILE__, __LINE__ ) #endif // ifdef INCiocinfh diff --git a/src/ca/nciu.cpp b/src/ca/nciu.cpp index 7a24fc6ff..61a9723ba 100644 --- a/src/ca/nciu.cpp +++ b/src/ca/nciu.cpp @@ -76,7 +76,17 @@ nciu::~nciu () { } -void nciu::destructor ( epicsGuard < epicsMutex > & guard ) +void nciu::destroy ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) +{ + this->cacCtx.destroyChannel ( + callbackControlGuard, mutualExclusionGuard, *this ); +} + +void nciu::destructor ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); // Send any side effect IO requests w/o holding the callback lock so that @@ -85,21 +95,24 @@ void nciu::destructor ( epicsGuard < epicsMutex > & guard ) // this is the tcp receive thread. // must not hold callback lock here this->cacCtx.flushIfRequired ( guard, *this->piiu ); + while ( baseNMIU * pNetIO = this->eventq.first () ) { - assert ( this->cacCtx.destroyIO ( guard, + assert ( this->cacCtx.destroyIO ( cbGuard, guard, pNetIO->getId (), *this ) ); } + + // if the claim reply has not returned yet 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 ( this->connected ( guard ) ) { + this->getPIIU()->clearChannelRequest ( + guard, this->sid, this->id ); + } + delete [] this->pNameStr; this->~nciu (); } -// called virtually -void nciu::destroy ( epicsGuard < epicsMutex > & guard ) -{ - // must not hold callback lock here - this->cacCtx.destroyChannel ( guard, *this ); -} - void * nciu::operator new ( size_t ) // X aCC 361 { // The HPUX compiler seems to require this even though no code @@ -126,15 +139,12 @@ void nciu::initiateConnect ( void nciu::connect ( unsigned nativeType, unsigned nativeCount, unsigned sidIn, - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); if ( ! dbf_type_is_valid ( nativeType ) ) { - this->cacCtx.printf ( - "CAC: Ignored conn resp with bad native data type CID=%u SID=%u?\n", - this->getId (), sidIn ); - return; + throw std::logic_error ( "Ignored conn resp with bad native data type" ); } this->typeCode = static_cast < unsigned short > ( nativeType ); @@ -174,7 +184,7 @@ void nciu::connect ( unsigned nativeType, } void nciu::unresponsiveCircuitNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); @@ -199,7 +209,7 @@ void nciu::setServerAddressUnknown ( udpiiu & newiiu, } void nciu::accessRightsStateChange ( - const caAccessRights & arIn, epicsGuard < callbackMutex > &, + const caAccessRights & arIn, epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); @@ -365,9 +375,10 @@ void nciu::subscribe ( } void nciu::ioCancel ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, const ioid & idIn ) { - this->cacCtx.destroyIO ( guard, idIn, *this ); + this->cacCtx.destroyIO ( cbGuard, guard, idIn, *this ); } void nciu::ioShow ( const ioid &idIn, unsigned level ) const @@ -478,19 +489,6 @@ void nciu::show ( unsigned level ) const } } -int nciu::printf ( const char *pFormat, ... ) -{ - va_list theArgs; - - va_start ( theArgs, pFormat ); - - int status = this->cacCtx.vPrintf ( pFormat, theArgs ); - - va_end ( theArgs ); - - return status; -} - void nciu::beaconAnomalyNotify () { if ( this->retry > beaconAnomalyRetrySetpoint ) { @@ -520,7 +518,7 @@ void nciu::resubscribe ( epicsGuard < epicsMutex > & guard ) this->getPIIU()->subscriptionRequest ( guard, *this, *pSubscr ); } catch ( ... ) { - this->printf ( "CAC: failed to send subscription request during channel connect\n" ); + errlogPrintf ( "CAC: failed to send subscription request during channel connect\n" ); } } pNetIO = next; @@ -541,14 +539,14 @@ void nciu::sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & guard ) pSubscr->subscriptionUpdateIfRequired ( guard, *this ); } catch ( ... ) { - this->printf ( "CAC: failed to send subscription request during channel connect\n" ); + errlogPrintf ( "CAC: failed to send subscription request during channel connect\n" ); } pNetIO = next; } } void nciu::disconnectAllIO ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { this->cacCtx.disconnectAllIO ( cbGuard, guard, diff --git a/src/ca/nciu.h b/src/ca/nciu.h index 3027922f6..3aea55ecc 100644 --- a/src/ca/nciu.h +++ b/src/ca/nciu.h @@ -49,7 +49,6 @@ class cac; class netiiu; -class callbackMutex; // The node and the state which tracks the list membership // are in the channel, but belong to the circuit. @@ -82,7 +81,6 @@ public: epicsGuard < epicsMutex > &, class baseNMIU & ) = 0; virtual arrayElementCount nativeElementCount ( epicsGuard < epicsMutex > & ) const = 0; - virtual int printf ( const char *pFormat, ... ) = 0; virtual bool connected ( epicsGuard < epicsMutex > & ) const = 0; }; @@ -95,18 +93,19 @@ public: nciu ( cac &, netiiu &, cacChannelNotify &, const char * pNameIn, cacChannel::priLev ); void destructor ( - epicsGuard < epicsMutex > & ); + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); void connect ( unsigned nativeType, unsigned nativeCount, unsigned sid, - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void connect ( epicsGuard < callbackMutex > & cbGuard, + void connect ( epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); void unresponsiveCircuitNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); void circuitHangupNotify ( class udpiiu &, - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); void setServerAddressUnknown ( udpiiu & newiiu, epicsGuard < epicsMutex > & guard ); @@ -114,13 +113,13 @@ public: void beaconAnomalyNotify (); void serviceShutdownNotify (); void accessRightsStateChange ( const caAccessRights &, - epicsGuard < callbackMutex > &, epicsGuard < epicsMutex > & ); + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); ca_uint32_t getSID () const; ca_uint32_t getCID () const; netiiu * getPIIU (); const netiiu * getConstPIIU () const; cac & getClient (); - int printf ( const char *pFormat, ... ); void searchReplySetUp ( netiiu &iiu, unsigned sidIn, ca_uint16_t typeIn, arrayElementCount countIn, epicsGuard < epicsMutex > & ); @@ -129,7 +128,7 @@ public: unsigned nameLen () const; const char * pHostName () const; // deprecated - please do not use void writeException ( - epicsGuard < callbackMutex > &, epicsGuard < epicsMutex > &, + epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count ); cacChannel::priLev getPriority () const; void * operator new ( @@ -140,7 +139,7 @@ public: void resubscribe ( epicsGuard < epicsMutex > & ); void sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & ); void disconnectAllIO ( - epicsGuard < callbackMutex > &, epicsGuard < epicsMutex > & ); + epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & ); bool connected ( epicsGuard < epicsMutex > & ) const; private: @@ -156,8 +155,9 @@ private: ca_uint16_t typeCode; ca_uint8_t priority; ~nciu (); - void destroy ( - epicsGuard < epicsMutex > & ); + virtual void destroy ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ); void initiateConnect ( epicsGuard < epicsMutex > & ); ioStatus read ( @@ -176,8 +176,10 @@ private: epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify ¬ify, ioid * ); - void ioCancel ( - epicsGuard < epicsMutex > &, const ioid & ); + virtual void ioCancel ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const ioid & ); void ioShow ( const ioid &, unsigned level ) const; short nativeType () const; @@ -222,7 +224,7 @@ inline ca_uint32_t nciu::getCID () const } // this is to only be used by early protocol revisions -inline void nciu::connect ( epicsGuard < callbackMutex > & cbGuard, +inline void nciu::connect ( epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { this->connect ( this->typeCode, this->count, @@ -245,7 +247,7 @@ inline netiiu * nciu::getPIIU () } inline void nciu::writeException ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, int status, const char * pContext, unsigned typeIn, arrayElementCount countIn ) diff --git a/src/ca/netSubscription.cpp b/src/ca/netSubscription.cpp index 355a3c5a3..9c9ae8660 100644 --- a/src/ca/netSubscription.cpp +++ b/src/ca/netSubscription.cpp @@ -80,7 +80,7 @@ void netSubscription::completion ( else { this->updateWhileDisconnected = true; } - this->privateChanForIO.printf ( "subscription update w/o data ?\n" ); + errlogPrintf ( "subscription update w/o data ?\n" ); } void netSubscription::exception ( diff --git a/src/ca/netiiu.cpp b/src/ca/netiiu.cpp index 3d862d0d5..22bbf981a 100644 --- a/src/ca/netiiu.cpp +++ b/src/ca/netiiu.cpp @@ -123,7 +123,8 @@ void netiiu::requestRecvProcessPostponedFlush () return; } -void netiiu::uninstallChan ( epicsGuard < epicsMutex > &, nciu & ) +void netiiu::uninstallChan ( epicsGuard < epicsMutex > &, + epicsGuard < epicsMutex > &, nciu & ) { throw cacChannel::notConnected(); } diff --git a/src/ca/netiiu.h b/src/ca/netiiu.h index 655d6357c..70d714f16 100644 --- a/src/ca/netiiu.h +++ b/src/ca/netiiu.h @@ -36,7 +36,6 @@ class netSubscription; union osiSockAddr; class cac; -class callbackMutex; class netiiu { public: @@ -67,7 +66,9 @@ public: ( cacContextNotify &, epicsGuard < epicsMutex > & ) = 0; virtual void requestRecvProcessPostponedFlush () = 0; virtual osiSockAddr getNetworkAddress () const = 0; - virtual void uninstallChan ( epicsGuard < epicsMutex > &, nciu & ) = 0; + virtual void uninstallChan ( + epicsGuard < epicsMutex > & cbMutex, + epicsGuard < epicsMutex > & mutex, nciu & ) = 0; virtual double receiveWatchdogDelay () const = 0; }; diff --git a/src/ca/oldAccess.h b/src/ca/oldAccess.h index d99645ade..e6ab4d0d5 100644 --- a/src/ca/oldAccess.h +++ b/src/ca/oldAccess.h @@ -54,7 +54,8 @@ public: const char * pName, caCh * pConnCallBackIn, void * pPrivateIn, capri priority ); void destructor ( - epicsGuard < epicsMutex > & ); + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); void setPrivatePointer ( void * ); void * privatePointer () const; int changeConnCallBack ( caCh *pfunc ); @@ -84,7 +85,9 @@ public: unsigned type, arrayElementCount count, unsigned mask, cacStateNotify &, cacChannel::ioid & ); void ioCancel ( - epicsGuard < epicsMutex > &, const cacChannel::ioid & ); + epicsGuard < epicsMutex > & callbackControl, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const cacChannel::ioid & ); void ioShow ( const cacChannel::ioid &, unsigned level ) const; short nativeType () const; arrayElementCount nativeElementCount () const; @@ -149,7 +152,7 @@ private: arrayElementCount count; ca_client_context & cacCtx; oldChannelNotify & chan; - void *pValue; + void * pValue; unsigned ioSeqNo; unsigned type; void completion ( @@ -226,7 +229,8 @@ public: tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & ); epicsPlacementDeleteOperator (( void *, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & )) - void ioCancel ( epicsGuard < epicsMutex > & ); + void ioCancel ( epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); private: oldChannelNotify & chan; cacChannel::ioid id; @@ -310,7 +314,7 @@ private: tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > subscriptionFreeList; tsFreeList < struct CASG, 128, epicsMutexNOOP > casgFreeList; mutable epicsMutex mutex; - epicsMutex callbackMutex; + mutable epicsMutex cbMutex; epicsEvent ioDone; epicsEvent callbackThreadActivityComplete; epics_auto_ptr < epicsGuard < epicsMutex > > pCallbackGuard; @@ -328,10 +332,11 @@ private: bool fdRegFuncNeedsToBeCalled; bool noWakeupSincePend; - void callbackLock (); - void callbackUnlock (); void attachToClientCtx (); - cacContext & createNetworkContext ( epicsMutex & mutex ); + void callbackProcessingInitiateNotify (); + void callbackProcessingCompleteNotify (); + cacContext & createNetworkContext ( + epicsMutex & mutualExclusion, epicsMutex & callbackControl ); ca_client_context ( const ca_client_context & ); ca_client_context & operator = ( const ca_client_context & ); @@ -359,6 +364,9 @@ private: friend int epicsShareAPI ca_flush_io (); friend int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ); friend int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid ); + friend int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeout ); + friend int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid ); + friend int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ); friend void epicsShareAPI caInstallDefaultService ( cacService & ); }; @@ -385,10 +393,12 @@ inline void oldChannelNotify::initiateConnect ( this->io.initiateConnect ( guard ); } -inline void oldChannelNotify::ioCancel ( - epicsGuard < epicsMutex > & guard, const cacChannel::ioid & id ) +inline void oldChannelNotify::ioCancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, + const cacChannel::ioid & id ) { - this->io.ioCancel ( guard, id ); + this->io.ioCancel ( cbGuard, guard, id ); } inline void oldChannelNotify::ioShow ( diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp index 32ffc7669..6b9ea3e87 100644 --- a/src/ca/oldChannelNotify.cpp +++ b/src/ca/oldChannelNotify.cpp @@ -63,10 +63,11 @@ oldChannelNotify::~oldChannelNotify () } void oldChannelNotify::destructor ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - this->io.destroy ( guard ); + this->io.destroy ( cbGuard, guard ); // no need to worry about a connect preempting here because // the io (the nciu) has been destroyed above if ( this->pConnCallBack == 0 && ! this->currentlyConnected ) { diff --git a/src/ca/oldSubscription.cpp b/src/ca/oldSubscription.cpp index 790acc4f2..933b83664 100644 --- a/src/ca/oldSubscription.cpp +++ b/src/ca/oldSubscription.cpp @@ -29,10 +29,12 @@ oldSubscription::~oldSubscription () { } -void oldSubscription::ioCancel ( epicsGuard < epicsMutex > & guard ) +void oldSubscription::ioCancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) { if ( this->subscribed ) { - this->chan.ioCancel ( guard, this->id ); + this->chan.ioCancel ( cbGuard, guard, this->id ); } } diff --git a/src/ca/repeaterSubscribeTimer.cpp b/src/ca/repeaterSubscribeTimer.cpp index 065467b17..464b5d049 100644 --- a/src/ca/repeaterSubscribeTimer.cpp +++ b/src/ca/repeaterSubscribeTimer.cpp @@ -22,6 +22,7 @@ #define epicsAssertAuthor "Jeff Hill johill@lanl.gov" +#include "cac.h" #include "iocinf.h" #include "repeaterSubscribeTimer.h" @@ -29,8 +30,11 @@ #include "udpiiu.h" #undef epicsExportSharedSymbols -repeaterSubscribeTimer::repeaterSubscribeTimer ( udpiiu &iiuIn, epicsTimerQueue &queueIn ) : +repeaterSubscribeTimer::repeaterSubscribeTimer ( + udpiiu & iiuIn, epicsTimerQueue & queueIn, + epicsMutex & cbMutexIn, cacContextNotify & ctxNotifyIn ) : timer ( queueIn.createTimer () ), iiu ( iiuIn ), + cbMutex ( cbMutexIn ),ctxNotify ( ctxNotifyIn ), attempts ( 0 ), registered ( false ), once ( false ) { this->timer.start ( *this, 10.0 ); @@ -51,12 +55,13 @@ epicsTimerNotify::expireStatus repeaterSubscribeTimer:: { static const unsigned nTriesToMsg = 50; if ( this->attempts > nTriesToMsg && ! this->once ) { - this->iiu.printf ( + callbackManager mgr ( this->ctxNotify, this->cbMutex ); + this->iiu.printf ( mgr.cbGuard, "CA client library is unable to contact CA repeater after %u tries.\n", nTriesToMsg); - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "Silence this message by starting a CA repeater daemon\n"); - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "or by calling ca_pend_event() and or ca_poll() more often.\n"); this->once = true; } diff --git a/src/ca/repeaterSubscribeTimer.h b/src/ca/repeaterSubscribeTimer.h index bf6679cf6..620f24384 100644 --- a/src/ca/repeaterSubscribeTimer.h +++ b/src/ca/repeaterSubscribeTimer.h @@ -30,17 +30,22 @@ #include "epicsTimer.h" class udpiiu; +class epicsMutex; +class cacContextNotify; class repeaterSubscribeTimer : private epicsTimerNotify { public: - repeaterSubscribeTimer ( udpiiu &, epicsTimerQueue & ); + repeaterSubscribeTimer ( udpiiu &, epicsTimerQueue &, + epicsMutex & cbMutex, cacContextNotify & ctxNotify ); virtual ~repeaterSubscribeTimer (); void shutdown (); void confirmNotify (); void show ( unsigned level ) const; private: - epicsTimer &timer; - udpiiu &iiu; + epicsTimer & timer; + udpiiu & iiu; + epicsMutex & cbMutex; + cacContextNotify & ctxNotify; unsigned attempts; bool registered; bool once; diff --git a/src/ca/sgAutoPtr.h b/src/ca/sgAutoPtr.h index 4d98172c3..8727d78aa 100644 --- a/src/ca/sgAutoPtr.h +++ b/src/ca/sgAutoPtr.h @@ -30,7 +30,8 @@ template < class T > class sgAutoPtr { public: - sgAutoPtr ( epicsGuard < epicsMutex > &, struct CASG & ); + sgAutoPtr ( epicsGuard < epicsMutex > &, + struct CASG &, tsDLList < syncGroupNotify > & ); ~sgAutoPtr (); sgAutoPtr < T > & operator = ( T * ); T * operator -> (); @@ -38,6 +39,7 @@ public: T * get (); T * release (); private: + tsDLList < syncGroupNotify > & list; T * pNotify; struct CASG & sg; epicsGuard < epicsMutex > & guard; @@ -45,24 +47,30 @@ private: template < class T > inline sgAutoPtr < T > :: sgAutoPtr ( - epicsGuard < epicsMutex > & guardIn, struct CASG & sgIn ) : - pNotify ( 0 ), sg ( sgIn ), guard ( guardIn ) + epicsGuard < epicsMutex > & guardIn, + struct CASG & sgIn, tsDLList < syncGroupNotify > & listIn ) : + list ( listIn ), pNotify ( 0 ), sg ( sgIn ), guard ( guardIn ) { } template < class T > inline sgAutoPtr < T > :: ~sgAutoPtr () { - this->sg.destroyPendingIO ( this->guard, this->pNotify ); + if ( this->pNotify ) { + list.remove ( *this->pNotify ); + pNotify->destroy ( this->guard, this->sg ); + } } template < class T > inline sgAutoPtr < T > & sgAutoPtr < T > :: operator = ( T * pNotifyIn ) { if ( this->pNotify ) { - this->sg.destroyPendingIO ( this->guard, this->pNotify ); + list.remove ( *this->pNotify ); + pNotify->destroy ( this->guard, this->sg ); } this->pNotify = pNotifyIn; + list.add ( *this->pNotify ); return *this; } diff --git a/src/ca/syncGroup.h b/src/ca/syncGroup.h index 87fe16d83..dd1fb67f8 100644 --- a/src/ca/syncGroup.h +++ b/src/ca/syncGroup.h @@ -64,9 +64,16 @@ class syncGroupNotify : public tsDLNode < syncGroupNotify > { public: syncGroupNotify (); virtual void destroy ( - epicsGuard < epicsMutex > &, casgRecycle & ) = 0; + epicsGuard < epicsMutex > & guard, + casgRecycle & ) = 0; + virtual bool ioPending ( + epicsGuard < epicsMutex > & guard ) = 0; + virtual void cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) = 0; virtual void show ( - epicsGuard < epicsMutex > &, unsigned level ) const = 0; + epicsGuard < epicsMutex > &, + unsigned level ) const = 0; protected: virtual ~syncGroupNotify (); syncGroupNotify ( const syncGroupNotify & ); @@ -78,19 +85,27 @@ public: static syncGroupReadNotify * factory ( tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &, struct CASG &, chid, void *pValueIn ); + void destroy ( + epicsGuard < epicsMutex > & guard, + casgRecycle & ); + bool ioPending ( + epicsGuard < epicsMutex > & guard ); void begin ( epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count ); - void destroy ( epicsGuard < epicsMutex > &, casgRecycle & ); + void cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; protected: virtual ~syncGroupReadNotify (); private: chid chan; struct CASG & sg; + void * pValue; const unsigned magic; cacChannel::ioid id; bool idIsValid; - void * pValue; + bool ioComplete; syncGroupReadNotify ( struct CASG & sgIn, chid, void * pValueIn ); void * operator new ( size_t ); void operator delete ( void * ); @@ -113,9 +128,16 @@ public: static syncGroupWriteNotify * factory ( tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &, struct CASG &, chid ); + void destroy ( + epicsGuard < epicsMutex > & guard, + casgRecycle & ); + bool ioPending ( + epicsGuard < epicsMutex > & guard ); void begin ( epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void * pValueIn ); - void destroy ( epicsGuard < epicsMutex > &, casgRecycle & ); + void cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; protected: virtual ~syncGroupWriteNotify (); // allocate only from pool @@ -125,6 +147,7 @@ private: const unsigned magic; cacChannel::ioid id; bool idIsValid; + bool ioComplete; syncGroupWriteNotify ( struct CASG &, chid ); void * operator new ( size_t ); void operator delete ( void * ); @@ -147,11 +170,17 @@ template < class T > class sgAutoPtr; struct CASG : public chronIntIdRes < CASG >, private casgRecycle { public: CASG ( epicsGuard < epicsMutex > &, ca_client_context & cacIn ); - void destructor ( epicsGuard < epicsMutex > & ); - bool ioComplete ( epicsGuard < epicsMutex > & ); + void destructor ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); + bool ioComplete ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); bool verify ( epicsGuard < epicsMutex > & ) const; - int block ( epicsGuard < epicsMutex > &, double timeout ); - void reset ( epicsGuard < epicsMutex > & ); + int block ( epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, double timeout ); + void reset ( epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; void show ( unsigned level ) const; void get ( epicsGuard < epicsMutex > &, chid pChan, @@ -185,9 +214,11 @@ private: void recycleSyncGroupReadNotify ( epicsGuard < epicsMutex > &, syncGroupReadNotify & io ); - void destroyPendingIO ( epicsGuard < epicsMutex > &, syncGroupNotify * ); - void destroyCompletedIO ( epicsGuard < epicsMutex > & ); - void destroyPendingIO ( epicsGuard < epicsMutex > & ); + void destroyPendingIO ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); + void destroyCompletedIO ( + epicsGuard < epicsMutex > & guard ); CASG ( const CASG & ); CASG & operator = ( const CASG & ); @@ -201,13 +232,40 @@ private: friend class sgAutoPtr < syncGroupReadNotify >; }; +class boolFlagManager { +public: + boolFlagManager ( bool & flag ); + ~boolFlagManager (); + void release (); +private: + bool * pBool; +}; + +inline boolFlagManager::boolFlagManager ( bool & flagIn ) : + pBool ( & flagIn ) +{ + *this->pBool = true; +} + +inline boolFlagManager::~boolFlagManager () +{ + if ( this->pBool ) { + *this->pBool = false; + } +} + +inline void boolFlagManager::release () +{ + this->pBool = 0; +} + inline void * CASG::operator new ( size_t size, tsFreeList < struct CASG, 128, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } -# if defined ( CXX_PLACEMENT_DELETE ) +#if defined ( CXX_PLACEMENT_DELETE ) inline void CASG::operator delete ( void * pCadaver, tsFreeList < struct CASG, 128, epicsMutexNOOP > & freeList ) { @@ -215,4 +273,16 @@ inline void CASG::operator delete ( void * pCadaver, } #endif +inline bool syncGroupWriteNotify::ioPending ( + epicsGuard < epicsMutex > & guard ) +{ + return ! this->ioComplete; +} + +inline bool syncGroupReadNotify::ioPending ( + epicsGuard < epicsMutex > & guard ) +{ + return ! this->ioComplete; +} + #endif // ifdef syncGrouph diff --git a/src/ca/syncGroupReadNotify.cpp b/src/ca/syncGroupReadNotify.cpp index 394e2f622..c4912bd71 100644 --- a/src/ca/syncGroupReadNotify.cpp +++ b/src/ca/syncGroupReadNotify.cpp @@ -27,8 +27,9 @@ syncGroupReadNotify::syncGroupReadNotify ( CASG & sgIn, chid pChan, void * pValueIn ) : - chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ), - id ( 0u ), idIsValid ( false ), pValue ( pValueIn ) + chan ( pChan ), sg ( sgIn ), pValue ( pValueIn ), + magic ( CASG_MAGIC ), id ( 0u ), + idIsValid ( false ), ioComplete ( false ) { } @@ -36,8 +37,20 @@ void syncGroupReadNotify::begin ( epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count ) { + this->ioComplete = false; + boolFlagManager mgr ( this->idIsValid ); this->chan->read ( guard, type, count, *this, &this->id ); - this->idIsValid = true; + mgr.release (); +} + +void syncGroupReadNotify::cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) +{ + if ( this->idIsValid ) { + this->chan->ioCancel ( cbGuard, guard, this->id ); + this->idIsValid = false; + } } syncGroupReadNotify * syncGroupReadNotify::factory ( @@ -51,15 +64,13 @@ syncGroupReadNotify * syncGroupReadNotify::factory ( void syncGroupReadNotify::destroy ( epicsGuard < epicsMutex > & guard, casgRecycle & recycle ) { - if ( this->idIsValid ) { - this->chan->ioCancel ( guard, this->id ); - } this->~syncGroupReadNotify (); recycle.recycleSyncGroupReadNotify ( guard, *this ); } syncGroupReadNotify::~syncGroupReadNotify () { + assert ( ! this->idIsValid ); } void syncGroupReadNotify::completion ( @@ -76,14 +87,20 @@ void syncGroupReadNotify::completion ( size_t size = dbr_size_n ( type, count ); memcpy ( this->pValue, pData, size ); } - this->idIsValid = false; this->sg.completionNotify ( guard, *this ); + this->idIsValid = false; + this->ioComplete = true; } void syncGroupReadNotify::exception ( epicsGuard < epicsMutex > & guard, int status, const char * pContext, unsigned type, arrayElementCount count ) { + if ( this->magic != CASG_MAGIC ) { + this->sg.printf ( + "cac: sync group io_complete(): bad sync grp op magic number?\n" ); + return; + } this->idIsValid = false; this->sg.exception ( guard, status, pContext, __FILE__, __LINE__, *this->chan, type, count, CA_OP_GET ); diff --git a/src/ca/syncGroupWriteNotify.cpp b/src/ca/syncGroupWriteNotify.cpp index 9ab2cbae0..d384f5eed 100644 --- a/src/ca/syncGroupWriteNotify.cpp +++ b/src/ca/syncGroupWriteNotify.cpp @@ -27,7 +27,7 @@ syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, chid pChan ) : chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ), - id ( 0u ), idIsValid ( false ) + id ( 0u ), idIsValid ( false ), ioComplete ( false ) { } @@ -35,9 +35,21 @@ void syncGroupWriteNotify::begin ( epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, const void * pValueIn ) { + this->ioComplete = false; + boolFlagManager mgr ( this->idIsValid ); this->chan->write ( guard, type, count, pValueIn, *this, &this->id ); - this->idIsValid = true; + mgr.release (); +} + +void syncGroupWriteNotify::cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) +{ + if ( this->idIsValid ) { + this->chan->ioCancel ( cbGuard, guard, this->id ); + this->idIsValid = false; + } } syncGroupWriteNotify * syncGroupWriteNotify::factory ( @@ -50,15 +62,13 @@ syncGroupWriteNotify * syncGroupWriteNotify::factory ( void syncGroupWriteNotify::destroy ( epicsGuard < epicsMutex > & guard, casgRecycle & recycle ) { - if ( this->idIsValid ) { - this->chan->ioCancel ( guard, this->id ); - } this->~syncGroupWriteNotify (); recycle.recycleSyncGroupWriteNotify ( guard, *this ); } syncGroupWriteNotify::~syncGroupWriteNotify () { + assert ( ! this->idIsValid ); } void syncGroupWriteNotify::completion ( @@ -68,18 +78,22 @@ void syncGroupWriteNotify::completion ( this->sg.printf ( "cac: sync group io_complete(): bad sync grp op magic number?\n" ); return; } - this->idIsValid = false; this->sg.completionNotify ( guard, *this ); + this->idIsValid = false; + this->ioComplete = true; } void syncGroupWriteNotify::exception ( epicsGuard < epicsMutex > & guard, int status, const char *pContext, unsigned type, arrayElementCount count ) { - this->sg.exception ( guard, status, pContext, - __FILE__, __LINE__, *this->chan, type, count, CA_OP_PUT ); - this->idIsValid = false; - + if ( this->magic != CASG_MAGIC ) { + this->sg.printf ( "cac: sync group io_complete(): bad sync grp op magic number?\n" ); + return; + } + this->sg.exception ( guard, status, pContext, + __FILE__, __LINE__, *this->chan, type, count, CA_OP_PUT ); + this->idIsValid = false; // // This notify is left installed at this point as a place holder indicating that // all requests have not been completed. This notify is not uninstalled until diff --git a/src/ca/syncgrp.cpp b/src/ca/syncgrp.cpp index de7b1ef41..d509ea647 100644 --- a/src/ca/syncgrp.cpp +++ b/src/ca/syncgrp.cpp @@ -60,15 +60,29 @@ extern "C" int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid ) return caStatus; } - epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); + if ( pcac->pCallbackGuard.get() ) { + epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); - CASG * pcasg = pcac->lookupCASG ( guard, gid ); - if ( ! pcasg ) { - return ECA_BADSYNCGRP; + CASG * pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + return ECA_BADSYNCGRP; + } + + pcasg->destructor ( *pcac->pCallbackGuard, guard ); + pcac->casgFreeList.release ( pcasg ); } + else { + epicsGuard < epicsMutex > cbGuard ( pcac->cbMutex ); + epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); - pcasg->destructor ( guard ); - pcac->casgFreeList.release ( pcasg ); + CASG * pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + return ECA_BADSYNCGRP; + } + + pcasg->destructor ( cbGuard, guard ); + pcac->casgFreeList.release ( pcasg ); + } return ECA_NORMAL; } @@ -82,19 +96,33 @@ extern "C" int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeou CASG *pcasg; int status; - status = fetchClientContext (&pcac); + status = fetchClientContext ( &pcac ); if ( status != ECA_NORMAL ) { return status; } - epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); + if ( pcac->pCallbackGuard.get() ) { + epicsGuard < epicsMutex > guard ( pcac->mutex ); - pcasg = pcac->lookupCASG ( guard, gid ); - if ( ! pcasg ) { - status = ECA_BADSYNCGRP; + pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + status = ECA_BADSYNCGRP; + } + else { + status = pcasg->block ( *pcac->pCallbackGuard, guard, timeout ); + } } else { - status = pcasg->block ( guard, timeout ); + epicsGuard < epicsMutex > cbGuard ( pcac->cbMutex); + epicsGuard < epicsMutex > guard ( pcac->mutex ); + + pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + status = ECA_BADSYNCGRP; + } + else { + status = pcasg->block ( cbGuard, guard, timeout ); + } } return status; @@ -114,15 +142,30 @@ extern "C" int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid ) return caStatus; } - epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); + if ( pcac->pCallbackGuard.get() ) { + epicsGuard < epicsMutex > guard ( pcac->mutex ); - pcasg = pcac->lookupCASG ( guard, gid ); - if ( ! pcasg ) { - caStatus = ECA_BADSYNCGRP; + pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + caStatus = ECA_BADSYNCGRP; + } + else { + caStatus = ECA_NORMAL; + pcasg->reset ( *pcac->pCallbackGuard, guard ); + } } else { - caStatus = ECA_NORMAL; - pcasg->reset ( guard ); + epicsGuard < epicsMutex > cbGuard ( pcac->cbMutex ); + epicsGuard < epicsMutex > guard ( pcac->mutex ); + + pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + caStatus = ECA_BADSYNCGRP; + } + else { + caStatus = ECA_NORMAL; + pcasg->reset ( cbGuard, guard ); + } } return caStatus; @@ -160,22 +203,39 @@ extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) // X aCC 361 CASG *pcasg; int caStatus; - caStatus = fetchClientContext (&pcac); + caStatus = fetchClientContext ( &pcac ); if ( caStatus != ECA_NORMAL ) { return caStatus; } - epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); + if ( pcac->pCallbackGuard.get() ) { + epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); - pcasg = pcac->lookupCASG ( guard, gid ); - if ( ! pcasg ) { - return ECA_BADSYNCGRP; + pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + return ECA_BADSYNCGRP; + } + if ( pcasg->ioComplete ( *pcac->pCallbackGuard, guard ) ) { + return ECA_IODONE; + } + else{ + return ECA_IOINPROGRESS; + } } - if ( pcasg->ioComplete ( guard ) ) { - return ECA_IODONE; - } - else{ - return ECA_IOINPROGRESS; + else { + epicsGuard < epicsMutex > cbGuard ( pcac->cbMutex ); + epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); + + pcasg = pcac->lookupCASG ( guard, gid ); + if ( ! pcasg ) { + return ECA_BADSYNCGRP; + } + if ( pcasg->ioComplete ( cbGuard, guard ) ) { + return ECA_IODONE; + } + else{ + return ECA_IOINPROGRESS; + } } } diff --git a/src/ca/tcpRecvWatchdog.cpp b/src/ca/tcpRecvWatchdog.cpp index 34217b069..c76239658 100644 --- a/src/ca/tcpRecvWatchdog.cpp +++ b/src/ca/tcpRecvWatchdog.cpp @@ -29,10 +29,12 @@ // the recv watchdog timer is active when this object is created // tcpRecvWatchdog::tcpRecvWatchdog - ( callbackMutex & cbMutexIn, epicsMutex & mutexIn, tcpiiu & iiuIn, + ( epicsMutex & cbMutexIn, cacContextNotify & ctxNotifyIn, + epicsMutex & mutexIn, tcpiiu & iiuIn, double periodIn, epicsTimerQueue & queueIn ) : period ( periodIn ), timer ( queueIn.createTimer () ), - cbMutex ( cbMutexIn ), mutex ( mutexIn ), iiu ( iiuIn ), + cbMutex ( cbMutexIn ), ctxNotify ( ctxNotifyIn ), + mutex ( mutexIn ), iiu ( iiuIn ), probeResponsePending ( false ), beaconAnomaly ( true ), probeTimeoutDetected ( false ) { @@ -46,18 +48,19 @@ tcpRecvWatchdog::~tcpRecvWatchdog () epicsTimerNotify::expireStatus tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) // X aCC 361 { + callbackManager mgr ( this->ctxNotify, this->cbMutex ); if ( this->probeResponsePending ) { if ( this->iiu.bytesArePendingInOS() ) { - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "The CA client library's server inactivity timer initiated server disconnect\n" ); - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "despite the fact that messages from this server are pending for processing in\n" ); - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "the client library. Here are some possible causes of the unnecessary disconnect:\n" ); - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "o ca_pend_event() or ca_poll() have not been called for %f seconds\n", this->period ); - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "o application is blocked in a callback from the client library\n" ); } # ifdef DEBUG @@ -68,9 +71,8 @@ tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) // X aCC 361 hostName, this->period ) ); # endif { - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); epicsGuard < epicsMutex > guard ( this->mutex ); - this->iiu.receiveTimeoutNotify ( cbGuard, guard ); + this->iiu.receiveTimeoutNotify ( mgr, guard ); this->probeTimeoutDetected = true; } return noRestart; @@ -134,7 +136,7 @@ void tcpRecvWatchdog::messageArrivalNotify ( } void tcpRecvWatchdog::probeResponseNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, const epicsTime & currentTime ) { bool restartNeeded = false; @@ -159,7 +161,7 @@ void tcpRecvWatchdog::probeResponseNotify ( } if ( restartNeeded ) { // timer callback takes the callback mutex and the cac mutex - epicsGuardRelease < callbackMutex > cbGuardRelease ( cbGuard ); + epicsGuardRelease < epicsMutex > cbGuardRelease ( cbGuard ); epicsTime expireTime = currentTime + restartDelay; this->timer.start ( *this, expireTime ); } @@ -207,7 +209,7 @@ void tcpRecvWatchdog::connectNotify () } void tcpRecvWatchdog::sendTimeoutNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, const epicsTime & currentTime ) { @@ -221,7 +223,7 @@ void tcpRecvWatchdog::sendTimeoutNotify ( if ( restartNeeded ) { epicsGuardRelease < epicsMutex > unguard ( guard ); { - epicsGuardRelease < callbackMutex > cbUnguard ( cbGuard ); + epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard ); this->timer.start ( *this, currentTime + CA_ECHO_TIMEOUT ); } } diff --git a/src/ca/tcpRecvWatchdog.h b/src/ca/tcpRecvWatchdog.h index 75d087349..7903eba13 100644 --- a/src/ca/tcpRecvWatchdog.h +++ b/src/ca/tcpRecvWatchdog.h @@ -33,8 +33,9 @@ class tcpiiu; class tcpRecvWatchdog : private epicsTimerNotify { public: - tcpRecvWatchdog ( callbackMutex &, - epicsMutex &, tcpiiu &, + tcpRecvWatchdog ( epicsMutex & cbMutex, + cacContextNotify & ctxNotify, + epicsMutex & mutex, tcpiiu &, double periodIn, epicsTimerQueue & ); virtual ~tcpRecvWatchdog (); void sendBacklogProgressNotify ( @@ -43,7 +44,7 @@ public: void messageArrivalNotify ( const epicsTime & currentTime ); void probeResponseNotify ( - epicsGuard < callbackMutex > &, + epicsGuard < epicsMutex > &, const epicsTime & currentTime ); void beaconArrivalNotify ( epicsGuard < epicsMutex > &, @@ -51,8 +52,8 @@ public: void beaconAnomalyNotify ( epicsGuard < epicsMutex > & ); void connectNotify (); void sendTimeoutNotify ( - epicsGuard < callbackMutex > &, - epicsGuard < epicsMutex > &, + epicsGuard < epicsMutex > & cbMutex, + epicsGuard < epicsMutex > & mutex, const epicsTime & currentTime ); void cancel (); void show ( unsigned level ) const; @@ -60,7 +61,8 @@ public: private: const double period; epicsTimer & timer; - callbackMutex & cbMutex; + epicsMutex & cbMutex; + cacContextNotify & ctxNotify; epicsMutex & mutex; tcpiiu & iiu; bool probeResponsePending; diff --git a/src/ca/tcpSendWatchdog.cpp b/src/ca/tcpSendWatchdog.cpp index c5fe1ce38..237622cb4 100644 --- a/src/ca/tcpSendWatchdog.cpp +++ b/src/ca/tcpSendWatchdog.cpp @@ -25,11 +25,12 @@ #include "cac.h" #include "virtualCircuit.h" -tcpSendWatchdog::tcpSendWatchdog - ( callbackMutex & cbMutexIn, tcpiiu & iiuIn, - double periodIn, epicsTimerQueue & queueIn ) : +tcpSendWatchdog::tcpSendWatchdog ( + epicsMutex & cbMutexIn, cacContextNotify & ctxNotifyIn, + tcpiiu & iiuIn, double periodIn, epicsTimerQueue & queueIn ) : period ( periodIn ), timer ( queueIn.createTimer () ), - cbMutex ( cbMutexIn ), iiu ( iiuIn ) + cbMutex ( cbMutexIn ), ctxNotify ( ctxNotifyIn ), + iiu ( iiuIn ) { } @@ -41,8 +42,9 @@ tcpSendWatchdog::~tcpSendWatchdog () epicsTimerNotify::expireStatus tcpSendWatchdog::expire ( const epicsTime & currentTime ) { + callbackManager mgr ( this->ctxNotify, this->cbMutex ); if ( this->iiu.bytesArePendingInOS() ) { - this->iiu.printf ( + this->iiu.printf ( mgr.cbGuard, "The CA client library is disconnecting after a flush request " "timed out, but receive data is pending, probably because of an " "application schedualing problem\n" ); @@ -53,10 +55,7 @@ epicsTimerNotify::expireStatus tcpSendWatchdog::expire ( debugPrintf ( ( "Request not accepted by CA server %s for %g sec. Disconnecting.\n", hostName, this->period ) ); # endif - { - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); - this->iiu.sendTimeoutNotify ( currentTime, cbGuard ); - } + this->iiu.sendTimeoutNotify ( currentTime, mgr ); return noRestart; } diff --git a/src/ca/tcpSendWatchdog.h b/src/ca/tcpSendWatchdog.h index 0e6b5c748..11ccce84b 100644 --- a/src/ca/tcpSendWatchdog.h +++ b/src/ca/tcpSendWatchdog.h @@ -31,15 +31,17 @@ class tcpSendWatchdog : private epicsTimerNotify { public: - tcpSendWatchdog ( callbackMutex &, tcpiiu &, - double periodIn, epicsTimerQueue & queueIn ); + tcpSendWatchdog ( + epicsMutex & cbMutex, cacContextNotify & ctxNotify, + tcpiiu &, double periodIn, epicsTimerQueue & queueIn ); virtual ~tcpSendWatchdog (); void start ( const epicsTime & ); void cancel (); private: const double period; epicsTimer & timer; - callbackMutex & cbMutex; + epicsMutex & cbMutex; + cacContextNotify & ctxNotify; tcpiiu & iiu; expireStatus expire ( const epicsTime & currentTime ); tcpSendWatchdog ( const tcpSendWatchdog & ); diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp index c4f1a2a44..b78dbb617 100644 --- a/src/ca/tcpiiu.cpp +++ b/src/ca/tcpiiu.cpp @@ -43,11 +43,10 @@ const unsigned mSecPerSec = 1000u; const unsigned uSecPerSec = 1000u * mSecPerSec; -tcpSendThread::tcpSendThread ( class tcpiiu & iiuIn, - callbackMutex & cbMutexIn, const char * pName, +tcpSendThread::tcpSendThread ( + class tcpiiu & iiuIn, const char * pName, unsigned stackSize, unsigned priority ) : - thread ( *this, pName, stackSize, priority ), iiu ( iiuIn ), - cbMutex ( cbMutexIn ) + thread ( *this, pName, stackSize, priority ), iiu ( iiuIn ) { } @@ -68,7 +67,7 @@ void tcpSendThread::exitWait () void tcpSendThread::run () { try { - epicsGuard < epicsMutex > guard ( this->iiu.cacRef.mutexRef() ); + epicsGuard < epicsMutex > guard ( this->iiu.mutex ); bool laborPending = false; @@ -166,7 +165,7 @@ void tcpSendThread::run () } } catch ( ... ) { - this->iiu.printf ( + errlogPrintf ( "cac: tcp send thread received an unexpected exception ", "- disconnecting\n"); // this should cause the server to disconnect from @@ -236,7 +235,7 @@ unsigned tcpiiu::sendBytes ( const void *pBuf, char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->cacRef.printf ( "CAC: unexpected TCP send error: %s\n", + errlogPrintf ( "CAC: unexpected TCP send error: %s\n", sockErrBuf ); } @@ -250,10 +249,9 @@ unsigned tcpiiu::sendBytes ( const void *pBuf, return nBytes; } -unsigned tcpiiu::recvBytes ( void * pBuf, unsigned nBytesInBuf ) +void tcpiiu::recvBytes ( + void * pBuf, unsigned nBytesInBuf, statusWireIO & stat ) { - unsigned bytesAvailable = 0u; - assert ( nBytesInBuf <= INT_MAX ); while ( this->state == iiucs_connected || @@ -263,68 +261,54 @@ unsigned tcpiiu::recvBytes ( void * pBuf, unsigned nBytesInBuf ) static_cast ( nBytesInBuf ), 0 ); if ( status > 0 ) { - bytesAvailable = static_cast ( status ); - assert ( bytesAvailable <= nBytesInBuf ); - break; + stat.bytesCopied = static_cast ( status ); + assert ( stat.bytesCopied <= nBytesInBuf ); + stat.circuitState = swioConnected; + return; } else { int localErrno = SOCKERRNO; if ( status == 0 ) { this->disconnectNotify (); - return 0u; + stat.bytesCopied = 0u; + stat.circuitState = swioPeerHangup; + return; } // if the circuit was aborted then supress warning message about // bad file descriptor if ( this->state != iiucs_connected && this->state != iiucs_clean_shutdown ) { - return 0u; + stat.bytesCopied = 0u; + stat.circuitState = swioLocalAbort; + return; } if ( localErrno == SOCK_SHUTDOWN ) { - this->disconnectNotify (); - return 0u; + stat.bytesCopied = 0u; + stat.circuitState = swioPeerHangup; + return; } if ( localErrno == SOCK_EINTR ) { continue; } - if ( localErrno == SOCK_ECONNABORTED ) { - this->disconnectNotify (); - return 0u; - } - - if ( localErrno == SOCK_ECONNRESET ) { - this->disconnectNotify (); - return 0u; - } - - { - char name[64]; - this->hostName ( name, sizeof ( name ) ); - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "Unexpected problem with circuit to CA ", - "server \"%s\" was \"%s\" - disconnecting\n", - name, sockErrBuf ); - } - - this->cacRef.initiateAbortShutdown ( *this ); - - break; + stat.bytesCopied = 0u; + stat.circuitState = swioPeerAbort; + return; } } - - return bytesAvailable; } -tcpRecvThread::tcpRecvThread ( class tcpiiu & iiuIn, class callbackMutex & cbMutexIn, - const char * pName, unsigned int stackSize, unsigned int priority ) : +tcpRecvThread::tcpRecvThread ( + class tcpiiu & iiuIn, class epicsMutex & cbMutexIn, + cacContextNotify & ctxNotifyIn, const char * pName, + unsigned int stackSize, unsigned int priority ) : thread ( *this, pName, stackSize, priority ), - iiu ( iiuIn ), cbMutex ( cbMutexIn ) {} + iiu ( iiuIn ), cbMutex ( cbMutexIn ), + ctxNotify ( ctxNotifyIn ) {} tcpRecvThread::~tcpRecvThread () { @@ -347,7 +331,7 @@ void tcpRecvThread::run () epicsThreadPrivateSet ( caClientCallbackThreadId, &this->iiu ); - this->iiu.connect (); + this->connect (); this->iiu.sendThread.start (); @@ -365,7 +349,7 @@ void tcpRecvThread::run () { bool wakeupNeeded = false; { - epicsGuard < epicsMutex > cacGuard ( this->iiu.cacRef.mutexRef() ); + epicsGuard < epicsMutex > cacGuard ( this->iiu.mutex ); if ( this->iiu.subscripReqPend.count() ) { wakeupNeeded = true; } @@ -382,8 +366,38 @@ void tcpRecvThread::run () // file manager call backs works correctly. This does not // appear to impact performance. // - unsigned nBytesIn = pComBuf->fillFromWire ( this->iiu ); - if ( nBytesIn == 0u ) { + statusWireIO stat; + pComBuf->fillFromWire ( this->iiu, stat ); + if ( stat.circuitState != swioConnected ) { + if ( stat.circuitState == swioPeerHangup || + stat.circuitState == swioPeerAbort ) { + this->iiu.disconnectNotify (); + } + else if ( stat.circuitState == swioLinkFailure ) { + callbackManager mgr ( this->ctxNotify, this->cbMutex ); + epicsGuard < epicsMutex > guard ( this->iiu.mutex ); + this->iiu.initiateAbortShutdown ( mgr, guard ); + break; + } + else if ( stat.circuitState == swioLocalAbort ) { + char name[64]; + this->iiu.hostName ( name, sizeof ( name ) ); + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + callbackManager mgr ( this->ctxNotify, this->cbMutex ); + this->iiu.printf ( mgr.cbGuard, + "Unexpected problem with CA circuit to", + " server \"%s\" was \"%s\" - disconnecting\n", + name, sockErrBuf ); + break; + } + else { + assert ( 0 ); + } + } + + if ( stat.bytesCopied == 0u ) { continue; } @@ -395,12 +409,12 @@ void tcpRecvThread::run () // only one recv thread at a time may call callbacks // - pendEvent() blocks until threads waiting for // this lock get a chance to run - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); + callbackManager mgr ( this->ctxNotify, this->cbMutex ); // force the receive watchdog to be reset every 5 frames unsigned contiguousFrameCount = 0; - while ( nBytesIn ) { - if ( nBytesIn == pComBuf->capacityBytes () ) { + while ( stat.bytesCopied ) { + if ( stat.bytesCopied == pComBuf->capacityBytes () ) { if ( this->iiu.contigRecvMsgCount >= contiguousMsgCountWhichTriggersFlowControl ) { this->iiu.busyStateDetected = true; @@ -419,9 +433,10 @@ void tcpRecvThread::run () pComBuf = new ( this->iiu.comBufMemMgr ) comBuf; // execute receive labor - bool protocolOK = this->iiu.processIncoming ( currentTime, cbGuard ); + bool protocolOK = this->iiu.processIncoming ( currentTime, mgr ); if ( ! protocolOK ) { - this->iiu.cacRef.initiateAbortShutdown ( this->iiu ); + epicsGuard < epicsMutex > guard ( this->iiu.mutex ); + this->iiu.initiateAbortShutdown ( mgr, guard ); break; } @@ -430,7 +445,31 @@ void tcpRecvThread::run () break; } - nBytesIn = pComBuf->fillFromWire ( this->iiu ); + pComBuf->fillFromWire ( this->iiu, stat ); + if ( stat.circuitState != swioConnected ) { + if ( stat.circuitState == swioPeerHangup ) { + this->iiu.disconnectNotify (); + } + else if ( stat.circuitState == swioLinkFailure ) { + epicsGuard < epicsMutex > guard ( this->iiu.mutex ); + this->iiu.initiateAbortShutdown ( mgr, guard ); + } + else if ( stat.circuitState == swioLocalAbort ) { + char name[64]; + this->iiu.hostName ( name, sizeof ( name ) ); + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + this->iiu.printf ( mgr.cbGuard, + "Unexpected problem with CA circuit to", + " server \"%s\" was \"%s\" - disconnecting\n", + name, sockErrBuf ); + break; + } + else { + assert ( 0 ); + } + } } } @@ -458,25 +497,79 @@ void tcpRecvThread::run () } } +/* + * tcpRecvThread::connect () + */ +void tcpRecvThread::connect () +{ + // attempt to connect to a CA server + while ( this->iiu.state == tcpiiu::iiucs_connecting ) { + osiSockAddr tmp = this->iiu.address (); + int status = ::connect ( this->iiu.sock, + & tmp.sa, sizeof ( tmp.sa ) ); + if ( status == 0 ) { + bool enteredConnectedState = false; + { + epicsGuard < epicsMutex > autoMutex ( this->iiu.mutex ); + + if ( this->iiu.state == tcpiiu::iiucs_connecting ) { + // put the iiu into the connected state + this->iiu.state = tcpiiu::iiucs_connected; + enteredConnectedState = true; + } + } + if ( enteredConnectedState ) { + // start connection activity watchdog + this->iiu.recvDog.connectNotify (); + } + break; + } + + int errnoCpy = SOCKERRNO; + + if ( errnoCpy == SOCK_EINTR ) { + continue; + } + else if ( errnoCpy == SOCK_SHUTDOWN ) { + break; + } + else { + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + callbackManager mgr ( this->ctxNotify, this->cbMutex ); + this->iiu.printf ( mgr.cbGuard, "Unable to connect because \"%s\"\n", + sockErrBuf ); + this->iiu.disconnectNotify (); + break; + } + } + return; +} + // // tcpiiu::tcpiiu () // -tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, +tcpiiu::tcpiiu ( + cac & cac, epicsMutex & mutexIn, epicsMutex & cbMutexIn, + cacContextNotify & ctxNotifyIn, double connectionTimeout, epicsTimerQueue & timerQueue, const osiSockAddr & addrIn, comBufMemoryManager & comBufMemMgrIn, unsigned minorVersion, ipAddrToAsciiEngine & engineIn, const cacChannel::priLev & priorityIn ) : caServerID ( addrIn.ia, priorityIn ), hostNameCacheInstance ( addrIn, engineIn ), - recvThread ( *this, cbMutex, "CAC-TCP-recv", + recvThread ( *this, cbMutexIn, ctxNotifyIn, "CAC-TCP-recv", epicsThreadGetStackSize ( epicsThreadStackBig ), cac::highestPriorityLevelBelow ( cac.getInitializingThreadsPriority() ) ), - sendThread ( *this, cbMutex, "CAC-TCP-send", + sendThread ( *this, "CAC-TCP-send", epicsThreadGetStackSize ( epicsThreadStackMedium ), cac::lowestPriorityLevelAbove ( cac.getInitializingThreadsPriority() ) ), - recvDog ( cbMutex, cac.mutexRef (), *this, connectionTimeout, timerQueue ), - sendDog ( cbMutex, *this, connectionTimeout, timerQueue ), + recvDog ( cbMutexIn, ctxNotifyIn, mutexIn, + *this, connectionTimeout, timerQueue ), + sendDog ( cbMutexIn, ctxNotifyIn, + *this, connectionTimeout, timerQueue ), sendQue ( *this, comBufMemMgrIn ), recvQue ( comBufMemMgrIn ), curDataMax ( MAX_TCP ), @@ -484,6 +577,8 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, comBufMemMgr ( comBufMemMgrIn ), cacRef ( cac ), pCurData ( cac.allocateSmallBufferTCP () ), + mutex ( mutexIn ), + cbMutex ( cbMutexIn ), minorProtocolVersion ( minorVersion ), state ( iiucs_connecting ), sock ( INVALID_SOCKET ), @@ -508,7 +603,7 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "CAC: unable to create virtual circuit because \"%s\"\n", + errlogPrintf ( "CAC: unable to create virtual circuit because \"%s\"\n", sockErrBuf ); cac.releaseSmallBufferTCP ( this->pCurData ); throw std::bad_alloc (); @@ -521,7 +616,7 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "CAC: problems setting socket option TCP_NODELAY = \"%s\"\n", + errlogPrintf ( "CAC: problems setting socket option TCP_NODELAY = \"%s\"\n", sockErrBuf ); } @@ -532,14 +627,14 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "CAC: problems setting socket option SO_KEEPALIVE = \"%s\"\n", + errlogPrintf ( "CAC: problems setting socket option SO_KEEPALIVE = \"%s\"\n", sockErrBuf ); } // load message queue with messages informing server // of version, user, and host name of client { - epicsGuard < epicsMutex > guard ( this->cacRef.mutexRef() ); + epicsGuard < epicsMutex > guard ( this->mutex ); this->versionMessage ( guard, this->priority() ); this->userNameSetRequest ( guard ); this->hostNameSetRequest ( guard ); @@ -559,7 +654,7 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, if (status < 0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ("CAC: problems setting socket option SO_SNDBUF = \"%s\"\n", + errlogPrintf ("CAC: problems setting socket option SO_SNDBUF = \"%s\"\n", sockErrBuf ); } i = MAX_MSG_SIZE; @@ -568,7 +663,7 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "CAC: problems setting socket option SO_RCVBUF = \"%s\"\n", + errlogPrintf ( "CAC: problems setting socket option SO_RCVBUF = \"%s\"\n", sockErrBuf ); } } @@ -584,7 +679,7 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ("CAC: problems getting socket option SO_SNDBUF = \"%s\"\n", + errlogPrintf ("CAC: problems getting socket option SO_SNDBUF = \"%s\"\n", sockErrBuf ); } else { @@ -624,58 +719,9 @@ void tcpiiu::start () this->recvThread.start (); } -/* - * tcpiiu::connect () - */ -void tcpiiu::connect () -{ - // attempt to connect to a CA server - while ( this->state == iiucs_connecting ) { - osiSockAddr tmp = this->address (); - int status = ::connect ( this->sock, - &tmp.sa, sizeof ( tmp.sa ) ); - if ( status == 0 ) { - bool enteredConnectedState = false; - { - epicsGuard < epicsMutex > autoMutex ( this->cacRef.mutexRef() ); - - if ( this->state == iiucs_connecting ) { - // put the iiu into the connected state - this->state = iiucs_connected; - enteredConnectedState = true; - } - } - if ( enteredConnectedState ) { - // start connection activity watchdog - this->recvDog.connectNotify (); - } - break; - } - - int errnoCpy = SOCKERRNO; - - if ( errnoCpy == SOCK_EINTR ) { - continue; - } - else if ( errnoCpy == SOCK_SHUTDOWN ) { - break; - } - else { - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "Unable to connect because \"%s\"\n", - sockErrBuf ); - this->disconnectNotify (); - break; - } - } - return; -} - void tcpiiu::initiateCleanShutdown ( epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( this->state == iiucs_connected ) { this->state = iiucs_clean_shutdown; this->sendThreadFlushEvent.signal (); @@ -685,17 +731,18 @@ void tcpiiu::initiateCleanShutdown ( epicsGuard < epicsMutex > & guard ) void tcpiiu::disconnectNotify () { { - epicsGuard < epicsMutex > guard ( this->cacRef.mutexRef () ); + epicsGuard < epicsMutex > guard ( this->mutex ); this->state = iiucs_disconnected; } this->sendThreadFlushEvent.signal (); } void tcpiiu::responsiveCircuitNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); while ( nciu * pChan = this->unrespCircuit.get() ) { this->subscripUpdateReqPend.add ( *pChan ); pChan->channelNode::listMember = @@ -707,27 +754,30 @@ void tcpiiu::responsiveCircuitNotify ( void tcpiiu::sendTimeoutNotify ( const epicsTime & currentTime, - epicsGuard < callbackMutex > & cbGuard ) + callbackManager & mgr ) { - epicsGuard < epicsMutex > guard ( this->cacRef.mutexRef() ); - this->unresponsiveCircuitNotify ( cbGuard, guard ); + mgr.cbGuard.assertIdenticalMutex ( this-> cbMutex ); + epicsGuard < epicsMutex > guard ( this->mutex ); + this->unresponsiveCircuitNotify ( mgr.cbGuard, guard ); // setup circuit probe sequence - this->recvDog.sendTimeoutNotify ( cbGuard, guard, currentTime ); + this->recvDog.sendTimeoutNotify ( mgr.cbGuard, guard, currentTime ); } void tcpiiu::receiveTimeoutNotify ( - epicsGuard < callbackMutex > & cbGuard, + callbackManager & mgr, epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); - this->unresponsiveCircuitNotify ( cbGuard, guard ); + mgr.cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); + this->unresponsiveCircuitNotify ( mgr.cbGuard, guard ); } void tcpiiu::unresponsiveCircuitNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! this->unresponsiveCircuit ) { this->unresponsiveCircuit = true; @@ -741,7 +791,8 @@ void tcpiiu::unresponsiveCircuitNotify ( this->hostName ( hostNameTmp, sizeof ( hostNameTmp ) ); { epicsGuardRelease < epicsMutex > guardRelease ( guard ); - genLocalExcep ( cbGuard, this->cacRef, ECA_UNRESPTMO, hostNameTmp ); + genLocalExcep ( cbGuard, guard, this->cacRef, + ECA_UNRESPTMO, hostNameTmp ); } while ( nciu * pChan = this->connectedList.get () ) { // The cac lock is released herein so there is concern that @@ -759,10 +810,12 @@ void tcpiiu::unresponsiveCircuitNotify ( } } -void tcpiiu::initiateAbortShutdown ( epicsGuard < callbackMutex > &, - epicsGuard < epicsMutex > & guard ) +void tcpiiu::initiateAbortShutdown ( + callbackManager & mgr, + epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + mgr.cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! this->discardingPendingData ) { // force abortive shutdown sequence @@ -781,6 +834,7 @@ void tcpiiu::initiateAbortShutdown ( epicsGuard < callbackMutex > &, } this->discardingPendingData = true; } + iiu_conn_state oldState = this->state; if ( oldState != iiucs_abort_shutdown && oldState != iiucs_disconnected ) { this->state = iiucs_abort_shutdown; @@ -824,6 +878,29 @@ void tcpiiu::initiateAbortShutdown ( epicsGuard < callbackMutex > &, // this->sendThreadFlushEvent.signal (); } + + // Disconnect all channels immediately from the timer thread + // because on certain OS such as HPUX it's difficult to + // unblock a blocking send() call, and we need immediate + // disconnect notification. + this->cacRef.disconnectAllChannels ( mgr.cbGuard, guard, *this ); + + char hostNameTmp[64]; + bool exceptionNeeded = false; + int exception = ECA_DISCONN; + + if ( this->channelCount( guard ) ) { + this->hostName ( hostNameTmp, sizeof ( hostNameTmp ) ); + if ( this->connecting () ) { + exception = ECA_CONNSEQTMO; + } + exceptionNeeded = true; + } + + if ( exceptionNeeded ) { + genLocalExcep ( mgr.cbGuard, guard, this->cacRef, + exception, hostNameTmp ); + } } // @@ -851,7 +928,7 @@ tcpiiu::~tcpiiu () void tcpiiu::show ( unsigned level ) const { - epicsGuard < epicsMutex > locker ( this->cacRef.mutexRef() ); + epicsGuard < epicsMutex > locker ( this->mutex ); char buf[256]; this->hostNameCacheInstance.hostName ( buf, sizeof ( buf ) ); ::printf ( "Virtual circuit to \"%s\" at version V%u.%u state %u\n", @@ -919,7 +996,7 @@ void tcpiiu::show ( unsigned level ) const bool tcpiiu::setEchoRequestPending ( epicsGuard < epicsMutex > & guard ) // X aCC 361 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); this->echoRequestPending = true; this->sendThreadFlushEvent.signal (); @@ -935,7 +1012,7 @@ bool tcpiiu::setEchoRequestPending ( epicsGuard < epicsMutex > & guard ) // X aC void tcpiiu::flushIfRecvProcessRequested () { - epicsGuard < epicsMutex > guard ( this->cacRef.mutexRef () ); + epicsGuard < epicsMutex > guard ( this->mutex ); if ( this->recvProcessPostponedFlush ) { this->flushRequest ( guard ); this->recvProcessPostponedFlush = false; @@ -943,8 +1020,11 @@ void tcpiiu::flushIfRecvProcessRequested () } bool tcpiiu::processIncoming ( - const epicsTime & currentTime, epicsGuard < callbackMutex > & guard ) + const epicsTime & currentTime, + callbackManager & mgr ) { + mgr.cbGuard.assertIdenticalMutex ( this->cbMutex ); + while ( true ) { // @@ -997,7 +1077,8 @@ bool tcpiiu::processIncoming ( this->curDataMax = this->cacRef.largeBufferSizeTCP (); } else { - this->printf ("CAC: not enough memory for message body cache (ignoring response message)\n"); + this->printf ( mgr.cbGuard, + "CAC: not enough memory for message body cache (ignoring response message)\n"); } } } @@ -1012,7 +1093,7 @@ bool tcpiiu::processIncoming ( return true; } } - bool msgOK = this->cacRef.executeResponse ( guard, *this, + bool msgOK = this->cacRef.executeResponse ( mgr, *this, currentTime, this->curMsg, this->pCurData ); if ( ! msgOK ) { return false; @@ -1021,7 +1102,7 @@ bool tcpiiu::processIncoming ( else { static bool once = false; if ( ! once ) { - this->printf ( + this->printf ( mgr.cbGuard, "CAC: response with payload size=%u > EPICS_CA_MAX_ARRAY_BYTES ignored\n", this->curMsg.m_postsize ); once = true; @@ -1045,7 +1126,7 @@ bool tcpiiu::processIncoming ( void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! CA_V41 ( this->minorProtocolVersion ) ) { return; @@ -1077,7 +1158,7 @@ void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 4 */ void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! CA_V41 ( this->minorProtocolVersion ) ) { return; @@ -1105,7 +1186,7 @@ void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 4 void tcpiiu::disableFlowControlRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest ( guard ); @@ -1121,7 +1202,7 @@ void tcpiiu::disableFlowControlRequest ( void tcpiiu::enableFlowControlRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest ( guard ); @@ -1137,7 +1218,7 @@ void tcpiiu::enableFlowControlRequest ( void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, // X aCC 431 const cacChannel::priLev & priority ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); assert ( priority <= 0xffff ); @@ -1155,7 +1236,7 @@ void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, // X aCC 431 void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest ( guard ); @@ -1171,7 +1252,7 @@ void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 nciu &chan, unsigned type, arrayElementCount nElem, const void *pValue ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); comQueSendMsgMinder minder ( this->sendQue, guard ); this->sendQue.insertRequestWithPayLoad ( CA_PROTO_WRITE, @@ -1185,7 +1266,7 @@ void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 43 nciu &chan, netWriteNotifyIO &io, unsigned type, arrayElementCount nElem, const void *pValue ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! this->ca_v41_ok () ) { throw cacChannel::unsupportedByService(); @@ -1201,7 +1282,7 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 nciu & chan, netReadNotifyIO & io, unsigned dataType, arrayElementCount nElem ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( INVALID_DB_REQ ( dataType ) ) { throw cacChannel::badType (); @@ -1231,7 +1312,7 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 void tcpiiu::createChannelRequest ( nciu & chan, epicsGuard < epicsMutex > & guard ) // X aCC 431 { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); const char *pName; unsigned nameLength; @@ -1275,7 +1356,7 @@ void tcpiiu::createChannelRequest ( void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 ca_uint32_t sid, ca_uint32_t cid ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); comQueSendMsgMinder minder ( this->sendQue, guard ); this->sendQue.insertRequestHeader ( @@ -1289,18 +1370,18 @@ void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 4 // this routine return void because if this internally fails the best response // is to try again the next time that we reconnect // -void tcpiiu::subscriptionRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 - nciu &chan, netSubscription & subscr ) +void tcpiiu::subscriptionRequest ( + epicsGuard < epicsMutex > & guard, // X aCC 431 + nciu & chan, netSubscription & subscr ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! chan.isConnected ( guard ) ) { return; } unsigned mask = subscr.getMask(); if ( mask > 0xffff ) { - mask &= 0xffff; - this->cacRef.printf ( "CAC: subscriptionRequest() truncated unusual event select mask\n" ); + throw cacChannel::badEventSelection (); } arrayElementCount nElem = subscr.getCount ( guard ); arrayElementCount maxBytes; @@ -1341,7 +1422,7 @@ void tcpiiu::subscriptionRequest ( epicsGuard < epicsMutex > & guard, // X aCC 4 void tcpiiu::subscriptionUpdateRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 nciu & chan, netSubscription & subscr ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! chan.isConnected ( guard ) ) { return; @@ -1374,7 +1455,7 @@ void tcpiiu::subscriptionUpdateRequest ( epicsGuard < epicsMutex > & guard, // X void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 nciu & chan, netSubscription & subscr ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); comQueSendMsgMinder minder ( this->sendQue, guard ); this->sendQue.insertRequestHeader ( @@ -1388,7 +1469,7 @@ void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, // X bool tcpiiu::flush ( epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef() ); + guard.assertIdenticalMutex ( this->mutex ); if ( this->sendQue.occupiedBytes() > 0 ) { while ( comBuf * pBuf = this->sendQue.popNextComBufToSend () ) { @@ -1434,7 +1515,7 @@ bool tcpiiu::flush ( epicsGuard < epicsMutex > & guard ) void tcpiiu::blockUntilSendBacklogIsReasonable ( cacContextNotify & notify, epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); assert ( this->blockingForFlush < UINT_MAX ); this->blockingForFlush++; @@ -1452,7 +1533,7 @@ void tcpiiu::blockUntilSendBacklogIsReasonable ( void tcpiiu::flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); if ( ! this->earlyFlush && this->sendQue.flushEarlyThreshold(0u) ) { this->earlyFlush = true; @@ -1463,7 +1544,7 @@ void tcpiiu::flushRequestIfAboveEarlyThreshold ( bool tcpiiu::flushBlockThreshold ( epicsGuard < epicsMutex > & guard ) const { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); return this->sendQue.flushBlockThreshold ( 0u ); } @@ -1498,11 +1579,12 @@ const char * tcpiiu::pHostName () const } void tcpiiu::removeAllChannels ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, udpiiu & discIIU ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); while ( nciu * pChan = this->createReqPend.get () ) { discIIU.installDisconnectedChannel ( *pChan ); @@ -1541,12 +1623,12 @@ void tcpiiu::removeAllChannels ( } void tcpiiu::installChannel ( - epicsGuard < callbackMutex > &, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, nciu & chan, unsigned sidIn, ca_uint16_t typeIn, arrayElementCount countIn ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); this->createReqPend.add ( chan ); this->channelCountTot++; @@ -1561,7 +1643,7 @@ void tcpiiu::nameResolutionMsgEndNotify () { bool wakeupNeeded = false; { - epicsGuard < epicsMutex > autoMutex ( this->cacRef.mutexRef() ); + epicsGuard < epicsMutex > autoMutex ( this->mutex ); if ( this->createReqPend.count () ) { wakeupNeeded = true; } @@ -1574,7 +1656,7 @@ void tcpiiu::nameResolutionMsgEndNotify () void tcpiiu::connectNotify ( epicsGuard < epicsMutex > & guard, nciu & chan ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->mutex ); this->createRespPend.remove ( chan ); this->subscripReqPend.add ( chan ); @@ -1584,9 +1666,12 @@ void tcpiiu::connectNotify ( } void tcpiiu::uninstallChan ( - epicsGuard < epicsMutex > & guard, nciu & chan ) + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, + nciu & chan ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); + guard.assertIdenticalMutex ( this->mutex ); switch ( chan.channelNode::listMember ) { case channelNode::cs_createReqPend: @@ -1608,7 +1693,7 @@ void tcpiiu::uninstallChan ( this->subscripUpdateReqPend.remove ( chan ); break; default: - this->cacRef.printf ( + this->cacRef.printf ( cbGuard, "cac: attempt to uninstall channel from tcp iiu, but it inst installed there?" ); } chan.channelNode::listMember = channelNode::cs_none; @@ -1618,14 +1703,18 @@ void tcpiiu::uninstallChan ( } } -int tcpiiu::printf ( const char *pformat, ... ) +int tcpiiu::printf ( + epicsGuard < epicsMutex > & cbGuard, + const char *pformat, ... ) { + cbGuard.assertIdenticalMutex ( this->cbMutex ); + va_list theArgs; int status; va_start ( theArgs, pformat ); - status = this->cacRef.vPrintf ( pformat, theArgs ); + status = this->cacRef.vPrintf ( cbGuard, pformat, theArgs ); va_end ( theArgs ); @@ -1640,91 +1729,6 @@ void tcpiiu::flushRequest ( epicsGuard < epicsMutex > & ) } } -void tcpiiu::blockUntilBytesArePendingInOS () -{ -#if 0 - FD_SET readBits; - FD_ZERO ( & readBits ); - while ( this->state == tcpiiu::iiucs_connected || - this->state == iiucs_clean_shutdown ) { - - FD_SET ( this->sock, & readBits ); - struct timeval tmo; - tmo.tv_sec = 1; - tmo.tv_usec = 0; - int status = select ( this->sock + 1, & readBits, NULL, NULL, & tmo ); - if ( status > 0 ) { - if ( FD_ISSET ( this->sock, & readBits ) ) { - return; - } - } - else if ( status < 0 ) { - if ( SOCKERRNO != SOCK_EINTR ) { - return; - } - } - } -#else - while ( this->state == tcpiiu::iiucs_connected || - this->state == iiucs_clean_shutdown ) { - - char buf; - int status = ::recv ( this->sock, - & buf, 1, MSG_PEEK ); - - // if the circuit was aborted then supress warning message about - // bad file descriptor - if ( this->state != iiucs_connected && - this->state != iiucs_clean_shutdown ) { - return; - } - - if ( status > 0 ) { - break; - } - else if ( status == 0 ) { - this->disconnectNotify (); - return; - } - else { - int localErrno = SOCKERRNO; - - if ( localErrno == SOCK_SHUTDOWN ) { - this->disconnectNotify (); - return; - } - - if ( localErrno == SOCK_EINTR ) { - continue; - } - - if ( localErrno == SOCK_ECONNABORTED ) { - this->disconnectNotify (); - return; - } - - if ( localErrno == SOCK_ECONNRESET ) { - this->disconnectNotify (); - return; - } - - { - char name[64]; - this->hostName ( name, sizeof ( name ) ); - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "Unexpected problem with circuit to CA server \"%s\" was \"%s\" - disconnecting\n", - name, sockErrBuf ); - } - - this->cacRef.initiateAbortShutdown ( *this ); - return; - } - } -#endif -} - bool tcpiiu::bytesArePendingInOS () const { #if 0 @@ -1792,9 +1796,9 @@ void tcpiiu::operator delete ( void * /* pCadaver */ ) __FILE__, __LINE__ ); } -// protected by callback lock -unsigned tcpiiu::channelCount ( epicsGuard < callbackMutex > & ) +unsigned tcpiiu::channelCount ( epicsGuard < epicsMutex > & guard ) { + guard.assertIdenticalMutex ( this->mutex ); return this->channelCountTot; } diff --git a/src/ca/udpiiu.cpp b/src/ca/udpiiu.cpp index c31e63f7e..fa2fcd60b 100644 --- a/src/ca/udpiiu.cpp +++ b/src/ca/udpiiu.cpp @@ -66,15 +66,21 @@ const udpiiu::pProtoStubUDP udpiiu::udpJumpTableCAC [] = // // udpiiu::udpiiu () // -udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, cac & cac ) : - recvThread ( *this, cbMutex, - "CAC-UDP", +udpiiu::udpiiu ( + epicsTimerQueueActive & timerQueue, + epicsMutex & cbMutexIn, + epicsMutex & cacMutexIn, + cacContextNotify & ctxNotifyIn, + cac & cac ) : + recvThread ( *this, ctxNotifyIn, cbMutexIn, "CAC-UDP", epicsThreadGetStackSize ( epicsThreadStackMedium ), cac::lowestPriorityLevelAbove ( cac::lowestPriorityLevelAbove ( cac.getInitializingThreadsPriority () ) ) ), rtteMean ( 5.0e-3 ), // seconds cacRef ( cac ), + cbMutex ( cbMutexIn ), + cacMutex ( cacMutexIn ), nBytesInXmitBuf ( 0 ), sequenceNumber ( 0 ), rtteSequenceNumber ( 0 ), @@ -85,7 +91,9 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca // this is much more efficent with recursive locks. Also, access // to the udp's netiiu base list is protected. pSearchTmr ( new searchTimer ( *this, timerQueue, this->mutex ) ), - pRepeaterSubscribeTmr ( new repeaterSubscribeTimer ( *this, timerQueue ) ), + pRepeaterSubscribeTmr ( + new repeaterSubscribeTimer ( + *this, timerQueue, cbMutexIn, ctxNotifyIn ) ), repeaterPort ( 0 ), serverPort ( 0 ), localPort ( 0 ), @@ -111,7 +119,7 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ("CAC: unable to create datagram socket because = \"%s\"\n", + errlogPrintf ("CAC: unable to create datagram socket because = \"%s\"\n", sockErrBuf ); throwWithLocation ( noSocket () ); } @@ -122,7 +130,7 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ("CAC: IP broadcasting enable failed because = \"%s\"\n", + errlogPrintf ("CAC: IP broadcasting enable failed because = \"%s\"\n", sockErrBuf ); } @@ -140,7 +148,7 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca if (status<0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "CAC: unable to set socket option SO_RCVBUF because \"%s\"\n", + errlogPrintf ( "CAC: unable to set socket option SO_RCVBUF because \"%s\"\n", sockErrBuf ); } } @@ -158,7 +166,7 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); epicsSocketDestroy (this->sock); - this->printf ( "CAC: unable to bind to an unconstrained address because = \"%s\"\n", + errlogPrintf ( "CAC: unable to bind to an unconstrained address because = \"%s\"\n", sockErrBuf ); throwWithLocation ( noSocket () ); } @@ -172,12 +180,12 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); epicsSocketDestroy ( this->sock ); - this->printf ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf ); + errlogPrintf ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf ); throwWithLocation ( noSocket () ); } if ( tmpAddr.sa.sa_family != AF_INET) { epicsSocketDestroy ( this->sock ); - this->printf ( "CAC: UDP socket was not inet addr family\n" ); + errlogPrintf ( "CAC: UDP socket was not inet addr family\n" ); throwWithLocation ( noSocket () ); } this->localPort = epicsNTOH16 ( tmpAddr.ia.sin_port ); @@ -262,63 +270,10 @@ void udpiiu::shutdown () } } -// -// udpiiu::recvMsg () -// -void udpiiu::recvMsg ( callbackMutex & cbMutex ) -{ - osiSockAddr src; - osiSocklen_t src_size = sizeof ( src ); - int status = recvfrom ( this->sock, - this->recvBuf, sizeof ( this->recvBuf ), 0, - & src.sa, & src_size ); - - epicsGuard < callbackMutex > guard ( cbMutex ); - - if ( status <= 0 ) { - - if ( status == 0 ) { - return; - } - - int errnoCpy = SOCKERRNO; - - if ( errnoCpy == SOCK_SHUTDOWN ) { - return; - } - if ( errnoCpy == SOCK_ENOTSOCK ) { - return; - } - if ( errnoCpy == SOCK_EBADF ) { - return; - } - if ( errnoCpy == SOCK_EINTR ) { - return; - } - // Avoid spurious ECONNREFUSED bug in linux - if ( errnoCpy == SOCK_ECONNREFUSED ) { - return; - } - // Avoid ECONNRESET from disconnected socket bug - // in windows - if ( errnoCpy == SOCK_ECONNRESET ) { - return; - } - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( "CAC: UDP recv error was \"%s\"\n", - sockErrBuf ); - } - else if ( status > 0 ) { - this->postMsg ( guard, src, this->recvBuf, - (arrayElementCount) status, epicsTime::getCurrent() ); - } -} - -udpRecvThread::udpRecvThread ( udpiiu & iiuIn, callbackMutex & cbMutexIn, +udpRecvThread::udpRecvThread ( + udpiiu & iiuIn, cacContextNotify & ctxNotifyIn, epicsMutex & cbMutexIn, const char * pName, unsigned stackSize, unsigned priority ) : - iiu ( iiuIn ), cbMutex ( cbMutexIn ), + iiu ( iiuIn ), ctxNotify ( ctxNotifyIn ), cbMutex ( cbMutexIn ), thread ( *this, pName, stackSize, priority ) {} udpRecvThread::~udpRecvThread () @@ -340,12 +295,49 @@ void udpRecvThread::run () epicsThreadPrivateSet ( caClientCallbackThreadId, &this->iiu ); if ( ellCount ( & this->iiu.dest ) == 0 ) { // X aCC 392 - epicsGuard < callbackMutex > cbGuard ( this->cbMutex ); - genLocalExcep ( cbGuard, this->iiu.cacRef, ECA_NOSEARCHADDR, NULL ); + callbackManager mgr ( this->ctxNotify, this->cbMutex ); + epicsGuard < epicsMutex > guard ( this->iiu.cacMutex ); + genLocalExcep ( mgr.cbGuard, guard, + this->iiu.cacRef, ECA_NOSEARCHADDR, NULL ); } do { - this->iiu.recvMsg ( this->cbMutex ); + osiSockAddr src; + osiSocklen_t src_size = sizeof ( src ); + int status = recvfrom ( this->iiu.sock, + this->iiu.recvBuf, sizeof ( this->iiu.recvBuf ), 0, + & src.sa, & src_size ); + + callbackManager mgr ( this->ctxNotify, this->cbMutex ); + + if ( status <= 0 ) { + + if ( status < 0 ) { + int errnoCpy = SOCKERRNO; + if ( + errnoCpy != SOCK_EINTR && + errnoCpy != SOCK_SHUTDOWN && + errnoCpy != SOCK_ENOTSOCK && + errnoCpy != SOCK_EBADF && + // Avoid spurious ECONNREFUSED bug in linux + errnoCpy != SOCK_ECONNREFUSED && + // Avoid ECONNRESET from disconnected socket bug + // in windows + errnoCpy != SOCK_ECONNRESET ) { + + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + errlogPrintf ( "CAC: UDP recv error was \"%s\"\n", + sockErrBuf ); + } + } + } + else if ( status > 0 ) { + this->iiu.postMsg ( mgr.cbGuard, src, this->iiu.recvBuf, + (arrayElementCount) status, epicsTime::getCurrent() ); + } + } while ( ! this->iiu.shutdownCmd ); } @@ -548,19 +540,20 @@ void epicsShareAPI caStartRepeaterIfNotInstalled ( unsigned repeaterPort ) } } -bool udpiiu::badUDPRespAction ( epicsGuard < callbackMutex > &, const caHdr &msg, +bool udpiiu::badUDPRespAction ( + epicsGuard < epicsMutex > & guard, const caHdr &msg, const osiSockAddr &netAddr, const epicsTime ¤tTime ) { char buf[64]; sockAddrToDottedIP ( &netAddr.sa, buf, sizeof ( buf ) ); char date[64]; currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S"); - this->printf ( "CAC: Undecipherable ( bad msg code %u ) UDP message from %s at %s\n", + this->printf ( guard, "CAC: Undecipherable ( bad msg code %u ) UDP message from %s at %s\n", msg.m_cmmd, buf, date ); return false; } -bool udpiiu::versionAction ( epicsGuard < callbackMutex > &, +bool udpiiu::versionAction ( epicsGuard < epicsMutex > &, const caHdr & hdr, const osiSockAddr &, const epicsTime & currentTime ) { epicsGuard < udpMutex > guard ( this->mutex ); @@ -586,8 +579,8 @@ bool udpiiu::versionAction ( epicsGuard < callbackMutex > &, } bool udpiiu::searchRespAction ( // X aCC 361 - epicsGuard < callbackMutex > & cbLocker, const caHdr &msg, - const osiSockAddr &addr, const epicsTime & currentTime ) + epicsGuard < epicsMutex > & cbGuard, const caHdr &msg, + const osiSockAddr & addr, const epicsTime & currentTime ) { if ( addr.sa.sa_family != AF_INET ) { return false; @@ -640,12 +633,12 @@ bool udpiiu::searchRespAction ( // X aCC 361 bool success; if ( CA_V42 ( minorVersion ) ) { success = this->cacRef.transferChanToVirtCircuit - ( cbLocker, msg.m_available, msg.m_cid, 0xffff, + ( cbGuard, msg.m_available, msg.m_cid, 0xffff, 0, minorVersion, serverAddr ); } else { success = this->cacRef.transferChanToVirtCircuit - ( cbLocker, msg.m_available, msg.m_cid, msg.m_dataType, + ( cbGuard, msg.m_available, msg.m_cid, msg.m_dataType, msg.m_count, minorVersion, serverAddr ); } @@ -660,7 +653,7 @@ bool udpiiu::searchRespAction ( // X aCC 361 return true; } -bool udpiiu::beaconAction ( epicsGuard < callbackMutex > &, const caHdr &msg, +bool udpiiu::beaconAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &net_addr, const epicsTime ¤tTime ) { struct sockaddr_in ina; @@ -704,21 +697,22 @@ bool udpiiu::beaconAction ( epicsGuard < callbackMutex > &, const caHdr &msg, return true; } -bool udpiiu::repeaterAckAction ( epicsGuard < callbackMutex > &, const caHdr &, +bool udpiiu::repeaterAckAction ( epicsGuard < epicsMutex > &, const caHdr &, const osiSockAddr &, const epicsTime &) { this->cacRef.repeaterSubscribeConfirmNotify (); return true; } -bool udpiiu::notHereRespAction ( epicsGuard < callbackMutex > &, const caHdr &, +bool udpiiu::notHereRespAction ( epicsGuard < epicsMutex > &, const caHdr &, const osiSockAddr &, const epicsTime & ) { return true; } -bool udpiiu::exceptionRespAction ( epicsGuard < callbackMutex > &, const caHdr &msg, - const osiSockAddr &net_addr, const epicsTime ¤tTime ) +bool udpiiu::exceptionRespAction ( + epicsGuard < epicsMutex > & cbGuard, const caHdr &msg, + const osiSockAddr & net_addr, const epicsTime & currentTime ) { const caHdr &reqMsg = * ( &msg + 1 ); char name[64]; @@ -727,19 +721,21 @@ bool udpiiu::exceptionRespAction ( epicsGuard < callbackMutex > &, const caHdr & currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S"); if ( msg.m_postsize > sizeof ( caHdr ) ){ - errlogPrintf ( "error condition \"%s\" detected by %s with context \"%s\" at %s\n", + this->cacRef.printf ( cbGuard, + "error condition \"%s\" detected by %s with context \"%s\" at %s\n", ca_message ( msg.m_available ), name, reinterpret_cast ( &reqMsg + 1 ), date ); } else{ - errlogPrintf ( "error condition \"%s\" detected by %s at %s\n", + this->cacRef.printf ( cbGuard, + "error condition \"%s\" detected by %s at %s\n", ca_message ( msg.m_available ), name, date ); } return true; } -void udpiiu::postMsg ( epicsGuard < callbackMutex > & guard, +void udpiiu::postMsg ( epicsGuard < epicsMutex > & guard, const osiSockAddr & net_addr, char * pInBuf, arrayElementCount blockSize, const epicsTime & currentTime ) @@ -755,7 +751,7 @@ void udpiiu::postMsg ( epicsGuard < callbackMutex > & guard, if ( blockSize < sizeof ( *pCurMsg ) ) { char buf[64]; sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) ); - this->printf ( + this->printf ( guard, "%s: Undecipherable (too small) UDP msg from %s ignored\n", __FILE__, buf ); return; @@ -792,7 +788,7 @@ void udpiiu::postMsg ( epicsGuard < callbackMutex > & guard, if ( size > blockSize ) { char buf[64]; sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) ); - this->printf ( + this->printf ( guard, "%s: Undecipherable (payload too small) UDP msg from %s ignored\n", __FILE__, buf ); return; @@ -812,7 +808,7 @@ void udpiiu::postMsg ( epicsGuard < callbackMutex > & guard, if ( ! success ) { char buf[256]; sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) ); - this->printf ( "CAC: Undecipherable UDP message from %s\n", buf ); + this->printf ( guard, "CAC: Undecipherable UDP message from %s\n", buf ); return; } @@ -837,7 +833,8 @@ bool udpiiu::pushVersionMsg () return pushDatagramMsg ( msg, 0, 0 ); } -bool udpiiu::pushDatagramMsg ( const caHdr & msg, const void *pExt, ca_uint16_t extsize ) +bool udpiiu::pushDatagramMsg ( const caHdr & msg, + const void * pExt, ca_uint16_t extsize ) { epicsGuard < udpMutex > guard ( this->mutex ); @@ -898,7 +895,7 @@ void udpiiu::datagramFlush ( &pNode->addr.sa, sizeof ( pNode->addr.sa ) ); if ( status != (int) this->nBytesInXmitBuf ) { if ( status >= 0 ) { - this->printf ( "CAC: UDP sendto () call returned strange xmit count?\n" ); + errlogPrintf ( "CAC: UDP sendto () call returned strange xmit count?\n" ); break; } else { @@ -927,7 +924,7 @@ void udpiiu::datagramFlush ( char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - this->printf ( + errlogPrintf ( "CAC: error = \"%s\" sending UDP msg to %s\n", sockErrBuf, buf); break; @@ -1111,14 +1108,15 @@ void udpiiu::govExpireNotify ( const epicsTime & currentTime ) } } -int udpiiu::printf ( const char *pformat, ... ) +int udpiiu::printf ( epicsGuard < epicsMutex > & cbGuard, + const char * pformat, ... ) { va_list theArgs; int status; va_start ( theArgs, pformat ); - status = this->cacRef.vPrintf ( pformat, theArgs ); + status = this->cacRef.vPrintf ( cbGuard, pformat, theArgs ); va_end ( theArgs ); @@ -1126,9 +1124,12 @@ int udpiiu::printf ( const char *pformat, ... ) } void udpiiu::uninstallChan ( - epicsGuard < epicsMutex > & guardIn, nciu & chan ) + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & cacGuard, + nciu & chan ) { - guardIn.assertIdenticalMutex ( this->cacRef.mutexRef () ); + cbGuard.assertIdenticalMutex ( this->cbMutex ); + cacGuard.assertIdenticalMutex ( this->cacMutex ); epicsGuard < udpMutex > guard ( this->mutex ); if ( chan.channelNode::listMember == channelNode::cs_disconnGov ) { @@ -1138,7 +1139,7 @@ void udpiiu::uninstallChan ( this->serverAddrRes.remove ( chan ); } else { - this->cacRef.printf ( + this->cacRef.printf ( cbGuard, "cac: attempt to uninstall channel from udp iiu, but it inst installed there?" ); } chan.channelNode::listMember = channelNode::cs_none; @@ -1167,35 +1168,35 @@ bool udpiiu::ca_v41_ok () const void udpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, unsigned type, arrayElementCount nElem, const void * pValue ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::writeRequest ( guard, chan, type, nElem, pValue ); } void udpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, netWriteNotifyIO & io, unsigned type, arrayElementCount nElem, const void *pValue ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::writeNotifyRequest ( guard, chan, io, type, nElem, pValue ); } void udpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, netReadNotifyIO & io, unsigned type, arrayElementCount nElem ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::readNotifyRequest ( guard, chan, io, type, nElem ); } void udpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, ca_uint32_t sid, ca_uint32_t cid ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::clearChannelRequest ( guard, sid, cid ); } void udpiiu::subscriptionRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, netSubscription & subscr ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::subscriptionRequest ( guard, chan, subscr ); } @@ -1207,7 +1208,7 @@ void udpiiu::subscriptionUpdateRequest ( epicsGuard < epicsMutex > &, nciu &, void udpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, netSubscription & subscr ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::subscriptionCancelRequest ( guard, chan, subscr ); } @@ -1218,20 +1219,20 @@ void udpiiu::flushRequest ( epicsGuard < epicsMutex > & guard ) bool udpiiu::flushBlockThreshold ( epicsGuard < epicsMutex > & guard ) const { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); return netiiu::flushBlockThreshold ( guard ); } void udpiiu::flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::flushRequestIfAboveEarlyThreshold ( guard ); } void udpiiu::blockUntilSendBacklogIsReasonable ( cacContextNotify & notify, epicsGuard < epicsMutex > & guard ) { - guard.assertIdenticalMutex ( this->cacRef.mutexRef () ); + guard.assertIdenticalMutex ( this->cacMutex ); netiiu::blockUntilSendBacklogIsReasonable ( notify, guard ); } diff --git a/src/ca/udpiiu.h b/src/ca/udpiiu.h index 60b677a1b..319ff6a19 100644 --- a/src/ca/udpiiu.h +++ b/src/ca/udpiiu.h @@ -53,20 +53,22 @@ epicsShareFunc void epicsShareAPI caRepeaterRegistrationMessage ( SOCKET sock, u extern "C" epicsShareFunc void caRepeaterThread ( void *pDummy ); epicsShareFunc void ca_repeater ( void ); -class epicsTime; -class callbackMutex; +class cac; +class cacContextNotify; class udpRecvThread : public epicsThreadRunable { public: - udpRecvThread ( class udpiiu & iiuIn, callbackMutex & cbMutexIn, + udpRecvThread ( + class udpiiu & iiuIn, cacContextNotify &, epicsMutex &, const char * pName, unsigned stackSize, unsigned priority ); virtual ~udpRecvThread (); void start (); bool exitWait ( double delay ); private: class udpiiu & iiu; - callbackMutex & cbMutex; + epicsMutex & cbMutex; + cacContextNotify & ctxNotify; epicsThread thread; void run(); }; @@ -82,7 +84,12 @@ private: class udpiiu : public netiiu { public: - udpiiu ( class epicsTimerQueueActive &, callbackMutex &, class cac & ); + udpiiu ( + class epicsTimerQueueActive &, + epicsMutex & callbackControl, + epicsMutex & mutualExclusion, + cacContextNotify &, + class cac & ); virtual ~udpiiu (); void installNewChannel ( const epicsTime & currentTime, nciu & ); void installDisconnectedChannel ( nciu & ); @@ -95,13 +102,16 @@ public: void repeaterConfirmNotify (); void beaconAnomalyNotify ( const epicsTime & currentTime ); void govExpireNotify ( const epicsTime & currentTime ); - int printf ( const char *pformat, ... ); unsigned unresolvedChannelCount ( epicsGuard < udpMutex > & ) const; - void uninstallChan ( epicsGuard < epicsMutex > &, nciu & ); + void uninstallChan ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, + nciu & ); bool pushDatagramMsg ( const caHdr & hdr, const void * pExt, ca_uint16_t extsize); void shutdown (); double roundTripDelayEstimate ( epicsGuard < udpMutex > & ) const; + int printf ( epicsGuard < epicsMutex > & callbackControl, const char *pformat, ... ); // exceptions class noSocket {}; @@ -118,6 +128,8 @@ private: epicsTime rtteTimeStamp; double rtteMean; cac & cacRef; + mutable epicsMutex & cbMutex; + mutable epicsMutex & cacMutex; unsigned nBytesInXmitBuf; ca_uint32_t sequenceNumber; ca_uint32_t rtteSequenceNumber; @@ -133,33 +145,32 @@ private: bool rtteActive; bool lastReceivedSeqNoIsValid; - void recvMsg ( callbackMutex & ); - void postMsg ( epicsGuard < callbackMutex > &, + void postMsg ( epicsGuard < epicsMutex > &, const osiSockAddr & net_addr, char *pInBuf, arrayElementCount blockSize, const epicsTime ¤Time ); typedef bool ( udpiiu::*pProtoStubUDP ) ( - epicsGuard < callbackMutex > &, const caHdr &, + epicsGuard < epicsMutex > &, const caHdr &, const osiSockAddr &, const epicsTime & ); // UDP protocol dispatch table static const pProtoStubUDP udpJumpTableCAC[]; // UDP protocol stubs - bool versionAction ( epicsGuard < callbackMutex > &, const caHdr &, + bool versionAction ( epicsGuard < epicsMutex > &, const caHdr &, const osiSockAddr &, const epicsTime & ); - bool badUDPRespAction ( epicsGuard < callbackMutex > &, const caHdr &msg, + bool badUDPRespAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &netAddr, const epicsTime & ); - bool searchRespAction ( epicsGuard < callbackMutex > &, const caHdr &msg, + bool searchRespAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &net_addr, const epicsTime & ); - bool exceptionRespAction ( epicsGuard < callbackMutex > &, const caHdr &msg, + bool exceptionRespAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &net_addr, const epicsTime & ); - bool beaconAction ( epicsGuard < callbackMutex > &, const caHdr &msg, + bool beaconAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &net_addr, const epicsTime & ); - bool notHereRespAction ( epicsGuard < callbackMutex > &, const caHdr &msg, + bool notHereRespAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &net_addr, const epicsTime & ); - bool repeaterAckAction ( epicsGuard < callbackMutex > &, const caHdr &msg, + bool repeaterAckAction ( epicsGuard < epicsMutex > &, const caHdr &msg, const osiSockAddr &net_addr, const epicsTime & ); friend void udpRecvThread::run (); diff --git a/src/ca/virtualCircuit.h b/src/ca/virtualCircuit.h index c24a6a56a..d8e364624 100644 --- a/src/ca/virtualCircuit.h +++ b/src/ca/virtualCircuit.h @@ -40,6 +40,8 @@ #include "hostNameCache.h" #include "compilerDependencies.h" +class callbackManager; + // a modified ca header with capacity for large arrays struct caHdrLargeArray { ca_uint32_t m_postsize; // size of message extension @@ -52,11 +54,11 @@ struct caHdrLargeArray { class hostNameCache; class ipAddrToAsciiEngine; -class callbackMutex; class tcpRecvThread : public epicsThreadRunable { public: - tcpRecvThread ( class tcpiiu & iiuIn, callbackMutex & cbMutexIn, + tcpRecvThread ( + class tcpiiu & iiuIn, epicsMutex & cbMutexIn, cacContextNotify &, const char * pName, unsigned int stackSize, unsigned int priority ); virtual ~tcpRecvThread (); void start (); @@ -65,15 +67,17 @@ public: private: epicsThread thread; class tcpiiu & iiu; - callbackMutex & cbMutex; + epicsMutex & cbMutex; + cacContextNotify & ctxNotify; void run (); + void connect (); }; class tcpSendThread : public epicsThreadRunable { public: - tcpSendThread ( class tcpiiu & iiuIn, callbackMutex &, - const char * pName, unsigned int stackSize, - unsigned int priority ); + tcpSendThread ( + class tcpiiu & iiuIn, const char * pName, + unsigned int stackSize, unsigned int priority ); virtual ~tcpSendThread (); void start (); void exitWait (); @@ -82,7 +86,6 @@ public: private: epicsThread thread; class tcpiiu & iiu; - callbackMutex & cbMutex; void run (); }; @@ -91,29 +94,32 @@ class tcpiiu : public tsSLNode < tcpiiu >, public caServerID, private wireSendAdapter, private wireRecvAdapter { public: - tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout, - epicsTimerQueue & timerQueue, const osiSockAddr & addrIn, - comBufMemoryManager &, unsigned minorVersion, ipAddrToAsciiEngine & engineIn, - const cacChannel::priLev & priorityIn ); + tcpiiu ( cac & cac, epicsMutex & mutualExclusion, epicsMutex & callbackControl, + cacContextNotify &, double connectionTimeout, epicsTimerQueue & timerQueue, + const osiSockAddr & addrIn, comBufMemoryManager &, unsigned minorVersion, + ipAddrToAsciiEngine & engineIn, const cacChannel::priLev & priorityIn ); ~tcpiiu (); void start (); - void initiateCleanShutdown ( epicsGuard < epicsMutex > & ); - void initiateAbortShutdown ( epicsGuard < callbackMutex > &, - epicsGuard < epicsMutex > & ); + void initiateCleanShutdown ( + epicsGuard < epicsMutex > & ); + void initiateAbortShutdown ( + callbackManager &, + epicsGuard < epicsMutex > & ); void responsiveCircuitNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void sendTimeoutNotify ( const epicsTime & currentTime, - epicsGuard < callbackMutex > & cbGuard ); + void sendTimeoutNotify ( + const epicsTime & currentTime, + callbackManager & ); void receiveTimeoutNotify( - epicsGuard < callbackMutex > & cbGuard, + callbackManager &, epicsGuard < epicsMutex > & ); void beaconAnomalyNotify ( epicsGuard < epicsMutex > & ); void beaconArrivalNotify ( epicsGuard < epicsMutex > &, const epicsTime & currentTime ); void probeResponseNotify ( - epicsGuard < callbackMutex > &, + epicsGuard < epicsMutex > &, const epicsTime & currentTime ); void flushRequest ( epicsGuard < epicsMutex > & ); @@ -136,15 +142,17 @@ public: bool alive () const; bool connecting () const; osiSockAddr getNetworkAddress () const; - int printf ( const char *pformat, ... ); - unsigned channelCount ( epicsGuard < callbackMutex > & ); + int printf ( epicsGuard < epicsMutex > & cbGuard, + const char *pformat, ... ); + unsigned channelCount ( epicsGuard < epicsMutex > & ); void removeAllChannels ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, udpiiu & ); - void installChannel ( epicsGuard < callbackMutex > &, + void installChannel ( epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > &, nciu & chan, unsigned sidIn, ca_uint16_t typeIn, arrayElementCount countIn ); - void uninstallChan ( epicsGuard < epicsMutex > &, nciu & chan ); + void uninstallChan ( epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, nciu & chan ); void connectNotify ( epicsGuard < epicsMutex > &, nciu & chan ); void nameResolutionMsgEndNotify (); @@ -177,6 +185,8 @@ private: comBufMemoryManager & comBufMemMgr; cac & cacRef; char * pCurData; + epicsMutex & mutex; + epicsMutex & cbMutex; unsigned minorProtocolVersion; enum iiu_conn_state { iiucs_connecting, // pending circuit connect @@ -205,16 +215,15 @@ private: bool unresponsiveCircuit; bool processIncoming ( - const epicsTime & currentTime, epicsGuard < callbackMutex > & ); + const epicsTime & currentTime, callbackManager & ); unsigned sendBytes ( const void *pBuf, unsigned nBytesInBuf, const epicsTime & currentTime ); - unsigned recvBytes ( void *pBuf, unsigned nBytesInBuf ); - void connect (); + void recvBytes ( + void * pBuf, unsigned nBytesInBuf, statusWireIO & ); const char * pHostName () const; - void blockUntilBytesArePendingInOS (); double receiveWatchdogDelay () const; void unresponsiveCircuitNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); void disconnectNotify (); @@ -243,6 +252,7 @@ private: bool flush ( epicsGuard < epicsMutex > & ); // only to be called by the send thread friend void tcpRecvThread::run (); + friend void tcpRecvThread::connect (); friend void tcpSendThread::run (); tcpiiu ( const tcpiiu & ); @@ -305,7 +315,7 @@ inline void tcpiiu::beaconArrivalNotify ( } inline void tcpiiu::probeResponseNotify ( - epicsGuard < callbackMutex > & cbGuard, + epicsGuard < epicsMutex > & cbGuard, const epicsTime & currentTime ) { this->recvDog.probeResponseNotify ( cbGuard, currentTime ); diff --git a/src/db/dbCAC.h b/src/db/dbCAC.h index 3579b73c1..0ed929ec9 100644 --- a/src/db/dbCAC.h +++ b/src/db/dbCAC.h @@ -117,6 +117,7 @@ class dbContext; class dbContextPrivateListOfIO { public: dbContextPrivateListOfIO (); + ~dbContextPrivateListOfIO (); private: tsDLList < dbSubscriptionIO > eventq; dbPutNotifyBlocker * pBlocker; @@ -145,7 +146,8 @@ private: class dbContext : public cacContext { public: - dbContext ( epicsMutex & mutex, cacContextNotify & notify ); + dbContext ( epicsMutex & cbMutex, epicsMutex & mutex, + cacContextNotify & notify ); virtual ~dbContext (); void destroyChannel ( epicsGuard < epicsMutex > &, dbChannelIO & ); void callReadNotify ( epicsGuard < epicsMutex > &, @@ -179,6 +181,7 @@ private: dbEventCtx ctx; unsigned long stateNotifyCacheSize; mutable epicsMutex & mutex; + mutable epicsMutex & cbMutex; cacContextNotify & notify; epics_auto_ptr < cacContext > pNetContext; char * pStateNotifyCache; @@ -207,6 +210,11 @@ inline dbContextPrivateListOfIO::dbContextPrivateListOfIO () : { } +inline dbContextPrivateListOfIO::~dbContextPrivateListOfIO () +{ + assert ( ! this->pBlocker ); +} + inline void dbContext::callReadNotify ( epicsGuard < epicsMutex > & guard, struct dbAddr &addr, unsigned type, unsigned long count, cacReadNotify & notify ) diff --git a/src/db/dbChannelIO.cpp b/src/db/dbChannelIO.cpp index e8f1ee420..0ed2429a9 100644 --- a/src/db/dbChannelIO.cpp +++ b/src/db/dbChannelIO.cpp @@ -65,15 +65,16 @@ void dbChannelIO::destructor ( epicsGuard < epicsMutex > & guard ) this->~dbChannelIO (); } -void dbChannelIO::destroy ( epicsGuard < epicsMutex > & guard ) +void dbChannelIO::destroy ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) { - guard.assertIdenticalMutex ( this->mutex ); - this->serviceIO.destroyChannel ( guard, *this ); + mutualExclusionGuard.assertIdenticalMutex ( this->mutex ); + this->serviceIO.destroyChannel ( mutualExclusionGuard, *this ); // dont access this pointer after above call because // object nolonger exists } - cacChannel::ioStatus dbChannelIO::read ( epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count, cacReadNotify & notify, ioid * ) @@ -129,10 +130,12 @@ void dbChannelIO::subscribe ( } void dbChannelIO::ioCancel ( - epicsGuard < epicsMutex > & guard, const ioid & id ) + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const ioid & id ) { - guard.assertIdenticalMutex ( this->mutex ); - this->serviceIO.ioCancel ( guard, *this, id ); + mutualExclusionGuard.assertIdenticalMutex ( this->mutex ); + this->serviceIO.ioCancel ( mutualExclusionGuard, *this, id ); } void dbChannelIO::ioShow ( diff --git a/src/db/dbChannelIO.h b/src/db/dbChannelIO.h index d8acf9135..2c0f1caf8 100644 --- a/src/db/dbChannelIO.h +++ b/src/db/dbChannelIO.h @@ -46,7 +46,9 @@ public: dbChannelIO ( epicsMutex &, cacChannelNotify &, const dbAddr &, dbContext & ); void destructor ( epicsGuard < epicsMutex > & ); - void destroy ( epicsGuard < epicsMutex > & ); + void destroy ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ); void callReadNotify ( epicsGuard < epicsMutex > &, unsigned type, unsigned long count, cacReadNotify & notify ); @@ -76,7 +78,9 @@ private: void subscribe ( epicsGuard < epicsMutex > &, unsigned type, unsigned long count, unsigned mask, cacStateNotify ¬ify, ioid * ); - void ioCancel ( epicsGuard < epicsMutex > &, + void ioCancel ( + epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, const ioid & ); void ioShow ( const ioid &, unsigned level ) const; diff --git a/src/db/dbContext.cpp b/src/db/dbContext.cpp index 4f24dd4ea..44e25d406 100644 --- a/src/db/dbContext.cpp +++ b/src/db/dbContext.cpp @@ -44,15 +44,20 @@ class dbService : public cacService { public: cacContext & contextCreate ( - epicsMutex &, cacContextNotify & ); + epicsMutex & mutualExclusion, + epicsMutex & callbackControl, + cacContextNotify & ); }; static dbService dbs; cacContext & dbService::contextCreate ( - epicsMutex & mutex, cacContextNotify & notify ) + epicsMutex & mutualExclusion, + epicsMutex & callbackControl, + cacContextNotify & notify ) { - return * new dbContext ( mutex, notify ); + return * new dbContext ( callbackControl, + mutualExclusion, notify ); } extern "C" void dbServiceIOInit () @@ -62,9 +67,10 @@ extern "C" void dbServiceIOInit () dbBaseIO::dbBaseIO () {} -dbContext::dbContext ( epicsMutex & mutexIn, cacContextNotify & notifyIn ) : +dbContext::dbContext ( epicsMutex & cbMutexIn, + epicsMutex & mutexIn, cacContextNotify & notifyIn ) : readNotifyCache ( mutexIn ), ctx ( 0 ), - stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), + stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), cbMutex ( cbMutexIn ), notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 ) { } @@ -94,7 +100,8 @@ cacChannel & dbContext::createChannel ( // X aCC 361 if ( status ) { if ( ! this->pNetContext.get() ) { this->pNetContext.reset ( - & this->notify.createNetworkContext ( this->mutex ) ); + & this->notify.createNetworkContext ( + this->mutex, this->cbMutex ) ); } return this->pNetContext->createChannel ( guard, pName, notifyIn, priority ); @@ -115,6 +122,14 @@ void dbContext::destroyChannel ( epicsGuard < epicsMutex > & guard, dbChannelIO & chan ) { guard.assertIdenticalMutex ( this->mutex ); + + if ( chan.dbContextPrivateListOfIO::pBlocker ) { + this->ioTable.remove ( *chan.dbContextPrivateListOfIO::pBlocker ); + chan.dbContextPrivateListOfIO::pBlocker->destructor ( guard ); + this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker ); + chan.dbContextPrivateListOfIO::pBlocker = 0; + } + chan.destructor ( guard ); this->dbChannelIOFreeList.release ( & chan ); }