many changes associated will disconnecting the channel but not disconnecting the circuit

This commit is contained in:
Jeff Hill
2004-01-09 00:42:15 +00:00
parent 60dde019c0
commit f04fa5fdf3
62 changed files with 3591 additions and 2586 deletions

View File

@@ -23,31 +23,35 @@
#include "iocinf.h"
#include "syncGroup.h"
#include "oldAccess.h"
#include "autoPtrDestroy.h"
#include "cac.h"
#include "sgAutoPtr.h"
casgRecycle::~casgRecycle () {}
CASG::CASG ( ca_client_context &cacIn ) :
CASG::CASG ( epicsGuard < epicsMutex > & guard, ca_client_context & cacIn ) :
client ( cacIn ), magic ( CASG_MAGIC )
{
client.installCASG ( *this );
client.installCASG ( guard, *this );
}
CASG::~CASG ()
{
if ( this->verify () ) {
this->reset ();
this->client.uninstallCASG ( *this );
}
void CASG::destructor ( epicsGuard < epicsMutex > & guard )
{
if ( this->verify ( guard ) ) {
this->reset ( guard );
this->client.uninstallCASG ( guard, *this );
this->magic = 0;
}
else {
this->printf ("cac: attempt to destroy invalid sync group ignored\n");
this->printf ( "cac: attempt to destroy invalid sync group ignored\n" );
}
this->~CASG ();
}
bool CASG::verify () const
bool CASG::verify ( epicsGuard < epicsMutex > & ) const
{
return ( this->magic == CASG_MAGIC );
}
@@ -55,7 +59,7 @@ bool CASG::verify () const
/*
* CASG::block ()
*/
int CASG::block ( double timeout )
int CASG::block ( epicsGuard < epicsMutex > & guard, double timeout )
{
epicsTime cur_time;
epicsTime beg_time;
@@ -75,7 +79,7 @@ int CASG::block ( double timeout )
cur_time = epicsTime::getCurrent ();
this->client.flushRequest ();
this->client.flush ( guard );
beg_time = cur_time;
delay = 0.0;
@@ -96,7 +100,11 @@ int CASG::block ( double timeout )
break;
}
this->client.blockForEventAndEnableCallbacks ( this->sem, remaining );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
this->client.blockForEventAndEnableCallbacks (
this->sem, remaining );
}
/*
* force a time update
@@ -106,87 +114,79 @@ int CASG::block ( double timeout )
delay = cur_time - beg_time;
}
this->reset ();
this->reset ( guard );
return status;
}
void CASG::reset ()
void CASG::reset (
epicsGuard < epicsMutex > & guard )
{
epicsGuard < casgMutex > locker ( this->mutex );
this->destroyCompletedIO ();
this->destroyPendingIO ();
this->destroyCompletedIO ( guard );
this->destroyPendingIO ( guard );
}
// lock must be applied
void CASG::destroyCompletedIO ()
void CASG::destroyCompletedIO (
epicsGuard < epicsMutex > & guard )
{
tsDLList < syncGroupNotify > userStillRequestingList;
syncGroupNotify *pNotify;
syncGroupNotify * pNotify;
while ( ( pNotify = this->ioCompletedList.get () ) ) {
if ( pNotify->ioInitiated() ) {
pNotify->destroy ( * this );
}
else {
userStillRequestingList.add ( *pNotify );
}
pNotify->destroy ( guard, * this );
}
this->ioCompletedList.add ( userStillRequestingList );
}
// lock must be applied
void CASG::destroyPendingIO ()
void CASG::destroyPendingIO (
epicsGuard < epicsMutex > & guard )
{
tsDLList < syncGroupNotify > userStillRequestingList;
syncGroupNotify *pNotify;
while ( ( pNotify = this->ioPendingList.get () ) ) {
if ( pNotify->ioInitiated() ) {
pNotify->destroy ( * this );
}
else {
userStillRequestingList.add ( *pNotify );
}
pNotify->destroy ( guard, * this );
}
this->ioPendingList.add ( userStillRequestingList );
}
void CASG::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->client.mutexRef () );
this->show ( guard, level );
}
void CASG::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
::printf ( "Sync Group: id=%u, magic=%u, opPend=%u\n",
this->getId (), this->magic, this->ioPendingList.count () );
if ( level ) {
epicsGuard < casgMutex > locker ( this->mutex );
::printf ( "\tPending" );
tsDLIterConst < syncGroupNotify > notifyPending = this->ioPendingList.firstIter ();
tsDLIterConst < syncGroupNotify > notifyPending =
this->ioPendingList.firstIter ();
while ( notifyPending.valid () ) {
notifyPending->show ( level - 1u );
notifyPending->show ( guard, level - 1u );
notifyPending++;
}
::printf ( "\tCompleted" );
tsDLIterConst < syncGroupNotify > notifyCompleted = this->ioCompletedList.firstIter ();
tsDLIterConst < syncGroupNotify > notifyCompleted =
this->ioCompletedList.firstIter ();
while ( notifyCompleted.valid () ) {
notifyCompleted->show ( level - 1u );
notifyCompleted->show ( guard, level - 1u );
notifyCompleted++;
}
}
}
bool CASG::ioComplete ()
bool CASG::ioComplete (
epicsGuard < epicsMutex > & guard )
{
bool isCompleted;
{
epicsGuard < casgMutex > locker ( this->mutex );
this->destroyCompletedIO ();
isCompleted = ( this->ioPendingList.count () == 0u );
}
return isCompleted;
this->destroyCompletedIO ( guard );
return this->ioPendingList.count () == 0u;
}
void CASG::put ( chid pChan, unsigned type, arrayElementCount count, const void * pValue )
void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan,
unsigned type, arrayElementCount count, const void * pValue )
{
sgAutoPtr < syncGroupWriteNotify > pNotify ( *this );
sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this );
{
epicsGuard < casgMutex > locker ( this->mutex );
pNotify = syncGroupWriteNotify::factory (
this->freeListWriteOP, *this, pChan );
if ( pNotify.get () ) {
@@ -196,15 +196,15 @@ void CASG::put ( chid pChan, unsigned type, arrayElementCount count, const void
return;
}
}
pNotify->begin ( type, count, pValue );
pNotify->begin ( guard, type, count, pValue );
pNotify.release ();
}
void CASG::get ( chid pChan, unsigned type, arrayElementCount count, void *pValue )
void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan,
unsigned type, arrayElementCount count, void *pValue )
{
sgAutoPtr < syncGroupReadNotify > pNotify ( *this );
sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this );
{
epicsGuard < casgMutex > locker ( this->mutex );
pNotify = syncGroupReadNotify::factory (
this->freeListReadOP, *this, pChan, pValue );
if ( pNotify.get () ) {
@@ -214,39 +214,37 @@ void CASG::get ( chid pChan, unsigned type, arrayElementCount count, void *pValu
return;
}
}
pNotify->begin ( type, count );
pNotify->begin ( guard, type, count );
pNotify.release ();
}
void CASG::destroyPendingIO ( syncGroupNotify * pNotify )
void CASG::destroyPendingIO (
epicsGuard < epicsMutex > & guard, syncGroupNotify * pNotify )
{
if ( pNotify ) {
epicsGuard < casgMutex > locker ( this->mutex );
this->ioPendingList.remove ( *pNotify );
pNotify->destroy ( *this );
pNotify->destroy ( guard, *this );
}
}
void CASG::completionNotify ( syncGroupNotify & notify )
void CASG::completionNotify (
epicsGuard < epicsMutex > & guard, syncGroupNotify & notify )
{
unsigned requestsIncomplete;
{
epicsGuard < casgMutex > locker ( this->mutex );
this->ioPendingList.remove ( notify );
this->ioCompletedList.add ( notify );
requestsIncomplete = this->ioPendingList.count ();
}
if ( requestsIncomplete == 0u ) {
this->ioPendingList.remove ( notify );
this->ioCompletedList.add ( notify );
if ( this->ioPendingList.count () == 0u ) {
this->sem.signal ();
}
}
void CASG::recycleSyncGroupWriteNotify ( syncGroupWriteNotify & io )
void CASG::recycleSyncGroupWriteNotify (
epicsGuard < epicsMutex > & guard, syncGroupWriteNotify & io )
{
this->freeListWriteOP.release ( & io );
}
void CASG::recycleSyncGroupReadNotify ( syncGroupReadNotify & io )
void CASG::recycleSyncGroupReadNotify (
epicsGuard < epicsMutex > & guard, syncGroupReadNotify & io )
{
this->freeListReadOP.release ( & io );
}
@@ -265,18 +263,28 @@ int CASG::printf ( const char *pformat, ... )
return status;
}
void CASG::exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo )
void CASG::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * pContext,
const char * pFileName, unsigned lineNo )
{
this->client.exception ( status, pContext, pFileName, lineNo );
if ( status != ECA_CHANDESTROY ) {
this->client.exception (
guard, status, pContext, pFileName, lineNo );
}
}
void CASG::exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo, oldChannelNotify &chan,
void CASG::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * pContext,
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
unsigned type, arrayElementCount count, unsigned op )
{
this->client.exception ( status, pContext, pFileName,
lineNo, chan, type, count, op );
if ( status != ECA_CHANDESTROY ) {
this->client.exception (
guard, status, pContext, pFileName,
lineNo, chan, type, count, op );
}
}
void * CASG::operator new ( size_t ) // X aCC 361

View File

@@ -29,23 +29,23 @@ INC += caDiagnostics.h
LIBSRCS += cac.cpp
LIBSRCS += cacChannel.cpp
LIBSRCS += cacChannelNotify.cpp
LIBSRCS += cacNotify.cpp
LIBSRCS += cacContextNotify.cpp
LIBSRCS += cacReadNotify.cpp
LIBSRCS += cacWriteNotify.cpp
LIBSRCS += cacStateNotify.cpp
LIBSRCS += cacServiceList.cpp
LIBSRCS += access.cpp
LIBSRCS += iocinf.cpp
LIBSRCS += convert.cpp
LIBSRCS += test_event.cpp
LIBSRCS += repeater.cpp
LIBSRCS += searchTimer.cpp
LIBSRCS += disconnectGovernorTimer.cpp
LIBSRCS += repeaterSubscribeTimer.cpp
LIBSRCS += tcpiiu.cpp
LIBSRCS += udpiiu.cpp
LIBSRCS += netiiu.cpp
LIBSRCS += nciu.cpp
LIBSRCS += baseNMIU.cpp
LIBSRCS += nciu.cpp
LIBSRCS += netiiu.cpp
LIBSRCS += udpiiu.cpp
LIBSRCS += tcpiiu.cpp
LIBSRCS += netReadNotifyIO.cpp
LIBSRCS += netWriteNotifyIO.cpp
LIBSRCS += netSubscription.cpp
@@ -89,7 +89,8 @@ PROD_LIBS = ca Com
PROD_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
PROD_HOST += caRepeater catime acctst caConnTest casw caEventRate
OBJS_IOC_vxWorks += catime acctst caConnTest casw caEventRate
OBJS_IOC_vxWorks +=
OBJS_IOC += catime acctst caConnTest casw caEventRate
caRepeater_SRCS = caRepeater.cpp
catime_SRCS = catimeMain.c catime.c
acctst_SRCS = acctstMain.c acctst.c

View File

@@ -41,7 +41,6 @@
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "oldAccess.h"
#include "autoPtrDestroy.h"
#include "cac.h"
epicsThreadPrivateId caClientContextId;
@@ -187,7 +186,7 @@ int epicsShareAPI ca_context_create (
ca_client_context *pcac;
try {
epicsThreadOnce ( &caClientContextIdOnce, ca_init_client_context, 0);
epicsThreadOnce ( & caClientContextIdOnce, ca_init_client_context, 0);
if ( caClientContextId == 0 ) {
return ECA_ALLOCMEM;
}
@@ -216,22 +215,6 @@ int epicsShareAPI ca_context_create (
return ECA_NORMAL;
}
//
// ca_register_service ()
//
int epicsShareAPI ca_register_service ( cacService *pService )
{
ca_client_context *pcac;
int caStatus = fetchClientContext (&pcac);
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
if ( pService ) {
pcac->registerService ( *pService );
}
return ECA_NORMAL;
}
//
// ca_modify_host_name ()
//
@@ -328,8 +311,8 @@ int epicsShareAPI ca_create_channel (
CAFDHANDLER * pFunc = 0;
void * pArg = 0;
{
epicsGuard < ca_client_context_mutex >
autoMutex ( pcac->mutex );
epicsGuard < epicsMutex >
guard ( pcac->mutex );
if ( pcac->fdRegFuncNeedsToBeCalled ) {
pFunc = pcac->fdRegFunc;
pArg = pcac->fdRegArg;
@@ -342,14 +325,18 @@ int epicsShareAPI ca_create_channel (
}
try {
epicsGuard < epicsMutex > guard ( pcac->mutex );
oldChannelNotify * pChanNotify =
new ( pcac->oldChannelNotifyFreeList )
oldChannelNotify ( *pcac, name_str,
oldChannelNotify ( guard, *pcac, name_str,
conn_func, puser, priority );
// make sure that their chan pointer is set prior to
// calling connection call backs
*chanptr = pChanNotify;
pChanNotify->initiateConnect ();
pChanNotify->initiateConnect ( guard );
// no need to worry about a connect preempting here because
// the connect sequence will not start untill initiateConnect()
// is called
}
catch ( cacChannel::badString & ) {
return ECA_BADSTR;
@@ -360,6 +347,9 @@ int epicsShareAPI ca_create_channel (
catch ( cacChannel::badPriority & ) {
return ECA_BADPRIORITY;
}
catch ( cacChannel::unsupportedByService & ) {
return ECA_UNAVAILINSERV;
}
catch ( ... ) {
return ECA_INTERNAL;
}
@@ -392,12 +382,13 @@ int epicsShareAPI ca_array_get ( chtype type,
return ECA_BADTYPE;
}
unsigned tmpType = static_cast < unsigned > ( type );
autoPtrFreeList < getCopy > pNotify
epicsGuard < epicsMutex > guard ( pChan->getClientCtx().mutex );
autoPtrFreeList < getCopy, 0x400, epicsMutexNOOP > pNotify
( pChan->getClientCtx().getCopyFreeList,
new ( pChan->getClientCtx().getCopyFreeList )
getCopy ( pChan->getClientCtx(), *pChan,
getCopy ( guard, pChan->getClientCtx(), *pChan,
tmpType, count, pValue ) );
pChan->read ( type, count, *pNotify );
pChan->read ( guard, type, count, *pNotify );
pNotify.release ();
caStatus = ECA_NORMAL;
}
@@ -458,11 +449,12 @@ int epicsShareAPI ca_array_get_callback ( chtype type,
}
unsigned tmpType = static_cast < unsigned > ( type );
autoPtrFreeList < getCallback > pNotify
epicsGuard < epicsMutex > guard ( pChan->getClientCtx().mutex );
autoPtrFreeList < getCallback, 0x400, epicsMutexNOOP > pNotify
( pChan->getClientCtx().getCallbackFreeList,
new ( pChan->getClientCtx().getCallbackFreeList )
getCallback ( *pChan, pfunc, arg ) );
pChan->read ( tmpType, count, *pNotify );
pChan->read ( guard, tmpType, count, *pNotify );
pNotify.release ();
caStatus = ECA_NORMAL;
}
@@ -520,12 +512,13 @@ int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count,
if ( type < 0 ) {
return ECA_BADTYPE;
}
epicsGuard < epicsMutex > guard ( pChan->getClientCtx().mutex );
unsigned tmpType = static_cast < unsigned > ( type );
autoPtrFreeList < putCallback > pNotify
autoPtrFreeList < putCallback, 0x400, epicsMutexNOOP > pNotify
( pChan->getClientCtx().putCallbackFreeList,
new ( pChan->getClientCtx().putCallbackFreeList )
putCallback ( *pChan, pfunc, usrarg ) );
pChan->write ( tmpType, count, pValue, *pNotify );
pChan->write ( guard, tmpType, count, pValue, *pNotify );
pNotify.release ();
caStatus = ECA_NORMAL;
}
@@ -573,7 +566,7 @@ int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count,
*/
// extern "C"
int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count,
chid pChan, const void *pValue )
chid pChan, const void * pValue )
{
if ( type < 0 ) {
return ECA_BADTYPE;
@@ -582,7 +575,8 @@ int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count,
int caStatus;
try {
pChan->write ( tmpType, count, pValue );
epicsGuard < epicsMutex > guard ( pChan->getClientCtx().mutex );
pChan->write ( guard, tmpType, count, pValue );
caStatus = ECA_NORMAL;
}
catch ( cacChannel::badString & )
@@ -687,7 +681,8 @@ int epicsShareAPI ca_create_subscription (
}
try {
autoPtrFreeList < oldSubscription > pSubsr
epicsGuard < epicsMutex > guard ( pChan->getClientCtx().mutex );
autoPtrFreeList < oldSubscription, 0x400, epicsMutexNOOP > pSubsr
( pChan->getClientCtx().subscriptionFreeList,
new ( pChan->getClientCtx().subscriptionFreeList )
oldSubscription ( *pChan,
@@ -696,7 +691,7 @@ int epicsShareAPI ca_create_subscription (
if ( monixptr ) {
*monixptr = pTmp;
}
pTmp->begin ( tmpType, count, mask );
pTmp->begin ( guard, tmpType, count, mask );
// dont touch pTmp after this because
// the first callback might have canceled it
return ECA_NORMAL;
@@ -751,8 +746,8 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
{
oldChannelNotify & chan = pMon->channel ();
ca_client_context & cac = chan.getClientCtx ();
pMon->ioCancel ();
cac.destroySubscription ( *pMon );
epicsGuard < epicsMutex > guard ( cac.mutex );
pMon->ioCancel ( guard );
return ECA_NORMAL;
}
@@ -837,16 +832,16 @@ int epicsShareAPI ca_pend_io ( ca_real timeout )
/*
* ca_flush_io ()
*/
// extern "C"
int epicsShareAPI ca_flush_io ()
{
ca_client_context *pcac;
ca_client_context * pcac;
int caStatus = fetchClientContext (&pcac);
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
pcac->flushRequest ();
epicsGuard < epicsMutex > guard ( pcac->mutex );
pcac->flush ( guard );
return ECA_NORMAL;
}
@@ -854,7 +849,6 @@ int epicsShareAPI ca_flush_io ()
/*
* CA_TEST_IO ()
*/
// extern "C"
int epicsShareAPI ca_test_io () // X aCC 361
{
ca_client_context *pcac;
@@ -934,9 +928,11 @@ void epicsShareAPI ca_signal_formated ( long ca_status, const char *pfilenm,
pcac->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs );
}
else {
fprintf ( stderr, "file=%s line=%d: CA exception delivered to a thread w/o ca context\n",
pfilenm, lineno );
vfprintf ( stderr, pFormat, theArgs );
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 );
}
}
va_end ( theArgs );
}
@@ -1109,7 +1105,6 @@ double epicsShareAPI ca_beacon_period ( chid pChan )
return pChan->beaconPeriod ();
}
// extern "C"
double epicsShareAPI ca_receive_watchdog_delay ( chid pChan )
{
return pChan->receiveWatchdogDelay ();
@@ -1130,7 +1125,7 @@ unsigned epicsShareAPI ca_get_ioc_connection_count ()
return 0u;
}
return pcac->connectionCount ();
return pcac->circuitCount ();
}
unsigned epicsShareAPI ca_beacon_anomaly_count ()

View File

@@ -30,27 +30,29 @@
template < class T >
class autoPtrRecycle {
public:
autoPtrRecycle ( chronIntIdResTable < baseNMIU > &,
tsDLList < class baseNMIU > &, cacRecycle &, T * );
autoPtrRecycle (
epicsGuard < epicsMutex > &, chronIntIdResTable < baseNMIU > &,
cacRecycle &, T * );
~autoPtrRecycle ();
T & operator * () const;
T * operator -> () const;
T * get () const;
T * release ();
private:
T *p;
cacRecycle &r;
tsDLList < class baseNMIU > &eventq;
chronIntIdResTable < baseNMIU > &ioTable;
T * p;
cacRecycle & r;
chronIntIdResTable < baseNMIU > & ioTable;
epicsGuard < epicsMutex > & guard;
// not implemented
autoPtrRecycle ( const autoPtrRecycle & );
autoPtrRecycle & operator = ( const autoPtrRecycle & );
};
template < class T >
inline autoPtrRecycle<T>::autoPtrRecycle ( chronIntIdResTable < baseNMIU > &tbl,
tsDLList < class baseNMIU > &list, cacRecycle &rIn, T *pIn ) :
p ( pIn ), r ( rIn ), eventq ( list ), ioTable ( tbl ) {}
inline autoPtrRecycle<T>::autoPtrRecycle (
epicsGuard < epicsMutex > & guardIn, chronIntIdResTable < baseNMIU > & tbl,
cacRecycle & rIn, T * pIn ) :
p ( pIn ), r ( rIn ), ioTable ( tbl ), guard ( guardIn ) {}
template < class T >
inline autoPtrRecycle<T>::~autoPtrRecycle ()
@@ -58,8 +60,7 @@ inline autoPtrRecycle<T>::~autoPtrRecycle ()
if ( this->p ) {
baseNMIU *pb = this->p;
this->ioTable.remove ( *pb );
this->eventq.remove ( *pb );
pb->destroy ( this->r );
pb->destroy ( this->guard, this->r );
}
}

View File

@@ -24,11 +24,6 @@
#include <limits.h>
#include <float.h>
#if 0
#define DEBUG
#define DEBUG_ALL 0
#endif
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#define epicsExportSharedSymbols
@@ -50,10 +45,10 @@
* zero (so we can correctly compute the period
* between the 1st and 2nd beacons)
*/
bhe::bhe ( const epicsTime & initialTimeStamp,
bhe::bhe ( epicsMutex & mutexIn, const epicsTime & initialTimeStamp,
unsigned initialBeaconNumber, const inetAddrID & addr ) :
inetAddrID ( addr ), timeStamp ( initialTimeStamp ), averagePeriod ( - DBL_MAX ),
pIIU ( 0 ), lastBeaconNumber ( initialBeaconNumber )
mutex ( mutexIn ), pIIU ( 0 ), lastBeaconNumber ( initialBeaconNumber )
{
# ifdef DEBUG
{
@@ -68,10 +63,11 @@ bhe::~bhe ()
{
}
void bhe::beaconAnomalyNotify ()
void bhe::beaconAnomalyNotify ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pIIU ) {
this->pIIU->beaconAnomalyNotify ();
this->pIIU->beaconAnomalyNotify ( guard );
}
}
@@ -125,10 +121,13 @@ void bhe::logBeaconDiscard ( unsigned /* beaconAdvance */,
*
* updates beacon period, and looks for beacon anomalies
*/
bool bhe::updatePeriod ( const epicsTime & programBeginTime,
bool bhe::updatePeriod (
epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime,
const epicsTime & currentTime, ca_uint32_t beaconNumber,
unsigned protocolRevision )
{
guard.assertIdenticalMutex ( this->mutex );
//
// this block is enetered if the beacon was created as a side effect of
// creating a connection and so we dont yet know the first beacon time
@@ -139,7 +138,7 @@ bool bhe::updatePeriod ( const epicsTime & programBeginTime,
this->lastBeaconNumber = beaconNumber;
}
this->beaconAnomalyNotify ();
this->beaconAnomalyNotify ( guard );
/*
* this is the 1st beacon seen - the beacon time stamp
@@ -189,7 +188,7 @@ bool bhe::updatePeriod ( const epicsTime & programBeginTime,
if ( this->averagePeriod < 0.0 ) {
double totalRunningTime;
this->beaconAnomalyNotify ();
this->beaconAnomalyNotify ( guard );
/*
* this is the 2nd beacon seen. We cant tell about
@@ -229,7 +228,7 @@ bool bhe::updatePeriod ( const epicsTime & programBeginTime,
* trigger on any missing beacon
* if connected to this server
*/
this->beaconAnomalyNotify ();
this->beaconAnomalyNotify ( guard );
if ( currentPeriod >= this->averagePeriod * 3.25 ) {
/*
@@ -253,14 +252,14 @@ bool bhe::updatePeriod ( const epicsTime & programBeginTime,
* that the server is available
*/
else if ( currentPeriod <= this->averagePeriod * 0.80 ) {
this->beaconAnomalyNotify ();
this->beaconAnomalyNotify ( guard );
netChange = true;
logBeacon ( "bal", currentPeriod, currentTime );
}
else if ( this->pIIU ) {
// update state of health for active virtual circuits
// if the beacon looks ok
this->pIIU->beaconArrivalNotify ( currentTime );
this->pIIU->beaconArrivalNotify ( guard, currentTime );
logBeacon ( "vb", currentPeriod, currentTime );
}
@@ -276,27 +275,34 @@ bool bhe::updatePeriod ( const epicsTime & programBeginTime,
void bhe::show ( unsigned /* level */ ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
::printf ( "CA beacon hash entry at %p with average period %f\n",
static_cast <const void *> ( this ), this->averagePeriod );
}
double bhe::period () const
double bhe::period ( epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return this->averagePeriod;
}
epicsTime bhe::updateTime () const
epicsTime bhe::updateTime ( epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return this->timeStamp;
}
void bhe::registerIIU ( tcpiiu & iiu )
void bhe::registerIIU (
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
{
guard.assertIdenticalMutex ( this->mutex );
this->pIIU = & iiu;
}
void bhe::unregisterIIU ( tcpiiu & iiu )
void bhe::unregisterIIU (
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pIIU == & iiu ) {
this->pIIU = 0;
this->timeStamp = epicsTime();

View File

@@ -55,18 +55,20 @@ public:
class bhe : public tsSLNode < bhe >, public inetAddrID {
public:
epicsShareFunc bhe ( const epicsTime & initialTimeStamp,
epicsShareFunc bhe (
epicsMutex &, const epicsTime & initialTimeStamp,
unsigned initialBeaconNumber, const inetAddrID & addr );
epicsShareFunc ~bhe ();
epicsShareFunc bool updatePeriod (
epicsGuard < epicsMutex > &,
const epicsTime & programBeginTime,
const epicsTime & currentTime, ca_uint32_t beaconNumber,
unsigned protocolRevision );
epicsShareFunc double period () const;
epicsShareFunc epicsTime updateTime () const;
epicsShareFunc void show ( unsigned level) const;
epicsShareFunc void registerIIU ( tcpiiu & );
epicsShareFunc void unregisterIIU ( tcpiiu & );
epicsShareFunc double period ( epicsGuard < epicsMutex > & ) const;
epicsShareFunc epicsTime updateTime ( epicsGuard < epicsMutex > & ) const;
epicsShareFunc void show ( unsigned level ) const;
epicsShareFunc void registerIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
epicsShareFunc void unregisterIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
epicsShareFunc void * operator new ( size_t size, bheMemoryManager & );
#ifdef CXX_PLACEMENT_DELETE
epicsShareFunc void operator delete ( void *, bheMemoryManager & );
@@ -74,9 +76,10 @@ public:
private:
epicsTime timeStamp;
double averagePeriod;
epicsMutex & mutex;
tcpiiu * pIIU;
ca_uint32_t lastBeaconNumber;
void beaconAnomalyNotify ();
void beaconAnomalyNotify ( epicsGuard < epicsMutex > & );
void logBeacon ( const char * pDiagnostic,
const double & currentPeriod,
const epicsTime & currentTime );

View File

@@ -38,6 +38,9 @@
extern epicsThreadPrivateId caClientContextId;
cacService * ca_client_context::pDefaultService = 0;
epicsMutex ca_client_context::defaultServiceInstallMutex;
ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
ca_exception_func ( 0 ), ca_exception_arg ( 0 ),
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ),
@@ -47,6 +50,22 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
{
static const unsigned short PORT_ANY = 0u;
if ( ! osiSockAttach () ) {
throwWithLocation ( noSocket () );
}
{
// this wont consistently work if called from file scope constructor
epicsGuard < epicsMutex > guard ( ca_client_context::defaultServiceInstallMutex );
if ( ca_client_context::pDefaultService ) {
this->pServiceContext.reset (
& ca_client_context::pDefaultService->contextCreate ( this->mutex, *this ) );
}
else {
this->pServiceContext.reset ( new cac ( this->mutex, *this ) );
}
}
this->sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( this->sock == INVALID_SOCKET ) {
char sockErrBuf[64];
@@ -113,9 +132,6 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
this->localPort = epicsNTOH16 ( tmpAddr.ia.sin_port );
}
epics_auto_ptr < cac > pCAC (
new cac ( *this ) );
epics_auto_ptr < epicsGuard < epicsMutex > > pCBGuard;
if ( ! enablePreemptiveCallback ) {
pCBGuard.reset ( new epicsGuard < epicsMutex > ( this->callbackMutex ) );
@@ -123,7 +139,6 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
// multiple steps ensure exception safety
this->pCallbackGuard = pCBGuard;
this->pClientCtx = pCAC;
}
ca_client_context::~ca_client_context ()
@@ -133,49 +148,75 @@ ca_client_context::~ca_client_context ()
( this->fdRegArg, this->sock, false );
}
epicsSocketDestroy ( this->sock );
osiSockRelease ();
// force a logical shutdown order
// so that the cac class does not hang its
// receive threads during their shutdown sequence
// and so that classes using this classes mutex
// are destroyed before the mutex is destroyed
if ( this->pCallbackGuard.get() ) {
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
this->pServiceContext.reset ( 0 );
}
else {
this->pServiceContext.reset ( 0 );
}
}
void ca_client_context::destroyChannel ( oldChannelNotify & chan )
{
chan.~oldChannelNotify ();
epicsGuard < epicsMutex > guard ( this->mutex );
chan.destructor ( guard );
this->oldChannelNotifyFreeList.release ( & chan );
}
void ca_client_context::destroyGetCopy ( getCopy & gc )
void ca_client_context::destroyGetCopy (
epicsGuard < epicsMutex > & guard, getCopy & gc )
{
guard.assertIdenticalMutex ( this->mutex );
gc.~getCopy ();
this->getCopyFreeList.release ( & gc );
}
void ca_client_context::destroyGetCallback ( getCallback & gcb )
void ca_client_context::destroyGetCallback (
epicsGuard < epicsMutex > & guard, getCallback & gcb )
{
guard.assertIdenticalMutex ( this->mutex );
gcb.~getCallback ();
this->getCallbackFreeList.release ( & gcb );
}
void ca_client_context::destroyPutCallback ( putCallback & pcb )
void ca_client_context::destroyPutCallback (
epicsGuard < epicsMutex > & guard, putCallback & pcb )
{
guard.assertIdenticalMutex ( this->mutex );
pcb.~putCallback ();
this->putCallbackFreeList.release ( & pcb );
}
void ca_client_context::destroySubscription ( oldSubscription & os )
void ca_client_context::destroySubscription (
epicsGuard < epicsMutex > & guard, oldSubscription & os )
{
guard.assertIdenticalMutex ( this->mutex );
os.~oldSubscription ();
this->subscriptionFreeList.release ( & os );
}
void ca_client_context::changeExceptionEvent ( caExceptionHandler *pfunc, void *arg )
void ca_client_context::changeExceptionEvent (
caExceptionHandler * pfunc, void * arg )
{
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
this->ca_exception_func = pfunc;
this->ca_exception_arg = arg;
// should block here until releated callback in progress completes
}
void ca_client_context::replaceErrLogHandler ( caPrintfFunc *ca_printf_func )
void ca_client_context::replaceErrLogHandler (
caPrintfFunc * ca_printf_func )
{
epicsGuard < ca_client_context_mutex > autoMutex ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
if ( ca_printf_func ) {
this->pVPrintfFunc = ca_printf_func;
}
@@ -185,16 +226,18 @@ void ca_client_context::replaceErrLogHandler ( caPrintfFunc *ca_printf_func )
// should block here until releated callback in progress completes
}
void ca_client_context::registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg )
void ca_client_context::registerForFileDescriptorCallBack (
CAFDHANDLER *pFunc, void *pArg )
{
epicsGuard < ca_client_context_mutex > autoMutex ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
this->fdRegFunc = pFunc;
this->fdRegArg = pArg;
this->fdRegFuncNeedsToBeCalled = true;
// should block here until releated callback in progress completes
}
int ca_client_context::printf ( const char *pformat, ... ) const
int ca_client_context::printf (
const char *pformat, ... ) const
{
va_list theArgs;
int status;
@@ -208,11 +251,12 @@ int ca_client_context::printf ( const char *pformat, ... ) const
return status;
}
int ca_client_context::vPrintf ( const char *pformat, va_list args ) const // X aCC 361
int ca_client_context::vPrintf (
const char *pformat, va_list args ) const // X aCC 361
{
caPrintfFunc *pFunc;
caPrintfFunc * pFunc;
{
epicsGuard < ca_client_context_mutex > autoMutex ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
pFunc = this->pVPrintfFunc;
}
if ( pFunc ) {
@@ -223,81 +267,137 @@ int ca_client_context::vPrintf ( const char *pformat, va_list args ) const // X
}
}
void ca_client_context::exception ( int stat, const char *pCtx,
const char *pFile, unsigned lineNo )
void ca_client_context::exception (
epicsGuard < epicsMutex > & guard, int stat, const char * pCtx,
const char * pFile, unsigned lineNo )
{
struct exception_handler_args args;
caExceptionHandler *pFunc;
void *pArg;
caExceptionHandler * pFunc = this->ca_exception_func;
void * pArg = this->ca_exception_arg;
{
epicsGuard < ca_client_context_mutex > autoMutex ( this->mutex );
pFunc = this->ca_exception_func;
pArg = this->ca_exception_arg;
}
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = NULL;
args.type = TYPENOTCONN;
args.count = 0;
args.addr = NULL;
args.stat = stat;
args.op = CA_OP_OTHER;
args.ctx = pCtx;
args.pFile = pFile;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
}
else {
this->pClientCtx->signal ( stat, pFile, lineNo, pCtx );
epicsGuardRelease < epicsMutex > unguard ( guard );
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = NULL;
args.type = TYPENOTCONN;
args.count = 0;
args.addr = NULL;
args.stat = stat;
args.op = CA_OP_OTHER;
args.ctx = pCtx;
args.pFile = pFile;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
}
else {
this->signal ( stat, pFile, lineNo, pCtx );
}
}
}
void ca_client_context::exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo, oldChannelNotify &chan,
void ca_client_context::exception (
epicsGuard < epicsMutex > & guard, int status, const char * pContext,
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
unsigned type, arrayElementCount count, unsigned op )
{
struct exception_handler_args args;
caExceptionHandler *pFunc;
void *pArg;
caExceptionHandler * pFunc = this->ca_exception_func;
void * pArg = this->ca_exception_arg;
{
epicsGuard < ca_client_context_mutex > autoMutex ( this->mutex );
pFunc = this->ca_exception_func;
pArg = this->ca_exception_arg;
epicsGuardRelease < epicsMutex > unguard ( guard );
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = &chan;
args.type = type;
args.count = count;
args.addr = NULL;
args.stat = status;
args.op = op;
args.ctx = pContext;
args.pFile = pFileName;
args.lineNo = lineNo;
args.usr = pArg;
( *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 <int> ( type ) ),
count, pContext );
}
}
}
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = &chan;
args.type = type;
args.count = count;
args.addr = NULL;
args.stat = status;
args.op = op;
args.ctx = pContext;
args.pFile = pFileName;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
void ca_client_context::signal ( int ca_status, const char * pfilenm,
int lineno, const char * pFormat, ... )
{
va_list theArgs;
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,
int lineno, const char *pFormat, va_list args )
{
static const char *severity[] =
{
"Warning",
"Success",
"Error",
"Info",
"Fatal",
"Fatal",
"Fatal",
"Fatal"
};
this->printf ( "CA.Client.Exception...............................................\n" );
this->printf ( " %s: \"%s\"\n",
severity[ CA_EXTRACT_SEVERITY ( ca_status ) ],
ca_message ( ca_status ) );
if ( pFormat ) {
this->printf ( " Context: \"" );
this->vPrintf ( pFormat, args );
this->printf ( "\"\n" );
}
else {
this->pClientCtx->signal ( status, pFileName, lineNo,
"op=%u, channel=%s, type=%s, count=%lu, ctx=\"%s\"",
op, ca_name ( &chan ),
dbr_type_to_text ( static_cast <int> ( type ) ),
count, pContext );
if ( pfilenm ) {
this->printf ( " Source File: %s line %d\n",
pfilenm, lineno );
}
epicsTime current = epicsTime::getCurrent ();
char date[64];
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
this->printf ( " Current Time: %s\n", date );
/*
* Terminate execution if unsuccessful
*/
if( ! ( ca_status & CA_M_SUCCESS ) &&
CA_EXTRACT_SEVERITY ( ca_status ) != CA_K_WARNING ){
errlogFlush ();
abort ();
}
this->printf ( "..................................................................\n" );
}
void ca_client_context::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
::printf ( "ca_client_context at %p pndRecvCnt=%u ioSeqNo=%u\n",
static_cast <const void *> ( this ),
this->pndRecvCnt, this->ioSeqNo );
if ( level > 0u ) {
this->mutex.show ( level - 1u );
this->pClientCtx->show ( level - 1u );
this->pServiceContext->show ( guard, level - 1u );
::printf ( "\tpreemptive callback is %s\n",
this->pCallbackGuard.get() ? "disabled" : "enabled" );
::printf ( "\tthere are %u unsatisfied IO operations blocking ca_pend_io()\n",
@@ -306,6 +406,8 @@ void ca_client_context::show ( unsigned level ) const
this->ioSeqNo );
::printf ( "IO done event:\n");
this->ioDone.show ( level - 1u );
::printf ( "Synchronous group identifier hash table:\n" );
this->sgTable.show ( level - 1u );
}
}
@@ -315,37 +417,26 @@ void ca_client_context::attachToClientCtx ()
epicsThreadPrivateSet ( caClientContextId, this );
}
void ca_client_context::incrementOutstandingIO ( unsigned ioSeqNoIn )
void ca_client_context::incrementOutstandingIO (
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
{
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
guard.assertIdenticalMutex ( this->mutex );
if ( this->ioSeqNo == ioSeqNoIn ) {
assert ( this->pndRecvCnt < UINT_MAX );
this->pndRecvCnt++;
}
}
void ca_client_context::decrementOutstandingIO ( unsigned ioSeqNoIn )
void ca_client_context::decrementOutstandingIO (
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
{
bool signalNeeded;
{
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
if ( this->ioSeqNo == ioSeqNoIn ) {
assert ( this->pndRecvCnt > 0u );
this->pndRecvCnt--;
if ( this->pndRecvCnt == 0u ) {
signalNeeded = true;
}
else {
signalNeeded = false;
}
guard.assertIdenticalMutex ( this->mutex );
if ( this->ioSeqNo == ioSeqNoIn ) {
assert ( this->pndRecvCnt > 0u );
this->pndRecvCnt--;
if ( this->pndRecvCnt == 0u ) {
this->ioDone.signal ();
}
else {
signalNeeded = false;
}
}
if ( signalNeeded ) {
this->ioDone.signal ();
}
}
@@ -367,7 +458,9 @@ int ca_client_context::pendIO ( const double & timeout )
epicsTime beg_time = epicsTime::getCurrent ();
double remaining = timeout;
this->flushRequest ();
epicsGuard < epicsMutex > guard ( this->mutex );
this->flush ( guard );
while ( this->pndRecvCnt > 0 ) {
if ( remaining < CAC_SIGNIFICANT_DELAY ) {
@@ -375,7 +468,10 @@ int ca_client_context::pendIO ( const double & timeout )
break;
}
this->blockForEventAndEnableCallbacks ( this->ioDone, remaining );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
this->blockForEventAndEnableCallbacks ( this->ioDone, remaining );
}
double delay = epicsTime::getCurrent () - beg_time;
if ( delay < timeout ) {
@@ -386,11 +482,8 @@ int ca_client_context::pendIO ( const double & timeout )
}
}
{
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
this->ioSeqNo++;
this->pndRecvCnt = 0u;
}
this->ioSeqNo++;
this->pndRecvCnt = 0u;
return status;
}
@@ -411,10 +504,16 @@ int ca_client_context::pendEvent ( const double & timeout )
epicsTime current = epicsTime::getCurrent ();
this->flushRequest ();
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->flush ( guard );
}
// process at least once if preemptive callback is disabled
if ( this->pCallbackGuard.get() ) {
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
epicsGuard < epicsMutex > guard ( this->mutex );
//
// This is needed because in non-preemptive callback mode
// legacy applications that use file descriptor managers
@@ -423,11 +522,11 @@ int ca_client_context::pendEvent ( const double & timeout )
// been read. We must guarantee that other threads get a
// chance to run if there is data in any of the sockets.
//
epicsGuardRelease < epicsMutex > unguardcb ( *this->pCallbackGuard );
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
if ( this->fdRegFunc ) {
epicsGuardRelease < ca_client_context_mutex > unguard ( guard );
// remove short udp message sent to wake up a file descriptor manager
epicsGuardRelease < epicsMutex > unguard ( guard );
// remove short udp message sent to wake
// up a file descriptor manager
osiSockAddr tmpAddr;
osiSocklen_t addrSize = sizeof ( tmpAddr.sa );
char buf = 0;
@@ -439,7 +538,7 @@ int ca_client_context::pendEvent ( const double & timeout )
}
this->noWakeupSincePend = true;
while ( this->callbackThreadsPending > 0 ) {
epicsGuardRelease < ca_client_context_mutex > unguard ( guard );
epicsGuardRelease < epicsMutex > unguard ( guard );
this->callbackThreadActivityComplete.wait ( 30.0 );
}
}
@@ -486,7 +585,7 @@ void ca_client_context::callbackLock ()
if ( this->pCallbackGuard.get() ) {
bool sendNeeded = false;
{
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
this->callbackThreadsPending++;
if ( this->fdRegFunc && this->noWakeupSincePend ) {
this->noWakeupSincePend = false;
@@ -517,7 +616,7 @@ void ca_client_context::callbackUnlock ()
if ( this->pCallbackGuard.get() ) {
bool signalNeeded = false;
{
epicsGuard < ca_client_context_mutex > guard ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
if ( this->callbackThreadsPending <= 1 ) {
if ( this->callbackThreadsPending == 1 ) {
this->callbackThreadsPending = 0;
@@ -537,71 +636,101 @@ void ca_client_context::callbackUnlock ()
void ca_client_context::changeConnCallBack (
caCh * pfunc, caCh * & pConnCallBack, const bool & currentlyConnected )
{
epicsGuard < epicsMutex > callbackGuard ( this->callbackMutex );
epicsGuard < epicsMutex > guard ( this->mutex );
if ( ! currentlyConnected ) {
if ( pfunc ) {
if ( ! pConnCallBack ) {
this->decrementOutstandingIO ( this->ioSeqNo );
this->decrementOutstandingIO ( guard, this->ioSeqNo );
}
}
else {
if ( pConnCallBack ) {
this->incrementOutstandingIO ( this->ioSeqNo );
this->incrementOutstandingIO ( guard, this->ioSeqNo );
}
}
}
pConnCallBack = pfunc;
}
void ca_client_context::registerService ( cacService &service )
cacChannel & ca_client_context::createChannel (
epicsGuard < epicsMutex > & guard, const char * pChannelName,
oldChannelNotify & chan, cacChannel::priLev pri )
{
this->pClientCtx->registerService ( service );
guard.assertIdenticalMutex ( this->mutex );
return this->pServiceContext->createChannel (
guard, pChannelName, chan, pri );
}
cacChannel & ca_client_context::createChannel ( const char * name_str,
oldChannelNotify & chan, cacChannel::priLev pri )
void ca_client_context::flush ( epicsGuard < epicsMutex > & guard )
{
return this->pClientCtx->createChannel ( name_str, chan, pri );
this->pServiceContext->flush ( guard );
}
void ca_client_context::flushRequest ()
unsigned ca_client_context::circuitCount () const
{
this->pClientCtx->flushRequest ();
}
unsigned ca_client_context::connectionCount () const
{
return this->pClientCtx->connectionCount ();
epicsGuard < epicsMutex > guard ( this->mutex );
return this->pServiceContext->circuitCount ( guard );
}
unsigned ca_client_context::beaconAnomaliesSinceProgramStart () const
{
return this->pClientCtx->beaconAnomaliesSinceProgramStart ();
epicsGuard < epicsMutex > guard ( this->mutex );
return this->pServiceContext->beaconAnomaliesSinceProgramStart ( guard );
}
CASG * ca_client_context::lookupCASG ( unsigned id )
void ca_client_context::installCASG (
epicsGuard < epicsMutex > & guard, CASG & sg )
{
return this->pClientCtx->lookupCASG ( id );
guard.assertIdenticalMutex ( this->mutex );
this->sgTable.add ( sg );
}
void ca_client_context::installCASG ( CASG &sg )
void ca_client_context::uninstallCASG (
epicsGuard < epicsMutex > & guard, CASG & sg )
{
this->pClientCtx->installCASG ( sg );
guard.assertIdenticalMutex ( this->mutex );
this->sgTable.remove ( sg );
}
void ca_client_context::uninstallCASG ( CASG &sg )
CASG * ca_client_context::lookupCASG (
epicsGuard < epicsMutex > & guard, unsigned idIn )
{
this->pClientCtx->uninstallCASG ( sg );
guard.assertIdenticalMutex ( this->mutex );
CASG * psg = this->sgTable.lookup ( idIn );
if ( psg ) {
if ( ! psg->verify ( guard ) ) {
psg = 0;
}
}
return psg;
}
void ca_client_context::vSignal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args )
void ca_client_context::selfTest () const
{
this->pClientCtx->vSignal ( ca_status, pfilenm,
lineno, pFormat, args );
epicsGuard < epicsMutex > guard ( this->mutex );
this->sgTable.verify ();
this->pServiceContext->selfTest ( guard );
}
void ca_client_context::selfTest ()
epicsMutex & ca_client_context::mutexRef () const
{
this->pClientCtx->selfTest ();
return this->mutex;
}
cacContext & ca_client_context::createNetworkContext ( epicsMutex & mutex )
{
return * new cac ( mutex, *this );
}
void epicsShareAPI caInstallDefaultService ( cacService & service )
{
// this wont consistently work if called from file scope constructor
epicsGuard < epicsMutex > guard ( ca_client_context::defaultServiceInstallMutex );
if ( ca_client_context::pDefaultService ) {
throw std::logic_error ( "CA in-memory service already installed and can't be replaced");
}
ca_client_context::pDefaultService = & service;
}

File diff suppressed because it is too large Load Diff

View File

@@ -60,9 +60,12 @@ class netSubscription;
// is applied
class cacRecycle { // X aCC 655
public:
virtual void recycleReadNotifyIO ( netReadNotifyIO &io ) = 0;
virtual void recycleWriteNotifyIO ( netWriteNotifyIO &io ) = 0;
virtual void recycleSubscription ( netSubscription &io ) = 0;
virtual void recycleReadNotifyIO (
epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0;
virtual void recycleWriteNotifyIO (
epicsGuard < epicsMutex > &, netWriteNotifyIO &io ) = 0;
virtual void recycleSubscription (
epicsGuard < epicsMutex > &, netSubscription &io ) = 0;
};
struct CASG;
@@ -72,15 +75,6 @@ struct caHdrLargeArray;
extern epicsThreadPrivateId caClientCallbackThreadId;
class cacMutex {
public:
void lock ();
void unlock ();
void show ( unsigned level ) const;
private:
epicsMutex mutex;
};
class cacComBufMemoryManager : public comBufMemoryManager
{
public:
@@ -95,82 +89,98 @@ public:
virtual void disconnectChannel (
const epicsTime & currentTime,
epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > &, nciu & chan ) = 0;
epicsGuard < epicsMutex > &, nciu & chan ) = 0;
};
class callbackMutex {
public:
callbackMutex ( cacNotify & );
callbackMutex ( cacContextNotify & );
~callbackMutex ();
void lock ();
void unlock ();
private:
cacNotify & notify;
cacContextNotify & notify;
callbackMutex ( callbackMutex & );
callbackMutex & operator = ( callbackMutex & );
};
class cac : private cacRecycle, private cacDisconnectChannelPrivate,
class cac :
public cacContext,
private cacRecycle,
private cacDisconnectChannelPrivate,
private callbackForMultiplyDefinedPV
{
public:
cac ( cacNotify & );
cac ( epicsMutex &, cacContextNotify & );
virtual ~cac ();
// beacon management
void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime,
ca_uint32_t beaconNumber, unsigned protocolRevision );
void repeaterSubscribeConfirmNotify ();
unsigned beaconAnomaliesSinceProgramStart () const;
unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const;
// IO management
void flushRequest ();
void flush ( epicsGuard < epicsMutex > & guard );
bool executeResponse ( epicsGuard < callbackMutex > &, tcpiiu &,
const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody );
// channel routines
bool transferChanToVirtCircuit (
epicsGuard < callbackMutex > &,
unsigned cid, unsigned sid,
ca_uint16_t typeCode, arrayElementCount count,
unsigned minorVersionNumber, const osiSockAddr & );
void connectAllIO ( epicsGuard < cacMutex > &, nciu & chan );
void destroyChannel ( nciu & );
cacChannel & createChannel ( const char *name_str,
cacChannelNotify &chan, cacChannel::priLev pri );
void registerService ( cacService &service );
void initiateConnect ( nciu & );
epicsGuard < callbackMutex > &,
unsigned cid, unsigned sid,
ca_uint16_t typeCode, arrayElementCount count,
unsigned minorVersionNumber, const osiSockAddr & );
cacChannel & createChannel (
epicsGuard < epicsMutex > & guard, const char * pChannelName,
cacChannelNotify &, cacChannel::priLev );
void destroyChannel (
epicsGuard < epicsMutex > &, nciu & );
void initiateConnect (
epicsGuard < epicsMutex > &, nciu & );
// IO requests
void writeRequest ( nciu &, unsigned type,
void writeRequest ( epicsGuard < epicsMutex > &, nciu &, unsigned type,
arrayElementCount nElem, const void * pValue );
cacChannel::ioid writeNotifyRequest ( nciu &, unsigned type,
arrayElementCount nElem, const void *pValue, cacWriteNotify & );
cacChannel::ioid readNotifyRequest ( nciu &, unsigned type,
arrayElementCount nElem, cacReadNotify & );
cacChannel::ioid subscriptionRequest ( nciu &, unsigned type,
arrayElementCount nElem, unsigned mask, cacStateNotify & );
void ioCancel ( nciu & chan, const cacChannel::ioid & id );
netWriteNotifyIO & writeNotifyRequest (
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
unsigned type, arrayElementCount nElem, const void * pValue,
cacWriteNotify & );
netReadNotifyIO & readNotifyRequest (
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
unsigned type, arrayElementCount nElem,
cacReadNotify & );
netSubscription & subscriptionRequest (
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
unsigned type, arrayElementCount nElem, unsigned mask,
cacStateNotify & );
baseNMIU * destroyIO (
epicsGuard < epicsMutex > & guard,
const cacChannel::ioid & idIn,
nciu & chan );
void disconnectAllIO (
epicsGuard < callbackMutex > &,
epicsGuard < epicsMutex > &,
nciu &, tsDLList < baseNMIU > & ioList );
void ioShow ( const cacChannel::ioid &id, unsigned level ) const;
// sync group routines
CASG * lookupCASG ( unsigned id );
void installCASG ( CASG & );
void uninstallCASG ( CASG & );
CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id );
void installCASG ( epicsGuard < epicsMutex > &, CASG & );
void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & );
// exception generation
void exception ( epicsGuard < callbackMutex > &, int status, const char * pContext,
void exception ( epicsGuard < callbackMutex > &,
int status, const char * pContext,
const char * pFileName, unsigned lineNo );
// diagnostics
unsigned connectionCount () const;
void show ( unsigned level ) const;
unsigned circuitCount ( epicsGuard < epicsMutex > & ) const;
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
int printf ( const char *pformat, ... ) const;
int vPrintf ( const char *pformat, va_list args ) const;
void signal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, ... );
void vSignal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args );
// buffer management
char * allocateSmallBufferTCP ();
@@ -182,20 +192,18 @@ public:
// misc
const char * userNamePointer () const;
unsigned getInitializingThreadsPriority () const;
cacMutex & mutexRef ();
epicsMutex & mutexRef ();
void attachToClientCtx ();
void selfTest () const;
void selfTest ( epicsGuard < epicsMutex > & ) const;
double beaconPeriod ( const nciu & chan ) const;
static unsigned lowestPriorityLevelAbove ( unsigned priority );
static unsigned highestPriorityLevelBelow ( unsigned priority );
void initiateAbortShutdown ( tcpiiu & );
void unresponsiveCircuitNotify ( tcpiiu & );
void disconnectNotify ( tcpiiu & );
void destroyIIU ( tcpiiu & iiu );
void flushIfRequired ( epicsGuard < epicsMutex > &, netiiu & );
private:
localHostName hostNameCache;
cacServiceList services;
chronIntIdResTable < nciu > chanTable;
//
// !!!! There is at this point no good reason
@@ -210,7 +218,6 @@ private:
// !!!! terms of detecting damaged protocol.
//
chronIntIdResTable < baseNMIU > ioTable;
chronIntIdResTable < CASG > sgTable;
resTable < bhe, inetAddrID > beaconTable;
resTable < tcpiiu, caServerID > serverTable;
tsDLList < tcpiiu > serverList;
@@ -226,7 +233,9 @@ private:
tsFreeList
< class netSubscription, 1024, epicsMutexNOOP >
freeListSubscription;
tsFreeList < nciu, 1024 > channelFreeList;
tsFreeList
< class nciu, 1024, epicsMutexNOOP >
channelFreeList;
tsFreeList
< class msgForMultiplyDefinedPV, 16 >
mdpvFreeList;
@@ -238,53 +247,41 @@ private:
// callback lock must always be acquired before
// the primary mutex if both locks are needed
callbackMutex cbMutex;
mutable cacMutex mutex;
mutable epicsMutex & mutex;
epicsEvent iiuUninstall;
epicsSingleton
< cacServiceList >::reference
globalServiceList;
ipAddrToAsciiEngine & ipToAEngine;
ipAddrToAsciiEngine & ipToAEngine;
epicsTimerQueueActive & timerQueue;
char * pUserName;
class udpiiu * pudpiiu;
void * tcpSmallRecvBufFreeList;
void * tcpLargeRecvBufFreeList;
cacNotify & notify;
cacContextNotify & notify;
epicsThreadId initializingThreadsId;
unsigned initializingThreadsPriority;
unsigned maxRecvBytesTCP;
unsigned beaconAnomalyCount;
void run ();
void disconnectAllIO ( epicsGuard < cacMutex > & locker, nciu & chan, bool enableCallbacks );
void flushIfRequired ( epicsGuard < cacMutex > &, netiiu & );
void recycleReadNotifyIO ( netReadNotifyIO &io );
void recycleWriteNotifyIO ( netWriteNotifyIO &io );
void recycleSubscription ( netSubscription &io );
void recycleReadNotifyIO (
epicsGuard < epicsMutex > &, netReadNotifyIO &io );
void recycleWriteNotifyIO (
epicsGuard < epicsMutex > &, netWriteNotifyIO &io );
void recycleSubscription (
epicsGuard < epicsMutex > &, netSubscription &io );
void disconnectChannel (
const epicsTime & currentTime,
epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > &, nciu & chan );
epicsGuard < epicsMutex > &, nciu & chan );
void ioCompletionNotify ( unsigned id, unsigned type,
arrayElementCount count, const void *pData );
void ioExceptionNotify ( unsigned id,
int status, const char *pContext );
void ioExceptionNotify ( unsigned id, int status,
const char *pContext, unsigned type, arrayElementCount count );
const char * pContext, unsigned type, arrayElementCount count );
void ioExceptionNotifyAndUninstall ( unsigned id, int status,
const char * pContext, unsigned type, arrayElementCount count );
void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
const char * pChannelName, const char * pAcc, const char * pRej );
void ioCompletionNotifyAndDestroy ( unsigned id );
void ioCompletionNotifyAndDestroy ( unsigned id,
unsigned type, arrayElementCount count, const void *pData );
void ioExceptionNotifyAndDestroy ( unsigned id,
int status, const char *pContext );
void ioExceptionNotifyAndDestroy ( unsigned id,
int status, const char *pContext, unsigned type, arrayElementCount count );
// recv protocol stubs
bool versionAction ( epicsGuard < callbackMutex > &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
@@ -304,7 +301,7 @@ private:
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool accessRightsRespAction ( epicsGuard < callbackMutex > &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool claimCIURespAction ( epicsGuard < callbackMutex > &, tcpiiu &,
bool createChannelRespAction ( epicsGuard < callbackMutex > &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool verifyAndDisconnectChan ( epicsGuard < callbackMutex > &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
@@ -349,17 +346,11 @@ inline unsigned cac::getInitializingThreadsPriority () const
return this->initializingThreadsPriority;
}
inline cacMutex & cac::mutexRef ()
inline epicsMutex & cac::mutexRef ()
{
return this->mutex;
}
inline void cac::exception ( epicsGuard < callbackMutex > &, int status,
const char *pContext, const char *pFileName, unsigned lineNo )
{
this->notify.exception ( status, pContext, pFileName, lineNo );
}
inline int cac::vPrintf ( const char *pformat, va_list args ) const
{
return this->notify.vPrintf ( pformat, args );
@@ -399,27 +390,14 @@ inline void cac::releaseLargeBufferTCP ( char *pBuf )
freeListFree ( this->tcpLargeRecvBufFreeList, pBuf );
}
inline unsigned cac::beaconAnomaliesSinceProgramStart () const
inline unsigned cac::beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return this->beaconAnomalyCount;
}
inline void cacMutex::lock ()
{
this->mutex.lock ();
}
inline void cacMutex::unlock ()
{
this->mutex.unlock ();
}
inline void cacMutex::show ( unsigned level ) const
{
this->mutex.show ( level );
}
inline callbackMutex::callbackMutex ( cacNotify & notifyIn ) :
inline callbackMutex::callbackMutex ( cacContextNotify & notifyIn ) :
notify ( notifyIn )
{
}

View File

@@ -104,5 +104,8 @@ void cacChannel::operator delete ( void * )
__FILE__, __LINE__ );
}
cacContext::~cacContext () {}
cacService::~cacService () {}

View File

@@ -27,15 +27,15 @@
#include "cacIO.h"
#undef epicsExportSharedSymbols
cacNotify::~cacNotify ()
cacContextNotify::~cacContextNotify ()
{
}
void cacNotify::callbackLock ()
void cacContextNotify::callbackLock ()
{
}
void cacNotify::callbackUnlock ()
void cacContextNotify::callbackUnlock ()
{
}

View File

@@ -55,6 +55,7 @@
#include "tsDLList.h"
#include "epicsMutex.h"
#include "epicsGuard.h"
#include "epicsSingleton.h"
#ifdef cacIOh_restore_epicsExportSharedSymbols
@@ -72,9 +73,11 @@ typedef unsigned long arrayElementCount;
class epicsShareClass cacWriteNotify { // X aCC 655
public:
virtual ~cacWriteNotify () = 0;
virtual void completion () = 0;
virtual void completion ( epicsGuard < epicsMutex > & ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void exception ( int status, const char *pContext,
virtual void exception (
epicsGuard < epicsMutex > &,
int status, const char * pContext,
unsigned type, arrayElementCount count ) = 0;
};
@@ -83,11 +86,14 @@ public:
class epicsShareClass cacReadNotify { // X aCC 655
public:
virtual ~cacReadNotify () = 0;
virtual void completion ( unsigned type,
arrayElementCount count, const void *pData ) = 0;
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 ( int status,
const char *pContext, unsigned type, arrayElementCount count ) = 0;
virtual void exception (
epicsGuard < epicsMutex > &, int status,
const char * pContext, unsigned type,
arrayElementCount count ) = 0;
};
// 1) this should not be passing caerr.h status to the exception callback
@@ -95,11 +101,14 @@ public:
class epicsShareClass cacStateNotify { // X aCC 655
public:
virtual ~cacStateNotify () = 0;
virtual void current ( unsigned type,
arrayElementCount count, const void *pData ) = 0;
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 ( int status,
const char *pContext, unsigned type, arrayElementCount count ) = 0;
virtual void exception (
epicsGuard < epicsMutex > &, int status,
const char *pContext, unsigned type,
arrayElementCount count ) = 0;
};
class caAccessRights {
@@ -126,16 +135,20 @@ private:
class epicsShareClass cacChannelNotify { // X aCC 655
public:
virtual ~cacChannelNotify () = 0;
virtual void connectNotify () = 0;
virtual void disconnectNotify () = 0;
virtual void connectNotify ( epicsGuard < epicsMutex > & ) = 0;
virtual void disconnectNotify ( epicsGuard < epicsMutex > & ) = 0;
virtual void serviceShutdownNotify () = 0;
virtual void accessRightsNotify ( const caAccessRights & ) = 0;
virtual void exception ( int status, const char *pContext ) = 0;
virtual void accessRightsNotify (
epicsGuard < epicsMutex > &, const caAccessRights & ) = 0;
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 ( int status, const char *pContext,
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 ( int status, const char *pContext,
virtual void writeException (
epicsGuard < epicsMutex > &, int status, const char * pContext,
unsigned type, arrayElementCount count ) = 0;
};
@@ -161,20 +174,33 @@ public:
cacChannel ( cacChannelNotify & );
cacChannelNotify & notify () const;
virtual void destroy () = 0;
virtual void destroy (
epicsGuard < epicsMutex > & ) = 0;
virtual const char * pName () const = 0; // not thread safe
virtual void show ( unsigned level ) const = 0;
virtual void initiateConnect () = 0;
virtual ioStatus read ( unsigned type, arrayElementCount count,
virtual void show (
unsigned level ) const = 0;
virtual void initiateConnect (
epicsGuard < epicsMutex > & ) = 0;
virtual ioStatus read (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
cacReadNotify &, ioid * = 0 ) = 0;
virtual void write ( unsigned type, arrayElementCount count,
virtual void write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue ) = 0;
virtual ioStatus write ( unsigned type, arrayElementCount count,
virtual ioStatus write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue, cacWriteNotify &, ioid * = 0 ) = 0;
virtual void subscribe ( unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &, ioid * = 0 ) = 0;
virtual void ioCancel ( const ioid & ) = 0;
virtual void ioShow ( const ioid &, unsigned level ) const = 0;
virtual void subscribe (
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, unsigned mask, cacStateNotify &,
ioid * = 0 ) = 0;
virtual void ioCancel (
epicsGuard < epicsMutex > &, const ioid & ) = 0;
virtual void ioShow (
const ioid &, unsigned level ) const = 0;
virtual short nativeType () const = 0;
virtual arrayElementCount nativeElementCount () const = 0;
virtual caAccessRights accessRights () const; // defaults to unrestricted access
@@ -211,15 +237,36 @@ private:
void operator delete ( void * );
};
class cacNotify { // X aCC 655
class epicsShareClass cacContext { // X aCC 655
public:
virtual ~cacNotify () = 0;
virtual ~cacContext ();
virtual cacChannel & createChannel (
epicsGuard < epicsMutex > &,
const char * pChannelName, cacChannelNotify &,
cacChannel::priLev = cacChannel::priorityDefault ) = 0;
virtual void flush (
epicsGuard < epicsMutex > & ) = 0;
virtual unsigned circuitCount (
epicsGuard < epicsMutex > & ) const = 0;
virtual void selfTest (
epicsGuard < epicsMutex > & ) const = 0;
virtual unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const = 0;
virtual void show (
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
};
class epicsShareClass cacContextNotify { // X aCC 655
public:
virtual ~cacContextNotify () = 0;
virtual cacContext & createNetworkContext ( epicsMutex & ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void exception ( 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 vPrintf ( const char *pformat, va_list args ) const = 0;
// backwards compatibility
virtual int vPrintf ( const char * pformat, va_list args ) const = 0;
// backwards compatibility (from here down)
virtual void attachToClientCtx () = 0;
virtual void blockForEventAndEnableCallbacks (
class epicsEvent & event, const double & timeout ) = 0;
@@ -227,34 +274,14 @@ public:
virtual void callbackUnlock () = 0;
};
class cacService : public tsDLNode < cacService > { // X aCC 655
class epicsShareClass cacService {
public:
virtual cacChannel * createChannel (
const char *pName, cacChannelNotify &,
cacChannel::priLev = cacChannel::priorityDefault ) = 0;
virtual void show ( unsigned level ) const = 0;
virtual ~cacService () = 0;
virtual cacContext & contextCreate (
epicsMutex &, cacContextNotify & ) = 0;
};
class cacServiceList {
public:
epicsShareFunc cacServiceList ();
epicsShareFunc void registerService ( cacService &service );
epicsShareFunc cacChannel * createChannel (
const char *pName, cacChannelNotify &,
cacChannel::priLev = cacChannel::priorityDefault );
epicsShareFunc void show ( unsigned level ) const;
private:
tsDLList < cacService > services;
mutable epicsMutex mutex;
cacServiceList ( const cacServiceList & );
cacServiceList & operator = ( const cacServiceList & );
};
template < class T > class epicsSingleton;
epicsShareExtern epicsSingleton < cacServiceList > globalServiceListCAC;
epicsShareFunc int epicsShareAPI ca_register_service ( cacService *pService );
epicsShareFunc void epicsShareAPI caInstallDefaultService ( cacService & service );
inline cacChannel::cacChannel ( cacChannelNotify & notify ) :
callback ( notify )

View File

@@ -1,71 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* 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.
\*************************************************************************/
/*
* $Id$
*
*
* 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
*/
#include "epicsSingleton.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "epicsGuard.h"
#include "cacIO.h"
epicsShareDef epicsSingleton < cacServiceList > globalServiceListCAC;
cacServiceList::cacServiceList ()
{
}
void cacServiceList::registerService ( cacService &service )
{
epicsGuard < epicsMutex > locker ( this->mutex );
this->services.add ( service );
}
cacChannel * cacServiceList::createChannel (
const char * pName, cacChannelNotify & chan, cacChannel::priLev pri )
{
cacChannel *pChanIO = 0;
epicsGuard < epicsMutex > locker ( this->mutex );
tsDLIter < cacService > iter = this->services.firstIter ();
while ( iter.valid () ) {
pChanIO = iter->createChannel ( pName, chan, pri );
if ( pChanIO ) {
break;
}
iter++;
}
return pChanIO;
}
void cacServiceList::show ( unsigned level ) const
{
epicsGuard < epicsMutex > locker ( this->mutex );
tsDLIterConst < cacService > iter = this->services.firstIter ();
while ( iter.valid () ) {
iter->show ( level );
iter++;
}
}

View File

@@ -53,6 +53,8 @@ void bheFreeStoreMgr::release ( void * pCadaver )
int main ( int argc, char ** argv )
{
epicsMutex mutex;
epicsGuard < epicsMutex > guard ( mutex );
bheFreeStoreMgr bheFreeList;
epicsTime programBeginTime = epicsTime::getCurrent ();
bool validCommandLine = false;
@@ -241,8 +243,9 @@ int main ( int argc, char ** argv )
*/
bhe *pBHE = beaconTable.lookup ( ina );
if ( pBHE ) {
epicsTime previousTime = pBHE->updateTime ();
bool anomaly = pBHE->updatePeriod ( programBeginTime,
epicsTime previousTime = pBHE->updateTime ( guard );
bool anomaly = pBHE->updatePeriod (
guard, programBeginTime,
currentTime, beaconNumber, protocolRevision );
if ( anomaly ) {
char date[64];
@@ -254,7 +257,8 @@ int main ( int argc, char ** argv )
host, date );
if ( interest > 0 ) {
printf ( "\testimate=%f current=%f\n",
pBHE->period (), currentTime - previousTime );
pBHE->period ( guard ),
currentTime - previousTime );
}
fflush(stdout);
}
@@ -268,7 +272,7 @@ int main ( int argc, char ** argv )
* shortly after the program started up)
*/
pBHE = new ( bheFreeList )
bhe ( currentTime, beaconNumber, ina );
bhe ( mutex, currentTime, beaconNumber, ina );
if ( pBHE ) {
if ( beaconTable.add ( *pBHE ) < 0 ) {
pBHE->~bhe ();

View File

@@ -321,10 +321,13 @@ void comQueSend::insertRequestHeader (
}
void comQueSend::insertRequestWithPayLoad (
ca_uint16_t request, unsigned dataType, ca_uint32_t nElem,
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
ca_uint32_t cid, ca_uint32_t requestDependent,
const void * pPayload, bool v49Ok )
{
if ( INVALID_DB_REQ ( dataType ) ) {
throw cacChannel::badType ();
}
if ( dataType >= comQueSendCopyDispatchSize ) {
throw cacChannel::badType();
}
@@ -353,24 +356,28 @@ void comQueSend::insertRequestWithPayLoad (
}
}
else {
unsigned maxBytes;
arrayElementCount maxBytes;
if ( v49Ok ) {
maxBytes = 0xffffffff;
}
else {
maxBytes = MAX_TCP - sizeof ( caHdr );
}
unsigned maxElem =
arrayElementCount maxElem =
( maxBytes - sizeof (dbr_double_t) - dbr_size[dataType] ) /
dbr_value_size[dataType];
if ( nElem >= maxElem ) {
throw cacChannel::outOfBounds();
}
size = dbr_size_n ( dataType, nElem );
// the above checks verify that the total size
// is lest that 0xffffffff
size = static_cast < ca_uint32_t >
( dbr_size_n ( dataType, nElem ) );
payloadSize = CA_MESSAGE_ALIGN ( size );
this->insertRequestHeader ( request, payloadSize,
static_cast <ca_uint16_t> ( dataType ),
nElem, cid, requestDependent, v49Ok );
static_cast < ca_uint32_t > ( nElem ),
cid, requestDependent, v49Ok );
( this->*dbrCopyVector [dataType] ) ( pPayload, nElem );
}
// set pad bytes to nill

View File

@@ -41,7 +41,7 @@ template < class T > class epicsGuard;
class comQueSendMsgMinder {
public:
comQueSendMsgMinder (
class comQueSend &, epicsGuard < cacMutex > & );
class comQueSend &, epicsGuard < epicsMutex > & );
~comQueSendMsgMinder ();
void commit ();
private:
@@ -69,7 +69,7 @@ public:
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
ca_uint32_t requestDependent, bool v49Ok );
void insertRequestWithPayLoad (
ca_uint16_t request, unsigned dataType, ca_uint32_t nElem,
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
ca_uint32_t cid, ca_uint32_t requestDependent,
const void * pPayload, bool v49Ok );
comBuf * popNextComBufToSend ();
@@ -157,7 +157,7 @@ private:
extern const char cacNillBytes[];
inline comQueSendMsgMinder::comQueSendMsgMinder (
class comQueSend & sendQueIn, epicsGuard < cacMutex > & ) :
class comQueSend & sendQueIn, epicsGuard < epicsMutex > & ) :
pSendQue ( & sendQueIn )
{
sendQueIn.beginMsg ();

View File

@@ -0,0 +1,57 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* 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.
\*************************************************************************/
//
// $Id$
//
// 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: Jeff Hill
//
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#define epicsExportSharedSymbols
#include "disconnectGovernorTimer.h"
#include "udpiiu.h"
static const double period = 10.0; // sec
disconnectGovernorTimer::disconnectGovernorTimer (
udpiiu & iiuIn, epicsTimerQueue & queueIn ) :
timer ( queueIn.createTimer () ),
iiu ( iiuIn )
{
this->timer.start ( *this, period );
}
disconnectGovernorTimer::~disconnectGovernorTimer ()
{
this->timer.destroy ();
}
void disconnectGovernorTimer::shutdown ()
{
this->timer.cancel ();
}
epicsTimerNotify::expireStatus disconnectGovernorTimer::expire ( const epicsTime & currentTime ) // X aCC 361
{
this->iiu.govExpireNotify ( currentTime );
return expireStatus ( restart, period );
}
void disconnectGovernorTimer::show ( unsigned /* level */ ) const
{
}

View File

@@ -0,0 +1,60 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* 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.
\*************************************************************************/
//
// $Id$
//
//
// 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 disconnectGovernorTimerh
#define disconnectGovernorTimerh
#ifdef epicsExportSharedSymbols
# define searchTimerh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "epicsMutex.h"
#include "epicsGuard.h"
#include "epicsTimer.h"
#ifdef searchTimerh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include "caProto.h"
class disconnectGovernorTimer : private epicsTimerNotify {
public:
disconnectGovernorTimer ( class udpiiu &, epicsTimerQueue & );
virtual ~disconnectGovernorTimer ();
void show ( unsigned level ) const;
void shutdown ();
private:
epicsTimer & timer;
class udpiiu & iiu;
epicsTimerNotify::expireStatus expire ( const epicsTime & currentTime );
disconnectGovernorTimer ( const disconnectGovernorTimer & );
disconnectGovernorTimer & operator = ( const disconnectGovernorTimer & );
};
#endif // ifdef disconnectGovernorTimerh

View File

@@ -31,7 +31,7 @@
#include "iocinf.h"
#include "oldAccess.h"
getCallback::getCallback ( oldChannelNotify &chanIn,
getCallback::getCallback ( oldChannelNotify & chanIn,
caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn )
{
@@ -42,34 +42,44 @@ getCallback::~getCallback ()
}
void getCallback::completion (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount count, const void *pData )
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.chid = & this->chan;
args.type = type;
args.count = count;
args.status = ECA_NORMAL;
args.dbr = pData;
( *this->pFunc ) ( args );
this->chan.getClientCtx().destroyGetCallback ( *this );
caEventCallBackFunc * pFuncTmp = this->pFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) ( args );
}
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
}
void getCallback::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * /* pContext */,
unsigned type, arrayElementCount count )
{
if ( status != ECA_CHANDESTROY ) {
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.chid = & this->chan;
args.type = type;
args.count = count;
args.status = status;
args.dbr = 0;
( *this->pFunc ) ( args );
caEventCallBackFunc * pFuncTmp = this->pFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) ( args );
}
}
this->chan.getClientCtx().destroyGetCallback ( *this );
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
}
void * getCallback::operator new ( size_t ) // X aCC 361

View File

@@ -34,12 +34,15 @@
#include "oldAccess.h"
#include "cac.h"
getCopy::getCopy ( ca_client_context &cacCtxIn, oldChannelNotify &chanIn,
unsigned typeIn, arrayElementCount countIn, void *pValueIn ) :
getCopy::getCopy (
epicsGuard < epicsMutex > & guard, ca_client_context & cacCtxIn,
oldChannelNotify & chanIn, unsigned typeIn,
arrayElementCount countIn, void * pValueIn ) :
count ( countIn ), cacCtx ( cacCtxIn ), chan ( chanIn ), pValue ( pValueIn ),
ioSeqNo ( cacCtxIn.sequenceNumberOfOutstandingIO () ), type ( typeIn )
ioSeqNo ( 0 ), type ( typeIn )
{
cacCtxIn.incrementOutstandingIO ( cacCtxIn.sequenceNumberOfOutstandingIO () );
this->ioSeqNo = cacCtxIn.sequenceNumberOfOutstandingIO ( guard );
cacCtxIn.incrementOutstandingIO ( guard, this->ioSeqNo );
}
getCopy::~getCopy ()
@@ -48,34 +51,37 @@ getCopy::~getCopy ()
void getCopy::cancel ()
{
this->cacCtx.decrementOutstandingIO ( this->ioSeqNo );
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
}
void getCopy::completion ( unsigned typeIn,
void getCopy::completion (
epicsGuard < epicsMutex > & guard, unsigned typeIn,
arrayElementCount countIn, const void *pDataIn )
{
if ( this->type == typeIn ) {
unsigned size = dbr_size_n ( typeIn, countIn );
memcpy ( this->pValue, pDataIn, size );
this->cacCtx.decrementOutstandingIO ( this->ioSeqNo );
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
}
else {
this->exception ( ECA_INTERNAL,
this->exception ( guard, ECA_INTERNAL,
"bad data type match in get copy back response",
typeIn, countIn);
}
this->cacCtx.destroyGetCopy ( *this );
this->cacCtx.destroyGetCopy ( guard, *this );
}
void getCopy::exception (
epicsGuard < epicsMutex > & guard,
int status, const char *pContext, unsigned /* typeIn */, arrayElementCount /* countIn */ )
{
if ( status != ECA_CHANDESTROY ) {
this->cacCtx.exception ( status, pContext,
this->cacCtx.exception ( guard, status, pContext,
__FILE__, __LINE__, this->chan, this->type,
this->count, CA_OP_GET );
}
this->cacCtx.destroyGetCopy ( *this );
this->cacCtx.destroyGetCopy ( guard, *this );
}
void getCopy::show ( unsigned level ) const

View File

@@ -27,9 +27,6 @@
#include <string.h>
#if 0
#include "iocinf.h"
#endif
#include "hostNameCache.h"
#include "epicsGuard.h"

View File

@@ -47,16 +47,13 @@ nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn,
const char *pNameIn, cacChannel::priLev pri ) :
cacChannel ( chanIn ),
cacCtx ( cacIn ),
piiu ( &iiuIn ),
piiu ( & iiuIn ),
sid ( UINT_MAX ),
count ( 0 ),
retry ( 0u ),
nameLength ( 0u ),
typeCode ( USHRT_MAX ),
priority ( static_cast <ca_uint8_t> ( pri ) ),
f_connected ( false ),
f_createChanReqSent ( false ),
f_createChanRespReceived ( false )
priority ( static_cast <ca_uint8_t> ( pri ) )
{
size_t nameLengthTmp = strlen ( pNameIn ) + 1;
@@ -77,13 +74,31 @@ nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn,
nciu::~nciu ()
{
delete [] this->pNameStr;
}
void nciu::destroy ()
void nciu::destructor ( epicsGuard < epicsMutex > & guard )
{
// care is taken so that a lock is not applied during this phase
this->cacCtx.destroyChannel ( *this );
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
// Send any side effect IO requests w/o holding the callback lock so that
// we do not dead lock.
// There is special protection in this routine that prevents blocking if
// this is the tcp receive thread.
// must not hold callback lock here
this->cacCtx.flushIfRequired ( guard, *this->piiu );
while ( baseNMIU * pNetIO = this->eventq.first () ) {
assert ( this->cacCtx.destroyIO ( guard,
pNetIO->getId (), *this ) );
}
delete [] this->pNameStr;
this->~nciu ();
}
#pragma message ("audit all callback mutex locks to verify that they dont occur at inappropriate times in the main thread?" )
// called virtually
void nciu::destroy ( epicsGuard < epicsMutex > & guard )
{
// must not hold callback lock here
this->cacCtx.destroyChannel ( guard, *this );
}
void * nciu::operator new ( size_t ) // X aCC 361
@@ -104,30 +119,18 @@ void nciu::operator delete ( void * )
__FILE__, __LINE__ );
}
void nciu::initiateConnect ()
void nciu::initiateConnect (
epicsGuard < epicsMutex > & guard )
{
this->cacCtx.initiateConnect ( *this );
this->cacCtx.initiateConnect ( guard, *this );
}
void nciu::connect ( unsigned nativeType,
unsigned nativeCount, unsigned sidIn,
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard )
epicsGuard < epicsMutex > & guard )
{
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_createChanRespReceived ) {
this->cacCtx.printf (
"CAC: Ignored create channel resp to conn chan CID=%u SID=%u?\n",
this->getId (), sidIn );
return;
}
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
if ( ! dbf_type_is_valid ( nativeType ) ) {
this->cacCtx.printf (
"CAC: Ignored conn resp with bad native data type CID=%u SID=%u?\n",
@@ -138,8 +141,6 @@ void nciu::connect ( unsigned nativeType,
this->typeCode = static_cast < unsigned short > ( 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
@@ -151,63 +152,44 @@ void nciu::connect ( unsigned nativeType,
this->accessRightState.setWritePermit();
}
// this installs any subscriptions that
// might still be attached
this->cacCtx.connectAllIO ( guard, *this );
{
epicsGuardRelease < cacMutex > unguard ( guard );
/*
* 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
* their call back here
*/
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 ();
/*
* 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
* their call back here
*/
if ( ! v41Ok ) {
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
// 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 ( guard );
}
void nciu::unresponsiveCircuitNotify (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard )
epicsGuard < epicsMutex > & guard )
{
if ( this->f_connected ) {
this->f_connected = false;
epicsGuardRelease < cacMutex > autoMutexRelease ( guard );
this->notify().disconnectNotify ();
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
if ( this->channelNode::isConnected ( guard ) ) {
this->notify().disconnectNotify ( guard );
caAccessRights noRights;
this->notify().accessRightsNotify ( noRights );
this->notify().accessRightsNotify ( guard, 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 )
void nciu::setServerAddressUnknown ( udpiiu & newiiu,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
this->piiu = & newiiu;
this->retry = disconnectRetrySetpoint;
this->typeCode = USHRT_MAX;
@@ -215,20 +197,13 @@ void nciu::circuitHangupNotify ( class udpiiu & newiiu,
this->sid = UINT_MAX;
this->accessRightState.clrReadPermit();
this->accessRightState.clrWritePermit();
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 );
}
}
void nciu::accessRightsStateChange (
const caAccessRights & arIn, epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > & guard )
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
this->accessRightState = arIn;
//
@@ -236,8 +211,7 @@ void nciu::accessRightsStateChange (
// that this will not be called when the channel is being
// deleted.
//
epicsGuardRelease < cacMutex > unguard ( guard );
this->notify().accessRightsNotify ( this->accessRightState );
this->notify().accessRightsNotify ( guard, this->accessRightState );
}
/*
@@ -281,41 +255,37 @@ unsigned nciu::nameLen () const
return this->nameLength;
}
void nciu::createChannelRequest (
tcpiiu & iiu, epicsGuard < cacMutex > & guard )
{
iiu.createChannelRequest ( *this, guard );
this->f_createChanReqSent = true;
}
cacChannel::ioStatus nciu::read (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount countIn,
cacReadNotify &notify, ioid *pId )
{
//
// fail out if their arguments are invalid
//
if ( ! this->f_connected ) {
throw notConnected ();
if ( ! this->isConnected ( guard ) ) {
throw cacChannel::notConnected ();
}
if ( INVALID_DB_REQ (type) ) {
throw badType ();
if ( ! this->accessRightState.readPermit () ) {
throw cacChannel::noReadAccess ();
}
if ( ! this->accessRightState.readPermit() ) {
throw noReadAccess ();
if ( countIn > this->count ) {
throw cacChannel::outOfBounds ();
}
if ( countIn > UINT_MAX ) {
throw outOfBounds ();
}
if ( countIn == 0 ) {
countIn = this->count;
}
ioid tmpId = this->cacCtx.readNotifyRequest ( *this, type, countIn, notify );
if ( pId ) {
*pId = tmpId;
//
// fail out if their arguments are invalid
//
if ( INVALID_DB_REQ ( type ) ) {
throw cacChannel::badType ();
}
netReadNotifyIO & io = this->cacCtx.readNotifyRequest (
guard, *this, *this, type, countIn, notify );
if ( pId ) {
*pId = io.getId ();
}
this->eventq.add ( io );
return cacChannel::iosAsynch;
}
@@ -332,79 +302,73 @@ void nciu::stringVerify ( const char *pStr, const unsigned count )
}
}
void nciu::write ( unsigned type,
arrayElementCount countIn, const void *pValue )
void nciu::write (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount countIn, const void * pValue )
{
// make sure that they get this and not "no write access"
// if disconnected
if ( ! this->f_connected ) {
throw notConnected();
if ( ! this->connected ( guard ) ) {
throw cacChannel::notConnected();
}
if ( ! this->accessRightState.writePermit() ) {
throw noWriteAccess();
throw cacChannel::noWriteAccess();
}
if ( countIn > this->count || countIn == 0 ) {
throw outOfBounds();
throw cacChannel::outOfBounds();
}
if ( type == DBR_STRING ) {
nciu::stringVerify ( (char *) pValue, countIn );
}
this->cacCtx.writeRequest ( *this, type, countIn, pValue );
this->cacCtx.writeRequest ( guard, *this, type, countIn, pValue );
}
cacChannel::ioStatus nciu::write ( unsigned type, arrayElementCount countIn,
const void *pValue, cacWriteNotify &notify, ioid *pId )
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"
// if disconnected
if ( ! this->f_connected ) {
throw notConnected();
if ( ! this->connected ( guard ) ) {
throw cacChannel::notConnected();
}
if ( ! this->accessRightState.writePermit() ) {
throw noWriteAccess();
throw cacChannel::noWriteAccess();
}
if ( countIn > this->count || countIn == 0 ) {
throw outOfBounds();
throw cacChannel::outOfBounds();
}
if ( type == DBR_STRING ) {
nciu::stringVerify ( (char *) pValue, countIn );
}
ioid tmpId = this->cacCtx.writeNotifyRequest ( *this, type, countIn, pValue, notify );
netWriteNotifyIO & io = this->cacCtx.writeNotifyRequest (
guard, *this, *this, type, countIn, pValue, notify );
if ( pId ) {
*pId = tmpId;
*pId = io.getId ();
}
this->eventq.add ( io );
return cacChannel::iosAsynch;
}
void nciu::subscribe ( unsigned type, arrayElementCount nElem,
unsigned mask, cacStateNotify &notify, ioid *pId )
void nciu::subscribe (
epicsGuard < epicsMutex > & guard, unsigned type,
arrayElementCount nElem, unsigned mask,
cacStateNotify & notify, ioid *pId )
{
if ( INVALID_DB_REQ(type) ) {
throw badType();
}
if ( mask > 0xffff || mask == 0u ) {
throw badEventSelection();
}
ioid tmpId = this->cacCtx.subscriptionRequest (
*this, type, nElem, mask, notify );
netSubscription & io = this->cacCtx.subscriptionRequest (
guard, *this, *this, type, nElem, mask, notify );
if ( pId ) {
*pId = tmpId;
*pId = io.getId ();
}
this->eventq.add ( io );
}
void nciu::ioCancel ( const ioid &idIn )
void nciu::ioCancel (
epicsGuard < epicsMutex > & guard, const ioid & idIn )
{
this->cacCtx.ioCancel ( *this, idIn );
this->cacCtx.destroyIO ( guard, idIn, *this );
}
void nciu::ioShow ( const ioid &idIn, unsigned level ) const
@@ -414,7 +378,7 @@ void nciu::ioShow ( const ioid &idIn, unsigned level ) const
void nciu::hostName ( char *pBuf, unsigned bufLength ) const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
epicsGuard < epicsMutex > locker ( this->cacCtx.mutexRef() );
this->piiu->hostName ( pBuf, bufLength );
}
@@ -426,15 +390,15 @@ const char * nciu::pHostName () const
bool nciu::ca_v42_ok () const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
epicsGuard < epicsMutex > locker ( this->cacCtx.mutexRef() );
return this->piiu->ca_v42_ok ();
}
short nciu::nativeType () const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef() );
short type;
if ( this->f_connected ) {
if ( this->channelNode::isConnected ( guard ) ) {
if ( this->typeCode < SHRT_MAX ) {
type = static_cast <short> ( this->typeCode );
}
@@ -450,27 +414,20 @@ short nciu::nativeType () const
arrayElementCount nciu::nativeElementCount () const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
arrayElementCount countOut;
if ( this->f_connected ) {
countOut = this->count;
}
else {
countOut = 0ul;
}
return countOut;
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef() );
return this->nativeElementCount ( guard );
}
caAccessRights nciu::accessRights () const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
epicsGuard < epicsMutex > locker ( this->cacCtx.mutexRef() );
caAccessRights tmp = this->accessRightState;
return tmp;
}
unsigned nciu::searchAttempts () const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
epicsGuard < epicsMutex > locker ( this->cacCtx.mutexRef() );
return this->retry;
}
@@ -481,14 +438,20 @@ double nciu::beaconPeriod () const
double nciu::receiveWatchdogDelay () const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
epicsGuard < epicsMutex > locker ( this->cacCtx.mutexRef() );
return this->piiu->receiveWatchdogDelay ();
}
bool nciu::connected ( epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
return this->channelNode::isConnected ( guard );
}
void nciu::show ( unsigned level ) const
{
epicsGuard < cacMutex > locker ( this->cacCtx.mutexRef() );
if ( this->f_connected ) {
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef() );
if ( this->channelNode::isConnected ( guard ) ) {
char hostNameTmp [256];
this->hostName ( hostNameTmp, sizeof ( hostNameTmp ) );
::printf ( "Channel \"%s\", connected to server %s",
@@ -536,3 +499,73 @@ void nciu::beaconAnomalyNotify ()
}
}
void nciu::ioCompletionNotify (
epicsGuard < epicsMutex > &, class baseNMIU & io )
{
this->eventq.remove ( io );
}
void nciu::resubscribe ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
tsDLIter < baseNMIU > pNetIO = this->eventq.firstIter ();
while ( pNetIO.valid () ) {
tsDLIter < baseNMIU > next = pNetIO;
next++;
class netSubscription * pSubscr = pNetIO->isSubscription ();
// Its normal for other types of IO to exist after the channel connects,
// but before all of the resubscription requests go out. We must ignore
// them here.
if ( pSubscr ) {
try {
this->getPIIU()->subscriptionRequest ( guard, *this, *pSubscr );
}
catch ( ... ) {
this->printf ( "CAC: failed to send subscription request during channel connect\n" );
}
}
pNetIO = next;
}
}
void nciu::sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
tsDLIter < baseNMIU > pNetIO = this->eventq.firstIter ();
while ( pNetIO.valid () ) {
tsDLIter < baseNMIU > next = pNetIO;
next++;
class netSubscription * pSubscr = pNetIO->isSubscription ();
// disconnected channels should have only subscription IO attached
assert ( pSubscr );
try {
pSubscr->subscriptionUpdateIfRequired ( guard, *this );
}
catch ( ... ) {
this->printf ( "CAC: failed to send subscription request during channel connect\n" );
}
pNetIO = next;
}
}
void nciu::disconnectAllIO (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & guard )
{
this->cacCtx.disconnectAllIO ( cbGuard, guard,
*this, this->eventq );
}
arrayElementCount nciu::nativeElementCount (
epicsGuard < epicsMutex > & guard ) const
{
arrayElementCount countOut;
if ( this->channelNode::isConnected ( guard ) ) {
countOut = this->count;
}
else {
countOut = 0ul;
}
return countOut;
}

View File

@@ -50,44 +50,71 @@
class cac;
class netiiu;
class callbackMutex;
class cacMutex;
class cacPrivateListOfIO {
// The node and the state which tracks the list membership
// are in the channel, but belong to the circuit.
// Protected by the callback mutex
class channelNode : public tsDLNode < class nciu >
{
public:
cacPrivateListOfIO ();
channelNode ();
bool isConnected ( epicsGuard < epicsMutex > & ) const;
private:
tsDLList < class baseNMIU > eventq;
friend class cac;
cacPrivateListOfIO ( const cacPrivateListOfIO & );
cacPrivateListOfIO & operator = ( const cacPrivateListOfIO & );
enum channelState {
cs_none,
cs_disconnGov,
cs_serverAddrResPend,
cs_createReqPend,
cs_createRespPend,
cs_subscripReqPend,
cs_connected,
cs_unrespCircuit,
cs_subscripUpdateReqPend
} listMember;
friend class tcpiiu;
friend class tcpSendThread;
friend class udpiiu;
};
class nciu : public cacChannel, public tsDLNode < nciu >,
public chronIntIdRes < nciu >, public cacPrivateListOfIO {
class privateInterfaceForIO {
public:
virtual void ioCompletionNotify (
epicsGuard < epicsMutex > &, class baseNMIU & ) = 0;
virtual arrayElementCount nativeElementCount (
epicsGuard < epicsMutex > & ) const = 0;
virtual int printf ( const char *pFormat, ... ) = 0;
virtual bool connected ( epicsGuard < epicsMutex > & ) const = 0;
};
class nciu :
public cacChannel,
public chronIntIdRes < nciu >,
public channelNode,
private privateInterfaceForIO {
public:
nciu ( cac &, netiiu &, cacChannelNotify &,
const char *pNameIn, cacChannel::priLev );
~nciu ();
void destroy ();
const char * pNameIn, cacChannel::priLev );
void destructor (
epicsGuard < epicsMutex > & );
void connect ( unsigned nativeType,
unsigned nativeCount, unsigned sid,
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard );
epicsGuard < epicsMutex > & guard );
void connect ( epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard );
void responsiveCircuitNotify (
epicsGuard < epicsMutex > & guard );
void unresponsiveCircuitNotify (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard );
void unresponsiveCircuitNotify ( epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard );
epicsGuard < epicsMutex > & guard );
void circuitHangupNotify ( class udpiiu &,
epicsGuard < callbackMutex > & cbGuard, epicsGuard < cacMutex > & guard );
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & guard );
void setServerAddressUnknown (
udpiiu & newiiu, epicsGuard < epicsMutex > & guard );
bool searchMsg ( class udpiiu & iiu, unsigned & retryNoForThisChannel );
void createChannelRequest ( class tcpiiu & iiu, epicsGuard < cacMutex > & );
void beaconAnomalyNotify ();
void serviceShutdownNotify ();
void accessRightsStateChange ( const caAccessRights &,
epicsGuard < callbackMutex > &, epicsGuard < cacMutex > & );
epicsGuard < callbackMutex > &, epicsGuard < epicsMutex > & );
ca_uint32_t getSID () const;
ca_uint32_t getCID () const;
netiiu * getPIIU ();
@@ -96,19 +123,28 @@ public:
int printf ( const char *pFormat, ... );
void searchReplySetUp ( netiiu &iiu, unsigned sidIn,
ca_uint16_t typeIn, arrayElementCount countIn,
epicsGuard < cacMutex > & );
epicsGuard < epicsMutex > & );
void show ( unsigned level ) const;
const char *pName () const;
const char * pName () const;
unsigned nameLen () const;
const char * pHostName () const; // deprecated - please do not use
arrayElementCount nativeElementCount () const;
bool connected () const;
void writeException ( epicsGuard < callbackMutex > &,
void writeException (
epicsGuard < callbackMutex > &, epicsGuard < epicsMutex > &,
int status, const char *pContext, unsigned type, arrayElementCount count );
cacChannel::priLev getPriority () const;
void * operator new ( size_t size, tsFreeList < class nciu, 1024 > & );
epicsPlacementDeleteOperator (( void *, tsFreeList < class nciu, 1024 > & ))
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 (
epicsGuard < callbackMutex > &, epicsGuard < epicsMutex > & );
bool connected ( epicsGuard < epicsMutex > & ) const;
private:
tsDLList < class baseNMIU > eventq;
caAccessRights accessRightState;
cac & cacCtx;
char * pNameStr;
@@ -119,20 +155,31 @@ private:
unsigned short nameLength; // channel name length
ca_uint16_t typeCode;
ca_uint8_t priority;
bool f_connected:1;
bool f_createChanReqSent:1;
bool f_createChanRespReceived:1;
void initiateConnect ();
ioStatus read ( unsigned type, arrayElementCount count,
~nciu ();
void destroy (
epicsGuard < epicsMutex > & );
void initiateConnect (
epicsGuard < epicsMutex > & );
ioStatus read (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
cacReadNotify &, ioid * );
void write ( unsigned type, arrayElementCount count,
void write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue );
ioStatus write ( unsigned type, arrayElementCount count,
ioStatus write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue, cacWriteNotify &, ioid * );
void subscribe ( unsigned type, arrayElementCount nElem,
void subscribe (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount nElem,
unsigned mask, cacStateNotify &notify, ioid * );
void ioCancel ( const ioid & );
void ioShow ( const ioid &, unsigned level ) const;
void ioCancel (
epicsGuard < epicsMutex > &, const ioid & );
void ioShow (
const ioid &, unsigned level ) const;
short nativeType () const;
caAccessRights accessRights () const;
unsigned searchAttempts () const;
@@ -140,7 +187,10 @@ private:
double receiveWatchdogDelay () const;
bool ca_v42_ok () const;
void hostName ( char *pBuf, unsigned bufLength ) const;
arrayElementCount nativeElementCount () const;
static void stringVerify ( const char *pStr, const unsigned count );
virtual void ioCompletionNotify (
epicsGuard < epicsMutex > &, class baseNMIU & );
nciu ( const nciu & );
nciu & operator = ( const nciu & );
void * operator new ( size_t );
@@ -148,14 +198,14 @@ private:
};
inline void * nciu::operator new ( size_t size,
tsFreeList < class nciu, 1024 > & freeList )
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 > & freeList )
tsFreeList < class nciu, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver, sizeof ( nciu ) );
}
@@ -173,7 +223,7 @@ inline ca_uint32_t nciu::getCID () const
// this is to only be used by early protocol revisions
inline void nciu::connect ( epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard )
epicsGuard < epicsMutex > & guard )
{
this->connect ( this->typeCode, this->count,
this->sid, cbGuard, guard );
@@ -181,7 +231,7 @@ inline void nciu::connect ( epicsGuard < callbackMutex > & cbGuard,
inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn,
ca_uint16_t typeIn, arrayElementCount countIn,
epicsGuard < cacMutex > & )
epicsGuard < epicsMutex > & )
{
this->piiu = & iiu;
this->typeCode = typeIn;
@@ -189,20 +239,19 @@ inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn,
this->sid = sidIn;
}
inline bool nciu::connected () const
{
return this->f_connected;
}
inline netiiu * nciu::getPIIU ()
{
return this->piiu;
}
inline void nciu::writeException ( epicsGuard < callbackMutex > &, int status,
const char *pContext, unsigned typeIn, arrayElementCount countIn )
inline void nciu::writeException (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & guard,
int status, const char * pContext,
unsigned typeIn, arrayElementCount countIn )
{
this->notify().writeException ( status, pContext, typeIn, countIn );
this->notify().writeException ( guard,
status, pContext, typeIn, countIn );
}
inline const netiiu * nciu::getConstPIIU () const
@@ -225,8 +274,17 @@ inline cacChannel::priLev nciu::getPriority () const
return this->priority;
}
inline cacPrivateListOfIO::cacPrivateListOfIO ()
inline channelNode::channelNode () :
listMember ( cs_none )
{
}
inline bool channelNode::isConnected ( epicsGuard < epicsMutex > & ) const
{
return
this->listMember == cs_connected ||
this->listMember == cs_subscripReqPend ||
this->listMember == cs_subscripUpdateReqPend;
}
#endif // ifdef nciuh

View File

@@ -41,24 +41,28 @@
# define NETIO_VIRTUAL_DESTRUCTOR virtual
#endif
class privateInterfaceForIO;
class baseNMIU : public tsDLNode < baseNMIU >, // X aCC 655
public chronIntIdRes < baseNMIU > {
public:
virtual void destroy ( class cacRecycle & ) = 0; // only called by cac
virtual void completion () = 0;
virtual void exception ( int status,
const char * pContext ) = 0;
virtual void exception ( int status,
const char * pContext, unsigned type,
virtual void destroy (
epicsGuard < epicsMutex > &, class cacRecycle & ) = 0; // only called by cac
virtual void completion (
epicsGuard < epicsMutex > &, cacRecycle & ) = 0;
virtual void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext ) = 0;
virtual void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext, unsigned type,
arrayElementCount count ) = 0;
virtual void completion ( unsigned type,
arrayElementCount count, const void * pData ) = 0;
virtual void completion (
epicsGuard < epicsMutex > &, cacRecycle &,
unsigned type, arrayElementCount count,
const void * pData ) = 0;
virtual class netSubscription * isSubscription () = 0;
virtual void show ( unsigned level ) const = 0;
//
// not fond of the vf overhead to fetch this
//
virtual nciu & channel () const = 0;
protected:
NETIO_VIRTUAL_DESTRUCTOR ~baseNMIU ();
};
@@ -67,20 +71,26 @@ class netSubscription : public baseNMIU {
public:
static netSubscription * factory (
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > &,
nciu & chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &notify );
class privateInterfaceForIO &, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify & );
void show ( unsigned level ) const;
arrayElementCount getCount () const;
arrayElementCount getCount (
epicsGuard < epicsMutex > & ) const;
unsigned getType () const;
unsigned getMask () const;
void subscriptionUpdateIfRequired (
epicsGuard < epicsMutex > &, nciu & );
private:
const arrayElementCount count;
nciu & chan;
class privateInterfaceForIO & privateChanForIO;
cacStateNotify & notify;
const unsigned type;
const unsigned mask;
netSubscription ( nciu & chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &notify );
bool updateWhileDisconnected;
netSubscription (
class privateInterfaceForIO &, unsigned type,
arrayElementCount count,
unsigned mask, cacStateNotify & );
class netSubscription * isSubscription ();
void * operator new ( size_t );
void operator delete ( void * );
@@ -88,16 +98,20 @@ private:
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & ))
void destroy ( class cacRecycle & );
void completion ();
void exception ( int status,
const char *pContext );
void completion ( unsigned type,
arrayElementCount count, const void *pData );
void exception ( int status,
const char *pContext, unsigned type,
void destroy (
epicsGuard < epicsMutex > &, class cacRecycle & );
void completion (
epicsGuard < epicsMutex > &, cacRecycle & );
void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext );
void completion (
epicsGuard < epicsMutex > &, cacRecycle &,
unsigned type, arrayElementCount count, const void * pData );
void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext, unsigned type,
arrayElementCount count );
nciu & channel () const;
netSubscription ( const netSubscription & );
netSubscription & operator = ( const netSubscription & );
~netSubscription ();
@@ -107,26 +121,33 @@ class netReadNotifyIO : public baseNMIU {
public:
static netReadNotifyIO * factory (
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > &,
nciu &chan, cacReadNotify &notify );
privateInterfaceForIO &, cacReadNotify & );
void show ( unsigned level ) const;
private:
cacReadNotify & notify;
nciu & chan;
netReadNotifyIO ( nciu & chan, cacReadNotify & notify );
class privateInterfaceForIO & privateChanForIO;
netReadNotifyIO ( privateInterfaceForIO &, cacReadNotify & );
void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & ))
void destroy ( class cacRecycle & );
void completion ();
void exception ( int status, const char *pContext );
void completion ( unsigned type,
arrayElementCount count, const void *pData );
void exception ( int status, const char *pContext,
void destroy (
epicsGuard < epicsMutex > &, class cacRecycle & );
void completion (
epicsGuard < epicsMutex > &, cacRecycle & );
void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext );
void completion (
epicsGuard < epicsMutex > &, cacRecycle &,
unsigned type, arrayElementCount count,
const void * pData );
void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext,
unsigned type, arrayElementCount count );
nciu & channel () const;
~netReadNotifyIO ();
class netSubscription * isSubscription ();
netReadNotifyIO ( const netReadNotifyIO & );
@@ -137,12 +158,12 @@ class netWriteNotifyIO : public baseNMIU {
public:
static netWriteNotifyIO * factory (
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > &,
nciu &chan, cacWriteNotify &notify );
privateInterfaceForIO &, cacWriteNotify & );
void show ( unsigned level ) const;
private:
cacWriteNotify & notify;
nciu & chan;
netWriteNotifyIO ( nciu &chan, cacWriteNotify &notify );
privateInterfaceForIO & privateChanForIO;
netWriteNotifyIO ( privateInterfaceForIO &, cacWriteNotify & );
void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
@@ -150,14 +171,21 @@ private:
epicsPlacementDeleteOperator (( void *,
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & ))
class netSubscription * isSubscription ();
void destroy ( class cacRecycle & );
void completion ();
void exception ( int status, const char *pContext );
void completion ( unsigned type,
arrayElementCount count, const void *pData );
void exception ( int status, const char *pContext,
unsigned type, arrayElementCount count );
nciu & channel () const;
void destroy (
epicsGuard < epicsMutex > &, class cacRecycle & );
void completion (
epicsGuard < epicsMutex > &, cacRecycle & );
void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext );
void completion (
epicsGuard < epicsMutex > &, cacRecycle &,
unsigned type, arrayElementCount count,
const void * pData );
void exception (
epicsGuard < epicsMutex > &, cacRecycle &,
int status, const char * pContext, unsigned type,
arrayElementCount count );
netWriteNotifyIO ( const netWriteNotifyIO & );
netWriteNotifyIO & operator = ( const netWriteNotifyIO & );
~netWriteNotifyIO ();
@@ -178,17 +206,19 @@ inline void * netSubscription::operator new ( size_t size,
#endif
inline netSubscription * netSubscription::factory (
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > &freeList,
nciu &chan, unsigned type, arrayElementCount count,
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & freeList,
class privateInterfaceForIO & chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &notify )
{
return new ( freeList ) netSubscription ( chan, type, // X aCC 930
count, mask, notify );
}
inline arrayElementCount netSubscription::getCount () const // X aCC 361
inline arrayElementCount netSubscription::getCount (
epicsGuard < epicsMutex > & guard ) const // X aCC 361
{
arrayElementCount nativeCount = this->chan.nativeElementCount ();
//guard.assertIdenticalMutex ( this->mutex );
arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard );
if ( this->count == 0u || this->count > nativeCount ) {
return nativeCount;
}
@@ -208,42 +238,42 @@ inline unsigned netSubscription::getMask () const
}
inline netReadNotifyIO * netReadNotifyIO::factory (
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > &freeList,
nciu &chan, cacReadNotify &notify )
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList,
privateInterfaceForIO & ioComplNotifIntf, cacReadNotify & notify )
{
return new ( freeList ) netReadNotifyIO ( chan, notify ); // X aCC 930
return new ( freeList ) netReadNotifyIO ( ioComplNotifIntf, notify ); // X aCC 930
}
inline void * netReadNotifyIO::operator new ( size_t size,
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > &freeList )
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#if defined ( CXX_PLACEMENT_DELETE )
inline void netReadNotifyIO::operator delete ( void *pCadaver,
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > &freeList )
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
inline netWriteNotifyIO * netWriteNotifyIO::factory (
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > &freeList,
nciu &chan, cacWriteNotify &notify )
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList,
privateInterfaceForIO & ioComplNotifyIntf, cacWriteNotify & notify )
{
return new ( freeList ) netWriteNotifyIO ( chan, notify ); // X aCC 930
return new ( freeList ) netWriteNotifyIO ( ioComplNotifyIntf, notify ); // X aCC 930
}
inline void * netWriteNotifyIO::operator new ( size_t size,
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > &freeList )
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#if defined ( CXX_PLACEMENT_DELETE )
inline void netWriteNotifyIO::operator delete ( void *pCadaver,
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > &freeList )
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}

View File

@@ -28,8 +28,10 @@
#include "nciu.h"
#include "cac.h"
netReadNotifyIO::netReadNotifyIO ( nciu & chanIn, cacReadNotify & notify ) :
notify ( notify ), chan ( chanIn )
netReadNotifyIO::netReadNotifyIO (
privateInterfaceForIO & ioComplIntfIn,
cacReadNotify & notify ) :
notify ( notify ), privateChanForIO ( ioComplIntfIn )
{
}
@@ -43,32 +45,61 @@ void netReadNotifyIO::show ( unsigned /* level */ ) const
static_cast < const void * > ( this ) );
}
void netReadNotifyIO::destroy ( cacRecycle & recycle )
void netReadNotifyIO::destroy (
epicsGuard < epicsMutex > & guard, cacRecycle & recycle )
{
this->~netReadNotifyIO();
recycle.recycleReadNotifyIO ( *this );
this->~netReadNotifyIO ();
recycle.recycleReadNotifyIO ( guard, *this );
}
void netReadNotifyIO::completion ()
void netReadNotifyIO::completion (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle, unsigned type,
arrayElementCount count, const void * pData )
{
this->chan.getClient().printf ( "Read response w/o data ?\n" );
//guard.assertIdenticalMutex ( this->mutex );
this->notify.completion ( guard, type, count, pData );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netReadNotifyIO ();
recycle.recycleReadNotifyIO ( guard, *this );
}
void netReadNotifyIO::exception ( int status, const char *pContext )
void netReadNotifyIO::completion (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle )
{
this->notify.exception ( status, pContext, UINT_MAX, 0u );
//guard.assertIdenticalMutex ( this->mutex );
//this->chan.getClient().printf ( "Read response w/o data ?\n" );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netReadNotifyIO ();
recycle.recycleReadNotifyIO ( guard, *this );
}
void netReadNotifyIO::exception ( int status, const char *pContext,
unsigned type, arrayElementCount count )
void netReadNotifyIO::exception (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle,
int status, const char *pContext )
{
this->notify.exception ( status, pContext, type, count );
//guard.assertIdenticalMutex ( this->mutex );
this->notify.exception (
guard, status, pContext, UINT_MAX, 0u );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netReadNotifyIO ();
recycle.recycleReadNotifyIO ( guard, *this );
}
void netReadNotifyIO::completion ( unsigned type,
arrayElementCount count, const void *pData )
void netReadNotifyIO::exception (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle,
int status, const char *pContext,
unsigned type, arrayElementCount count )
{
this->notify.completion ( type, count, pData );
//guard.assertIdenticalMutex ( this->mutex )
this->notify.exception (
guard, status, pContext, type, count );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netReadNotifyIO ();
recycle.recycleReadNotifyIO ( guard, *this );
}
class netSubscription * netReadNotifyIO::isSubscription ()
@@ -76,11 +107,6 @@ class netSubscription * netReadNotifyIO::isSubscription ()
return 0;
}
nciu & netReadNotifyIO::channel () const
{
return this->chan;
}
void * netReadNotifyIO::operator new ( size_t ) // X aCC 361
{
// The HPUX compiler seems to require this even though no code

View File

@@ -29,12 +29,15 @@
#include "nciu.h"
#include "cac.h"
#include "db_access.h" // for dbf_type_to_text
#include "caerr.h"
netSubscription::netSubscription ( nciu & chanIn,
netSubscription::netSubscription (
privateInterfaceForIO & chanIn,
unsigned typeIn, arrayElementCount countIn,
unsigned maskIn, cacStateNotify &notifyIn ) :
count ( countIn ), chan ( chanIn ),
notify ( notifyIn ), type ( typeIn ), mask ( maskIn )
unsigned maskIn, cacStateNotify & notifyIn ) :
count ( countIn ), privateChanForIO ( chanIn ),
notify ( notifyIn ), type ( typeIn ), mask ( maskIn ),
updateWhileDisconnected ( false )
{
if ( ! dbr_type_is_valid ( typeIn ) ) {
throw cacChannel::badType ();
@@ -48,10 +51,11 @@ netSubscription::~netSubscription ()
{
}
void netSubscription::destroy ( cacRecycle &recycle )
void netSubscription::destroy (
epicsGuard < epicsMutex > & guard, cacRecycle & recycle )
{
this->~netSubscription ();
recycle.recycleSubscription ( *this );
recycle.recycleSubscription ( guard, *this );
}
class netSubscription * netSubscription::isSubscription ()
@@ -67,31 +71,91 @@ void netSubscription::show ( unsigned /* level */ ) const
this->count, this->mask );
}
void netSubscription::completion ()
void netSubscription::completion (
epicsGuard < epicsMutex > & guard, cacRecycle & )
{
this->chan.printf ( "subscription update w/o data ?\n" );
if ( this->privateChanForIO.connected ( guard ) ) {
this->updateWhileDisconnected = false;
}
else {
this->updateWhileDisconnected = true;
}
this->privateChanForIO.printf ( "subscription update w/o data ?\n" );
}
void netSubscription::exception ( int status, const char *pContext )
void netSubscription::exception (
epicsGuard < epicsMutex > & guard, cacRecycle & recycle,
int status, const char * pContext )
{
this->notify.exception ( status, pContext, UINT_MAX, 0 );
if ( status == ECA_CHANDESTROY ) {
this->notify.exception (
guard, status, pContext, UINT_MAX, 0 );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netSubscription ();
recycle.recycleSubscription ( guard, *this );
}
else {
// guard.assertIdenticalMutex ( this->mutex );
if ( this->privateChanForIO.connected ( guard ) ) {
this->updateWhileDisconnected = false;
this->notify.exception (
guard, status, pContext, UINT_MAX, 0 );
}
else {
this->updateWhileDisconnected = true;
}
}
}
void netSubscription::exception ( int status, const char *pContext,
unsigned typeIn, arrayElementCount countIn )
void netSubscription::exception (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle, int status, const char * pContext,
unsigned typeIn, arrayElementCount countIn )
{
this->notify.exception ( status, pContext, typeIn, countIn );
if ( status == ECA_CHANDESTROY ) {
this->notify.exception (
guard, status, pContext, UINT_MAX, 0 );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netSubscription ();
recycle.recycleSubscription ( guard, *this );
}
else {
//guard.assertIdenticalMutex ( this->mutex );
if ( this->privateChanForIO.connected ( guard ) ) {
this->updateWhileDisconnected = false;
this->notify.exception (
guard, status, pContext, typeIn, countIn );
}
else {
this->updateWhileDisconnected = true;
}
}
}
void netSubscription::completion ( unsigned typeIn,
arrayElementCount countIn, const void *pDataIn )
void netSubscription::completion (
epicsGuard < epicsMutex > & guard, cacRecycle &,
unsigned typeIn, arrayElementCount countIn,
const void * pDataIn )
{
this->notify.current ( typeIn, countIn, pDataIn );
// guard.assertIdenticalMutex ( this->mutex );
if ( this->privateChanForIO.connected ( guard ) ) {
this->updateWhileDisconnected = false;
this->notify.current (
guard, typeIn, countIn, pDataIn );
}
else {
this->updateWhileDisconnected = true;
}
}
nciu & netSubscription::channel () const
void netSubscription::subscriptionUpdateIfRequired (
epicsGuard < epicsMutex > & guard, nciu & chan )
{
return this->chan;
if ( this->updateWhileDisconnected ) {
chan.getPIIU()->subscriptionUpdateRequest (
guard, chan, *this );
this->updateWhileDisconnected = false;
}
}
void * netSubscription::operator new ( size_t ) // X aCC 361

View File

@@ -28,8 +28,9 @@
#include "nciu.h"
#include "cac.h"
netWriteNotifyIO::netWriteNotifyIO ( nciu & chanIn, cacWriteNotify & notifyIn ) :
notify ( notifyIn ), chan ( chanIn )
netWriteNotifyIO::netWriteNotifyIO (
privateInterfaceForIO & ioComplIntf, cacWriteNotify & notifyIn ) :
notify ( notifyIn ), privateChanForIO ( ioComplIntf )
{
}
@@ -43,33 +44,59 @@ void netWriteNotifyIO::show ( unsigned /* level */ ) const
static_cast < const void * > ( this ) );
}
void netWriteNotifyIO::destroy ( cacRecycle & recycle )
void netWriteNotifyIO::destroy (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle )
{
this->~netWriteNotifyIO ();
recycle.recycleWriteNotifyIO ( *this );
recycle.recycleWriteNotifyIO ( guard, *this );
}
void netWriteNotifyIO::completion ()
void netWriteNotifyIO::completion (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle )
{
this->notify.completion ();
this->notify.completion ( guard );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netWriteNotifyIO ();
recycle.recycleWriteNotifyIO ( guard, *this );
}
void netWriteNotifyIO::exception ( int status, const char *pContext )
void netWriteNotifyIO::completion (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle,
unsigned /* type */, arrayElementCount /* count */,
const void * /* pData */ )
{
this->notify.exception ( status, pContext, UINT_MAX, 0u );
//this->chan.getClient().printf ( "Write response with data ?\n" );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netWriteNotifyIO ();
recycle.recycleWriteNotifyIO ( guard, *this );
}
void netWriteNotifyIO::exception ( int status, const char *pContext,
unsigned type, arrayElementCount count )
void netWriteNotifyIO::exception (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle,
int status, const char * pContext )
{
this->notify.exception ( status, pContext, type, count );
this->notify.exception (
guard, status, pContext, UINT_MAX, 0u );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netWriteNotifyIO ();
recycle.recycleWriteNotifyIO ( guard, *this );
}
void netWriteNotifyIO::completion ( unsigned /* type */,
arrayElementCount /* count */, const void * /* pData */ )
void netWriteNotifyIO::exception (
epicsGuard < epicsMutex > & guard,
cacRecycle & recycle,
int status, const char *pContext,
unsigned type, arrayElementCount count )
{
this->chan.getClient().printf ( "Write response with data ?\n" );
this->notify.exception (
guard, status, pContext, type, count );
this->privateChanForIO.ioCompletionNotify ( guard, *this );
this->~netWriteNotifyIO ();
recycle.recycleWriteNotifyIO ( guard, *this );
}
class netSubscription * netWriteNotifyIO::isSubscription ()
@@ -77,16 +104,12 @@ class netSubscription * netWriteNotifyIO::isSubscription ()
return 0;
}
nciu & netWriteNotifyIO::channel () const
{
return this->chan;
}
void * netWriteNotifyIO::operator new ( size_t ) // X aCC 361
{
// The HPUX compiler seems to require this even though no code
// calls it directly
throw std::logic_error ( "why is the compiler calling private operator new" );
throw std::logic_error (
"why is the compiler calling private operator new" );
}
void netWriteNotifyIO::operator delete ( void * )

View File

@@ -42,35 +42,41 @@ bool netiiu::ca_v41_ok () const
return false;
}
void netiiu::writeRequest ( epicsGuard < cacMutex > &, nciu &,
unsigned, unsigned, const void * )
void netiiu::writeRequest ( epicsGuard < epicsMutex > &, nciu &,
unsigned, arrayElementCount, const void * )
{
throw cacChannel::notConnected();
}
void netiiu::writeNotifyRequest ( epicsGuard < cacMutex > &,
nciu &, netWriteNotifyIO &, unsigned, unsigned, const void * )
void netiiu::writeNotifyRequest ( epicsGuard < epicsMutex > &,
nciu &, netWriteNotifyIO &, unsigned, arrayElementCount, const void * )
{
throw cacChannel::notConnected();
}
void netiiu::readNotifyRequest ( epicsGuard < cacMutex > &,
nciu &, netReadNotifyIO &, unsigned, unsigned )
void netiiu::readNotifyRequest ( epicsGuard < epicsMutex > &,
nciu &, netReadNotifyIO &, unsigned, arrayElementCount )
{
throw cacChannel::notConnected();
}
void netiiu::clearChannelRequest ( epicsGuard < cacMutex > &, ca_uint32_t, ca_uint32_t )
void netiiu::clearChannelRequest (
epicsGuard < epicsMutex > &, ca_uint32_t, ca_uint32_t )
{
}
void netiiu::subscriptionRequest ( epicsGuard < cacMutex > &,
nciu &, netSubscription & )
void netiiu::subscriptionRequest (
epicsGuard < epicsMutex > &, nciu &, netSubscription & )
{
}
void netiiu::subscriptionCancelRequest ( epicsGuard < cacMutex > &,
nciu &, netSubscription & )
void netiiu::subscriptionCancelRequest (
epicsGuard < epicsMutex > &, nciu &, netSubscription & )
{
}
void netiiu::subscriptionUpdateRequest (
epicsGuard < epicsMutex > &, nciu &, netSubscription & )
{
}
@@ -94,21 +100,21 @@ osiSockAddr netiiu::getNetworkAddress () const
return addr;
}
void netiiu::flushRequest ()
void netiiu::flushRequest ( epicsGuard < epicsMutex > & )
{
}
bool netiiu::flushBlockThreshold ( epicsGuard < cacMutex > & ) const
bool netiiu::flushBlockThreshold ( epicsGuard < epicsMutex > & ) const
{
return false;
}
void netiiu::flushRequestIfAboveEarlyThreshold ( epicsGuard < cacMutex > & )
void netiiu::flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & )
{
}
void netiiu::blockUntilSendBacklogIsReasonable
( cacNotify &, epicsGuard < cacMutex > & )
( cacContextNotify &, epicsGuard < epicsMutex > & )
{
}
@@ -117,8 +123,7 @@ void netiiu::requestRecvProcessPostponedFlush ()
return;
}
void netiiu::uninstallChan (
epicsGuard < callbackMutex > &, epicsGuard < cacMutex > &, nciu & )
void netiiu::uninstallChan ( epicsGuard < epicsMutex > &, nciu & )
{
throw cacChannel::notConnected();
}

View File

@@ -33,7 +33,6 @@
class netWriteNotifyIO;
class netReadNotifyIO;
class netSubscription;
class cacMutex;
union osiSockAddr;
class cac;
@@ -46,28 +45,29 @@ public:
virtual const char * pHostName () const = 0; // deprecated - please do not use
virtual bool ca_v41_ok () const = 0;
virtual bool ca_v42_ok () const = 0;
virtual void writeRequest ( epicsGuard < cacMutex > &, nciu &,
unsigned type, unsigned nElem, const void *pValue ) = 0;
virtual void writeNotifyRequest ( epicsGuard < cacMutex > &,
nciu &, netWriteNotifyIO &,
unsigned type, unsigned nElem, const void *pValue ) = 0;
virtual void readNotifyRequest ( epicsGuard < cacMutex > &, nciu &,
netReadNotifyIO &, unsigned type, unsigned nElem ) = 0;
virtual void clearChannelRequest ( epicsGuard < cacMutex > &,
ca_uint32_t sid, ca_uint32_t cid ) = 0;
virtual void subscriptionRequest ( epicsGuard < cacMutex > &,
nciu &, netSubscription &subscr ) = 0;
virtual void subscriptionCancelRequest ( epicsGuard < cacMutex > &,
nciu & chan, netSubscription & subscr ) = 0;
virtual void flushRequest () = 0;
virtual bool flushBlockThreshold ( epicsGuard < cacMutex > & ) const = 0;
virtual void flushRequestIfAboveEarlyThreshold ( epicsGuard < cacMutex > & ) = 0;
virtual void writeRequest ( epicsGuard < epicsMutex > &, nciu &,
unsigned type, arrayElementCount nElem, const void *pValue ) = 0;
virtual void writeNotifyRequest ( epicsGuard < epicsMutex > &,
nciu &, netWriteNotifyIO &,
unsigned type, arrayElementCount nElem, const void *pValue ) = 0;
virtual void readNotifyRequest ( epicsGuard < epicsMutex > &, nciu &,
netReadNotifyIO &, unsigned type, arrayElementCount nElem ) = 0;
virtual void clearChannelRequest ( epicsGuard < epicsMutex > &,
ca_uint32_t sid, ca_uint32_t cid ) = 0;
virtual void subscriptionRequest ( epicsGuard < epicsMutex > &,
nciu &, netSubscription & ) = 0;
virtual void subscriptionUpdateRequest (
epicsGuard < epicsMutex > &, nciu &, netSubscription & ) = 0;
virtual void subscriptionCancelRequest ( epicsGuard < epicsMutex > &,
nciu & chan, netSubscription & subscr ) = 0;
virtual void flushRequest ( epicsGuard < epicsMutex > & ) = 0;
virtual bool flushBlockThreshold ( epicsGuard < epicsMutex > & ) const = 0;
virtual void flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & ) = 0;
virtual void blockUntilSendBacklogIsReasonable
( cacNotify &, epicsGuard < cacMutex > & ) = 0;
( cacContextNotify &, epicsGuard < epicsMutex > & ) = 0;
virtual void requestRecvProcessPostponedFlush () = 0;
virtual osiSockAddr getNetworkAddress () const = 0;
virtual void uninstallChan ( epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > &, nciu & ) = 0;
virtual void uninstallChan ( epicsGuard < epicsMutex > &, nciu & ) = 0;
virtual double receiveWatchdogDelay () const = 0;
};

View File

@@ -49,32 +49,42 @@
struct oldChannelNotify : public cacChannelNotify {
public:
oldChannelNotify ( struct ca_client_context &, const char * pName,
caCh * pConnCallBackIn, void * pPrivateIn, capri priority );
~oldChannelNotify ();
oldChannelNotify (
epicsGuard < epicsMutex > &, struct ca_client_context &,
const char * pName, caCh * pConnCallBackIn,
void * pPrivateIn, capri priority );
void destructor (
epicsGuard < epicsMutex > & );
void setPrivatePointer ( void * );
void * privatePointer () const;
int changeConnCallBack ( caCh *pfunc );
int replaceAccessRightsEvent ( caArh *pfunc );
const char *pName () const;
void show ( unsigned level ) const;
void initiateConnect ();
void initiateConnect (
epicsGuard < epicsMutex > & );
void read (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
cacReadNotify &notify, cacChannel::ioid *pId = 0 );
void read (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
void *pValue );
void write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue );
void write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count, const void *pValue,
cacWriteNotify &, cacChannel::ioid *pId = 0 );
void subscribe (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count, unsigned mask,
cacStateNotify &, cacChannel::ioid & );
void ioCancel ( const cacChannel::ioid & );
void ioCancel (
epicsGuard < epicsMutex > &, const cacChannel::ioid & );
void ioShow ( const cacChannel::ioid &, unsigned level ) const;
short nativeType () const;
arrayElementCount nativeElementCount () const;
@@ -89,9 +99,9 @@ public:
const char * pHostName () const; // deprecated - please do not use
ca_client_context & getClientCtx ();
void * operator new ( size_t size,
tsFreeList < struct oldChannelNotify, 1024 > & );
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void * ,
tsFreeList < struct oldChannelNotify, 1024 > & ))
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & ))
private:
ca_client_context & cacCtx;
cacChannel & io;
@@ -101,14 +111,19 @@ private:
unsigned ioSeqNo;
bool currentlyConnected;
bool prevConnected;
void connectNotify ();
void disconnectNotify ();
~oldChannelNotify ();
void connectNotify ( epicsGuard < epicsMutex > & );
void disconnectNotify ( epicsGuard < epicsMutex > & );
void serviceShutdownNotify ();
void accessRightsNotify ( const caAccessRights & );
void exception ( int status, const char *pContext );
void readException ( int status, const char *pContext,
void accessRightsNotify (
epicsGuard < epicsMutex > &, const caAccessRights & );
void exception ( epicsGuard < epicsMutex > &,
int status, const char * pContext );
void readException ( epicsGuard < epicsMutex > &,
int status, const char * pContext,
unsigned type, arrayElementCount count, void *pValue );
void writeException ( int status, const char *pContext,
void writeException ( epicsGuard < epicsMutex > &,
int status, const char * pContext,
unsigned type, arrayElementCount count );
oldChannelNotify ( const oldChannelNotify & );
oldChannelNotify & operator = ( const oldChannelNotify & );
@@ -118,25 +133,30 @@ private:
class getCopy : public cacReadNotify {
public:
getCopy ( 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,
tsFreeList < class getCopy, 1024 > & );
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < class getCopy, 1024 > & ))
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & ))
private:
arrayElementCount count;
ca_client_context &cacCtx;
oldChannelNotify &chan;
ca_client_context & cacCtx;
oldChannelNotify & chan;
void *pValue;
unsigned ioSeqNo;
unsigned type;
void completion (
unsigned type, arrayElementCount count, const void *pData);
void exception ( int status,
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void *pData );
void exception (
epicsGuard < epicsMutex > &, int status,
const char *pContext, unsigned type, arrayElementCount count );
getCopy ( const getCopy & );
getCopy & operator = ( const getCopy & );
@@ -146,21 +166,24 @@ private:
class getCallback : public cacReadNotify {
public:
getCallback ( oldChannelNotify &chanIn,
getCallback (
oldChannelNotify & chanIn,
caEventCallBackFunc *pFunc, void *pPrivate );
~getCallback ();
void * operator new ( size_t size,
tsFreeList < class getCallback, 1024 > & );
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < class getCallback, 1024 > & ))
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & ))
private:
oldChannelNotify & chan;
caEventCallBackFunc * pFunc;
void * pPrivate;
void completion (
unsigned type, arrayElementCount count, const void *pData);
void exception ( int status,
const char *pContext, unsigned type, arrayElementCount count );
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void *pData);
void exception (
epicsGuard < epicsMutex > &, int status,
const char * pContext, unsigned type, arrayElementCount count );
getCallback ( const getCallback & );
getCallback & operator = ( const getCallback & );
void * operator new ( size_t size );
@@ -169,19 +192,21 @@ private:
class putCallback : public cacWriteNotify {
public:
putCallback ( oldChannelNotify &,
putCallback (
oldChannelNotify &,
caEventCallBackFunc *pFunc, void *pPrivate );
~putCallback ();
void * operator new ( size_t size,
tsFreeList < class putCallback, 1024 > & );
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < class putCallback, 1024 > & ))
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & ))
private:
oldChannelNotify & chan;
caEventCallBackFunc * pFunc;
void *pPrivate;
void completion ();
void exception ( int status, const char *pContext,
void completion ( epicsGuard < epicsMutex > & );
void exception (
epicsGuard < epicsMutex > &, int status, const char *pContext,
unsigned type, arrayElementCount count );
putCallback ( const putCallback & );
putCallback & operator = ( const putCallback & );
@@ -194,13 +219,14 @@ public:
oldSubscription (
oldChannelNotify &, caEventCallBackFunc *pFunc, void *pPrivate );
~oldSubscription ();
void begin ( unsigned type, arrayElementCount nElem, unsigned mask );
void begin ( epicsGuard < epicsMutex > & guard, unsigned type,
arrayElementCount nElem, unsigned mask );
oldChannelNotify & channel () const;
void * operator new ( size_t size,
tsFreeList < struct oldSubscription, 1024 > & );
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < struct oldSubscription, 1024 > & ))
void ioCancel ();
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & ))
void ioCancel ( epicsGuard < epicsMutex > & );
private:
oldChannelNotify & chan;
cacChannel::ioid id;
@@ -208,8 +234,10 @@ private:
void * pPrivate;
bool subscribed;
void current (
unsigned type, arrayElementCount count, const void *pData );
void exception ( int status,
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void *pData );
void exception (
epicsGuard < epicsMutex > &, int status,
const char *pContext, unsigned type, arrayElementCount count );
oldSubscription ( const oldSubscription & );
oldSubscription & operator = ( const oldSubscription & );
@@ -217,16 +245,7 @@ private:
void operator delete ( void * );
};
class ca_client_context_mutex {
public:
void lock ();
void unlock ();
void show ( unsigned level ) const;
private:
epicsMutex mutex;
};
struct ca_client_context : public cacNotify
struct ca_client_context : public cacContextNotify
{
public:
ca_client_context ( bool enablePreemptiveCallback = false );
@@ -234,59 +253,68 @@ public:
void changeExceptionEvent ( caExceptionHandler * pfunc, void * arg );
void registerForFileDescriptorCallBack ( CAFDHANDLER * pFunc, void * pArg );
void replaceErrLogHandler ( caPrintfFunc * ca_printf_func );
void registerService ( cacService & service );
cacChannel & createChannel ( const char * name_str,
oldChannelNotify & chan, cacChannel::priLev pri );
void flushRequest ();
cacChannel & createChannel (
epicsGuard < epicsMutex > &, const char * pChannelName,
oldChannelNotify &, cacChannel::priLev pri );
void flush ( epicsGuard < epicsMutex > & );
int pendIO ( const double & timeout );
int pendEvent ( const double & timeout );
bool ioComplete () const;
void show ( unsigned level ) const;
unsigned connectionCount () const;
unsigned sequenceNumberOfOutstandingIO () const;
unsigned circuitCount () const;
unsigned sequenceNumberOfOutstandingIO (
epicsGuard < epicsMutex > & ) const;
unsigned beaconAnomaliesSinceProgramStart () const;
void incrementOutstandingIO ( unsigned ioSeqNo );
void decrementOutstandingIO ( unsigned ioSeqNo );
void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo );
void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo, oldChannelNotify &chan,
void incrementOutstandingIO (
epicsGuard < epicsMutex > &, unsigned ioSeqNo );
void decrementOutstandingIO (
epicsGuard < epicsMutex > &, unsigned ioSeqNo );
void exception (
epicsGuard < epicsMutex > &, int status, const char * pContext,
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 (
epicsEvent & event, const double & timeout );
CASG * lookupCASG ( unsigned id );
void installCASG ( CASG & );
void uninstallCASG ( CASG & );
void selfTest ();
CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id );
void installCASG ( epicsGuard < epicsMutex > &, CASG & );
void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & );
void selfTest () const;
// 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;
void vSignal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args );
int printf ( const char * pformat, ... ) const;
int vPrintf ( const char * pformat, va_list args ) const;
void signal ( int ca_status, const char * pfilenm,
int lineno, const char * pFormat, ... );
void vSignal ( int ca_status, const char * pfilenm,
int lineno, const char *pFormat, va_list args );
bool preemptiveCallbakIsEnabled () const;
void destroyChannel ( oldChannelNotify & chan );
void destroyGetCopy ( getCopy & );
void destroyGetCallback ( getCallback & );
void destroyPutCallback ( putCallback & );
void destroySubscription ( oldSubscription & );
void destroyGetCopy ( epicsGuard < epicsMutex > &, getCopy & );
void destroyGetCallback ( epicsGuard < epicsMutex > &, getCallback & );
void destroyPutCallback ( epicsGuard < epicsMutex > &, putCallback & );
void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & );
void changeConnCallBack ( caCh * pfunc, caCh * & pConnCallBack,
const bool & currentlyConnected );
epicsMutex & mutexRef () const;
// exceptions
class noSocket {};
private:
tsFreeList < struct oldChannelNotify, 1024 > oldChannelNotifyFreeList;
tsFreeList < class getCopy, 1024 > getCopyFreeList;
tsFreeList < class getCallback, 1024 > getCallbackFreeList;
tsFreeList < class putCallback, 1024 > putCallbackFreeList;
tsFreeList < struct oldSubscription, 1024 > subscriptionFreeList;
tsFreeList < struct CASG, 128 > casgFreeList;
mutable ca_client_context_mutex mutex;
chronIntIdResTable < CASG > sgTable;
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > oldChannelNotifyFreeList;
tsFreeList < class getCopy, 1024, epicsMutexNOOP > getCopyFreeList;
tsFreeList < class getCallback, 1024, epicsMutexNOOP > getCallbackFreeList;
tsFreeList < class putCallback, 1024, epicsMutexNOOP > putCallbackFreeList;
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > subscriptionFreeList;
tsFreeList < struct CASG, 128, epicsMutexNOOP > casgFreeList;
mutable epicsMutex mutex;
epicsMutex callbackMutex;
epicsEvent ioDone;
epicsEvent callbackThreadActivityComplete;
epics_auto_ptr < class cac > pClientCtx;
epics_auto_ptr < epicsGuard < epicsMutex > > pCallbackGuard;
epics_auto_ptr < cacContext > pServiceContext;
caExceptionHandler * ca_exception_func;
void * ca_exception_arg;
caPrintfFunc * pVPrintfFunc;
@@ -303,29 +331,38 @@ private:
void callbackLock ();
void callbackUnlock ();
void attachToClientCtx ();
cacContext & createNetworkContext ( epicsMutex & mutex );
ca_client_context ( const ca_client_context & );
ca_client_context & operator = ( const ca_client_context & );
static cacService * pDefaultService;
static epicsMutex defaultServiceInstallMutex;
friend int epicsShareAPI ca_create_channel (
const char * name_str, caCh * conn_func, void * puser,
capri priority, chid * chanptr );
friend int epicsShareAPI ca_array_get ( chtype type,
arrayElementCount count, chid pChan, void *pValue );
arrayElementCount count, chid pChan, void * pValue );
friend int epicsShareAPI ca_array_get_callback ( chtype type,
arrayElementCount count, chid pChan,
caEventCallBackFunc *pfunc, void *arg );
arrayElementCount count, chid pChan,
caEventCallBackFunc *pfunc, void *arg );
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,
caEventCallBackFunc *pfunc, void *usrarg );
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,
evid *monixptr );
chtype type, arrayElementCount count, chid pChan,
long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg,
evid *monixptr );
friend int epicsShareAPI ca_clear_subscription ( evid pMon );
friend int epicsShareAPI ca_flush_io ();
friend int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid );
friend int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid );
friend void epicsShareAPI caInstallDefaultService ( cacService & );
};
int fetchClientContext ( ca_client_context **ppcac );
int fetchClientContext ( ca_client_context * * ppcac );
inline ca_client_context & oldChannelNotify::getClientCtx ()
{
@@ -342,42 +379,20 @@ inline void oldChannelNotify::show ( unsigned level ) const
this->io.show ( level );
}
inline void oldChannelNotify::initiateConnect ()
inline void oldChannelNotify::initiateConnect (
epicsGuard < epicsMutex > & guard )
{
this->io.initiateConnect ();
this->io.initiateConnect ( guard );
}
inline void oldChannelNotify::read ( unsigned type, arrayElementCount count,
cacReadNotify &notify, cacChannel::ioid * pId )
inline void oldChannelNotify::ioCancel (
epicsGuard < epicsMutex > & guard, const cacChannel::ioid & id )
{
this->io.read ( type, count, notify, pId );
this->io.ioCancel ( guard, id );
}
inline void oldChannelNotify::write ( unsigned type,
arrayElementCount count, const void * pValue )
{
this->io.write ( type, count, pValue );
}
inline void oldChannelNotify::write ( unsigned type, arrayElementCount count,
const void * pValue, cacWriteNotify & notify, cacChannel::ioid * pId )
{
this->io.write ( type, count, pValue, notify, pId );
}
inline void oldChannelNotify::subscribe ( unsigned type,
arrayElementCount count, unsigned mask, cacStateNotify & notify,
cacChannel::ioid & idOut)
{
this->io.subscribe ( type, count, mask, notify, &idOut );
}
inline void oldChannelNotify::ioCancel ( const cacChannel::ioid &id )
{
this->io.ioCancel ( id );
}
inline void oldChannelNotify::ioShow ( const cacChannel::ioid &id, unsigned level ) const
inline void oldChannelNotify::ioShow (
const cacChannel::ioid & id, unsigned level ) const
{
this->io.ioShow ( id, level );
}
@@ -438,45 +453,46 @@ inline const char * oldChannelNotify::pHostName () const
}
inline void * oldChannelNotify::operator new ( size_t size,
tsFreeList < struct oldChannelNotify, 1024 > & freeList )
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 > & freeList )
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
inline oldSubscription::oldSubscription (
oldChannelNotify & chanIn,
caEventCallBackFunc * pFuncIn, void * pPrivateIn ) :
oldChannelNotify & chanIn, caEventCallBackFunc * pFuncIn,
void * pPrivateIn ) :
chan ( chanIn ), id ( UINT_MAX ), pFunc ( pFuncIn ),
pPrivate ( pPrivateIn ), subscribed ( false )
{
}
inline void oldSubscription::begin ( unsigned type,
arrayElementCount nElem, unsigned mask )
inline void oldSubscription::begin (
epicsGuard < epicsMutex > & guard, unsigned type,
arrayElementCount nElem, unsigned mask )
{
this->subscribed = true;
this->chan.subscribe ( type, nElem, mask, *this, this->id );
this->chan.subscribe ( guard, type, nElem, mask, *this, this->id );
// dont touch this pointer after this point because the
// 1st update callback might cancel the subscription
}
inline void * oldSubscription::operator new ( size_t size,
tsFreeList < struct oldSubscription, 1024 > & freeList )
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 > & freeList )
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
@@ -489,49 +505,48 @@ inline oldChannelNotify & oldSubscription::channel () const
inline int oldChannelNotify::changeConnCallBack ( caCh * pfunc )
{
// operation protected by call back lock in ca_client_context
this->cacCtx.changeConnCallBack ( pfunc,
this->pConnCallBack, this->currentlyConnected );
return ECA_NORMAL;
}
inline void * getCopy::operator new ( size_t size,
tsFreeList < class getCopy, 1024 > & freeList )
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 > & freeList )
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
inline void * putCallback::operator new ( size_t size,
tsFreeList < class putCallback, 1024 > & freeList )
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 > & freeList )
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
inline void * getCallback::operator new ( size_t size,
tsFreeList < class getCallback, 1024 > & freeList )
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 > & freeList )
inline void getCallback::operator delete ( void * pCadaver,
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
@@ -547,25 +562,11 @@ inline bool ca_client_context::ioComplete () const
return ( this->pndRecvCnt == 0u );
}
inline unsigned ca_client_context::sequenceNumberOfOutstandingIO () const
inline unsigned ca_client_context::sequenceNumberOfOutstandingIO (
epicsGuard < epicsMutex > & ) const
{
// perhaps on SMP systems THERE should be lock/unlock around this
return this->ioSeqNo;
}
inline void ca_client_context_mutex::lock ()
{
this->mutex.lock ();
}
inline void ca_client_context_mutex::unlock ()
{
this->mutex.unlock ();
}
inline void ca_client_context_mutex::show ( unsigned level ) const
{
this->mutex.show ( level );
}
#endif // ifndef oldAccessh

View File

@@ -41,56 +41,70 @@ extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args )
{
}
oldChannelNotify::oldChannelNotify ( ca_client_context & cacIn, const char *pName,
caCh * pConnCallBackIn, void * pPrivateIn, capri priority ) :
oldChannelNotify::oldChannelNotify (
epicsGuard < epicsMutex > & guard, ca_client_context & cacIn,
const char *pName, caCh * pConnCallBackIn,
void * pPrivateIn, capri priority ) :
cacCtx ( cacIn ),
io ( cacIn.createChannel ( pName, *this, priority ) ),
io ( cacIn.createChannel ( guard, pName, *this, priority ) ),
pConnCallBack ( pConnCallBackIn ),
pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler ),
ioSeqNo ( cacIn.sequenceNumberOfOutstandingIO () ),
currentlyConnected ( false ), prevConnected ( false )
ioSeqNo ( 0 ), currentlyConnected ( false ), prevConnected ( false )
{
// no need to worry about a connect preempting here because
// the connect sequence will not start untill initiateConnect()
// is called
guard.assertIdenticalMutex ( cacIn.mutexRef () );
this->ioSeqNo = cacIn.sequenceNumberOfOutstandingIO ( guard );
if ( pConnCallBackIn == 0 ) {
this->cacCtx.incrementOutstandingIO ( cacIn.sequenceNumberOfOutstandingIO () );
cacIn.incrementOutstandingIO ( guard, this->ioSeqNo );
}
}
oldChannelNotify::~oldChannelNotify ()
{
this->io.destroy ();
}
void oldChannelNotify::destructor (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
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 ) {
this->cacCtx.decrementOutstandingIO ( this->ioSeqNo );
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
}
this->~oldChannelNotify ();
}
void oldChannelNotify::setPrivatePointer ( void *pPrivateIn )
{
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
this->pPrivate = pPrivateIn;
}
void * oldChannelNotify::privatePointer () const
{
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
return this->pPrivate;
}
int oldChannelNotify::replaceAccessRightsEvent ( caArh *pfunc )
{
// 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
// that will not upset the application.
this->pAccessRightsFunc = pfunc ? pfunc : cacNoopAccesRightsHandler;
if ( this->currentlyConnected ) {
bool isConnected;
caAccessRights tmp;
{
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
// 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
// that will not upset the application.
this->pAccessRightsFunc = pfunc ? pfunc : cacNoopAccesRightsHandler;
isConnected = this->currentlyConnected;
tmp = this->io.accessRights ();
}
if ( isConnected ) {
struct access_rights_handler_args args;
args.chid = this;
caAccessRights tmp = this->io.accessRights ();
args.ar.read_access = tmp.readPermit ();
args.ar.write_access = tmp.writePermit ();
( *pfunc ) ( args );
@@ -98,7 +112,8 @@ int oldChannelNotify::replaceAccessRightsEvent ( caArh *pfunc )
return ECA_NORMAL;
}
void oldChannelNotify::connectNotify ()
void oldChannelNotify::connectNotify (
epicsGuard < epicsMutex > & guard )
{
this->currentlyConnected = true;
this->prevConnected = true;
@@ -106,26 +121,34 @@ void oldChannelNotify::connectNotify ()
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_UP;
( *this->pConnCallBack ) ( args );
caCh * pFunc = this->pConnCallBack;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFunc ) ( args );
}
}
else {
this->cacCtx.decrementOutstandingIO ( this->ioSeqNo );
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
}
}
void oldChannelNotify::disconnectNotify ()
void oldChannelNotify::disconnectNotify (
epicsGuard < epicsMutex > & guard )
{
this->currentlyConnected = false;
if ( this->pConnCallBack ) {
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_DOWN;
( *this->pConnCallBack ) ( args );
caCh * pFunc = this->pConnCallBack;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFunc ) ( args );
}
}
else {
this->cacCtx.incrementOutstandingIO ( this->ioSeqNo );
this->cacCtx.incrementOutstandingIO (
guard, this->ioSeqNo );
}
}
@@ -134,31 +157,39 @@ void oldChannelNotify::serviceShutdownNotify ()
this->cacCtx.destroyChannel ( *this );
}
void oldChannelNotify::accessRightsNotify ( const caAccessRights &ar )
void oldChannelNotify::accessRightsNotify (
epicsGuard < epicsMutex > & guard, const caAccessRights & ar )
{
struct access_rights_handler_args args;
args.chid = this;
args.ar.read_access = ar.readPermit();
args.ar.write_access = ar.writePermit();
( *this->pAccessRightsFunc ) ( args );
caArh * pFunc = this->pAccessRightsFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFunc ) ( args );
}
}
void oldChannelNotify::exception ( int status, const char *pContext )
void oldChannelNotify::exception (
epicsGuard < epicsMutex > & guard, int status, const char * pContext )
{
this->cacCtx.exception ( status, pContext, __FILE__, __LINE__ );
this->cacCtx.exception ( guard, status, pContext, __FILE__, __LINE__ );
}
void oldChannelNotify::readException ( int status, const char *pContext,
void oldChannelNotify::readException (
epicsGuard < epicsMutex > & guard, int status, const char *pContext,
unsigned type, arrayElementCount count, void * /* pValue */ )
{
this->cacCtx.exception ( status, pContext,
this->cacCtx.exception ( guard, status, pContext,
__FILE__, __LINE__, *this, type, count, CA_OP_GET );
}
void oldChannelNotify::writeException ( int status, const char *pContext,
void oldChannelNotify::writeException (
epicsGuard < epicsMutex > & guard, int status, const char *pContext,
unsigned type, arrayElementCount count )
{
this->cacCtx.exception ( status, pContext,
this->cacCtx.exception ( guard, status, pContext,
__FILE__, __LINE__, *this, type, count, CA_OP_PUT );
}
@@ -180,3 +211,34 @@ void oldChannelNotify::operator delete ( void * )
__FILE__, __LINE__ );
}
void oldChannelNotify::read (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount count,
cacReadNotify & notify, cacChannel::ioid * pId )
{
this->io.read ( guard, type, count, notify, pId );
}
void oldChannelNotify::write (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount count, const void * pValue )
{
this->io.write ( guard, type, count, pValue );
}
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 );
}
void oldChannelNotify::subscribe (
epicsGuard < epicsMutex > & guard, unsigned type,
arrayElementCount count, unsigned mask, cacStateNotify & notify,
cacChannel::ioid & idOut)
{
this->io.subscribe ( guard, type, count, mask, notify, &idOut );
}

View File

@@ -29,44 +29,53 @@ oldSubscription::~oldSubscription ()
{
}
void oldSubscription::ioCancel ()
void oldSubscription::ioCancel ( epicsGuard < epicsMutex > & guard )
{
if ( this->subscribed ) {
this->chan.ioCancel ( this->id );
this->chan.ioCancel ( guard, this->id );
}
}
void oldSubscription::current (
void oldSubscription::current (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount count, const void * pData )
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = & this->chan;
args.type = static_cast < long > ( type );
args.count = static_cast < long > ( count );
args.status = ECA_NORMAL;
args.dbr = pData;
( *this->pFunc ) ( args );
caEventCallBackFunc * pFuncTmp = this->pFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) ( args );
}
}
void oldSubscription::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * /* pContext */,
unsigned type, arrayElementCount count )
{
if ( status == ECA_CHANDESTROY ) {
ca_client_context & cac = this->chan.getClientCtx ();
cac.destroySubscription ( *this );
cac.destroySubscription ( guard, *this );
}
else if ( status != ECA_DISCONN ) {
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.chid = & this->chan;
args.type = type;
args.count = count;
args.status = status;
args.dbr = 0;
( *this->pFunc ) ( args );
caEventCallBackFunc * pFuncTmp = this->pFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) ( args );
}
}
}

View File

@@ -31,8 +31,9 @@
#include "iocinf.h"
#include "oldAccess.h"
putCallback::putCallback ( oldChannelNotify &chanIn,
caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
putCallback::putCallback (
oldChannelNotify & chanIn, caEventCallBackFunc * pFuncIn,
void * pPrivateIn ) :
chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn )
{
}
@@ -41,7 +42,7 @@ putCallback::~putCallback ()
{
}
void putCallback::completion ()
void putCallback::completion ( epicsGuard < epicsMutex > & guard )
{
struct event_handler_args args;
@@ -51,11 +52,16 @@ void putCallback::completion ()
args.count = 0;
args.status = ECA_NORMAL;
args.dbr = 0;
( *this->pFunc ) (args);
this->chan.getClientCtx().destroyPutCallback ( *this );
caEventCallBackFunc * pFuncTmp = this->pFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) ( args );
}
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
}
void putCallback::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * /* pContext */,
unsigned type, arrayElementCount count )
{
@@ -67,9 +73,13 @@ void putCallback::exception (
args.count = count;
args.status = status;
args.dbr = 0;
( *this->pFunc ) (args);
caEventCallBackFunc * pFuncTmp = this->pFunc;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) (args);
}
}
this->chan.getClientCtx().destroyPutCallback ( *this );
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
}
void * putCallback::operator new ( size_t ) // X aCC 361

View File

@@ -87,11 +87,11 @@
#include "envDefs.h"
#include "tsFreeList.h"
#include "osiWireFormat.h"
#include "taskwd.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "caProto.h"
#include "taskwd.h"
#include "udpiiu.h"
#include "repeaterClient.h"

View File

@@ -41,6 +41,11 @@ repeaterSubscribeTimer::~repeaterSubscribeTimer ()
this->timer.destroy ();
}
void repeaterSubscribeTimer::shutdown ()
{
this->timer.cancel ();
}
epicsTimerNotify::expireStatus repeaterSubscribeTimer::
expire ( const epicsTime & /* currentTime */ ) // X aCC 361
{

View File

@@ -35,6 +35,7 @@ class repeaterSubscribeTimer : private epicsTimerNotify {
public:
repeaterSubscribeTimer ( udpiiu &, epicsTimerQueue & );
virtual ~repeaterSubscribeTimer ();
void shutdown ();
void confirmNotify ();
void show ( unsigned level ) const;
private:

View File

@@ -23,6 +23,10 @@
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#if 0
#define DEBUG
#endif
#include "tsMinMax.h"
#define epicsExportSharedSymbols
@@ -47,7 +51,7 @@ searchTimer::searchTimer ( udpiiu & iiuIn,
iiu ( iiuIn ),
mutex ( mutexIn ),
framesPerTry ( initialTriesPerFrame ),
framesPerTryCongestThresh ( UINT_MAX ),
framesPerTryCongestThresh ( DBL_MAX ),
minRetry ( 0 ),
minRetryThisPass ( UINT_MAX ),
searchAttempts ( 0u ),
@@ -55,7 +59,8 @@ searchTimer::searchTimer ( udpiiu & iiuIn,
searchAttemptsThisPass ( 0u ),
searchResponsesThisPass ( 0u ),
dgSeqNoAtTimerExpireBegin ( 0u ),
dgSeqNoAtTimerExpireEnd ( 0u )
dgSeqNoAtTimerExpireEnd ( 0u ),
stopped ( false )
{
}
@@ -64,22 +69,30 @@ searchTimer::~searchTimer ()
this->timer.destroy ();
}
void searchTimer::shutdown ()
{
this->stopped = true;
this->timer.cancel ();
}
void searchTimer::newChannelNotify (
epicsGuard < udpMutex > & guard, const epicsTime & currentTime,
bool firstChannel, unsigned minRetryNo )
{
if ( firstChannel ) {
this->recomputeTimerPeriod ( guard, minRetryNo );
double newPeriod = this->period;
{
// avoid timer cancel block deadlock
epicsGuardRelease < udpMutex > unguard ( guard );
this->timer.start ( *this, currentTime + newPeriod );
if ( ! this->stopped ) {
if ( firstChannel ) {
this->recomputeTimerPeriod ( guard, minRetryNo );
double newPeriod = this->period;
{
// avoid timer cancel block deadlock
epicsGuardRelease < udpMutex > unguard ( guard );
this->timer.start ( *this, currentTime + newPeriod );
}
}
else {
this->recomputeTimerPeriodAndStartTimer ( guard,
currentTime, minRetryNo, 0.0 );
}
}
else {
this->recomputeTimerPeriodAndStartTimer ( guard,
currentTime, minRetryNo, 0.0 );
}
}
@@ -110,7 +123,7 @@ void searchTimer::recomputeTimerPeriod (
void searchTimer::recomputeTimerPeriodAndStartTimer ( epicsGuard < udpMutex > & guard,
const epicsTime & currentTime, unsigned minRetryNew, const double & initialDelay )
{
if ( this->iiu.channelCount ( guard ) == 0 ) {
if ( this->iiu.unresolvedChannelCount ( guard ) == 0 || this->stopped ) {
return;
}
@@ -159,7 +172,7 @@ void searchTimer::recomputeTimerPeriodAndStartTimer ( epicsGuard < udpMutex > &
void searchTimer::notifySearchResponse ( epicsGuard < udpMutex > & guard,
ca_uint32_t respDatagramSeqNo, bool seqNumberIsValid, const epicsTime & currentTime )
{
if ( this->iiu.channelCount ( guard ) == 0 ) {
if ( this->iiu.unresolvedChannelCount ( guard ) == 0 || this->stopped ) {
return;
}
@@ -186,14 +199,7 @@ void searchTimer::notifySearchResponse ( epicsGuard < udpMutex > & guard,
}
if ( reschedualNeeded ) {
# if defined(DEBUG) && 0
char buf[64];
epicsTime ts = currentTime;
ts.strftime ( buf, sizeof(buf), "%M:%S.%09f");
# endif
// debugPrintf ( ( "Response set timer delay to zero. ts=%s\n",
// buf ) );
debugPrintf ( ( "Response set timer delay to zero\n" ) );
// avoid timer cancel block deadlock
epicsGuardRelease < udpMutex > unguard ( guard );
this->timer.start ( *this, currentTime );
@@ -208,12 +214,13 @@ epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTi
epicsGuard < udpMutex > guard ( this->mutex );
// check to see if there is nothing to do here
if ( this->iiu.channelCount ( guard ) == 0 ) {
if ( this->iiu.unresolvedChannelCount ( guard ) == 0 ) {
debugPrintf ( ( "all channels located - search timer terminating\n" ) );
this->period = DBL_MAX;
return noRestart;
}
#if 0
//
// dynamically adjust the number of UDP frames per
// try depending how many search requests are not
@@ -260,9 +267,37 @@ epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTi
this->framesPerTry--;
}
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
debugPrintf ( ("Congestion detected - set frames per try to %f t=%u r=%u\n",
this->framesPerTry, this->searchAttempts, this->searchResponses) );
}
#else
if ( this->searchResponses == this->searchAttempts ) {
// increase UDP frames per try if we have a good score
if ( this->framesPerTry < maxTriesPerFrame ) {
// a congestion avoidance threshold similar to TCP is now used
if ( this->framesPerTry < this->framesPerTryCongestThresh ) {
double doubled = 2 * this->framesPerTry;
if ( doubled > this->framesPerTryCongestThresh ) {
this->framesPerTry = this->framesPerTryCongestThresh;
}
else {
this->framesPerTry = doubled;
}
}
else {
this->framesPerTry += 1.0 / this->framesPerTry;
}
debugPrintf ( ("Increasing frame count to %u t=%u r=%u\n",
this->framesPerTry, this->searchAttempts, this->searchResponses) );
}
}
else {
this->framesPerTryCongestThresh = this->framesPerTry / 2.0;
this->framesPerTry = 1u;
debugPrintf ( ("Congestion detected - set frames per try to %u t=%u r=%u\n",
this->framesPerTry, this->searchAttempts, this->searchResponses) );
}
#endif
if ( this->searchAttemptsThisPass <= UINT_MAX - this->searchAttempts ) {
this->searchAttemptsThisPass += this->searchAttempts;
@@ -287,7 +322,7 @@ epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTi
while ( true ) {
// check to see if we have reached the end of the list
if ( this->searchAttemptsThisPass >= this->iiu.channelCount ( guard ) ) {
if ( this->searchAttemptsThisPass >= this->iiu.unresolvedChannelCount ( guard ) ) {
// if we are making some progress then dont increase the
// delay between search requests
if ( this->searchResponsesThisPass == 0u ) {
@@ -330,7 +365,7 @@ epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTi
//
// dont send any of the channels twice within one try
//
if ( nChanSent >= this->iiu.channelCount ( guard ) ) {
if ( nChanSent >= this->iiu.unresolvedChannelCount ( guard ) ) {
//
// add one to nFrameSent because there may be
// one more partial frame to be sent
@@ -363,7 +398,7 @@ epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTi
nFrameSent, this->period, buf ) );
# endif
if ( this->iiu.channelCount ( guard ) == 0 ) {
if ( this->iiu.unresolvedChannelCount ( guard ) == 0 ) {
debugPrintf ( ( "all channels connected\n" ) );
this->period = DBL_MAX;
return noRestart;

View File

@@ -57,14 +57,15 @@ public:
unsigned minRetryNo );
void beaconAnomalyNotify ( epicsGuard < udpMutex > &,
const epicsTime & currentTime, const double & delay );
void shutdown ();
void show ( unsigned level ) const;
private:
double period; /* period between tries */
epicsTimer & timer;
class udpiiu & iiu;
udpMutex & mutex;
unsigned framesPerTry; /* # of UDP frames per search try */
unsigned framesPerTryCongestThresh; /* one half N tries w congest */
double framesPerTry; /* # of UDP frames per search try */
double framesPerTryCongestThresh; /* one half N tries w congest */
unsigned minRetry; /* min retry number so far */
unsigned minRetryThisPass;
unsigned searchAttempts; /* num search tries within this timer experation */
@@ -73,6 +74,7 @@ private:
unsigned searchResponsesThisPass; /* num search resp within this pass */
ca_uint32_t dgSeqNoAtTimerExpireBegin;
ca_uint32_t dgSeqNoAtTimerExpireEnd;
bool stopped;
expireStatus expire ( const epicsTime & currentTime );
void recomputeTimerPeriod ( epicsGuard < udpMutex > &, unsigned minRetryNew );
void recomputeTimerPeriodAndStartTimer ( epicsGuard < udpMutex > &,

View File

@@ -30,7 +30,7 @@
template < class T >
class sgAutoPtr {
public:
sgAutoPtr ( struct CASG & );
sgAutoPtr ( epicsGuard < epicsMutex > &, struct CASG & );
~sgAutoPtr ();
sgAutoPtr < T > & operator = ( T * );
T * operator -> ();
@@ -40,25 +40,27 @@ public:
private:
T * pNotify;
struct CASG & sg;
epicsGuard < epicsMutex > & guard;
};
template < class T >
inline sgAutoPtr < T > :: sgAutoPtr ( struct CASG & sgIn ) :
pNotify ( 0 ), sg ( sgIn )
inline sgAutoPtr < T > :: sgAutoPtr (
epicsGuard < epicsMutex > & guardIn, struct CASG & sgIn ) :
pNotify ( 0 ), sg ( sgIn ), guard ( guardIn )
{
}
template < class T >
inline sgAutoPtr < T > :: ~sgAutoPtr ()
{
this->sg.destroyPendingIO ( this->pNotify );
this->sg.destroyPendingIO ( this->guard, this->pNotify );
}
template < class T >
inline sgAutoPtr < T > & sgAutoPtr < T > :: operator = ( T * pNotifyIn )
{
if ( this->pNotify ) {
this->sg.destroyPendingIO ( this->pNotify );
this->sg.destroyPendingIO ( this->guard, this->pNotify );
}
this->pNotify = pNotifyIn;
return *this;

View File

@@ -52,24 +52,22 @@ static const unsigned CASG_MAGIC = 0xFAB4CAFE;
// is applied
class casgRecycle { // X aCC 655
public:
virtual void recycleSyncGroupWriteNotify ( class syncGroupWriteNotify & io ) = 0;
virtual void recycleSyncGroupReadNotify ( class syncGroupReadNotify & io ) = 0;
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 ( struct CASG &sgIn, chid );
virtual void destroy ( casgRecycle & ) = 0;
void show ( unsigned level ) const;
bool ioInitiated () const;
syncGroupNotify ();
virtual void destroy (
epicsGuard < epicsMutex > &, casgRecycle & ) = 0;
virtual void show (
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
protected:
chid chan;
struct CASG & sg;
const unsigned magic;
cacChannel::ioid id;
bool idIsValid;
virtual ~syncGroupNotify ();
syncGroupNotify ( const syncGroupNotify & );
syncGroupNotify & operator = ( const syncGroupNotify & );
@@ -80,14 +78,20 @@ public:
static syncGroupReadNotify * factory (
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &,
struct CASG &, chid, void *pValueIn );
void begin ( unsigned type, arrayElementCount count );
void destroy ( casgRecycle & );
void show ( unsigned level ) const;
void begin ( epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count );
void destroy ( epicsGuard < epicsMutex > &, casgRecycle & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
protected:
virtual ~syncGroupReadNotify ();
private:
void *pValue;
syncGroupReadNotify ( struct CASG &sgIn, chid, void *pValueIn );
chid chan;
struct CASG & sg;
const unsigned magic;
cacChannel::ioid id;
bool idIsValid;
void * pValue;
syncGroupReadNotify ( struct CASG & sgIn, chid, void * pValueIn );
void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
@@ -95,9 +99,11 @@ private:
epicsPlacementDeleteOperator (( void *,
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & ))
void completion (
unsigned type, arrayElementCount count, const void *pData );
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void * pData );
void exception (
int status, const char *pContext, unsigned type, arrayElementCount count );
epicsGuard < epicsMutex > &, int status,
const char * pContext, unsigned type, arrayElementCount count );
syncGroupReadNotify ( const syncGroupReadNotify & );
syncGroupReadNotify & operator = ( const syncGroupReadNotify & );
};
@@ -107,14 +113,18 @@ public:
static syncGroupWriteNotify * factory (
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &,
struct CASG &, chid );
void begin ( unsigned type,
arrayElementCount count, const void * pValueIn );
void destroy ( casgRecycle & );
void show ( unsigned level ) const;
void begin ( epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void * pValueIn );
void destroy ( epicsGuard < epicsMutex > &, casgRecycle & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
protected:
virtual ~syncGroupWriteNotify (); // allocate only from pool
private:
void *pValue;
chid chan;
struct CASG & sg;
const unsigned magic;
cacChannel::ioid id;
bool idIsValid;
syncGroupWriteNotify ( struct CASG &, chid );
void * operator new ( size_t );
void operator delete ( void * );
@@ -122,8 +132,9 @@ private:
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & ))
void completion ();
void exception ( int status, const char *pContext,
void completion ( epicsGuard < epicsMutex > & );
void exception (
epicsGuard < epicsMutex > &, int status, const char *pContext,
unsigned type, arrayElementCount count );
syncGroupWriteNotify ( const syncGroupWriteNotify & );
syncGroupWriteNotify & operator = ( const syncGroupWriteNotify & );
@@ -131,52 +142,52 @@ private:
struct ca_client_context;
class casgMutex {
public:
void lock ();
void unlock ();
void show ( unsigned level ) const;
private:
epicsMutex mutex;
};
template < class T > class sgAutoPtr;
struct CASG : public chronIntIdRes < CASG >, private casgRecycle {
public:
CASG ( ca_client_context & cacIn );
~CASG ();
bool ioComplete ();
bool verify () const;
int block ( double timeout );
void reset ();
CASG ( epicsGuard < epicsMutex > &, ca_client_context & cacIn );
void destructor ( epicsGuard < epicsMutex > & );
bool ioComplete ( epicsGuard < epicsMutex > & );
bool verify ( epicsGuard < epicsMutex > & ) const;
int block ( epicsGuard < epicsMutex > &, double timeout );
void reset ( epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void get ( chid pChan, unsigned type, arrayElementCount count, void * pValue );
void put ( chid pChan, unsigned type, arrayElementCount count, const void * pValue );
void completionNotify ( syncGroupNotify & );
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 (
epicsGuard < epicsMutex > &, syncGroupNotify & );
int printf ( const char * pFormat, ... );
void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo );
void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo, oldChannelNotify &chan,
void exception (
epicsGuard < epicsMutex > &, int status, const char * pContext,
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, tsFreeList < struct CASG, 128 > & );
epicsPlacementDeleteOperator (( void *, tsFreeList < struct CASG, 128 > & ))
void * operator new ( size_t size,
tsFreeList < struct CASG, 128, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < struct CASG, 128, epicsMutexNOOP > & ))
private:
tsDLList < syncGroupNotify > ioPendingList;
tsDLList < syncGroupNotify > ioCompletedList;
casgMutex mutable mutex;
epicsEvent sem;
ca_client_context & client;
unsigned magic;
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > freeListReadOP;
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > freeListWriteOP;
void recycleSyncGroupWriteNotify ( syncGroupWriteNotify &io );
void recycleSyncGroupReadNotify ( syncGroupReadNotify &io );
void recycleSyncGroupWriteNotify (
epicsGuard < epicsMutex > &, syncGroupWriteNotify & io );
void recycleSyncGroupReadNotify (
epicsGuard < epicsMutex > &, syncGroupReadNotify & io );
void destroyPendingIO ( syncGroupNotify * );
void destroyCompletedIO ();
void destroyPendingIO ();
void destroyPendingIO ( epicsGuard < epicsMutex > &, syncGroupNotify * );
void destroyCompletedIO ( epicsGuard < epicsMutex > & );
void destroyPendingIO ( epicsGuard < epicsMutex > & );
CASG ( const CASG & );
CASG & operator = ( const CASG & );
@@ -184,42 +195,24 @@ private:
void * operator new ( size_t size );
void operator delete ( void * );
~CASG ();
friend class sgAutoPtr < syncGroupWriteNotify >;
friend class sgAutoPtr < syncGroupReadNotify >;
};
inline void * CASG::operator new ( size_t size,
tsFreeList < struct CASG, 128 > & freeList )
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 > & freeList )
tsFreeList < struct CASG, 128, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
inline bool syncGroupNotify::ioInitiated () const
{
return this->idIsValid;
}
inline void casgMutex::lock ()
{
this->mutex.lock ();
}
inline void casgMutex::unlock ()
{
this->mutex.unlock ();
}
inline void casgMutex::show ( unsigned level ) const
{
this->mutex.show ( level );
}
#endif // ifdef syncGrouph

View File

@@ -22,24 +22,14 @@
#include "syncGroup.h"
#include "oldAccess.h"
syncGroupNotify::syncGroupNotify ( CASG &sgIn, chid chanIn ) :
chan ( chanIn ), sg ( sgIn ),
magic ( CASG_MAGIC ), id ( 0u ), idIsValid ( false )
syncGroupNotify::syncGroupNotify ()
{
}
syncGroupNotify::~syncGroupNotify ()
{
if ( this->idIsValid ) {
this->chan->ioCancel ( this->id );
}
}
void syncGroupNotify::show ( unsigned /* level */ ) const
{
::printf ( "pending sg op: chan=%s magic=%u sg=%p\n",
this->chan->pName(), this->magic,
static_cast <void *> ( &this->sg ) );
}

View File

@@ -25,43 +25,50 @@
#include "syncGroup.h"
#include "oldAccess.h"
syncGroupReadNotify::syncGroupReadNotify ( CASG &sgIn, chid pChan, void *pValueIn ) :
syncGroupNotify ( sgIn, pChan ), pValue ( pValueIn )
syncGroupReadNotify::syncGroupReadNotify (
CASG & sgIn, chid pChan, void * pValueIn ) :
chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ),
id ( 0u ), idIsValid ( false ), pValue ( pValueIn )
{
}
void syncGroupReadNotify::begin ( unsigned type, arrayElementCount count )
void syncGroupReadNotify::begin (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount count )
{
this->chan->read ( type, count, *this, &this->id );
this->chan->read ( guard, type, count, *this, &this->id );
this->idIsValid = true;
}
syncGroupReadNotify * syncGroupReadNotify::factory (
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &freeList,
struct CASG &sg, chid chan, void *pValueIn )
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & freeList,
struct CASG & sg, chid chan, void * pValueIn )
{
return new ( freeList ) // X aCC 930
syncGroupReadNotify ( sg, chan, pValueIn );
}
void syncGroupReadNotify::destroy ( casgRecycle &recycle )
void syncGroupReadNotify::destroy (
epicsGuard < epicsMutex > & guard, casgRecycle & recycle )
{
if ( this->idIsValid ) {
this->chan->ioCancel ( guard, this->id );
}
this->~syncGroupReadNotify ();
recycle.recycleSyncGroupReadNotify ( * this );
recycle.recycleSyncGroupReadNotify ( guard, *this );
}
syncGroupReadNotify::~syncGroupReadNotify ()
{
if ( this->idIsValid ) {
this->chan->ioCancel ( this-> id );
}
}
void syncGroupReadNotify::completion (
unsigned type, arrayElementCount count, const void *pData )
epicsGuard < epicsMutex > & guard, unsigned type,
arrayElementCount count, const void * pData )
{
if ( this->magic != CASG_MAGIC ) {
this->sg.printf ( "cac: sync group io_complete(): bad sync grp op magic number?\n" );
this->sg.printf (
"cac: sync group io_complete(): bad sync grp op magic number?\n" );
return;
}
@@ -70,13 +77,15 @@ void syncGroupReadNotify::completion (
memcpy ( this->pValue, pData, size );
}
this->idIsValid = false;
this->sg.completionNotify ( *this );
this->sg.completionNotify ( guard, *this );
}
void syncGroupReadNotify::exception (
int status, const char *pContext, unsigned type, arrayElementCount count )
epicsGuard < epicsMutex > & guard, int status, const char * pContext,
unsigned type, arrayElementCount count )
{
this->sg.exception ( status, pContext,
this->idIsValid = false;
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
@@ -85,11 +94,14 @@ void syncGroupReadNotify::exception (
//
}
void syncGroupReadNotify::show ( unsigned level ) const
void syncGroupReadNotify::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
::printf ( "pending sg read op: pVal=%p\n", this->pValue );
if ( level > 0u ) {
this->syncGroupNotify::show ( level - 1u );
::printf ( "pending sg op: chan=%s magic=%u sg=%p\n",
this->chan->pName(), this->magic,
static_cast < void * > ( & this->sg ) );
}
}

View File

@@ -26,52 +26,60 @@
#include "oldAccess.h"
syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, chid pChan ) :
syncGroupNotify ( sgIn, pChan )
chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ),
id ( 0u ), idIsValid ( false )
{
}
void syncGroupWriteNotify::begin ( unsigned type,
arrayElementCount count, const void * pValueIn )
void syncGroupWriteNotify::begin (
epicsGuard < epicsMutex > & guard, unsigned type,
arrayElementCount count, const void * pValueIn )
{
this->chan->write ( type, count, pValueIn, *this, &this->id );
this->chan->write ( guard, type, count,
pValueIn, *this, &this->id );
this->idIsValid = true;
}
syncGroupWriteNotify * syncGroupWriteNotify::factory (
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &freeList,
struct CASG &sg, chid chan )
struct CASG & sg, chid chan )
{
return new ( freeList ) syncGroupWriteNotify ( sg, chan );
}
void syncGroupWriteNotify::destroy ( casgRecycle & recycle )
void syncGroupWriteNotify::destroy (
epicsGuard < epicsMutex > & guard, casgRecycle & recycle )
{
if ( this->idIsValid ) {
this->chan->ioCancel ( guard, this->id );
}
this->~syncGroupWriteNotify ();
recycle.recycleSyncGroupWriteNotify ( * this );
recycle.recycleSyncGroupWriteNotify ( guard, *this );
}
syncGroupWriteNotify::~syncGroupWriteNotify ()
{
if ( this->idIsValid ) {
this->chan->ioCancel ( this->id );
}
}
void syncGroupWriteNotify::completion ()
void syncGroupWriteNotify::completion (
epicsGuard < epicsMutex > & guard )
{
if ( this->magic != CASG_MAGIC ) {
this->sg.printf ( "cac: sync group io_complete(): bad sync grp op magic number?\n" );
return;
}
this->idIsValid = false;
this->sg.completionNotify ( *this );
this->sg.completionNotify ( guard, *this );
}
void syncGroupWriteNotify::exception (
epicsGuard < epicsMutex > & guard,
int status, const char *pContext, unsigned type, arrayElementCount count )
{
this->sg.exception ( status, pContext,
this->sg.exception ( guard, status, pContext,
__FILE__, __LINE__, *this->chan, type, count, CA_OP_PUT );
this->idIsValid = false;
//
// This notify is left installed at this point as a place holder indicating that
// all requests have not been completed. This notify is not uninstalled until
@@ -79,11 +87,14 @@ void syncGroupWriteNotify::exception (
//
}
void syncGroupWriteNotify::show ( unsigned level ) const
void syncGroupWriteNotify::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
::printf ( "pending write sg op\n" );
if ( level > 0u ) {
this->syncGroupNotify::show ( level - 1u );
::printf ( "pending sg op: chan=%s magic=%u sg=%p\n",
this->chan->pName(), this->magic,
static_cast < void * > ( &this->sg ) );
}
}

View File

@@ -26,9 +26,9 @@
*/
extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) // X aCC 361
{
ca_client_context *pcac;
ca_client_context * pcac;
int caStatus;
CASG *pcasg;
CASG * pcasg;
caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
@@ -36,7 +36,8 @@ extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) // X aCC 361
}
try {
pcasg = new ( pcac->casgFreeList ) CASG ( *pcac );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
pcasg = new ( pcac->casgFreeList ) CASG ( guard, *pcac );
*pgid = pcasg->getId ();
return ECA_NORMAL;
}
@@ -59,12 +60,14 @@ extern "C" int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid )
return caStatus;
}
CASG * pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
CASG * pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
pcasg->~CASG ();
pcasg->destructor ( guard );
pcac->casgFreeList.release ( pcasg );
return ECA_NORMAL;
@@ -84,12 +87,14 @@ extern "C" int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeou
return status;
}
pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
status = ECA_BADSYNCGRP;
}
else {
status = pcasg->block ( timeout );
status = pcasg->block ( guard, timeout );
}
return status;
@@ -109,13 +114,15 @@ extern "C" int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid )
return caStatus;
}
pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
caStatus = ECA_BADSYNCGRP;
}
else {
caStatus = ECA_NORMAL;
pcasg->reset ();
pcasg->reset ( guard );
}
return caStatus;
@@ -126,21 +133,20 @@ extern "C" int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid )
*/
extern "C" int epicsShareAPI ca_sg_stat ( const CA_SYNC_GID gid )
{
ca_client_context *pcac;
CASG *pcasg;
int caStatus = fetchClientContext (&pcac);
ca_client_context * pcac;
int caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
CASG * pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
::printf ( "Bad Sync Group Id\n");
return ECA_BADSYNCGRP;
}
pcasg->show ( 1000u );
pcasg->show ( guard, 1000u );
return ECA_NORMAL;
}
@@ -159,12 +165,13 @@ extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) // X aCC 361
return caStatus;
}
pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
if ( pcasg->ioComplete () ) {
if ( pcasg->ioComplete ( guard ) ) {
return ECA_IODONE;
}
else{
@@ -187,13 +194,15 @@ extern "C" int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid, chtype typ
return caStatus;
}
pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
try {
pcasg->put ( pChan, type,
pcasg->put ( guard, pChan, type,
static_cast < unsigned > ( count ), pValue );
return ECA_NORMAL;
}
@@ -250,13 +259,15 @@ extern "C" int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid, chtype typ
return caStatus;
}
pcasg = pcac->lookupCASG ( gid );
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
try {
pcasg->get ( pChan, type,
pcasg->get ( guard, pChan, type,
static_cast < unsigned > ( count ), pValue );
return ECA_NORMAL;
}

View File

@@ -29,10 +29,12 @@
// the recv watchdog timer is active when this object is created
//
tcpRecvWatchdog::tcpRecvWatchdog
( cac & cacIn, tcpiiu & iiuIn, double periodIn, epicsTimerQueue & queueIn ) :
( callbackMutex & cbMutexIn, epicsMutex & mutexIn, tcpiiu & iiuIn,
double periodIn, epicsTimerQueue & queueIn ) :
period ( periodIn ), timer ( queueIn.createTimer () ),
iiu ( iiuIn ), cacRef ( cacIn ), responsePending ( false ),
beaconAnomaly ( true )
iiu ( iiuIn ), cbMutex ( cbMutexIn ), mutex ( mutexIn ),
probeResponsePending ( false ), beaconAnomaly ( true ),
probeTimeoutDetected ( false )
{
}
@@ -44,21 +46,20 @@ tcpRecvWatchdog::~tcpRecvWatchdog ()
epicsTimerNotify::expireStatus
tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) // X aCC 361
{
if ( this->responsePending ) {
if ( this->probeResponsePending ) {
if ( this->iiu.bytesArePendingInOS() ) {
this->cacRef.printf (
this->iiu.printf (
"The CA client library's server inactivity timer initiated server disconnect\n" );
this->cacRef.printf (
this->iiu.printf (
"despite the fact that messages from this server are pending for processing in\n" );
this->cacRef.printf (
this->iiu.printf (
"the client library. Here are some possible causes of the unnecessary disconnect:\n" );
this->cacRef.printf (
this->iiu.printf (
"o ca_pend_event() or ca_poll() have not been called for %f seconds\n",
this->period );
this->cacRef.printf (
this->iiu.printf (
"o application is blocked in a callback from the client library\n" );
}
this->cancel ();
# ifdef DEBUG
char hostName[128];
this->iiu.hostName ( hostName, sizeof (hostName) );
@@ -66,19 +67,31 @@ tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) // X aCC 361
"- disconnecting.\n",
hostName, this->period ) );
# endif
this->cacRef.unresponsiveCircuitNotify ( this->iiu );
{
epicsGuard < callbackMutex > cbGuard ( this->cbMutex );
epicsGuard < epicsMutex > guard ( this->mutex );
this->iiu.receiveTimeoutNotify ( cbGuard, guard );
this->probeTimeoutDetected = true;
}
return noRestart;
}
else {
this->responsePending = this->iiu.setEchoRequestPending ();
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->probeTimeoutDetected = false;
this->probeResponsePending = this->iiu.setEchoRequestPending ( guard );
}
debugPrintf ( ("TCP connection timed out - sending echo request\n") );
return expireStatus ( restart, CA_ECHO_TIMEOUT );
}
}
void tcpRecvWatchdog::beaconArrivalNotify ( const epicsTime & currentTime )
void tcpRecvWatchdog::beaconArrivalNotify (
epicsGuard < epicsMutex > & guard, const epicsTime & currentTime )
{
if ( ! this->beaconAnomaly && ! this->responsePending ) {
guard.assertIdenticalMutex ( this->mutex );
if ( ! this->beaconAnomaly && ! this->probeResponsePending ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
this->timer.start ( *this, currentTime + this->period );
debugPrintf ( ("Saw a normal beacon - reseting TCP recv watchdog\n") );
}
@@ -91,18 +104,65 @@ void tcpRecvWatchdog::beaconArrivalNotify ( const epicsTime & currentTime )
// faster when the server is rebooted twice in rapid
// succession before a 1st or 2nd beacon has been received)
//
void tcpRecvWatchdog::beaconAnomalyNotify ()
void tcpRecvWatchdog::beaconAnomalyNotify (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->beaconAnomaly = true;
debugPrintf ( ("Saw an abnormal beacon\n") );
}
void tcpRecvWatchdog::messageArrivalNotify ( const epicsTime & currentTime )
void tcpRecvWatchdog::messageArrivalNotify (
const epicsTime & currentTime )
{
this->beaconAnomaly = false;
this->responsePending = false;
this->timer.start ( *this, currentTime + this->period );
debugPrintf ( ("received a message - reseting TCP recv watchdog\n") );
bool restartNeeded = false;
{
epicsGuard < epicsMutex > guard ( this->mutex );
if ( ! this->probeResponsePending ) {
this->beaconAnomaly = false;
restartNeeded = true;
}
}
// dont hold the lock for fear of deadlocking
// because cancel is blocking for the completion
// of the recvDog expire which takes the lock
// - it take also the callback lock
if ( restartNeeded ) {
this->timer.start ( *this, currentTime + this->period );
debugPrintf ( ("received a message - reseting TCP recv watchdog\n") );
}
}
void tcpRecvWatchdog::probeResponseNotify (
epicsGuard < callbackMutex > & cbGuard,
const epicsTime & currentTime )
{
bool restartNeeded = false;
double restartDelay = DBL_MAX;
{
epicsGuard < epicsMutex > guard ( this->mutex );
if ( this->probeResponsePending ) {
restartNeeded = true;
if ( this->probeTimeoutDetected ) {
this->probeTimeoutDetected = false;
this->probeResponsePending = this->iiu.setEchoRequestPending ( guard );
restartDelay = CA_ECHO_TIMEOUT;
debugPrintf ( ("late probe response - sending another probe request\n") );
}
else {
this->probeResponsePending = false;
restartDelay = this->period;
this->iiu.responsiveCircuitNotify ( cbGuard, guard );
debugPrintf ( ("probe response on time - setting circuit to reponsive state\n") );
}
}
}
if ( restartNeeded ) {
// timer callback takes the callback mutex and the cac mutex
epicsGuardRelease < callbackMutex > cbGuardRelease ( cbGuard );
epicsTime expireTime = currentTime + restartDelay;
this->timer.start ( *this, expireTime );
}
}
//
@@ -119,15 +179,25 @@ void tcpRecvWatchdog::messageArrivalNotify ( const epicsTime & currentTime )
// The send watchdog will be responsible for detecting
// dead connections in this case.
//
void tcpRecvWatchdog::sendBacklogProgressNotify ( const epicsTime & currentTime )
void tcpRecvWatchdog::sendBacklogProgressNotify (
epicsGuard < epicsMutex > & guard,
const epicsTime & currentTime )
{
guard.assertIdenticalMutex ( this->mutex );
// We dont set "beaconAnomaly" to be false here because, after we see a
// beacon anomaly (which could be transiently detecting a reboot) we will
// not trust the beacon as an indicator of a healthy server until we
// receive at least one message from the server.
this->responsePending = false;
this->timer.start ( *this, currentTime + this->period );
debugPrintf ( ("saw heavy send backlog - reseting TCP recv watchdog\n") );
if ( this->probeResponsePending ) {
// we avoid calling this with the lock applied because
// it restarts the recv wd timer, this might block
// until a recv wd timer expire callback completes, and
// this callback takes the lock
epicsGuardRelease < epicsMutex > unguard ( guard );
this->timer.start ( *this, currentTime + CA_ECHO_TIMEOUT );
debugPrintf ( ("saw heavy send backlog - reseting TCP recv watchdog\n") );
}
}
void tcpRecvWatchdog::connectNotify ()
@@ -136,6 +206,28 @@ void tcpRecvWatchdog::connectNotify ()
debugPrintf ( ("connected to the server - reseting TCP recv watchdog\n") );
}
void tcpRecvWatchdog::sendTimeoutNotify (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & guard,
const epicsTime & currentTime )
{
guard.assertIdenticalMutex ( this->mutex );
bool restartNeeded = false;
if ( ! this->probeResponsePending ) {
this->probeResponsePending = this->iiu.setEchoRequestPending ( guard );
restartNeeded = true;
}
if ( restartNeeded ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
{
epicsGuardRelease < callbackMutex > cbUnguard ( cbGuard );
this->timer.start ( *this, currentTime + CA_ECHO_TIMEOUT );
}
}
debugPrintf ( ("TCP send timed out - sending echo request\n") );
}
void tcpRecvWatchdog::cancel ()
{
this->timer.cancel ();
@@ -149,10 +241,15 @@ double tcpRecvWatchdog::delay () const
void tcpRecvWatchdog::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
::printf ( "Receive virtual circuit watchdog at %p, period %f\n",
static_cast <const void *> ( this ), this->period );
if ( level > 0u ) {
::printf ( "\tresponse pending boolean %u, beacon anomaly boolean %u\n",
this->responsePending, this->beaconAnomaly );
::printf ( "\t%s %s %s\n",
this->probeResponsePending ? "probe-response-pending" : "",
this->beaconAnomaly ? "beacon-anomaly-detected" : "",
this->probeTimeoutDetected ? "probe-response-timeout" : "" );
}
}

View File

@@ -33,27 +33,40 @@ class tcpiiu;
class tcpRecvWatchdog : private epicsTimerNotify {
public:
tcpRecvWatchdog ( cac &, tcpiiu &,
tcpRecvWatchdog ( callbackMutex &,
epicsMutex &, tcpiiu &,
double periodIn, epicsTimerQueue & );
virtual ~tcpRecvWatchdog ();
void sendBacklogProgressNotify (
epicsGuard < epicsMutex > &,
const epicsTime & currentTime );
void messageArrivalNotify (
const epicsTime & currentTime );
void beaconArrivalNotify (
void probeResponseNotify (
epicsGuard < callbackMutex > &,
const epicsTime & currentTime );
void beaconAnomalyNotify ();
void beaconArrivalNotify (
epicsGuard < epicsMutex > &,
const epicsTime & currentTime );
void beaconAnomalyNotify ( epicsGuard < epicsMutex > & );
void connectNotify ();
void sendTimeoutNotify (
epicsGuard < callbackMutex > &,
epicsGuard < epicsMutex > &,
const epicsTime & currentTime );
#pragma message ("too low level?")
void cancel ();
void show ( unsigned level ) const;
double delay () const;
private:
const double period;
epicsTimer & timer;
callbackMutex & cbMutex;
epicsMutex & mutex;
tcpiiu & iiu;
cac & cacRef;
bool responsePending;
bool probeResponsePending;
bool beaconAnomaly;
bool probeTimeoutDetected;
expireStatus expire ( const epicsTime & currentTime );
tcpRecvWatchdog ( const tcpRecvWatchdog & );
tcpRecvWatchdog & operator = ( const tcpRecvWatchdog & );

View File

@@ -26,9 +26,10 @@
#include "virtualCircuit.h"
tcpSendWatchdog::tcpSendWatchdog
( cac & cacIn, tcpiiu & iiuIn, double periodIn, epicsTimerQueue & queueIn ) :
( callbackMutex & cbMutexIn, tcpiiu & iiuIn,
double periodIn, epicsTimerQueue & queueIn ) :
period ( periodIn ), timer ( queueIn.createTimer () ),
cacRef ( cacIn ), iiu ( iiuIn )
cbMutex ( cbMutexIn ), iiu ( iiuIn )
{
}
@@ -38,10 +39,10 @@ tcpSendWatchdog::~tcpSendWatchdog ()
}
epicsTimerNotify::expireStatus tcpSendWatchdog::expire (
const epicsTime & /* currentTime */ )
const epicsTime & currentTime )
{
if ( this->iiu.bytesArePendingInOS() ) {
this->cacRef.printf (
this->iiu.printf (
"The CA client library is disconnecting after a flush request "
"timed out, but receive data is pending, probably because of an "
"application schedualing problem\n" );
@@ -52,7 +53,10 @@ epicsTimerNotify::expireStatus tcpSendWatchdog::expire (
debugPrintf ( ( "Request not accepted by CA server %s for %g sec. Disconnecting.\n",
hostName, this->period ) );
# endif
this->cacRef.unresponsiveCircuitNotify ( this->iiu );
{
epicsGuard < callbackMutex > cbGuard ( this->cbMutex );
this->iiu.sendTimeoutNotify ( currentTime, cbGuard );
}
return noRestart;
}

View File

@@ -31,14 +31,15 @@
class tcpSendWatchdog : private epicsTimerNotify {
public:
tcpSendWatchdog ( cac &, tcpiiu &, double periodIn, epicsTimerQueue & queueIn );
tcpSendWatchdog ( callbackMutex &, tcpiiu &,
double periodIn, epicsTimerQueue & queueIn );
virtual ~tcpSendWatchdog ();
void start ( const epicsTime & );
void cancel ();
private:
const double period;
epicsTimer & timer;
cac & cacRef;
callbackMutex & cbMutex;
tcpiiu & iiu;
expireStatus expire ( const epicsTime & currentTime );
tcpSendWatchdog ( const tcpSendWatchdog & );

File diff suppressed because it is too large Load Diff

View File

@@ -58,17 +58,16 @@ template class tsFreeList < CASG, 128 >;
template class tsFreeList < syncGroupReadNotify, 128, epicsMutexNOOP >;
template class tsFreeList < syncGroupWriteNotify, 128, epicsMutexNOOP >;
template class tsFreeList < comBuf, 0x20 >;
template class tsFreeList < getCallback, 1024 >;
template class tsFreeList < getCopy, 1024 >;
template class tsFreeList < getCallback, 1024, epicsMutexNOOP >;
template class tsFreeList < getCopy, 1024, epicsMutexNOOP >;
template class tsFreeList < hostNameCache, 16 >;
template class tsFreeList < msgForMultiplyDefinedPV, 16 >;
template class tsFreeList < nciu, 1024 >;
template class tsFreeList < oldChannelNotify, 1024 >;
template class tsFreeList < oldSubscription, 1024 >;
template class tsFreeList < putCallback, 1024 >;
template class tsFreeList < oldSubscription, 1024, epicsMutexNOOP >;
template class tsFreeList < putCallback, 1024, epicsMutexNOOP >;
template class tsFreeList < repeaterClient, 0x20 >;
template class epicsSingleton <cacServiceList>;
template class epicsSingleton <localHostName>;
template class epicsSingleton < localHostName >;
#ifdef _MSC_VER
# pragma warning ( pop )

View File

@@ -36,8 +36,9 @@
#include "iocinf.h"
#include "inetAddrID.h"
#include "cac.h"
#include "repeaterSubscribeTimer.h"
#include "searchTimer.h"
#include "repeaterSubscribeTimer.h"
#include "disconnectGovernorTimer.h"
// UDP protocol dispatch table
const udpiiu::pProtoStubUDP udpiiu::udpJumpTableCAC [] =
@@ -69,8 +70,9 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca
recvThread ( *this, cbMutex,
"CAC-UDP",
epicsThreadGetStackSize ( epicsThreadStackMedium ),
cac::lowestPriorityLevelAbove
( cac.getInitializingThreadsPriority () ) ),
cac::lowestPriorityLevelAbove (
cac::lowestPriorityLevelAbove (
cac.getInitializingThreadsPriority () ) ) ),
rtteMean ( 5.0e-3 ), // seconds
cacRef ( cac ),
nBytesInXmitBuf ( 0 ),
@@ -78,6 +80,7 @@ udpiiu::udpiiu ( epicsTimerQueueActive & timerQueue, callbackMutex & cbMutex, ca
rtteSequenceNumber ( 0 ),
lastReceivedSeqNo ( 0 ),
sock ( 0 ),
pGovTmr ( new disconnectGovernorTimer ( *this, timerQueue ) ),
// The udpiiu and the search timer share the same lock because
// this is much more efficent with recursive locks. Also, access
// to the udp's netiiu base list is protected.
@@ -203,7 +206,14 @@ udpiiu::~udpiiu ()
// no need to own CAC lock here because the CA context
// is being decomissioned
tsDLIter < nciu > chan = this->channelList.firstIter ();
tsDLIter < nciu > chan = this->disconnGovernor.firstIter ();
while ( chan.valid () ) {
tsDLIter < nciu > next = chan;
next++;
chan->serviceShutdownNotify ();
chan = next;
}
chan = this->serverAddrRes.firstIter ();
while ( chan.valid () ) {
tsDLIter < nciu > next = chan;
next++;
@@ -226,6 +236,11 @@ udpiiu::~udpiiu ()
void udpiiu::shutdown ()
{
// stop all of the timers
this->pGovTmr->shutdown ();
this->pSearchTmr->shutdown ();
this->pRepeaterSubscribeTmr->shutdown ();
if ( ! this->recvThread.exitWait ( 0.0 ) ) {
unsigned tries = 0u;
@@ -353,8 +368,8 @@ void udpiiu::repeaterRegistrationMessage ( unsigned attemptNumber )
void epicsShareAPI caRepeaterRegistrationMessage (
SOCKET sock, unsigned repeaterPort, unsigned attemptNumber )
{
caHdr msg;
osiSockAddr saddr;
caHdr msg;
int status;
int len;
@@ -943,11 +958,18 @@ void udpiiu::show ( unsigned level ) const
::printf ("\tshut down command bool %u\n", this->shutdownCmd );
::printf ( "\trecv thread exit signal:\n" );
this->recvThread.show ( level - 2u );
::printf ( "search message timer:\n" );
this->pSearchTmr->show ( level - 2u );
::printf ( "repeater subscribee timer:\n" );
this->pRepeaterSubscribeTmr->show ( level - 2u );
tsDLIterConst < nciu > pChan = this->channelList.firstIter ();
::printf ( "disconnect governor subscribee timer:\n" );
this->pGovTmr->show ( level - 2u );
tsDLIterConst < nciu > pChan = this->disconnGovernor.firstIter ();
while ( pChan.valid () ) {
pChan->show ( level - 2u );
pChan++;
}
::printf ( "search message timer:\n" );
this->pSearchTmr->show ( level - 2u );
pChan = this->serverAddrRes.firstIter ();
while ( pChan.valid () ) {
pChan->show ( level - 2u );
pChan++;
@@ -990,7 +1012,7 @@ void udpiiu::beaconAnomalyNotify ( const epicsTime & currentTime )
{
epicsGuard <udpMutex> guard ( this->mutex );
tsDLIter < nciu > chan = this->channelList.firstIter ();
tsDLIter < nciu > chan = this->serverAddrRes.firstIter ();
while ( chan.valid () ) {
chan->beaconAnomalyNotify ();
chan++;
@@ -1022,13 +1044,13 @@ bool udpiiu::searchMsg ( epicsGuard < udpMutex > & /* guard */,
{
bool success;
if ( nciu *pChan = this->channelList.get () ) {
if ( nciu *pChan = this->serverAddrRes.get () ) {
success = pChan->searchMsg ( *this, retryNoForThisChannel );
if ( success ) {
this->channelList.add ( *pChan );
this->serverAddrRes.add ( *pChan );
}
else {
this->channelList.push ( *pChan );
this->serverAddrRes.push ( *pChan );
}
}
else {
@@ -1038,23 +1060,55 @@ bool udpiiu::searchMsg ( epicsGuard < udpMutex > & /* guard */,
return success;
}
void udpiiu::installChannel ( const epicsTime & currentTime,
nciu & chan, unsigned minRetryNo )
void udpiiu::installNewChannel ( const epicsTime & currentTime, nciu & chan )
{
bool firstChannel = false;
epicsGuard < udpMutex > guard ( this->mutex );
// add it to the front of the list so that
if ( this->serverAddrRes.count() == 0 ) {
firstChannel = true;
}
// push them to the front of the list so that
// a search request is sent immediately, and
// so that the new channel's retry count is
// seen when calculating the minimum retry
// which is used to compute the search interval
this->channelList.push ( chan );
if ( this->channelList.count() == 1 ) {
firstChannel = true;
}
this->serverAddrRes.push ( chan );
chan.channelNode::listMember =
channelNode::cs_serverAddrResPend;
this->pSearchTmr->newChannelNotify ( guard, currentTime,
firstChannel, minRetryNo );
firstChannel, 0 );
}
void udpiiu::installDisconnectedChannel ( nciu & chan )
{
epicsGuard < udpMutex > guard ( this->mutex );
this->disconnGovernor.add ( chan );
chan.channelNode::listMember =
channelNode::cs_disconnGov;
}
void udpiiu::govExpireNotify ( const epicsTime & currentTime )
{
epicsGuard < udpMutex > guard ( this->mutex );
if ( this->disconnGovernor.count () ) {
bool firstChannel = false;
if ( this->serverAddrRes.count() == 0 ) {
firstChannel = true;
}
// push them to the front of the list so that
// a search request is sent immediately, and
// so that the new channel's retry count is
// seen when calculating the minimum retry
// which is used to compute the search interval
while ( nciu * pChan = this->disconnGovernor.get () ) {
this->serverAddrRes.push ( *pChan );
pChan->channelNode::listMember =
channelNode::cs_serverAddrResPend;
}
this->pSearchTmr->newChannelNotify ( guard, currentTime,
firstChannel, disconnectRetrySetpoint );
}
}
int udpiiu::printf ( const char *pformat, ... )
@@ -1071,12 +1125,23 @@ int udpiiu::printf ( const char *pformat, ... )
return status;
}
void udpiiu::uninstallChan (
epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > &, nciu & chan )
void udpiiu::uninstallChan (
epicsGuard < epicsMutex > & guardIn, nciu & chan )
{
guardIn.assertIdenticalMutex ( this->cacRef.mutexRef () );
epicsGuard < udpMutex > guard ( this->mutex );
this->channelList.remove ( chan );
if ( chan.channelNode::listMember == channelNode::cs_disconnGov ) {
this->disconnGovernor.remove ( chan );
}
else if ( chan.channelNode::listMember == channelNode::cs_serverAddrResPend ) {
this->serverAddrRes.remove ( chan );
}
else {
this->cacRef.printf (
"cac: attempt to uninstall channel from udp iiu, but it inst installed there?" );
}
chan.channelNode::listMember = channelNode::cs_none;
}
void udpiiu::hostName ( char *pBuf, unsigned bufLength ) const
@@ -1099,60 +1164,74 @@ bool udpiiu::ca_v41_ok () const
return netiiu::ca_v41_ok ();
}
void udpiiu::writeRequest ( epicsGuard < cacMutex > & guard, nciu & chan, unsigned type,
unsigned nElem, const void * pValue )
void udpiiu::writeRequest ( epicsGuard < epicsMutex > & guard,
nciu & chan, unsigned type, arrayElementCount nElem, const void * pValue )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::writeRequest ( guard, chan, type, nElem, pValue );
}
void udpiiu::writeNotifyRequest ( epicsGuard < cacMutex > & guard, nciu & chan,
netWriteNotifyIO & io, unsigned type, unsigned nElem, const void *pValue )
void udpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan,
netWriteNotifyIO & io, unsigned type, arrayElementCount nElem, const void *pValue )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::writeNotifyRequest ( guard, chan, io, type, nElem, pValue );
}
void udpiiu::readNotifyRequest ( epicsGuard < cacMutex > & guard, nciu & chan,
netReadNotifyIO & io, unsigned type, unsigned nElem )
void udpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, nciu & chan,
netReadNotifyIO & io, unsigned type, arrayElementCount nElem )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::readNotifyRequest ( guard, chan, io, type, nElem );
}
void udpiiu::clearChannelRequest ( epicsGuard < cacMutex > & guard,
void udpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard,
ca_uint32_t sid, ca_uint32_t cid )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::clearChannelRequest ( guard, sid, cid );
}
void udpiiu::subscriptionRequest ( epicsGuard < cacMutex > & guard, nciu & chan,
void udpiiu::subscriptionRequest ( epicsGuard < epicsMutex > & guard, nciu & chan,
netSubscription & subscr )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::subscriptionRequest ( guard, chan, subscr );
}
void udpiiu::subscriptionCancelRequest ( epicsGuard < cacMutex > & guard,
void udpiiu::subscriptionUpdateRequest ( epicsGuard < epicsMutex > &, nciu &,
netSubscription & )
{
}
void udpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard,
nciu & chan, netSubscription & subscr )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::subscriptionCancelRequest ( guard, chan, subscr );
}
void udpiiu::flushRequest ()
void udpiiu::flushRequest ( epicsGuard < epicsMutex > & guard )
{
netiiu::flushRequest ();
netiiu::flushRequest ( guard );
}
bool udpiiu::flushBlockThreshold ( epicsGuard < cacMutex > & guard ) const
bool udpiiu::flushBlockThreshold ( epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
return netiiu::flushBlockThreshold ( guard );
}
void udpiiu::flushRequestIfAboveEarlyThreshold ( epicsGuard < cacMutex > & guard )
void udpiiu::flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::flushRequestIfAboveEarlyThreshold ( guard );
}
void udpiiu::blockUntilSendBacklogIsReasonable
( cacNotify & notify, epicsGuard < cacMutex > & guard )
( cacContextNotify & notify, epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
netiiu::blockUntilSendBacklogIsReasonable ( notify, guard );
}

View File

@@ -85,7 +85,7 @@ public:
udpiiu ( class epicsTimerQueueActive &, callbackMutex &, class cac & );
virtual ~udpiiu ();
void installNewChannel ( const epicsTime & currentTime, nciu & );
void installDisconnectedChannel ( const epicsTime & currentTime, nciu & );
void installDisconnectedChannel ( nciu & );
void repeaterRegistrationMessage ( unsigned attemptNumber );
bool searchMsg ( epicsGuard < udpMutex > &, unsigned & retryNoForThisChannel );
void datagramFlush ( epicsGuard < udpMutex > &, const epicsTime & currentTime );
@@ -94,10 +94,10 @@ public:
bool wakeupMsg ();
void repeaterConfirmNotify ();
void beaconAnomalyNotify ( const epicsTime & currentTime );
void govExpireNotify ( const epicsTime & currentTime );
int printf ( const char *pformat, ... );
unsigned channelCount ( epicsGuard < udpMutex > & ) const;
void uninstallChan (
epicsGuard < callbackMutex > &, epicsGuard < cacMutex > &, nciu & );
unsigned unresolvedChannelCount ( epicsGuard < udpMutex > & ) const;
void uninstallChan ( epicsGuard < epicsMutex > &, nciu & );
bool pushDatagramMsg ( const caHdr & hdr,
const void * pExt, ca_uint16_t extsize);
void shutdown ();
@@ -111,7 +111,9 @@ private:
char recvBuf [MAX_UDP_RECV];
mutable udpMutex mutex;
udpRecvThread recvThread;
tsDLList < nciu > channelList;
// nciu state field tells us which list
tsDLList < nciu > disconnGovernor;
tsDLList < nciu > serverAddrRes;
ELLLIST dest;
epicsTime rtteTimeStamp;
double rtteMean;
@@ -121,6 +123,7 @@ private:
ca_uint32_t rtteSequenceNumber;
ca_uint32_t lastReceivedSeqNo;
SOCKET sock;
epics_auto_ptr < class disconnectGovernorTimer > pGovTmr;
epics_auto_ptr < class searchTimer > pSearchTmr;
epics_auto_ptr < class repeaterSubscribeTimer > pRepeaterSubscribeTmr;
ca_uint16_t repeaterPort;
@@ -165,28 +168,29 @@ private:
const char * pHostName () const; // deprecated - please do not use
bool ca_v42_ok () const;
bool ca_v41_ok () const;
void writeRequest ( epicsGuard < cacMutex > &, nciu &, unsigned type,
unsigned nElem, const void *pValue );
void writeNotifyRequest ( epicsGuard < cacMutex > &, nciu &, netWriteNotifyIO &,
unsigned type, unsigned nElem, const void *pValue );
void readNotifyRequest ( epicsGuard < cacMutex > &, nciu &, netReadNotifyIO &,
unsigned type, unsigned nElem );
void clearChannelRequest ( epicsGuard < cacMutex > &,
void writeRequest ( epicsGuard < epicsMutex > &, nciu &, unsigned type,
arrayElementCount nElem, const void *pValue );
void writeNotifyRequest ( epicsGuard < epicsMutex > &, nciu &, netWriteNotifyIO &,
unsigned type, arrayElementCount nElem, const void *pValue );
void readNotifyRequest ( epicsGuard < epicsMutex > &, nciu &, netReadNotifyIO &,
unsigned type, arrayElementCount nElem );
void clearChannelRequest ( epicsGuard < epicsMutex > &,
ca_uint32_t sid, ca_uint32_t cid );
void subscriptionRequest ( epicsGuard < cacMutex > &, nciu &,
netSubscription &subscr );
void subscriptionRequest ( epicsGuard < epicsMutex > &, nciu &,
netSubscription & );
void subscriptionUpdateRequest ( epicsGuard < epicsMutex > &, nciu &,
netSubscription & );
bool pushVersionMsg ();
void subscriptionCancelRequest ( epicsGuard < cacMutex > &,
void subscriptionCancelRequest ( epicsGuard < epicsMutex > &,
nciu & chan, netSubscription & subscr );
void flushRequest ();
bool flushBlockThreshold ( epicsGuard < cacMutex > & ) const;
void flushRequestIfAboveEarlyThreshold ( epicsGuard < cacMutex > & );
void flushRequest ( epicsGuard < epicsMutex > & );
bool flushBlockThreshold ( epicsGuard < epicsMutex > & ) const;
void flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & );
void blockUntilSendBacklogIsReasonable
( cacNotify &, epicsGuard < cacMutex > & );
( cacContextNotify &, epicsGuard < epicsMutex > & );
void requestRecvProcessPostponedFlush ();
osiSockAddr getNetworkAddress () const;
double receiveWatchdogDelay () const;
void installChannel ( const epicsTime & currentTime, nciu &, unsigned minRetryNo );
udpiiu ( const udpiiu & );
udpiiu & operator = ( const udpiiu & );
@@ -215,10 +219,10 @@ inline void udpMutex::show ( unsigned level ) const
this->mutex.show ( level );
}
inline unsigned udpiiu::channelCount (
inline unsigned udpiiu::unresolvedChannelCount (
epicsGuard < udpMutex > & ) const
{
return this->channelList.count ();
return this->serverAddrRes.count ();
}
inline ca_uint32_t udpiiu::datagramSeqNumber (
@@ -233,15 +237,5 @@ inline double udpiiu::roundTripDelayEstimate (
return this->rtteMean;
}
inline void udpiiu::installNewChannel ( const epicsTime & currentTime, nciu & chan )
{
this->installChannel ( currentTime, chan, 0 );
}
inline void udpiiu::installDisconnectedChannel ( const epicsTime & currentTime, nciu & chan )
{
this->installChannel ( currentTime, chan, disconnectRetrySetpoint );
}
#endif // udpiiuh

View File

@@ -41,7 +41,7 @@
#include "compilerDependencies.h"
// a modified ca header with capacity for large arrays
struct caHdrLargeArray {
struct caHdrLargeArray {
ca_uint32_t m_postsize; // size of message extension
ca_uint32_t m_count; // operation data count
ca_uint32_t m_cid; // channel identifier
@@ -97,29 +97,34 @@ public:
const cacChannel::priLev & priorityIn );
~tcpiiu ();
void start ();
void initiateCleanShutdown ( epicsGuard < cacMutex > & );
void initiateCleanShutdown ( epicsGuard < epicsMutex > & );
void initiateAbortShutdown ( epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > & );
void unresponsiveCircuitNotify ( epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > & );
void tcpiiu::responsiveCircuitNotify (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard );
void disconnectNotify ( epicsGuard < cacMutex > & );
void beaconAnomalyNotify ();
epicsGuard < epicsMutex > & );
void responsiveCircuitNotify (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & guard );
void sendTimeoutNotify ( const epicsTime & currentTime,
epicsGuard < callbackMutex > & cbGuard );
void tcpiiu::receiveTimeoutNotify(
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & );
void beaconAnomalyNotify ( epicsGuard < epicsMutex > & );
void beaconArrivalNotify (
epicsGuard < epicsMutex > &,
const epicsTime & currentTime );
void probeResponseNotify (
epicsGuard < callbackMutex > &,
const epicsTime & currentTime );
void flushRequest ();
bool flushBlockThreshold ( epicsGuard < cacMutex > & ) const;
void flushRequestIfAboveEarlyThreshold ( epicsGuard < cacMutex > & );
void flushRequest ( epicsGuard < epicsMutex > & );
bool flushBlockThreshold ( epicsGuard < epicsMutex > & ) const;
void flushRequestIfAboveEarlyThreshold ( epicsGuard < epicsMutex > & );
void blockUntilSendBacklogIsReasonable
( cacNotify &, epicsGuard < cacMutex > & );
( cacContextNotify &, epicsGuard < epicsMutex > & );
virtual void show ( unsigned level ) const;
bool setEchoRequestPending ();
void createChannelRequest ( nciu &, epicsGuard < cacMutex > & );
bool setEchoRequestPending ( epicsGuard < epicsMutex > & );
void requestRecvProcessPostponedFlush ();
void clearChannelRequest ( epicsGuard < cacMutex > &,
void clearChannelRequest ( epicsGuard < epicsMutex > &,
ca_uint32_t sid, ca_uint32_t cid );
bool ca_v41_ok () const;
@@ -135,13 +140,13 @@ public:
unsigned channelCount ( epicsGuard < callbackMutex > & );
void removeAllChannels (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < cacMutex > & guard,
class cacDisconnectChannelPrivate & );
epicsGuard < epicsMutex > & guard, udpiiu & );
void installChannel ( epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > &, nciu & chan,
epicsGuard < epicsMutex > &, nciu & chan,
unsigned sidIn, ca_uint16_t typeIn, arrayElementCount countIn );
void uninstallChan ( epicsGuard < callbackMutex > &,
epicsGuard < cacMutex > &, nciu & chan );
void uninstallChan ( epicsGuard < epicsMutex > &, nciu & chan );
void connectNotify ( epicsGuard < epicsMutex > &, nciu & chan );
void nameResolutionMsgEndNotify ();
bool bytesArePendingInOS () const;
@@ -158,7 +163,14 @@ private:
tcpSendWatchdog sendDog;
comQueSend sendQue;
comQueRecv recvQue;
tsDLList < nciu > channelList;
// nciu state field tells us which list
// protected by the callback mutex
tsDLList < nciu > createReqPend;
tsDLList < nciu > createRespPend;
tsDLList < nciu > subscripReqPend;
tsDLList < nciu > connectedList;
tsDLList < nciu > unrespCircuit;
tsDLList < nciu > subscripUpdateReqPend;
caHdrLargeArray curMsg;
arrayElementCount curDataMax;
arrayElementCount curDataBytes;
@@ -180,6 +192,7 @@ private:
unsigned blockingForFlush;
unsigned socketLibrarySendBufferSize;
unsigned unacknowledgedSendBytes;
unsigned channelCountTot;
bool busyStateDetected; // only modified by the recv thread
bool flowControlActive; // only modified by the send process thread
bool echoRequestPending;
@@ -189,7 +202,7 @@ private:
bool recvProcessPostponedFlush;
bool discardingPendingData;
bool socketHasBeenClosed;
bool softDisconnect;
bool unresponsiveCircuit;
bool processIncoming (
const epicsTime & currentTime, epicsGuard < callbackMutex > & );
@@ -200,21 +213,34 @@ private:
const char * pHostName () const;
void blockUntilBytesArePendingInOS ();
double receiveWatchdogDelay () const;
void unresponsiveCircuitNotify (
epicsGuard < callbackMutex > & cbGuard,
epicsGuard < epicsMutex > & guard );
void disconnectNotify ();
// send protocol stubs
void echoRequest ( epicsGuard < cacMutex > & );
void versionMessage ( epicsGuard < cacMutex > &, const cacChannel::priLev & priority );
void disableFlowControlRequest (epicsGuard < cacMutex > & );
void enableFlowControlRequest (epicsGuard < cacMutex > & );
void hostNameSetRequest ( epicsGuard < cacMutex > & );
void userNameSetRequest ( epicsGuard < cacMutex > & );
void writeRequest ( epicsGuard < cacMutex > &, nciu &, unsigned type, unsigned nElem, const void *pValue );
void writeNotifyRequest ( epicsGuard < cacMutex > &, nciu &, netWriteNotifyIO &, unsigned type, unsigned nElem, const void *pValue );
void readNotifyRequest ( epicsGuard < cacMutex > &, nciu &, netReadNotifyIO &, unsigned type, unsigned nElem );
void subscriptionRequest ( epicsGuard < cacMutex > &, nciu &, netSubscription & subscr );
void subscriptionCancelRequest ( epicsGuard < cacMutex > &, nciu & chan, netSubscription & subscr );
void echoRequest ( epicsGuard < epicsMutex > & );
void versionMessage ( epicsGuard < epicsMutex > &, const cacChannel::priLev & priority );
void disableFlowControlRequest (epicsGuard < epicsMutex > & );
void enableFlowControlRequest (epicsGuard < epicsMutex > & );
void hostNameSetRequest ( epicsGuard < epicsMutex > & );
void userNameSetRequest ( epicsGuard < epicsMutex > & );
void createChannelRequest ( nciu &, epicsGuard < epicsMutex > & );
void writeRequest ( epicsGuard < epicsMutex > &, nciu &,
unsigned type, arrayElementCount nElem, const void *pValue );
void writeNotifyRequest ( epicsGuard < epicsMutex > &, nciu &,
netWriteNotifyIO &, unsigned type,
arrayElementCount nElem, const void *pValue );
void readNotifyRequest ( epicsGuard < epicsMutex > &, nciu &,
netReadNotifyIO &, unsigned type, arrayElementCount nElem );
void subscriptionRequest ( epicsGuard < epicsMutex > &,
nciu &, netSubscription & subscr );
void subscriptionUpdateRequest ( epicsGuard < epicsMutex > &,
nciu & chan, netSubscription & subscr );
void subscriptionCancelRequest ( epicsGuard < epicsMutex > &,
nciu & chan, netSubscription & subscr );
void flushIfRecvProcessRequested ();
bool flush (); // only to be called by the send thread
bool flush ( epicsGuard < epicsMutex > & ); // only to be called by the send thread
friend void tcpRecvThread::run ();
friend void tcpSendThread::run ();
@@ -265,29 +291,24 @@ inline bool tcpiiu::connecting () const
return ( this->state == iiucs_connecting );
}
inline void tcpiiu::beaconAnomalyNotify ()
inline void tcpiiu::beaconAnomalyNotify ( epicsGuard < epicsMutex > & guard )
{
this->recvDog.beaconAnomalyNotify ();
//guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
this->recvDog.beaconAnomalyNotify ( guard );
}
inline void tcpiiu::beaconArrivalNotify (
epicsGuard < epicsMutex > & guard, const epicsTime & currentTime )
{
//guard.assertIdenticalMutex ( this->cacRef.mutexRef () );
this->recvDog.beaconArrivalNotify ( guard, currentTime );
}
inline void tcpiiu::probeResponseNotify (
epicsGuard < callbackMutex > & cbGuard,
const epicsTime & currentTime )
{
this->recvDog.beaconArrivalNotify ( currentTime );
}
inline void tcpiiu::flushIfRecvProcessRequested ()
{
if ( this->recvProcessPostponedFlush ) {
this->flushRequest ();
this->recvProcessPostponedFlush = false;
}
}
inline unsigned tcpiiu::channelCount ( epicsGuard < callbackMutex > & )
{
// protected by callback lock
return this->channelList.count ();
this->recvDog.probeResponseNotify ( cbGuard, currentTime );
}
#endif // ifdef virtualCircuith

View File

@@ -71,7 +71,7 @@ LIBSRCS += dbServiceIO.cpp
LIBSRCS += dbChannelIO.cpp
LIBSRCS += dbSubscriptionIO.cpp
LIBSRCS += dbPutNotifyBlocker.cpp
LIBSRCS += dbServiceIOReadNotifyCache.cpp
LIBSRCS += dbContextReadNotifyCache.cpp
LIBSRCS += templateInstances.cpp
LIBRARY_IOC = dbIoc

View File

@@ -39,6 +39,7 @@
#include "resourceLib.h"
#include "cacIO.h"
#include "compilerDependencies.h"
#include "epicsMemory.h"
#ifdef dbCACh_restore_epicsExportSharedSymbols
# define epicsExportSharedSymbols
@@ -56,7 +57,7 @@
extern "C" void putNotifyCompletion ( putNotify *ppn );
class dbServiceIO;
class dbContext;
class dbChannelIO;
class dbPutNotifyBlocker;
class dbSubscriptionIO;
@@ -65,6 +66,7 @@ class dbBaseIO // X aCC 655
: public chronIntIdRes < dbBaseIO > {
public:
virtual dbSubscriptionIO * isSubscription () = 0;
virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0;
virtual void show ( unsigned level ) const = 0;
dbBaseIO ();
dbBaseIO ( const dbBaseIO & );
@@ -74,109 +76,144 @@ public:
extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbAddr *paddr,
int eventsRemaining, struct db_field_log *pfl );
class dbSubscriptionIO : public tsDLNode <dbSubscriptionIO>, public dbBaseIO {
class dbSubscriptionIO :
public tsDLNode < dbSubscriptionIO >,
public dbBaseIO {
public:
dbSubscriptionIO ( dbServiceIO &, dbChannelIO &, struct dbAddr &, cacStateNotify &,
dbSubscriptionIO (
epicsGuard < epicsMutex > &, epicsMutex &,
dbContext &, dbChannelIO &, struct dbAddr &, cacStateNotify &,
unsigned type, unsigned long count, unsigned mask, dbEventCtx );
virtual ~dbSubscriptionIO ();
void unsubscribe ();
void channelDeleteException ();
void destructor ( epicsGuard < epicsMutex > & );
void unsubscribe ( epicsGuard < epicsMutex > & );
void channelDeleteException ( epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void * operator new ( size_t size, tsFreeList < dbSubscriptionIO > & );
epicsPlacementDeleteOperator (( void *, tsFreeList < dbSubscriptionIO > & ))
void * operator new ( size_t size,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & ))
private:
epicsMutex & mutex;
unsigned long count;
cacStateNotify & notify;
dbChannelIO & chan;
dbEventSubscription es;
unsigned type;
unsigned long count;
unsigned id;
dbSubscriptionIO * isSubscription ();
friend void dbSubscriptionEventCallback ( void *pPrivate, struct dbAddr *paddr,
int eventsRemaining, struct db_field_log *pfl );
friend void dbSubscriptionEventCallback (
void * pPrivate, struct dbAddr * paddr,
int eventsRemaining, struct db_field_log * pfl );
dbSubscriptionIO ( const dbSubscriptionIO & );
dbSubscriptionIO & operator = ( const dbSubscriptionIO & );
virtual ~dbSubscriptionIO ();
void * operator new ( size_t size );
void operator delete ( void * );
};
class dbServiceIO;
class dbContext;
class dbServicePrivateListOfIO {
class dbContextPrivateListOfIO {
public:
dbServicePrivateListOfIO ();
dbContextPrivateListOfIO ();
private:
tsDLList < dbSubscriptionIO > eventq;
dbPutNotifyBlocker * pBlocker;
friend class dbServiceIO;
dbServicePrivateListOfIO ( const dbServicePrivateListOfIO & );
dbServicePrivateListOfIO & operator = ( const dbServicePrivateListOfIO & );
friend class dbContext;
dbContextPrivateListOfIO ( const dbContextPrivateListOfIO & );
dbContextPrivateListOfIO & operator = ( const dbContextPrivateListOfIO & );
};
#pragma message ( "name change reflecting dbContext indicated?" )
// allow only one thread at a time to use the cache, but do not hold
// lock when calling the callback
class dbServiceIOReadNotifyCache {
class dbContextReadNotifyCache {
public:
dbServiceIOReadNotifyCache ();
~dbServiceIOReadNotifyCache ();
void callReadNotify ( struct dbAddr &addr, unsigned type, unsigned long count,
cacReadNotify &notify );
void show ( unsigned level ) const;
dbContextReadNotifyCache ( epicsMutex & );
~dbContextReadNotifyCache ();
void callReadNotify ( epicsGuard < epicsMutex > &,
struct dbAddr & addr, unsigned type, unsigned long count,
cacReadNotify & notify );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
private:
epicsMutex mutex;
unsigned long readNotifyCacheSize;
char *pReadNotifyCache;
dbServiceIOReadNotifyCache ( const dbServiceIOReadNotifyCache & );
dbServiceIOReadNotifyCache & operator = ( const dbServiceIOReadNotifyCache & );
epicsMutex & mutex;
char * pReadNotifyCache;
dbContextReadNotifyCache ( const dbContextReadNotifyCache & );
dbContextReadNotifyCache & operator = ( const dbContextReadNotifyCache & );
};
class dbServiceIO : public cacService {
class dbContext : public cacContext {
public:
dbServiceIO ();
virtual ~dbServiceIO ();
cacChannel * createChannel ( const char *pName,
cacChannelNotify &, cacChannel::priLev );
void destroyChannel ( dbChannelIO & );
void callReadNotify ( struct dbAddr &addr, unsigned type, unsigned long count,
cacReadNotify &notify );
dbContext ( epicsMutex & mutex, cacContextNotify & notify );
virtual ~dbContext ();
void destroyChannel ( epicsGuard < epicsMutex > &, dbChannelIO & );
void callReadNotify ( epicsGuard < epicsMutex > &,
struct dbAddr & addr, unsigned type, unsigned long count,
cacReadNotify & notify );
void callStateNotify ( struct dbAddr &addr, unsigned type, unsigned long count,
const struct db_field_log * pfl, cacStateNotify & notify );
void subscribe (
epicsGuard < epicsMutex > &,
struct dbAddr & addr, dbChannelIO & chan,
unsigned type, unsigned long count, unsigned mask,
cacStateNotify & notify, cacChannel::ioid * pId );
void initiatePutNotify ( dbChannelIO &, struct dbAddr &, unsigned type,
unsigned long count, const void *pValue, cacWriteNotify &notify,
cacChannel::ioid * pId );
void initiatePutNotify (
epicsGuard < epicsMutex > &, dbChannelIO &, struct dbAddr &,
unsigned type, unsigned long count, const void * pValue,
cacWriteNotify & notify, cacChannel::ioid * pId );
void show ( unsigned level ) const;
void showAllIO ( const dbChannelIO &chan, unsigned level ) const;
void destroyAllIO ( dbChannelIO & chan );
void ioCancel ( dbChannelIO & chan, const cacChannel::ioid &id );
void ioShow ( const cacChannel::ioid &id, unsigned level ) const;
void showAllIO ( const dbChannelIO & chan, unsigned level ) const;
void destroyAllIO (
epicsGuard < epicsMutex > &, dbChannelIO & chan );
void ioCancel ( epicsGuard < epicsMutex > &,
dbChannelIO & chan, const cacChannel::ioid &id );
void ioShow ( epicsGuard < epicsMutex > &,
const cacChannel::ioid & id, unsigned level ) const;
private:
mutable epicsMutex mutex;
tsFreeList < dbPutNotifyBlocker > dbPutNotifyBlockerFreeList;
tsFreeList < dbSubscriptionIO > dbSubscriptionIOFreeList;
tsFreeList < dbChannelIO > dbChannelIOFreeList;
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > dbPutNotifyBlockerFreeList;
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > dbSubscriptionIOFreeList;
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > dbChannelIOFreeList;
chronIntIdResTable < dbBaseIO > ioTable;
dbServiceIOReadNotifyCache readNotifyCache;
dbContextReadNotifyCache readNotifyCache;
dbEventCtx ctx;
unsigned long stateNotifyCacheSize;
char *pStateNotifyCache;
dbServiceIO ( const dbServiceIO & );
dbServiceIO & operator = ( const dbServiceIO & );
mutable epicsMutex & mutex;
cacContextNotify & notify;
epics_auto_ptr < cacContext > pNetContext;
char * pStateNotifyCache;
cacChannel & createChannel (
epicsGuard < epicsMutex > &,
const char * pChannelName, cacChannelNotify &,
cacChannel::priLev );
void flush (
epicsGuard < epicsMutex > & );
unsigned circuitCount (
epicsGuard < epicsMutex > & ) const;
void selfTest (
epicsGuard < epicsMutex > & ) const;
unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const;
void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
dbContext ( const dbContext & );
dbContext & operator = ( const dbContext & );
};
inline dbServicePrivateListOfIO::dbServicePrivateListOfIO () :
inline dbContextPrivateListOfIO::dbContextPrivateListOfIO () :
pBlocker ( 0 )
{
}
inline void dbServiceIO::callReadNotify ( struct dbAddr &addr,
unsigned type, unsigned long count,
cacReadNotify &notify )
inline void dbContext::callReadNotify (
epicsGuard < epicsMutex > & guard, struct dbAddr &addr,
unsigned type, unsigned long count, cacReadNotify & notify )
{
this->readNotifyCache.callReadNotify ( addr, type, count, notify );
guard.assertIdenticalMutex ( this-> mutex );
this->readNotifyCache.callReadNotify ( guard, addr, type, count, notify );
}
#endif // dbCACh

View File

@@ -40,46 +40,59 @@
#include "dbChannelIO.h"
#include "dbPutNotifyBlocker.h"
dbChannelIO::dbChannelIO ( cacChannelNotify & notify,
const dbAddr & addrIn, dbServiceIO & serviceIO ) :
cacChannel ( notify ), serviceIO ( serviceIO ),
dbChannelIO::dbChannelIO (
epicsMutex & mutexIn, cacChannelNotify & notify,
const dbAddr & addrIn, dbContext & serviceIO ) :
mutex ( mutexIn ), cacChannel ( notify ), serviceIO ( serviceIO ),
addr ( addrIn )
{
}
void dbChannelIO::initiateConnect ()
void dbChannelIO::initiateConnect ( epicsGuard < epicsMutex > & guard )
{
this->notify ().connectNotify ();
guard.assertIdenticalMutex ( this->mutex );
this->notify().connectNotify ( guard );
}
dbChannelIO::~dbChannelIO ()
dbChannelIO::~dbChannelIO ()
{
this->serviceIO.destroyAllIO ( *this );
}
void dbChannelIO::destroy ()
void dbChannelIO::destructor ( epicsGuard < epicsMutex > & guard )
{
this->serviceIO.destroyChannel ( *this );
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.destroyAllIO ( guard, *this );
this->~dbChannelIO ();
}
void dbChannelIO::destroy ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.destroyChannel ( guard, *this );
// dont access this pointer after above call because
// object nolonger exists
}
cacChannel::ioStatus dbChannelIO::read ( unsigned type,
unsigned long count, cacReadNotify &notify, ioid * )
cacChannel::ioStatus dbChannelIO::read (
epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, cacReadNotify & notify, ioid * )
{
this->serviceIO.callReadNotify ( this->addr,
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.callReadNotify ( guard, this->addr,
type, count, notify );
return iosSynch;
}
void dbChannelIO::write ( unsigned type, unsigned long count, const void *pValue )
void dbChannelIO::write (
epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, const void *pValue )
{
int status;
epicsGuardRelease < epicsMutex > unguard ( guard );
if ( count > LONG_MAX ) {
throw outOfBounds();
}
status = db_put_field ( &this->addr, type, pValue,
int status = db_put_field ( &this->addr, type, pValue,
static_cast <long> (count) );
if ( status ) {
throw std::logic_error (
@@ -87,33 +100,46 @@ void dbChannelIO::write ( unsigned type, unsigned long count, const void *pValue
}
}
cacChannel::ioStatus dbChannelIO::write ( unsigned type, unsigned long count,
const void *pValue, cacWriteNotify &notify, ioid *pId )
cacChannel::ioStatus dbChannelIO::write (
epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, const void * pValue,
cacWriteNotify & notify, ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
if ( count > LONG_MAX ) {
throw outOfBounds();
}
this->serviceIO.initiatePutNotify ( *this, this->addr, type, count, pValue, notify, pId );
this->serviceIO.initiatePutNotify (
guard, *this, this->addr,
type, count, pValue, notify, pId );
return iosAsynch;
}
void dbChannelIO::subscribe ( unsigned type, unsigned long count,
void dbChannelIO::subscribe (
epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
unsigned mask, cacStateNotify & notify, ioid * pId )
{
this->serviceIO.subscribe ( this->addr, *this,
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.subscribe (
guard, this->addr, *this,
type, count, mask, notify, pId );
}
void dbChannelIO::ioCancel ( const ioid & id )
void dbChannelIO::ioCancel (
epicsGuard < epicsMutex > & guard, const ioid & id )
{
this->serviceIO.ioCancel ( *this, id );
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.ioCancel ( guard, *this, id );
}
void dbChannelIO::ioShow ( const ioid &id, unsigned level ) const
void dbChannelIO::ioShow (
const ioid & id, unsigned level ) const
{
this->serviceIO.ioShow ( id, level );
epicsGuard < epicsMutex > guard ( this->mutex );
this->serviceIO.ioShow ( guard, id, level );
}
void dbChannelIO::show ( unsigned level ) const
@@ -133,7 +159,7 @@ void dbChannelIO::show ( unsigned level ) const
}
void * dbChannelIO::operator new ( size_t size,
tsFreeList < dbChannelIO > & freeList )
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
@@ -147,7 +173,7 @@ void * dbChannelIO::operator new ( size_t ) // X aCC 361
#ifdef CXX_PLACEMENT_DELETE
void dbChannelIO::operator delete ( void *pCadaver,
tsFreeList < dbChannelIO > & freeList )
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}

View File

@@ -41,40 +41,52 @@
# define epicsExportSharedSymbols
#endif
class dbChannelIO : public cacChannel, public dbServicePrivateListOfIO {
class dbChannelIO : public cacChannel, public dbContextPrivateListOfIO {
public:
dbChannelIO ( cacChannelNotify &notify,
const dbAddr &addr, dbServiceIO &serviceIO );
~dbChannelIO ();
void destroy ();
void callReadNotify ( unsigned type, unsigned long count,
cacReadNotify &notify );
dbChannelIO ( epicsMutex &, cacChannelNotify &,
const dbAddr &, dbContext & );
void destructor ( epicsGuard < epicsMutex > & );
void destroy ( epicsGuard < epicsMutex > & );
void callReadNotify ( epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
cacReadNotify & notify );
void callStateNotify ( unsigned type, unsigned long count,
const struct db_field_log *pfl, cacStateNotify &notify );
const struct db_field_log * pfl, cacStateNotify & notify );
void show ( unsigned level ) const;
const char *pName () const;
void * operator new ( size_t size, tsFreeList < dbChannelIO > & );
epicsPlacementDeleteOperator (( void *, tsFreeList < dbChannelIO > & ))
const char * pName () const;
void * operator new ( size_t size,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & ))
private:
dbServiceIO & serviceIO;
epicsMutex & mutex;
dbContext & serviceIO;
dbAddr addr;
void initiateConnect ();
ioStatus read ( unsigned type, unsigned long count,
void initiateConnect (
epicsGuard < epicsMutex > & );
ioStatus read ( epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
cacReadNotify &, ioid * );
void write ( unsigned type, unsigned long count,
void write ( epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
const void *pvalue );
ioStatus write ( unsigned type, unsigned long count,
ioStatus write ( epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
const void *pvalue, cacWriteNotify &, ioid * );
void subscribe ( unsigned type, unsigned long count,
void subscribe ( epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
unsigned mask, cacStateNotify &notify, ioid * );
void ioCancel ( const ioid & );
void ioShow ( const ioid &, unsigned level ) const;
void ioCancel ( epicsGuard < epicsMutex > &,
const ioid & );
void ioShow (
const ioid &, unsigned level ) const;
short nativeType () const;
unsigned long nativeElementCount () const;
dbChannelIO ( const dbChannelIO & );
dbChannelIO & operator = ( const dbChannelIO & );
void * operator new ( size_t size );
void operator delete ( void * );
~dbChannelIO ();
};
@@ -96,10 +108,12 @@ inline short dbChannelIO::nativeType () const
return this->addr.dbr_field_type;
}
inline void dbChannelIO::callReadNotify ( unsigned type, unsigned long count,
cacReadNotify &notify )
inline void dbChannelIO::callReadNotify (
epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
cacReadNotify & notify )
{
this->serviceIO.callReadNotify ( this->addr, type, count, notify );
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.callReadNotify ( guard, this->addr, type, count, notify );
}
inline void dbChannelIO::callStateNotify ( unsigned type, unsigned long count,

View File

@@ -24,18 +24,21 @@
#include "db_access_routines.h"
#include "dbCAC.h"
dbServiceIOReadNotifyCache::dbServiceIOReadNotifyCache () :
readNotifyCacheSize ( 0 ), pReadNotifyCache ( 0 )
dbContextReadNotifyCache::dbContextReadNotifyCache ( epicsMutex & mutexIn ) :
readNotifyCacheSize ( 0 ), mutex ( mutexIn ), pReadNotifyCache ( 0 )
{
}
dbServiceIOReadNotifyCache::~dbServiceIOReadNotifyCache ()
dbContextReadNotifyCache::~dbContextReadNotifyCache ()
{
delete this->pReadNotifyCache;
}
void dbServiceIOReadNotifyCache::show ( unsigned level ) const
void dbContextReadNotifyCache::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
if ( level > 0 ) {
printf ( "\tget call back cache location %p, and its size %lu\n",
static_cast <void *> ( this->pReadNotifyCache ),
@@ -44,23 +47,24 @@ void dbServiceIOReadNotifyCache::show ( unsigned level ) const
}
// extra effort taken here to not hold the lock when caslling the callback
void dbServiceIOReadNotifyCache::callReadNotify ( struct dbAddr &addr,
unsigned type, unsigned long count, cacReadNotify &notify )
void dbContextReadNotifyCache::callReadNotify (
epicsGuard < epicsMutex > & guard, struct dbAddr & addr,
unsigned type, unsigned long count, cacReadNotify & notify )
{
epicsGuard < epicsMutex > locker ( this->mutex );
guard.assertIdenticalMutex ( this->mutex );
unsigned long size = dbr_size_n ( type, count );
if ( type > INT_MAX ) {
notify.exception ( ECA_BADTYPE,
notify.exception ( guard, ECA_BADTYPE,
"type code out of range (high side)",
type, count );
return;
}
if ( count > static_cast<unsigned>(INT_MAX) ||
count > static_cast<unsigned>(addr.no_elements) ) {
notify.exception ( ECA_BADCOUNT,
if ( count > static_cast < unsigned > ( INT_MAX ) ||
count > static_cast < unsigned > ( addr.no_elements ) ) {
notify.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
@@ -69,7 +73,7 @@ void dbServiceIOReadNotifyCache::callReadNotify ( struct dbAddr &addr,
if ( this->readNotifyCacheSize < size) {
char * pTmp = new char [size];
if ( ! pTmp ) {
notify.exception ( ECA_ALLOCMEM,
notify.exception ( guard, ECA_ALLOCMEM,
"unable to allocate callback cache",
type, count );
return;
@@ -78,14 +82,18 @@ void dbServiceIOReadNotifyCache::callReadNotify ( struct dbAddr &addr,
this->pReadNotifyCache = pTmp;
this->readNotifyCacheSize = size;
}
int status = db_get_field ( &addr, static_cast <int> ( type ),
int status;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
status = db_get_field ( &addr, static_cast <int> ( type ),
this->pReadNotifyCache, static_cast <int> ( count ), 0 );
}
if ( status ) {
notify.exception ( ECA_GETFAIL,
notify.exception ( guard, ECA_GETFAIL,
"db_get_field() completed unsuccessfuly",
type, count);
}
else {
notify.completion ( type, count, this->pReadNotifyCache );
notify.completion ( guard, type, count, this->pReadNotifyCache );
}
}

View File

@@ -45,8 +45,9 @@
#include "dbChannelIO.h"
#include "dbPutNotifyBlocker.h"
dbPutNotifyBlocker::dbPutNotifyBlocker () :
pNotify ( 0 ), maxValueSize ( sizeof ( this->dbrScalarValue ) )
dbPutNotifyBlocker::dbPutNotifyBlocker ( epicsMutex & mutexIn ) :
mutex ( mutexIn ), pNotify ( 0 ),
maxValueSize ( sizeof ( this->dbrScalarValue ) )
{
memset ( & this->pn, '\0', sizeof ( this->pn ) );
memset ( & this->dbrScalarValue, '\0', sizeof ( this->dbrScalarValue ) );
@@ -55,24 +56,35 @@ dbPutNotifyBlocker::dbPutNotifyBlocker () :
dbPutNotifyBlocker::~dbPutNotifyBlocker ()
{
this->cancel ();
}
void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->cancel ( guard );
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
char * pBuf = static_cast < char * > ( this->pn.pbuffer );
delete [] pBuf;
}
this->~dbPutNotifyBlocker ();
}
void dbPutNotifyBlocker::cancel ()
void dbPutNotifyBlocker::cancel (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pn.paddr ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
dbNotifyCancel ( &this->pn );
}
this->pNotify = 0;
this->block.signal ();
}
void dbPutNotifyBlocker::expandValueBuf ( unsigned long newSize )
void dbPutNotifyBlocker::expandValueBuf (
epicsGuard < epicsMutex > & guard, unsigned long newSize )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->maxValueSize < newSize ) {
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
char * pBuf = static_cast < char * > ( this->pn.pbuffer );
@@ -87,31 +99,34 @@ void dbPutNotifyBlocker::expandValueBuf ( unsigned long newSize )
extern "C" void putNotifyCompletion ( putNotify *ppn )
{
dbPutNotifyBlocker *pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
if ( pBlocker->pNotify ) {
if ( pBlocker->pn.status != putNotifyOK) {
pBlocker->pNotify->exception (
ECA_PUTFAIL, "put notify unsuccessful",
static_cast <unsigned> (pBlocker->pn.dbrType),
static_cast <unsigned> (pBlocker->pn.nRequest) );
dbPutNotifyBlocker * pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
{
epicsGuard < epicsMutex > guard ( pBlocker->mutex );
if ( pBlocker->pNotify ) {
if ( pBlocker->pn.status != putNotifyOK) {
pBlocker->pNotify->exception (
guard, ECA_PUTFAIL, "put notify unsuccessful",
static_cast <unsigned> (pBlocker->pn.dbrType),
static_cast <unsigned> (pBlocker->pn.nRequest) );
}
else {
pBlocker->pNotify->completion ( guard );
}
}
else {
pBlocker->pNotify->completion ();
errlogPrintf ( "put notify completion with nill pNotify?\n" );
}
pBlocker->pNotify = 0;
}
else {
errlogPrintf ( "put notify completion with nill pNotify?\n" );
}
// no need to lock here because only one put notify at a time is allowed to run
pBlocker->pNotify = 0;
pBlocker->block.signal ();
}
void dbPutNotifyBlocker::initiatePutNotify ( epicsGuard < epicsMutex > & locker, cacWriteNotify & notify,
struct dbAddr & addr, unsigned type, unsigned long count, const void * pValue )
void dbPutNotifyBlocker::initiatePutNotify (
epicsGuard < epicsMutex > & guard, cacWriteNotify & notify,
struct dbAddr & addr, unsigned type, unsigned long count,
const void * pValue )
{
int status;
guard. assertIdenticalMutex ( this->mutex );
epicsTime begin;
bool beginTimeInit = false;
while ( true ) {
@@ -129,7 +144,7 @@ void dbPutNotifyBlocker::initiatePutNotify ( epicsGuard < epicsMutex > & locker,
beginTimeInit = true;
}
{
epicsGuardRelease < epicsMutex > autoRelease ( locker );
epicsGuardRelease < epicsMutex > autoRelease ( guard );
this->block.wait ( 1.0 );
}
}
@@ -142,7 +157,7 @@ void dbPutNotifyBlocker::initiatePutNotify ( epicsGuard < epicsMutex > & locker,
throw cacChannel::badType();
}
status = dbPutNotifyMapType (
int status = dbPutNotifyMapType (
&this->pn, static_cast <short> ( type ) );
if ( status ) {
this->pNotify = 0;
@@ -155,13 +170,23 @@ void dbPutNotifyBlocker::initiatePutNotify ( epicsGuard < epicsMutex > & locker,
this->pn.usrPvt = this;
unsigned long size = dbr_size_n ( type, count );
this->expandValueBuf ( size );
this->expandValueBuf ( guard, size );
memcpy ( this->pn.pbuffer, pValue, size );
::dbPutNotify ( &this->pn );
{
epicsGuardRelease < epicsMutex > autoRelease ( guard );
::dbPutNotify ( &this->pn );
}
}
void dbPutNotifyBlocker::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->show ( guard, level );
}
void dbPutNotifyBlocker::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
printf ( "put notify blocker at %p\n",
static_cast <const void *> ( this ) );
@@ -176,7 +201,7 @@ dbSubscriptionIO * dbPutNotifyBlocker::isSubscription ()
}
void * dbPutNotifyBlocker::operator new ( size_t size,
tsFreeList < dbPutNotifyBlocker > & freeList )
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
@@ -190,7 +215,7 @@ void * dbPutNotifyBlocker::operator new ( size_t ) // X aCC 361
#ifdef CXX_PLACEMENT_DELETE
void dbPutNotifyBlocker::operator delete ( void *pCadaver,
tsFreeList < dbPutNotifyBlocker > & freeList )
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}

View File

@@ -41,17 +41,18 @@
class dbPutNotifyBlocker : public dbBaseIO {
public:
dbPutNotifyBlocker ();
virtual ~dbPutNotifyBlocker ();
void initiatePutNotify ( epicsGuard < epicsMutex > & locker,
cacWriteNotify & notify, struct dbAddr & addr,
dbPutNotifyBlocker ( epicsMutex & );
void destructor ( epicsGuard < epicsMutex > & );
void initiatePutNotify ( epicsGuard < epicsMutex > &,
cacWriteNotify &, struct dbAddr &,
unsigned type, unsigned long count, const void * pValue );
void cancel ();
void cancel ( epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void * operator new ( size_t size,
tsFreeList < dbPutNotifyBlocker > & );
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < dbPutNotifyBlocker > & ))
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & ))
private:
putNotify pn;
//
@@ -71,13 +72,16 @@ private:
dbr_double_t doubleval;
} dbrScalarValue;
epicsEvent block;
epicsMutex & mutex;
cacWriteNotify * pNotify;
unsigned long maxValueSize;
dbSubscriptionIO * isSubscription ();
void expandValueBuf ( unsigned long newSize );
friend void putNotifyCompletion ( putNotify *ppn );
void expandValueBuf (
epicsGuard < epicsMutex > &, unsigned long newSize );
friend void putNotifyCompletion ( putNotify * ppn );
dbPutNotifyBlocker ( const dbPutNotifyBlocker & );
dbPutNotifyBlocker & operator = ( const dbPutNotifyBlocker & );
virtual ~dbPutNotifyBlocker ();
void * operator new ( size_t size );
void operator delete ( void * );
};

View File

@@ -23,6 +23,8 @@
* 505 665 1831
*/
#pragma message ( "file name needs to change" )
#include <limits.h>
#include "epicsMutex.h"
@@ -41,37 +43,35 @@
#include "dbChannelIO.h"
#include "dbPutNotifyBlocker.h"
class dbServiceIOLoadTimeInit {
class dbService : public cacService {
public:
dbServiceIOLoadTimeInit ();
private:
dbServiceIO dbio;
dbServiceIOLoadTimeInit ( const dbServiceIOLoadTimeInit & );
dbServiceIOLoadTimeInit & operator = ( const dbServiceIOLoadTimeInit & );
cacContext & contextCreate (
epicsMutex &, cacContextNotify & );
};
// The following is just to force lti to be constructed
extern "C" void dbServiceIOInit()
static dbService dbs;
cacContext & dbService::contextCreate (
epicsMutex & mutex, cacContextNotify & notify )
{
static dbServiceIOLoadTimeInit lti;
return * new dbContext ( mutex, notify );
}
extern "C" void dbServiceIOInit ()
{
caInstallDefaultService ( dbs );
}
dbBaseIO::dbBaseIO () {}
dbServiceIOLoadTimeInit::dbServiceIOLoadTimeInit ()
{
epicsSingleton < cacServiceList > :: reference
ref ( globalServiceListCAC.getReference () );
ref->registerService ( this->dbio );
}
dbServiceIO::dbServiceIO () :
ctx ( 0 ), stateNotifyCacheSize ( 0 ),
pStateNotifyCache ( 0 )
dbContext::dbContext ( epicsMutex & mutexIn, cacContextNotify & notifyIn ) :
readNotifyCache ( mutexIn ), ctx ( 0 ),
stateNotifyCacheSize ( 0 ), mutex ( mutexIn ),
notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 )
{
}
dbServiceIO::~dbServiceIO ()
dbContext::~dbContext ()
{
delete [] this->pStateNotifyCache;
if ( this->ctx ) {
@@ -79,35 +79,49 @@ dbServiceIO::~dbServiceIO ()
}
}
cacChannel *dbServiceIO::createChannel ( // X aCC 361
const char * pName, cacChannelNotify & notify,
cacChannel::priLev )
cacChannel & dbContext::createChannel ( // X aCC 361
epicsGuard < epicsMutex > & guard, const char * pName,
cacChannelNotify & notifyIn, cacChannel::priLev priority )
{
struct dbAddr addr;
guard.assertIdenticalMutex ( this->mutex );
int status = db_name_to_addr ( pName, & addr );
if ( status ) {
return 0;
struct dbAddr addr;
int status;
{
// dont know if the database might call a put callback
// while holding its lock ...
epicsGuardRelease < epicsMutex > unguard ( guard );
status = db_name_to_addr ( pName, & addr );
}
else if ( ! ca_preemtive_callback_is_enabled () ) {
errlogPrintf (
"dbServiceIO: preemptive callback required for direct in\n"
"memory interfacing of CA channels to the DB.\n" );
return 0;
if ( status ) {
if ( ! this->pNetContext.get() ) {
this->pNetContext.reset (
& this->notify.createNetworkContext ( this->mutex ) );
}
return this->pNetContext->createChannel (
guard, pName, notifyIn, priority );
}
else if ( ca_preemtive_callback_is_enabled () ) {
return * new ( this->dbChannelIOFreeList )
dbChannelIO ( this->mutex, notifyIn, addr, *this );
}
else {
return new ( this->dbChannelIOFreeList )
dbChannelIO ( notify, addr, *this );
errlogPrintf (
"dbContext: preemptive callback required for direct in\n"
"memory interfacing of CA channels to the DB.\n" );
throw cacChannel::unsupportedByService ();
}
}
void dbServiceIO::destroyChannel ( dbChannelIO & chan )
void dbContext::destroyChannel (
epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
{
chan.~dbChannelIO ();
guard.assertIdenticalMutex ( this->mutex );
chan.destructor ( guard );
this->dbChannelIOFreeList.release ( & chan );
}
void dbServiceIO::callStateNotify ( struct dbAddr & addr,
void dbContext::callStateNotify ( struct dbAddr & addr,
unsigned type, unsigned long count,
const struct db_field_log * pfl,
cacStateNotify & notify )
@@ -115,14 +129,16 @@ void dbServiceIO::callStateNotify ( struct dbAddr & addr,
unsigned long size = dbr_size_n ( type, count );
if ( type > INT_MAX ) {
notify.exception ( ECA_BADTYPE,
epicsGuard < epicsMutex > guard ( this->mutex );
notify.exception ( guard, ECA_BADTYPE,
"type code out of range (high side)",
type, count );
return;
}
if ( count > INT_MAX ) {
notify.exception ( ECA_BADCOUNT,
epicsGuard < epicsMutex > guard ( this->mutex );
notify.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
@@ -140,11 +156,13 @@ void dbServiceIO::callStateNotify ( struct dbAddr & addr,
int status = db_get_field ( &addr, static_cast <int> ( type ),
this->pStateNotifyCache, static_cast <int> ( count ), pvfl );
if ( status ) {
notify.exception ( ECA_GETFAIL,
epicsGuard < epicsMutex > guard ( this->mutex );
notify.exception ( guard, ECA_GETFAIL,
"db_get_field() completed unsuccessfuly", type, count );
}
else {
notify.current ( type, count, this->pStateNotifyCache );
epicsGuard < epicsMutex > guard ( this->mutex );
notify.current ( guard, type, count, this->pStateNotifyCache );
}
}
@@ -154,11 +172,14 @@ extern "C" void cacAttachClientCtx ( void * pPrivate )
assert ( status == ECA_NORMAL );
}
void dbServiceIO::subscribe (
void dbContext::subscribe (
epicsGuard < epicsMutex > & guard,
struct dbAddr & addr, dbChannelIO & chan,
unsigned type, unsigned long count, unsigned mask,
cacStateNotify & notify, cacChannel::ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
/*
* the database uses type "int" to store these parameters
*/
@@ -169,14 +190,15 @@ void dbServiceIO::subscribe (
throw cacChannel::outOfBounds();
}
{
epicsGuard < epicsMutex > locker ( this->mutex );
if ( ! this->ctx ) {
this->ctx = db_init_events ();
if ( ! this->ctx ) {
if ( ! this->ctx ) {
dbEventCtx tmpctx = 0;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
tmpctx = db_init_events ();
if ( ! tmpctx ) {
throw std::bad_alloc ();
}
unsigned selfPriority = epicsThreadGetPrioritySelf ();
unsigned above;
epicsThreadBooleanStatus tbs =
@@ -184,136 +206,178 @@ void dbServiceIO::subscribe (
if ( tbs != epicsThreadBooleanStatusSuccess ) {
above = selfPriority;
}
int status = db_start_events ( this->ctx, "CAC-event",
int status = db_start_events ( tmpctx, "CAC-event",
cacAttachClientCtx, ca_current_context (), above );
if ( status ) {
db_close_events ( this->ctx );
this->ctx = 0;
db_close_events ( tmpctx );
throw std::bad_alloc ();
}
}
if ( this->ctx ) {
// another thread tried to simultaneously setup
// the event system
db_close_events ( tmpctx );
}
else {
this->ctx = tmpctx;
}
}
dbSubscriptionIO & subscr =
* new ( this->dbSubscriptionIOFreeList )
dbSubscriptionIO ( *this, chan,
dbSubscriptionIO ( guard, this->mutex, *this, chan,
addr, notify, type, count, mask, this->ctx );
{
epicsGuard < epicsMutex > locker ( this->mutex );
chan.dbServicePrivateListOfIO::eventq.add ( subscr );
this->ioTable.add ( subscr );
}
chan.dbContextPrivateListOfIO::eventq.add ( subscr );
this->ioTable.add ( subscr );
if ( pId ) {
*pId = subscr.getId ();
}
}
void dbServiceIO::initiatePutNotify (
void dbContext::initiatePutNotify (
epicsGuard < epicsMutex > & guard,
dbChannelIO & chan, struct dbAddr & addr,
unsigned type, unsigned long count, const void * pValue,
cacWriteNotify & notify, cacChannel::ioid * pId )
{
epicsGuard < epicsMutex > locker ( this->mutex );
if ( ! chan.dbServicePrivateListOfIO::pBlocker ) {
chan.dbServicePrivateListOfIO::pBlocker =
guard.assertIdenticalMutex ( this->mutex );
if ( ! chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker =
new ( this->dbPutNotifyBlockerFreeList )
dbPutNotifyBlocker ();
this->ioTable.add ( *chan.dbServicePrivateListOfIO::pBlocker );
dbPutNotifyBlocker ( this->mutex );
this->ioTable.add ( *chan.dbContextPrivateListOfIO::pBlocker );
}
chan.dbServicePrivateListOfIO::pBlocker->initiatePutNotify (
locker, notify, addr, type, count, pValue );
chan.dbContextPrivateListOfIO::pBlocker->initiatePutNotify (
guard, notify, addr, type, count, pValue );
if ( pId ) {
*pId = chan.dbServicePrivateListOfIO::pBlocker->getId ();
*pId = chan.dbContextPrivateListOfIO::pBlocker->getId ();
}
}
void dbServiceIO::destroyAllIO ( dbChannelIO & chan )
void dbContext::destroyAllIO (
epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
{
dbSubscriptionIO *pIO;
guard.assertIdenticalMutex ( this->mutex );
dbSubscriptionIO * pIO;
tsDLList < dbSubscriptionIO > tmp;
{
epicsGuard < epicsMutex > locker ( this->mutex );
while ( ( pIO = chan.dbServicePrivateListOfIO::eventq.get() ) ) {
this->ioTable.remove ( *pIO );
tmp.add ( *pIO );
}
if ( chan.dbServicePrivateListOfIO::pBlocker ) {
this->ioTable.remove ( *chan.dbServicePrivateListOfIO::pBlocker );
}
while ( ( pIO = chan.dbContextPrivateListOfIO::eventq.get() ) ) {
this->ioTable.remove ( *pIO );
tmp.add ( *pIO );
}
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
this->ioTable.remove ( *chan.dbContextPrivateListOfIO::pBlocker );
}
while ( ( pIO = tmp.get() ) ) {
// This prevents a db event callback from coming
// through after the notify IO is deleted
pIO->unsubscribe ();
pIO->unsubscribe ( guard );
// If they call ioCancel() here it will be ignored
// because the IO has been unregistered above.
pIO->channelDeleteException ();
pIO->~dbSubscriptionIO ();
pIO->channelDeleteException ( guard );
pIO->destructor ( guard );
this->dbSubscriptionIOFreeList.release ( pIO );
}
if ( chan.dbServicePrivateListOfIO::pBlocker ) {
chan.dbServicePrivateListOfIO::pBlocker->~dbPutNotifyBlocker ();
this->dbPutNotifyBlockerFreeList.release ( chan.dbServicePrivateListOfIO::pBlocker );
chan.dbServicePrivateListOfIO::pBlocker = 0;
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker->destructor ( guard );
this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker );
chan.dbContextPrivateListOfIO::pBlocker = 0;
}
}
void dbServiceIO::ioCancel ( dbChannelIO & chan, const cacChannel::ioid &id )
void dbContext::ioCancel (
epicsGuard < epicsMutex > & guard, dbChannelIO & chan,
const cacChannel::ioid &id )
{
epicsGuard < epicsMutex > locker ( this->mutex );
guard.assertIdenticalMutex ( this->mutex );
dbBaseIO * pIO = this->ioTable.remove ( id );
if ( pIO ) {
dbSubscriptionIO *pSIO = pIO->isSubscription ();
if ( pSIO ) {
chan.dbServicePrivateListOfIO::eventq.remove ( *pSIO );
pSIO->~dbSubscriptionIO ();
chan.dbContextPrivateListOfIO::eventq.remove ( *pSIO );
pSIO->destructor ( guard );
this->dbSubscriptionIOFreeList.release ( pSIO );
}
else if ( pIO == chan.dbServicePrivateListOfIO::pBlocker ) {
chan.dbServicePrivateListOfIO::pBlocker->cancel ();
else if ( pIO == chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker->cancel ( guard );
}
else {
errlogPrintf ( "dbServiceIO::ioCancel() unrecognized IO was probably leaked or not canceled\n" );
errlogPrintf ( "dbContext::ioCancel() unrecognized IO was probably leaked or not canceled\n" );
}
}
}
void dbServiceIO::ioShow ( const cacChannel::ioid &id, unsigned level ) const
void dbContext::ioShow (
epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id,
unsigned level ) const
{
epicsGuard < epicsMutex > locker ( this->mutex );
const dbBaseIO *pIO = this->ioTable.lookup ( id );
guard.assertIdenticalMutex ( this->mutex );
const dbBaseIO * pIO = this->ioTable.lookup ( id );
if ( pIO ) {
pIO->show ( level );
pIO->show ( guard, level );
}
}
void dbServiceIO::showAllIO ( const dbChannelIO &chan, unsigned level ) const
void dbContext::showAllIO ( const dbChannelIO & chan, unsigned level ) const
{
epicsGuard < epicsMutex > locker ( this->mutex );
epicsGuard < epicsMutex > guard ( this->mutex );
tsDLIterConst < dbSubscriptionIO > pItem =
chan.dbServicePrivateListOfIO::eventq.firstIter ();
chan.dbContextPrivateListOfIO::eventq.firstIter ();
while ( pItem.valid () ) {
pItem->show ( level );
pItem->show ( guard, level );
pItem++;
}
if ( chan.dbServicePrivateListOfIO::pBlocker ) {
chan.dbServicePrivateListOfIO::pBlocker->show ( level );
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker->show ( guard, level );
}
}
void dbServiceIO::show ( unsigned level ) const
void dbContext::show ( unsigned level ) const
{
epicsGuard < epicsMutex > locker ( this->mutex );
printf ( "dbServiceIO at %p\n",
epicsGuard < epicsMutex > guard ( this->mutex );
}
void dbContext::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
printf ( "dbContext at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
printf ( "\tevent call back cache location %p, and its size %lu\n",
static_cast <void *> ( this->pStateNotifyCache ), this->stateNotifyCacheSize );
this->readNotifyCache.show ( level - 1 );
this->readNotifyCache.show ( guard, level - 1 );
}
if ( level > 1u ) {
this->mutex.show ( level - 2u );
}
}
void dbContext::flush (
epicsGuard < epicsMutex > & )
{
}
unsigned dbContext::circuitCount (
epicsGuard < epicsMutex > & ) const
{
return 0u;
}
void dbContext::selfTest (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
this->ioTable.verify ();
}
unsigned dbContext::beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const
{
return 0u;
}

View File

@@ -41,37 +41,57 @@
#include "dbChannelIO.h"
#include "db_access_routines.h"
dbSubscriptionIO::dbSubscriptionIO ( dbServiceIO & /* serviceIO */, dbChannelIO & chanIO,
dbAddr & addr, cacStateNotify & notifyIn, unsigned typeIn, unsigned long countIn,
unsigned maskIn, dbEventCtx ctx ) :
notify ( notifyIn ), chan ( chanIO ), es ( 0 ),
type ( typeIn ), count ( countIn ), id ( 0u )
dbSubscriptionIO::dbSubscriptionIO (
epicsGuard < epicsMutex > & guard, epicsMutex & mutexIn,
dbContext &, dbChannelIO & chanIO,
dbAddr & addr, cacStateNotify & notifyIn, unsigned typeIn,
unsigned long countIn, unsigned maskIn, dbEventCtx ctx ) :
mutex ( mutexIn ), count ( countIn ), notify ( notifyIn ),
chan ( chanIO ), es ( 0 ), type ( typeIn ), id ( 0u )
{
this->es = db_add_event ( ctx, & addr,
dbSubscriptionEventCallback, (void *) this, maskIn );
if ( this->es == 0 ) {
throw std::bad_alloc();
guard.assertIdenticalMutex ( this->mutex );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
this->es = db_add_event ( ctx, & addr,
dbSubscriptionEventCallback, (void *) this, maskIn );
if ( this->es == 0 ) {
throw std::bad_alloc();
}
db_post_single_event ( this->es );
db_event_enable ( this->es );
}
db_post_single_event ( this->es );
db_event_enable ( this->es );
}
dbSubscriptionIO::~dbSubscriptionIO ()
dbSubscriptionIO::~dbSubscriptionIO ()
{
this->unsubscribe ();
}
void dbSubscriptionIO::unsubscribe ()
void dbSubscriptionIO::destructor ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->unsubscribe ( guard );
this->~dbSubscriptionIO ();
}
void dbSubscriptionIO::unsubscribe (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->es ) {
db_cancel_event ( this->es );
dbEventSubscription tmp = this->es;
this->es = 0;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
db_cancel_event ( tmp );
}
}
}
void dbSubscriptionIO::channelDeleteException ()
void dbSubscriptionIO::channelDeleteException (
epicsGuard < epicsMutex > & guard )
{
this->notify.exception ( ECA_CHANDESTROY,
guard.assertIdenticalMutex ( this->mutex );
this->notify.exception ( guard, ECA_CHANDESTROY,
this->chan.pName(), this->type, this->count );
}
@@ -94,14 +114,14 @@ void dbSubscriptionIO::operator delete ( void * )
}
void * dbSubscriptionIO::operator new ( size_t size,
tsFreeList < dbSubscriptionIO > & freeList )
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
void dbSubscriptionIO::operator delete ( void * pCadaver,
tsFreeList < dbSubscriptionIO > & freeList )
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
@@ -110,12 +130,21 @@ void dbSubscriptionIO::operator delete ( void * pCadaver,
extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbAddr * /* paddr */,
int /* eventsRemaining */, struct db_field_log *pfl )
{
dbSubscriptionIO *pIO = static_cast < dbSubscriptionIO * > ( pPrivate );
dbSubscriptionIO * pIO = static_cast < dbSubscriptionIO * > ( pPrivate );
pIO->chan.callStateNotify ( pIO->type, pIO->count, pfl, pIO->notify );
}
void dbSubscriptionIO::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->show ( guard, level );
}
void dbSubscriptionIO::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
printf ( "Data base subscription IO at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {