diff --git a/src/ca/CASG.cpp b/src/ca/CASG.cpp index 16573d1bc..f5cb64e0e 100644 --- a/src/ca/CASG.cpp +++ b/src/ca/CASG.cpp @@ -25,8 +25,6 @@ #include "cac.h" #include "sgAutoPtr.h" -casgRecycle::~casgRecycle () {} - CASG::CASG ( epicsGuard < epicsMutex > & guard, ca_client_context & cacIn ) : client ( cacIn ), magic ( CASG_MAGIC ) { @@ -38,12 +36,13 @@ CASG::~CASG () } void CASG::destructor ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); if ( this->verify ( guard ) ) { - this->reset ( guard ); + this->reset ( cbGuard, guard ); this->client.uninstallCASG ( guard, *this ); this->magic = 0; } @@ -127,36 +126,37 @@ int CASG::block ( delay = cur_time - beg_time; } - this->reset ( guard ); - return status; } void CASG::reset ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); - this->destroyCompletedIO ( guard ); - this->destroyPendingIO ( guard ); + this->destroyCompletedIO ( cbGuard, guard ); + this->destroyPendingIO ( cbGuard, guard ); } // lock must be applied void CASG::destroyCompletedIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); syncGroupNotify * pNotify; while ( ( pNotify = this->ioCompletedList.get () ) ) { - pNotify->destroy ( guard, * this ); + pNotify->destroy ( cbGuard, guard ); } } void CASG::destroyPendingIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) { - pNotify->cancel ( guard ); + pNotify->cancel ( cbGuard, guard ); // cancel must release the guard while // canceling put callbacks so we // must double check list membership @@ -166,7 +166,7 @@ void CASG::destroyPendingIO ( else { this->ioCompletedList.remove ( *pNotify ); } - pNotify->destroy ( guard, *this ); + pNotify->destroy ( cbGuard, guard ); } } @@ -201,10 +201,11 @@ void CASG::show ( } bool CASG::ioComplete ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); - this->destroyCompletedIO ( guard ); + this->destroyCompletedIO ( cbGuard, guard ); return this->ioPendingList.count () == 0u; } @@ -212,9 +213,9 @@ void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan, unsigned type, arrayElementCount count, const void * pValue ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); - sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this, this->ioPendingList ); + sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this ); pNotify = syncGroupWriteNotify::factory ( - this->freeListWriteOP, *this, pChan ); + this->freeListWriteOP, *this, & CASG :: recycleWriteNotifyIO, pChan ); pNotify->begin ( guard, type, count, pValue ); pNotify.release (); } @@ -223,9 +224,9 @@ void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan, unsigned type, arrayElementCount count, void *pValue ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); - sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this, this->ioPendingList ); + sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this ); pNotify = syncGroupReadNotify::factory ( - this->freeListReadOP, *this, pChan, pValue ); + this->freeListReadOP, *this, & CASG :: recycleReadNotifyIO, pChan, pValue ); pNotify->begin ( guard, type, count ); pNotify.release (); } @@ -241,20 +242,20 @@ void CASG::completionNotify ( } } -void CASG::recycleSyncGroupWriteNotify ( - epicsGuard < epicsMutex > & guard, syncGroupWriteNotify & io ) -{ - guard.assertIdenticalMutex ( this->client.mutexRef() ); - this->freeListWriteOP.release ( & io ); -} - -void CASG::recycleSyncGroupReadNotify ( - epicsGuard < epicsMutex > & guard, syncGroupReadNotify & io ) +void CASG :: recycleReadNotifyIO ( epicsGuard < epicsMutex > & guard, + syncGroupReadNotify & io ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); this->freeListReadOP.release ( & io ); } +void CASG :: recycleWriteNotifyIO ( epicsGuard < epicsMutex > & guard, + syncGroupWriteNotify & io ) +{ + guard.assertIdenticalMutex ( this->client.mutexRef() ); + this->freeListWriteOP.release ( & io ); +} + int CASG :: printFormated ( const char *pformat, ... ) { va_list theArgs; @@ -295,13 +296,6 @@ void CASG::exception ( } } -void * CASG::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void CASG::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/access.cpp b/src/ca/access.cpp index 85fe2b205..74f74325a 100644 --- a/src/ca/access.cpp +++ b/src/ca/access.cpp @@ -376,15 +376,35 @@ int epicsShareAPI ca_create_channel ( int epicsShareAPI ca_clear_channel ( chid pChan ) { ca_client_context & cac = pChan->getClientCtx (); - epicsGuard < epicsMutex > guard ( cac.mutex ); - try { - pChan->eliminateExcessiveSendBacklog ( guard ); + { + epicsGuard < epicsMutex > guard ( cac.mutex ); + try { + pChan->eliminateExcessiveSendBacklog ( guard ); + } + catch ( cacChannel::notConnected & ) { + // intentionally ignored + } } - catch ( cacChannel::notConnected & ) { - // intentionally ignored - } - pChan->destructor ( guard ); + if ( cac.pCallbackGuard.get() && + cac.createdByThread == epicsThreadGetIdSelf () ) { + epicsGuard < epicsMutex > guard ( cac.mutex ); + pChan->destructor ( *cac.pCallbackGuard.get(), guard ); cac.oldChannelNotifyFreeList.release ( pChan ); + } + else { + // + // we will definately stall out here if all of the + // following are true + // + // o user creates non-preemtive mode client library context + // o user doesnt periodically call a ca function + // o user calls this function from an auxiillary thread + // + CallbackGuard cbGuard ( cac.cbMutex ); + epicsGuard < epicsMutex > guard ( cac.mutex ); + pChan->destructor ( *cac.pCallbackGuard.get(), guard ); + cac.oldChannelNotifyFreeList.release ( pChan ); + } return ECA_NORMAL; } @@ -433,7 +453,7 @@ chid epicsShareAPI ca_evid_to_chid ( evid pMon ) } // extern "C" -int epicsShareAPI ca_pend ( ca_real timeout, int early ) // X aCC 361 +int epicsShareAPI ca_pend ( ca_real timeout, int early ) { if ( early ) { return ca_pend_io ( timeout ); @@ -516,7 +536,7 @@ int epicsShareAPI ca_flush_io () /* * CA_TEST_IO () */ -int epicsShareAPI ca_test_io () // X aCC 361 +int epicsShareAPI ca_test_io () { ca_client_context *pcac; int caStatus = fetchClientContext ( &pcac ); @@ -551,7 +571,7 @@ void epicsShareAPI ca_signal ( long ca_status, const char *message ) * (if they call this routine again). */ // extern "C" -const char * epicsShareAPI ca_message ( long ca_status ) // X aCC 361 +const char * epicsShareAPI ca_message ( long ca_status ) { unsigned msgNo = CA_EXTRACT_MSG_NO ( ca_status ); diff --git a/src/ca/acctst.c b/src/ca/acctst.c index f2d102868..a01ee131d 100644 --- a/src/ca/acctst.c +++ b/src/ca/acctst.c @@ -13,6 +13,7 @@ * Authors: * Jeff Hill * Murali Shankar - initial versions of verifyMultithreadSubscr + * Michael Abbott - initial versions of multiSubscrDestroyNoLateCallbackTest * */ @@ -1328,6 +1329,158 @@ void test_sync_groups ( chid chan, unsigned interestLevel ) showProgressEnd ( interestLevel ); } +#define multiSubscrDestroyNoLateCallbackEventCount 500 + +struct MultiSubscrDestroyNoLateCallbackEventData { + evid m_id; + size_t m_nCallback; + int m_callbackIsOk; + struct MultiSubscrDestroyNoLateCallbackTestData * m_pTestData; +}; + +struct MultiSubscrDestroyNoLateCallbackTestData { + const char * m_pChanName; + chid m_chan; + epicsMutexId m_mutex; + epicsEventId m_testDoneEvent; + unsigned m_interestLevel; + struct MultiSubscrDestroyNoLateCallbackEventData + m_eventData [multiSubscrDestroyNoLateCallbackEventCount]; +}; + +static void noLateCallbackDetect ( struct event_handler_args args ) +{ + int callbackIsOk; + struct MultiSubscrDestroyNoLateCallbackEventData * const pEventData = args.usr; + epicsMutexLockStatus lockStatus = epicsMutexLock ( pEventData->m_pTestData->m_mutex ); + callbackIsOk = pEventData->m_callbackIsOk; + pEventData->m_nCallback++; + epicsMutexUnlock ( pEventData->m_pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + verify ( callbackIsOk ); +} + +static void multiSubscrDestroyNoLateCallbackThread ( void * pParm ) +{ + struct MultiSubscrDestroyNoLateCallbackTestData * const pTestData = + ( struct MultiSubscrDestroyNoLateCallbackTestData * ) pParm; + unsigned i, j; + int status; + + status = ca_context_create ( ca_enable_preemptive_callback ); + verify ( status == ECA_NORMAL ); + + status = ca_create_channel ( pTestData->m_pChanName, 0, 0, + CA_PRIORITY_DEFAULT, &pTestData->m_chan ); + status = ca_pend_io ( timeoutToPendIO ); + SEVCHK ( status, "multiSubscrDestroyLateNoCallbackTest: channel connect failed" ); + verify ( status == ECA_NORMAL ); + + /* + * create a set of subscriptions + */ + for ( i=0; i < 10000; i++ ) { + unsigned int priorityOfTestThread; + for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) { + epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + pTestData->m_eventData[j].m_nCallback = 0; + pTestData->m_eventData[j].m_callbackIsOk = TRUE; + pTestData->m_eventData[j].m_pTestData = pTestData; + epicsMutexUnlock ( pTestData->m_mutex ); + SEVCHK ( ca_add_event ( DBR_GR_FLOAT, pTestData->m_chan, noLateCallbackDetect, + &pTestData->m_eventData[j], &pTestData->m_eventData[j].m_id ) , NULL ); + } + SEVCHK ( ca_flush_io(), NULL ); + + /* + * raise the priority of the current thread hoping to improve our + * likelyhood of detecting a bug + */ + priorityOfTestThread = epicsThreadGetPrioritySelf (); + epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsThreadPriorityHigh ); + + + /* + * wait for the first subscription update to arrive + */ + { + epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + while ( pTestData->m_eventData[0].m_nCallback == 0 ) { + epicsMutexUnlock ( pTestData->m_mutex ); + epicsThreadSleep ( 50e-6 ); + lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + } + epicsMutexUnlock ( pTestData->m_mutex ); + } + /* + * try to destroy all of the subscriptions at precisely the same time that + * their first callbacks are running + */ + for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) { + SEVCHK ( ca_clear_event ( pTestData->m_eventData[j].m_id ) , NULL ); + epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + pTestData->m_eventData[j].m_callbackIsOk = FALSE; + epicsMutexUnlock ( pTestData->m_mutex ); + } + /* + * return to the original priority + */ + epicsThreadSetPriority ( epicsThreadGetIdSelf(), priorityOfTestThread ); + + if ( i % 1000 == 0 ) { + showProgress ( pTestData->m_interestLevel ); + } + } + + SEVCHK ( ca_clear_channel ( pTestData->m_chan ), NULL ); + + ca_context_destroy (); + + epicsEventSignal ( pTestData->m_testDoneEvent ); +} + +/* + * verify that, in a preemtive callback mode client, a subscription callback never + * comes after the subscription is destroyed + */ +static void multiSubscrDestroyNoLateCallbackTest ( const char *pName, unsigned interestLevel ) +{ + struct MultiSubscrDestroyNoLateCallbackTestData * pTestData; + + showProgressBegin ( "multiSubscrDestroyNoLateCallbackTest", interestLevel ); + + pTestData = calloc ( 1u, sizeof ( struct MultiSubscrDestroyNoLateCallbackTestData ) ); + verify ( pTestData ); + pTestData->m_mutex = epicsMutexMustCreate (); + pTestData->m_testDoneEvent = epicsEventMustCreate ( epicsEventEmpty ); + pTestData->m_pChanName = pName; + pTestData->m_interestLevel = interestLevel; + epicsThreadMustCreate ( + "multiSubscrDestroyNoLateCallbackTest", + epicsThreadPriorityLow, + epicsThreadGetStackSize ( epicsThreadStackMedium ), + multiSubscrDestroyNoLateCallbackThread, + pTestData ); + + /* + * wait for test to complete + */ + epicsEventMustWait ( pTestData->m_testDoneEvent ); + + /* + * cleanup + */ + epicsMutexDestroy ( pTestData->m_mutex ); + epicsEventDestroy ( pTestData->m_testDoneEvent ); + free ( pTestData ); + + showProgressEnd ( interestLevel ); +} + /* * multiSubscriptionDeleteTest * @@ -3263,6 +3416,11 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount, epicsEnvSet ( "EPICS_CA_MAX_ARRAY_BYTES", tmpString ); } + /* + * this test creates, and then destroys, a private CA context + */ + multiSubscrDestroyNoLateCallbackTest ( pName, interestLevel ); + status = ca_context_create ( select ); SEVCHK ( status, NULL ); diff --git a/src/ca/bhe.cpp b/src/ca/bhe.cpp index 8ede482b4..d6f1796be 100644 --- a/src/ca/bhe.cpp +++ b/src/ca/bhe.cpp @@ -332,13 +332,6 @@ void bhe::unregisterIIU ( } } -void * bhe::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void bhe::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/bhe.h b/src/ca/bhe.h index 1660e485b..4da95202a 100644 --- a/src/ca/bhe.h +++ b/src/ca/bhe.h @@ -87,7 +87,6 @@ private: const epicsTime & currentTime ); bhe ( const bhe & ); bhe & operator = ( const bhe & ); - void * operator new ( size_t size ); epicsShareFunc void operator delete ( void * ); }; diff --git a/src/ca/ca_client_context.cpp b/src/ca/ca_client_context.cpp index f0d71f5b3..b8f6d9d0b 100644 --- a/src/ca/ca_client_context.cpp +++ b/src/ca/ca_client_context.cpp @@ -106,7 +106,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : { osiSockIoctl_t yes = true; - int status = socket_ioctl ( this->sock, // X aCC 392 + int status = socket_ioctl ( this->sock, FIONBIO, & yes); if ( status < 0 ) { char sockErrBuf[64]; @@ -126,7 +126,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : memset ( (char *)&addr, 0 , sizeof ( addr ) ); addr.ia.sin_family = AF_INET; addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); - addr.ia.sin_port = htons ( PORT_ANY ); // X aCC 818 + addr.ia.sin_port = htons ( PORT_ANY ); int status = bind (this->sock, &addr.sa, sizeof (addr) ); if ( status < 0 ) { char sockErrBuf[64]; @@ -159,9 +159,9 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : this->localPort = htons ( tmpAddr.ia.sin_port ); } - epics_auto_ptr < epicsGuard < epicsMutex > > pCBGuard; + epics_auto_ptr < CallbackGuard > pCBGuard; if ( ! enablePreemptiveCallback ) { - pCBGuard.reset ( new epicsGuard < epicsMutex > ( this->cbMutex ) ); + pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) ); } // multiple steps ensure exception safety @@ -277,7 +277,7 @@ int ca_client_context :: printFormated ( } int ca_client_context :: varArgsPrintFormated ( - const char *pformat, va_list args ) const // X aCC 361 + const char *pformat, va_list args ) const { caPrintfFunc * pFunc; { @@ -751,6 +751,8 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon ) { oldChannelNotify & chan = pMon->channel (); ca_client_context & cac = chan.getClientCtx (); + // !!!! the order in which we take the mutex here prevents deadlocks + { epicsGuard < epicsMutex > guard ( cac.mutex ); try { // if this stalls out on a live circuit then an exception @@ -761,7 +763,25 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon ) catch ( cacChannel::notConnected & ) { // intentionally ignored } - pMon->cancel ( guard ); + } + if ( cac.pCallbackGuard.get() && + cac.createdByThread == epicsThreadGetIdSelf () ) { + epicsGuard < epicsMutex > guard ( cac.mutex ); + pMon->cancel ( *cac.pCallbackGuard.get(), guard ); + } + else { + // + // we will definately stall out here if all of the + // following are true + // + // o user creates non-preemtive mode client library context + // o user doesnt periodically call a ca function + // o user calls this function from an auxiillary thread + // + CallbackGuard cbGuard ( cac.cbMutex ); + epicsGuard < epicsMutex > guard ( cac.mutex ); + pMon->cancel ( cbGuard, guard ); + } return ECA_NORMAL; } diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp index 42a491fec..0317f2145 100644 --- a/src/ca/cac.cpp +++ b/src/ca/cac.cpp @@ -568,7 +568,7 @@ bool cac::findOrCreateVirtCircuit ( } void cac::transferChanToVirtCircuit ( - unsigned cid, unsigned sid, // X aCC 431 + unsigned cid, unsigned sid, ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber, const osiSockAddr & addr, const epicsTime & currentTime ) @@ -711,6 +711,7 @@ netReadNotifyIO & cac::readNotifyRequest ( } bool cac::destroyIO ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & guard, const cacChannel::ioid & idIn, nciu & chan ) { @@ -787,7 +788,7 @@ void cac::recycleSubscription ( netSubscription & cac::subscriptionRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, privateInterfaceForIO & privChan, - unsigned type, // X aCC 361 + unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify & notifyIn, bool chanIsInstalled ) @@ -1021,7 +1022,7 @@ bool cac::readExcep ( callbackManager &, tcpiiu &, } bool cac::writeExcep ( - callbackManager & mgr, // X aCC 431 + callbackManager & mgr, tcpiiu &, const caHdrLargeArray & hdr, const char * pCtx, unsigned status ) { @@ -1093,7 +1094,7 @@ bool cac::exceptionRespAction ( callbackManager & cbMutexIn, tcpiiu & iiu, } bool cac::accessRightsRespAction ( - callbackManager & mgr, tcpiiu &, // X aCC 431 + callbackManager & mgr, tcpiiu &, const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -1110,7 +1111,7 @@ bool cac::accessRightsRespAction ( } bool cac::createChannelRespAction ( - callbackManager & mgr, tcpiiu & iiu, // X aCC 431 + callbackManager & mgr, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -1157,7 +1158,7 @@ bool cac::verifyAndDisconnectChan ( } void cac::disconnectChannel ( - epicsGuard < epicsMutex > & cbGuard, // X aCC 431 + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, nciu & chan ) { guard.assertIdenticalMutex ( this->mutex ); diff --git a/src/ca/cac.h b/src/ca/cac.h index ae20eef27..63acccb6f 100644 --- a/src/ca/cac.h +++ b/src/ca/cac.h @@ -55,7 +55,7 @@ class netSubscription; // used to control access to cac's recycle routines which // should only be indirectly invoked by CAC when its lock // is applied -class cacRecycle { // X aCC 655 +class cacRecycle { public: virtual void recycleReadNotifyIO ( epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0; @@ -155,7 +155,8 @@ public: unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify &, bool channelIsInstalled ); bool destroyIO ( - epicsGuard < epicsMutex > & guard, + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, const cacChannel::ioid & idIn, nciu & chan ); void disconnectAllIO ( @@ -167,11 +168,6 @@ public: epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id, unsigned level ) const; - // sync group routines - CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id ); - void installCASG ( epicsGuard < epicsMutex > &, CASG & ); - void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & ); - // exception generation void exception ( epicsGuard < epicsMutex > & cbGuard, diff --git a/src/ca/cacIO.h b/src/ca/cacIO.h index 8086f1239..dd3955737 100644 --- a/src/ca/cacIO.h +++ b/src/ca/cacIO.h @@ -69,7 +69,7 @@ typedef unsigned long arrayElementCount; // 1) this should not be passing caerr.h status to the exception callback // 2) needless-to-say the data should be passed here using the new data access API -class epicsShareClass cacWriteNotify { // X aCC 655 +class epicsShareClass cacWriteNotify { public: virtual ~cacWriteNotify () = 0; virtual void completion ( epicsGuard < epicsMutex > & ) = 0; @@ -82,7 +82,7 @@ public: // 1) this should not be passing caerr.h status to the exception callback // 2) needless-to-say the data should be passed here using the new data access API -class epicsShareClass cacReadNotify { // X aCC 655 +class epicsShareClass cacReadNotify { public: virtual ~cacReadNotify () = 0; virtual void completion ( @@ -97,7 +97,7 @@ public: // 1) this should not be passing caerr.h status to the exception callback // 2) needless-to-say the data should be passed here using the new data access API -class epicsShareClass cacStateNotify { // X aCC 655 +class epicsShareClass cacStateNotify { public: virtual ~cacStateNotify () = 0; virtual void current ( @@ -131,7 +131,7 @@ private: bool f_operatorConfirmationRequest:1; }; -class epicsShareClass cacChannelNotify { // X aCC 655 +class epicsShareClass cacChannelNotify { public: virtual ~cacChannelNotify () = 0; virtual void connectNotify ( epicsGuard < epicsMutex > & ) = 0; @@ -152,6 +152,16 @@ public: unsigned type, arrayElementCount count ) = 0; }; +class CallbackGuard : + public epicsGuard < epicsMutex > { +public: + CallbackGuard ( epicsMutex & mutex ) : + epicsGuard < epicsMutex > ( mutex ) {} +private: + CallbackGuard ( const CallbackGuard & ); + CallbackGuard & operator = ( const CallbackGuard & ); +}; + // // Notes // 1) This interface assumes that when a channel is deleted then all @@ -174,6 +184,7 @@ public: cacChannel ( cacChannelNotify & ); virtual void destroy ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; cacChannelNotify & notify () const; // required ????? virtual unsigned getName ( @@ -207,7 +218,15 @@ public: epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, unsigned mask, cacStateNotify &, ioid * = 0 ) = 0; + // The primary mutex must be released when calling the user's + // callback, and therefore a finite interval exists when we are + // moving forward with the intent to call the users callback + // but the users IO could be deleted during this interval. + // To prevent the user's callback from being called after + // destroying his IO we must past a guard for the callback + // mutex here. virtual void ioCancel ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard, const ioid & ) = 0; virtual void ioShow ( @@ -258,7 +277,7 @@ private: cacChannel & operator = ( const cacChannel & ); }; -class epicsShareClass cacContext { // X aCC 655 +class epicsShareClass cacContext { public: virtual ~cacContext (); virtual cacChannel & createChannel ( @@ -277,7 +296,7 @@ public: epicsGuard < epicsMutex > &, unsigned level ) const = 0; }; -class epicsShareClass cacContextNotify { // X aCC 655 +class epicsShareClass cacContextNotify { public: virtual ~cacContextNotify () = 0; virtual cacContext & createNetworkContext ( @@ -297,7 +316,7 @@ public: // **** Lock Hierarchy **** // callbackControl must be taken before mutualExclusion if both are held at // the same time -class epicsShareClass cacService { // X aCC 655 +class epicsShareClass cacService { public: virtual ~cacService () = 0; virtual cacContext & contextCreate ( diff --git a/src/ca/casw.cpp b/src/ca/casw.cpp index d8334b8ca..f69632c13 100644 --- a/src/ca/casw.cpp +++ b/src/ca/casw.cpp @@ -131,7 +131,7 @@ int main ( int argc, char ** argv ) } osiSockIoctl_t yes = true; - status = socket_ioctl ( sock, FIONBIO, &yes ); // X aCC 392 + status = socket_ioctl ( sock, FIONBIO, &yes ); if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( @@ -166,7 +166,7 @@ int main ( int argc, char ** argv ) } osiSockIoctl_t no = false; - status = socket_ioctl ( sock, FIONBIO, &no ); // X aCC 392 + status = socket_ioctl ( sock, FIONBIO, &no ); if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( diff --git a/src/ca/comBuf.h b/src/ca/comBuf.h index 2f6c6faa1..59e38780b 100644 --- a/src/ca/comBuf.h +++ b/src/ca/comBuf.h @@ -44,7 +44,7 @@ public: virtual void release ( void * ) = 0; }; -class wireSendAdapter { // X aCC 655 +class wireSendAdapter { public: virtual unsigned sendBytes ( const void * pBuf, unsigned nBytesInBuf, @@ -65,7 +65,7 @@ struct statusWireIO { swioCircuitState circuitState; }; -class wireRecvAdapter { // X aCC 655 +class wireRecvAdapter { public: virtual void recvBytes ( void * pBuf, unsigned nBytesInBuf, statusWireIO & ) = 0; @@ -114,7 +114,6 @@ private: unsigned nextWriteIndex; unsigned nextReadIndex; epicsUInt8 buf [ comBufSize ]; - void * operator new ( size_t size ); void operator delete ( void * ); template < class T > bool push ( const T * ); // disabled diff --git a/src/ca/comQueRecv.cpp b/src/ca/comQueRecv.cpp index db797fd65..88263544d 100644 --- a/src/ca/comQueRecv.cpp +++ b/src/ca/comQueRecv.cpp @@ -155,7 +155,7 @@ epicsUInt32 comQueRecv::multiBufferPopUInt32 () unsigned byte3 = this->popUInt8(); unsigned byte4 = this->popUInt8(); tmp = static_cast - ( ( byte1 << 24u ) | ( byte2 << 16u ) | //X aCC 392 + ( ( byte1 << 24u ) | ( byte2 << 16u ) | ( byte3 << 8u ) | byte4 ); } else { diff --git a/src/ca/comQueSend.cpp b/src/ca/comQueSend.cpp index 5ae150be2..6ed516bb3 100644 --- a/src/ca/comQueSend.cpp +++ b/src/ca/comQueSend.cpp @@ -368,7 +368,7 @@ void comQueSend::insertRequestWithPayLoad ( // the above checks verify that the total size // is lest that 0xffffffff size = static_cast < ca_uint32_t > - ( dbr_size_n ( dataType, nElem ) ); // X aCC 392 + ( dbr_size_n ( dataType, nElem ) ); payloadSize = CA_MESSAGE_ALIGN ( size ); this->insertRequestHeader ( request, payloadSize, static_cast ( dataType ), diff --git a/src/ca/disconnectGovernorTimer.cpp b/src/ca/disconnectGovernorTimer.cpp index 755b29cb3..f1d517f07 100644 --- a/src/ca/disconnectGovernorTimer.cpp +++ b/src/ca/disconnectGovernorTimer.cpp @@ -65,7 +65,7 @@ void disconnectGovernorTimer::shutdown ( } epicsTimerNotify::expireStatus disconnectGovernorTimer::expire ( - const epicsTime & /* currentTime */ ) // X aCC 361 + const epicsTime & /* currentTime */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); while ( nciu * pChan = chanList.get () ) { diff --git a/src/ca/disconnectGovernorTimer.h b/src/ca/disconnectGovernorTimer.h index 06b8a36a8..f636d6260 100644 --- a/src/ca/disconnectGovernorTimer.h +++ b/src/ca/disconnectGovernorTimer.h @@ -43,7 +43,7 @@ #include "caProto.h" #include "netiiu.h" -class disconnectGovernorNotify { // X aCC 655 +class disconnectGovernorNotify { public: virtual ~disconnectGovernorNotify () = 0; virtual void govExpireNotify ( diff --git a/src/ca/getCallback.cpp b/src/ca/getCallback.cpp index e95433dd5..05e654e30 100644 --- a/src/ca/getCallback.cpp +++ b/src/ca/getCallback.cpp @@ -90,13 +90,6 @@ void getCallback::exception ( } } -void * getCallback::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void getCallback::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/getCopy.cpp b/src/ca/getCopy.cpp index 978676ef0..23a508d9a 100644 --- a/src/ca/getCopy.cpp +++ b/src/ca/getCopy.cpp @@ -105,13 +105,6 @@ void getCopy::show ( unsigned level ) const } } -void * getCopy::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void getCopy::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/iocinf.cpp b/src/ca/iocinf.cpp index d6fac8178..487067c00 100644 --- a/src/ca/iocinf.cpp +++ b/src/ca/iocinf.cpp @@ -133,7 +133,7 @@ extern "C" void epicsShareAPI removeDuplicateAddresses if ( pNode->addr.sa.sa_family == AF_INET ) { - pTmpNode = (osiSockAddrNode *) ellFirst (pDestList); // X aCC 749 + pTmpNode = (osiSockAddrNode *) ellFirst (pDestList); while ( pTmpNode ) { if (pTmpNode->addr.sa.sa_family == AF_INET) { if ( pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr && @@ -149,7 +149,7 @@ extern "C" void epicsShareAPI removeDuplicateAddresses break; } } - pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node); // X aCC 749 + pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node); } if (pNode) { ellAdd (pDestList, &pNode->node); @@ -168,12 +168,12 @@ static void forcePort ( ELLLIST *pList, unsigned short port ) { osiSockAddrNode *pNode; - pNode = ( osiSockAddrNode * ) ellFirst ( pList ); // X aCC 749 + pNode = ( osiSockAddrNode * ) ellFirst ( pList ); while ( pNode ) { if ( pNode->addr.sa.sa_family == AF_INET ) { pNode->addr.ia.sin_port = htons ( port ); } - pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node ); // X aCC 749 + pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node ); } } @@ -192,9 +192,9 @@ extern "C" void epicsShareAPI configureChannelAccessAddressList /* * dont load the list twice */ - assert ( ellCount (pList) == 0 ); // X aCC 392 + assert ( ellCount (pList) == 0 ); - ellInit ( &tmpList ); // X aCC 392 + ellInit ( &tmpList ); /* * Check to see if the user has disabled @@ -217,12 +217,12 @@ extern "C" void epicsShareAPI configureChannelAccessAddressList if (yes) { ELLLIST bcastList; osiSockAddr addr; - ellInit ( &bcastList ); // X aCC 392 + ellInit ( &bcastList ); addr.ia.sin_family = AF_UNSPEC; osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr ); forcePort ( &bcastList, port ); removeDuplicateAddresses ( &tmpList, &bcastList, 1 ); - if ( ellCount ( &tmpList ) == 0 ) { // X aCC 392 + if ( ellCount ( &tmpList ) == 0 ) { osiSockAddrNode *pNewNode; pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) ); if ( pNewNode ) { @@ -254,11 +254,11 @@ extern "C" void epicsShareAPI printChannelAccessAddressList ( const ELLLIST *pLi osiSockAddrNode *pNode; ::printf ( "Channel Access Address List\n" ); - pNode = (osiSockAddrNode *) ellFirst ( pList ); // X aCC 749 + pNode = (osiSockAddrNode *) ellFirst ( pList ); while (pNode) { char buf[64]; ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) ); ::printf ( "%s\n", buf ); - pNode = (osiSockAddrNode *) ellNext ( &pNode->node ); // X aCC 749 + pNode = (osiSockAddrNode *) ellNext ( &pNode->node ); } } diff --git a/src/ca/msgForMultiplyDefinedPV.cpp b/src/ca/msgForMultiplyDefinedPV.cpp index 516bb63bb..2f1a45cde 100644 --- a/src/ca/msgForMultiplyDefinedPV.cpp +++ b/src/ca/msgForMultiplyDefinedPV.cpp @@ -73,13 +73,6 @@ void msgForMultiplyDefinedPV::operator delete ( void *pCadaver, } #endif -void * msgForMultiplyDefinedPV::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void msgForMultiplyDefinedPV::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/msgForMultiplyDefinedPV.h b/src/ca/msgForMultiplyDefinedPV.h index 545adc815..45d3453ac 100644 --- a/src/ca/msgForMultiplyDefinedPV.h +++ b/src/ca/msgForMultiplyDefinedPV.h @@ -39,7 +39,7 @@ # define epicsExportSharedSymbols #endif -class callbackForMultiplyDefinedPV { // X aCC 655 +class callbackForMultiplyDefinedPV { public: virtual ~callbackForMultiplyDefinedPV () = 0; virtual void pvMultiplyDefinedNotify ( @@ -64,7 +64,6 @@ private: void transactionComplete ( const char * pHostName ); msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & ); msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; diff --git a/src/ca/nciu.cpp b/src/ca/nciu.cpp index c5ae941b2..66bbf02a0 100644 --- a/src/ca/nciu.cpp +++ b/src/ca/nciu.cpp @@ -76,29 +76,24 @@ nciu::~nciu () // channels are created by the user, and only destroyed by the user // using this routine void nciu::destroy ( - epicsGuard < epicsMutex > & guard ) + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExcusionGuard ) { while ( baseNMIU * pNetIO = this->eventq.first () ) { - bool success = this->cacCtx.destroyIO ( guard, pNetIO->getId (), *this ); + bool success = this->cacCtx.destroyIO ( callbackGuard, mutualExcusionGuard, + pNetIO->getId (), *this ); assert ( success ); } // 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->channelNode::isInstalledInServer ( guard ) ) { - this->getPIIU(guard)->clearChannelRequest ( - guard, this->sid, this->id ); + if ( this->channelNode::isInstalledInServer ( mutualExcusionGuard ) ) { + this->getPIIU(mutualExcusionGuard)->clearChannelRequest ( + mutualExcusionGuard, this->sid, this->id ); } - this->piiu->uninstallChan ( guard, *this ); - 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 - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); + this->piiu->uninstallChan ( mutualExcusionGuard, *this ); + this->cacCtx.destroyChannel ( mutualExcusionGuard, *this ); } void nciu::operator delete ( void * ) @@ -387,9 +382,12 @@ void nciu::subscribe ( } void nciu::ioCancel ( - epicsGuard < epicsMutex > & guard, const ioid & idIn ) + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const ioid & idIn ) { - this->cacCtx.destroyIO ( guard, idIn, *this ); + this->cacCtx.destroyIO ( callbackGuard, + mutualExclusionGuard, idIn, *this ); } void nciu::ioShow ( diff --git a/src/ca/nciu.h b/src/ca/nciu.h index de070dcea..417e7fd5c 100644 --- a/src/ca/nciu.h +++ b/src/ca/nciu.h @@ -121,7 +121,7 @@ private: friend class disconnectGovernorTimer; }; -class privateInterfaceForIO { // X aCC 655 +class privateInterfaceForIO { public: virtual void ioCompletionNotify ( epicsGuard < epicsMutex > &, class baseNMIU & ) = 0; @@ -220,6 +220,7 @@ private: ca_uint16_t typeCode; ca_uint8_t priority; virtual void destroy ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard ); void initiateConnect ( epicsGuard < epicsMutex > & ); @@ -243,7 +244,15 @@ private: epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify ¬ify, ioid * ); + // The primary mutex must be released when calling the user's + // callback, and therefore a finite interval exists when we are + // moving forward with the intent to call the users callback + // but the users IO could be deleted during this interval. + // To prevent the user's callback from being called after + // destroying his IO we must past a guard for the callback + // mutex here. virtual void ioCancel ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard, const ioid & ); void ioShow ( @@ -270,7 +279,6 @@ private: epicsGuard < epicsMutex > & guard ) const throw (); nciu ( const nciu & ); nciu & operator = ( const nciu & ); - void * operator new ( size_t ); void operator delete ( void * ); }; diff --git a/src/ca/netIO.h b/src/ca/netIO.h index 57273427a..e728d2a1a 100644 --- a/src/ca/netIO.h +++ b/src/ca/netIO.h @@ -42,7 +42,7 @@ class privateInterfaceForIO; -class baseNMIU : public tsDLNode < baseNMIU >, // X aCC 655 +class baseNMIU : public tsDLNode < baseNMIU >, public chronIntIdRes < baseNMIU > { public: virtual void destroy ( @@ -106,7 +106,6 @@ private: const unsigned mask; bool subscribed; class netSubscription * isSubscription (); - void * operator new ( size_t ); void operator delete ( void * ); void * operator new ( size_t, tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & ); @@ -147,7 +146,6 @@ protected: private: cacReadNotify & notify; class privateInterfaceForIO & privateChanForIO; - void * operator new ( size_t ); void operator delete ( void * ); void * operator new ( size_t, tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & ); @@ -190,7 +188,6 @@ protected: private: cacWriteNotify & notify; privateInterfaceForIO & privateChanForIO; - void * operator new ( size_t ); void operator delete ( void * ); void * operator new ( size_t, tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & ); @@ -237,12 +234,12 @@ inline netSubscription * netSubscription::factory ( class privateInterfaceForIO & chan, unsigned type, arrayElementCount count, unsigned mask, cacStateNotify ¬ify ) { - return new ( freeList ) netSubscription ( chan, type, // X aCC 930 + return new ( freeList ) netSubscription ( chan, type, count, mask, notify ); } inline arrayElementCount netSubscription::getCount ( - epicsGuard < epicsMutex > & guard, bool allow_zero ) const // X aCC 361 + epicsGuard < epicsMutex > & guard, bool allow_zero ) const { //guard.assertIdenticalMutex ( this->mutex ); arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard ); @@ -268,7 +265,7 @@ inline netReadNotifyIO * netReadNotifyIO::factory ( tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList, privateInterfaceForIO & ioComplNotifIntf, cacReadNotify & notify ) { - return new ( freeList ) netReadNotifyIO ( ioComplNotifIntf, notify ); // X aCC 930 + return new ( freeList ) netReadNotifyIO ( ioComplNotifIntf, notify ); } inline void * netReadNotifyIO::operator new ( size_t size, @@ -289,7 +286,7 @@ inline netWriteNotifyIO * netWriteNotifyIO::factory ( tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList, privateInterfaceForIO & ioComplNotifyIntf, cacWriteNotify & notify ) { - return new ( freeList ) netWriteNotifyIO ( ioComplNotifyIntf, notify ); // X aCC 930 + return new ( freeList ) netWriteNotifyIO ( ioComplNotifyIntf, notify ); } inline void * netWriteNotifyIO::operator new ( size_t size, diff --git a/src/ca/netReadNotifyIO.cpp b/src/ca/netReadNotifyIO.cpp index 446b7175d..2e4b8ead6 100644 --- a/src/ca/netReadNotifyIO.cpp +++ b/src/ca/netReadNotifyIO.cpp @@ -119,13 +119,6 @@ void netReadNotifyIO::forceSubscriptionUpdate ( { } -void * netReadNotifyIO::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void netReadNotifyIO::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/netSubscription.cpp b/src/ca/netSubscription.cpp index 9a29ac2b6..fe2426a89 100644 --- a/src/ca/netSubscription.cpp +++ b/src/ca/netSubscription.cpp @@ -170,13 +170,6 @@ void netSubscription::forceSubscriptionUpdate ( guard, chan, *this ); } -void * netSubscription::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void netSubscription::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/netWriteNotifyIO.cpp b/src/ca/netWriteNotifyIO.cpp index 68d4992e7..afa9996d5 100644 --- a/src/ca/netWriteNotifyIO.cpp +++ b/src/ca/netWriteNotifyIO.cpp @@ -117,14 +117,6 @@ void netWriteNotifyIO::forceSubscriptionUpdate ( { } -void * netWriteNotifyIO::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( - "why is the compiler calling private operator new" ); -} - void netWriteNotifyIO::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/netiiu.h b/src/ca/netiiu.h index 99ea128f1..2caa3d0fa 100644 --- a/src/ca/netiiu.h +++ b/src/ca/netiiu.h @@ -35,7 +35,7 @@ union osiSockAddr; class cac; class nciu; -class netiiu { // X aCC 655 +class netiiu { public: virtual ~netiiu () = 0; virtual unsigned getHostName ( diff --git a/src/ca/oldAccess.h b/src/ca/oldAccess.h index d18a4fe1b..5684b83c3 100644 --- a/src/ca/oldAccess.h +++ b/src/ca/oldAccess.h @@ -53,7 +53,8 @@ public: const char * pName, caCh * pConnCallBackIn, void * pPrivateIn, capri priority ); void destructor ( - epicsGuard < epicsMutex > & guard ); + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & mutexGuard ); // legacy C API friend unsigned epicsShareAPI ca_get_host_name ( @@ -122,6 +123,7 @@ public: unsigned type, arrayElementCount count, const void *pValue, cacWriteNotify &, cacChannel::ioid *pId = 0 ); void ioCancel ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard, const cacChannel::ioid & ); void ioShow ( @@ -162,7 +164,6 @@ private: unsigned type, arrayElementCount count ); oldChannelNotify ( const oldChannelNotify & ); oldChannelNotify & operator = ( const oldChannelNotify & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -195,7 +196,6 @@ private: const char *pContext, unsigned type, arrayElementCount count ); getCopy ( const getCopy & ); getCopy & operator = ( const getCopy & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -221,7 +221,6 @@ private: const char * pContext, unsigned type, arrayElementCount count ); getCallback ( const getCallback & ); getCallback & operator = ( const getCallback & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -245,7 +244,6 @@ private: unsigned type, arrayElementCount count ); putCallback ( const putCallback & ); putCallback & operator = ( const putCallback & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -259,8 +257,16 @@ public: evid * ); ~oldSubscription (); oldChannelNotify & channel () const; + // The primary mutex must be released when calling the user's + // callback, and therefore a finite interval exists when we are + // moving forward with the intent to call the users callback + // but the users IO could be deleted during this interval. + // To prevent the user's callback from being called after + // destroying his IO we must past a guard for the callback + // mutex here. void cancel ( - epicsGuard < epicsMutex > & guard ); + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ); void * operator new ( size_t size, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & ); epicsPlacementDeleteOperator (( void *, @@ -278,7 +284,6 @@ private: const char *pContext, unsigned type, arrayElementCount count ); oldSubscription ( const oldSubscription & ); oldSubscription & operator = ( const oldSubscription & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -341,6 +346,8 @@ public: void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & ); epicsMutex & mutexRef () const; + template < class T > + void whenThereIsAnExceptionDestroySyncGroupIO ( epicsGuard < epicsMutex > &, T & ); // legacy C API friend int epicsShareAPI ca_create_channel ( @@ -368,6 +375,17 @@ public: 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 int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid, + chtype type, arrayElementCount count, + chid pChan, void *pValue ); + friend int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid, + chtype type, arrayElementCount count, + chid pChan, const void *pValue ); + friend int ca_sync_group_destroy ( CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard, + ca_client_context & cac, const CA_SYNC_GID gid ); + friend void sync_group_reset ( ca_client_context & client, + CASG & sg ); // exceptions class noSocket {}; @@ -384,7 +402,7 @@ private: epicsEvent ioDone; epicsEvent callbackThreadActivityComplete; epicsThreadId createdByThread; - epics_auto_ptr < epicsGuard < epicsMutex > > pCallbackGuard; + epics_auto_ptr < CallbackGuard > pCallbackGuard; epics_auto_ptr < cacContext > pServiceContext; caExceptionHandler * ca_exception_func; void * ca_exception_arg; @@ -444,10 +462,11 @@ inline void oldChannelNotify::initiateConnect ( } inline void oldChannelNotify::ioCancel ( - epicsGuard < epicsMutex > & guard, + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, const cacChannel::ioid & id ) { - this->io.ioCancel ( guard, id ); + this->io.ioCancel ( callbackGuard, mutualExclusionGuard, id ); } inline void oldChannelNotify::ioShow ( @@ -492,9 +511,10 @@ inline void oldSubscription::operator delete ( void *pCadaver, #endif inline void oldSubscription::cancel ( - epicsGuard < epicsMutex > & guard ) + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) { - this->chan.ioCancel ( guard, this->id ); + this->chan.ioCancel ( callbackGuard, mutualExclusionGuard, this->id ); } inline oldChannelNotify & oldSubscription::channel () const @@ -560,5 +580,32 @@ inline unsigned ca_client_context::sequenceNumberOfOutstandingIO ( // perhaps on SMP systems THERE should be lock/unlock around this return this->ioSeqNo; } + +template < class T > +void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO ( + epicsGuard < epicsMutex > & guard, T & io ) +{ + if ( this->pCallbackGuard.get() && + this->createdByThread == epicsThreadGetIdSelf () ) { + io.destroy ( *this->pCallbackGuard.get(), guard ); + } + else { + // dont reverse the lock hierarchy + epicsGuardRelease < epicsMutex > guardRelease (); + { + // + // we will definately stall out here if all of the + // following are true + // + // o user creates non-preemtive mode client library context + // o user doesnt periodically call a ca function + // o user calls this function from an auxiillary thread + // + CallbackGuard cbGuard ( this->cbMutex ); + epicsGuard < epicsMutex > guard ( this->mutex ); + io.destroy ( cbGuard, guard ); + } + } +} #endif // ifndef oldAccessh diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp index 8865f8d63..289c4e8b4 100644 --- a/src/ca/oldChannelNotify.cpp +++ b/src/ca/oldChannelNotify.cpp @@ -65,14 +65,15 @@ oldChannelNotify::~oldChannelNotify () } void oldChannelNotify::destructor ( - epicsGuard < epicsMutex > & guard ) + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & mutexGuard ) { - guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - this->io.destroy ( guard ); + mutexGuard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); + this->io.destroy ( cbGuard, mutexGuard ); // no need to worry about a connect preempting here because // the io (the nciu) has been destroyed above if ( this->pConnCallBack == 0 && ! this->currentlyConnected ) { - this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo ); + this->cacCtx.decrementOutstandingIO ( mutexGuard, this->ioSeqNo ); } this->~oldChannelNotify (); } @@ -159,13 +160,6 @@ void oldChannelNotify::writeException ( __FILE__, __LINE__, *this, type, count, CA_OP_PUT ); } -void * oldChannelNotify::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void oldChannelNotify::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if @@ -638,7 +632,7 @@ arrayElementCount epicsShareAPI ca_element_count ( chid pChan ) /* * ca_state () */ -enum channel_state epicsShareAPI ca_state ( chid pChan ) // X aCC 361 +enum channel_state epicsShareAPI ca_state ( chid pChan ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); if ( pChan->io.connected ( guard ) ) { diff --git a/src/ca/putCallback.cpp b/src/ca/putCallback.cpp index bff1dd8a4..ba17a654c 100644 --- a/src/ca/putCallback.cpp +++ b/src/ca/putCallback.cpp @@ -90,13 +90,6 @@ void putCallback::exception ( } } -void * putCallback::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void putCallback::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/repeater.cpp b/src/ca/repeater.cpp index 64016aed6..ef271e461 100644 --- a/src/ca/repeater.cpp +++ b/src/ca/repeater.cpp @@ -178,7 +178,7 @@ bool repeaterClient::connect () return true; } -bool repeaterClient::sendConfirm () // X aCC 361 +bool repeaterClient::sendConfirm () { int status; @@ -204,7 +204,7 @@ bool repeaterClient::sendConfirm () // X aCC 361 } } -bool repeaterClient::sendMessage ( const void *pBuf, unsigned bufSize ) // X aCC 361 +bool repeaterClient::sendMessage ( const void *pBuf, unsigned bufSize ) { int status; @@ -245,13 +245,6 @@ repeaterClient::~repeaterClient () #endif } -void * repeaterClient::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void repeaterClient::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if @@ -304,7 +297,7 @@ inline bool repeaterClient::identicalPort ( const osiSockAddr &fromIn ) return false; } -bool repeaterClient::verify () // X aCC 361 +bool repeaterClient::verify () { SOCKET tmpSock; bool success = makeSocket ( this->port (), false, & tmpSock ); diff --git a/src/ca/repeaterClient.h b/src/ca/repeaterClient.h index c57aeaefe..faaf0809f 100644 --- a/src/ca/repeaterClient.h +++ b/src/ca/repeaterClient.h @@ -64,7 +64,6 @@ private: osiSockAddr from; SOCKET sock; unsigned short port () const; - void * operator new ( size_t size ); void operator delete ( void * ); }; diff --git a/src/ca/repeaterSubscribeTimer.cpp b/src/ca/repeaterSubscribeTimer.cpp index 337ff00ba..69362da5f 100644 --- a/src/ca/repeaterSubscribeTimer.cpp +++ b/src/ca/repeaterSubscribeTimer.cpp @@ -64,7 +64,7 @@ void repeaterSubscribeTimer::shutdown ( } epicsTimerNotify::expireStatus repeaterSubscribeTimer:: - expire ( const epicsTime & /* currentTime */ ) // X aCC 361 + expire ( const epicsTime & /* currentTime */ ) { static const unsigned nTriesToMsg = 50; if ( this->attempts > nTriesToMsg && ! this->once ) { diff --git a/src/ca/repeaterSubscribeTimer.h b/src/ca/repeaterSubscribeTimer.h index 0a23d16d3..52f146d6e 100644 --- a/src/ca/repeaterSubscribeTimer.h +++ b/src/ca/repeaterSubscribeTimer.h @@ -43,7 +43,7 @@ class epicsMutex; class cacContextNotify; -class repeaterTimerNotify { // X aCC 655 +class repeaterTimerNotify { public: virtual ~repeaterTimerNotify () = 0; virtual void repeaterRegistrationMessage ( diff --git a/src/ca/searchTimer.cpp b/src/ca/searchTimer.cpp index c7aa980ae..e5a8d1c54 100644 --- a/src/ca/searchTimer.cpp +++ b/src/ca/searchTimer.cpp @@ -124,7 +124,7 @@ void searchTimer::moveChannels ( // searchTimer::expire () // epicsTimerNotify::expireStatus searchTimer::expire ( - const epicsTime & currentTime ) // X aCC 361 + const epicsTime & currentTime ) { epicsGuard < epicsMutex > guard ( this->mutex ); diff --git a/src/ca/searchTimer.h b/src/ca/searchTimer.h index 2df980ded..7b9fe1717 100644 --- a/src/ca/searchTimer.h +++ b/src/ca/searchTimer.h @@ -43,7 +43,7 @@ #include "caProto.h" #include "netiiu.h" -class searchTimerNotify { // X aCC 655 +class searchTimerNotify { public: virtual ~searchTimerNotify () = 0; virtual void boostChannel ( diff --git a/src/ca/sgAutoPtr.h b/src/ca/sgAutoPtr.h index b3753bb44..a6383d69b 100644 --- a/src/ca/sgAutoPtr.h +++ b/src/ca/sgAutoPtr.h @@ -29,8 +29,7 @@ template < class T > class sgAutoPtr { public: - sgAutoPtr ( epicsGuard < epicsMutex > &, - struct CASG &, tsDLList < syncGroupNotify > & ); + sgAutoPtr ( epicsGuard < epicsMutex > &, struct CASG & ); ~sgAutoPtr (); sgAutoPtr < T > & operator = ( T * ); T * operator -> (); @@ -38,7 +37,6 @@ public: T * get (); T * release (); private: - tsDLList < syncGroupNotify > & list; T * pNotify; struct CASG & sg; epicsGuard < epicsMutex > & guard; @@ -47,9 +45,8 @@ private: template < class T > inline sgAutoPtr < T > :: sgAutoPtr ( - epicsGuard < epicsMutex > & guardIn, - struct CASG & sgIn, tsDLList < syncGroupNotify > & listIn ) : - list ( listIn ), pNotify ( 0 ), sg ( sgIn ), guard ( guardIn ) + epicsGuard < epicsMutex > & guardIn, struct CASG & sgIn ) : + pNotify ( 0 ), sg ( sgIn ), guard ( guardIn ) { } @@ -57,8 +54,9 @@ template < class T > inline sgAutoPtr < T > :: ~sgAutoPtr () { if ( this->pNotify ) { - list.remove ( *this->pNotify ); - pNotify->destroy ( this->guard, this->sg ); + this->sg.ioPendingList.remove ( *this->pNotify ); + this->sg.client. + whenThereIsAnExceptionDestroySyncGroupIO ( this->guard, *this->pNotify ); } } @@ -66,11 +64,12 @@ template < class T > inline sgAutoPtr < T > & sgAutoPtr < T > :: operator = ( T * pNotifyIn ) { if ( this->pNotify ) { - list.remove ( *this->pNotify ); - pNotify->destroy ( this->guard, this->sg ); + this->sg.ioPendingList.remove ( *this->pNotify ); + this->sg.client. + whenThereIsAnExceptionDestroySyncGroupIO ( this->guard, *this->pNotify ); } this->pNotify = pNotifyIn; - list.add ( *this->pNotify ); + this->sg.ioPendingList.add ( *this->pNotify ); return *this; } diff --git a/src/ca/syncGroup.h b/src/ca/syncGroup.h index c41c9b5b8..f805b6bbd 100644 --- a/src/ca/syncGroup.h +++ b/src/ca/syncGroup.h @@ -46,29 +46,17 @@ static const unsigned CASG_MAGIC = 0xFAB4CAFE; -// used to control access to CASG's recycle routines which -// should only be indirectly invoked by CASG when its lock -// is applied -class casgRecycle { // X aCC 655 -public: - virtual void recycleSyncGroupWriteNotify ( - epicsGuard < epicsMutex > &, class syncGroupWriteNotify & io ) = 0; - virtual void recycleSyncGroupReadNotify ( - epicsGuard < epicsMutex > &, class syncGroupReadNotify & io ) = 0; -protected: - virtual ~casgRecycle (); -}; - class syncGroupNotify : public tsDLNode < syncGroupNotify > { public: syncGroupNotify (); virtual void destroy ( - epicsGuard < epicsMutex > & guard, - casgRecycle & ) = 0; + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ) = 0; virtual bool ioPending ( epicsGuard < epicsMutex > & guard ) = 0; virtual void cancel ( - epicsGuard < epicsMutex > & guard ) = 0; + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0; @@ -78,33 +66,38 @@ protected: syncGroupNotify & operator = ( const syncGroupNotify & ); }; +struct CASG; + class syncGroupReadNotify : public syncGroupNotify, public cacReadNotify { public: + typedef void ( CASG :: * PRecycleFunc ) + ( epicsGuard < epicsMutex > &, syncGroupReadNotify & ); static syncGroupReadNotify * factory ( tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &, - struct CASG &, chid, void *pValueIn ); + CASG &, PRecycleFunc, chid, void *pValueIn ); void destroy ( - epicsGuard < epicsMutex > & guard, - casgRecycle & ); + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ); bool ioPending ( epicsGuard < epicsMutex > & guard ); void begin ( epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count ); void cancel ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; protected: - syncGroupReadNotify ( struct CASG & sgIn, chid, void * pValueIn ); + syncGroupReadNotify ( CASG & sgIn, PRecycleFunc, chid, void * pValueIn ); virtual ~syncGroupReadNotify (); private: chid chan; - struct CASG & sg; + PRecycleFunc pRecycleFunc; + CASG & sg; void * pValue; const unsigned magic; cacChannel::ioid id; bool idIsValid; bool ioComplete; - void * operator new ( size_t ); void operator delete ( void * ); void * operator new ( size_t, tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & ); @@ -122,30 +115,33 @@ private: class syncGroupWriteNotify : public syncGroupNotify, public cacWriteNotify { public: + typedef void ( CASG :: * PRecycleFunc ) + ( epicsGuard < epicsMutex > &, syncGroupWriteNotify & ); static syncGroupWriteNotify * factory ( tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &, - struct CASG &, chid ); + CASG &, PRecycleFunc, chid ); void destroy ( - epicsGuard < epicsMutex > & guard, - casgRecycle & ); + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ); bool ioPending ( epicsGuard < epicsMutex > & guard ); void begin ( epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void * pValueIn ); void cancel ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; protected: - syncGroupWriteNotify ( struct CASG &, chid ); + syncGroupWriteNotify ( struct CASG &, PRecycleFunc, chid ); virtual ~syncGroupWriteNotify (); // allocate only from pool private: chid chan; - struct CASG & sg; + PRecycleFunc pRecycleFunc; + CASG & sg; const unsigned magic; cacChannel::ioid id; bool idIsValid; bool ioComplete; - void * operator new ( size_t ); void operator delete ( void * ); void * operator new ( size_t, tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & ); @@ -163,17 +159,19 @@ struct ca_client_context; template < class T > class sgAutoPtr; -struct CASG : public chronIntIdRes < CASG >, private casgRecycle { +struct CASG : public chronIntIdRes < CASG > { public: CASG ( epicsGuard < epicsMutex > &, ca_client_context & cacIn ); void destructor ( + CallbackGuard &, epicsGuard < epicsMutex > & guard ); bool ioComplete ( + CallbackGuard &, epicsGuard < epicsMutex > & guard ); bool verify ( epicsGuard < epicsMutex > & ) const; int block ( epicsGuard < epicsMutex > * pcbGuard, epicsGuard < epicsMutex > & guard, double timeout ); - void reset ( epicsGuard < epicsMutex > & guard ); + void reset ( CallbackGuard &, epicsGuard < epicsMutex > & ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; void show ( unsigned level ) const; void get ( epicsGuard < epicsMutex > &, chid pChan, @@ -194,6 +192,7 @@ public: tsFreeList < struct CASG, 128, epicsMutexNOOP > & ); epicsPlacementDeleteOperator (( void *, tsFreeList < struct CASG, 128, epicsMutexNOOP > & )) + private: tsDLList < syncGroupNotify > ioPendingList; tsDLList < syncGroupNotify > ioCompletedList; @@ -202,20 +201,21 @@ private: unsigned magic; tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > freeListReadOP; tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > freeListWriteOP; - void recycleSyncGroupWriteNotify ( - epicsGuard < epicsMutex > &, syncGroupWriteNotify & io ); - void recycleSyncGroupReadNotify ( - epicsGuard < epicsMutex > &, syncGroupReadNotify & io ); void destroyPendingIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); void destroyCompletedIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); + void recycleReadNotifyIO ( epicsGuard < epicsMutex > &, + syncGroupReadNotify & ); + void recycleWriteNotifyIO ( epicsGuard < epicsMutex > &, + syncGroupWriteNotify & ); CASG ( const CASG & ); CASG & operator = ( const CASG & ); - void * operator new ( size_t size ); void operator delete ( void * ); ~CASG (); diff --git a/src/ca/syncGroupReadNotify.cpp b/src/ca/syncGroupReadNotify.cpp index 11f90fe57..33ba5fb32 100644 --- a/src/ca/syncGroupReadNotify.cpp +++ b/src/ca/syncGroupReadNotify.cpp @@ -27,8 +27,10 @@ #include "oldAccess.h" syncGroupReadNotify::syncGroupReadNotify ( - CASG & sgIn, chid pChan, void * pValueIn ) : - chan ( pChan ), sg ( sgIn ), pValue ( pValueIn ), + CASG & sgIn, PRecycleFunc pRecycleFuncIn, + chid pChan, void * pValueIn ) : + chan ( pChan ), pRecycleFunc ( pRecycleFuncIn ), + sg ( sgIn ), pValue ( pValueIn ), magic ( CASG_MAGIC ), id ( 0u ), idIsValid ( false ), ioComplete ( false ) { @@ -46,27 +48,30 @@ void syncGroupReadNotify::begin ( } void syncGroupReadNotify::cancel ( - epicsGuard < epicsMutex > & guard ) + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExcusionGuard ) { if ( this->idIsValid ) { - this->chan->ioCancel ( guard, this->id ); + this->chan->ioCancel ( callbackGuard, mutualExcusionGuard, this->id ); this->idIsValid = false; } } syncGroupReadNotify * syncGroupReadNotify::factory ( tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & freeList, - struct CASG & sg, chid chan, void * pValueIn ) + struct CASG & sg, PRecycleFunc pRecycleFunc, chid chan, void * pValueIn ) { - return new ( freeList ) // X aCC 930 - syncGroupReadNotify ( sg, chan, pValueIn ); + return new ( freeList ) + syncGroupReadNotify ( sg, pRecycleFunc, chan, pValueIn ); } void syncGroupReadNotify::destroy ( - epicsGuard < epicsMutex > & guard, casgRecycle & recycle ) + CallbackGuard &, + epicsGuard < epicsMutex > & guard ) { + CASG & sgRef ( this->sg ); this->~syncGroupReadNotify (); - recycle.recycleSyncGroupReadNotify ( guard, *this ); + ( sgRef.*pRecycleFunc ) ( guard, *this ); } syncGroupReadNotify::~syncGroupReadNotify () @@ -122,13 +127,6 @@ void syncGroupReadNotify::show ( } } -void * syncGroupReadNotify::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void syncGroupReadNotify::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/syncGroupWriteNotify.cpp b/src/ca/syncGroupWriteNotify.cpp index 244d9d3bd..fed76ed81 100644 --- a/src/ca/syncGroupWriteNotify.cpp +++ b/src/ca/syncGroupWriteNotify.cpp @@ -26,8 +26,10 @@ #include "syncGroup.h" #include "oldAccess.h" -syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, chid pChan ) : - chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ), +syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, + PRecycleFunc pRecycleFuncIn, chid pChan ) : + chan ( pChan ), pRecycleFunc ( pRecycleFuncIn ), + sg ( sgIn ), magic ( CASG_MAGIC ), id ( 0u ), idIsValid ( false ), ioComplete ( false ) { } @@ -45,26 +47,29 @@ void syncGroupWriteNotify::begin ( } void syncGroupWriteNotify::cancel ( - epicsGuard < epicsMutex > & guard ) + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExcusionGuard ) { if ( this->idIsValid ) { - this->chan->ioCancel ( guard, this->id ); + this->chan->ioCancel ( callbackGuard, mutualExcusionGuard, this->id ); this->idIsValid = false; } } syncGroupWriteNotify * syncGroupWriteNotify::factory ( tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &freeList, - struct CASG & sg, chid chan ) + struct CASG & sg, PRecycleFunc pRecycleFunc, chid chan ) { - return new ( freeList ) syncGroupWriteNotify ( sg, chan ); + return new ( freeList ) syncGroupWriteNotify ( sg, pRecycleFunc, chan ); } void syncGroupWriteNotify::destroy ( - epicsGuard < epicsMutex > & guard, casgRecycle & recycle ) + CallbackGuard &, + epicsGuard < epicsMutex > & guard ) { + CASG & sgRef ( this->sg ); this->~syncGroupWriteNotify (); - recycle.recycleSyncGroupWriteNotify ( guard, *this ); + ( sgRef.*pRecycleFunc ) ( guard, *this ); } syncGroupWriteNotify::~syncGroupWriteNotify () @@ -112,13 +117,6 @@ void syncGroupWriteNotify::show ( } } -void * syncGroupWriteNotify::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void syncGroupWriteNotify::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if diff --git a/src/ca/syncgrp.cpp b/src/ca/syncgrp.cpp index c76f6a194..cb7a7cffa 100644 --- a/src/ca/syncgrp.cpp +++ b/src/ca/syncgrp.cpp @@ -23,7 +23,7 @@ /* * ca_sg_create() */ -extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) // X aCC 361 +extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) { ca_client_context * pcac; int caStatus; @@ -48,6 +48,22 @@ extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) // X aCC 361 } } +int ca_sync_group_destroy ( CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard, + ca_client_context & cac, const CA_SYNC_GID gid ) +{ + int caStatus; + CASG * pcasg = cac.lookupCASG ( guard, gid ); + if ( pcasg ) { + pcasg->destructor ( cbGuard, guard ); + cac.casgFreeList.release ( pcasg ); + caStatus = ECA_NORMAL; + } + else { + caStatus = ECA_BADSYNCGRP; + } + return caStatus; +} + /* * ca_sg_delete() */ @@ -56,19 +72,51 @@ extern "C" int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid ) ca_client_context * pcac; int caStatus = fetchClientContext ( & pcac ); if ( caStatus == ECA_NORMAL ) { - epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); - CASG * pcasg = pcac->lookupCASG ( guard, gid ); - if ( pcasg ) { - pcasg->destructor ( guard ); - pcac->casgFreeList.release ( pcasg ); + if ( pcac->pCallbackGuard.get() && + pcac->createdByThread == epicsThreadGetIdSelf () ) { + epicsGuard < epicsMutex > guard ( pcac->mutex ); + caStatus = ca_sync_group_destroy ( *pcac->pCallbackGuard.get(), + guard, *pcac, gid ); } else { - caStatus = ECA_BADSYNCGRP; + // + // we will definately stall out here if all of the + // following are true + // + // o user creates non-preemtive mode client library context + // o user doesnt periodically call a ca function + // o user calls this function from an auxiillary thread + // + CallbackGuard cbGuard ( pcac->cbMutex ); + epicsGuard < epicsMutex > guard ( pcac->mutex ); + caStatus = ca_sync_group_destroy ( cbGuard, guard, *pcac, gid ); } } return caStatus; } +void sync_group_reset ( ca_client_context & client, CASG & sg ) +{ + if ( client.pCallbackGuard.get() && + client.createdByThread == epicsThreadGetIdSelf () ) { + epicsGuard < epicsMutex > guard ( client.mutex ); + sg.reset ( *client.pCallbackGuard.get(), guard ); + } + else { + // + // we will definately stall out here if all of the + // following are true + // + // o user creates non-preemtive mode client library context + // o user doesnt periodically call a ca function + // o user calls this function from an auxiillary thread + // + CallbackGuard cbGuard ( client.cbMutex ); + epicsGuard < epicsMutex > guard ( client.mutex ); + sg.reset ( cbGuard, guard ); + } +} + // // ca_sg_block () // @@ -84,14 +132,20 @@ extern "C" int epicsShareAPI ca_sg_block ( ca_client_context *pcac; int status = fetchClientContext ( &pcac ); if ( status == ECA_NORMAL ) { + CASG * pcasg; + { epicsGuard < epicsMutex > guard ( pcac->mutex ); - CASG * pcasg = pcac->lookupCASG ( guard, gid ); - if ( ! pcasg ) { - status = ECA_BADSYNCGRP; - } - else { + pcasg = pcac->lookupCASG ( guard, gid ); + if ( pcasg ) { status = pcasg->block ( pcac->pCallbackGuard.get (), guard, timeout ); + } + else { + status = ECA_BADSYNCGRP; + } + } + if ( pcasg ) { + sync_group_reset ( *pcac, *pcasg ); } } return status; @@ -105,10 +159,14 @@ extern "C" int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid ) ca_client_context *pcac; int caStatus = fetchClientContext (&pcac); if ( caStatus == ECA_NORMAL ) { + CASG * pcasg; + { epicsGuard < epicsMutex > guard ( pcac->mutex ); - CASG * pcasg = pcac->lookupCASG ( guard, gid ); + pcasg = pcac->lookupCASG ( guard, gid ); + } if ( pcasg ) { - pcasg->reset ( guard ); + sync_group_reset ( *pcac, *pcasg ); + caStatus = ECA_NORMAL; } else { caStatus = ECA_BADSYNCGRP; @@ -143,7 +201,7 @@ extern "C" int epicsShareAPI ca_sg_stat ( const CA_SYNC_GID gid ) /* * ca_sg_test */ -extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) // X aCC 361 +extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) { ca_client_context * pcac; int caStatus = fetchClientContext ( &pcac ); @@ -151,7 +209,26 @@ extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) // X aCC 361 epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); CASG * pcasg = pcac->lookupCASG ( guard, gid ); if ( pcasg ) { - if ( pcasg->ioComplete ( guard ) ) { + bool isComplete; + if ( pcac->pCallbackGuard.get() && + pcac->createdByThread == epicsThreadGetIdSelf () ) { + epicsGuard < epicsMutex > guard ( pcac->mutex ); + isComplete = pcasg->ioComplete ( *pcac->pCallbackGuard.get(), guard ); + } + else { + // + // we will definately stall out here if all of the + // following are true + // + // o user creates non-preemtive mode client library context + // o user doesnt periodically call a ca function + // o user calls this function from an auxiillary thread + // + CallbackGuard cbGuard ( pcac->cbMutex ); + epicsGuard < epicsMutex > guard ( pcac->mutex ); + isComplete = pcasg->ioComplete ( cbGuard, guard ); + } + if ( isComplete ) { caStatus = ECA_IODONE; } else{ @@ -172,17 +249,14 @@ extern "C" int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid, chtype typ arrayElementCount count, chid pChan, const void *pValue ) { ca_client_context *pcac; - CASG *pcasg; - int caStatus; - caStatus = fetchClientContext ( &pcac ); + int caStatus = fetchClientContext ( &pcac ); if ( caStatus != ECA_NORMAL ) { return caStatus; } epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); - - pcasg = pcac->lookupCASG ( guard, gid ); + CASG * const pcasg = pcac->lookupCASG ( guard, gid ); if ( ! pcasg ) { return ECA_BADSYNCGRP; } @@ -237,17 +311,14 @@ extern "C" int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid, chtype typ arrayElementCount count, chid pChan, void *pValue ) { ca_client_context *pcac; - CASG *pcasg; - int caStatus; - caStatus = fetchClientContext ( &pcac ); + int caStatus = fetchClientContext ( &pcac ); if ( caStatus != ECA_NORMAL ) { return caStatus; } epicsGuard < epicsMutex > guard ( pcac->mutexRef() ); - - pcasg = pcac->lookupCASG ( guard, gid ); + CASG * const pcasg = pcac->lookupCASG ( guard, gid ); if ( ! pcasg ) { return ECA_BADSYNCGRP; } diff --git a/src/ca/tcpRecvWatchdog.cpp b/src/ca/tcpRecvWatchdog.cpp index 35e509a7c..72c92968b 100644 --- a/src/ca/tcpRecvWatchdog.cpp +++ b/src/ca/tcpRecvWatchdog.cpp @@ -45,7 +45,7 @@ tcpRecvWatchdog::~tcpRecvWatchdog () } epicsTimerNotify::expireStatus -tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) // X aCC 361 +tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); if ( this->shuttingDown ) { diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp index 9cf9f6f4d..377e3ac3c 100644 --- a/src/ca/tcpiiu.cpp +++ b/src/ca/tcpiiu.cpp @@ -1135,7 +1135,7 @@ void tcpiiu::show ( unsigned level ) const } } -bool tcpiiu::setEchoRequestPending ( epicsGuard < epicsMutex > & guard ) // X aCC 361 +bool tcpiiu::setEchoRequestPending ( epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1275,12 +1275,9 @@ bool tcpiiu::processIncoming ( this->msgHeaderAvailable = false; this->curDataBytes = 0u; } -# if defined ( __HP_aCC ) && _HP_aCC <= 033300 - return false; // to make hpux compiler happy... -# endif } -void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 +void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1310,7 +1307,7 @@ void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 4 /* * tcpiiu::userNameSetRequest () */ -void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 +void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1338,7 +1335,7 @@ void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 4 } void tcpiiu::disableFlowControlRequest ( - epicsGuard < epicsMutex > & guard ) // X aCC 431 + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1354,7 +1351,7 @@ void tcpiiu::disableFlowControlRequest ( } void tcpiiu::enableFlowControlRequest ( - epicsGuard < epicsMutex > & guard ) // X aCC 431 + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1369,7 +1366,7 @@ void tcpiiu::enableFlowControlRequest ( minder.commit (); } -void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, // X aCC 431 +void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, const cacChannel::priLev & priority ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1389,7 +1386,7 @@ void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, // X aCC 431 minder.commit (); } -void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 +void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1410,7 +1407,7 @@ void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431 minder.commit (); } -void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 +void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, nciu &chan, unsigned type, arrayElementCount nElem, const void *pValue ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1425,7 +1422,7 @@ void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 } -void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 +void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu &chan, netWriteNotifyIO &io, unsigned type, arrayElementCount nElem, const void *pValue ) { @@ -1444,7 +1441,7 @@ void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 43 minder.commit (); } -void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 +void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, netReadNotifyIO & io, unsigned dataType, arrayElementCount nElem ) { @@ -1477,7 +1474,7 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 } void tcpiiu::createChannelRequest ( - nciu & chan, epicsGuard < epicsMutex > & guard ) // X aCC 431 + nciu & chan, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1525,7 +1522,7 @@ void tcpiiu::createChannelRequest ( minder.commit (); } -void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 +void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, ca_uint32_t sid, ca_uint32_t cid ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1547,7 +1544,7 @@ void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 4 // is to try again the next time that we reconnect // void tcpiiu::subscriptionRequest ( - epicsGuard < epicsMutex > & guard, // X aCC 431 + epicsGuard < epicsMutex > & guard, nciu & chan, netSubscription & subscr ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1599,7 +1596,7 @@ void tcpiiu::subscriptionRequest ( // is to try again the next time that we reconnect // void tcpiiu::subscriptionUpdateRequest ( - epicsGuard < epicsMutex > & guard, // X aCC 431 + epicsGuard < epicsMutex > & guard, nciu & chan, netSubscription & subscr ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1634,7 +1631,7 @@ void tcpiiu::subscriptionUpdateRequest ( minder.commit (); } -void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431 +void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, netSubscription & subscr ) { guard.assertIdenticalMutex ( this->mutex ); @@ -2052,7 +2049,7 @@ bool tcpiiu::bytesArePendingInOS () const return false; #else osiSockIoctl_t bytesPending = 0; /* shut up purifys yapping */ - int status = socket_ioctl ( this->sock, // X aCC 392 + int status = socket_ioctl ( this->sock, FIONREAD, & bytesPending ); if ( status >= 0 ) { if ( bytesPending > 0 ) { diff --git a/src/ca/test_event.cpp b/src/ca/test_event.cpp index c39375aef..17cfe2f47 100644 --- a/src/ca/test_event.cpp +++ b/src/ca/test_event.cpp @@ -78,7 +78,7 @@ extern "C" void epicsShareAPI ca_dump_dbr ( dbr_short_t *pvalue = (dbr_short_t *)pbuffer; for (i = 0; i < count; i++,pvalue++){ if(count!=1 && (i%10 == 0)) printf("\n"); - printf("%d ",* (short *)pvalue); // X aCC 392 + printf("%d ",* (short *)pvalue); } break; } @@ -96,7 +96,7 @@ extern "C" void epicsShareAPI ca_dump_dbr ( dbr_float_t *pvalue = (dbr_float_t *)pbuffer; for (i = 0; i < count; i++,pvalue++){ if(count!=1 && (i%10 == 0)) printf("\n"); - printf("%6.4f ",*(float *)pvalue); // X aCC 392 + printf("%6.4f ",*(float *)pvalue); } break; } diff --git a/src/ca/udpiiu.cpp b/src/ca/udpiiu.cpp index 4760583e9..e4e8bd31f 100644 --- a/src/ca/udpiiu.cpp +++ b/src/ca/udpiiu.cpp @@ -201,7 +201,7 @@ udpiiu::udpiiu ( memset ( (char *)&addr, 0 , sizeof (addr) ); addr.ia.sin_family = AF_INET; addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); - addr.ia.sin_port = htons ( PORT_ANY ); // X aCC 818 + addr.ia.sin_port = htons ( PORT_ANY ); status = bind (this->sock, &addr.sa, sizeof (addr) ); if ( status < 0 ) { char sockErrBuf[64]; @@ -471,7 +471,7 @@ void epicsShareAPI caRepeaterRegistrationMessage ( } memset ( (char *) &msg, 0, sizeof (msg) ); - AlignedWireRef < epicsUInt16 > ( msg.m_cmmd ) = REPEATER_REGISTER; // X aCC 818 + AlignedWireRef < epicsUInt16 > ( msg.m_cmmd ) = REPEATER_REGISTER; msg.m_available = saddr.ia.sin_addr.s_addr; /* diff --git a/src/ca/virtualCircuit.h b/src/ca/virtualCircuit.h index 3d3031f31..017b99d0e 100644 --- a/src/ca/virtualCircuit.h +++ b/src/ca/virtualCircuit.h @@ -335,7 +335,6 @@ private: tcpiiu ( const tcpiiu & ); tcpiiu & operator = ( const tcpiiu & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -372,7 +371,7 @@ inline bool tcpiiu::ca_v49_ok ( } inline bool tcpiiu::alive ( - epicsGuard < epicsMutex > & ) const // X aCC 361 + epicsGuard < epicsMutex > & ) const { return ( this->state == iiucs_connecting || this->state == iiucs_connected ); diff --git a/src/db/dbCAC.h b/src/db/dbCAC.h index 3032023dc..a45bc60aa 100644 --- a/src/db/dbCAC.h +++ b/src/db/dbCAC.h @@ -62,7 +62,7 @@ class dbChannelIO; class dbPutNotifyBlocker; class dbSubscriptionIO; -class dbBaseIO // X aCC 655 +class dbBaseIO : public chronIntIdRes < dbBaseIO > { public: virtual dbSubscriptionIO * isSubscription () = 0; @@ -86,9 +86,9 @@ public: epicsGuard < epicsMutex > &, epicsMutex &, dbContext &, dbChannelIO &, struct dbAddr &, cacStateNotify &, unsigned type, unsigned long count, unsigned mask, dbEventCtx ); - void destructor ( epicsGuard < epicsMutex > & ); - void unsubscribe ( epicsGuard < epicsMutex > & ); - void channelDeleteException ( epicsGuard < epicsMutex > & ); + void destructor ( CallbackGuard &, epicsGuard < epicsMutex > & ); + void unsubscribe ( CallbackGuard &, epicsGuard < epicsMutex > & ); + void channelDeleteException ( CallbackGuard &, epicsGuard < epicsMutex > & ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; void show ( unsigned level ) const; void * operator new ( size_t size, @@ -110,7 +110,6 @@ private: dbSubscriptionIO ( const dbSubscriptionIO & ); dbSubscriptionIO & operator = ( const dbSubscriptionIO & ); virtual ~dbSubscriptionIO (); - void * operator new ( size_t size ); void operator delete ( void * ); }; @@ -165,7 +164,7 @@ public: dbContext ( epicsMutex & cbMutex, epicsMutex & mutex, cacContextNotify & notify ); virtual ~dbContext (); - void destroyChannel ( epicsGuard < epicsMutex > &, dbChannelIO & ); + void destroyChannel ( CallbackGuard &,epicsGuard < epicsMutex > &, dbChannelIO & ); void callReadNotify ( epicsGuard < epicsMutex > &, struct dbAddr & addr, unsigned type, unsigned long count, cacReadNotify & notify ); @@ -182,9 +181,9 @@ public: cacWriteNotify & notify, cacChannel::ioid * pId ); void show ( unsigned level ) const; void showAllIO ( const dbChannelIO & chan, unsigned level ) const; - void destroyAllIO ( + void destroyAllIO ( CallbackGuard & cbGuard, epicsGuard < epicsMutex > &, dbChannelIO & chan ); - void ioCancel ( epicsGuard < epicsMutex > &, + void ioCancel ( CallbackGuard &, epicsGuard < epicsMutex > &, dbChannelIO & chan, const cacChannel::ioid &id ); void ioShow ( epicsGuard < epicsMutex > &, const cacChannel::ioid & id, unsigned level ) const; diff --git a/src/db/dbChannelIO.cpp b/src/db/dbChannelIO.cpp index c95778abe..294c13d71 100644 --- a/src/db/dbChannelIO.cpp +++ b/src/db/dbChannelIO.cpp @@ -61,19 +61,21 @@ dbChannelIO::~dbChannelIO () { } -void dbChannelIO::destructor ( epicsGuard < epicsMutex > & guard ) +void dbChannelIO::destructor ( CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); - this->serviceIO.destroyAllIO ( guard, *this ); + this->serviceIO.destroyAllIO ( cbGuard, guard, *this ); this->~dbChannelIO (); } void dbChannelIO::destroy ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); - this->serviceIO.destroyChannel ( guard, *this ); - // dont access this pointer after above call because + this->serviceIO.destroyChannel ( cbGuard, guard, *this ); + // don't access this pointer after above call because // object nolonger exists } @@ -132,11 +134,12 @@ void dbChannelIO::subscribe ( } void dbChannelIO::ioCancel ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & mutualExclusionGuard, const ioid & id ) { mutualExclusionGuard.assertIdenticalMutex ( this->mutex ); - this->serviceIO.ioCancel ( mutualExclusionGuard, *this, id ); + this->serviceIO.ioCancel ( cbGuard, mutualExclusionGuard, *this, id ); } void dbChannelIO::ioShow ( @@ -204,13 +207,6 @@ void * dbChannelIO::operator new ( size_t size, return freeList.allocate ( size ); } -void * dbChannelIO::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - #ifdef CXX_PLACEMENT_DELETE void dbChannelIO::operator delete ( void *pCadaver, tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList ) diff --git a/src/db/dbChannelIO.h b/src/db/dbChannelIO.h index 0473962ba..54b2e2a3c 100644 --- a/src/db/dbChannelIO.h +++ b/src/db/dbChannelIO.h @@ -48,8 +48,10 @@ public: epicsMutex &, cacChannelNotify &, const dbAddr &, dbContext & ); void destructor ( + CallbackGuard &, epicsGuard < epicsMutex > & ); void destroy ( + CallbackGuard &, epicsGuard < epicsMutex > & mutualExclusionGuard ); void callReadNotify ( epicsGuard < epicsMutex > &, @@ -100,7 +102,8 @@ private: unsigned type, unsigned long count, unsigned mask, cacStateNotify ¬ify, ioid * ); void ioCancel ( - epicsGuard < epicsMutex > & mutualExclusionGuard, + CallbackGuard &, + epicsGuard < epicsMutex > &, const ioid & ); void ioShow ( epicsGuard < epicsMutex > &, @@ -111,7 +114,6 @@ private: epicsGuard < epicsMutex > & ) const; dbChannelIO ( const dbChannelIO & ); dbChannelIO & operator = ( const dbChannelIO & ); - void * operator new ( size_t size ); void operator delete ( void * ); }; diff --git a/src/db/dbContext.cpp b/src/db/dbContext.cpp index 86ebf1997..3ac05dfbc 100644 --- a/src/db/dbContext.cpp +++ b/src/db/dbContext.cpp @@ -83,7 +83,7 @@ dbContext::~dbContext () } } -cacChannel & dbContext::createChannel ( // X aCC 361 +cacChannel & dbContext::createChannel ( epicsGuard < epicsMutex > & guard, const char * pName, cacChannelNotify & notifyIn, cacChannel::priLev priority ) { @@ -119,18 +119,20 @@ cacChannel & dbContext::createChannel ( // X aCC 361 } void dbContext::destroyChannel ( - epicsGuard < epicsMutex > & guard, dbChannelIO & chan ) + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard, + dbChannelIO & chan ) { guard.assertIdenticalMutex ( this->mutex ); if ( chan.dbContextPrivateListOfIO::pBlocker ) { this->ioTable.remove ( *chan.dbContextPrivateListOfIO::pBlocker ); - chan.dbContextPrivateListOfIO::pBlocker->destructor ( guard ); + chan.dbContextPrivateListOfIO::pBlocker->destructor ( cbGuard, guard ); this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker ); chan.dbContextPrivateListOfIO::pBlocker = 0; } - chan.destructor ( guard ); + chan.destructor ( cbGuard, guard ); this->dbChannelIOFreeList.release ( & chan ); } @@ -269,7 +271,9 @@ void dbContext::initiatePutNotify ( } void dbContext::destroyAllIO ( - epicsGuard < epicsMutex > & guard, dbChannelIO & chan ) + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard, + dbChannelIO & chan ) { guard.assertIdenticalMutex ( this->mutex ); dbSubscriptionIO * pIO; @@ -286,24 +290,24 @@ void dbContext::destroyAllIO ( while ( ( pIO = tmp.get() ) ) { // This prevents a db event callback from coming // through after the notify IO is deleted - pIO->unsubscribe ( guard ); + pIO->unsubscribe ( cbGuard, guard ); // If they call ioCancel() here it will be ignored // because the IO has been unregistered above. - pIO->channelDeleteException ( guard ); - pIO->destructor ( guard ); + pIO->channelDeleteException ( cbGuard, guard ); + pIO->destructor ( cbGuard, guard ); this->dbSubscriptionIOFreeList.release ( pIO ); } if ( chan.dbContextPrivateListOfIO::pBlocker ) { - chan.dbContextPrivateListOfIO::pBlocker->destructor ( guard ); + chan.dbContextPrivateListOfIO::pBlocker->destructor ( cbGuard, guard ); this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker ); chan.dbContextPrivateListOfIO::pBlocker = 0; } } void dbContext::ioCancel ( - epicsGuard < epicsMutex > & guard, dbChannelIO & chan, - const cacChannel::ioid &id ) + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard, + dbChannelIO & chan, const cacChannel::ioid &id ) { guard.assertIdenticalMutex ( this->mutex ); dbBaseIO * pIO = this->ioTable.remove ( id ); @@ -311,13 +315,13 @@ void dbContext::ioCancel ( dbSubscriptionIO *pSIO = pIO->isSubscription (); if ( pSIO ) { chan.dbContextPrivateListOfIO::eventq.remove ( *pSIO ); - pSIO->unsubscribe ( guard ); - pSIO->channelDeleteException ( guard ); - pSIO->destructor ( guard ); + pSIO->unsubscribe ( cbGuard, guard ); + pSIO->channelDeleteException ( cbGuard, guard ); + pSIO->destructor ( cbGuard, guard ); this->dbSubscriptionIOFreeList.release ( pSIO ); } else if ( pIO == chan.dbContextPrivateListOfIO::pBlocker ) { - chan.dbContextPrivateListOfIO::pBlocker->cancel ( guard ); + chan.dbContextPrivateListOfIO::pBlocker->cancel ( cbGuard, guard ); } else { errlogPrintf ( "dbContext::ioCancel() unrecognized IO was probably leaked or not canceled\n" ); diff --git a/src/db/dbPutNotifyBlocker.cpp b/src/db/dbPutNotifyBlocker.cpp index e91234b67..6c82e4153 100644 --- a/src/db/dbPutNotifyBlocker.cpp +++ b/src/db/dbPutNotifyBlocker.cpp @@ -59,10 +59,11 @@ dbPutNotifyBlocker::~dbPutNotifyBlocker () { } -void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard ) +void dbPutNotifyBlocker::destructor ( CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); - this->cancel ( guard ); + this->cancel ( cbGuard, guard ); if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) { char * pBuf = static_cast < char * > ( this->pn.pbuffer ); delete [] pBuf; @@ -71,6 +72,7 @@ void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard ) } void dbPutNotifyBlocker::cancel ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -212,13 +214,6 @@ void * dbPutNotifyBlocker::operator new ( size_t size, return freeList.allocate ( size ); } -void * dbPutNotifyBlocker::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - #ifdef CXX_PLACEMENT_DELETE void dbPutNotifyBlocker::operator delete ( void *pCadaver, tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList ) diff --git a/src/db/dbPutNotifyBlocker.h b/src/db/dbPutNotifyBlocker.h index da2cc9fcb..56d3a37da 100644 --- a/src/db/dbPutNotifyBlocker.h +++ b/src/db/dbPutNotifyBlocker.h @@ -42,11 +42,11 @@ class dbPutNotifyBlocker : public dbBaseIO { public: dbPutNotifyBlocker ( epicsMutex & ); - void destructor ( epicsGuard < epicsMutex > & ); + void destructor ( CallbackGuard &, epicsGuard < epicsMutex > & ); void initiatePutNotify ( epicsGuard < epicsMutex > &, cacWriteNotify &, struct dbAddr &, unsigned type, unsigned long count, const void * pValue ); - void cancel ( epicsGuard < epicsMutex > & ); + void cancel ( CallbackGuard &, epicsGuard < epicsMutex > & ); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; void show ( unsigned level ) const; void * operator new ( size_t size, @@ -82,7 +82,6 @@ private: dbPutNotifyBlocker ( const dbPutNotifyBlocker & ); dbPutNotifyBlocker & operator = ( const dbPutNotifyBlocker & ); virtual ~dbPutNotifyBlocker (); - void * operator new ( size_t size ); void operator delete ( void * ); }; diff --git a/src/db/dbSubscriptionIO.cpp b/src/db/dbSubscriptionIO.cpp index 4fd190d3f..260d26e89 100644 --- a/src/db/dbSubscriptionIO.cpp +++ b/src/db/dbSubscriptionIO.cpp @@ -66,13 +66,14 @@ dbSubscriptionIO::~dbSubscriptionIO () { } -void dbSubscriptionIO::destructor ( epicsGuard < epicsMutex > & guard ) +void dbSubscriptionIO::destructor ( CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); this->~dbSubscriptionIO (); } -void dbSubscriptionIO::unsubscribe ( +void dbSubscriptionIO::unsubscribe ( CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -87,6 +88,7 @@ void dbSubscriptionIO::unsubscribe ( } void dbSubscriptionIO::channelDeleteException ( + CallbackGuard &, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); @@ -94,13 +96,6 @@ void dbSubscriptionIO::channelDeleteException ( this->chan.pName(guard), this->type, this->count ); } -void * dbSubscriptionIO::operator new ( size_t ) // X aCC 361 -{ - // The HPUX compiler seems to require this even though no code - // calls it directly - throw std::logic_error ( "why is the compiler calling private operator new" ); -} - void dbSubscriptionIO::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if