fixed a bug where the callback control gaurd was used from a different thread
than the one that created it
This commit is contained in:
@@ -40,13 +40,12 @@ CASG::~CASG ()
|
||||
}
|
||||
|
||||
void CASG::destructor (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
|
||||
if ( this->verify ( guard ) ) {
|
||||
this->reset ( cbGuard, guard );
|
||||
this->reset ( guard );
|
||||
this->client.uninstallCASG ( guard, *this );
|
||||
this->magic = 0;
|
||||
}
|
||||
@@ -65,7 +64,7 @@ bool CASG::verify ( epicsGuard < epicsMutex > & ) const
|
||||
* CASG::block ()
|
||||
*/
|
||||
int CASG::block (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > * pcbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
double timeout )
|
||||
{
|
||||
@@ -110,9 +109,15 @@ int CASG::block (
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
if ( pcbGuard ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > uncbGuard ( *pcbGuard );
|
||||
this->sem.wait ( remaining );
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
epicsGuardRelease < epicsMutex > uncbGuard ( cbGuard );
|
||||
this->sem.wait ( remaining );
|
||||
}
|
||||
|
||||
@@ -124,18 +129,17 @@ int CASG::block (
|
||||
delay = cur_time - beg_time;
|
||||
}
|
||||
|
||||
this->reset ( cbGuard, guard );
|
||||
this->reset ( guard );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void CASG::reset (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->destroyCompletedIO ( guard );
|
||||
this->destroyPendingIO ( cbGuard, guard );
|
||||
this->destroyPendingIO ( guard );
|
||||
}
|
||||
|
||||
// lock must be applied
|
||||
@@ -150,13 +154,11 @@ void CASG::destroyCompletedIO (
|
||||
}
|
||||
|
||||
void CASG::destroyPendingIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
syncGroupNotify * pNotify;
|
||||
while ( ( pNotify = this->ioPendingList.first () ) ) {
|
||||
pNotify->cancel ( cbGuard, guard );
|
||||
while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) {
|
||||
pNotify->cancel ( guard );
|
||||
// cancel must release the guard while
|
||||
// canceling put callbacks so we
|
||||
// must double check list membership
|
||||
@@ -201,7 +203,6 @@ void CASG::show (
|
||||
}
|
||||
|
||||
bool CASG::ioComplete (
|
||||
epicsGuard < epicsMutex > & /* cbGuard */,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
|
||||
@@ -364,16 +364,15 @@ int epicsShareAPI ca_create_channel (
|
||||
int epicsShareAPI ca_clear_channel ( chid pChan )
|
||||
{
|
||||
ca_client_context & cac = pChan->getClientCtx ();
|
||||
epicsGuard < epicsMutex > * pCBGuard = cac.pCallbackGuard.get();
|
||||
if ( pCBGuard ) {
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
cac.destroyChannel ( *pCBGuard, guard, *pChan );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
try {
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
}
|
||||
else {
|
||||
epicsGuard < epicsMutex > cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
cac.destroyChannel ( cbGuard, guard, *pChan );
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored
|
||||
}
|
||||
pChan->destructor ( guard );
|
||||
cac.oldChannelNotifyFreeList.release ( pChan );
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ epicsShareDef epicsThreadPrivateId caClientCallbackThreadId;
|
||||
|
||||
static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
const unsigned ca_client_context :: flushBlockThreshold = 0x58000;
|
||||
|
||||
extern "C" void cacExitHandler ( void *)
|
||||
{
|
||||
epicsThreadPrivateDelete ( caClientCallbackThreadId );
|
||||
@@ -65,6 +67,7 @@ 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 ),
|
||||
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ),
|
||||
pndRecvCnt ( 0u ), ioSeqNo ( 0u ), callbackThreadsPending ( 0u ),
|
||||
@@ -189,22 +192,6 @@ ca_client_context::~ca_client_context ()
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::destroyChannel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
oldChannelNotify & chan )
|
||||
{
|
||||
try {
|
||||
chan.eliminateExcessiveSendBacklog (
|
||||
&cbGuard, guard );
|
||||
}
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored
|
||||
}
|
||||
chan.destructor ( cbGuard, guard );
|
||||
this->oldChannelNotifyFreeList.release ( & chan );
|
||||
}
|
||||
|
||||
void ca_client_context::destroyGetCopy (
|
||||
epicsGuard < epicsMutex > & guard, getCopy & gc )
|
||||
{
|
||||
@@ -663,7 +650,7 @@ void ca_client_context::callbackProcessingCompleteNotify ()
|
||||
|
||||
cacChannel & ca_client_context::createChannel (
|
||||
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
||||
oldChannelNotify & chan, cacChannel::priLev pri )
|
||||
cacChannelNotify & chan, cacChannel::priLev pri )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->pServiceContext->createChannel (
|
||||
@@ -753,32 +740,41 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
|
||||
{
|
||||
oldChannelNotify & chan = pMon->channel ();
|
||||
ca_client_context & cac = chan.getClientCtx ();
|
||||
epicsGuard < epicsMutex > * pCBGuard = cac.pCallbackGuard.get();
|
||||
if ( pCBGuard ) {
|
||||
cac.clearSubscriptionPrivate ( *pCBGuard, *pMon );
|
||||
}
|
||||
else {
|
||||
epicsGuard < epicsMutex > cbGuard ( cac.cbMutex );
|
||||
cac.clearSubscriptionPrivate ( cbGuard, *pMon );
|
||||
}
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
void ca_client_context::clearSubscriptionPrivate (
|
||||
epicsGuard < epicsMutex > & cbGuard, oldSubscription & subscr )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
oldChannelNotify & chan = subscr.channel ();
|
||||
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 (
|
||||
& cbGuard, guard );
|
||||
chan.eliminateExcessiveSendBacklog ( guard );
|
||||
}
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored
|
||||
}
|
||||
subscr.cancel ( cbGuard, guard );
|
||||
pMon->cancel ( guard );
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
void ca_client_context :: eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & guard, cacChannel & chan )
|
||||
{
|
||||
if ( chan.requestMessageBytesPending ( guard ) >
|
||||
ca_client_context :: flushBlockThreshold ) {
|
||||
if ( this->pCallbackGuard.get() &&
|
||||
this->createdByThread == epicsThreadGetIdSelf () ) {
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
chan.flush ( guard );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,15 +497,15 @@ void cac::transferChanToVirtCircuit (
|
||||
if ( ! sockAddrAreIdentical ( &addr, &chanAddr ) ) {
|
||||
char acc[64];
|
||||
pChan->getPIIU(guard)->getHostName ( guard, acc, sizeof ( acc ) );
|
||||
msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList )
|
||||
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
|
||||
// hierarchy inversion.
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList )
|
||||
msgForMultiplyDefinedPV ( this->ipToAEngine,
|
||||
*this, pChan->pName ( guard ), acc );
|
||||
pMsg->ioInitiate ( addr );
|
||||
}
|
||||
return;
|
||||
@@ -566,19 +566,16 @@ void cac::transferChanToVirtCircuit (
|
||||
}
|
||||
|
||||
void cac::destroyChannel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
nciu & chan )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
cbGuard.assertIdenticalMutex ( this->cbMutex );
|
||||
|
||||
// uninstall channel so that recv threads
|
||||
// will not start a new callback for this channel's IO.
|
||||
if ( this->chanTable.remove ( chan ) != & chan ) {
|
||||
throw std::logic_error ( "Invalid channel identifier" );
|
||||
}
|
||||
|
||||
chan.~nciu ();
|
||||
this->channelFreeList.release ( & chan );
|
||||
}
|
||||
@@ -642,12 +639,10 @@ netReadNotifyIO & cac::readNotifyRequest (
|
||||
return *pIO.release();
|
||||
}
|
||||
|
||||
baseNMIU * cac::destroyIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
bool cac::destroyIO (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid & idIn, nciu & chan )
|
||||
{
|
||||
cbGuard.assertIdenticalMutex ( this->cbMutex );
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
baseNMIU * pIO = this->ioTable.remove ( idIn );
|
||||
@@ -660,8 +655,9 @@ baseNMIU * cac::destroyIO (
|
||||
// this uninstalls from the list and destroys the IO
|
||||
pIO->exception ( guard, *this,
|
||||
ECA_CHANDESTROY, chan.pName ( guard ) );
|
||||
return true;
|
||||
}
|
||||
return pIO;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cac::ioShow (
|
||||
|
||||
@@ -135,9 +135,7 @@ public:
|
||||
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
||||
cacChannelNotify &, cacChannel::priLev );
|
||||
void destroyChannel (
|
||||
epicsGuard < epicsMutex > & callbackControlGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
nciu & );
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void initiateConnect (
|
||||
epicsGuard < epicsMutex > &, nciu &, netiiu * & );
|
||||
nciu * lookupChannel (
|
||||
@@ -156,8 +154,7 @@ public:
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem, unsigned mask,
|
||||
cacStateNotify &, bool channelIsInstalled );
|
||||
baseNMIU * destroyIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
bool destroyIO (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid & idIn,
|
||||
nciu & chan );
|
||||
|
||||
@@ -64,25 +64,28 @@ void getCopy::completion (
|
||||
unsigned size = dbr_size_n ( typeIn, countIn );
|
||||
memcpy ( this->pValue, pDataIn, size );
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
}
|
||||
else {
|
||||
this->exception ( guard, ECA_INTERNAL,
|
||||
"bad data type match in get copy back response",
|
||||
typeIn, countIn);
|
||||
}
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
}
|
||||
|
||||
void getCopy::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char *pContext, unsigned /* typeIn */, arrayElementCount /* countIn */ )
|
||||
{
|
||||
oldChannelNotify & chanTmp ( this->chan );
|
||||
unsigned typeTmp ( this->type );
|
||||
arrayElementCount countTmp ( this->count );
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
this->cacCtx.exception ( guard, status, pContext,
|
||||
__FILE__, __LINE__, this->chan, this->type,
|
||||
this->count, CA_OP_GET );
|
||||
__FILE__, __LINE__, chanTmp, typeTmp,
|
||||
countTmp, CA_OP_GET );
|
||||
}
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
}
|
||||
|
||||
void getCopy::show ( unsigned level ) const
|
||||
|
||||
@@ -76,27 +76,22 @@ nciu::~nciu ()
|
||||
// channels are created by the user, and only destroyed by the user
|
||||
// using this routine
|
||||
void nciu::destroy (
|
||||
epicsGuard < epicsMutex > & callbackControlGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
while ( baseNMIU * pNetIO = this->eventq.first () ) {
|
||||
assert ( this->cacCtx.destroyIO (
|
||||
callbackControlGuard, mutualExclusionGuard,
|
||||
pNetIO->getId (), *this ) );
|
||||
guard, pNetIO->getId (), *this ) );
|
||||
}
|
||||
|
||||
|
||||
// if the claim reply has not returned yet then we will issue
|
||||
// the clear channel request to the server when the claim reply
|
||||
// arrives and there is no matching nciu in the client
|
||||
if ( this->channelNode::isInstalledInServer ( mutualExclusionGuard ) ) {
|
||||
this->getPIIU(mutualExclusionGuard)->clearChannelRequest (
|
||||
mutualExclusionGuard, this->sid, this->id );
|
||||
if ( this->channelNode::isInstalledInServer ( guard ) ) {
|
||||
this->getPIIU(guard)->clearChannelRequest (
|
||||
guard, this->sid, this->id );
|
||||
}
|
||||
|
||||
this->piiu->uninstallChan ( mutualExclusionGuard, *this );
|
||||
|
||||
this->cacCtx.destroyChannel (
|
||||
callbackControlGuard, mutualExclusionGuard, *this );
|
||||
this->piiu->uninstallChan ( guard, *this );
|
||||
this->cacCtx.destroyChannel ( guard, *this );
|
||||
}
|
||||
|
||||
void * nciu::operator new ( size_t ) // X aCC 361
|
||||
@@ -268,12 +263,16 @@ unsigned nciu::nameLen (
|
||||
return this->nameLength;
|
||||
}
|
||||
|
||||
void nciu::eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > * pCallbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
unsigned nciu::requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->piiu->eliminateExcessiveSendBacklog (
|
||||
pCallbackGuard, mutualExclusionGuard );
|
||||
return piiu->requestMessageBytesPending ( guard );
|
||||
}
|
||||
|
||||
void nciu::flush (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
piiu->flush ( guard );
|
||||
}
|
||||
|
||||
cacChannel::ioStatus nciu::read (
|
||||
@@ -391,10 +390,9 @@ void nciu::subscribe (
|
||||
}
|
||||
|
||||
void nciu::ioCancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard, const ioid & idIn )
|
||||
{
|
||||
this->cacCtx.destroyIO ( cbGuard, guard, idIn, *this );
|
||||
this->cacCtx.destroyIO ( guard, idIn, *this );
|
||||
}
|
||||
|
||||
void nciu::ioShow (
|
||||
@@ -577,7 +575,7 @@ void nciu::serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
{
|
||||
this->setServerAddressUnknown ( noopIIU, mutualExclusionGuard );
|
||||
this->notify().serviceShutdownNotify ( callbackControlGuard, mutualExclusionGuard );
|
||||
this->notify().serviceShutdownNotify ( mutualExclusionGuard );
|
||||
}
|
||||
|
||||
void channelNode::setRespPendingState (
|
||||
|
||||
@@ -46,14 +46,13 @@
|
||||
#include "cadef.h"
|
||||
#include "syncGroup.h"
|
||||
|
||||
struct oldChannelNotify : public cacChannelNotify {
|
||||
struct oldChannelNotify : private cacChannelNotify {
|
||||
public:
|
||||
oldChannelNotify (
|
||||
epicsGuard < epicsMutex > &, struct ca_client_context &,
|
||||
const char * pName, caCh * pConnCallBackIn,
|
||||
void * pPrivateIn, capri priority );
|
||||
void destructor (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
|
||||
// legacy C API
|
||||
@@ -114,9 +113,6 @@ public:
|
||||
unsigned level ) const;
|
||||
void initiateConnect (
|
||||
epicsGuard < epicsMutex > & );
|
||||
void eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > * pCallbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void read (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
@@ -126,13 +122,15 @@ public:
|
||||
unsigned type, arrayElementCount count, const void *pValue,
|
||||
cacWriteNotify &, cacChannel::ioid *pId = 0 );
|
||||
void ioCancel (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const cacChannel::ioid & );
|
||||
void ioShow (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid &, unsigned level ) const;
|
||||
ca_client_context & getClientCtx ();
|
||||
void eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & );
|
||||
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void * ,
|
||||
@@ -151,7 +149,6 @@ private:
|
||||
void connectNotify ( epicsGuard < epicsMutex > & );
|
||||
void disconnectNotify ( epicsGuard < epicsMutex > & );
|
||||
void serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & callbackControlGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void accessRightsNotify (
|
||||
epicsGuard < epicsMutex > &, const caAccessRights & );
|
||||
@@ -263,7 +260,6 @@ public:
|
||||
~oldSubscription ();
|
||||
oldChannelNotify & channel () const;
|
||||
void cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & );
|
||||
@@ -301,10 +297,10 @@ public:
|
||||
void replaceErrLogHandler ( caPrintfFunc * ca_printf_func );
|
||||
cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > &, const char * pChannelName,
|
||||
oldChannelNotify &, cacChannel::priLev pri );
|
||||
cacChannelNotify &, cacChannel::priLev pri );
|
||||
void flush ( epicsGuard < epicsMutex > & );
|
||||
void eliminateExcessiveSendBacklog (
|
||||
oldChannelNotify & chan, epicsGuard < epicsMutex > & guard );
|
||||
epicsGuard < epicsMutex > &, cacChannel & );
|
||||
int pendIO ( const double & timeout );
|
||||
int pendEvent ( const double & timeout );
|
||||
bool ioComplete () const;
|
||||
@@ -339,14 +335,14 @@ public:
|
||||
void vSignal ( int ca_status, const char * pfilenm,
|
||||
int lineno, const char *pFormat, va_list args );
|
||||
bool preemptiveCallbakIsEnabled () const;
|
||||
void destroyChannel ( epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard, oldChannelNotify & chan );
|
||||
void destroyGetCopy ( epicsGuard < epicsMutex > &, getCopy & );
|
||||
void destroyGetCallback ( epicsGuard < epicsMutex > &, getCallback & );
|
||||
void destroyPutCallback ( epicsGuard < epicsMutex > &, putCallback & );
|
||||
void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & );
|
||||
epicsMutex & mutexRef () const;
|
||||
|
||||
|
||||
// legacy C API
|
||||
friend int epicsShareAPI ca_create_channel (
|
||||
const char * name_str, caCh * conn_func, void * puser,
|
||||
capri priority, chid * chanptr );
|
||||
@@ -365,8 +361,6 @@ public:
|
||||
chtype type, arrayElementCount count, chid pChan,
|
||||
long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg,
|
||||
evid *monixptr );
|
||||
|
||||
// legacy C API
|
||||
friend int epicsShareAPI ca_flush_io ();
|
||||
friend int epicsShareAPI ca_clear_subscription ( evid pMon );
|
||||
friend int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid );
|
||||
@@ -389,6 +383,7 @@ private:
|
||||
mutable epicsMutex cbMutex;
|
||||
epicsEvent ioDone;
|
||||
epicsEvent callbackThreadActivityComplete;
|
||||
epicsThreadId createdByThread;
|
||||
epics_auto_ptr < epicsGuard < epicsMutex > > pCallbackGuard;
|
||||
epics_auto_ptr < cacContext > pServiceContext;
|
||||
caExceptionHandler * ca_exception_func;
|
||||
@@ -409,8 +404,6 @@ private:
|
||||
void callbackProcessingCompleteNotify ();
|
||||
cacContext & createNetworkContext (
|
||||
epicsMutex & mutualExclusion, epicsMutex & callbackControl );
|
||||
void clearSubscriptionPrivate (
|
||||
epicsGuard < epicsMutex > & cbGuard, oldSubscription & subscr );
|
||||
|
||||
ca_client_context ( const ca_client_context & );
|
||||
ca_client_context & operator = ( const ca_client_context & );
|
||||
@@ -419,6 +412,7 @@ private:
|
||||
friend void cacExitHandler ( void *);
|
||||
static cacService * pDefaultService;
|
||||
static epicsMutex * pDefaultServiceInstallMutex;
|
||||
static const unsigned flushBlockThreshold;
|
||||
};
|
||||
|
||||
int fetchClientContext ( ca_client_context * * ppcac );
|
||||
@@ -448,20 +442,11 @@ inline void oldChannelNotify::initiateConnect (
|
||||
this->io.initiateConnect ( guard );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > * pCallbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
{
|
||||
this->io.eliminateExcessiveSendBacklog (
|
||||
pCallbackGuard, mutualExclusionGuard );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::ioCancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid & id )
|
||||
{
|
||||
this->io.ioCancel ( cbGuard, guard, id );
|
||||
this->io.ioCancel ( guard, id );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::ioShow (
|
||||
@@ -471,6 +456,12 @@ inline void oldChannelNotify::ioShow (
|
||||
this->io.ioShow ( guard, id, level );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->cacCtx.eliminateExcessiveSendBacklog ( guard, this->io );
|
||||
}
|
||||
|
||||
inline void * oldChannelNotify::operator new ( size_t size,
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
@@ -500,10 +491,9 @@ inline void oldSubscription::operator delete ( void *pCadaver,
|
||||
#endif
|
||||
|
||||
inline void oldSubscription::cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->chan.ioCancel ( cbGuard, guard, this->id );
|
||||
this->chan.ioCancel ( guard, this->id );
|
||||
}
|
||||
|
||||
inline oldChannelNotify & oldSubscription::channel () const
|
||||
@@ -569,12 +559,5 @@ inline unsigned ca_client_context::sequenceNumberOfOutstandingIO (
|
||||
// perhaps on SMP systems THERE should be lock/unlock around this
|
||||
return this->ioSeqNo;
|
||||
}
|
||||
|
||||
inline void ca_client_context::eliminateExcessiveSendBacklog (
|
||||
oldChannelNotify & chan, epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
chan.eliminateExcessiveSendBacklog (
|
||||
this->pCallbackGuard.get(), guard );
|
||||
}
|
||||
|
||||
#endif // ifndef oldAccessh
|
||||
|
||||
@@ -65,11 +65,10 @@ oldChannelNotify::~oldChannelNotify ()
|
||||
}
|
||||
|
||||
void oldChannelNotify::destructor (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
this->io.destroy ( cbGuard, guard );
|
||||
this->io.destroy ( guard );
|
||||
// no need to worry about a connect preempting here because
|
||||
// the io (the nciu) has been destroyed above
|
||||
if ( this->pConnCallBack == 0 && ! this->currentlyConnected ) {
|
||||
@@ -119,13 +118,9 @@ void oldChannelNotify::disconnectNotify (
|
||||
}
|
||||
|
||||
void oldChannelNotify::serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & callbackControlGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->cacCtx.destroyChannel (
|
||||
callbackControlGuard,
|
||||
mutualExclusionGuard,
|
||||
*this );
|
||||
this->disconnectNotify ( guard );
|
||||
}
|
||||
|
||||
void oldChannelNotify::accessRightsNotify (
|
||||
@@ -287,8 +282,7 @@ int epicsShareAPI ca_array_get ( chtype type,
|
||||
}
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog (
|
||||
pChan->getClientCtx().pCallbackGuard.get(), guard );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
autoPtrFreeList < getCopy, 0x400, epicsMutexNOOP > pNotify
|
||||
( pChan->getClientCtx().getCopyFreeList,
|
||||
new ( pChan->getClientCtx().getCopyFreeList )
|
||||
@@ -355,8 +349,7 @@ int epicsShareAPI ca_array_get_callback ( chtype type,
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog (
|
||||
pChan->getClientCtx().pCallbackGuard.get(), guard );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
autoPtrFreeList < getCallback, 0x400, epicsMutexNOOP > pNotify
|
||||
( pChan->getClientCtx().getCallbackFreeList,
|
||||
new ( pChan->getClientCtx().getCallbackFreeList )
|
||||
@@ -427,8 +420,7 @@ int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count,
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog (
|
||||
pChan->getClientCtx().pCallbackGuard.get(), guard );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
autoPtrFreeList < putCallback, 0x400, epicsMutexNOOP > pNotify
|
||||
( pChan->getClientCtx().putCallbackFreeList,
|
||||
@@ -491,8 +483,7 @@ int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count,
|
||||
int caStatus;
|
||||
try {
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog (
|
||||
pChan->getClientCtx().pCallbackGuard.get(), guard );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
pChan->io.write ( guard, tmpType, count, pValue );
|
||||
caStatus = ECA_NORMAL;
|
||||
}
|
||||
@@ -569,8 +560,7 @@ int epicsShareAPI ca_create_subscription (
|
||||
// can be forthcoming which we must ignore (this is a
|
||||
// special case preserving legacy ca_create_subscription
|
||||
// behavior)
|
||||
pChan->eliminateExcessiveSendBacklog (
|
||||
pChan->getClientCtx().pCallbackGuard.get(), guard );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
}
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored (its ok to subscribe when not connected)
|
||||
|
||||
@@ -68,7 +68,6 @@ public:
|
||||
virtual bool ioPending (
|
||||
epicsGuard < epicsMutex > & guard ) = 0;
|
||||
virtual void cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard ) = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
@@ -92,7 +91,6 @@ public:
|
||||
void begin ( epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count );
|
||||
void cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
protected:
|
||||
@@ -135,7 +133,6 @@ public:
|
||||
void begin ( epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void * pValueIn );
|
||||
void cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
protected:
|
||||
@@ -170,16 +167,13 @@ struct CASG : public chronIntIdRes < CASG >, private casgRecycle {
|
||||
public:
|
||||
CASG ( epicsGuard < epicsMutex > &, ca_client_context & cacIn );
|
||||
void destructor (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
bool ioComplete (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
bool verify ( epicsGuard < epicsMutex > & ) const;
|
||||
int block ( epicsGuard < epicsMutex > & cbGuard,
|
||||
int block ( epicsGuard < epicsMutex > * pcbGuard,
|
||||
epicsGuard < epicsMutex > & guard, double timeout );
|
||||
void reset ( epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void reset ( epicsGuard < epicsMutex > & guard );
|
||||
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
void show ( unsigned level ) const;
|
||||
void get ( epicsGuard < epicsMutex > &, chid pChan,
|
||||
@@ -214,7 +208,6 @@ private:
|
||||
epicsGuard < epicsMutex > &, syncGroupReadNotify & io );
|
||||
|
||||
void destroyPendingIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void destroyCompletedIO (
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
|
||||
@@ -38,8 +38,7 @@ void syncGroupReadNotify::begin (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
this->chan->getClientCtx().
|
||||
eliminateExcessiveSendBacklog ( *this->chan, guard );
|
||||
this->chan->eliminateExcessiveSendBacklog ( guard );
|
||||
this->ioComplete = false;
|
||||
boolFlagManager mgr ( this->idIsValid );
|
||||
this->chan->read ( guard, type, count, *this, &this->id );
|
||||
@@ -47,11 +46,10 @@ void syncGroupReadNotify::begin (
|
||||
}
|
||||
|
||||
void syncGroupReadNotify::cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
if ( this->idIsValid ) {
|
||||
this->chan->ioCancel ( cbGuard, guard, this->id );
|
||||
this->chan->ioCancel ( guard, this->id );
|
||||
this->idIsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,7 @@ void syncGroupWriteNotify::begin (
|
||||
epicsGuard < epicsMutex > & guard, unsigned type,
|
||||
arrayElementCount count, const void * pValueIn )
|
||||
{
|
||||
this->chan->getClientCtx().eliminateExcessiveSendBacklog (
|
||||
*this->chan, guard );
|
||||
this->chan->eliminateExcessiveSendBacklog ( guard );
|
||||
this->ioComplete = false;
|
||||
boolFlagManager mgr ( this->idIsValid );
|
||||
this->chan->write ( guard, type, count,
|
||||
@@ -46,11 +45,10 @@ void syncGroupWriteNotify::begin (
|
||||
}
|
||||
|
||||
void syncGroupWriteNotify::cancel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
if ( this->idIsValid ) {
|
||||
this->chan->ioCancel ( cbGuard, guard, this->id );
|
||||
this->chan->ioCancel ( guard, this->id );
|
||||
this->idIsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user