From 5e5ea11658b30feeafb2f5bb075b23e6f8663a4d Mon Sep 17 00:00:00 2001 From: "Jeff Hill johill@lanl.gov" Date: Thu, 16 May 2013 11:17:47 -0600 Subject: [PATCH] fix for https://bugs.launchpad.net/epics-base/+bug/1179642 --- src/ca/client/CASG.cpp | 103 ++++---- src/ca/client/access.cpp | 148 ++++++----- src/ca/client/ca_client_context.cpp | 208 ++++++++------- src/ca/client/cac.cpp | 287 ++++++++++----------- src/ca/client/cac.h | 196 +++++++-------- src/ca/client/cacIO.h | 127 ++++++---- src/ca/client/nciu.cpp | 173 ++++++------- src/ca/client/nciu.h | 137 +++++----- src/ca/client/oldAccess.h | 334 ++++++++++++++----------- src/ca/client/oldChannelNotify.cpp | 107 ++++---- src/ca/client/sgAutoPtr.h | 23 +- src/ca/client/syncGroup.h | 179 ++++++------- src/ca/client/syncGroupReadNotify.cpp | 57 +++-- src/ca/client/syncGroupWriteNotify.cpp | 53 ++-- src/ca/client/syncgrp.cpp | 137 +++++++--- src/ioc/db/dbCAC.h | 14 +- src/ioc/db/dbChannelIO.cpp | 11 +- src/ioc/db/dbChannelIO.h | 9 +- src/ioc/db/dbContext.cpp | 32 +-- src/ioc/db/dbPutNotifyBlocker.cpp | 6 +- src/ioc/db/dbPutNotifyBlocker.h | 4 +- src/ioc/db/dbSubscriptionIO.cpp | 8 +- 22 files changed, 1287 insertions(+), 1066 deletions(-) diff --git a/src/ca/client/CASG.cpp b/src/ca/client/CASG.cpp index 4938d2364..b2dbaac4d 100644 --- a/src/ca/client/CASG.cpp +++ b/src/ca/client/CASG.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* @@ -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 ) { @@ -37,13 +35,14 @@ CASG::~CASG () { } -void CASG::destructor ( +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; } @@ -61,9 +60,9 @@ bool CASG::verify ( epicsGuard < epicsMutex > & ) const /* * CASG::block () */ -int CASG::block ( - epicsGuard < epicsMutex > * pcbGuard, - epicsGuard < epicsMutex > & guard, +int CASG::block ( + epicsGuard < epicsMutex > * pcbGuard, + epicsGuard < epicsMutex > & guard, double timeout ) { epicsTime cur_time; @@ -75,7 +74,7 @@ int CASG::block ( guard.assertIdenticalMutex ( this->client.mutexRef() ); // prevent recursion nightmares by disabling blocking - // for IO from within a CA callback. + // for IO from within a CA callback. if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) { return ECA_EVDISALLOW; } @@ -120,44 +119,45 @@ int CASG::block ( } /* - * force a time update + * force a time update */ cur_time = epicsTime::getCurrent (); delay = cur_time - beg_time; } - this->reset ( guard ); - return status; } -void CASG::reset ( +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 ( +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 ( +void CASG::destroyPendingIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) { - pNotify->cancel ( guard ); - // cancel must release the guard while + pNotify->cancel ( cbGuard, guard ); + // cancel must release the guard while // canceling put callbacks so we // must double check list membership if ( pNotify->ioPending ( guard ) ) { @@ -166,7 +166,7 @@ void CASG::destroyPendingIO ( else { this->ioCompletedList.remove ( *pNotify ); } - pNotify->destroy ( guard, *this ); + pNotify->destroy ( cbGuard, guard ); } } @@ -176,7 +176,7 @@ void CASG::show ( unsigned level ) const this->show ( guard, level ); } -void CASG::show ( +void CASG::show ( epicsGuard < epicsMutex > & guard, unsigned level ) const { guard.assertIdenticalMutex ( this->client.mutexRef() ); @@ -184,14 +184,14 @@ void CASG::show ( this->getId (), this->magic, this->ioPendingList.count () ); if ( level ) { ::printf ( "\tPending" ); - tsDLIterConst < syncGroupNotify > notifyPending = + tsDLIterConst < syncGroupNotify > notifyPending = this->ioPendingList.firstIter (); while ( notifyPending.valid () ) { notifyPending->show ( guard, level - 1u ); notifyPending++; } ::printf ( "\tCompleted" ); - tsDLIterConst < syncGroupNotify > notifyCompleted = + tsDLIterConst < syncGroupNotify > notifyCompleted = this->ioCompletedList.firstIter (); while ( notifyCompleted.valid () ) { notifyCompleted->show ( guard, level - 1u ); @@ -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,14 +224,14 @@ 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 (); } -void CASG::completionNotify ( +void CASG::completionNotify ( epicsGuard < epicsMutex > & guard, syncGroupNotify & notify ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); @@ -241,56 +242,56 @@ 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; int status; va_start ( theArgs, pformat ); - + status = this->client.varArgsPrintFormated ( pformat, theArgs ); - + va_end ( theArgs ); - + return status; } -void CASG::exception ( - epicsGuard < epicsMutex > & guard, - int status, const char * pContext, +void CASG::exception ( + epicsGuard < epicsMutex > & guard, + int status, const char * pContext, const char * pFileName, unsigned lineNo ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); if ( status != ECA_CHANDESTROY ) { - this->client.exception ( + this->client.exception ( guard, status, pContext, pFileName, lineNo ); } } -void CASG::exception ( - epicsGuard < epicsMutex > & guard, +void CASG::exception ( + epicsGuard < epicsMutex > & guard, int status, const char * pContext, - const char * pFileName, unsigned lineNo, oldChannelNotify & chan, + const char * pFileName, unsigned lineNo, oldChannelNotify & chan, unsigned type, arrayElementCount count, unsigned op ) { guard.assertIdenticalMutex ( this->client.mutexRef() ); if ( status != ECA_CHANDESTROY ) { - this->client.exception ( - guard, status, pContext, pFileName, + this->client.exception ( + guard, status, pContext, pFileName, lineNo, chan, type, count, op ); } } diff --git a/src/ca/client/access.cpp b/src/ca/client/access.cpp index 74278acd2..8c1f9901e 100644 --- a/src/ca/client/access.cpp +++ b/src/ca/client/access.cpp @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* @@ -30,7 +30,7 @@ /* - * allocate error message string array + * allocate error message string array * here so I can use sizeof */ #define CA_ERROR_GLBLSOURCE @@ -182,7 +182,7 @@ int epicsShareAPI ca_task_initialize ( void ) } // extern "C" -int epicsShareAPI ca_context_create ( +int epicsShareAPI ca_context_create ( ca_preemptive_callback_select premptiveCallbackSelect ) { ca_client_context *pcac; @@ -202,7 +202,7 @@ int epicsShareAPI ca_context_create ( return ECA_NORMAL; } - pcac = new ca_client_context ( + pcac = new ca_client_context ( premptiveCallbackSelect == ca_enable_preemptive_callback ); if ( ! pcac ) { return ECA_ALLOCMEM; @@ -275,7 +275,7 @@ int epicsShareAPI ca_task_exit () */ // extern "C" int epicsShareAPI ca_build_and_connect ( const char *name_str, chtype get_type, - arrayElementCount get_count, chid * chan, void *pvalue, + arrayElementCount get_count, chid * chan, void *pvalue, caCh *conn_func, void *puser ) { if ( get_type != TYPENOTCONN && pvalue != 0 && get_count != 0 ) { @@ -286,14 +286,14 @@ int epicsShareAPI ca_build_and_connect ( const char *name_str, chtype get_type, } /* - * ca_search_and_connect() + * ca_search_and_connect() */ // extern "C" int epicsShareAPI ca_search_and_connect ( const char * name_str, chid * chanptr, caCh * conn_func, void * puser ) { - return ca_create_channel ( name_str, conn_func, + return ca_create_channel ( name_str, conn_func, puser, CA_PRIORITY_DEFAULT, chanptr ); } @@ -312,7 +312,7 @@ int epicsShareAPI ca_create_channel ( CAFDHANDLER * pFunc = 0; void * pArg = 0; { - epicsGuard < epicsMutex > + epicsGuard < epicsMutex > guard ( pcac->mutex ); if ( pcac->fdRegFuncNeedsToBeCalled ) { pFunc = pcac->fdRegFunc; @@ -327,9 +327,9 @@ int epicsShareAPI ca_create_channel ( try { epicsGuard < epicsMutex > guard ( pcac->mutex ); - oldChannelNotify * pChanNotify = - new ( pcac->oldChannelNotifyFreeList ) - oldChannelNotify ( guard, *pcac, name_str, + oldChannelNotify * pChanNotify = + new ( pcac->oldChannelNotifyFreeList ) + oldChannelNotify ( guard, *pcac, name_str, conn_func, puser, priority ); // make sure that their chan pointer is set prior to // calling connection call backs @@ -352,9 +352,9 @@ int epicsShareAPI ca_create_channel ( return ECA_UNAVAILINSERV; } catch ( std :: exception & except ) { - pcac->printFormated ( + pcac->printFormated ( "ca_create_channel: " - "unexpected exception was \"%s\"", + "unexpected exception was \"%s\"", except.what () ); return ECA_INTERNAL; } @@ -369,22 +369,42 @@ int epicsShareAPI ca_create_channel ( * ca_clear_channel () * * a known defect here is that there will be a - * crash if they destroy the channel after destroying + * crash if they destroy the channel after destroying * its context */ // extern "C" 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 + 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 ); } - pChan->destructor ( guard ); - cac.oldChannelNotifyFreeList.release ( pChan ); return ECA_NORMAL; } @@ -399,7 +419,7 @@ int epicsShareAPI ca_add_exception_event ( caExceptionHandler *pfunc, void *arg if ( caStatus != ECA_NORMAL ) { return caStatus; } - + pcac->changeExceptionEvent ( pfunc, arg ); return ECA_NORMAL; @@ -408,10 +428,10 @@ int epicsShareAPI ca_add_exception_event ( caExceptionHandler *pfunc, void *arg /* * ca_add_masked_array_event */ -int epicsShareAPI ca_add_masked_array_event ( - chtype type, arrayElementCount count, chid pChan, - caEventCallBackFunc *pCallBack, void *pCallBackArg, - ca_real, ca_real, ca_real, +int epicsShareAPI ca_add_masked_array_event ( + chtype type, arrayElementCount count, chid pChan, + caEventCallBackFunc *pCallBack, void *pCallBackArg, + ca_real, ca_real, ca_real, evid *monixptr, long mask ) { return ca_create_subscription ( type, count, pChan, mask, @@ -429,7 +449,7 @@ int epicsShareAPI ca_clear_event ( evid pMon ) // extern "C" chid epicsShareAPI ca_evid_to_chid ( evid pMon ) { - return & pMon->channel (); + return & pMon->channel (); } // extern "C" @@ -498,7 +518,7 @@ int epicsShareAPI ca_pend_io ( ca_real timeout ) /* * ca_flush_io () - */ + */ int epicsShareAPI ca_flush_io () { ca_client_context * pcac; @@ -545,7 +565,7 @@ void epicsShareAPI ca_signal ( long ca_status, const char *message ) * ca_message (long ca_status) * * - if it is an unknown error code then it possible - * that the error string generated below + * that the error string generated below * will be overwritten before (or while) the caller * of this routine is calling this routine * (if they call this routine again). @@ -567,7 +587,7 @@ const char * epicsShareAPI ca_message ( long ca_status ) * ca_signal_with_file_and_lineno() */ // extern "C" -void epicsShareAPI ca_signal_with_file_and_lineno ( long ca_status, +void epicsShareAPI ca_signal_with_file_and_lineno ( long ca_status, const char *message, const char *pfilenm, int lineno ) { ca_signal_formated ( ca_status, pfilenm, lineno, message ); @@ -577,7 +597,7 @@ void epicsShareAPI ca_signal_with_file_and_lineno ( long ca_status, * ca_signal_formated() */ // extern "C" -void epicsShareAPI ca_signal_formated ( long ca_status, const char *pfilenm, +void epicsShareAPI ca_signal_formated ( long ca_status, const char *pfilenm, int lineno, const char *pFormat, ... ) { ca_client_context *pcac; @@ -590,12 +610,12 @@ void epicsShareAPI ca_signal_formated ( long ca_status, const char *pfilenm, } va_list theArgs; - va_start ( theArgs, pFormat ); + va_start ( theArgs, pFormat ); if ( pcac ) { pcac->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs ); } else { - fprintf ( stderr, "CA exception in thread w/o CA ctx: status=%s file=%s line=%d: \n", + fprintf ( stderr, "CA exception in thread w/o CA ctx: status=%s file=%s line=%d: \n", ca_message ( ca_status ), pfilenm, lineno ); if ( pFormat ) { vfprintf ( stderr, pFormat, theArgs ); @@ -607,7 +627,7 @@ void epicsShareAPI ca_signal_formated ( long ca_status, const char *pfilenm, /* * CA_ADD_FD_REGISTRATION * - * call their function with their argument whenever + * call their function with their argument whenever * a new fd is added or removed * (for a manager of the select system call under UNIX) * @@ -631,7 +651,7 @@ int epicsShareAPI ca_add_fd_registration ( CAFDHANDLER * func, void * arg ) * function that returns the CA version string */ // extern "C" -const char * epicsShareAPI ca_version () +const char * epicsShareAPI ca_version () { return CA_VERSION_STRING ( CA_MINOR_PROTOCOL_REVISION ); } @@ -660,7 +680,7 @@ int epicsShareAPI ca_replace_printf_handler ( caPrintfFunc *ca_printf_func ) * (for testing purposes only) */ // extern "C" -unsigned epicsShareAPI ca_get_ioc_connection_count () +unsigned epicsShareAPI ca_get_ioc_connection_count () { ca_client_context * pcac; int caStatus = fetchClientContext ( & pcac ); @@ -720,7 +740,7 @@ struct ca_client_context * epicsShareAPI ca_current_context () { struct ca_client_context *pCtx; if ( caClientContextId ) { - pCtx = ( struct ca_client_context * ) + pCtx = ( struct ca_client_context * ) epicsThreadPrivateGet ( caClientContextId ); } else { @@ -749,7 +769,7 @@ int epicsShareAPI ca_attach_context ( struct ca_client_context * pCtx ) return ECA_NORMAL; } -void epicsShareAPI ca_detach_context () +void epicsShareAPI ca_detach_context () { if ( caClientContextId ) { epicsThreadPrivateSet ( caClientContextId, 0 ); @@ -794,43 +814,43 @@ epicsShareDef const int epicsTypeToDBR_XXXX [lastEpicsType+1] = { // extern "C" epicsShareDef const epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1] = { epicsOldStringT, - epicsInt16T, - epicsFloat32T, - epicsEnum16T, - epicsUInt8T, - epicsInt32T, + epicsInt16T, + epicsFloat32T, + epicsEnum16T, + epicsUInt8T, + epicsInt32T, epicsFloat64T, epicsOldStringT, - epicsInt16T, - epicsFloat32T, - epicsEnum16T, - epicsUInt8T, - epicsInt32T, + epicsInt16T, + epicsFloat32T, + epicsEnum16T, + epicsUInt8T, + epicsInt32T, epicsFloat64T, epicsOldStringT, - epicsInt16T, - epicsFloat32T, - epicsEnum16T, - epicsUInt8T, - epicsInt32T, + epicsInt16T, + epicsFloat32T, + epicsEnum16T, + epicsUInt8T, + epicsInt32T, epicsFloat64T, epicsOldStringT, - epicsInt16T, - epicsFloat32T, - epicsEnum16T, - epicsUInt8T, - epicsInt32T, + epicsInt16T, + epicsFloat32T, + epicsEnum16T, + epicsUInt8T, + epicsInt32T, epicsFloat64T, epicsOldStringT, - epicsInt16T, - epicsFloat32T, - epicsEnum16T, - epicsUInt8T, - epicsInt32T, + epicsInt16T, + epicsFloat32T, + epicsEnum16T, + epicsUInt8T, + epicsInt32T, epicsFloat64T, epicsUInt16T, @@ -939,7 +959,7 @@ epicsShareDef const unsigned short dbr_value_size[LAST_BUFFER_TYPE+1] = { sizeof(dbr_string_t), /* string max size */ }; -//extern "C" +//extern "C" epicsShareDef const enum dbr_value_class dbr_value_class[LAST_BUFFER_TYPE+1] = { dbr_class_string, /* string max size */ dbr_class_int, /* short */ diff --git a/src/ca/client/ca_client_context.cpp b/src/ca/client/ca_client_context.cpp index c96c215f9..75ff80bb0 100644 --- a/src/ca/client/ca_client_context.cpp +++ b/src/ca/client/ca_client_context.cpp @@ -4,19 +4,19 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* +/* + * * - * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 - * + * * Copyright, 1986, The Regents of the University of California. - * - * + * + * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 @@ -27,7 +27,7 @@ #endif #include -#include // vxWorks 6.0 requires this include +#include // vxWorks 6.0 requires this include #include #include "epicsExit.h" @@ -67,11 +67,11 @@ cacService * ca_client_context::pDefaultService = 0; epicsMutex * ca_client_context::pDefaultServiceInstallMutex; ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : - createdByThread ( epicsThreadGetIdSelf () ), - ca_exception_func ( 0 ), ca_exception_arg ( 0 ), + createdByThread ( epicsThreadGetIdSelf () ), + ca_exception_func ( 0 ), ca_exception_arg ( 0 ), pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ), - pndRecvCnt ( 0u ), ioSeqNo ( 0u ), callbackThreadsPending ( 0u ), - localPort ( 0 ), fdRegFuncNeedsToBeCalled ( false ), + pndRecvCnt ( 0u ), ioSeqNo ( 0u ), callbackThreadsPending ( 0u ), + localPort ( 0 ), fdRegFuncNeedsToBeCalled ( false ), noWakeupSincePend ( true ) { static const unsigned short PORT_ANY = 0u; @@ -85,7 +85,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex ); if ( ca_client_context::pDefaultService ) { this->pServiceContext.reset ( - & ca_client_context::pDefaultService->contextCreate ( + & ca_client_context::pDefaultService->contextCreate ( this->mutex, this->cbMutex, *this ) ); } else { @@ -125,7 +125,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : osiSockAddr addr; memset ( (char *)&addr, 0 , sizeof ( addr ) ); addr.ia.sin_family = AF_INET; - addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); + addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); addr.ia.sin_port = htons ( PORT_ANY ); int status = bind (this->sock, &addr.sa, sizeof (addr) ); if ( status < 0 ) { @@ -139,7 +139,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : throwWithLocation ( noSocket () ); } } - + { osiSockAddr tmpAddr; osiSocklen_t saddr_length = sizeof ( tmpAddr ); @@ -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 @@ -171,7 +171,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) : ca_client_context::~ca_client_context () { if ( this->fdRegFunc ) { - ( *this->fdRegFunc ) + ( *this->fdRegFunc ) ( this->fdRegArg, this->sock, false ); } epicsSocketDestroy ( this->sock ); @@ -179,9 +179,9 @@ ca_client_context::~ca_client_context () osiSockRelease (); // force a logical shutdown order - // so that the cac class does not hang its + // so that the cac class does not hang its // receive threads during their shutdown sequence - // and so that classes using this classes mutex + // and so that classes using this classes mutex // are destroyed before the mutex is destroyed if ( this->pCallbackGuard.get() ) { epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard ); @@ -192,7 +192,7 @@ ca_client_context::~ca_client_context () } } -void ca_client_context::destroyGetCopy ( +void ca_client_context::destroyGetCopy ( epicsGuard < epicsMutex > & guard, getCopy & gc ) { guard.assertIdenticalMutex ( this->mutex ); @@ -200,7 +200,7 @@ void ca_client_context::destroyGetCopy ( this->getCopyFreeList.release ( & gc ); } -void ca_client_context::destroyGetCallback ( +void ca_client_context::destroyGetCallback ( epicsGuard < epicsMutex > & guard, getCallback & gcb ) { guard.assertIdenticalMutex ( this->mutex ); @@ -208,7 +208,7 @@ void ca_client_context::destroyGetCallback ( this->getCallbackFreeList.release ( & gcb ); } -void ca_client_context::destroyPutCallback ( +void ca_client_context::destroyPutCallback ( epicsGuard < epicsMutex > & guard, putCallback & pcb ) { guard.assertIdenticalMutex ( this->mutex ); @@ -216,7 +216,7 @@ void ca_client_context::destroyPutCallback ( this->putCallbackFreeList.release ( & pcb ); } -void ca_client_context::destroySubscription ( +void ca_client_context::destroySubscription ( epicsGuard < epicsMutex > & guard, oldSubscription & os ) { guard.assertIdenticalMutex ( this->mutex ); @@ -224,7 +224,7 @@ void ca_client_context::destroySubscription ( this->subscriptionFreeList.release ( & os ); } -void ca_client_context::changeExceptionEvent ( +void ca_client_context::changeExceptionEvent ( caExceptionHandler * pfunc, void * arg ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -233,7 +233,7 @@ void ca_client_context::changeExceptionEvent ( // should block here until releated callback in progress completes } -void ca_client_context::replaceErrLogHandler ( +void ca_client_context::replaceErrLogHandler ( caPrintfFunc * ca_printf_func ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -246,7 +246,7 @@ void ca_client_context::replaceErrLogHandler ( // should block here until releated callback in progress completes } -void ca_client_context::registerForFileDescriptorCallBack ( +void ca_client_context::registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -261,22 +261,22 @@ void ca_client_context::registerForFileDescriptorCallBack ( // should block here until releated callback in progress completes } -int ca_client_context :: printFormated ( +int ca_client_context :: printFormated ( const char *pformat, ... ) const { va_list theArgs; int status; va_start ( theArgs, pformat ); - + status = this->ca_client_context :: varArgsPrintFormated ( pformat, theArgs ); - + va_end ( theArgs ); - + return status; } -int ca_client_context :: varArgsPrintFormated ( +int ca_client_context :: varArgsPrintFormated ( const char *pformat, va_list args ) const { caPrintfFunc * pFunc; @@ -292,8 +292,8 @@ int ca_client_context :: varArgsPrintFormated ( } } -void ca_client_context::exception ( - epicsGuard < epicsMutex > & guard, int stat, const char * pCtx, +void ca_client_context::exception ( + epicsGuard < epicsMutex > & guard, int stat, const char * pCtx, const char * pFile, unsigned lineNo ) { struct exception_handler_args args; @@ -321,9 +321,9 @@ void ca_client_context::exception ( } } -void ca_client_context::exception ( +void ca_client_context::exception ( epicsGuard < epicsMutex > & guard, int status, const char * pContext, - const char * pFileName, unsigned lineNo, oldChannelNotify & chan, + const char * pFileName, unsigned lineNo, oldChannelNotify & chan, unsigned type, arrayElementCount count, unsigned op ) { struct exception_handler_args args; @@ -346,29 +346,29 @@ void ca_client_context::exception ( ( *pFunc ) ( args ); } else { - this->signal ( status, pFileName, lineNo, - "op=%u, channel=%s, type=%s, count=%lu, ctx=\"%s\"", - op, ca_name ( &chan ), - dbr_type_to_text ( static_cast ( type ) ), + this->signal ( status, pFileName, lineNo, + "op=%u, channel=%s, type=%s, count=%lu, ctx=\"%s\"", + op, ca_name ( &chan ), + dbr_type_to_text ( static_cast ( type ) ), count, pContext ); } } } -void ca_client_context::signal ( int ca_status, const char * pfilenm, +void ca_client_context::signal ( int ca_status, const char * pfilenm, int lineno, const char * pFormat, ... ) { va_list theArgs; - va_start ( theArgs, pFormat ); + va_start ( theArgs, pFormat ); this->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs); va_end ( theArgs ); } -void ca_client_context :: vSignal ( - int ca_status, const char *pfilenm, +void ca_client_context :: vSignal ( + int ca_status, const char *pfilenm, int lineno, const char *pFormat, va_list args ) { - static const char *severity[] = + static const char *severity[] = { "Warning", "Success", @@ -379,11 +379,11 @@ void ca_client_context :: vSignal ( "Fatal", "Fatal" }; - + this->printFormated ( "CA.Client.Exception...............................................\n" ); - - this->printFormated ( " %s: \"%s\"\n", - severity[ CA_EXTRACT_SEVERITY ( ca_status ) ], + + this->printFormated ( " %s: \"%s\"\n", + severity[ CA_EXTRACT_SEVERITY ( ca_status ) ], ca_message ( ca_status ) ); if ( pFormat ) { @@ -391,26 +391,26 @@ void ca_client_context :: vSignal ( this->varArgsPrintFormated ( pFormat, args ); this->printFormated ( "\"\n" ); } - + if ( pfilenm ) { this->printFormated ( " Source File: %s line %d\n", - pfilenm, lineno ); - } + pfilenm, lineno ); + } epicsTime current = epicsTime::getCurrent (); char date[64]; current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f"); this->printFormated ( " Current Time: %s\n", date ); - + /* * Terminate execution if unsuccessful */ - if( ! ( ca_status & CA_M_SUCCESS ) && + if( ! ( ca_status & CA_M_SUCCESS ) && CA_EXTRACT_SEVERITY ( ca_status ) != CA_K_WARNING ){ errlogFlush (); abort (); } - + this->printFormated ( "..................................................................\n" ); } @@ -418,7 +418,7 @@ void ca_client_context::show ( unsigned level ) const { epicsGuard < epicsMutex > guard ( this->mutex ); - ::printf ( "ca_client_context at %p pndRecvCnt=%u ioSeqNo=%u\n", + ::printf ( "ca_client_context at %p pndRecvCnt=%u ioSeqNo=%u\n", static_cast ( this ), this->pndRecvCnt, this->ioSeqNo ); @@ -443,7 +443,7 @@ void ca_client_context::attachToClientCtx () epicsThreadPrivateSet ( caClientContextId, this ); } -void ca_client_context::incrementOutstandingIO ( +void ca_client_context::incrementOutstandingIO ( epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn ) { guard.assertIdenticalMutex ( this->mutex ); @@ -453,7 +453,7 @@ void ca_client_context::incrementOutstandingIO ( } } -void ca_client_context::decrementOutstandingIO ( +void ca_client_context::decrementOutstandingIO ( epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn ) { guard.assertIdenticalMutex ( this->mutex ); @@ -466,16 +466,16 @@ void ca_client_context::decrementOutstandingIO ( } } -// !!!! This routine is only visible in the old interface - or in a new ST interface. -// !!!! In the old interface we restrict thread attach so that calls from threads -// !!!! other than the initializing thread are not allowed if preemptive callback +// !!!! This routine is only visible in the old interface - or in a new ST interface. +// !!!! In the old interface we restrict thread attach so that calls from threads +// !!!! other than the initializing thread are not allowed if preemptive callback // !!!! is disabled. This prevents the preemptive callback lock from being released // !!!! by other threads than the one that locked it. // int ca_client_context::pendIO ( const double & timeout ) { - // prevent recursion nightmares by disabling calls to - // pendIO () from within a CA callback. + // prevent recursion nightmares by disabling calls to + // pendIO () from within a CA callback. if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) { return ECA_EVDISALLOW; } @@ -487,7 +487,7 @@ int ca_client_context::pendIO ( const double & timeout ) epicsGuard < epicsMutex > guard ( this->mutex ); this->flush ( guard ); - + while ( this->pndRecvCnt > 0 ) { if ( remaining < CAC_SIGNIFICANT_DELAY ) { status = ECA_TIMEOUT; @@ -514,16 +514,16 @@ int ca_client_context::pendIO ( const double & timeout ) return status; } -// !!!! This routine is only visible in the old interface - or in a new ST interface. -// !!!! In the old interface we restrict thread attach so that calls from threads -// !!!! other than the initializing thread are not allowed if preemptive callback +// !!!! This routine is only visible in the old interface - or in a new ST interface. +// !!!! In the old interface we restrict thread attach so that calls from threads +// !!!! other than the initializing thread are not allowed if preemptive callback // !!!! is disabled. This prevents the preemptive callback lock from being released // !!!! by other threads than the one that locked it. // int ca_client_context::pendEvent ( const double & timeout ) { - // prevent recursion nightmares by disabling calls to - // pendIO () from within a CA callback. + // prevent recursion nightmares by disabling calls to + // pendIO () from within a CA callback. if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) { return ECA_EVDISALLOW; } @@ -541,17 +541,17 @@ int ca_client_context::pendEvent ( const double & timeout ) epicsGuard < epicsMutex > guard ( this->mutex ); // - // This is needed because in non-preemptive callback mode - // legacy applications that use file descriptor managers + // This is needed because in non-preemptive callback mode + // legacy applications that use file descriptor managers // will register for ca receive thread activity and keep // calling ca_pend_event until all of the socket data has - // been read. We must guarantee that other threads get a + // been read. We must guarantee that other threads get a // chance to run if there is data in any of the sockets. // if ( this->fdRegFunc ) { epicsGuardRelease < epicsMutex > unguard ( guard ); - // remove short udp message sent to wake + // remove short udp message sent to wake // up a file descriptor manager osiSockAddr tmpAddr; osiSocklen_t addrSize = sizeof ( tmpAddr.sa ); @@ -592,7 +592,7 @@ int ca_client_context::pendEvent ( const double & timeout ) return ECA_TIMEOUT; } -void ca_client_context::blockForEventAndEnableCallbacks ( +void ca_client_context::blockForEventAndEnableCallbacks ( epicsEvent & event, const double & timeout ) { if ( this->pCallbackGuard.get() ) { @@ -659,12 +659,12 @@ void ca_client_context::callbackProcessingCompleteNotify () } } -cacChannel & ca_client_context::createChannel ( - epicsGuard < epicsMutex > & guard, const char * pChannelName, +cacChannel & ca_client_context::createChannel ( + epicsGuard < epicsMutex > & guard, const char * pChannelName, cacChannelNotify & chan, cacChannel::priLev pri ) { guard.assertIdenticalMutex ( this->mutex ); - return this->pServiceContext->createChannel ( + return this->pServiceContext->createChannel ( guard, pChannelName, chan, pri ); } @@ -685,21 +685,21 @@ unsigned ca_client_context::beaconAnomaliesSinceProgramStart () const return this->pServiceContext->beaconAnomaliesSinceProgramStart ( guard ); } -void ca_client_context::installCASG ( +void ca_client_context::installCASG ( epicsGuard < epicsMutex > & guard, CASG & sg ) { guard.assertIdenticalMutex ( this->mutex ); this->sgTable.idAssignAdd ( sg ); } -void ca_client_context::uninstallCASG ( +void ca_client_context::uninstallCASG ( epicsGuard < epicsMutex > & guard, CASG & sg ) { guard.assertIdenticalMutex ( this->mutex ); this->sgTable.remove ( sg ); } -CASG * ca_client_context::lookupCASG ( +CASG * ca_client_context::lookupCASG ( epicsGuard < epicsMutex > & guard, unsigned idIn ) { guard.assertIdenticalMutex ( this->mutex ); @@ -724,7 +724,7 @@ epicsMutex & ca_client_context::mutexRef () const return this->mutex; } -cacContext & ca_client_context::createNetworkContext ( +cacContext & ca_client_context::createNetworkContext ( epicsMutex & mutexIn, epicsMutex & cbMutexIn ) { return * new cac ( mutexIn, cbMutexIn, *this ); @@ -751,34 +751,54 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon ) { oldChannelNotify & chan = pMon->channel (); ca_client_context & cac = chan.getClientCtx (); - epicsGuard < epicsMutex > guard ( cac.mutex ); - try { - // if this stalls out on a live circuit then an exception - // can be forthcoming which we must ignore as the clear - // request must always be successful - chan.eliminateExcessiveSendBacklog ( guard ); + // !!!! 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 + // can be forthcoming which we must ignore as the clear + // request must always be successful + chan.eliminateExcessiveSendBacklog ( guard ); + } + catch ( cacChannel::notConnected & ) { + // intentionally ignored + } } - catch ( cacChannel::notConnected & ) { - // intentionally ignored + 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 ); } - pMon->cancel ( guard ); return ECA_NORMAL; } -void ca_client_context :: eliminateExcessiveSendBacklog ( +void ca_client_context :: eliminateExcessiveSendBacklog ( epicsGuard < epicsMutex > & guard, cacChannel & chan ) { - if ( chan.requestMessageBytesPending ( guard ) > + if ( chan.requestMessageBytesPending ( guard ) > ca_client_context :: flushBlockThreshold ) { - if ( this->pCallbackGuard.get() && + if ( this->pCallbackGuard.get() && this->createdByThread == epicsThreadGetIdSelf () ) { - // we need to be very careful about lock hierarchy + // we need to be very careful about lock hierarchy // inversion in this situation epicsGuardRelease < epicsMutex > unguard ( guard ); { epicsGuardRelease < epicsMutex > cbunguard ( * this->pCallbackGuard.get() ); - { + { epicsGuard < epicsMutex > nestedGuard ( this->mutex ); chan.flush ( nestedGuard ); } diff --git a/src/ca/client/cac.cpp b/src/ca/client/cac.cpp index 99825f417..9d23cce62 100644 --- a/src/ca/client/cac.cpp +++ b/src/ca/client/cac.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* @@ -22,7 +22,7 @@ #include #include -#include // vxWorks 6.0 requires this include +#include // vxWorks 6.0 requires this include #include "dbDefs.h" #include "epicsGuard.h" @@ -50,12 +50,12 @@ #include "autoPtrFreeList.h" #include "noopiiu.h" -static const char pVersionCAC[] = - "@(#) " EPICS_VERSION_STRING +static const char pVersionCAC[] = + "@(#) " EPICS_VERSION_STRING ", CA Client Library " __DATE__; // TCP response dispatch table -const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = +const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = { &cac::versionAction, &cac::eventRespAction, @@ -68,7 +68,7 @@ const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = &cac::badTCPRespAction, &cac::badTCPRespAction, // legacy CA_PROTO_READ_SYNC used as an echo with legacy server - &cac::echoRespAction, + &cac::echoRespAction, &cac::exceptionRespAction, &cac::clearChannelRespAction, &cac::badTCPRespAction, @@ -89,7 +89,7 @@ const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = }; // TCP exception dispatch table -const cac::pExcepProtoStubTCP cac::tcpExcepJumpTableCAC [] = +const cac::pExcepProtoStubTCP cac::tcpExcepJumpTableCAC [] = { &cac::defaultExcep, // CA_PROTO_VERSION &cac::eventAddExcep, // CA_PROTO_EVENT_ADD @@ -109,7 +109,7 @@ const cac::pExcepProtoStubTCP cac::tcpExcepJumpTableCAC [] = &cac::readNotifyExcep, // CA_PROTO_READ_NOTIFY &cac::defaultExcep, // CA_PROTO_READ_BUILD &cac::defaultExcep, // REPEATER_CONFIRM - &cac::defaultExcep, // CA_PROTO_CREATE_CHAN + &cac::defaultExcep, // CA_PROTO_CREATE_CHAN &cac::writeNotifyExcep, // CA_PROTO_WRITE_NOTIFY &cac::defaultExcep, // CA_PROTO_CLIENT_NAME &cac::defaultExcep, // CA_PROTO_HOST_NAME @@ -124,9 +124,9 @@ const cac::pExcepProtoStubTCP cac::tcpExcepJumpTableCAC [] = // // cac::cac () // -cac::cac ( - epicsMutex & mutualExclusionIn, - epicsMutex & callbackControlIn, +cac::cac ( + epicsMutex & mutualExclusionIn, + epicsMutex & callbackControlIn, cacContextNotify & notifyIn ) : _refLocalHostName ( localHostNameCache.getReference () ), programBeginTime ( epicsTime::getCurrent() ), @@ -134,7 +134,7 @@ cac::cac ( mutex ( mutualExclusionIn ), cbMutex ( callbackControlIn ), ipToAEngine ( ipAddrToAsciiEngine::allocate () ), - timerQueue ( epicsTimerQueueActive::allocate ( false, + timerQueue ( epicsTimerQueueActive::allocate ( false, lowestPriorityLevelAbove(epicsThreadGetPrioritySelf()) ) ), pUserName ( 0 ), pudpiiu ( 0 ), @@ -157,8 +157,8 @@ cac::cac ( long status; /* - * Certain os, such as HPUX, do not unblock a socket system call - * when another thread asynchronously calls both shutdown() and + * Certain os, such as HPUX, do not unblock a socket system call + * when another thread asynchronously calls both shutdown() and * close(). To solve this problem we need to employ OS specific * mechanisms. */ @@ -179,7 +179,7 @@ cac::cac ( strncpy ( this->pUserName, tmp, len ); } - this->_serverPort = + this->_serverPort = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, static_cast (CA_SERVER_PORT) ); @@ -224,7 +224,7 @@ cac::cac ( } unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes (); if ( bufsPerArray > 1u ) { - maxContigFrames = bufsPerArray * + maxContigFrames = bufsPerArray * contiguousMsgCountWhichTriggersFlowControl; } } @@ -275,8 +275,8 @@ cac::~cac () // this blocks until the UDP thread exits so that // it will not sneak in any new clients // - // lock intentionally not held here so that we dont deadlock - // waiting for the UDP thread to exit while it is waiting to + // lock intentionally not held here so that we dont deadlock + // waiting for the UDP thread to exit while it is waiting to // get the lock. { epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); @@ -298,11 +298,11 @@ cac::~cac () } } } - + // // wait for all tcp threads to exit // - // this will block for oustanding sends to go out so dont + // this will block for oustanding sends to go out so dont // hold a lock while waiting // { @@ -323,7 +323,7 @@ cac::~cac () delete [] this->pUserName; tsSLList < bhe > tmpBeaconList; - this->beaconTable.removeAll ( tmpBeaconList ); + this->beaconTable.removeAll ( tmpBeaconList ); while ( bhe * pBHE = tmpBeaconList.get() ) { pBHE->~bhe (); this->bheFreeList.release ( pBHE ); @@ -338,7 +338,7 @@ cac::~cac () osiSockRelease (); // its ok for channels and subscriptions to still - // exist at this point. The user created them and + // exist at this point. The user created them and // its his responsibility to clean them up. } @@ -346,7 +346,7 @@ unsigned cac::lowestPriorityLevelAbove ( unsigned priority ) { unsigned abovePriority; epicsThreadBooleanStatus tbs; - tbs = epicsThreadLowestPriorityLevelAbove ( + tbs = epicsThreadLowestPriorityLevelAbove ( priority, & abovePriority ); if ( tbs != epicsThreadBooleanStatusSuccess ) { abovePriority = priority; @@ -358,7 +358,7 @@ unsigned cac::highestPriorityLevelBelow ( unsigned priority ) { unsigned belowPriority; epicsThreadBooleanStatus tbs; - tbs = epicsThreadHighestPriorityLevelBelow ( + tbs = epicsThreadHighestPriorityLevelBelow ( priority, & belowPriority ); if ( tbs != epicsThreadBooleanStatusSuccess ) { belowPriority = priority; @@ -379,21 +379,21 @@ void cac::flush ( epicsGuard < epicsMutex > & guard ) } } -unsigned cac::circuitCount ( +unsigned cac::circuitCount ( epicsGuard < epicsMutex > & guard ) const { guard.assertIdenticalMutex ( this->mutex ); return this->circuitList.count (); } -void cac::show ( +void cac::show ( epicsGuard < epicsMutex > & guard, unsigned level ) const { guard.assertIdenticalMutex ( this->mutex ); - ::printf ( "Channel Access Client Context at %p for user %s\n", + ::printf ( "Channel Access Client Context at %p for user %s\n", static_cast ( this ), this->pUserName ); - // this also supresses the "defined, but not used" + // this also supresses the "defined, but not used" // warning message ::printf ( "\trevision \"%s\"\n", pVersionCAC ); @@ -451,7 +451,7 @@ void cac::beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime, /* * return if the beacon period has not changed significantly */ - if ( ! pBHE->updatePeriod ( guard, this->programBeginTime, + if ( ! pBHE->updatePeriod ( guard, this->programBeginTime, currentTime, beaconNumber, protocolRevision ) ) { return; } @@ -488,8 +488,8 @@ void cac::beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime, # endif } -cacChannel & cac::createChannel ( - epicsGuard < epicsMutex > & guard, const char * pName, +cacChannel & cac::createChannel ( + epicsGuard < epicsMutex > & guard, const char * pName, cacChannelNotify & chan, cacChannel::priLev pri ) { guard.assertIdenticalMutex ( this->mutex ); @@ -503,19 +503,19 @@ cacChannel & cac::createChannel ( } if ( ! this->pudpiiu ) { - this->pudpiiu = new udpiiu ( - guard, this->timerQueue, this->cbMutex, + this->pudpiiu = new udpiiu ( + guard, this->timerQueue, this->cbMutex, this->mutex, this->notify, *this, this->_serverPort, this->searchDestList ); } - nciu * pNetChan = new ( this->channelFreeList ) + nciu * pNetChan = new ( this->channelFreeList ) nciu ( *this, noopIIU, chan, pName, pri ); this->chanTable.idAssignAdd ( *pNetChan ); return *pNetChan; } -bool cac::findOrCreateVirtCircuit ( +bool cac::findOrCreateVirtCircuit ( epicsGuard < epicsMutex > & guard, const osiSockAddr & addr, unsigned priority, tcpiiu *& piiu, unsigned minorVersionNumber, SearchDestTCP * pSearchDest ) @@ -532,14 +532,14 @@ bool cac::findOrCreateVirtCircuit ( try { autoPtrFreeList < tcpiiu, 32, epicsMutexNOOP > pnewiiu ( this->freeListVirtualCircuit, - new ( this->freeListVirtualCircuit ) tcpiiu ( - *this, this->mutex, this->cbMutex, this->notify, this->connTMO, - this->timerQueue, addr, this->comBufMemMgr, minorVersionNumber, + new ( this->freeListVirtualCircuit ) tcpiiu ( + *this, this->mutex, this->cbMutex, this->notify, this->connTMO, + this->timerQueue, addr, this->comBufMemMgr, minorVersionNumber, this->ipToAEngine, priority, pSearchDest ) ); bhe * pBHE = this->beaconTable.lookup ( addr.ia ); if ( ! pBHE ) { - pBHE = new ( this->bheFreeList ) + pBHE = new ( this->bheFreeList ) bhe ( this->mutex, epicsTime (), 0u, addr.ia ); if ( this->beaconTable.add ( *pBHE ) < 0 ) { return newIIU; @@ -553,13 +553,13 @@ bool cac::findOrCreateVirtCircuit ( newIIU = true; } catch ( std :: exception & except ) { - errlogPrintf ( + errlogPrintf ( "CAC: exception during virtual circuit creation \"%s\"\n", except.what () ); return newIIU; } catch ( ... ) { - errlogPrintf ( + errlogPrintf ( "CAC: Nonstandard exception during virtual circuit creation\n" ); return newIIU; } @@ -567,9 +567,9 @@ bool cac::findOrCreateVirtCircuit ( return newIIU; } -void cac::transferChanToVirtCircuit ( +void cac::transferChanToVirtCircuit ( unsigned cid, unsigned sid, - ca_uint16_t typeCode, arrayElementCount count, + ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber, const osiSockAddr & addr, const epicsTime & currentTime ) { @@ -604,12 +604,12 @@ void cac::transferChanToVirtCircuit ( char acc[64]; pChan->getPIIU(guard)->getHostName ( guard, acc, sizeof ( acc ) ); msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList ) - msgForMultiplyDefinedPV ( this->ipToAEngine, + msgForMultiplyDefinedPV ( this->ipToAEngine, *this, pChan->pName ( guard ), acc ); // It is possible for the ioInitiate call below to // call the callback directly if queue quota is exceeded. // This callback takes the callback lock and therefore we - // must release the primary mutex here to avoid a lock + // must release the primary mutex here to avoid a lock // hierarchy inversion. epicsGuardRelease < epicsMutex > unguard ( guard ); pMsg->ioInitiate ( addr ); @@ -625,9 +625,9 @@ void cac::transferChanToVirtCircuit ( pChan->getPriority(guard), piiu, minorVersionNumber ); // must occur before moving to new iiu - pChan->getPIIU(guard)->uninstallChanDueToSuccessfulSearchResponse ( + pChan->getPIIU(guard)->uninstallChanDueToSuccessfulSearchResponse ( guard, *pChan, currentTime ); - piiu->installChannel ( + piiu->installChannel ( guard, *pChan, sid, typeCode, count ); if ( newIIU ) { @@ -635,14 +635,14 @@ void cac::transferChanToVirtCircuit ( } } -void cac::destroyChannel ( +void cac::destroyChannel ( epicsGuard < epicsMutex > & guard, - nciu & chan ) + nciu & chan ) { guard.assertIdenticalMutex ( this->mutex ); // uninstall channel so that recv threads - // will not start a new callback for this channel's IO. + // will not start a new callback for this channel's IO. if ( this->chanTable.remove ( chan ) != & chan ) { throw std::logic_error ( "Invalid channel identifier" ); } @@ -650,9 +650,9 @@ void cac::destroyChannel ( this->channelFreeList.release ( & chan ); } -void cac::disconnectAllIO ( +void cac::disconnectAllIO ( epicsGuard < epicsMutex > & cbGuard, - epicsGuard < epicsMutex > & guard, + epicsGuard < epicsMutex > & guard, nciu & chan, tsDLList < baseNMIU > & ioList ) { cbGuard.assertIdenticalMutex ( this->cbMutex ); @@ -672,8 +672,8 @@ void cac::disconnectAllIO ( } } -int cac :: printFormated ( - epicsGuard < epicsMutex > & callbackControl, +int cac :: printFormated ( + epicsGuard < epicsMutex > & callbackControl, const char * pformat, ... ) const { va_list theArgs; @@ -683,26 +683,26 @@ int cac :: printFormated ( return status; } -netWriteNotifyIO & cac::writeNotifyRequest ( +netWriteNotifyIO & cac::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, privateInterfaceForIO & icni, unsigned type, arrayElementCount nElem, const void * pValue, cacWriteNotify & notifyIn ) { guard.assertIdenticalMutex ( this->mutex ); - autoPtrRecycle < netWriteNotifyIO > pIO ( - guard, this->ioTable, *this, + autoPtrRecycle < netWriteNotifyIO > pIO ( + guard, this->ioTable, *this, netWriteNotifyIO::factory ( this->freeListWriteNotifyIO, icni, notifyIn ) ); this->ioTable.idAssignAdd ( *pIO ); - chan.getPIIU(guard)->writeNotifyRequest ( + chan.getPIIU(guard)->writeNotifyRequest ( guard, chan, *pIO, type, nElem, pValue ); return *pIO.release(); } -netReadNotifyIO & cac::readNotifyRequest ( +netReadNotifyIO & cac::readNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan, privateInterfaceForIO & icni, unsigned type, arrayElementCount nElem, cacReadNotify & notifyIn ) { guard.assertIdenticalMutex ( this->mutex ); - autoPtrRecycle < netReadNotifyIO > pIO ( + autoPtrRecycle < netReadNotifyIO > pIO ( guard, this->ioTable, *this, netReadNotifyIO::factory ( this->freeListReadNotifyIO, icni, notifyIn ) ); this->ioTable.idAssignAdd ( *pIO ); @@ -711,7 +711,8 @@ netReadNotifyIO & cac::readNotifyRequest ( } bool cac::destroyIO ( - epicsGuard < epicsMutex > & guard, + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & guard, const cacChannel::ioid & idIn, nciu & chan ) { guard.assertIdenticalMutex ( this->mutex ); @@ -720,18 +721,18 @@ bool cac::destroyIO ( if ( pIO ) { class netSubscription * pSubscr = pIO->isSubscription (); if ( pSubscr ) { - pSubscr->unsubscribeIfRequired ( guard, chan ); + pSubscr->unsubscribeIfRequired ( guard, chan ); } // this uninstalls from the list and destroys the IO pIO->exception ( guard, *this, ECA_CHANDESTROY, chan.pName ( guard ) ); return true; - } + } return false; } -void cac::ioShow ( +void cac::ioShow ( epicsGuard < epicsMutex > & guard, const cacChannel::ioid & idIn, unsigned level ) const { @@ -741,8 +742,8 @@ void cac::ioShow ( } } -void cac::ioExceptionNotify ( - unsigned idIn, int status, const char * pContext, +void cac::ioExceptionNotify ( + unsigned idIn, int status, const char * pContext, unsigned type, arrayElementCount count ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -752,8 +753,8 @@ void cac::ioExceptionNotify ( } } -void cac::ioExceptionNotifyAndUninstall ( - unsigned idIn, int status, const char * pContext, +void cac::ioExceptionNotifyAndUninstall ( + unsigned idIn, int status, const char * pContext, unsigned type, arrayElementCount count ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -763,38 +764,38 @@ void cac::ioExceptionNotifyAndUninstall ( } } -void cac::recycleReadNotifyIO ( +void cac::recycleReadNotifyIO ( epicsGuard < epicsMutex > & guard, netReadNotifyIO & io ) { guard.assertIdenticalMutex ( this->mutex ); this->freeListReadNotifyIO.release ( & io ); } -void cac::recycleWriteNotifyIO ( +void cac::recycleWriteNotifyIO ( epicsGuard < epicsMutex > & guard, netWriteNotifyIO & io ) { guard.assertIdenticalMutex ( this->mutex ); this->freeListWriteNotifyIO.release ( & io ); } -void cac::recycleSubscription ( +void cac::recycleSubscription ( epicsGuard < epicsMutex > & guard, netSubscription & io ) { guard.assertIdenticalMutex ( this->mutex ); this->freeListSubscription.release ( & io ); } -netSubscription & cac::subscriptionRequest ( - epicsGuard < epicsMutex > & guard, +netSubscription & cac::subscriptionRequest ( + epicsGuard < epicsMutex > & guard, nciu & chan, privateInterfaceForIO & privChan, unsigned type, - arrayElementCount nElem, unsigned mask, + arrayElementCount nElem, unsigned mask, cacStateNotify & notifyIn, bool chanIsInstalled ) { guard.assertIdenticalMutex ( this->mutex ); - autoPtrRecycle < netSubscription > pIO ( - guard, this->ioTable, *this, + autoPtrRecycle < netSubscription > pIO ( + guard, this->ioTable, *this, netSubscription::factory ( this->freeListSubscription, privChan, type, nElem, mask, notifyIn ) ); this->ioTable.idAssignAdd ( *pIO ); @@ -804,23 +805,23 @@ netSubscription & cac::subscriptionRequest ( return *pIO.release (); } -bool cac::versionAction ( callbackManager &, tcpiiu & iiu, +bool cac::versionAction ( callbackManager &, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & msg, void * ) { iiu.versionRespNotify ( msg ); return true; } - -bool cac::echoRespAction ( - callbackManager & mgr, tcpiiu & iiu, + +bool cac::echoRespAction ( + callbackManager & mgr, tcpiiu & iiu, const epicsTime & /* current */, const caHdrLargeArray &, void * ) { iiu.probeResponseNotify ( mgr.cbGuard ); return true; } -bool cac::writeNotifyRespAction ( - callbackManager &, tcpiiu &, +bool cac::writeNotifyRespAction ( + callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray & hdr, void * ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -837,7 +838,7 @@ bool cac::writeNotifyRespAction ( return true; } -bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, +bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -856,13 +857,13 @@ bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, baseNMIU * pmiu = this->ioTable.remove ( hdr.m_available ); // - // The IO destroy routines take the call back mutex - // when uninstalling and deleting the baseNMIU so there is + // The IO destroy routines take the call back mutex + // when uninstalling and deleting the baseNMIU so there is // no need to worry here about the baseNMIU being deleted while // it is in use here. // if ( pmiu ) { - // if its a circuit-becomes-responsive subscription update + // if its a circuit-becomes-responsive subscription update // then we need to reinstall the IO into the table netSubscription * pSubscr = pmiu->isSubscription (); if ( pSubscr ) { @@ -874,7 +875,7 @@ bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, * convert the data buffer from net * format to host format */ - caStatus = caNetConvert ( + caStatus = caNetConvert ( hdr.m_dataType, pMsgBdy, pMsgBdy, false, hdr.m_count ); } if ( caStatus == ECA_NORMAL ) { @@ -882,7 +883,7 @@ bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, hdr.m_dataType, hdr.m_count, pMsgBdy ); } else { - pmiu->exception ( guard, *this, + pmiu->exception ( guard, *this, caStatus, "read failed", hdr.m_dataType, hdr.m_count ); } @@ -890,8 +891,8 @@ bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu, return true; } -bool cac::searchRespAction ( callbackManager &, tcpiiu & iiu, - const epicsTime & currentTime, const caHdrLargeArray & msg, +bool cac::searchRespAction ( callbackManager &, tcpiiu & iiu, + const epicsTime & currentTime, const caHdrLargeArray & msg, void * /* pMsgBdy */ ) { assert ( this->pudpiiu ); @@ -899,13 +900,13 @@ bool cac::searchRespAction ( callbackManager &, tcpiiu & iiu, return true; } -bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, +bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) -{ +{ int caStatus; /* - * m_postsize = 0 used to be a subscription cancel confirmation, + * m_postsize = 0 used to be a subscription cancel confirmation, * but is now a noop because the IO block is immediately deleted */ if ( ! hdr.m_postsize ) { @@ -926,8 +927,8 @@ bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, } // - // The IO destroy routines take the call back mutex - // when uninstalling and deleting the baseNMIU so there is + // The IO destroy routines take the call back mutex + // when uninstalling and deleting the baseNMIU so there is // no need to worry here about the baseNMIU being deleted while // it is in use here. // @@ -937,7 +938,7 @@ bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, * convert the data buffer from net format to host format */ if ( caStatus == ECA_NORMAL ) { - caStatus = caNetConvert ( + caStatus = caNetConvert ( hdr.m_dataType, pMsgBdy, pMsgBdy, false, hdr.m_count ); } if ( caStatus == ECA_NORMAL ) { @@ -945,7 +946,7 @@ bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, hdr.m_dataType, hdr.m_count, pMsgBdy ); } else { - pmiu->exception ( guard, *this, caStatus, + pmiu->exception ( guard, *this, caStatus, "subscription update read failed", hdr.m_dataType, hdr.m_count ); } @@ -953,14 +954,14 @@ bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu, return true; } -bool cac::readRespAction ( callbackManager &, tcpiiu &, +bool cac::readRespAction ( callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy ) { epicsGuard < epicsMutex > guard ( this->mutex ); baseNMIU * pmiu = this->ioTable.remove ( hdr.m_available ); // - // The IO destroy routines take the call back mutex - // when uninstalling and deleting the baseNMIU so there is + // The IO destroy routines take the call back mutex + // when uninstalling and deleting the baseNMIU so there is // no need to worry here about the baseNMIU being deleted while // it is in use here. // @@ -971,14 +972,14 @@ bool cac::readRespAction ( callbackManager &, tcpiiu &, return true; } -bool cac::clearChannelRespAction ( callbackManager &, tcpiiu &, +bool cac::clearChannelRespAction ( callbackManager &, tcpiiu &, const epicsTime &, const caHdrLargeArray &, void * /* pMsgBody */ ) { return true; // currently a noop } -bool cac::defaultExcep ( - callbackManager &, tcpiiu & iiu, +bool cac::defaultExcep ( + callbackManager &, tcpiiu & iiu, const caHdrLargeArray &, const char * pCtx, unsigned status ) { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -990,69 +991,69 @@ bool cac::defaultExcep ( return true; } -void cac::exception ( - epicsGuard < epicsMutex > & cbGuard, - epicsGuard < epicsMutex > & guard, int status, +void cac::exception ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard, int status, const char * pContext, const char * pFileName, unsigned lineNo ) { cbGuard.assertIdenticalMutex ( this->cbMutex ); guard.assertIdenticalMutex ( this->mutex ); - this->notify.exception ( guard, status, pContext, + this->notify.exception ( guard, status, pContext, pFileName, lineNo ); } -bool cac::eventAddExcep ( - callbackManager &, tcpiiu &, - const caHdrLargeArray &hdr, +bool cac::eventAddExcep ( + callbackManager &, tcpiiu &, + const caHdrLargeArray &hdr, const char *pCtx, unsigned status ) { - this->ioExceptionNotify ( hdr.m_available, status, pCtx, + this->ioExceptionNotify ( hdr.m_available, status, pCtx, hdr.m_dataType, hdr.m_count ); return true; } -bool cac::readExcep ( callbackManager &, tcpiiu &, - const caHdrLargeArray & hdr, +bool cac::readExcep ( callbackManager &, tcpiiu &, + const caHdrLargeArray & hdr, const char * pCtx, unsigned status ) { - this->ioExceptionNotifyAndUninstall ( hdr.m_available, + this->ioExceptionNotifyAndUninstall ( hdr.m_available, status, pCtx, hdr.m_dataType, hdr.m_count ); return true; } -bool cac::writeExcep ( +bool cac::writeExcep ( callbackManager & mgr, - tcpiiu &, const caHdrLargeArray & hdr, + 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 ( mgr.cbGuard, guard, status, pCtx, + pChan->writeException ( mgr.cbGuard, guard, status, pCtx, hdr.m_dataType, hdr.m_count ); } return true; } -bool cac::readNotifyExcep ( callbackManager &, tcpiiu &, - const caHdrLargeArray &hdr, +bool cac::readNotifyExcep ( callbackManager &, tcpiiu &, + const caHdrLargeArray &hdr, const char *pCtx, unsigned status ) { - this->ioExceptionNotifyAndUninstall ( hdr.m_available, + this->ioExceptionNotifyAndUninstall ( hdr.m_available, status, pCtx, hdr.m_dataType, hdr.m_count ); return true; } -bool cac::writeNotifyExcep ( callbackManager &, tcpiiu &, - const caHdrLargeArray &hdr, +bool cac::writeNotifyExcep ( callbackManager &, tcpiiu &, + const caHdrLargeArray &hdr, const char *pCtx, unsigned status ) { - this->ioExceptionNotifyAndUninstall ( hdr.m_available, + this->ioExceptionNotifyAndUninstall ( hdr.m_available, status, pCtx, hdr.m_dataType, hdr.m_count ); return true; } -bool cac::exceptionRespAction ( callbackManager & 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 ); @@ -1069,7 +1070,7 @@ bool cac::exceptionRespAction ( callbackManager & cbMutexIn, tcpiiu & iiu, req.m_available = AlignedWireRef < const epicsUInt32 > ( pReq->m_available ); const ca_uint32_t * pLW = reinterpret_cast < const ca_uint32_t * > ( pReq + 1 ); if ( req.m_postsize == 0xffff ) { - static const unsigned annexSize = + static const unsigned annexSize = sizeof ( req.m_postsize ) + sizeof ( req.m_count ); bytesSoFar += annexSize; if ( hdr.m_postsize < bytesSoFar ) { @@ -1100,9 +1101,9 @@ bool cac::accessRightsRespAction ( nciu * pChan = this->chanTable.lookup ( hdr.m_cid ); if ( pChan ) { unsigned ar = hdr.m_available; - caAccessRights accessRights ( - ( ar & CA_PROTO_ACCESS_RIGHT_READ ) ? true : false, - ( ar & CA_PROTO_ACCESS_RIGHT_WRITE ) ? true : false); + caAccessRights accessRights ( + ( ar & CA_PROTO_ACCESS_RIGHT_READ ) ? true : false, + ( ar & CA_PROTO_ACCESS_RIGHT_WRITE ) ? true : false); pChan->accessRightsStateChange ( accessRights, mgr.cbGuard, guard ); } @@ -1125,11 +1126,11 @@ bool cac::createChannelRespAction ( } bool wasExpected = iiu.connectNotify ( guard, *pChan ); if ( wasExpected ) { - pChan->connect ( hdr.m_dataType, hdr.m_count, sidTmp, + pChan->connect ( hdr.m_dataType, hdr.m_count, sidTmp, mgr.cbGuard, guard ); } else { - errlogPrintf ( + errlogPrintf ( "CA Client Library: Ignored duplicate create channel " "response from CA server?\n" ); } @@ -1140,10 +1141,10 @@ bool cac::createChannelRespAction ( iiu.clearChannelRequest ( guard, hdr.m_available, hdr.m_cid ); } - return true; + return true; } -bool cac::verifyAndDisconnectChan ( +bool cac::verifyAndDisconnectChan ( callbackManager & mgr, tcpiiu &, const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ ) { @@ -1168,18 +1169,18 @@ void cac::disconnectChannel ( chan.unresponsiveCircuitNotify ( cbGuard, guard ); } -bool cac::badTCPRespAction ( callbackManager &, tcpiiu & iiu, +bool cac::badTCPRespAction ( callbackManager &, tcpiiu & iiu, const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ ) { epicsGuard < epicsMutex > guard ( this->mutex ); char hostName[64]; iiu.getHostName ( guard, hostName, sizeof ( hostName ) ); - errlogPrintf ( "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 ( callbackManager & mgr, tcpiiu & iiu, +bool cac::executeResponse ( callbackManager & mgr, tcpiiu & iiu, const epicsTime & currentTime, caHdrLargeArray & hdr, char * pMshBody ) { // execute the response message @@ -1193,7 +1194,7 @@ bool cac::executeResponse ( callbackManager & mgr, tcpiiu & iiu, return ( this->*pStub ) ( mgr, iiu, currentTime, hdr, pMshBody ); } -void cac::selfTest ( +void cac::selfTest ( epicsGuard < epicsMutex > & guard ) const { guard.assertIdenticalMutex ( this->mutex ); @@ -1221,7 +1222,7 @@ void cac::destroyIIU ( tcpiiu & iiu ) pBHE->unregisterIIU ( guard, iiu ); } } - + assert ( this->pudpiiu ); iiu.disconnectAllChannels ( mgr.cbGuard, guard, *this->pudpiiu ); @@ -1233,7 +1234,7 @@ void cac::destroyIIU ( tcpiiu & iiu ) // so we must not hold the primary mutex here // // this waits for send/recv threads to exit - // this also uses the cac free lists so cac must wait + // this also uses the cac free lists so cac must wait // for this to finish before it shuts down iiu.~tcpiiu (); @@ -1248,8 +1249,8 @@ void cac::destroyIIU ( tcpiiu & iiu ) // do not touch "this" after lock is released above } -double cac::beaconPeriod ( - epicsGuard < epicsMutex > & guard, +double cac::beaconPeriod ( + epicsGuard < epicsMutex > & guard, const nciu & chan ) const { const netiiu * pIIU = chan.getConstPIIU ( guard ); @@ -1266,8 +1267,8 @@ double cac::beaconPeriod ( return - DBL_MAX; } -void cac::initiateConnect ( - epicsGuard < epicsMutex > & guard, +void cac::initiateConnect ( + epicsGuard < epicsMutex > & guard, nciu & chan, netiiu * & piiu ) { guard.assertIdenticalMutex ( this->mutex ); @@ -1285,7 +1286,7 @@ void cacComBufMemoryManager::release ( void * pCadaver ) this->freeList.release ( pCadaver ); } -void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, +void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, const char * pChannelName, const char * pAcc, const char * pRej ) { char buf[256]; diff --git a/src/ca/client/cac.h b/src/ca/client/cac.h index 2e95ed6bf..9f9d45a65 100644 --- a/src/ca/client/cac.h +++ b/src/ca/client/cac.h @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* @@ -57,11 +57,11 @@ class netSubscription; // is applied class cacRecycle { public: - virtual void recycleReadNotifyIO ( + virtual void recycleReadNotifyIO ( epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0; - virtual void recycleWriteNotifyIO ( + virtual void recycleWriteNotifyIO ( epicsGuard < epicsMutex > &, netWriteNotifyIO &io ) = 0; - virtual void recycleSubscription ( + virtual void recycleSubscription ( epicsGuard < epicsMutex > &, netSubscription &io ) = 0; protected: virtual ~cacRecycle() {} @@ -96,85 +96,81 @@ private: class callbackManager : public notifyGuard { public: - callbackManager ( - cacContextNotify &, + callbackManager ( + cacContextNotify &, epicsMutex & callbackControl ); epicsGuard < epicsMutex > cbGuard; }; -class cac : +class cac : public cacContext, - private cacRecycle, + private cacRecycle, private callbackForMultiplyDefinedPV { public: - cac ( - epicsMutex & mutualExclusion, - epicsMutex & callbackControl, + cac ( + epicsMutex & mutualExclusion, + epicsMutex & callbackControl, cacContextNotify & ); virtual ~cac (); // beacon management - void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime, + void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime, ca_uint32_t beaconNumber, unsigned protocolRevision ); unsigned beaconAnomaliesSinceProgramStart ( epicsGuard < epicsMutex > & ) const; // IO management void flush ( epicsGuard < epicsMutex > & guard ); - bool executeResponse ( callbackManager &, tcpiiu &, + bool executeResponse ( callbackManager &, tcpiiu &, const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody ); // channel routines - void transferChanToVirtCircuit ( - unsigned cid, unsigned sid, - ca_uint16_t typeCode, arrayElementCount count, + void transferChanToVirtCircuit ( + unsigned cid, unsigned sid, + ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber, const osiSockAddr &, const epicsTime & currentTime ); - cacChannel & createChannel ( - epicsGuard < epicsMutex > & guard, const char * pChannelName, + cacChannel & createChannel ( + epicsGuard < epicsMutex > & guard, const char * pChannelName, cacChannelNotify &, cacChannel::priLev ); - void destroyChannel ( + void destroyChannel ( epicsGuard < epicsMutex > &, nciu & ); - void initiateConnect ( + void initiateConnect ( epicsGuard < epicsMutex > &, nciu &, netiiu * & ); nciu * lookupChannel ( epicsGuard < epicsMutex > &, const cacChannel::ioid & ); // IO requests - netWriteNotifyIO & writeNotifyRequest ( + netWriteNotifyIO & writeNotifyRequest ( epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &, - unsigned type, arrayElementCount nElem, const void * pValue, + unsigned type, arrayElementCount nElem, const void * pValue, cacWriteNotify & ); - netReadNotifyIO & readNotifyRequest ( + netReadNotifyIO & readNotifyRequest ( epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &, - unsigned type, arrayElementCount nElem, + unsigned type, arrayElementCount nElem, cacReadNotify & ); - netSubscription & subscriptionRequest ( + netSubscription & subscriptionRequest ( epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &, - unsigned type, arrayElementCount nElem, unsigned mask, + unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify &, bool channelIsInstalled ); bool destroyIO ( - epicsGuard < epicsMutex > & guard, - const cacChannel::ioid & idIn, + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const cacChannel::ioid & idIn, nciu & chan ); - void disconnectAllIO ( + void disconnectAllIO ( epicsGuard < epicsMutex > & cbGuard, - epicsGuard < epicsMutex > & guard, + epicsGuard < epicsMutex > & guard, nciu &, tsDLList < baseNMIU > & ioList ); - void ioShow ( + void ioShow ( 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, + void exception ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, int status, const char * pContext, const char * pFileName, unsigned lineNo ); @@ -189,11 +185,11 @@ public: // diagnostics unsigned circuitCount ( epicsGuard < epicsMutex > & ) const; void show ( epicsGuard < epicsMutex > &, unsigned level ) const; - int printFormated ( - epicsGuard < epicsMutex > & callbackControl, + int printFormated ( + epicsGuard < epicsMutex > & callbackControl, const char *pformat, ... ) const; - int varArgsPrintFormated ( - epicsGuard < epicsMutex > & callbackControl, + int varArgsPrintFormated ( + epicsGuard < epicsMutex > & callbackControl, const char *pformat, va_list args ) const; double connectionTimeout ( epicsGuard < epicsMutex > & ); @@ -210,17 +206,17 @@ public: unsigned getInitializingThreadsPriority () const; epicsMutex & mutexRef (); void attachToClientCtx (); - void selfTest ( + void selfTest ( epicsGuard < epicsMutex > & ) const; - double beaconPeriod ( + double beaconPeriod ( epicsGuard < epicsMutex > &, const nciu & chan ) const; static unsigned lowestPriorityLevelAbove ( unsigned priority ); static unsigned highestPriorityLevelBelow ( unsigned priority ); - void destroyIIU ( tcpiiu & iiu ); + void destroyIIU ( tcpiiu & iiu ); const char * pLocalHostName (); - + private: epicsSingleton < localHostName > :: reference _refLocalHostName; chronIntIdResTable < nciu > chanTable; @@ -229,11 +225,11 @@ private: // !!!! to maintain one IO table for all types of // !!!! IO. It would probably be better to maintain // !!!! an independent table for each IO type. The - // !!!! new adaptive sized hash table will not - // !!!! waste memory. Making this change will - // !!!! avoid virtual function overhead when + // !!!! new adaptive sized hash table will not + // !!!! waste memory. Making this change will + // !!!! avoid virtual function overhead when // !!!! accessing the different types of IO. This - // !!!! approach would also probably be safer in + // !!!! approach would also probably be safer in // !!!! terms of detecting damaged protocol. // chronIntIdResTable < baseNMIU > ioTable; @@ -241,23 +237,23 @@ private: resTable < tcpiiu, caServerID > serverTable; tsDLList < tcpiiu > circuitList; tsDLList < SearchDest > searchDestList; - tsFreeList - < class tcpiiu, 32, epicsMutexNOOP > + tsFreeList + < class tcpiiu, 32, epicsMutexNOOP > freeListVirtualCircuit; - tsFreeList - < class netReadNotifyIO, 1024, epicsMutexNOOP > + tsFreeList + < class netReadNotifyIO, 1024, epicsMutexNOOP > freeListReadNotifyIO; - tsFreeList - < class netWriteNotifyIO, 1024, epicsMutexNOOP > + tsFreeList + < class netWriteNotifyIO, 1024, epicsMutexNOOP > freeListWriteNotifyIO; - tsFreeList - < class netSubscription, 1024, epicsMutexNOOP > + tsFreeList + < class netSubscription, 1024, epicsMutexNOOP > freeListSubscription; - tsFreeList - < class nciu, 1024, epicsMutexNOOP > + tsFreeList + < class nciu, 1024, epicsMutexNOOP > channelFreeList; - tsFreeList - < class msgForMultiplyDefinedPV, 16 > + tsFreeList + < class msgForMultiplyDefinedPV, 16 > mdpvFreeList; cacComBufMemoryManager comBufMemMgr; bheFreeStore bheFreeList; @@ -285,74 +281,74 @@ private: unsigned iiuExistenceCount; bool cacShutdownInProgress; - void recycleReadNotifyIO ( + void recycleReadNotifyIO ( epicsGuard < epicsMutex > &, netReadNotifyIO &io ); - void recycleWriteNotifyIO ( + void recycleWriteNotifyIO ( epicsGuard < epicsMutex > &, netWriteNotifyIO &io ); - void recycleSubscription ( + void recycleSubscription ( epicsGuard < epicsMutex > &, netSubscription &io ); - void disconnectChannel ( - epicsGuard < epicsMutex > & cbGuard, + void disconnectChannel ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard, nciu & chan ); - void ioExceptionNotify ( unsigned id, int status, + void ioExceptionNotify ( unsigned id, int status, const char * pContext, unsigned type, arrayElementCount count ); - void ioExceptionNotifyAndUninstall ( unsigned id, int status, + void ioExceptionNotifyAndUninstall ( unsigned id, int status, const char * pContext, unsigned type, arrayElementCount count ); - void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, + void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, const char * pChannelName, const char * pAcc, const char * pRej ); // recv protocol stubs - bool versionAction ( callbackManager &, tcpiiu &, + bool versionAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool echoRespAction ( callbackManager &, tcpiiu &, + bool echoRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool writeNotifyRespAction ( callbackManager &, tcpiiu &, + bool writeNotifyRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool searchRespAction ( callbackManager &, tcpiiu &, + bool searchRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool readNotifyRespAction ( callbackManager &, tcpiiu &, + bool readNotifyRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool eventRespAction ( callbackManager &, tcpiiu &, + bool eventRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool readRespAction ( callbackManager &, tcpiiu &, + bool readRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool clearChannelRespAction ( callbackManager &, tcpiiu &, + bool clearChannelRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool exceptionRespAction ( callbackManager &, tcpiiu &, + bool exceptionRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool accessRightsRespAction ( callbackManager &, tcpiiu &, + bool accessRightsRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool createChannelRespAction ( callbackManager &, tcpiiu &, + bool createChannelRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &, + bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - bool badTCPRespAction ( callbackManager &, tcpiiu &, + bool badTCPRespAction ( callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); - typedef bool ( cac::*pProtoStubTCP ) ( - callbackManager &, tcpiiu &, + typedef bool ( cac::*pProtoStubTCP ) ( + callbackManager &, tcpiiu &, const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy ); static const pProtoStubTCP tcpJumpTableCAC []; - bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); - typedef bool ( cac::*pExcepProtoStubTCP ) ( - callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, + typedef bool ( cac::*pExcepProtoStubTCP ) ( + callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr, const char *pCtx, unsigned status ); static const pExcepProtoStubTCP tcpExcepJumpTableCAC []; @@ -375,8 +371,8 @@ inline epicsMutex & cac::mutexRef () return this->mutex; } -inline int cac :: varArgsPrintFormated ( - epicsGuard < epicsMutex > & callbackControl, +inline int cac :: varArgsPrintFormated ( + epicsGuard < epicsMutex > & callbackControl, const char *pformat, va_list args ) const { callbackControl.assertIdenticalMutex ( this->cbMutex ); @@ -435,14 +431,14 @@ inline notifyGuard::~notifyGuard () this->notify.callbackProcessingCompleteNotify (); } -inline callbackManager::callbackManager ( +inline callbackManager::callbackManager ( cacContextNotify & notify, epicsMutex & callbackControl ) : notifyGuard ( notify ), cbGuard ( callbackControl ) { } inline nciu * cac::lookupChannel ( - epicsGuard < epicsMutex > & guard, + epicsGuard < epicsMutex > & guard, const cacChannel::ioid & idIn ) { guard.assertIdenticalMutex ( this->mutex ); @@ -458,11 +454,11 @@ inline unsigned cac :: maxContiguousFrames ( epicsGuard < epicsMutex > & ) const { return maxContigFrames; -} +} inline double cac :: connectionTimeout ( epicsGuard < epicsMutex > & guard ) -{ +{ guard.assertIdenticalMutex ( this->mutex ); return this->connTMO; } diff --git a/src/ca/client/cacIO.h b/src/ca/client/cacIO.h index f1cf81f47..4e8af4a05 100644 --- a/src/ca/client/cacIO.h +++ b/src/ca/client/cacIO.h @@ -5,18 +5,18 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* +/* + * * - * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 - * + * * Copyright, 1986, The Regents of the University of California. - * - * + * + * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 @@ -74,9 +74,9 @@ public: virtual ~cacWriteNotify () = 0; virtual void completion ( epicsGuard < epicsMutex > & ) = 0; // we should probably have a different vf for each type of exception ???? - virtual void exception ( + virtual void exception ( epicsGuard < epicsMutex > &, - int status, const char * pContext, + int status, const char * pContext, unsigned type, arrayElementCount count ) = 0; }; @@ -85,13 +85,13 @@ public: class epicsShareClass cacReadNotify { public: virtual ~cacReadNotify () = 0; - virtual void completion ( - epicsGuard < epicsMutex > &, unsigned type, + virtual void completion ( + epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void * pData ) = 0; // we should probably have a different vf for each type of exception ???? - virtual void exception ( - epicsGuard < epicsMutex > &, int status, - const char * pContext, unsigned type, + virtual void exception ( + epicsGuard < epicsMutex > &, int status, + const char * pContext, unsigned type, arrayElementCount count ) = 0; }; @@ -100,21 +100,21 @@ public: class epicsShareClass cacStateNotify { public: virtual ~cacStateNotify () = 0; - virtual void current ( - epicsGuard < epicsMutex > &, unsigned type, + virtual void current ( + epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void * pData ) = 0; // we should probably have a different vf for each type of exception ???? - virtual void exception ( - epicsGuard < epicsMutex > &, int status, - const char *pContext, unsigned type, + virtual void exception ( + epicsGuard < epicsMutex > &, int status, + const char *pContext, unsigned type, arrayElementCount count ) = 0; }; class caAccessRights { public: - caAccessRights ( - bool readPermit = false, - bool writePermit = false, + caAccessRights ( + bool readPermit = false, + bool writePermit = false, bool operatorConfirmationRequest = false); void setReadPermit (); void setWritePermit (); @@ -138,20 +138,30 @@ public: virtual void disconnectNotify ( epicsGuard < epicsMutex > & ) = 0; virtual void serviceShutdownNotify ( epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; - virtual void accessRightsNotify ( + virtual void accessRightsNotify ( epicsGuard < epicsMutex > &, const caAccessRights & ) = 0; - virtual void exception ( + virtual void exception ( epicsGuard < epicsMutex > &, int status, const char *pContext ) = 0; // we should probably have a different vf for each type of exception ???? - virtual void readException ( + virtual void readException ( epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count, void *pValue ) = 0; // we should probably have a different vf for each type of exception ???? - virtual void writeException ( + virtual void writeException ( epicsGuard < epicsMutex > &, int status, const char * pContext, 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,43 +184,52 @@ public: cacChannel ( cacChannelNotify & ); virtual void destroy ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; cacChannelNotify & notify () const; // required ????? virtual unsigned getName ( - epicsGuard < epicsMutex > &, + epicsGuard < epicsMutex > &, char * pBuf, unsigned bufLen ) const throw () = 0; // !! deprecated, avoid use !! virtual const char * pName ( epicsGuard < epicsMutex > & guard ) const throw () = 0; - virtual void show ( + virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0; virtual void initiateConnect ( epicsGuard < epicsMutex > & ) = 0; - virtual unsigned requestMessageBytesPending ( + virtual unsigned requestMessageBytesPending ( epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; - virtual void flush ( + virtual void flush ( epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; - virtual ioStatus read ( + virtual ioStatus read ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, cacReadNotify &, ioid * = 0 ) = 0; - virtual void write ( + virtual void write ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, const void *pValue ) = 0; - virtual ioStatus write ( + virtual ioStatus write ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, const void *pValue, cacWriteNotify &, ioid * = 0 ) = 0; - virtual void subscribe ( - epicsGuard < epicsMutex > &, unsigned type, - arrayElementCount count, unsigned mask, cacStateNotify &, + virtual void subscribe ( + epicsGuard < epicsMutex > &, unsigned type, + arrayElementCount count, unsigned mask, cacStateNotify &, ioid * = 0 ) = 0; - virtual void ioCancel ( + // 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 ( + virtual void ioShow ( epicsGuard < epicsMutex > &, const ioid &, unsigned level ) const = 0; virtual short nativeType ( @@ -226,9 +245,9 @@ public: virtual double receiveWatchdogDelay ( epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN virtual bool ca_v42_ok ( - epicsGuard < epicsMutex > & ) const; + epicsGuard < epicsMutex > & ) const; virtual bool connected ( - epicsGuard < epicsMutex > & ) const; + epicsGuard < epicsMutex > & ) const; virtual unsigned getHostName ( epicsGuard < epicsMutex > &, char * pBuf, unsigned bufLength ) const throw (); @@ -261,11 +280,11 @@ private: class epicsShareClass cacContext { public: virtual ~cacContext (); - virtual cacChannel & createChannel ( + virtual cacChannel & createChannel ( epicsGuard < epicsMutex > &, - const char * pChannelName, cacChannelNotify &, + const char * pChannelName, cacChannelNotify &, cacChannel::priLev = cacChannel::priorityDefault ) = 0; - virtual void flush ( + virtual void flush ( epicsGuard < epicsMutex > & ) = 0; virtual unsigned circuitCount ( epicsGuard < epicsMutex > & ) const = 0; @@ -273,18 +292,18 @@ public: epicsGuard < epicsMutex > & ) const = 0; virtual unsigned beaconAnomaliesSinceProgramStart ( epicsGuard < epicsMutex > & ) const = 0; - virtual void show ( + virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0; }; class epicsShareClass cacContextNotify { public: virtual ~cacContextNotify () = 0; - virtual cacContext & createNetworkContext ( + 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, + virtual void exception ( + epicsGuard < epicsMutex > &, int status, const char * pContext, const char * pFileName, unsigned lineNo ) = 0; // perhaps this should be phased out in deference to the exception mechanism virtual int varArgsPrintFormated ( const char * pformat, va_list args ) const = 0; @@ -300,9 +319,9 @@ public: class epicsShareClass cacService { public: virtual ~cacService () = 0; - virtual cacContext & contextCreate ( - epicsMutex & mutualExclusion, - epicsMutex & callbackControl, + virtual cacContext & contextCreate ( + epicsMutex & mutualExclusion, + epicsMutex & callbackControl, cacContextNotify & ) = 0; }; @@ -320,9 +339,9 @@ inline cacChannelNotify & cacChannel::notify () const return this->callback; } -inline caAccessRights::caAccessRights ( +inline caAccessRights::caAccessRights ( bool readPermit, bool writePermit, bool operatorConfirmationRequest) : - f_readPermit ( readPermit ), f_writePermit ( writePermit ), + f_readPermit ( readPermit ), f_writePermit ( writePermit ), f_operatorConfirmationRequest ( operatorConfirmationRequest ) {} inline void caAccessRights::setReadPermit () diff --git a/src/ca/client/nciu.cpp b/src/ca/client/nciu.cpp index 4efe6f5ab..8eb89c5c3 100644 --- a/src/ca/client/nciu.cpp +++ b/src/ca/client/nciu.cpp @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* * @@ -39,9 +39,9 @@ #include "db_access.h" // for INVALID_DB_REQ #include "noopiiu.h" -nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn, +nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn, const char *pNameIn, cacChannel::priLev pri ) : - cacChannel ( chanIn ), + cacChannel ( chanIn ), cacCtx ( cacIn ), piiu ( & iiuIn ), sid ( UINT_MAX ), @@ -57,7 +57,7 @@ nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn, if ( nameLengthTmp > MAX_UDP_SEND - sizeof ( caHdr ) || nameLengthTmp > USHRT_MAX ) { throw cacChannel::badString (); } - + if ( pri > 0xff ) { throw cacChannel::badPriority (); } @@ -76,26 +76,28 @@ 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 ); + this->piiu->uninstallChan ( mutualExcusionGuard, *this ); + this->cacCtx.destroyChannel ( mutualExcusionGuard, *this ); } void nciu::operator delete ( void * ) -{ +{ // Visual C++ .net appears to require operator delete if // placement operator delete is defined? I smell a ms rat // because if I declare placement new and delete, but @@ -105,15 +107,15 @@ void nciu::operator delete ( void * ) __FILE__, __LINE__ ); } -void nciu::initiateConnect ( +void nciu::initiateConnect ( epicsGuard < epicsMutex > & guard ) -{ +{ this->cacCtx.initiateConnect ( guard, *this, this->piiu ); } -void nciu::connect ( unsigned nativeType, - unsigned nativeCount, unsigned sidIn, - epicsGuard < epicsMutex > & /* cbGuard */, +void nciu::connect ( unsigned nativeType, + unsigned nativeCount, unsigned sidIn, + epicsGuard < epicsMutex > & /* cbGuard */, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); @@ -127,7 +129,7 @@ void nciu::connect ( unsigned nativeType, /* * if less than v4.1 then the server will never - * send access rights and there will always be access + * send access rights and there will always be access */ bool v41Ok = this->piiu->ca_v41_ok ( guard ); if ( ! v41Ok ) { @@ -138,49 +140,49 @@ void nciu::connect ( unsigned nativeType, /* * if less than v4.1 then the server will never * send access rights and we know that there - * will always be access and also need to call + * will always be access and also need to call * their call back here */ if ( ! v41Ok ) { - this->notify().accessRightsNotify ( + this->notify().accessRightsNotify ( guard, this->accessRightState ); } // channel uninstal routine grabs the callback lock so - // a channel will not be deleted while a call back is + // a channel will not be deleted while a call back is // in progress // - // the callback lock is also taken when a channel - // disconnects to prevent a race condition with the + // the callback lock is also taken when a channel + // disconnects to prevent a race condition with the // code below - ie we hold the callback lock here // so a chanel cant be destroyed out from under us. this->notify().connectNotify ( guard ); } -void nciu::unresponsiveCircuitNotify ( - epicsGuard < epicsMutex > & cbGuard, +void nciu::unresponsiveCircuitNotify ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { ioid tmpId = this->getId (); cac & caRefTmp = this->cacCtx; guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - this->cacCtx.disconnectAllIO ( cbGuard, guard, + this->cacCtx.disconnectAllIO ( cbGuard, guard, *this, this->eventq ); this->notify().disconnectNotify ( guard ); - // if they destroy the channel in their disconnect + // if they destroy the channel in their disconnect // handler then we have to be very careful to not // touch this object if it has been destroyed nciu * pChan = caRefTmp.lookupChannel ( guard, tmpId ); if ( pChan ) { caAccessRights noRights; pChan->notify().accessRightsNotify ( guard, noRights ); - // likewise, they might destroy the channel in their access rights - // handler so we have to be very careful to not touch this + // likewise, they might destroy the channel in their access rights + // handler so we have to be very careful to not touch this // object from here on down } } -void nciu::setServerAddressUnknown ( netiiu & newiiu, +void nciu::setServerAddressUnknown ( netiiu & newiiu, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); @@ -193,8 +195,8 @@ void nciu::setServerAddressUnknown ( netiiu & newiiu, this->accessRightState.clrWritePermit(); } -void nciu::accessRightsStateChange ( - const caAccessRights & arIn, epicsGuard < epicsMutex > & /* cbGuard */, +void nciu::accessRightsStateChange ( + const caAccessRights & arIn, epicsGuard < epicsMutex > & /* cbGuard */, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); @@ -204,7 +206,7 @@ void nciu::accessRightsStateChange ( // the channel delete routine takes the call back lock so // that this will not be called when the channel is being // deleted. - // + // this->notify().accessRightsNotify ( guard, this->accessRightState ); } @@ -213,7 +215,7 @@ void nciu::accessRightsStateChange ( */ bool nciu::searchMsg ( epicsGuard < epicsMutex > & guard ) { - bool success = this->piiu->searchMsg ( + bool success = this->piiu->searchMsg ( guard, this->getId (), this->pNameStr, this->nameLength ); if ( success ) { if ( this->retry < UINT_MAX ) { @@ -256,21 +258,21 @@ unsigned nciu::nameLen ( return this->nameLength; } -unsigned nciu::requestMessageBytesPending ( +unsigned nciu::requestMessageBytesPending ( epicsGuard < epicsMutex > & guard ) { return piiu->requestMessageBytesPending ( guard ); } -void nciu::flush ( +void nciu::flush ( epicsGuard < epicsMutex > & guard ) { piiu->flush ( guard ); } -cacChannel::ioStatus nciu::read ( +cacChannel::ioStatus nciu::read ( epicsGuard < epicsMutex > & guard, - unsigned type, arrayElementCount countIn, + unsigned type, arrayElementCount countIn, cacReadNotify ¬ify, ioid *pId ) { guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); @@ -292,7 +294,7 @@ cacChannel::ioStatus nciu::read ( throw cacChannel::badType (); } - netReadNotifyIO & io = this->cacCtx.readNotifyRequest ( + netReadNotifyIO & io = this->cacCtx.readNotifyRequest ( guard, *this, *this, type, countIn, notify ); if ( pId ) { *pId = io.getId (); @@ -314,7 +316,7 @@ void nciu::stringVerify ( const char *pStr, const unsigned count ) } } -void nciu::write ( +void nciu::write ( epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount countIn, const void * pValue ) { @@ -337,8 +339,8 @@ void nciu::write ( this->piiu->writeRequest ( guard, *this, type, countIn, pValue ); } -cacChannel::ioStatus nciu::write ( - epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount countIn, +cacChannel::ioStatus nciu::write ( + epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount countIn, const void * pValue, cacWriteNotify & notify, ioid * pId ) { // make sure that they get this and not "no write access" @@ -356,7 +358,7 @@ cacChannel::ioStatus nciu::write ( nciu::stringVerify ( (char *) pValue, countIn ); } - netWriteNotifyIO & io = this->cacCtx.writeNotifyRequest ( + netWriteNotifyIO & io = this->cacCtx.writeNotifyRequest ( guard, *this, *this, type, countIn, pValue, notify ); if ( pId ) { *pId = io.getId (); @@ -365,13 +367,13 @@ cacChannel::ioStatus nciu::write ( return cacChannel::iosAsynch; } -void nciu::subscribe ( - epicsGuard < epicsMutex > & guard, unsigned type, - arrayElementCount nElem, unsigned mask, +void nciu::subscribe ( + epicsGuard < epicsMutex > & guard, unsigned type, + arrayElementCount nElem, unsigned mask, cacStateNotify & notify, ioid *pId ) { - netSubscription & io = this->cacCtx.subscriptionRequest ( - guard, *this, *this, type, nElem, mask, notify, + netSubscription & io = this->cacCtx.subscriptionRequest ( + guard, *this, *this, type, nElem, mask, notify, this->channelNode::isInstalledInServer ( guard ) ); this->eventq.add ( io ); if ( pId ) { @@ -379,24 +381,27 @@ void nciu::subscribe ( } } -void nciu::ioCancel ( - epicsGuard < epicsMutex > & guard, const ioid & idIn ) +void nciu::ioCancel ( + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, + const ioid & idIn ) { - this->cacCtx.destroyIO ( guard, idIn, *this ); + this->cacCtx.destroyIO ( callbackGuard, + mutualExclusionGuard, idIn, *this ); } -void nciu::ioShow ( - epicsGuard < epicsMutex > & guard, +void nciu::ioShow ( + epicsGuard < epicsMutex > & guard, const ioid &idIn, unsigned level ) const { this->cacCtx.ioShow ( guard, idIn, level ); } -unsigned nciu::getHostName ( +unsigned nciu::getHostName ( epicsGuard < epicsMutex > & guard, char *pBuf, unsigned bufLength ) const throw () -{ - return this->piiu->getHostName ( +{ + return this->piiu->getHostName ( guard, pBuf, bufLength ); } @@ -424,7 +429,7 @@ short nciu::nativeType ( return type; } -arrayElementCount nciu::nativeElementCount ( +arrayElementCount nciu::nativeElementCount ( epicsGuard < epicsMutex > & guard ) const { arrayElementCount countOut = 0ul; @@ -472,20 +477,20 @@ void nciu::show ( unsigned level ) const this->show ( guard, level ); } -void nciu::show ( +void nciu::show ( epicsGuard < epicsMutex > & guard, unsigned level ) const { if ( this->connected ( guard ) ) { char hostNameTmp [256]; this->getHostName ( guard, hostNameTmp, sizeof ( hostNameTmp ) ); - ::printf ( "Channel \"%s\", connected to server %s", + ::printf ( "Channel \"%s\", connected to server %s", this->pNameStr, hostNameTmp ); if ( level > 1u ) { int tmpTypeCode = static_cast < int > ( this->typeCode ); ::printf ( ", native type %s, native element count %u", dbf_type_to_text ( tmpTypeCode ), this->count ); - ::printf ( ", %sread access, %swrite access", - this->accessRightState.readPermit() ? "" : "no ", + ::printf ( ", %sread access, %swrite access", + this->accessRightState.readPermit() ? "" : "no ", this->accessRightState.writePermit() ? "" : "no "); } ::printf ( "\n" ); @@ -495,7 +500,7 @@ void nciu::show ( } if ( level > 2u ) { - ::printf ( "\tnetwork IO pointer = %p\n", + ::printf ( "\tnetwork IO pointer = %p\n", static_cast ( this->piiu ) ); ::printf ( "\tserver identifier %u\n", this->sid ); ::printf ( "\tsearch retry number=%u\n", this->retry ); @@ -503,7 +508,7 @@ void nciu::show ( } } -void nciu::ioCompletionNotify ( +void nciu::ioCompletionNotify ( epicsGuard < epicsMutex > &, class baseNMIU & io ) { this->eventq.remove ( io ); @@ -544,7 +549,7 @@ void nciu::sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & guard ) pNetIO->forceSubscriptionUpdate ( guard, *this ); } catch ( ... ) { - errlogPrintf ( + errlogPrintf ( "CAC: failed to send subscription update request " "during channel connect\n" ); } @@ -552,68 +557,68 @@ void nciu::sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & guard ) } } -void nciu::disconnectAllIO ( - epicsGuard < epicsMutex > & cbGuard, +void nciu::disconnectAllIO ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { - this->cacCtx.disconnectAllIO ( cbGuard, guard, + this->cacCtx.disconnectAllIO ( cbGuard, guard, *this, this->eventq ); } void nciu::serviceShutdownNotify ( - epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & callbackControlGuard, epicsGuard < epicsMutex > & mutualExclusionGuard ) { this->setServerAddressUnknown ( noopIIU, mutualExclusionGuard ); this->notify().serviceShutdownNotify ( mutualExclusionGuard ); } -void channelNode::setRespPendingState ( - epicsGuard < epicsMutex > &, unsigned index ) +void channelNode::setRespPendingState ( + epicsGuard < epicsMutex > &, unsigned index ) { - this->listMember = + this->listMember = static_cast < channelNode::channelState > ( channelNode::cs_searchRespPending0 + index ); if ( this->listMember > cs_searchRespPending17 ) { - throw std::runtime_error ( + throw std::runtime_error ( "resp search timer index out of bounds" ); } } -void channelNode::setReqPendingState ( - epicsGuard < epicsMutex > &, unsigned index ) +void channelNode::setReqPendingState ( + epicsGuard < epicsMutex > &, unsigned index ) { - this->listMember = + this->listMember = static_cast < channelNode::channelState > ( channelNode::cs_searchReqPending0 + index ); if ( this->listMember > cs_searchReqPending17 ) { - throw std::runtime_error ( + throw std::runtime_error ( "req search timer index out of bounds" ); } } -unsigned channelNode::getMaxSearchTimerCount () +unsigned channelNode::getMaxSearchTimerCount () { - return epicsMin ( + return epicsMin ( cs_searchReqPending17 - cs_searchReqPending0, cs_searchRespPending17 - cs_searchRespPending0 ) + 1u; } -unsigned channelNode::getSearchTimerIndex ( +unsigned channelNode::getSearchTimerIndex ( epicsGuard < epicsMutex > & ) { channelNode::channelState chanState = this->listMember; unsigned index = 0u; - if ( chanState >= cs_searchReqPending0 && + if ( chanState >= cs_searchReqPending0 && chanState <= cs_searchReqPending17 ) { index = chanState - cs_searchReqPending0; } - else if ( chanState >= cs_searchRespPending0 && + else if ( chanState >= cs_searchRespPending0 && chanState <= cs_searchRespPending17 ) { index = chanState - cs_searchRespPending0; } else { - throw std::runtime_error ( + throw std::runtime_error ( "channel was expected to be in a search timer, but wasnt" );; } return index; diff --git a/src/ca/client/nciu.h b/src/ca/client/nciu.h index 0e83e9f96..4994465a8 100644 --- a/src/ca/client/nciu.h +++ b/src/ca/client/nciu.h @@ -5,24 +5,24 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* +/* + * * - * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 - * + * * Copyright, 1986, The Regents of the University of California. - * - * + * + * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 */ -#ifndef nciuh +#ifndef nciuh #define nciuh #ifdef epicsExportSharedSymbols @@ -123,45 +123,45 @@ private: class privateInterfaceForIO { public: - virtual void ioCompletionNotify ( + virtual void ioCompletionNotify ( epicsGuard < epicsMutex > &, class baseNMIU & ) = 0; - virtual arrayElementCount nativeElementCount ( + virtual arrayElementCount nativeElementCount ( epicsGuard < epicsMutex > & ) const = 0; virtual bool connected ( epicsGuard < epicsMutex > & ) const = 0; protected: virtual ~privateInterfaceForIO() {} }; -class nciu : +class nciu : public cacChannel, - public chronIntIdRes < nciu >, + public chronIntIdRes < nciu >, public channelNode, private privateInterfaceForIO { public: - nciu ( cac &, netiiu &, cacChannelNotify &, + nciu ( cac &, netiiu &, cacChannelNotify &, const char * pNameIn, cacChannel::priLev ); ~nciu (); - void connect ( unsigned nativeType, - unsigned nativeCount, unsigned sid, - epicsGuard < epicsMutex > & cbGuard, + void connect ( unsigned nativeType, + unsigned nativeCount, unsigned sid, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void connect ( epicsGuard < epicsMutex > & cbGuard, + void connect ( epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void unresponsiveCircuitNotify ( - epicsGuard < epicsMutex > & cbGuard, + void unresponsiveCircuitNotify ( + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void circuitHangupNotify ( class udpiiu &, - epicsGuard < epicsMutex > & cbGuard, + void circuitHangupNotify ( class udpiiu &, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void setServerAddressUnknown ( + void setServerAddressUnknown ( netiiu & newiiu, epicsGuard < epicsMutex > & guard ); - bool searchMsg ( + bool searchMsg ( epicsGuard < epicsMutex > & ); void serviceShutdownNotify ( - epicsGuard < epicsMutex > & callbackControlGuard, + epicsGuard < epicsMutex > & callbackControlGuard, epicsGuard < epicsMutex > & mutualExclusionGuard ); - void accessRightsStateChange ( const caAccessRights &, - epicsGuard < epicsMutex > & cbGuard, + void accessRightsStateChange ( const caAccessRights &, + epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); ca_uint32_t getSID ( epicsGuard < epicsMutex > & ) const; @@ -172,12 +172,12 @@ public: const netiiu * getConstPIIU ( epicsGuard < epicsMutex > & ) const; cac & getClient (); - void searchReplySetUp ( netiiu &iiu, unsigned sidIn, + void searchReplySetUp ( netiiu &iiu, unsigned sidIn, ca_uint16_t typeIn, arrayElementCount countIn, epicsGuard < epicsMutex > & ); - void show ( + void show ( unsigned level ) const; - void show ( + void show ( epicsGuard < epicsMutex > &, unsigned level ) const; unsigned getName ( @@ -189,22 +189,22 @@ public: epicsGuard < epicsMutex > & ) const; unsigned getHostName ( epicsGuard < epicsMutex > &, - char * pBuf, unsigned bufLen ) const throw (); - void writeException ( + char * pBuf, unsigned bufLen ) const throw (); + void writeException ( epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count ); cacChannel::priLev getPriority ( epicsGuard < epicsMutex > & ) const; - void * operator new ( + void * operator new ( size_t size, tsFreeList < class nciu, 1024, epicsMutexNOOP > & ); epicsPlacementDeleteOperator ( ( void *, tsFreeList < class nciu, 1024, epicsMutexNOOP > & )) //arrayElementCount nativeElementCount ( epicsGuard < epicsMutex > & ) const; void resubscribe ( epicsGuard < epicsMutex > & ); void sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & ); - void disconnectAllIO ( + void disconnectAllIO ( epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & ); - bool connected ( epicsGuard < epicsMutex > & ) const; + bool connected ( epicsGuard < epicsMutex > & ) const; unsigned getcount() const { return count; } private: @@ -218,38 +218,47 @@ private: unsigned retry; // search retry number unsigned short nameLength; // channel name length ca_uint16_t typeCode; - ca_uint8_t priority; + ca_uint8_t priority; virtual void destroy ( + CallbackGuard & callbackGuard, epicsGuard < epicsMutex > & mutualExclusionGuard ); void initiateConnect ( epicsGuard < epicsMutex > & ); - unsigned requestMessageBytesPending ( + unsigned requestMessageBytesPending ( epicsGuard < epicsMutex > & mutualExclusionGuard ); - void flush ( + void flush ( epicsGuard < epicsMutex > & mutualExclusionGuard ); - ioStatus read ( + ioStatus read ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, cacReadNotify &, ioid * ); - void write ( + void write ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, const void *pValue ); - ioStatus write ( + ioStatus write ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, const void *pValue, cacWriteNotify &, ioid * ); - void subscribe ( - epicsGuard < epicsMutex > & guard, - unsigned type, arrayElementCount nElem, + void subscribe ( + epicsGuard < epicsMutex > & guard, + unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify ¬ify, ioid * ); - virtual void ioCancel ( + // 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 ( + void ioShow ( epicsGuard < epicsMutex > &, const ioid &, unsigned level ) const; - short nativeType ( + short nativeType ( epicsGuard < epicsMutex > & ) const; caAccessRights accessRights ( epicsGuard < epicsMutex > & ) const; @@ -264,7 +273,7 @@ private: arrayElementCount nativeElementCount ( epicsGuard < epicsMutex > & ) const; static void stringVerify ( const char *pStr, const unsigned count ); - void ioCompletionNotify ( + void ioCompletionNotify ( epicsGuard < epicsMutex > &, class baseNMIU & ); const char * pHostName ( epicsGuard < epicsMutex > & guard ) const throw (); @@ -273,16 +282,16 @@ private: void operator delete ( void * ); }; -inline void * nciu::operator new ( size_t size, +inline void * nciu::operator new ( size_t size, tsFreeList < class nciu, 1024, epicsMutexNOOP > & freeList ) -{ +{ return freeList.allocate ( size ); } #ifdef CXX_PLACEMENT_DELETE inline void nciu::operator delete ( void * pCadaver, tsFreeList < class nciu, 1024, epicsMutexNOOP > & freeList ) -{ +{ freeList.release ( pCadaver, sizeof ( nciu ) ); } #endif @@ -300,19 +309,19 @@ inline ca_uint32_t nciu::getCID ( } // this is to only be used by early protocol revisions -inline void nciu::connect ( epicsGuard < epicsMutex > & cbGuard, +inline void nciu::connect ( epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ) { - this->connect ( this->typeCode, this->count, + this->connect ( this->typeCode, this->count, this->sid, cbGuard, guard ); } -inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn, +inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn, ca_uint16_t typeIn, arrayElementCount countIn, epicsGuard < epicsMutex > & ) { this->piiu = & iiu; - this->typeCode = typeIn; + this->typeCode = typeIn; this->count = countIn; this->sid = sidIn; } @@ -323,13 +332,13 @@ inline netiiu * nciu::getPIIU ( return this->piiu; } -inline void nciu::writeException ( - epicsGuard < epicsMutex > & /* cbGuard */, - epicsGuard < epicsMutex > & guard, - int status, const char * pContext, +inline void nciu::writeException ( + epicsGuard < epicsMutex > & /* cbGuard */, + epicsGuard < epicsMutex > & guard, + int status, const char * pContext, unsigned typeIn, arrayElementCount countIn ) { - this->notify().writeException ( guard, + this->notify().writeException ( guard, status, pContext, typeIn, countIn ); } @@ -357,15 +366,15 @@ inline channelNode::channelNode () : inline bool channelNode::isConnected ( epicsGuard < epicsMutex > & ) const { - return - this->listMember == cs_connected || + return + this->listMember == cs_connected || this->listMember == cs_subscripReqPend || this->listMember == cs_subscripUpdateReqPend; } inline bool channelNode::isInstalledInServer ( epicsGuard < epicsMutex > & ) const { - return + return this->listMember == cs_connected || this->listMember == cs_subscripReqPend || this->listMember == cs_unrespCircuit || diff --git a/src/ca/client/oldAccess.h b/src/ca/client/oldAccess.h index ff4f36e4a..ee5020513 100644 --- a/src/ca/client/oldAccess.h +++ b/src/ca/client/oldAccess.h @@ -5,19 +5,19 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* +/* + * * - * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 - * + * * Copyright, The Regents of the University of California. - * - * + * + * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 @@ -48,92 +48,94 @@ struct oldChannelNotify : private cacChannelNotify { public: - oldChannelNotify ( - epicsGuard < epicsMutex > &, struct ca_client_context &, - const char * pName, caCh * pConnCallBackIn, + oldChannelNotify ( + epicsGuard < epicsMutex > &, struct ca_client_context &, + const char * pName, caCh * pConnCallBackIn, void * pPrivateIn, capri priority ); - void destructor ( - epicsGuard < epicsMutex > & guard ); + void destructor ( + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & mutexGuard ); // legacy C API - friend unsigned epicsShareAPI ca_get_host_name ( + friend unsigned epicsShareAPI ca_get_host_name ( chid pChan, char * pBuf, unsigned bufLength ); - friend const char * epicsShareAPI ca_host_name ( + friend const char * epicsShareAPI ca_host_name ( chid pChan ); - friend const char * epicsShareAPI ca_name ( + friend const char * epicsShareAPI ca_name ( chid pChan ); - friend void epicsShareAPI ca_set_puser ( + friend void epicsShareAPI ca_set_puser ( chid pChan, void * puser ); - friend void * epicsShareAPI ca_puser ( + friend void * epicsShareAPI ca_puser ( chid pChan ); - friend int epicsShareAPI ca_change_connection_event ( + friend int epicsShareAPI ca_change_connection_event ( chid pChan, caCh * pfunc ); - friend int epicsShareAPI ca_replace_access_rights_event ( + friend int epicsShareAPI ca_replace_access_rights_event ( chid pChan, caArh *pfunc ); - friend int epicsShareAPI ca_array_get ( chtype type, + friend int epicsShareAPI ca_array_get ( chtype type, arrayElementCount count, chid pChan, void * pValue ); - friend int epicsShareAPI ca_array_get_callback ( chtype type, + friend int epicsShareAPI ca_array_get_callback ( chtype type, arrayElementCount count, chid pChan, caEventCallBackFunc *pfunc, void *arg ); - friend int epicsShareAPI ca_array_put ( - chtype type, arrayElementCount count, + friend int epicsShareAPI ca_array_put ( + chtype type, arrayElementCount count, chid pChan, const void * pValue ); - friend int epicsShareAPI ca_array_put_callback ( - chtype type, arrayElementCount count, - chid pChan, const void *pValue, + friend int epicsShareAPI ca_array_put_callback ( + chtype type, arrayElementCount count, + chid pChan, const void *pValue, caEventCallBackFunc *pfunc, void *usrarg ); - friend double epicsShareAPI ca_beacon_period ( + friend double epicsShareAPI ca_beacon_period ( chid pChan ); - friend unsigned epicsShareAPI ca_search_attempts ( + friend unsigned epicsShareAPI ca_search_attempts ( chid pChan ); - friend unsigned epicsShareAPI ca_write_access ( + friend unsigned epicsShareAPI ca_write_access ( chid pChan ); - friend unsigned epicsShareAPI ca_read_access ( + friend unsigned epicsShareAPI ca_read_access ( chid pChan ); - friend short epicsShareAPI ca_field_type ( + friend short epicsShareAPI ca_field_type ( chid pChan ); - friend arrayElementCount epicsShareAPI ca_element_count ( + friend arrayElementCount epicsShareAPI ca_element_count ( chid pChan ); - friend int epicsShareAPI ca_v42_ok ( + friend int epicsShareAPI ca_v42_ok ( chid pChan ); - friend int epicsShareAPI ca_create_subscription ( - chtype type, arrayElementCount count, chid pChan, - long mask, caEventCallBackFunc * pCallBack, + friend int epicsShareAPI ca_create_subscription ( + chtype type, arrayElementCount count, chid pChan, + long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, evid * monixptr ); - friend enum channel_state epicsShareAPI ca_state ( - chid pChan ); - friend double epicsShareAPI ca_receive_watchdog_delay ( + friend enum channel_state epicsShareAPI ca_state ( + chid pChan ); + friend double epicsShareAPI ca_receive_watchdog_delay ( chid pChan ); unsigned getName ( epicsGuard < epicsMutex > &, char * pBuf, unsigned bufLen ) const throw (); - void show ( + void show ( epicsGuard < epicsMutex > &, unsigned level ) const; void initiateConnect ( epicsGuard < epicsMutex > & ); - void read ( + void read ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, cacReadNotify ¬ify, cacChannel::ioid *pId = 0 ); - void write ( + void write ( epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, const void *pValue, + unsigned type, arrayElementCount count, const void *pValue, cacWriteNotify &, cacChannel::ioid *pId = 0 ); - void ioCancel ( - epicsGuard < epicsMutex > & mutualExclusionGuard, + void ioCancel ( + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, const cacChannel::ioid & ); - void ioShow ( + void ioShow ( epicsGuard < epicsMutex > & guard, const cacChannel::ioid &, unsigned level ) const; ca_client_context & getClientCtx (); - void eliminateExcessiveSendBacklog ( + void eliminateExcessiveSendBacklog ( epicsGuard < epicsMutex > & ); - void * operator new ( size_t size, + void * operator new ( size_t size, tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void * , + epicsPlacementDeleteOperator (( void * , tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & )) protected: ~oldChannelNotify (); @@ -150,7 +152,7 @@ private: void disconnectNotify ( epicsGuard < epicsMutex > & ); void serviceShutdownNotify ( epicsGuard < epicsMutex > & mutualExclusionGuard ); - void accessRightsNotify ( + void accessRightsNotify ( epicsGuard < epicsMutex > &, const caAccessRights & ); void exception ( epicsGuard < epicsMutex > &, int status, const char * pContext ); @@ -160,24 +162,24 @@ private: void writeException ( epicsGuard < epicsMutex > &, int status, const char * pContext, unsigned type, arrayElementCount count ); - oldChannelNotify ( const oldChannelNotify & ); - oldChannelNotify & operator = ( const oldChannelNotify & ); + oldChannelNotify ( const oldChannelNotify & ); + oldChannelNotify & operator = ( const oldChannelNotify & ); void operator delete ( void * ); }; class getCopy : public cacReadNotify { public: - getCopy ( - epicsGuard < epicsMutex > & guard, - ca_client_context & cacCtx, - oldChannelNotify &, unsigned type, + getCopy ( + epicsGuard < epicsMutex > & guard, + ca_client_context & cacCtx, + oldChannelNotify &, unsigned type, arrayElementCount count, void *pValue ); ~getCopy (); void show ( unsigned level ) const; void cancel (); - void * operator new ( size_t size, + void * operator new ( size_t size, tsFreeList < class getCopy, 1024, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < class getCopy, 1024, epicsMutexNOOP > & )) private: arrayElementCount count; @@ -187,10 +189,10 @@ private: unsigned ioSeqNo; unsigned type; void completion ( - epicsGuard < epicsMutex > &, unsigned type, + epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void *pData ); - void exception ( - epicsGuard < epicsMutex > &, int status, + void exception ( + epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count ); getCopy ( const getCopy & ); getCopy & operator = ( const getCopy & ); @@ -199,23 +201,23 @@ private: class getCallback : public cacReadNotify { public: - getCallback ( - oldChannelNotify & chanIn, + getCallback ( + oldChannelNotify & chanIn, caEventCallBackFunc *pFunc, void *pPrivate ); - ~getCallback (); - void * operator new ( size_t size, + ~getCallback (); + void * operator new ( size_t size, tsFreeList < class getCallback, 1024, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < class getCallback, 1024, epicsMutexNOOP > & )) private: oldChannelNotify & chan; caEventCallBackFunc * pFunc; void * pPrivate; void completion ( - epicsGuard < epicsMutex > &, unsigned type, + epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void *pData); - void exception ( - epicsGuard < epicsMutex > &, int status, + void exception ( + epicsGuard < epicsMutex > &, int status, const char * pContext, unsigned type, arrayElementCount count ); getCallback ( const getCallback & ); getCallback & operator = ( const getCallback & ); @@ -224,21 +226,21 @@ private: class putCallback : public cacWriteNotify { public: - putCallback ( - oldChannelNotify &, + putCallback ( + oldChannelNotify &, caEventCallBackFunc *pFunc, void *pPrivate ); ~putCallback (); - void * operator new ( size_t size, + void * operator new ( size_t size, tsFreeList < class putCallback, 1024, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < class putCallback, 1024, epicsMutexNOOP > & )) private: oldChannelNotify & chan; caEventCallBackFunc * pFunc; void *pPrivate; void completion ( epicsGuard < epicsMutex > & ); - void exception ( - epicsGuard < epicsMutex > &, int status, const char *pContext, + void exception ( + epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count ); putCallback ( const putCallback & ); putCallback & operator = ( const putCallback & ); @@ -249,17 +251,25 @@ struct oldSubscription : private cacStateNotify { public: oldSubscription ( epicsGuard < epicsMutex > & guard, - oldChannelNotify & chanIn, cacChannel & io, + oldChannelNotify & chanIn, cacChannel & io, unsigned type, arrayElementCount nElem, unsigned mask, caEventCallBackFunc * pFuncIn, void * pPrivateIn, evid * ); ~oldSubscription (); oldChannelNotify & channel () const; - void cancel ( - epicsGuard < epicsMutex > & guard ); - void * operator new ( size_t size, + // 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 ( + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ); + void * operator new ( size_t size, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & )) private: oldChannelNotify & chan; @@ -267,10 +277,10 @@ private: caEventCallBackFunc * pFunc; void * pPrivate; void current ( - epicsGuard < epicsMutex > &, unsigned type, + epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void *pData ); - void exception ( - epicsGuard < epicsMutex > &, int status, + void exception ( + epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count ); oldSubscription ( const oldSubscription & ); oldSubscription & operator = ( const oldSubscription & ); @@ -285,16 +295,16 @@ struct ca_client_context : public cacContextNotify public: ca_client_context ( bool enablePreemptiveCallback = false ); virtual ~ca_client_context (); - void changeExceptionEvent ( + void changeExceptionEvent ( caExceptionHandler * pfunc, void * arg ); - void registerForFileDescriptorCallBack ( + void registerForFileDescriptorCallBack ( CAFDHANDLER * pFunc, void * pArg ); void replaceErrLogHandler ( caPrintfFunc * ca_printf_func ); - cacChannel & createChannel ( - epicsGuard < epicsMutex > &, const char * pChannelName, + cacChannel & createChannel ( + epicsGuard < epicsMutex > &, const char * pChannelName, cacChannelNotify &, cacChannel::priLev pri ); void flush ( epicsGuard < epicsMutex > & ); - void eliminateExcessiveSendBacklog ( + void eliminateExcessiveSendBacklog ( epicsGuard < epicsMutex > &, cacChannel & ); int pendIO ( const double & timeout ); int pendEvent ( const double & timeout ); @@ -304,18 +314,18 @@ public: unsigned sequenceNumberOfOutstandingIO ( epicsGuard < epicsMutex > & ) const; unsigned beaconAnomaliesSinceProgramStart () const; - void incrementOutstandingIO ( + void incrementOutstandingIO ( epicsGuard < epicsMutex > &, unsigned ioSeqNo ); - void decrementOutstandingIO ( + void decrementOutstandingIO ( epicsGuard < epicsMutex > &, unsigned ioSeqNo ); - void exception ( - epicsGuard < epicsMutex > &, int status, const char * pContext, - const char * pFileName, unsigned lineNo ); - void exception ( + void exception ( epicsGuard < epicsMutex > &, int status, const char * pContext, - const char * pFileName, unsigned lineNo, oldChannelNotify & chan, + const char * pFileName, unsigned lineNo ); + void exception ( + epicsGuard < epicsMutex > &, int status, const char * pContext, + const char * pFileName, unsigned lineNo, oldChannelNotify & chan, unsigned type, arrayElementCount count, unsigned op ); - void blockForEventAndEnableCallbacks ( + void blockForEventAndEnableCallbacks ( epicsEvent & event, const double & timeout ); CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id ); static void installDefaultService ( cacService & ); @@ -325,9 +335,9 @@ public: // perhaps these should be eliminated in deference to the exception mechanism int printFormated ( const char * pformat, ... ) const; int varArgsPrintFormated ( const char * pformat, va_list args ) const; - void signal ( int ca_status, const char * pfilenm, + void signal ( int ca_status, const char * pfilenm, int lineno, const char * pFormat, ... ); - void vSignal ( int ca_status, const char * pfilenm, + void vSignal ( int ca_status, const char * pfilenm, int lineno, const char *pFormat, va_list args ); bool preemptiveCallbakIsEnabled () const; void destroyGetCopy ( epicsGuard < epicsMutex > &, getCopy & ); @@ -336,25 +346,27 @@ public: void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & ); epicsMutex & mutexRef () const; - - // legacy C API + template < class T > + void whenThereIsAnExceptionDestroySyncGroupIO ( epicsGuard < epicsMutex > &, T & ); + + // legacy C API friend int epicsShareAPI ca_create_channel ( const char * name_str, caCh * conn_func, void * puser, capri priority, chid * chanptr ); friend int epicsShareAPI ca_clear_channel ( chid pChan ); - friend int epicsShareAPI ca_array_get ( chtype type, + friend int epicsShareAPI ca_array_get ( chtype type, arrayElementCount count, chid pChan, void * pValue ); - friend int epicsShareAPI ca_array_get_callback ( chtype type, + friend int epicsShareAPI ca_array_get_callback ( chtype type, arrayElementCount count, chid pChan, caEventCallBackFunc *pfunc, void *arg ); - friend int epicsShareAPI ca_array_put ( chtype type, + friend int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count, chid pChan, const void * pValue ); - friend int epicsShareAPI ca_array_put_callback ( chtype type, - arrayElementCount count, chid pChan, const void * pValue, + friend int epicsShareAPI ca_array_put_callback ( chtype type, + arrayElementCount count, chid pChan, const void * pValue, caEventCallBackFunc *pfunc, void *usrarg ); - friend int epicsShareAPI ca_create_subscription ( - chtype type, arrayElementCount count, chid pChan, - long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, + friend int epicsShareAPI ca_create_subscription ( + chtype type, arrayElementCount count, chid pChan, + long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, evid *monixptr ); friend int epicsShareAPI ca_flush_io (); friend int epicsShareAPI ca_clear_subscription ( evid pMon ); @@ -363,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 {}; @@ -375,11 +398,11 @@ private: tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > subscriptionFreeList; tsFreeList < struct CASG, 128, epicsMutexNOOP > casgFreeList; mutable epicsMutex mutex; - mutable epicsMutex cbMutex; + mutable epicsMutex cbMutex; 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; @@ -397,15 +420,15 @@ private: void attachToClientCtx (); void callbackProcessingInitiateNotify (); void callbackProcessingCompleteNotify (); - cacContext & createNetworkContext ( + cacContext & createNetworkContext ( epicsMutex & mutualExclusion, epicsMutex & callbackControl ); void _sendWakeupMsg (); - ca_client_context ( const ca_client_context & ); - ca_client_context & operator = ( const ca_client_context & ); - - friend void cacOnceFunc ( void * ); - friend void cacExitHandler ( void *); + ca_client_context ( const ca_client_context & ); + ca_client_context & operator = ( const ca_client_context & ); + + friend void cacOnceFunc ( void * ); + friend void cacExitHandler ( void *); static cacService * pDefaultService; static epicsMutex * pDefaultServiceInstallMutex; static const unsigned flushBlockThreshold; @@ -425,7 +448,7 @@ inline unsigned oldChannelNotify::getName ( return this->io.getName ( guard, pBuf, bufLen ); } -inline void oldChannelNotify::show ( +inline void oldChannelNotify::show ( epicsGuard < epicsMutex > & guard, unsigned level ) const { @@ -438,58 +461,60 @@ inline void oldChannelNotify::initiateConnect ( this->io.initiateConnect ( guard ); } -inline void oldChannelNotify::ioCancel ( - epicsGuard < epicsMutex > & guard, +inline void oldChannelNotify::ioCancel ( + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard, const cacChannel::ioid & id ) { - this->io.ioCancel ( guard, id ); + this->io.ioCancel ( callbackGuard, mutualExclusionGuard, id ); } -inline void oldChannelNotify::ioShow ( +inline void oldChannelNotify::ioShow ( epicsGuard < epicsMutex > & guard, const cacChannel::ioid & id, unsigned level ) const { this->io.ioShow ( guard, id, level ); } -inline void oldChannelNotify::eliminateExcessiveSendBacklog ( +inline void oldChannelNotify::eliminateExcessiveSendBacklog ( epicsGuard < epicsMutex > & guard ) { this->cacCtx.eliminateExcessiveSendBacklog ( guard, this->io ); } -inline void * oldChannelNotify::operator new ( size_t size, +inline void * oldChannelNotify::operator new ( size_t size, tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #ifdef CXX_PLACEMENT_DELETE -inline void oldChannelNotify::operator delete ( void *pCadaver, - tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList ) +inline void oldChannelNotify::operator delete ( void *pCadaver, + tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } #endif -inline void * oldSubscription::operator new ( size_t size, +inline void * oldSubscription::operator new ( size_t size, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #ifdef CXX_PLACEMENT_DELETE -inline void oldSubscription::operator delete ( void *pCadaver, - tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList ) +inline void oldSubscription::operator delete ( void *pCadaver, + tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } #endif -inline void oldSubscription::cancel ( - epicsGuard < epicsMutex > & guard ) +inline void oldSubscription::cancel ( + CallbackGuard & callbackGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) { - this->chan.ioCancel ( guard, this->id ); + this->chan.ioCancel ( callbackGuard, mutualExclusionGuard, this->id ); } inline oldChannelNotify & oldSubscription::channel () const @@ -497,43 +522,43 @@ inline oldChannelNotify & oldSubscription::channel () const return this->chan; } -inline void * getCopy::operator new ( size_t size, +inline void * getCopy::operator new ( size_t size, tsFreeList < class getCopy, 1024, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #ifdef CXX_PLACEMENT_DELETE -inline void getCopy::operator delete ( void *pCadaver, - tsFreeList < class getCopy, 1024, epicsMutexNOOP > & freeList ) +inline void getCopy::operator delete ( void *pCadaver, + tsFreeList < class getCopy, 1024, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } #endif -inline void * putCallback::operator new ( size_t size, +inline void * putCallback::operator new ( size_t size, tsFreeList < class putCallback, 1024, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #ifdef CXX_PLACEMENT_DELETE -inline void putCallback::operator delete ( void * pCadaver, - tsFreeList < class putCallback, 1024, epicsMutexNOOP > & freeList ) +inline void putCallback::operator delete ( void * pCadaver, + tsFreeList < class putCallback, 1024, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } #endif -inline void * getCallback::operator new ( size_t size, +inline void * getCallback::operator new ( size_t size, tsFreeList < class getCallback, 1024, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #ifdef CXX_PLACEMENT_DELETE -inline void getCallback::operator delete ( void * pCadaver, - tsFreeList < class getCallback, 1024, epicsMutexNOOP > & freeList ) +inline void getCallback::operator delete ( void * pCadaver, + tsFreeList < class getCallback, 1024, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } @@ -555,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/client/oldChannelNotify.cpp b/src/ca/client/oldChannelNotify.cpp index 508792b2e..d8c259040 100644 --- a/src/ca/client/oldChannelNotify.cpp +++ b/src/ca/client/oldChannelNotify.cpp @@ -5,18 +5,18 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* +/* + * * - * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 - * + * * Copyright, 1986, The Regents of the University of California. - * - * + * + * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 @@ -43,13 +43,13 @@ extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args ) { } -oldChannelNotify::oldChannelNotify ( - epicsGuard < epicsMutex > & guard, ca_client_context & cacIn, - const char *pName, caCh * pConnCallBackIn, +oldChannelNotify::oldChannelNotify ( + epicsGuard < epicsMutex > & guard, ca_client_context & cacIn, + const char *pName, caCh * pConnCallBackIn, void * pPrivateIn, capri priority ) : - cacCtx ( cacIn ), - io ( cacIn.createChannel ( guard, pName, *this, priority ) ), - pConnCallBack ( pConnCallBackIn ), + cacCtx ( cacIn ), + io ( cacIn.createChannel ( guard, pName, *this, priority ) ), + pConnCallBack ( pConnCallBackIn ), pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler ), ioSeqNo ( 0 ), currentlyConnected ( false ), prevConnected ( false ) { @@ -65,19 +65,20 @@ 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 (); } -void oldChannelNotify::connectNotify ( +void oldChannelNotify::connectNotify ( epicsGuard < epicsMutex > & guard ) { this->currentlyConnected = true; @@ -97,7 +98,7 @@ void oldChannelNotify::connectNotify ( } } -void oldChannelNotify::disconnectNotify ( +void oldChannelNotify::disconnectNotify ( epicsGuard < epicsMutex > & guard ) { this->currentlyConnected = false; @@ -112,7 +113,7 @@ void oldChannelNotify::disconnectNotify ( } } else { - this->cacCtx.incrementOutstandingIO ( + this->cacCtx.incrementOutstandingIO ( guard, this->ioSeqNo ); } } @@ -123,7 +124,7 @@ void oldChannelNotify::serviceShutdownNotify ( this->disconnectNotify ( guard ); } -void oldChannelNotify::accessRightsNotify ( +void oldChannelNotify::accessRightsNotify ( epicsGuard < epicsMutex > & guard, const caAccessRights & ar ) { struct access_rights_handler_args args; @@ -137,25 +138,25 @@ void oldChannelNotify::accessRightsNotify ( } } -void oldChannelNotify::exception ( +void oldChannelNotify::exception ( epicsGuard < epicsMutex > & guard, int status, const char * pContext ) { this->cacCtx.exception ( guard, status, pContext, __FILE__, __LINE__ ); } -void oldChannelNotify::readException ( +void oldChannelNotify::readException ( epicsGuard < epicsMutex > & guard, int status, const char *pContext, unsigned type, arrayElementCount count, void * /* pValue */ ) { - this->cacCtx.exception ( guard, status, pContext, + this->cacCtx.exception ( guard, status, pContext, __FILE__, __LINE__, *this, type, count, CA_OP_GET ); } -void oldChannelNotify::writeException ( +void oldChannelNotify::writeException ( epicsGuard < epicsMutex > & guard, int status, const char *pContext, unsigned type, arrayElementCount count ) { - this->cacCtx.exception ( guard, status, pContext, + this->cacCtx.exception ( guard, status, pContext, __FILE__, __LINE__, *this, type, count, CA_OP_PUT ); } @@ -173,7 +174,7 @@ void oldChannelNotify::operator delete ( void * ) /* * ca_get_host_name () */ -unsigned epicsShareAPI ca_get_host_name ( +unsigned epicsShareAPI ca_get_host_name ( chid pChan, char * pBuf, unsigned bufLength ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef() ); @@ -186,7 +187,7 @@ unsigned epicsShareAPI ca_get_host_name ( * !!!! not thread safe !!!! * */ -const char * epicsShareAPI ca_host_name ( +const char * epicsShareAPI ca_host_name ( chid pChan ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); @@ -196,7 +197,7 @@ const char * epicsShareAPI ca_host_name ( /* * ca_set_puser () */ -void epicsShareAPI ca_set_puser ( +void epicsShareAPI ca_set_puser ( chid pChan, void * puser ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); @@ -206,7 +207,7 @@ void epicsShareAPI ca_set_puser ( /* * ca_get_puser () */ -void * epicsShareAPI ca_puser ( +void * epicsShareAPI ca_puser ( chid pChan ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); @@ -220,7 +221,7 @@ int epicsShareAPI ca_change_connection_event ( chid pChan, caCh * pfunc ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); if ( ! pChan->currentlyConnected ) { - if ( pfunc ) { + if ( pfunc ) { if ( ! pChan->pConnCallBack ) { pChan->cacCtx.decrementOutstandingIO ( guard, pChan->ioSeqNo ); } @@ -238,7 +239,7 @@ int epicsShareAPI ca_change_connection_event ( chid pChan, caCh * pfunc ) /* * ca_replace_access_rights_event */ -int epicsShareAPI ca_replace_access_rights_event ( +int epicsShareAPI ca_replace_access_rights_event ( chid pChan, caArh *pfunc ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); @@ -246,11 +247,11 @@ int epicsShareAPI ca_replace_access_rights_event ( // The order of the following is significant to guarantee that the // access rights handler is always gets called even if the channel connects // while this is running. There is some very small chance that the - // handler could be called twice here with the same access rights state, but + // handler could be called twice here with the same access rights state, but // that will not upset the application. pChan->pAccessRightsFunc = pfunc ? pfunc : cacNoopAccesRightsHandler; caAccessRights tmp = pChan->io.accessRights ( guard ); - + if ( pChan->currentlyConnected ) { struct access_rights_handler_args args; args.chid = pChan; @@ -265,7 +266,7 @@ int epicsShareAPI ca_replace_access_rights_event ( /* * ca_array_get () */ -int epicsShareAPI ca_array_get ( chtype type, +int epicsShareAPI ca_array_get ( chtype type, arrayElementCount count, chid pChan, void *pValue ) { int caStatus; @@ -279,10 +280,10 @@ int epicsShareAPI ca_array_get ( chtype type, unsigned tmpType = static_cast < unsigned > ( type ); epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); pChan->eliminateExcessiveSendBacklog ( guard ); - autoPtrFreeList < getCopy, 0x400, epicsMutexNOOP > pNotify + autoPtrFreeList < getCopy, 0x400, epicsMutexNOOP > pNotify ( pChan->getClientCtx().getCopyFreeList, - new ( pChan->getClientCtx().getCopyFreeList ) - getCopy ( guard, pChan->getClientCtx(), *pChan, + new ( pChan->getClientCtx().getCopyFreeList ) + getCopy ( guard, pChan->getClientCtx(), *pChan, tmpType, count, pValue ) ); pChan->io.read ( guard, type, count, *pNotify, 0 ); pNotify.release (); @@ -333,7 +334,7 @@ int epicsShareAPI ca_array_get ( chtype type, /* * ca_array_get_callback () */ -int epicsShareAPI ca_array_get_callback ( chtype type, +int epicsShareAPI ca_array_get_callback ( chtype type, arrayElementCount count, chid pChan, caEventCallBackFunc *pfunc, void *arg ) { @@ -346,7 +347,7 @@ int epicsShareAPI ca_array_get_callback ( chtype type, epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); pChan->eliminateExcessiveSendBacklog ( guard ); - autoPtrFreeList < getCallback, 0x400, epicsMutexNOOP > pNotify + autoPtrFreeList < getCallback, 0x400, epicsMutexNOOP > pNotify ( pChan->getClientCtx().getCallbackFreeList, new ( pChan->getClientCtx().getCallbackFreeList ) getCallback ( *pChan, pfunc, arg ) ); @@ -396,9 +397,9 @@ int epicsShareAPI ca_array_get_callback ( chtype type, return caStatus; } -void oldChannelNotify::read ( +void oldChannelNotify::read ( epicsGuard < epicsMutex > & guard, - unsigned type, arrayElementCount count, + unsigned type, arrayElementCount count, cacReadNotify & notify, cacChannel::ioid * pId ) { this->io.read ( guard, type, count, notify, pId ); @@ -407,7 +408,7 @@ void oldChannelNotify::read ( /* * ca_array_put_callback () */ -int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count, +int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count, chid pChan, const void *pValue, caEventCallBackFunc *pfunc, void *usrarg ) { int caStatus; @@ -468,7 +469,7 @@ int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count, /* * ca_array_put () */ -int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count, +int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count, chid pChan, const void * pValue ) { if ( type < 0 ) { @@ -522,9 +523,9 @@ int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count, return caStatus; } -int epicsShareAPI ca_create_subscription ( - chtype type, arrayElementCount count, chid pChan, - long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, +int epicsShareAPI ca_create_subscription ( + chtype type, arrayElementCount count, chid pChan, + long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, evid * monixptr ) { if ( type < 0 ) { @@ -552,7 +553,7 @@ int epicsShareAPI ca_create_subscription ( try { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); try { - // if this stalls out on a live circuit then an exception + // if this stalls out on a live circuit then an exception // can be forthcoming which we must ignore (this is a // special case preserving legacy ca_create_subscription // behavior) @@ -562,7 +563,7 @@ int epicsShareAPI ca_create_subscription ( // intentionally ignored (its ok to subscribe when not connected) } new ( pChan->getClientCtx().subscriptionFreeList ) - oldSubscription ( + oldSubscription ( guard, *pChan, pChan->io, tmpType, count, mask, pCallBack, pCallBackArg, monixptr ); // dont touch object created after above new because @@ -603,8 +604,8 @@ int epicsShareAPI ca_create_subscription ( } } -void oldChannelNotify::write ( - epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, +void oldChannelNotify::write ( + epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, const void * pValue, cacWriteNotify & notify, cacChannel::ioid * pId ) { this->io.write ( guard, type, count, pValue, notify, pId ); @@ -613,7 +614,7 @@ void oldChannelNotify::write ( /* * ca_field_type() */ -short epicsShareAPI ca_field_type ( chid pChan ) +short epicsShareAPI ca_field_type ( chid pChan ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); return pChan->io.nativeType ( guard ); @@ -622,7 +623,7 @@ short epicsShareAPI ca_field_type ( chid pChan ) /* * ca_element_count () */ -arrayElementCount epicsShareAPI ca_element_count ( chid pChan ) +arrayElementCount epicsShareAPI ca_element_count ( chid pChan ) { epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); return pChan->io.nativeElementCount ( guard ); @@ -674,7 +675,7 @@ const char * epicsShareAPI ca_name ( chid pChan ) unsigned epicsShareAPI ca_search_attempts ( chid pChan ) { - epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); return pChan->io.searchAttempts ( guard ); } diff --git a/src/ca/client/sgAutoPtr.h b/src/ca/client/sgAutoPtr.h index b3753bb44..e2899468c 100644 --- a/src/ca/client/sgAutoPtr.h +++ b/src/ca/client/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,18 +37,16 @@ public: T * get (); T * release (); private: - tsDLList < syncGroupNotify > & list; T * pNotify; struct CASG & sg; epicsGuard < epicsMutex > & guard; - sgAutoPtr & operator = ( const sgAutoPtr & ); + sgAutoPtr & operator = ( const sgAutoPtr & ); }; 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/client/syncGroup.h b/src/ca/client/syncGroup.h index ab4d7b6df..3b9c3cd4f 100644 --- a/src/ca/client/syncGroup.h +++ b/src/ca/client/syncGroup.h @@ -5,24 +5,24 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* +/* + * * - * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 - * + * * Copyright, 1986, The Regents of the University of California. - * - * + * + * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 */ -#ifndef syncGrouph +#ifndef syncGrouph #define syncGrouph #ifdef epicsExportSharedSymbols @@ -46,152 +46,153 @@ 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 { -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; - virtual bool ioPending ( + virtual void destroy ( + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ) = 0; + virtual bool ioPending ( epicsGuard < epicsMutex > & guard ) = 0; virtual void cancel ( - epicsGuard < epicsMutex > & guard ) = 0; - virtual void show ( - epicsGuard < epicsMutex > &, + CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0; + virtual void show ( + epicsGuard < epicsMutex > &, unsigned level ) const = 0; protected: - virtual ~syncGroupNotify (); - syncGroupNotify ( const syncGroupNotify & ); - syncGroupNotify & operator = ( const syncGroupNotify & ); + virtual ~syncGroupNotify (); + syncGroupNotify ( const syncGroupNotify & ); + syncGroupNotify & operator = ( const syncGroupNotify & ); }; +struct CASG; + class syncGroupReadNotify : public syncGroupNotify, public cacReadNotify { public: - static syncGroupReadNotify * factory ( - tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &, - struct CASG &, chid, void *pValueIn ); - void destroy ( - epicsGuard < epicsMutex > & guard, - casgRecycle & ); - bool ioPending ( + typedef void ( CASG :: * PRecycleFunc ) + ( epicsGuard < epicsMutex > &, syncGroupReadNotify & ); + static syncGroupReadNotify * factory ( + tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &, + CASG &, PRecycleFunc, chid, void *pValueIn ); + void destroy ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); - void begin ( epicsGuard < epicsMutex > &, + 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 delete ( void * ); - void * operator new ( size_t, + void * operator new ( size_t, tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & )) void completion ( - epicsGuard < epicsMutex > &, unsigned type, + epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void * pData ); void exception ( - epicsGuard < epicsMutex > &, int status, + epicsGuard < epicsMutex > &, int status, const char * pContext, unsigned type, arrayElementCount count ); - syncGroupReadNotify ( const syncGroupReadNotify & ); - syncGroupReadNotify & operator = ( const syncGroupReadNotify & ); + syncGroupReadNotify ( const syncGroupReadNotify & ); + syncGroupReadNotify & operator = ( const syncGroupReadNotify & ); }; class syncGroupWriteNotify : public syncGroupNotify, public cacWriteNotify { public: - static syncGroupWriteNotify * factory ( - tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &, - struct CASG &, chid ); - void destroy ( - epicsGuard < epicsMutex > & guard, - casgRecycle & ); - bool ioPending ( + typedef void ( CASG :: * PRecycleFunc ) + ( epicsGuard < epicsMutex > &, syncGroupWriteNotify & ); + static syncGroupWriteNotify * factory ( + tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &, + CASG &, PRecycleFunc, chid ); + void destroy ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); - void begin ( epicsGuard < epicsMutex > &, unsigned type, + 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 delete ( void * ); - void * operator new ( size_t, + void * operator new ( size_t, tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & )) void completion ( epicsGuard < epicsMutex > & ); - void exception ( - epicsGuard < epicsMutex > &, int status, const char *pContext, + void exception ( + epicsGuard < epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count ); - syncGroupWriteNotify ( const syncGroupWriteNotify & ); - syncGroupWriteNotify & operator = ( const syncGroupWriteNotify & ); + syncGroupWriteNotify ( const syncGroupWriteNotify & ); + syncGroupWriteNotify & operator = ( const syncGroupWriteNotify & ); }; 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 ( + void destructor ( + CallbackGuard &, epicsGuard < epicsMutex > & guard ); - bool ioComplete ( + bool ioComplete ( + CallbackGuard &, epicsGuard < epicsMutex > & guard ); bool verify ( epicsGuard < epicsMutex > & ) const; - int block ( epicsGuard < epicsMutex > * pcbGuard, + 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, unsigned type, arrayElementCount count, void * pValue ); void put ( epicsGuard < epicsMutex > &, chid pChan, unsigned type, arrayElementCount count, const void * pValue ); - void completionNotify ( + void completionNotify ( epicsGuard < epicsMutex > &, syncGroupNotify & ); int printFormated ( const char * pFormat, ... ); - void exception ( - epicsGuard < epicsMutex > &, int status, const char * pContext, - const char * pFileName, unsigned lineNo ); - void exception ( + void exception ( epicsGuard < epicsMutex > &, int status, const char * pContext, - const char * pFileName, unsigned lineNo, oldChannelNotify & chan, + const char * pFileName, unsigned lineNo ); + void exception ( + epicsGuard < epicsMutex > &, int status, const char * pContext, + const char * pFileName, unsigned lineNo, oldChannelNotify & chan, unsigned type, arrayElementCount count, unsigned op ); - void * operator new ( size_t size, + void * operator new ( size_t size, tsFreeList < struct CASG, 128, epicsMutexNOOP > & ); - epicsPlacementDeleteOperator (( void *, + epicsPlacementDeleteOperator (( void *, tsFreeList < struct CASG, 128, epicsMutexNOOP > & )) + private: tsDLList < syncGroupNotify > ioPendingList; tsDLList < syncGroupNotify > ioCompletedList; @@ -200,18 +201,20 @@ 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 ( + void destroyPendingIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); - void destroyCompletedIO ( + void destroyCompletedIO ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ); + void recycleReadNotifyIO ( epicsGuard < epicsMutex > &, + syncGroupReadNotify & ); + void recycleWriteNotifyIO ( epicsGuard < epicsMutex > &, + syncGroupWriteNotify & ); - CASG ( const CASG & ); - CASG & operator = ( const CASG & ); + CASG ( const CASG & ); + CASG & operator = ( const CASG & ); void operator delete ( void * ); @@ -248,27 +251,27 @@ inline void boolFlagManager::release () this->pBool = 0; } -inline void * CASG::operator new ( size_t size, +inline void * CASG::operator new ( size_t size, tsFreeList < struct CASG, 128, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #if defined ( CXX_PLACEMENT_DELETE ) -inline void CASG::operator delete ( void * pCadaver, - tsFreeList < struct CASG, 128, epicsMutexNOOP > & freeList ) +inline void CASG::operator delete ( void * pCadaver, + tsFreeList < struct CASG, 128, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } #endif -inline bool syncGroupWriteNotify::ioPending ( +inline bool syncGroupWriteNotify::ioPending ( epicsGuard < epicsMutex > & /* guard */ ) { return ! this->ioComplete; } -inline bool syncGroupReadNotify::ioPending ( +inline bool syncGroupReadNotify::ioPending ( epicsGuard < epicsMutex > & /* guard */ ) { return ! this->ioComplete; diff --git a/src/ca/client/syncGroupReadNotify.cpp b/src/ca/client/syncGroupReadNotify.cpp index 5d2be25c6..711a2fae4 100644 --- a/src/ca/client/syncGroupReadNotify.cpp +++ b/src/ca/client/syncGroupReadNotify.cpp @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* @@ -26,16 +26,18 @@ #include "syncGroup.h" #include "oldAccess.h" -syncGroupReadNotify::syncGroupReadNotify ( - CASG & sgIn, chid pChan, void * pValueIn ) : - chan ( pChan ), sg ( sgIn ), pValue ( pValueIn ), - magic ( CASG_MAGIC ), id ( 0u ), +syncGroupReadNotify::syncGroupReadNotify ( + 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 ) { } -void syncGroupReadNotify::begin ( - epicsGuard < epicsMutex > & guard, +void syncGroupReadNotify::begin ( + epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count ) { this->chan->eliminateExcessiveSendBacklog ( guard ); @@ -45,28 +47,31 @@ void syncGroupReadNotify::begin ( mgr.release (); } -void syncGroupReadNotify::cancel ( - epicsGuard < epicsMutex > & guard ) +void syncGroupReadNotify::cancel ( + 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 ) +syncGroupReadNotify * syncGroupReadNotify::factory ( + tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & freeList, + struct CASG & sg, PRecycleFunc pRecycleFunc, chid chan, void * pValueIn ) { return new ( freeList ) - syncGroupReadNotify ( sg, chan, pValueIn ); + syncGroupReadNotify ( sg, pRecycleFunc, chan, pValueIn ); } -void syncGroupReadNotify::destroy ( - epicsGuard < epicsMutex > & guard, casgRecycle & recycle ) +void syncGroupReadNotify::destroy ( + CallbackGuard &, + epicsGuard < epicsMutex > & guard ) { + CASG & sgRef ( this->sg ); this->~syncGroupReadNotify (); - recycle.recycleSyncGroupReadNotify ( guard, *this ); + ( sgRef.*pRecycleFunc ) ( guard, *this ); } syncGroupReadNotify::~syncGroupReadNotify () @@ -75,11 +80,11 @@ syncGroupReadNotify::~syncGroupReadNotify () } void syncGroupReadNotify::completion ( - epicsGuard < epicsMutex > & guard, unsigned type, + epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, const void * pData ) { if ( this->magic != CASG_MAGIC ) { - this->sg.printFormated ( + this->sg.printFormated ( "cac: sync group io_complete(): bad sync grp op magic number?\n" ); return; } @@ -94,16 +99,16 @@ void syncGroupReadNotify::completion ( } void syncGroupReadNotify::exception ( - epicsGuard < epicsMutex > & guard, int status, const char * pContext, + epicsGuard < epicsMutex > & guard, int status, const char * pContext, unsigned type, arrayElementCount count ) { if ( this->magic != CASG_MAGIC ) { - this->sg.printFormated ( + this->sg.printFormated ( "cac: sync group io_complete(): bad sync grp op magic number?\n" ); return; } this->idIsValid = false; - this->sg.exception ( guard, status, pContext, + this->sg.exception ( guard, status, pContext, __FILE__, __LINE__, *this->chan, type, count, CA_OP_GET ); // // This notify is left installed at this point as a place holder indicating that @@ -112,7 +117,7 @@ void syncGroupReadNotify::exception ( // } -void syncGroupReadNotify::show ( +void syncGroupReadNotify::show ( epicsGuard < epicsMutex > &, unsigned level ) const { ::printf ( "pending sg read op: pVal=%p\n", this->pValue ); @@ -133,15 +138,15 @@ void syncGroupReadNotify::operator delete ( void * ) __FILE__, __LINE__ ); } -void * syncGroupReadNotify::operator new ( size_t size, +void * syncGroupReadNotify::operator new ( size_t size, tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #if defined ( CXX_PLACEMENT_DELETE ) -void syncGroupReadNotify::operator delete ( void *pCadaver, - tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &freeList ) +void syncGroupReadNotify::operator delete ( void *pCadaver, + tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &freeList ) { freeList.release ( pCadaver ); } diff --git a/src/ca/client/syncGroupWriteNotify.cpp b/src/ca/client/syncGroupWriteNotify.cpp index 7c0c582e9..f0bf42753 100644 --- a/src/ca/client/syncGroupWriteNotify.cpp +++ b/src/ca/client/syncGroupWriteNotify.cpp @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* @@ -26,45 +26,50 @@ #include "syncGroup.h" #include "oldAccess.h" -syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, chid pChan ) : - chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ), - id ( 0u ), idIsValid ( false ), ioComplete ( false ) +syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, + PRecycleFunc pRecycleFuncIn, chid pChan ) : + chan ( pChan ), pRecycleFunc ( pRecycleFuncIn ), + sg ( sgIn ), magic ( CASG_MAGIC ), + id ( 0u ), idIsValid ( false ), ioComplete ( false ) { } -void syncGroupWriteNotify::begin ( - epicsGuard < epicsMutex > & guard, unsigned type, +void syncGroupWriteNotify::begin ( + epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, const void * pValueIn ) { this->chan->eliminateExcessiveSendBacklog ( guard ); this->ioComplete = false; boolFlagManager mgr ( this->idIsValid ); - this->chan->write ( guard, type, count, + this->chan->write ( guard, type, count, pValueIn, *this, &this->id ); mgr.release (); } -void syncGroupWriteNotify::cancel ( - epicsGuard < epicsMutex > & guard ) +void syncGroupWriteNotify::cancel ( + 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 ) +syncGroupWriteNotify * syncGroupWriteNotify::factory ( + tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &freeList, + 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 ) +void syncGroupWriteNotify::destroy ( + CallbackGuard &, + epicsGuard < epicsMutex > & guard ) { + CASG & sgRef ( this->sg ); this->~syncGroupWriteNotify (); - recycle.recycleSyncGroupWriteNotify ( guard, *this ); + ( sgRef.*pRecycleFunc ) ( guard, *this ); } syncGroupWriteNotify::~syncGroupWriteNotify () @@ -72,7 +77,7 @@ syncGroupWriteNotify::~syncGroupWriteNotify () assert ( ! this->idIsValid ); } -void syncGroupWriteNotify::completion ( +void syncGroupWriteNotify::completion ( epicsGuard < epicsMutex > & guard ) { if ( this->magic != CASG_MAGIC ) { @@ -85,14 +90,14 @@ void syncGroupWriteNotify::completion ( } void syncGroupWriteNotify::exception ( - epicsGuard < epicsMutex > & guard, + epicsGuard < epicsMutex > & guard, int status, const char *pContext, unsigned type, arrayElementCount count ) { if ( this->magic != CASG_MAGIC ) { this->sg.printFormated ( "cac: sync group io_complete(): bad sync grp op magic number?\n" ); return; } - this->sg.exception ( guard, status, pContext, + this->sg.exception ( guard, status, pContext, __FILE__, __LINE__, *this->chan, type, count, CA_OP_PUT ); this->idIsValid = false; // @@ -102,7 +107,7 @@ void syncGroupWriteNotify::exception ( // } -void syncGroupWriteNotify::show ( +void syncGroupWriteNotify::show ( epicsGuard < epicsMutex > &, unsigned level ) const { ::printf ( "pending write sg op\n" ); @@ -123,15 +128,15 @@ void syncGroupWriteNotify::operator delete ( void * ) __FILE__, __LINE__ ); } -void * syncGroupWriteNotify::operator new ( size_t size, +void * syncGroupWriteNotify::operator new ( size_t size, tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } #if defined ( CXX_PLACEMENT_DELETE ) -void syncGroupWriteNotify::operator delete ( void *pCadaver, - tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &freeList ) +void syncGroupWriteNotify::operator delete ( void *pCadaver, + tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &freeList ) { freeList.release ( pCadaver ); } diff --git a/src/ca/client/syncgrp.cpp b/src/ca/client/syncgrp.cpp index 9b65c4f57..f11ce3551 100644 --- a/src/ca/client/syncgrp.cpp +++ b/src/ca/client/syncgrp.cpp @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* * Author: Jeffrey O. Hill @@ -48,6 +48,22 @@ extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) } } +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,42 +72,80 @@ 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 () // -// !!!! This routine is only visible in the old interface - or in a new ST interface. -// !!!! In the old interface we restrict thread attach so that calls from threads -// !!!! other than the initializing thread are not allowed if preemptive callback +// !!!! This routine is only visible in the old interface - or in a new ST interface. +// !!!! In the old interface we restrict thread attach so that calls from threads +// !!!! other than the initializing thread are not allowed if preemptive callback // !!!! is disabled. This prevents the preemptive callback lock from being released // !!!! by other threads than the one that locked it. // -extern "C" int epicsShareAPI ca_sg_block ( +extern "C" int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeout ) { ca_client_context *pcac; int status = fetchClientContext ( &pcac ); if ( status == ECA_NORMAL ) { - epicsGuard < epicsMutex > guard ( pcac->mutex ); - CASG * pcasg = pcac->lookupCASG ( guard, gid ); - if ( ! pcasg ) { - status = ECA_BADSYNCGRP; + CASG * pcasg; + { + epicsGuard < epicsMutex > guard ( pcac->mutex ); + pcasg = pcac->lookupCASG ( guard, gid ); + if ( pcasg ) { + status = pcasg->block ( + pcac->pCallbackGuard.get (), guard, timeout ); + } + else { + status = ECA_BADSYNCGRP; + } } - else { - status = pcasg->block ( - pcac->pCallbackGuard.get (), guard, timeout ); + 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 ) { - epicsGuard < epicsMutex > guard ( pcac->mutex ); - CASG * pcasg = pcac->lookupCASG ( guard, gid ); + CASG * pcasg; + { + epicsGuard < epicsMutex > guard ( pcac->mutex ); + pcasg = pcac->lookupCASG ( guard, gid ); + } if ( pcasg ) { - pcasg->reset ( guard ); + sync_group_reset ( *pcac, *pcasg ); + caStatus = ECA_NORMAL; } else { caStatus = ECA_BADSYNCGRP; @@ -151,7 +209,26 @@ extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) 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/ioc/db/dbCAC.h b/src/ioc/db/dbCAC.h index d4949e568..1a4086b4e 100644 --- a/src/ioc/db/dbCAC.h +++ b/src/ioc/db/dbCAC.h @@ -87,9 +87,9 @@ public: epicsGuard < epicsMutex > &, epicsMutex &, dbContext &, dbChannelIO &, struct dbChannel *, 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, @@ -165,7 +165,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 dbChannel * dbch, unsigned type, unsigned long count, cacReadNotify & notify ); @@ -182,9 +182,9 @@ public: cacWriteNotify & notify, cacChannel::ioid * pId ); void show ( unsigned level ) const; void showAllIO ( const dbChannelIO & chan, unsigned level ) const; - void destroyAllIO ( - epicsGuard < epicsMutex > &, dbChannelIO & chan ); - void ioCancel ( epicsGuard < epicsMutex > &, + void destroyAllIO ( CallbackGuard & cbGuard, + epicsGuard < epicsMutex > &, dbChannelIO & chan ); + 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/ioc/db/dbChannelIO.cpp b/src/ioc/db/dbChannelIO.cpp index bdf7e459f..4632ffb16 100644 --- a/src/ioc/db/dbChannelIO.cpp +++ b/src/ioc/db/dbChannelIO.cpp @@ -58,19 +58,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 ); dbChannelDelete ( this->dbch ); this->~dbChannelIO (); } void dbChannelIO::destroy ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); - this->serviceIO.destroyChannel ( guard, *this ); + this->serviceIO.destroyChannel ( cbGuard, guard, *this ); // don't access this pointer after above call because // object no longer exists } @@ -130,11 +132,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 ( diff --git a/src/ioc/db/dbChannelIO.h b/src/ioc/db/dbChannelIO.h index bdb92cc5b..372f809a3 100644 --- a/src/ioc/db/dbChannelIO.h +++ b/src/ioc/db/dbChannelIO.h @@ -48,8 +48,10 @@ public: epicsMutex &, cacChannelNotify &, dbChannel *, dbContext & ); void destructor ( + CallbackGuard &, epicsGuard < epicsMutex > & ); void destroy ( + CallbackGuard &, epicsGuard < epicsMutex > & mutualExclusionGuard ); void callReadNotify ( epicsGuard < epicsMutex > &, @@ -99,7 +101,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 > &, @@ -108,8 +111,8 @@ private: epicsGuard < epicsMutex > & ) const; unsigned long nativeElementCount ( epicsGuard < epicsMutex > & ) const; - dbChannelIO ( const dbChannelIO & ); - dbChannelIO & operator = ( const dbChannelIO & ); + dbChannelIO ( const dbChannelIO & ); + dbChannelIO & operator = ( const dbChannelIO & ); void operator delete ( void * ); }; diff --git a/src/ioc/db/dbContext.cpp b/src/ioc/db/dbContext.cpp index e337d698b..d005f084a 100644 --- a/src/ioc/db/dbContext.cpp +++ b/src/ioc/db/dbContext.cpp @@ -120,18 +120,20 @@ cacChannel & dbContext::createChannel ( } 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 ); } @@ -270,7 +272,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; @@ -287,24 +291,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 ); @@ -312,13 +316,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/ioc/db/dbPutNotifyBlocker.cpp b/src/ioc/db/dbPutNotifyBlocker.cpp index d2ffa2fa6..54cdec9fe 100644 --- a/src/ioc/db/dbPutNotifyBlocker.cpp +++ b/src/ioc/db/dbPutNotifyBlocker.cpp @@ -58,10 +58,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->pbuffer ); delete [] pBuf; @@ -70,6 +71,7 @@ void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard ) } void dbPutNotifyBlocker::cancel ( + CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); diff --git a/src/ioc/db/dbPutNotifyBlocker.h b/src/ioc/db/dbPutNotifyBlocker.h index e4d8e92ed..78acc0a13 100644 --- a/src/ioc/db/dbPutNotifyBlocker.h +++ b/src/ioc/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 dbChannel *, 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, diff --git a/src/ioc/db/dbSubscriptionIO.cpp b/src/ioc/db/dbSubscriptionIO.cpp index cfb4251bd..02b2b0105 100644 --- a/src/ioc/db/dbSubscriptionIO.cpp +++ b/src/ioc/db/dbSubscriptionIO.cpp @@ -66,14 +66,15 @@ 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 ( - epicsGuard < epicsMutex > & guard ) +void dbSubscriptionIO::unsubscribe ( CallbackGuard & cbGuard, + epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); if ( this->es ) { @@ -87,6 +88,7 @@ void dbSubscriptionIO::unsubscribe ( } void dbSubscriptionIO::channelDeleteException ( + CallbackGuard &, epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex );