keep circuit open with disconnected channels attached if the circuit
becomes unresponsive
This commit is contained in:
@@ -602,8 +602,8 @@ bool cac::transferChanToVirtCircuit (
|
||||
}
|
||||
}
|
||||
|
||||
this->pudpiiu->uninstallChan ( guard, *pChan );
|
||||
piiu->installChannel ( guard, *pChan, sid, typeCode, count );
|
||||
this->pudpiiu->uninstallChan ( cbGuard, guard, *pChan );
|
||||
piiu->installChannel ( cbGuard, guard, *pChan, sid, typeCode, count );
|
||||
|
||||
if ( ! piiu->ca_v42_ok () ) {
|
||||
// connect to old server with lock applied
|
||||
@@ -697,7 +697,7 @@ void cac::destroyChannel ( nciu & chan )
|
||||
// o chan destroy exception has been delivered
|
||||
{
|
||||
epicsGuard < cacMutex > guard ( this->mutex );
|
||||
chan.getPIIU()->uninstallChan ( guard, chan );
|
||||
chan.getPIIU()->uninstallChan ( cbGuard, guard, chan );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1370,9 +1370,9 @@ void cac::disconnectChannel (
|
||||
{
|
||||
assert ( this->pudpiiu );
|
||||
this->disconnectAllIO ( guard, chan, true );
|
||||
chan.getPIIU()->uninstallChan ( guard, chan );
|
||||
chan.disconnect ( *this->pudpiiu, cbGuard, guard );
|
||||
chan.getPIIU()->uninstallChan ( cbGuard, guard, chan );
|
||||
this->pudpiiu->installDisconnectedChannel ( currentTime, chan );
|
||||
chan.circuitHangupNotify ( *this->pudpiiu, cbGuard, guard );
|
||||
}
|
||||
|
||||
bool cac::badTCPRespAction ( epicsGuard < callbackMutex > &, tcpiiu & iiu,
|
||||
@@ -1472,17 +1472,23 @@ void cac::disconnectNotify ( tcpiiu & iiu )
|
||||
iiu.disconnectNotify ( guard );
|
||||
}
|
||||
|
||||
void cac::unresponsiveCircuitNotify ( tcpiiu & iiu )
|
||||
{
|
||||
epicsGuard < callbackMutex > cbGuard ( this->cbMutex );
|
||||
epicsGuard < cacMutex > guard ( this->mutex );
|
||||
iiu.unresponsiveCircuitNotify ( cbGuard, guard );
|
||||
}
|
||||
|
||||
void cac::initiateAbortShutdown ( tcpiiu & iiu )
|
||||
{
|
||||
int exception = ECA_DISCONN;
|
||||
char hostNameTmp[64];
|
||||
bool exceptionNeeded = false;
|
||||
epicsGuard < callbackMutex > cbGuard ( this->cbMutex );
|
||||
|
||||
{
|
||||
epicsGuard < cacMutex > guard ( this->mutex );
|
||||
|
||||
if ( iiu.channelCount() ) {
|
||||
if ( iiu.channelCount( cbGuard ) ) {
|
||||
iiu.hostName ( hostNameTmp, sizeof ( hostNameTmp ) );
|
||||
if ( iiu.connecting () ) {
|
||||
exception = ECA_CONNSEQTMO;
|
||||
@@ -1509,7 +1515,7 @@ void cac::destroyIIU ( tcpiiu & iiu )
|
||||
{
|
||||
epicsGuard < callbackMutex > cbGuard ( this->cbMutex );
|
||||
epicsGuard < cacMutex > guard ( this->mutex );
|
||||
if ( iiu.channelCount() ) {
|
||||
if ( iiu.channelCount ( cbGuard ) ) {
|
||||
char hostNameTmp[64];
|
||||
iiu.hostName ( hostNameTmp, sizeof ( hostNameTmp ) );
|
||||
genLocalExcep ( cbGuard, *this, ECA_DISCONN, hostNameTmp );
|
||||
|
||||
@@ -55,7 +55,8 @@ nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn,
|
||||
typeCode ( USHRT_MAX ),
|
||||
priority ( static_cast <ca_uint8_t> ( pri ) ),
|
||||
f_connected ( false ),
|
||||
f_claimSent ( false )
|
||||
f_createChanReqSent ( false ),
|
||||
f_createChanRespReceived ( false )
|
||||
{
|
||||
size_t nameLengthTmp = strlen ( pNameIn ) + 1;
|
||||
|
||||
@@ -113,16 +114,16 @@ void nciu::connect ( unsigned nativeType,
|
||||
epicsGuard < callbackMutex > & cbGuard,
|
||||
epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
if ( ! this->f_claimSent ) {
|
||||
if ( ! this->f_createChanReqSent ) {
|
||||
this->cacCtx.printf (
|
||||
"CAC: Ignored conn resp to chan lacking virtual circuit CID=%u SID=%u?\n",
|
||||
this->getId (), sidIn );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this->f_connected ) {
|
||||
if ( this->f_createChanRespReceived ) {
|
||||
this->cacCtx.printf (
|
||||
"CAC: Ignored conn resp to conn chan CID=%u SID=%u?\n",
|
||||
"CAC: Ignored create channel resp to conn chan CID=%u SID=%u?\n",
|
||||
this->getId (), sidIn );
|
||||
return;
|
||||
}
|
||||
@@ -138,6 +139,7 @@ void nciu::connect ( unsigned nativeType,
|
||||
this->count = nativeCount;
|
||||
this->sid = sidIn;
|
||||
this->f_connected = true;
|
||||
this->f_createChanRespReceived = true;
|
||||
|
||||
/*
|
||||
* if less than v4.1 then the server will never
|
||||
@@ -156,16 +158,6 @@ void nciu::connect ( unsigned nativeType,
|
||||
{
|
||||
epicsGuardRelease < cacMutex > unguard ( guard );
|
||||
|
||||
// channel uninstal routine grabs the callback lock so
|
||||
// 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
|
||||
// code below - ie we hold the callback lock here
|
||||
// so a chanel cant be destroyed out from under us.
|
||||
this->notify().connectNotify ();
|
||||
|
||||
/*
|
||||
* if less than v4.1 then the server will never
|
||||
* send access rights and we know that there
|
||||
@@ -175,14 +167,47 @@ void nciu::connect ( unsigned nativeType,
|
||||
if ( ! v41Ok ) {
|
||||
this->notify().accessRightsNotify ( this->accessRightState );
|
||||
}
|
||||
|
||||
// channel uninstal routine grabs the callback lock so
|
||||
// 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
|
||||
// code below - ie we hold the callback lock here
|
||||
// so a chanel cant be destroyed out from under us.
|
||||
this->notify().connectNotify ();
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::disconnect (
|
||||
netiiu & newiiu, epicsGuard < callbackMutex > & cbGuard,
|
||||
void nciu::unresponsiveCircuitNotify (
|
||||
epicsGuard < callbackMutex > & cbGuard,
|
||||
epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
bool currentlyConnected = this->f_connected;
|
||||
if ( this->f_connected ) {
|
||||
this->f_connected = false;
|
||||
epicsGuardRelease < cacMutex > autoMutexRelease ( guard );
|
||||
this->notify().disconnectNotify ();
|
||||
caAccessRights noRights;
|
||||
this->notify().accessRightsNotify ( noRights );
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::responsiveCircuitNotify (
|
||||
epicsGuard < callbackMutex > & cbGuard,
|
||||
epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
if ( ! this->f_connected ) {
|
||||
this->f_connected = true;
|
||||
epicsGuardRelease < cacMutex > autoMutexRelease ( guard );
|
||||
this->notify().connectNotify ();
|
||||
this->notify().accessRightsNotify ( this->accessRightState );
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::circuitHangupNotify ( class udpiiu & newiiu,
|
||||
epicsGuard < callbackMutex > & cbGuard, epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
this->piiu = & newiiu;
|
||||
this->retry = disconnectRetrySetpoint;
|
||||
this->typeCode = USHRT_MAX;
|
||||
@@ -190,9 +215,10 @@ void nciu::disconnect (
|
||||
this->sid = UINT_MAX;
|
||||
this->accessRightState.clrReadPermit();
|
||||
this->accessRightState.clrWritePermit();
|
||||
this->f_claimSent = false;
|
||||
this->f_connected = false;
|
||||
if ( currentlyConnected ) {
|
||||
this->f_createChanReqSent = false;
|
||||
this->f_createChanRespReceived = false;
|
||||
if ( this->f_connected ) {
|
||||
this->f_connected = false;
|
||||
epicsGuardRelease < cacMutex > autoMutexRelease ( guard );
|
||||
this->notify().disconnectNotify ();
|
||||
this->notify().accessRightsNotify ( this->accessRightState );
|
||||
@@ -259,11 +285,12 @@ void nciu::createChannelRequest (
|
||||
tcpiiu & iiu, epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
iiu.createChannelRequest ( *this, guard );
|
||||
this->f_claimSent = true;
|
||||
this->f_createChanReqSent = true;
|
||||
}
|
||||
|
||||
cacChannel::ioStatus nciu::read ( unsigned type, arrayElementCount countIn,
|
||||
cacReadNotify ¬ify, ioid *pId )
|
||||
cacChannel::ioStatus nciu::read (
|
||||
unsigned type, arrayElementCount countIn,
|
||||
cacReadNotify ¬ify, ioid *pId )
|
||||
{
|
||||
//
|
||||
// fail out if their arguments are invalid
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "net_convert.h"
|
||||
#include "bhe.h"
|
||||
#include "epicsSignal.h"
|
||||
#include "caerr.h"
|
||||
|
||||
const unsigned mSecPerSec = 1000u;
|
||||
const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
@@ -344,7 +345,12 @@ void tcpRecvThread::run ()
|
||||
// only one recv thread at a time may call callbacks
|
||||
// - pendEvent() blocks until threads waiting for
|
||||
// this lock get a chance to run
|
||||
epicsGuard < callbackMutex > guard ( this->cbMutex );
|
||||
epicsGuard < callbackMutex > cbGuard ( this->cbMutex );
|
||||
|
||||
if ( this->iiu.softDisconnect ) {
|
||||
epicsGuard < cacMutex > cacGuard ( this->iiu.cacRef.mutexRef() );
|
||||
this->iiu.responsiveCircuitNotify ( cbGuard, cacGuard );
|
||||
}
|
||||
|
||||
// force the receive watchdog to be reset every 5 frames
|
||||
unsigned contiguousFrameCount = 0;
|
||||
@@ -368,7 +374,7 @@ void tcpRecvThread::run ()
|
||||
pComBuf = new ( this->iiu.comBufMemMgr ) comBuf;
|
||||
|
||||
// execute receive labor
|
||||
bool protocolOK = this->iiu.processIncoming ( currentTime, guard );
|
||||
bool protocolOK = this->iiu.processIncoming ( currentTime, cbGuard );
|
||||
if ( ! protocolOK ) {
|
||||
this->iiu.cacRef.initiateAbortShutdown ( this->iiu );
|
||||
break;
|
||||
@@ -449,7 +455,8 @@ tcpiiu::tcpiiu ( cac & cac, callbackMutex & cbMutex, double connectionTimeout,
|
||||
earlyFlush ( false ),
|
||||
recvProcessPostponedFlush ( false ),
|
||||
discardingPendingData ( false ),
|
||||
socketHasBeenClosed ( false )
|
||||
socketHasBeenClosed ( false ),
|
||||
softDisconnect ( false )
|
||||
{
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if ( this->sock == INVALID_SOCKET ) {
|
||||
@@ -637,6 +644,52 @@ void tcpiiu::disconnectNotify ( epicsGuard < cacMutex > & )
|
||||
this->sendThreadFlushEvent.signal ();
|
||||
}
|
||||
|
||||
void tcpiiu::responsiveCircuitNotify (
|
||||
epicsGuard < callbackMutex > & cbGuard,
|
||||
epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
this->softDisconnect = false;
|
||||
tsDLIter < nciu > pChan = this->channelList.firstIter ();
|
||||
while ( pChan.valid() ) {
|
||||
// The cac lock is released herein so there is concern that
|
||||
// the list could be changed while we are traversing it.
|
||||
// However, this occurs only if a circuit disconnects,
|
||||
// a user deletes a channel, or a server disconnects a
|
||||
// channel. The callback lock must be taken in all of
|
||||
// these situations so this code is protected.
|
||||
pChan->responsiveCircuitNotify ( cbGuard, guard );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
|
||||
void tcpiiu::unresponsiveCircuitNotify (
|
||||
epicsGuard < callbackMutex > & cbGuard,
|
||||
epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
this->recvDog.cancel();
|
||||
this->sendDog.cancel();
|
||||
this->softDisconnect = true;
|
||||
if ( this->channelList.count() ) {
|
||||
char hostNameTmp[128];
|
||||
this->hostName ( hostNameTmp, sizeof ( hostNameTmp ) );
|
||||
{
|
||||
epicsGuardRelease < cacMutex > guardRelease ( guard );
|
||||
genLocalExcep ( cbGuard, this->cacRef, ECA_UNRESPTMO, hostNameTmp );
|
||||
}
|
||||
tsDLIter < nciu > pChan = this->channelList.firstIter ();
|
||||
while ( pChan.valid() ) {
|
||||
// The cac lock is released herein so there is concern that
|
||||
// the list could be changed while we are traversing it.
|
||||
// However, this occurs only if a circuit disconnects,
|
||||
// a user deletes a channel, or a server disconnects a
|
||||
// channel. The callback lock must be taken in all of
|
||||
// these situations so this code is protected.
|
||||
pChan->unresponsiveCircuitNotify ( cbGuard, guard );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tcpiiu::initiateAbortShutdown ( epicsGuard < callbackMutex > &,
|
||||
epicsGuard < cacMutex > & guard )
|
||||
{
|
||||
@@ -750,6 +803,7 @@ void tcpiiu::show ( unsigned level ) const
|
||||
this->recvThread.show ( level-2u );
|
||||
::printf ("\techo pending bool = %u\n", this->echoRequestPending );
|
||||
::printf ( "IO identifier hash table:\n" );
|
||||
|
||||
tsDLIterConst < nciu > pChan = this->channelList.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 2u );
|
||||
@@ -1301,7 +1355,9 @@ void tcpiiu::removeAllChannels (
|
||||
}
|
||||
}
|
||||
|
||||
void tcpiiu::installChannel ( epicsGuard < cacMutex > & guard,
|
||||
void tcpiiu::installChannel (
|
||||
epicsGuard < callbackMutex > &,
|
||||
epicsGuard < cacMutex > & guard,
|
||||
nciu & chan, unsigned sidIn,
|
||||
ca_uint16_t typeIn, arrayElementCount countIn )
|
||||
{
|
||||
@@ -1311,8 +1367,9 @@ void tcpiiu::installChannel ( epicsGuard < cacMutex > & guard,
|
||||
this->flushRequest ();
|
||||
}
|
||||
|
||||
void tcpiiu::uninstallChan
|
||||
( epicsGuard < cacMutex > & guard, nciu & chan )
|
||||
void tcpiiu::uninstallChan (
|
||||
epicsGuard < callbackMutex > &,
|
||||
epicsGuard < cacMutex > & guard, nciu & chan )
|
||||
{
|
||||
this->channelList.remove ( chan );
|
||||
if ( channelList.count() == 0 ) {
|
||||
|
||||
Reference in New Issue
Block a user