keep circuit open with disconnected channels attached if the circuit

becomes unresponsive
This commit is contained in:
Jeff Hill
2003-10-23 22:45:54 +00:00
parent 70091854bc
commit 0712df904b
3 changed files with 127 additions and 37 deletions

View File

@@ -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 );

View File

@@ -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 &notify, ioid *pId )
cacChannel::ioStatus nciu::read (
unsigned type, arrayElementCount countIn,
cacReadNotify &notify, ioid *pId )
{
//
// fail out if their arguments are invalid

View File

@@ -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 ) {