many changes associated will disconnecting the channel but not disconnecting the circuit
This commit is contained in:
162
src/ca/CASG.cpp
162
src/ca/CASG.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
17
src/ca/bhe.h
17
src/ca/bhe.h
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
867
src/ca/cac.cpp
867
src/ca/cac.cpp
File diff suppressed because it is too large
Load Diff
186
src/ca/cac.h
186
src/ca/cac.h
@@ -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 )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -104,5 +104,8 @@ void cacChannel::operator delete ( void * )
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
cacContext::~cacContext () {}
|
||||
|
||||
cacService::~cacService () {}
|
||||
|
||||
|
||||
|
||||
@@ -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 ()
|
||||
{
|
||||
}
|
||||
|
||||
139
src/ca/cacIO.h
139
src/ca/cacIO.h
@@ -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 )
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
57
src/ca/disconnectGovernorTimer.cpp
Normal file
57
src/ca/disconnectGovernorTimer.cpp
Normal 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
|
||||
{
|
||||
}
|
||||
|
||||
60
src/ca/disconnectGovernorTimer.h
Normal file
60
src/ca/disconnectGovernorTimer.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,9 +27,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if 0
|
||||
#include "iocinf.h"
|
||||
#endif
|
||||
#include "hostNameCache.h"
|
||||
#include "epicsGuard.h"
|
||||
|
||||
|
||||
359
src/ca/nciu.cpp
359
src/ca/nciu.cpp
@@ -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 ¬ify, 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 ¬ify, 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 ¬ify, 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;
|
||||
}
|
||||
|
||||
|
||||
160
src/ca/nciu.h
160
src/ca/nciu.h
@@ -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 ¬ify, 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
|
||||
|
||||
154
src/ca/netIO.h
154
src/ca/netIO.h
@@ -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 ¬ify );
|
||||
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 ¬ify );
|
||||
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 ¬ify );
|
||||
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 ¬ify );
|
||||
privateInterfaceForIO &, cacWriteNotify & );
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
cacWriteNotify & notify;
|
||||
nciu & chan;
|
||||
netWriteNotifyIO ( nciu &chan, cacWriteNotify ¬ify );
|
||||
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 ¬ify )
|
||||
{
|
||||
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 ¬ify )
|
||||
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 ¬ify )
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ¬ifyIn ) :
|
||||
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
|
||||
|
||||
@@ -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 * )
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 ¬ify, 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 ¬ify, 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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ class repeaterSubscribeTimer : private epicsTimerNotify {
|
||||
public:
|
||||
repeaterSubscribeTimer ( udpiiu &, epicsTimerQueue & );
|
||||
virtual ~repeaterSubscribeTimer ();
|
||||
void shutdown ();
|
||||
void confirmNotify ();
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 > &,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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" : "" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 & );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
147
src/db/dbCAC.h
147
src/db/dbCAC.h
@@ -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 ¬ify );
|
||||
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 ¬ify );
|
||||
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 ¬ify,
|
||||
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 ¬ify )
|
||||
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
|
||||
|
||||
@@ -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 ¬ify, 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 ¬ify, 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 );
|
||||
}
|
||||
|
||||
@@ -41,40 +41,52 @@
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
class dbChannelIO : public cacChannel, public dbServicePrivateListOfIO {
|
||||
class dbChannelIO : public cacChannel, public dbContextPrivateListOfIO {
|
||||
public:
|
||||
dbChannelIO ( cacChannelNotify ¬ify,
|
||||
const dbAddr &addr, dbServiceIO &serviceIO );
|
||||
~dbChannelIO ();
|
||||
void destroy ();
|
||||
void callReadNotify ( unsigned type, unsigned long count,
|
||||
cacReadNotify ¬ify );
|
||||
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 ¬ify );
|
||||
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 ¬ify, 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 ¬ify )
|
||||
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,
|
||||
|
||||
@@ -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 ¬ify )
|
||||
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 );
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 * );
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
Reference in New Issue
Block a user