fixed a disconnect related problem and also improved

structure of locking
This commit is contained in:
Jeff Hill
2001-06-20 17:45:19 +00:00
parent 61ff831b2d
commit 99df1b5584
5 changed files with 102 additions and 96 deletions
+4 -11
View File
@@ -88,15 +88,10 @@ int CASG::block ( double timeout )
beg_time = cur_time;
delay = 0.0;
this->client.enableCallbackPreemption ();
while ( 1 ) {
{
epicsAutoMutex locker ( this->mutex );
if ( this->ioList.count() == 0u ) {
status = ECA_NORMAL;
break;
}
if ( this->ioList.count() == 0u ) {
status = ECA_NORMAL;
break;
}
remaining = timeout - delay;
@@ -110,7 +105,7 @@ int CASG::block ( double timeout )
break;
}
this->sem.wait ( remaining );
this->client.blockForEventAndEnableCallbacks ( this->sem, remaining );
/*
* force a time update
@@ -120,8 +115,6 @@ int CASG::block ( double timeout )
delay = cur_time - beg_time;
}
this->client.disableCallbackPreemption ();
return status;
}
+86 -66
View File
@@ -354,6 +354,12 @@ void cac::processRecvBacklog ()
void cac::flushRequest ()
{
epicsAutoMutex autoMutex ( this->mutex );
this->flushRequestPrivate ();
}
// lock must be applied
void cac::flushRequestPrivate ()
{
tsDLIterBD <tcpiiu> piiu = this->iiuList.firstIter ();
while ( piiu.valid () ) {
piiu->flushRequest ();
@@ -527,10 +533,6 @@ int cac::pendIO ( const double &timeout )
return ECA_EVDISALLOW;
}
this->enableCallbackPreemption ();
this->flushRequest ();
int status = ECA_NORMAL;
epicsTime beg_time = epicsTime::getCurrent ();
double remaining;
@@ -540,20 +542,29 @@ int cac::pendIO ( const double &timeout )
else{
remaining = timeout;
}
while ( this->pndRecvCnt > 0 ) {
if ( remaining < CAC_SIGNIFICANT_SELECT_DELAY ) {
status = ECA_TIMEOUT;
break;
}
this->ioDone.wait ( remaining );
if ( timeout != 0.0 ) {
double delay = epicsTime::getCurrent () - beg_time;
remaining = timeout - delay;
}
}
{
epicsAutoMutex autoMutex ( this->mutex );
this->flushRequestPrivate ();
while ( this->pndRecvCnt > 0 ) {
if ( remaining < CAC_SIGNIFICANT_SELECT_DELAY ) {
status = ECA_TIMEOUT;
break;
}
this->enableCallbackPreemption ();
{
epicsAutoMutexRelease autoRelease ( this->mutex );
this->ioDone.wait ( remaining );
}
this->disableCallbackPreemption ();
if ( timeout != 0.0 ) {
double delay = epicsTime::getCurrent () - beg_time;
remaining = timeout - delay;
}
}
this->readSeq++;
this->pndRecvCnt = 0u;
if ( this->pudpiiu ) {
@@ -561,11 +572,20 @@ int cac::pendIO ( const double &timeout )
}
}
this->disableCallbackPreemption ();
return status;
}
void cac::blockForEventAndEnableCallbacks ( epicsEvent &event, double timeout )
{
epicsAutoMutex autoMutex ( this->mutex );
this->enableCallbackPreemption ();
{
epicsAutoMutexRelease autoMutexRelease ( this->mutex );
event.wait ( timeout );
}
this->disableCallbackPreemption ();
}
int cac::pendEvent ( const double &timeout )
{
// prevent recursion nightmares by disabling calls to
@@ -574,20 +594,27 @@ int cac::pendEvent ( const double &timeout )
return ECA_EVDISALLOW;
}
this->enableCallbackPreemption ();
{
epicsAutoMutex autoMutex ( this->mutex );
this->flushRequest ();
this->flushRequestPrivate ();
if ( timeout == 0.0 ) {
while ( true ) {
epicsThreadSleep ( 60.0 );
this->enableCallbackPreemption ();
{
epicsAutoMutexRelease autoMutexRelease ( this->mutex );
if ( timeout == 0.0 ) {
while ( true ) {
epicsThreadSleep ( 60.0 );
}
}
else if ( timeout >= CAC_SIGNIFICANT_SELECT_DELAY ) {
epicsThreadSleep ( timeout );
}
}
}
else if ( timeout >= CAC_SIGNIFICANT_SELECT_DELAY ) {
epicsThreadSleep ( timeout );
}
this->disableCallbackPreemption ();
this->disableCallbackPreemption ();
}
return ECA_TIMEOUT;
}
@@ -760,56 +787,44 @@ bool cac::setupUDP ()
return true;
}
// lock must already be applied
void cac::enableCallbackPreemption ()
{
unsigned copy;
{
epicsAutoMutex autoMutex ( this->mutex );
assert ( this->recvProcessEnableRefCount < UINT_MAX );
copy = this->recvProcessEnableRefCount;
this->recvProcessEnableRefCount++;
}
if ( copy == 0u ) {
assert ( this->recvProcessEnableRefCount < UINT_MAX );
this->recvProcessEnableRefCount++;
if ( this->recvProcessEnableRefCount == 1u ) {
this->recvProcessActivityEvent.signal ();
}
}
// lock must already be applied
void cac::disableCallbackPreemption ()
{
bool wakeupNeeded;
{
epicsAutoMutex autoMutex ( this->mutex );
if ( ! this->recvProcessInProgress ) {
assert ( this->recvProcessEnableRefCount != 0u );
this->recvProcessEnableRefCount--;
return;
}
else {
this->recvProcessCompletionNBlockers++;
}
while ( true ) {
{
epicsAutoMutexRelease autoMutexRelease ( this->mutex );
this->recvProcessCompletion.wait ();
}
if ( ! this->recvProcessInProgress ) {
assert ( this->recvProcessEnableRefCount != 0u );
assert ( this->recvProcessEnableRefCount > 0u );
this->recvProcessEnableRefCount--;
assert ( this->recvProcessCompletionNBlockers > 0u );
this->recvProcessCompletionNBlockers--;
if ( this->recvProcessCompletionNBlockers > 0u ) {
this->recvProcessCompletion.signal ();
}
return;
}
else {
this->recvProcessCompletionNBlockers++;
}
}
while ( true ) {
this->recvProcessCompletion.wait ();
{
epicsAutoMutex autoMutex ( this->mutex );
if ( ! this->recvProcessInProgress ) {
assert ( this->recvProcessEnableRefCount > 0u );
this->recvProcessEnableRefCount--;
assert ( this->recvProcessCompletionNBlockers > 0u );
this->recvProcessCompletionNBlockers--;
wakeupNeeded = this->recvProcessCompletionNBlockers > 0u;
break;
}
}
}
if ( wakeupNeeded ) {
this->recvProcessCompletion.signal ();
}
}
@@ -957,9 +972,14 @@ void cac::flushIfRequired ( nciu &chan )
blockPermit = false;
}
}
this->flushRequest ();
this->flushRequestPrivate ();
if ( blockPermit ) {
// enable / disable of call back preemption must occur here
// because the tcpiiu might disconnect while waiting and its
// pointer to this cac might become invalid
this->enableCallbackPreemption ();
chan.getPIIU()->blockUntilSendBacklogIsReasonable ( this->mutex );
this->disableCallbackPreemption ();
}
}
else {
+4 -2
View File
@@ -111,8 +111,7 @@ public:
const char *pFileName, unsigned lineNo );
// callback preemption control
void enableCallbackPreemption ();
void disableCallbackPreemption ();
void blockForEventAndEnableCallbacks ( epicsEvent &event, double timeout );
// diagnostics
unsigned connectionCount () const;
@@ -189,8 +188,11 @@ private:
bool recvProcessInProgress;
bool recvProcessThreadExitRequest;
void flushRequestPrivate ();
void run ();
bool setupUDP ();
void enableCallbackPreemption ();
void disableCallbackPreemption ();
void flushIfRequired ( nciu & ); // lock must be applied
void recycleReadNotifyIO ( netReadNotifyIO &io );
void recycleWriteNotifyIO ( netWriteNotifyIO &io );
+4 -9
View File
@@ -212,8 +212,7 @@ public:
CASG * lookupCASG ( unsigned id );
void installCASG ( CASG & );
void uninstallCASG ( CASG & );
void enableCallbackPreemption ();
void disableCallbackPreemption ();
void blockForEventAndEnableCallbacks ( epicsEvent &event, double timeout );
// perhaps these should be eliminated in deference to the exception mechanism
int printf ( const char *pformat, ... ) const;
int vPrintf ( const char *pformat, va_list args ) const;
@@ -492,14 +491,10 @@ inline void oldCAC::uninstallCASG ( CASG &sg )
this->clientCtx.uninstallCASG ( sg );
}
inline void oldCAC::enableCallbackPreemption ()
inline void oldCAC::blockForEventAndEnableCallbacks (
epicsEvent &event, double timeout )
{
this->clientCtx.enableCallbackPreemption ();
}
inline void oldCAC::disableCallbackPreemption ()
{
this->clientCtx.disableCallbackPreemption ();
this->clientCtx.blockForEventAndEnableCallbacks ( event, timeout );
}
inline void oldCAC::vSignal ( int ca_status, const char *pfilenm,
+4 -8
View File
@@ -1272,24 +1272,20 @@ bool tcpiiu::flush ()
}
}
// ~tcpiiu() will not return while this->blockingForFlush is greater than zero
void tcpiiu::blockUntilSendBacklogIsReasonable ( epicsMutex &mutex )
{
this->pCAC()->enableCallbackPreemption ();
assert ( this->blockingForFlush < UINT_MAX );
this->blockingForFlush++;
while ( this->sendQue.flushBlockThreshold(0u) && this->state == iiu_connected ) {
epicsAutoMutexRelease autoRelease ( mutex );
this->flushBlockEvent.wait ( 5.0 );
}
assert ( this->blockingForFlush > 0u );
this->blockingForFlush--;
if ( this->blockingForFlush ) {
if ( this->blockingForFlush == 1 ) {
this->flushBlockEvent.signal ();
}
{
epicsAutoMutexRelease autoRelease ( mutex );
this->pCAC()->disableCallbackPreemption ();
}
assert ( this->blockingForFlush > 0u );
this->blockingForFlush--;
}
void tcpiiu::flushRequestIfAboveEarlyThreshold ()