From a1fbe85e7b4dfdab1ec01d7e274773b4b459a769 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 9 Feb 2001 17:38:00 +0000 Subject: [PATCH] redesigned class hierarchy --- src/ca/CASG.cpp | 18 ++- src/ca/Makefile | 5 +- src/ca/cacChannelIO.cpp | 66 +---------- src/ca/cacIO.h | 219 ++++++++++++++-------------------- src/ca/cacNotify.cpp | 36 +++--- src/ca/cacNotifyIO.cpp | 11 +- src/ca/cacServiceList.cpp | 7 +- src/ca/cadef.h | 29 ++--- src/ca/getCallback.cpp | 49 ++++---- src/ca/ioCounter_IL.h | 22 +++- src/ca/iocinf.h | 226 ++++++++++++++++-------------------- src/ca/nciu.cpp | 130 ++++++++++++--------- src/ca/nciu_IL.h | 20 +++- src/ca/netReadCopyIO.cpp | 23 ++-- src/ca/netReadNotifyIO.cpp | 25 ++-- src/ca/netSubscription.cpp | 29 +++-- src/ca/netWriteNotifyIO.cpp | 29 +++-- src/ca/netiiu.cpp | 36 +++--- src/ca/oldAccess.h | 154 ++++++++++++++---------- src/ca/oldChannel.cpp | 196 +------------------------------ src/ca/oldChannelNotify.cpp | 124 ++++++++++++++++++++ src/ca/oldSubscription.cpp | 53 ++++----- src/ca/putCallback.cpp | 62 +++++----- src/ca/syncGroupNotify.cpp | 48 ++++---- src/ca/tcpiiu.cpp | 81 ++++++++++--- 25 files changed, 819 insertions(+), 879 deletions(-) create mode 100644 src/ca/oldChannelNotify.cpp diff --git a/src/ca/CASG.cpp b/src/ca/CASG.cpp index d75ef02ec..3c6242687 100644 --- a/src/ca/CASG.cpp +++ b/src/ca/CASG.cpp @@ -49,7 +49,7 @@ CASG::~CASG () this->mutex.lock (); tsDLIterBD notify ( this->ioList.first () ); while ( notify.valid () ) { - notify->destroy (); + notify->release (); notify = this->ioList.first (); } this->mutex.unlock (); @@ -85,12 +85,12 @@ int CASG::block ( double timeout ) /* * dont allow recursion */ - void *p = epicsThreadPrivateGet (cacRecursionLock); + void *p = epicsThreadPrivateGet ( cacRecursionLock ); if ( p ) { return ECA_EVDISALLOW; } - epicsThreadPrivateSet (cacRecursionLock, &cacRecursionLock); + epicsThreadPrivateSet ( cacRecursionLock, &cacRecursionLock ); cur_time = epicsTime::getCurrent (); @@ -189,7 +189,11 @@ int CASG::put (chid pChan, unsigned type, unsigned long count, const void *pValu if ( ! pNotify ) { return ECA_ALLOCMEM; } - return pChan->write ( type, count, pValue, *pNotify ); + int status = pChan->write ( type, count, pValue, *pNotify ); + if ( status != ECA_NORMAL ) { + pNotify->release (); + } + return status; } int CASG::get (chid pChan, unsigned type, unsigned long count, void *pValue) @@ -198,6 +202,10 @@ int CASG::get (chid pChan, unsigned type, unsigned long count, void *pValue) if ( ! pNotify ) { return ECA_ALLOCMEM; } - return pChan->read ( type, count, *pNotify ); + int status = pChan->read ( type, count, *pNotify ); + if ( status != ECA_NORMAL ) { + pNotify->release (); + } + return status; } diff --git a/src/ca/Makefile b/src/ca/Makefile index fd85e1107..4054fd0e9 100644 --- a/src/ca/Makefile +++ b/src/ca/Makefile @@ -14,8 +14,8 @@ INC += db_access.h INC += addrList.h INC += cacIO.h -LIBSRCS += cacChannel.cpp LIBSRCS += cacChannelIO.cpp +LIBSRCS += cacChannelNotify.cpp LIBSRCS += cacNotify.cpp LIBSRCS += cacNotifyIO.cpp LIBSRCS += cacServiceList.cpp @@ -40,7 +40,7 @@ LIBSRCS += cac.cpp LIBSRCS += tcpSendWatchdog.cpp LIBSRCS += tcpRecvWatchdog.cpp LIBSRCS += bhe.cpp -LIBSRCS += oldChannel.cpp +LIBSRCS += oldChannelNotify.cpp LIBSRCS += oldSubscription.cpp LIBSRCS += getCallback.cpp LIBSRCS += putCallback.cpp @@ -79,6 +79,7 @@ caRepeater_SRCS = caRepeater.cpp PROD += caRepeater PROD_DEFAULT += catime acctst caConnTest casw caEventRate +OBJS_IOC += catime acctst caConnTest casw caEventRate catime_SRCS = catimeMain.c catime.c acctst_SRCS = acctstMain.c acctst.c caEventRate_SRCS = caEventRateMain.cpp caEventRate.cpp diff --git a/src/ca/cacChannelIO.cpp b/src/ca/cacChannelIO.cpp index 9df75bd07..cafbd7756 100644 --- a/src/ca/cacChannelIO.cpp +++ b/src/ca/cacChannelIO.cpp @@ -15,47 +15,8 @@ #include "iocinf.h" -cacChannelIO::cacChannelIO ( cacChannel &chanIn ) : - chan ( chanIn ) -{ -} - cacChannelIO::~cacChannelIO () { - this->chan.pChannelIO = 0; -} - -cacLocalChannelIO::cacLocalChannelIO ( cac &cacCtxIn, cacChannel &chan ) : - cacChannelIO ( chan ), cacCtx ( cacCtxIn ) {}; - -cacLocalChannelIO::~cacLocalChannelIO () -{ - this->cacCtx.uninstallLocalChannel ( *this ); -} - -void cacChannelIO::connectNotify () -{ - this->chan.connectNotify (); -} - -void cacChannelIO::disconnectNotify () -{ - this->chan.disconnectNotify (); -} - -void cacChannelIO::connectTimeoutNotify () -{ - this->chan.connectTimeoutNotify (); -} - -void cacChannelIO::accessRightsNotify ( caar ar ) -{ - this->chan.accessRightsNotify ( ar ); -} - -void cacChannelIO::ioReleaseNotify () -{ - this->chan.ioReleaseNotify (); } channel_state cacChannelIO::state () const @@ -71,6 +32,10 @@ caar cacChannelIO::accessRights () const return ar; } +void cacChannelIO::notifyStateChangeFirstConnectInCountOfOutstandingIO () +{ +} + unsigned cacChannelIO::searchAttempts () const { return 0u; @@ -91,15 +56,10 @@ bool cacChannelIO::connected () const return true; } -unsigned cacChannelIO::readSequence () const -{ - return 0u; -} - void cacChannelIO::hostName ( char *pBuf, unsigned bufLength ) const { if ( bufLength ) { - localHostNameAtLoadTime.copy (pBuf, bufLength ); + localHostNameAtLoadTime.copy ( pBuf, bufLength ); } } @@ -109,20 +69,4 @@ const char * cacChannelIO::pHostName () const return localHostNameAtLoadTime.pointer (); } -void cacChannelIO::incrementOutstandingIO () -{ -} - -void cacChannelIO::decrementOutstandingIO () -{ -} - -void cacChannelIO::lockOutstandingIO () const -{ -} - -void cacChannelIO::unlockOutstandingIO () const -{ -} - diff --git a/src/ca/cacIO.h b/src/ca/cacIO.h index 71a4be32e..87e8daaa4 100644 --- a/src/ca/cacIO.h +++ b/src/ca/cacIO.h @@ -15,147 +15,105 @@ * 505 665 1831 */ +// +// Notes +// 1) these routines should be changed to throw exceptions and not return +// ECA_XXXX style status in the future. +// + #include "tsDLList.h" #include "epicsMutex.h" #include "shareLib.h" -class cacNotifyIO; -class cac; +struct cacChannelIO; +struct cacNotifyIO; -class epicsShareClass cacNotify { +class cacNotify { public: - cacNotify (); - virtual ~cacNotify () = 0; - virtual void destroy () = 0; - virtual void completionNotify (); - virtual void completionNotify ( unsigned type, unsigned long count, const void *pData ); - virtual void exceptionNotify ( int status, const char *pContext ); - virtual void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); -private: - cacNotifyIO *pIO; - friend class cacNotifyIO; -}; - -class epicsShareClass cacNotifyIO { -public: - cacNotifyIO ( cacNotify & ); - virtual ~cacNotifyIO () = 0; - virtual void uninstall () = 0; - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); -private: - cacNotify ¬ify; - friend class cacNotify; -}; - -class epicsShareClass cacChannel { -public: - cacChannel (); - virtual ~cacChannel () = 0; - virtual void destroy () = 0; - - void attachIO ( class cacChannelIO &io ); - int read ( unsigned type, unsigned long count, void *pValue ); - int read ( unsigned type, unsigned long count, cacNotify & ); - int write ( unsigned type, unsigned long count, const void *pvalue ); - int write ( unsigned type, unsigned long count, const void *pvalue, cacNotify ¬ify ); - int subscribe ( unsigned type, unsigned long count, unsigned mask, cacNotify ¬ify ); - void hostName ( char *pBuf, unsigned bufLength ) const; - short nativeType () const; - unsigned long nativeElementCount () const; - channel_state state () const; - bool readAccess () const; - bool writeAccess () const; - const char *pName () const; - unsigned searchAttempts () const; - double beaconPeriod () const; - bool ca_v42_ok () const; - bool connected () const; - caar accessRights () const; - unsigned readSequence () const; - void incrementOutstandingIO (); - void decrementOutstandingIO (); - void decrementOutstandingIO ( unsigned seqNumber ); - - const char * pHostName () const; // deprecated - please do not use - + epicsShareFunc virtual void release () = 0; + epicsShareFunc virtual void completionNotify ( cacChannelIO & ); + epicsShareFunc virtual void completionNotify ( cacChannelIO &, unsigned type, + unsigned long count, const void *pData ); + epicsShareFunc virtual void exceptionNotify ( cacChannelIO &, + int status, const char *pContext ); + epicsShareFunc virtual void exceptionNotify ( cacChannelIO &, + int status, const char *pContext, unsigned type, unsigned long count ); protected: - class cacChannelIO *pChannelIO; - - void lockOutstandingIO () const; - void unlockOutstandingIO () const; - -private: - virtual void ioAttachNotify (); - virtual void ioReleaseNotify (); - virtual void connectNotify (); - virtual void disconnectNotify (); - virtual void accessRightsNotify ( caar ); - virtual void exceptionNotify ( int status, const char *pContext ); - virtual void connectTimeoutNotify (); - - friend class cacChannelIO; + epicsShareFunc virtual ~cacNotify () = 0; }; -class epicsShareClass cacChannelIO { +struct cacNotifyIO { public: - cacChannelIO ( cacChannel &chan ); - virtual ~cacChannelIO () = 0; - virtual void destroy () = 0; - - void connectNotify (); - void disconnectNotify (); - void connectTimeoutNotify (); - void accessRightsNotify ( caar ); - void ioReleaseNotify (); - - virtual const char *pName () const = 0; - - virtual void lockOutstandingIO () const = 0; - virtual void unlockOutstandingIO () const = 0; - - virtual void show ( unsigned level ) const = 0; - + epicsShareFunc cacNotifyIO ( cacNotify & ); + epicsShareFunc cacNotify & notify () const; + epicsShareFunc virtual void destroy () = 0; // also uninstalls + epicsShareFunc virtual cacChannelIO & channelIO () const = 0; +protected: + epicsShareFunc virtual ~cacNotifyIO () = 0; private: - virtual int read ( unsigned type, unsigned long count, void *pValue) = 0; - virtual int read ( unsigned type, unsigned long count, cacNotify ¬ify ) = 0; - virtual int write ( unsigned type, unsigned long count, const void *pValue ) = 0; - virtual int write ( unsigned type, unsigned long count, const void *pValue, cacNotify ¬ify ) = 0; - virtual int subscribe ( unsigned type, unsigned long count, unsigned mask, cacNotify ¬ify ) = 0; - virtual short nativeType () const = 0; - virtual unsigned long nativeElementCount () const = 0; - virtual void hostName (char *pBuf, unsigned bufLength) const; // defaults to local host name - virtual channel_state state () const; // defaults to always connected - virtual caar accessRights () const; // defaults to unrestricted access - virtual unsigned searchAttempts () const; // defaults to zero - virtual double beaconPeriod () const; // defaults to negative DBL_MAX - virtual bool ca_v42_ok () const; // defaults to true - virtual bool connected () const; // defaults to true - virtual unsigned readSequence () const; // defaults to always zero - virtual void incrementOutstandingIO (); - virtual void decrementOutstandingIO (); - virtual const char * pHostName () const; // deprecated - please do not use - - cacChannel &chan; - - friend class cacChannel; + cacNotify &callback; }; -class cacLocalChannelIO : - public cacChannelIO, public tsDLNode < cacLocalChannelIO > { +class cacChannelNotify { public: - epicsShareFunc cacLocalChannelIO ( cac&, cacChannel &chan ); - epicsShareFunc virtual ~cacLocalChannelIO (); -private: - cac &cacCtx; + epicsShareFunc virtual void release () = 0; + epicsShareFunc virtual void connectNotify ( cacChannelIO & ); + epicsShareFunc virtual void disconnectNotify ( cacChannelIO & ); + epicsShareFunc virtual void accessRightsNotify ( cacChannelIO &, const caar & ); + epicsShareFunc virtual void exceptionNotify ( cacChannelIO &, int status, const char *pContext ); + + // not for public consumption + epicsShareFunc virtual bool includeFirstConnectInCountOfOutstandingIO () const; + epicsShareFunc virtual class oldChannelNotify * pOldChannelNotify (); +protected: + epicsShareFunc virtual ~cacChannelNotify () = 0; }; +struct cacChannelIO { +public: + epicsShareFunc cacChannelIO ( cacChannelNotify &chan ); + epicsShareFunc cacChannelNotify & notify () const; + + epicsShareFunc virtual void destroy () = 0; + epicsShareFunc virtual const char *pName () const = 0; + epicsShareFunc virtual void show ( unsigned level ) const = 0; + epicsShareFunc virtual void initiateConnect () = 0; + epicsShareFunc virtual int read ( unsigned type, + unsigned long count, void *pValue) = 0; + epicsShareFunc virtual int read ( unsigned type, + unsigned long count, cacNotify ¬ify ) = 0; + epicsShareFunc virtual int write ( unsigned type, + unsigned long count, const void *pValue ) = 0; + epicsShareFunc virtual int write ( unsigned type, + unsigned long count, const void *pValue, + cacNotify ¬ify ) = 0; + epicsShareFunc virtual int subscribe ( unsigned type, + unsigned long count, unsigned mask, + cacNotify ¬ify, cacNotifyIO *& ) = 0; + epicsShareFunc virtual short nativeType () const = 0; + epicsShareFunc virtual unsigned long nativeElementCount () const = 0; + epicsShareFunc virtual channel_state state () const; // defaults to always connected + epicsShareFunc virtual caar accessRights () const; // defaults to unrestricted access + epicsShareFunc virtual unsigned searchAttempts () const; // defaults to zero + epicsShareFunc virtual double beaconPeriod () const; // defaults to negative DBL_MAX + epicsShareFunc virtual bool ca_v42_ok () const; // defaults to true + epicsShareFunc virtual bool connected () const; // defaults to true + epicsShareFunc virtual void hostName (char *pBuf, unsigned bufLength) const; // defaults to local host name + epicsShareFunc virtual const char * pHostName () const; // deprecated - please do not use + epicsShareFunc virtual void notifyStateChangeFirstConnectInCountOfOutstandingIO (); +protected: + epicsShareFunc virtual ~cacChannelIO () = 0; +private: + cacChannelNotify &chan; +}; + +class cac; + struct cacServiceIO : public tsDLNode < cacServiceIO > { public: - epicsShareFunc virtual cacLocalChannelIO *createChannelIO ( const char *pName, cac &, cacChannel & ) = 0; + epicsShareFunc virtual cacChannelIO *createChannelIO ( + const char *pName, cac &, cacChannelNotify & ) = 0; epicsShareFunc virtual void show ( unsigned level ) const = 0; private: }; @@ -164,7 +122,8 @@ class cacServiceList : private epicsMutex { public: epicsShareFunc cacServiceList (); epicsShareFunc void registerService ( cacServiceIO &service ); - epicsShareFunc cacLocalChannelIO * createChannelIO ( const char *pName, cac &, cacChannel & ); + epicsShareFunc cacChannelIO * createChannelIO ( + const char *pName, cac &, cacChannelNotify & ); epicsShareFunc void show ( unsigned level ) const; private: tsDLList < cacServiceIO > services; @@ -174,23 +133,21 @@ epicsShareExtern cacServiceList cacGlobalServiceList; epicsShareFunc int epicsShareAPI ca_register_service ( struct cacServiceIO *pService ); -inline void cacNotifyIO::completionNotify () +inline cacNotifyIO::cacNotifyIO ( cacNotify ¬ifyIn ) : callback ( notifyIn ) { - this->notify.completionNotify (); } -inline void cacNotifyIO::completionNotify ( unsigned type, unsigned long count, const void *pData ) +inline cacNotify & cacNotifyIO::notify () const { - this->notify.completionNotify ( type, count, pData ); + return this->callback; } -inline void cacNotifyIO::exceptionNotify ( int status, const char *pContext ) +inline cacChannelIO::cacChannelIO ( cacChannelNotify &chanIn ) : chan ( chanIn ) { - this->notify.exceptionNotify ( status, pContext ); } -inline void cacNotifyIO::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ) +inline cacChannelNotify & cacChannelIO::notify () const { - this->notify.exceptionNotify ( status, pContext, type, count ); + return this->chan; } diff --git a/src/ca/cacNotify.cpp b/src/ca/cacNotify.cpp index 4b25f90b3..99737c55c 100644 --- a/src/ca/cacNotify.cpp +++ b/src/ca/cacNotify.cpp @@ -12,40 +12,32 @@ #include "iocinf.h" -cacNotify::cacNotify () : pIO (0) -{ -} - cacNotify::~cacNotify () { - cacNotifyIO *pTmpIO = this->pIO; - if ( pTmpIO ) { - this->pIO = 0; - // the code fits together better in iother places - // if the delete and the uninstall are speparate steps - pTmpIO->uninstall (); - delete pTmpIO; - } } -void cacNotify::completionNotify () +void cacNotify::completionNotify ( cacChannelIO &chan ) { - ca_printf ("CAC: IO completion with no handler installed?\n"); + ca_printf ( "CAC: IO completion for channel %s with no handler installed?\n", + chan.pName () ); } -void cacNotify::completionNotify ( unsigned type, unsigned long count, const void *pData ) +void cacNotify::completionNotify ( cacChannelIO &chan, + unsigned type, unsigned long count, const void *pData ) { - ca_printf ("CAC: IO completion with no handler installed? type=%u count=%u data pointer=%p\n", - type, count, pData); + ca_printf ( "CAC: IO completion with no handler installed? channel=%s type=%u count=%u data pointer=%p\n", + chan.pName (), type, count, pData ); } -void cacNotify::exceptionNotify ( int status, const char *pContext ) +void cacNotify::exceptionNotify ( cacChannelIO &chan, int status, const char *pContext ) { - ca_signal (status, pContext); + ca_signal_formated ( status, __FILE__, __LINE__, "%s channel=%s\n", + pContext, chan.pName () ); } -void cacNotify::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ) +void cacNotify::exceptionNotify ( cacChannelIO &chan, int status, + const char *pContext, unsigned type, unsigned long count ) { - ca_signal_formated (status, __FILE__, __LINE__, "%s type=%d count=%ld\n", - pContext, type, count); + ca_signal_formated ( status, __FILE__, __LINE__, "%s channel=%s type=%d count=%ld\n", + chan.pName (), pContext, type, count ); } diff --git a/src/ca/cacNotifyIO.cpp b/src/ca/cacNotifyIO.cpp index ac3a93122..df837a566 100644 --- a/src/ca/cacNotifyIO.cpp +++ b/src/ca/cacNotifyIO.cpp @@ -12,17 +12,8 @@ #include "iocinf.h" -cacNotifyIO::cacNotifyIO ( cacNotify ¬ifyIn ) : notify ( notifyIn ) -{ - assert ( ! this->notify.pIO ); - this->notify.pIO = this; -} - cacNotifyIO::~cacNotifyIO () { - if ( this->notify.pIO == this ) { - this->notify.pIO = 0; - this->notify.destroy (); - } + this->callback.release (); } diff --git a/src/ca/cacServiceList.cpp b/src/ca/cacServiceList.cpp index 1ddab1b70..62f8b3357 100644 --- a/src/ca/cacServiceList.cpp +++ b/src/ca/cacServiceList.cpp @@ -30,12 +30,13 @@ void cacServiceList::registerService ( cacServiceIO &service ) this->unlock (); } -cacLocalChannelIO * cacServiceList::createChannelIO (const char *pName, cac &cacCtx, cacChannel &chan) +cacChannelIO * cacServiceList::createChannelIO ( const char *pName, + cac &cacCtx, cacChannelNotify &chan ) { - cacLocalChannelIO *pChanIO = 0; + cacChannelIO *pChanIO = 0; this->lock (); - tsDLIterBD iter ( this->services.first () ); + tsDLIterBD < cacServiceIO > iter ( this->services.first () ); while ( iter.valid () ) { pChanIO = iter->createChannelIO ( pName, cacCtx, chan ); if ( pChanIO ) { diff --git a/src/ca/cadef.h b/src/ca/cadef.h index 513dae70b..761bf3efc 100644 --- a/src/ca/cadef.h +++ b/src/ca/cadef.h @@ -47,10 +47,10 @@ extern "C" { #endif -typedef struct oldChannel *chid; +typedef struct cacChannelIO *chid; typedef chid chanId; /* for when the structures field name is "chid" */ typedef long chtype; -typedef struct oldSubscription *evid; +typedef struct cacNotifyIO *evid; typedef double ca_real; /* Format for the arguments to user connection handlers */ @@ -869,26 +869,6 @@ ca_sg_array_put (gid, type, 1u, chan, pValue) */ epicsShareFunc int epicsShareAPI ca_sg_stat (CA_SYNC_GID gid); -/* - * ca_modify_user_name() - * - * Modify or override the default - * client user name. - * - * pUserName R new user name string copied from this location - */ -epicsShareFunc int epicsShareAPI ca_modify_user_name ( const char *pUserName ); - -/* - * CA_MODIFY_HOST_NAME() - * - * Modify or override the default - * client host name. - * - * pHostName R new host name string copied from this location - */ -epicsShareFunc int epicsShareAPI ca_modify_host_name ( const char *pHostName ); - /* * ca_v42_ok() * @@ -950,6 +930,11 @@ epicsShareFunc int epicsShareAPI ca_client_status (unsigned level); epicsShareFunc int epicsShareAPI ca_import (epicsThreadId tid); epicsShareFunc int epicsShareAPI ca_import_cancel (epicsThreadId tid); +/* + * defunct + */ +epicsShareFunc int epicsShareAPI ca_modify_user_name ( const char *pUserName ); +epicsShareFunc int epicsShareAPI ca_modify_host_name ( const char *pHostName ); #else /* CAC_ANSI_FUNC_PROTO */ epicsShareFunc short epicsShareAPI ca_get_field_type (); diff --git a/src/ca/getCallback.cpp b/src/ca/getCallback.cpp index 97c273be4..375089013 100644 --- a/src/ca/getCallback.cpp +++ b/src/ca/getCallback.cpp @@ -20,61 +20,52 @@ tsFreeList < class getCallback, 1024 > getCallback::freeList; -getCallback::getCallback (oldChannel &chanIn, caEventCallBackFunc *pFuncIn, void *pPrivateIn) : - chan (chanIn), pFunc (pFuncIn), pPrivate (pPrivateIn) -{ -} - getCallback::~getCallback () { } -void getCallback::destroy () +void getCallback::release () { delete this; } -void getCallback::completionNotify () -{ - cacNotify::completionNotify (); -} - -void getCallback::completionNotify ( unsigned type, unsigned long count, const void *pData ) +void getCallback::completionNotify ( cacChannelIO &io, + unsigned type, unsigned long count, const void *pData ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = &this->chan; + args.chid = & io; args.type = type; args.count = count; args.status = ECA_NORMAL; args.dbr = pData; - (*this->pFunc) (args); + ( *this->pFunc ) ( args ); } -void getCallback::exceptionNotify (int status, const char * /* pContext */) +void getCallback::exceptionNotify ( cacChannelIO &io, int status, + const char * /* pContext */) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = &this->chan; - args.type = 0; + args.chid = & io; + args.type = TYPENOTCONN; args.count = 0; args.status = status; args.dbr = 0; - (*this->pFunc) (args); + ( *this->pFunc ) ( args ); } -void getCallback::exceptionNotify ( int status, const char *pContext, +void getCallback::exceptionNotify ( cacChannelIO &io, + int status, const char *pContext, unsigned type, unsigned long count ) { - cacNotify::exceptionNotify ( status, pContext, type, count); + struct event_handler_args args; + args.usr = this->pPrivate; + args.chid = & io; + args.type = type; + args.count = count; + args.status = status; + args.dbr = 0; + ( *this->pFunc ) ( args ); } -void * getCallback::operator new ( size_t size ) -{ - return getCallback::freeList.allocate ( size ); -} - -void getCallback::operator delete ( void *pCadaver, size_t size ) -{ - getCallback::freeList.release ( pCadaver, size ); -} diff --git a/src/ca/ioCounter_IL.h b/src/ca/ioCounter_IL.h index 121950b39..aed34a76a 100644 --- a/src/ca/ioCounter_IL.h +++ b/src/ca/ioCounter_IL.h @@ -16,6 +16,9 @@ * 505 665 1831 */ +#ifndef ioCounter_ILh +#define ioCounter_ILh + inline ioCounter::ioCounter () : pndrecvcnt ( 0u ), readSeq ( 0u ) { } @@ -26,16 +29,23 @@ inline void ioCounter::incrementOutstandingIO () if ( this->pndrecvcnt < UINT_MAX ) { this->pndrecvcnt++; } + else { + throwWithLocation ( caErrorCode (ECA_INTERNAL) ); + } this->mutex.unlock (); } -inline void ioCounter::lockOutstandingIO () const +inline void ioCounter::incrementOutstandingIO ( unsigned readSeqIn ) { this->mutex.lock (); -} - -inline void ioCounter::unlockOutstandingIO () const -{ + if ( readSeqIn == this->readSeq ) { + if ( this->pndrecvcnt < UINT_MAX ) { + this->pndrecvcnt++; + } + else { + throwWithLocation ( caErrorCode (ECA_INTERNAL) ); + } + } this->mutex.unlock (); } @@ -64,4 +74,4 @@ inline void ioCounter::cleanUpOutstandingIO () this->mutex.unlock (); } - +#endif // ioCounter_ILh diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h index f5bb9b89d..af0a6ad68 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -28,7 +28,7 @@ #include #include -#if defined (epicsExportSharedSymbols) +#if defined ( epicsExportSharedSymbols ) # error suspect that libCom was not imported #endif @@ -48,7 +48,6 @@ #include "epicsThread.h" #include "osiTimer.h" #include "epicsMutex.h" -#include "epicsEvent.h" #include "resourceLib.h" #include "localHostName.h" #include "ipAddrToAsciiAsynchronous.h" @@ -108,9 +107,6 @@ static const unsigned comBufSize = 0x4000; -class gnuWarningEliminate { -}; - class wireSendAdapter { public: virtual unsigned sendBytes ( const void *pBuf, @@ -150,16 +146,14 @@ public: void operator delete ( void *pCadaver, size_t size ); bool flushToWire ( wireSendAdapter & ); unsigned fillFromWire ( wireRecvAdapter & ); -private: - static tsFreeList < class comBuf, 0x20 > freeList; - +protected: ~comBuf (); +private: unsigned nextWriteIndex; unsigned nextReadIndex; unsigned char buf [ comBufSize ]; // optimal for 100 Mb Ethernet LAN MTU - unsigned clipNElem ( unsigned elemSize, unsigned nElem ); - friend class gnuWarningEliminate; + static tsFreeList < class comBuf, 0x20 > freeList; }; struct msgDescriptor { @@ -262,14 +256,15 @@ class nciu : public cacChannelIO, public tsDLNode < nciu >, public chronIntIdRes < nciu >, public tcpiiuPrivateListOfIO { public: nciu ( class cac &, netiiu &, - cacChannel &, const char *pNameIn ); + cacChannelNotify &, const char *pNameIn ); + bool fullyConstructed () const; void destroy (); - void cacDestroy (); void connect ( unsigned nativeType, unsigned long nativeCount, unsigned sid ); void connect (); void disconnect ( netiiu &newiiu ); int createChannelRequest (); + void initiateConnect (); int read ( unsigned type, unsigned long count, void *pValue ); int read ( unsigned type, @@ -278,8 +273,9 @@ public: unsigned long count, const void *pValue ); int write ( unsigned type, unsigned long count, const void *pValue, cacNotify & ); - int subscribe ( unsigned type, - unsigned long count, unsigned mask, cacNotify ¬ify ); + int subscribe ( unsigned type, unsigned long nElem, + unsigned mask, cacNotify ¬ify, + cacNotifyIO *&pNotifyIO ); void hostName ( char *pBuf, unsigned bufLength ) const; bool ca_v42_ok () const; short nativeType () const; @@ -291,13 +287,8 @@ public: unsigned searchAttempts () const; double beaconPeriod () const; bool connected () const; - unsigned readSequence () const; - void incrementOutstandingIO (); - void decrementOutstandingIO (); - void decrementOutstandingIO ( unsigned seqNumber ); bool searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisChannel ); - bool fullyConstructed () const; bool isAttachedToVirtaulCircuit ( const osiSockAddr & ); bool identifierEquivelence ( unsigned idToMatch ); void * operator new ( size_t size ); @@ -308,12 +299,17 @@ public: ca_uint32_t getSID () const; ca_uint32_t getCID () const; netiiu * getPIIU (); + cac & getCAC (); void searchReplySetUp ( netiiu &iiu, unsigned sidIn, unsigned typeIn, unsigned long countIn ); void show ( unsigned level ) const; bool verifyIIU ( netiiu & ); bool verifyConnected ( netiiu & ); - + void decrementOutstandingIO ( unsigned seqNumber ); + void incrementOutstandingIO ( unsigned seqNumber ); + void connectTimeoutNotify (); +protected: + ~nciu (); // force pool allocation private: cac &cacCtx; caar ar; // access rights @@ -329,16 +325,13 @@ private: unsigned f_fullyConstructed:1; unsigned f_previousConn:1; // T if connected in the past unsigned f_claimSent:1; - - static tsFreeList < class nciu, 1024 > freeList; - - ~nciu (); // force pool allocation + unsigned f_firstConnectDecrementsOutstandingIO:1; + unsigned f_connectTimeOutSeen:1; void lock () const; void unlock () const; - void lockOutstandingIO () const; - void unlockOutstandingIO () const; const char * pHostName () const; // deprecated - please do not use - friend class gnuWarningEliminate; + void notifyStateChangeFirstConnectInCountOfOutstandingIO (); + static tsFreeList < class nciu, 1024 > freeList; }; class baseNMIU : public tsDLNode < baseNMIU >, @@ -347,12 +340,15 @@ public: baseNMIU ( nciu &chan ); virtual ~baseNMIU () = 0; virtual void completionNotify () = 0; - virtual void completionNotify ( unsigned type, unsigned long count, const void *pData ) = 0; - virtual void exceptionNotify ( int status, const char *pContext ) = 0; - virtual void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ) = 0; + virtual void completionNotify ( unsigned type, + unsigned long count, const void *pData ) = 0; + virtual void exceptionNotify ( int status, + const char *pContext ) = 0; + virtual void exceptionNotify ( int status, + const char *pContext, unsigned type, + unsigned long count ) = 0; virtual class netSubscription * isSubscription (); virtual void show ( unsigned level ) const; - virtual void uninstall () = 0; ca_uint32_t getID () const; nciu & channel () const; void destroy (); @@ -360,30 +356,36 @@ protected: nciu &chan; }; -class netSubscription : private cacNotifyIO, public baseNMIU { +class netSubscription : public cacNotifyIO, public baseNMIU { public: netSubscription ( nciu &chan, unsigned type, unsigned long count, unsigned mask, cacNotify ¬ify ); + void destroy (); void show ( unsigned level ) const; - void * operator new ( size_t size ); - void operator delete ( void *pCadaver, size_t size ); unsigned long getCount () const; unsigned getType () const; unsigned getMask () const; + void * operator new ( size_t size ); + void operator delete ( void *pCadaver, size_t size ); + +protected: + ~netSubscription (); + private: unsigned long count; unsigned type; unsigned mask; - void uninstall (); void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); + void completionNotify ( unsigned type, + unsigned long count, const void *pData ); + void exceptionNotify ( int status, + const char *pContext ); + void exceptionNotify ( int status, + const char *pContext, unsigned type, unsigned long count ); + cacChannelIO & channelIO () const; class netSubscription * isSubscription (); - ~netSubscription (); static tsFreeList < class netSubscription, 1024 > freeList; - friend class gnuWarningEliminate; }; class netReadCopyIO : public baseNMIU { @@ -393,53 +395,61 @@ public: void show ( unsigned level ) const; void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); +protected: + ~netReadCopyIO (); // must be allocated from pool private: unsigned type; unsigned long count; void *pValue; unsigned seqNumber; - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); + void completionNotify ( ); + void completionNotify ( unsigned type, + unsigned long count, const void *pData ); void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); - void uninstall (); - ~netReadCopyIO (); // must be allocated from pool + void exceptionNotify ( int status, + const char *pContext, unsigned type, unsigned long count ); + cacChannelIO & channelIO () const; static tsFreeList < class netReadCopyIO, 1024 > freeList; - friend class gnuWarningEliminate; }; class netReadNotifyIO : public cacNotifyIO, public baseNMIU { public: netReadNotifyIO ( nciu &chan, cacNotify ¬ify ); + void destroy (); void show ( unsigned level ) const; void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); -private: - void uninstall (); - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); +protected: ~netReadNotifyIO (); +private: + void completionNotify (); + void completionNotify ( unsigned type, + unsigned long count, const void *pData ); + void exceptionNotify ( int status, const char *pContext ); + void exceptionNotify ( int status, + const char *pContext, unsigned type, unsigned long count ); + cacChannelIO & channelIO () const; static tsFreeList < class netReadNotifyIO, 1024 > freeList; - friend class gnuWarningEliminate; }; class netWriteNotifyIO : public cacNotifyIO, public baseNMIU { public: netWriteNotifyIO ( nciu &chan, cacNotify ¬ify ); + void destroy (); void show ( unsigned level ) const; void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); -private: - void uninstall (); - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); +protected: ~netWriteNotifyIO (); +private: + void completionNotify (); + void completionNotify ( unsigned type, + unsigned long count, const void *pData ); + void exceptionNotify ( int status, const char *pContext ); + void exceptionNotify ( int status, + const char *pContext, unsigned type, unsigned long count ); + cacChannelIO & channelIO () const; static tsFreeList < class netWriteNotifyIO, 1024 > freeList; - friend class gnuWarningEliminate; }; /* @@ -497,7 +507,6 @@ public: void show ( unsigned level ) const; unsigned channelCount () const; void disconnectAllChan ( netiiu & newiiu ); - void destroyAllIO ( nciu &chan ); void connectTimeoutNotify (); bool searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisChannel ); void resetChannelRetryCounts (); @@ -518,9 +527,10 @@ public: virtual void connectAllIO ( nciu &chan ); virtual void disconnectAllIO ( nciu &chan ); virtual int clearChannelRequest ( nciu & ); - virtual void uninstallIO ( baseNMIU & ); + virtual bool uninstallIO ( baseNMIU & ); virtual void subscriptionCancelRequest ( netSubscription &subscr, bool userThread ); virtual double beaconPeriod () const; + virtual bool destroyAllIO ( nciu &chan ); protected: cac * pCAC () const; @@ -605,7 +615,7 @@ public: char *pInBuf, unsigned long blockSize ); void repeaterRegistrationMessage ( unsigned attemptNumber ); void flush (); - SOCKET getSock () const; + unsigned getPort () const; void show ( unsigned level ) const; bool isCurrentThread () const; @@ -622,6 +632,7 @@ private: SOCKET sock; unsigned short repeaterPort; unsigned short serverPort; + unsigned short localPort; bool shutdownCmd; bool sockCloseCompleted; @@ -711,12 +722,11 @@ public: void hostName ( char *pBuf, unsigned bufLength ) const; void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); +protected: + ~hostNameCache (); private: bool ioComplete; char hostNameBuf [128]; - ~hostNameCache (); - friend class gnuWarningEliminate; - static tsFreeList < class hostNameCache, 16 > freeList; }; @@ -743,7 +753,6 @@ public: void flush (); virtual void show ( unsigned level ) const; //osiSockAddr address () const; - SOCKET getSock () const; bool setEchoRequestPending (); void processIncoming (); @@ -794,6 +803,7 @@ private: unsigned sendBytes ( const void *pBuf, unsigned nBytesInBuf ); unsigned recvBytes ( void *pBuf, unsigned nBytesInBuf ); bool flushToWire ( bool userThread ); + bool threadContextSensitiveFlushToWire ( bool userThread ); friend void cacSendThreadTCP ( void *pParam ); friend void cacRecvThreadTCP ( void *pParam ); @@ -842,7 +852,8 @@ private: int status, const char *pContext, unsigned type, unsigned long count ); void connectAllIO ( nciu &chan ); void disconnectAllIO ( nciu &chan ); - void uninstallIO ( baseNMIU & ); + bool uninstallIO ( baseNMIU & ); + bool destroyAllIO ( nciu &chan ); int subscriptionRequest ( netSubscription &subscr, bool userThread ); void subscriptionCancelRequest ( netSubscription &subscr, bool userThread ); @@ -851,25 +862,6 @@ private: static const pProtoStubTCP tcpJumpTableCAC []; }; -#if 0 -class claimMsgCache { -public: - claimMsgCache ( bool v44 ); - ~claimMsgCache (); - int deliverMsg ( netiiu &iiu ); - void connectChannel ( cac & ); -private: - char *pStr; - unsigned clientId; - unsigned serverId; - unsigned currentStrLen; - unsigned bufLen; - bool v44; - - friend bool nciu::setClaimMsgCache ( class claimMsgCache & ); -}; -#endif - class inetAddrID { public: inetAddrID ( const struct sockaddr_in &addrIn ); @@ -892,15 +884,13 @@ public: epicsShareFunc void show ( unsigned level) const; epicsShareFunc void * operator new ( size_t size ); epicsShareFunc void operator delete ( void *pCadaver, size_t size ); - +protected: + epicsShareFunc ~bhe (); // force allocation from freeList private: tcpiiu *piiu; epicsTime timeStamp; double averagePeriod; - static tsFreeList < class bhe, 1024 > freeList; - epicsShareFunc ~bhe (); // force allocation from freeList - friend class gnuWarningEliminate; }; class caErrorCode { @@ -959,28 +949,26 @@ static const unsigned CASG_MAGIC = 0xFAB4CAFE; class syncGroupNotify : public cacNotify, public tsDLNode < syncGroupNotify > { public: syncGroupNotify ( struct CASG &sgIn, void *pValue ); - void destroy (); - void show (unsigned level) const; + void release (); + void show ( unsigned level ) const; - void * operator new (size_t size); - void operator delete (void *pCadaver, size_t size); - -private: - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); - void lock () const; - void unlock () const; + void * operator new ( size_t size ); + void operator delete ( void *pCadaver, size_t size ); +protected: virtual ~syncGroupNotify (); // allocate only from pool - +private: struct CASG &sg; unsigned magic; void *pValue; unsigned long seqNo; - + void completionNotify ( cacChannelIO & ); + void completionNotify ( cacChannelIO &, + unsigned type, unsigned long count, const void *pData ); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext ); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < class syncGroupNotify, 1024 > freeList; - friend class gnuWarningEliminate; }; /* @@ -1022,8 +1010,7 @@ public: void decrementOutstandingIO (); void decrementOutstandingIO ( unsigned seqNumber ); void incrementOutstandingIO (); - void lockOutstandingIO () const; - void unlockOutstandingIO () const; + void incrementOutstandingIO ( unsigned seqNumber ); unsigned readSequenceOfOutstandingIO () const; unsigned currentOutstandingIOCount () const; void cleanUpOutstandingIO (); @@ -1065,9 +1052,6 @@ public: // beacon management void beaconNotify ( const inetAddrID &addr ); - bhe *lookupBeaconInetAddr ( const inetAddrID &ina ); - bhe *createBeaconHashEntry ( const inetAddrID &ina, - const epicsTime &initialTimeStamp ); void repeaterSubscribeConfirmNotify (); // IIU routines @@ -1090,15 +1074,14 @@ public: void connectChannel ( unsigned id ); void connectChannel ( bool v44Ok, unsigned id, unsigned nativeType, unsigned long nativeCount, unsigned sid ); - void channelDestroy ( unsigned id ); void disconnectChannel ( unsigned id ); - bool createChannelIO ( const char *name_str, cacChannel &chan ); + cacChannelIO * createChannelIO ( const char *name_str, cacChannelNotify &chan ); + void installNetworkChannel ( nciu &, netiiu *&piiu ); void lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid, unsigned typeCode, unsigned long count, unsigned minorVersionNumber, const osiSockAddr & ); - void accessRightsNotify ( unsigned id, caar ); - void uninstallLocalChannel ( cacLocalChannelIO & ); - void destroyNCIU ( nciu & ); + void accessRightsNotify ( unsigned id, const caar & ); + void uninstallChannel ( nciu & ); // sync group routines CASG * lookupCASG ( unsigned id ); @@ -1109,9 +1092,8 @@ public: void registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg ); void enableCallbackPreemption (); void disableCallbackPreemption (); - void notifySearchResponse ( unsigned short retrySeqNo ); bool flushPermit () const; - const char * userNamePointer (); + const char * userNamePointer () const; // diagnostics unsigned connectionCount () const; @@ -1121,13 +1103,13 @@ public: void replaceErrLogHandler ( caPrintfFunc *ca_printf_func ); void ipAddrToAsciiAsynchronousRequestInstall ( ipAddrToAsciiAsynchronous & request ); + void getFDRegCallback ( CAFDHANDLER *&fdRegFunc, void *&fdRegArg ) const; + private: ipAddrToAsciiEngine ipToAEngine; cacServiceList services; tsDLList iiuList; tsDLList iiuListLimbo; - tsDLList - localChanList; chronIntIdResTable < nciu > chanTable; chronIntIdResTable @@ -1154,10 +1136,6 @@ private: unsigned initializingThreadsPriority; bool enablePreemptiveCallback; - // IIU routines - tcpiiu * constructTCPIIU ( const osiSockAddr &, unsigned minorVersion ); - double connectionTimeout () const; - int pendPrivate ( double timeout, int early ); bool setupUDP (); }; diff --git a/src/ca/nciu.cpp b/src/ca/nciu.cpp index d53d4931f..edcb92489 100644 --- a/src/ca/nciu.cpp +++ b/src/ca/nciu.cpp @@ -10,13 +10,13 @@ * Author: Jeff Hill * * Notes: - * 1) This class has a pointer to the IIU. Since it is possible - * for the channel to exist when no IIU exists (because the user - * created the channel), and because an IIU can disconnect and be - * destroyed at any time, then it is necessary to hold a mutex while - * the IIU pointer is in use. This mutex can not be the IIU's mutex - * because the IIU's lock must not be held while waiting for a - * message to be sent (otherwise a push pull deadlock can occur). + * 1) This class has a pointer to the IIU. This pointer always points at + * a valid IIU. If the client is deleted then the channel points at a + * static file scope IIU. IIU's that disconnect go into an inactive state + * and are stored on a list for later reuse. When the channel calls a + * member function of the IIU, the IIU verifies that the channel's IIU + * pointer is still pointing at itself only after it has acquired the IIU + * lock. */ #include "iocinf.h" @@ -33,7 +33,7 @@ tsFreeList < class nciu, 1024 > nciu::freeList; static const caar defaultAccessRights = { false, false }; -nciu::nciu ( cac &cacIn, netiiu &iiuIn, cacChannel &chanIn, +nciu::nciu ( cac &cacIn, netiiu &iiuIn, cacChannelNotify &chanIn, const char *pNameIn ) : cacChannelIO ( chanIn ), cacCtx ( cacIn ), @@ -48,7 +48,9 @@ nciu::nciu ( cac &cacIn, netiiu &iiuIn, cacChannel &chanIn, f_connected ( false ), f_fullyConstructed ( true ), f_previousConn ( false ), - f_claimSent ( false ) + f_claimSent ( false ), + f_firstConnectDecrementsOutstandingIO ( false ), + f_connectTimeOutSeen ( false ) { // second constraint is imposed by size field in protocol header if ( this->nameLength > MAX_UDP_SEND - sizeof ( caHdr ) || this->nameLength > 0xffff ) { @@ -67,13 +69,16 @@ void nciu::destroy () { // this occurs here so that it happens when // a lock is not applied - this->piiu->destroyAllIO ( *this ); + unsigned i = 0u; + while ( ! this->piiu->destroyAllIO ( *this ) ) { + if ( i++ > 1000u ) { + this->cacCtx.printf ( + "CAC: unable to destroy IO when channel destroyed?\n" ); + break; + } + } this->piiu->clearChannelRequest ( *this ); - this->cacCtx.destroyNCIU ( *this ); -} - -void nciu::cacDestroy () -{ + this->cacCtx.uninstallChannel ( *this ); delete this; } @@ -83,9 +88,11 @@ nciu::~nciu () return; } - // this must go in the derived class's destructor because - // this calls virtual functions in the cacChannelIO base - this->ioReleaseNotify (); + if ( ! this->f_connectTimeOutSeen && ! this->f_previousConn ) { + if ( this->f_firstConnectDecrementsOutstandingIO ) { + this->cacCtx.decrementOutstandingIO (); + } + } delete [] this->pNameStr; } @@ -217,6 +224,12 @@ int nciu::write ( unsigned type, unsigned long countIn, const void *pValue, cacN return this->piiu->writeNotifyRequest ( *this, notify, type, countIn, pValue ); } +void nciu::initiateConnect () +{ + this->notifyStateChangeFirstConnectInCountOfOutstandingIO (); + this->cacCtx.installNetworkChannel ( *this, this->piiu ); +} + void nciu::connect ( unsigned nativeType, unsigned long nativeCount, unsigned sidIn ) { @@ -235,6 +248,13 @@ void nciu::connect ( unsigned nativeType, } this->lock (); + + if ( ! this->f_connectTimeOutSeen && ! this->f_previousConn ) { + if ( this->f_firstConnectDecrementsOutstandingIO ) { + this->cacCtx.decrementOutstandingIO (); + } + } + bool v41Ok; if ( this->piiu ) { v41Ok = this->piiu->ca_v41_ok (); @@ -263,7 +283,7 @@ void nciu::connect ( unsigned nativeType, // resubscribe for monitors from this channel this->piiu->connectAllIO ( *this ); - this->connectNotify (); + this->notify ().connectNotify ( *this ); /* * if less than v4.1 then the server will never @@ -272,7 +292,16 @@ void nciu::connect ( unsigned nativeType, * their call back here */ if ( ! v41Ok ) { - this->accessRightsNotify ( this->ar ); + this->notify ().accessRightsNotify ( *this, this->ar ); + } +} + +void nciu::connectTimeoutNotify () +{ + if ( ! this->f_connectTimeOutSeen ) { + this->lock (); + this->f_connectTimeOutSeen = true; + this->unlock (); } } @@ -309,8 +338,8 @@ void nciu::disconnect ( netiiu &newiiu ) /* * look for events that have an event cancel in progress */ - this->disconnectNotify (); - this->accessRightsNotify ( this->ar ); + this->notify ().disconnectNotify ( *this ); + this->notify ().accessRightsNotify ( *this, this->ar ); } this->resetRetryCount (); @@ -352,36 +381,6 @@ bool nciu::searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisCh return status; } -void nciu::incrementOutstandingIO () -{ - this->cacCtx.incrementOutstandingIO (); -} - -void nciu::decrementOutstandingIO () -{ - this->cacCtx.decrementOutstandingIO (); -} - -void nciu::decrementOutstandingIO ( unsigned seqNumber ) -{ - this->cacCtx.decrementOutstandingIO ( seqNumber ); -} - -void nciu::lockOutstandingIO () const -{ - this->cacCtx.lockOutstandingIO (); -} - -void nciu::unlockOutstandingIO () const -{ - this->cacCtx.unlockOutstandingIO (); -} - -unsigned nciu::readSequence () const -{ - return this->cacCtx.readSequenceOfOutstandingIO (); -} - void nciu::hostName ( char *pBuf, unsigned bufLength ) const { this->piiu->hostName ( pBuf, bufLength ); @@ -499,7 +498,8 @@ int nciu::createChannelRequest () } int nciu::subscribe ( unsigned type, unsigned long nElem, - unsigned mask, cacNotify ¬ify ) + unsigned mask, cacNotify ¬ify, + cacNotifyIO *&pNotifyIO ) { netSubscription *pSubcr = new netSubscription ( *this, type, nElem, mask, notify ); @@ -508,6 +508,9 @@ int nciu::subscribe ( unsigned type, unsigned long nElem, if ( status != ECA_NORMAL ) { pSubcr->destroy (); } + else { + pNotifyIO = pSubcr; + } return status; } else { @@ -515,6 +518,27 @@ int nciu::subscribe ( unsigned type, unsigned long nElem, } } +void nciu::notifyStateChangeFirstConnectInCountOfOutstandingIO () +{ + this->lock (); + // test is performed via a callback so that locking is correct + if ( ! this->f_connectTimeOutSeen && ! this->f_previousConn ) { + if ( this->notify ().includeFirstConnectInCountOfOutstandingIO () ) { + if ( ! this->f_firstConnectDecrementsOutstandingIO ) { + this->cacCtx.incrementOutstandingIO (); + this->f_firstConnectDecrementsOutstandingIO = true; + } + } + else { + if ( this->f_firstConnectDecrementsOutstandingIO ) { + this->cacCtx.decrementOutstandingIO (); + this->f_firstConnectDecrementsOutstandingIO = false; + } + } + } + this->unlock (); +} + void nciu::show ( unsigned level ) const { if ( this->f_connected ) { diff --git a/src/ca/nciu_IL.h b/src/ca/nciu_IL.h index f2cfba546..c9a2c8ca8 100644 --- a/src/ca/nciu_IL.h +++ b/src/ca/nciu_IL.h @@ -20,6 +20,8 @@ // nciu inline member functions // +#include "ioCounter_IL.h" + inline void * nciu::operator new ( size_t size ) { return nciu::freeList.allocate ( size ); @@ -58,7 +60,7 @@ inline void nciu::resetRetryCount () inline void nciu::accessRightsStateChange ( const caar &arIn ) { this->ar = arIn; - this->accessRightsNotify ( this->ar ); + this->notify ().accessRightsNotify ( *this, this->ar ); } inline ca_uint32_t nciu::getSID () const @@ -127,3 +129,19 @@ inline netiiu * nciu::getPIIU () return this->piiu; } +inline cac & nciu::getCAC () +{ + return this->cacCtx; +} + + +inline void nciu::incrementOutstandingIO ( unsigned seqNumber ) +{ + this->cacCtx.incrementOutstandingIO ( seqNumber ); +} + +inline void nciu::decrementOutstandingIO ( unsigned seqNumber ) +{ + this->cacCtx.decrementOutstandingIO ( seqNumber ); +} + diff --git a/src/ca/netReadCopyIO.cpp b/src/ca/netReadCopyIO.cpp index 45c5f0f94..3232f8fb8 100644 --- a/src/ca/netReadCopyIO.cpp +++ b/src/ca/netReadCopyIO.cpp @@ -13,6 +13,7 @@ #include "iocinf.h" #include "netReadCopyIO_IL.h" #include "nciu_IL.h" +#include "baseNMIU_IL.h" tsFreeList < class netReadCopyIO, 1024 > netReadCopyIO::freeList; @@ -21,17 +22,11 @@ netReadCopyIO::netReadCopyIO ( nciu &chanIn, unsigned typeIn, unsigned long coun baseNMIU ( chanIn ), type ( typeIn ), count ( countIn ), pValue ( pValueIn ), seqNumber ( seqNumberIn ) { - chanIn.incrementOutstandingIO (); + this->chan.incrementOutstandingIO ( seqNumberIn ); } netReadCopyIO::~netReadCopyIO () { - -} - -void netReadCopyIO::uninstall () -{ - this->chan.getPIIU ()->uninstallIO ( *this ); } void netReadCopyIO::completionNotify () @@ -59,14 +54,22 @@ void netReadCopyIO::completionNotify ( unsigned typeIn, void netReadCopyIO::exceptionNotify ( int status, const char *pContext ) { - ca_signal (status, pContext); + ca_signal_formated ( status, __FILE__, __LINE__, + "%s chan=%s\n", pContext, this->channelIO ().pName () ); + } void netReadCopyIO::exceptionNotify ( int status, const char *pContextIn, unsigned typeIn, unsigned long countIn ) { - ca_signal_formated (status, __FILE__, __LINE__, - "%s type=%d count=%ld\n", pContextIn, typeIn, countIn); + ca_signal_formated ( status, __FILE__, __LINE__, + "%s chan=%s type=%d count=%ld\n", pContextIn, + this->channelIO ().pName (), typeIn, countIn); +} + +cacChannelIO & netReadCopyIO::channelIO () const +{ + return this->channel (); } void netReadCopyIO::show ( unsigned level ) const diff --git a/src/ca/netReadNotifyIO.cpp b/src/ca/netReadNotifyIO.cpp index 01424bf1b..bc75addae 100644 --- a/src/ca/netReadNotifyIO.cpp +++ b/src/ca/netReadNotifyIO.cpp @@ -13,40 +13,47 @@ #include "iocinf.h" #include "netReadNotifyIO_IL.h" #include "nciu_IL.h" +#include "baseNMIU_IL.h" tsFreeList < class netReadNotifyIO, 1024 > netReadNotifyIO::freeList; netReadNotifyIO::netReadNotifyIO ( nciu &chan, cacNotify ¬ifyIn ) : cacNotifyIO ( notifyIn ), baseNMIU ( chan ) {} -// private NOOP forces pool allocation -netReadNotifyIO::~netReadNotifyIO () {} - -void netReadNotifyIO::uninstall () +netReadNotifyIO::~netReadNotifyIO () { - this->chan.getPIIU ()->uninstallIO ( *this ); +} + +void netReadNotifyIO::destroy () +{ + delete this; } void netReadNotifyIO::completionNotify () { - this->cacNotifyIO::exceptionNotify ( ECA_INTERNAL, "no data returned ?" ); + this->notify ().exceptionNotify ( this->channelIO (), ECA_INTERNAL, "no data returned ?" ); } void netReadNotifyIO::completionNotify ( unsigned type, unsigned long count, const void *pData ) { - this->cacNotifyIO::completionNotify ( type, count, pData ); + this->notify ().completionNotify ( this->channelIO (), type, count, pData ); } void netReadNotifyIO::exceptionNotify ( int status, const char *pContext ) { - this->cacNotifyIO::exceptionNotify ( status, pContext ); + this->notify ().exceptionNotify ( this->channelIO (), status, pContext ); } void netReadNotifyIO::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ) { - this->cacNotifyIO::exceptionNotify ( status, pContext, type ,count ); + this->notify ().exceptionNotify ( this->channelIO (), status, pContext, type ,count ); +} + +cacChannelIO & netReadNotifyIO::channelIO () const +{ + return this->channel (); } void netReadNotifyIO::show ( unsigned level ) const diff --git a/src/ca/netSubscription.cpp b/src/ca/netSubscription.cpp index 734459db1..b26858c71 100644 --- a/src/ca/netSubscription.cpp +++ b/src/ca/netSubscription.cpp @@ -13,6 +13,7 @@ #include "iocinf.h" #include "netSubscription_IL.h" #include "nciu_IL.h" +#include "baseNMIU_IL.h" tsFreeList < class netSubscription, 1024 > netSubscription::freeList; @@ -25,14 +26,21 @@ netSubscription::netSubscription ( nciu &chan, unsigned typeIn, unsigned long co netSubscription::~netSubscription () { - // o netiiu lock must _not_ be applied when calling this - // o uninstall from channel and IIU occur in uninstall method + // netiiu lock must _not_ be applied when calling this this->chan.getPIIU ()->subscriptionCancelRequest ( *this, true ); } -void netSubscription::uninstall () +void netSubscription::destroy () { - this->chan.getPIIU ()->uninstallIO ( *this ); + unsigned i = 0u; + while ( ! this->chan.getPIIU ()->uninstallIO ( *this ) ) { + if ( i++ > 1000u ) { + this->chan.getCAC ().printf ( + "CAC: unable to destroy IO\n" ); + break; + } + } + delete this; } class netSubscription * netSubscription::isSubscription () @@ -42,27 +50,32 @@ class netSubscription * netSubscription::isSubscription () void netSubscription::completionNotify () { - this->cacNotifyIO::completionNotify (); + this->notify ().completionNotify ( this->channel () ); } void netSubscription::completionNotify ( unsigned typeIn, unsigned long countIn, const void *pDataIn ) { - this->cacNotifyIO::completionNotify ( typeIn, countIn, pDataIn ); + this->notify ().completionNotify ( this->channel (), typeIn, countIn, pDataIn ); } void netSubscription::exceptionNotify ( int status, const char *pContext ) { - this->cacNotifyIO::exceptionNotify ( status, pContext ); + this->notify ().exceptionNotify ( this->channel (), status, pContext ); } void netSubscription::exceptionNotify ( int statusIn, const char *pContextIn, unsigned typeIn, unsigned long countIn ) { - this->cacNotifyIO::exceptionNotify ( statusIn, + this->notify ().exceptionNotify ( this->channel (), statusIn, pContextIn, typeIn, countIn ); } +cacChannelIO & netSubscription::channelIO () const +{ + return this->channel (); +} + void netSubscription::show ( unsigned level ) const { printf ( "event subscription IO at %p, type %s, element count %lu, mask %u\n", diff --git a/src/ca/netWriteNotifyIO.cpp b/src/ca/netWriteNotifyIO.cpp index e82de6710..d84f141f0 100644 --- a/src/ca/netWriteNotifyIO.cpp +++ b/src/ca/netWriteNotifyIO.cpp @@ -13,44 +13,51 @@ #include "iocinf.h" #include "netWriteNotifyIO_IL.h" #include "nciu_IL.h" +#include "baseNMIU_IL.h" tsFreeList < class netWriteNotifyIO, 1024 > netWriteNotifyIO::freeList; -netWriteNotifyIO::netWriteNotifyIO (nciu &chan, cacNotify ¬ifyIn) : - cacNotifyIO (notifyIn), baseNMIU (chan) +netWriteNotifyIO::netWriteNotifyIO ( nciu &chan, cacNotify ¬ifyIn ) : + cacNotifyIO ( notifyIn ), baseNMIU ( chan ) { } netWriteNotifyIO::~netWriteNotifyIO () { - // private NOOP forces pool allocation } -void netWriteNotifyIO::uninstall () +void netWriteNotifyIO::destroy () { - this->chan.getPIIU ()->uninstallIO ( *this ); + delete this; } void netWriteNotifyIO::completionNotify () { - this->cacNotifyIO::completionNotify (); + this->notify ().completionNotify ( this->channelIO () ); } void netWriteNotifyIO::completionNotify ( unsigned /* type */, unsigned long /* count */, const void * /* pData */ ) { - this->cacNotifyIO::completionNotify (); + this->notify ().completionNotify ( this->channelIO () ); } -void netWriteNotifyIO::exceptionNotify ( int status, const char *pContext ) +void netWriteNotifyIO::exceptionNotify ( int status, + const char *pContext ) { - this->cacNotifyIO::exceptionNotify (status, pContext); + this->notify ().exceptionNotify ( this->channelIO (), status, pContext ); } -void netWriteNotifyIO::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ) +void netWriteNotifyIO::exceptionNotify ( int status, + const char *pContext, unsigned type, unsigned long count ) { - this->cacNotifyIO::exceptionNotify (status, pContext, type, count); + this->notify ().exceptionNotify ( this->channelIO (), status, pContext, type, count ); +} + +cacChannelIO & netWriteNotifyIO::channelIO () const +{ + return this->channel (); } void netWriteNotifyIO::show ( unsigned level ) const diff --git a/src/ca/netiiu.cpp b/src/ca/netiiu.cpp index 9c64a6ca0..a4ed40561 100644 --- a/src/ca/netiiu.cpp +++ b/src/ca/netiiu.cpp @@ -24,7 +24,6 @@ netiiu::netiiu ( cac *pClientCtxIn ) : pClientCtx ( pClientCtxIn ) netiiu::~netiiu () { - assert ( this->channelList.count () == 0u ); } void netiiu::show ( unsigned level ) const @@ -99,23 +98,26 @@ void netiiu::disconnectAllChan ( netiiu & newiiu ) // // netiiu::destroyAllIO () // -// care is taken not to not hold the lock while sending event -// subscription delete ( when the IO is deleted ) +// care is taken to not hold the lock while deleting the +// IO so that subscription delete request (sent by the +// IO's destructor) do not deadlock // -void netiiu::destroyAllIO ( nciu &chan ) +bool netiiu::destroyAllIO ( nciu &chan ) { - baseNMIU *pIO; - while ( true ) { - { - epicsAutoMutex autoMutex ( this->mutex ); - pIO = chan.tcpiiuPrivateListOfIO::eventq.first (); - if ( ! pIO ) { - break; - } - pIO->uninstall (); + tsDLList < baseNMIU > eventQ; + { + epicsAutoMutex autoMutex ( this->mutex ); + if ( chan.verifyIIU ( *this ) ) { + eventQ.add ( chan.tcpiiuPrivateListOfIO::eventq ); } + else { + return false; + } + } + while ( baseNMIU *pIO = eventQ.get () ) { pIO->destroy (); } + return true; } void netiiu::connectTimeoutNotify () @@ -260,13 +262,17 @@ void netiiu::connectAllIO ( nciu & ) { } -void netiiu::uninstallIO ( baseNMIU &io ) +bool netiiu::uninstallIO ( baseNMIU &io ) { epicsAutoMutex autoMutex ( this->mutex ); + if ( ! io.channel ().verifyIIU ( *this ) ) { + return false; + } io.channel ().tcpiiuPrivateListOfIO::eventq.remove ( io ); + return true; } double netiiu::beaconPeriod () const { - return - DBL_MAX; + return ( - DBL_MAX ); } diff --git a/src/ca/oldAccess.h b/src/ca/oldAccess.h index e07d9e913..afdad5635 100644 --- a/src/ca/oldAccess.h +++ b/src/ca/oldAccess.h @@ -15,105 +15,133 @@ * 505 665 1831 */ -extern "C" void cacNoConnHandler ( struct connection_handler_args args ); - -class gnuOldAccessWarningEliminate { -}; - -struct oldChannel : public cacChannel { +class oldChannelNotify : public cacChannelNotify { public: - oldChannel (caCh *pConnCallBack, void *pPrivate); - void destroy (); - void setPrivatePointer (void *); + oldChannelNotify ( caCh *pConnCallBackIn, void *pPrivateIn ); + void release (); + void setPrivatePointer ( void * ); void * privatePointer () const; - int changeConnCallBack (caCh *pfunc); - int replaceAccessRightsEvent (caArh *pfunc); - void ioAttachNotify (); - void ioReleaseNotify (); - - void * operator new (size_t size); - void operator delete (void *pCadaver, size_t size); + int changeConnCallBack ( cacChannelIO &, caCh *pfunc ); + int replaceAccessRightsEvent ( cacChannelIO &chan, caArh *pfunc ); + void * operator new ( size_t size ); + void operator delete ( void *pCadaver, size_t size ); +protected: + ~oldChannelNotify (); // must allocate from pool private: caCh *pConnCallBack; void *pPrivate; caArh *pAccessRightsFunc; - - ~oldChannel (); // must allocate from pool - void connectTimeoutNotify (); - void connectNotify (); - void disconnectNotify (); - void accessRightsNotify ( caar ); - static tsFreeList < struct oldChannel, 1024 > freeList; - - friend int epicsShareAPI ca_array_get (chtype type, unsigned long count, chid pChan, void *pValue); - friend void cacNoConnHandler ( struct connection_handler_args args ); + void connectNotify ( cacChannelIO &chan ); + void disconnectNotify ( cacChannelIO &chan ); + void accessRightsNotify ( cacChannelIO &chan, const caar & ); + bool includeFirstConnectInCountOfOutstandingIO () const; + class oldChannelNotify * pOldChannelNotify (); + static tsFreeList < class oldChannelNotify, 1024 > freeList; }; class getCallback : public cacNotify { public: - getCallback (oldChannel &chan, caEventCallBackFunc *pFunc, void *pPrivate); - void destroy (); - + getCallback ( caEventCallBackFunc *pFunc, void *pPrivate ); + void release (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); - +protected: + ~getCallback (); // allocate only out of pool private: - oldChannel &chan; caEventCallBackFunc *pFunc; void *pPrivate; - ~getCallback (); // allocate only out of pool - void completionNotify (); - void completionNotify (unsigned type, unsigned long count, const void *pData); - void exceptionNotify (int status, const char *pContext); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); + void completionNotify ( cacChannelIO &, + unsigned type, unsigned long count, const void *pData); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < class getCallback, 1024 > freeList; - friend class gnuWarningEliminate; }; class putCallback : public cacNotify { public: - putCallback (oldChannel &chan, caEventCallBackFunc *pFunc, void *pPrivate ); - void destroy (); - + putCallback ( caEventCallBackFunc *pFunc, void *pPrivate ); + void release (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); - +protected: + ~putCallback (); // allocate only out of pool private: - oldChannel &chan; caEventCallBackFunc *pFunc; void *pPrivate; - ~putCallback (); // allocate only out of pool - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); + void completionNotify ( cacChannelIO & ); + void completionNotify ( cacChannelIO &, + unsigned type, unsigned long count, const void *pData ); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext ); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < class putCallback, 1024 > freeList; - friend class gnuWarningEliminate; }; struct oldSubscription : public cacNotify { public: - oldSubscription ( oldChannel &chan, caEventCallBackFunc *pFunc, void *pPrivate ); - void destroy (); - oldChannel &channel (); - + oldSubscription ( caEventCallBackFunc *pFunc, void *pPrivate ); + void release (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); - +protected: + ~oldSubscription (); // must allocate from pool private: - oldChannel &chan; - caEventCallBackFunc *pFunc; void *pPrivate; - - void completionNotify (); - void completionNotify ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( int status, const char *pContext ); - void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ); - - ~oldSubscription (); // must allocate from pool + void completionNotify ( cacChannelIO &, + unsigned type, unsigned long count, const void *pData ); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext ); + void exceptionNotify ( cacChannelIO &, + int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < struct oldSubscription, 1024 > freeList; - friend class gnuWarningEliminate; }; +inline getCallback::getCallback ( caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : + pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +{ +} + +inline void * getCallback::operator new ( size_t size ) +{ + return getCallback::freeList.allocate ( size ); +} + +inline void getCallback::operator delete ( void *pCadaver, size_t size ) +{ + getCallback::freeList.release ( pCadaver, size ); +} + +inline putCallback::putCallback ( caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : + pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +{ +} + +inline void * putCallback::operator new ( size_t size ) +{ + return putCallback::freeList.allocate ( size ); +} + +inline void putCallback::operator delete ( void *pCadaver, size_t size ) +{ + putCallback::freeList.release ( pCadaver, size ); +} + +inline oldSubscription::oldSubscription ( caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : + pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +{ +} + +inline void * oldSubscription::operator new ( size_t size ) +{ + return oldSubscription::freeList.allocate ( size ); +} + +inline void oldSubscription::operator delete ( void *pCadaver, size_t size ) +{ + oldSubscription::freeList.release ( pCadaver, size ); +} diff --git a/src/ca/oldChannel.cpp b/src/ca/oldChannel.cpp index f7835e8bc..32de039d0 100644 --- a/src/ca/oldChannel.cpp +++ b/src/ca/oldChannel.cpp @@ -1,196 +1,2 @@ -/* - * $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 "iocinf.h" -#include "oldAccess.h" - -tsFreeList < struct oldChannel, 1024 > oldChannel::freeList; - -/* - * cacAlreadyConnHandler () - * This is installed into channels which dont have - * a connection handler when ca_pend_io() times - * out so that we will not decrement the pending - * recv count in the future. - */ -extern "C" void cacAlreadyConnHandler ( struct connection_handler_args ) -{ -} - -/* - * cacNoConnHandler () - * This is installed into channels which dont have - * a connection handler before ca_pend_io() times - * out so that we will properly decrement the pending - * recv count in the future. - */ -extern "C" void cacNoConnHandler ( struct connection_handler_args args ) -{ - args.chid->lockOutstandingIO (); - if ( args.chid->pConnCallBack == cacNoConnHandler ) { - args.chid->pConnCallBack = cacAlreadyConnHandler; - if ( args.op == CA_OP_CONN_UP ) { - args.chid->decrementOutstandingIO (); - } - } - args.chid->unlockOutstandingIO (); -} - -extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args ) -{ -} - -oldChannel::oldChannel (caCh *pConnCallBackIn, void *pPrivateIn) : - pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler ) -{ - if ( ! pConnCallBackIn ) { - this->pConnCallBack = cacNoConnHandler; - } - else { - this->pConnCallBack = pConnCallBackIn; - } -} - -oldChannel::~oldChannel () -{ - if ( this->pConnCallBack == cacNoConnHandler ) { - this->decrementOutstandingIO (); - } -} - -void oldChannel::destroy () -{ - delete this; -} - -void oldChannel::ioAttachNotify () -{ - this->lockOutstandingIO (); - if ( this->pConnCallBack == cacNoConnHandler ) { - this->incrementOutstandingIO (); - } - this->unlockOutstandingIO (); -} - -void oldChannel::ioReleaseNotify () -{ - this->lockOutstandingIO (); - if ( this->pConnCallBack == cacNoConnHandler ) { - this->decrementOutstandingIO (); - } - this->unlockOutstandingIO (); -} - -void oldChannel::setPrivatePointer ( void *pPrivateIn ) -{ - this->pPrivate = pPrivateIn; -} - -void * oldChannel::privatePointer () const -{ - return this->pPrivate; -} - -void oldChannel::connectTimeoutNotify () -{ - this->lockOutstandingIO (); - if ( this->pConnCallBack == cacNoConnHandler ) { - this->pConnCallBack = cacAlreadyConnHandler; - } - this->unlockOutstandingIO (); -} - -void oldChannel::connectNotify () -{ - this->lockOutstandingIO (); - struct connection_handler_args args; - args.chid = this; - args.op = CA_OP_CONN_UP; - (*this->pConnCallBack) (args); - this->unlockOutstandingIO (); -} - -void oldChannel::disconnectNotify () -{ - this->lockOutstandingIO (); - struct connection_handler_args args; - args.chid = this; - args.op = CA_OP_CONN_DOWN; - (*this->pConnCallBack) ( args ); - this->unlockOutstandingIO (); -} - -int oldChannel::changeConnCallBack ( caCh *pfunc ) -{ - this->lockOutstandingIO (); - if ( ! pfunc ) { - if ( this->pConnCallBack != cacNoConnHandler && - this->pConnCallBack != cacAlreadyConnHandler ) { - if ( this->state () == cs_never_conn ) { - this->incrementOutstandingIO (); - this->pConnCallBack = cacNoConnHandler; - } - else { - this->pConnCallBack = cacAlreadyConnHandler; - } - } - } - else { - if ( this->pConnCallBack == cacNoConnHandler ) { - this->decrementOutstandingIO (); - } - this->pConnCallBack = pfunc; - } - this->unlockOutstandingIO (); - - return ECA_NORMAL; -} - -void oldChannel::accessRightsNotify ( caar ar ) -{ - struct access_rights_handler_args args; - args.chid = this; - args.ar = ar; - ( *this->pAccessRightsFunc ) ( args ); -} - -int oldChannel::replaceAccessRightsEvent ( caArh *pfunc ) -{ - if ( ! pfunc ) { - pfunc = cacNoopAccesRightsHandler; - } - - this->pAccessRightsFunc = pfunc; - if ( this->connected () ) { - struct access_rights_handler_args args; - args.chid = this; - args.ar = this->accessRights (); - (*pfunc) (args); - } - - return ECA_NORMAL; -} - -void * oldChannel::operator new ( size_t size ) -{ - return oldChannel::freeList.allocate ( size ); -} - -void oldChannel::operator delete ( void *pCadaver, size_t size ) -{ - oldChannel::freeList.release ( pCadaver, size ); -} +#error defunct \ No newline at end of file diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp new file mode 100644 index 000000000..4bd5c39b6 --- /dev/null +++ b/src/ca/oldChannelNotify.cpp @@ -0,0 +1,124 @@ + +/* + * $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 "iocinf.h" +#include "oldAccess.h" + +tsFreeList < class oldChannelNotify, 1024 > oldChannelNotify::freeList; + +extern "C" void cacNoopConnHandler ( struct connection_handler_args ) +{ +} + +extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args ) +{ +} + +oldChannelNotify::oldChannelNotify ( caCh *pConnCallBackIn, void *pPrivateIn ) : +pConnCallBack ( pConnCallBackIn ? pConnCallBackIn : cacNoopConnHandler ), + pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler ) +{ +} + +oldChannelNotify::~oldChannelNotify () +{ +} + +void oldChannelNotify::release () +{ + delete this; +} + +void oldChannelNotify::setPrivatePointer ( void *pPrivateIn ) +{ + this->pPrivate = pPrivateIn; +} + +void * oldChannelNotify::privatePointer () const +{ + return this->pPrivate; +} + +int oldChannelNotify::changeConnCallBack ( cacChannelIO &chan, caCh *pfunc ) +{ + this->pConnCallBack = pfunc ? pfunc : cacNoopConnHandler; + // test for NOOP connection handler does _not_ occur here because the + // lock is not applied + chan.notifyStateChangeFirstConnectInCountOfOutstandingIO (); + return ECA_NORMAL; +} + +int oldChannelNotify::replaceAccessRightsEvent ( cacChannelIO &chan, 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 ( chan.connected () ) { + struct access_rights_handler_args args; + args.chid = &chan; + args.ar = chan.accessRights (); + ( *pfunc ) ( args ); + } + return ECA_NORMAL; +} + +void oldChannelNotify::connectNotify ( cacChannelIO &chan ) +{ + struct connection_handler_args args; + args.chid = &chan; + args.op = CA_OP_CONN_UP; + ( *this->pConnCallBack ) ( args ); +} + +void oldChannelNotify::disconnectNotify ( cacChannelIO &chan ) +{ + struct connection_handler_args args; + args.chid = &chan; + args.op = CA_OP_CONN_DOWN; + ( *this->pConnCallBack ) ( args ); +} + +void oldChannelNotify::accessRightsNotify ( cacChannelIO &chan, const caar &ar ) +{ + struct access_rights_handler_args args; + args.chid = &chan; + args.ar = ar; + ( *this->pAccessRightsFunc ) ( args ); +} + +bool oldChannelNotify::includeFirstConnectInCountOfOutstandingIO () const +{ + return ( this->pConnCallBack == cacNoopConnHandler ); +} + +class oldChannelNotify * oldChannelNotify::pOldChannelNotify () +{ + return this; +} + +void * oldChannelNotify::operator new ( size_t size ) +{ + return oldChannelNotify::freeList.allocate ( size ); +} + +void oldChannelNotify::operator delete ( void *pCadaver, size_t size ) +{ + oldChannelNotify::freeList.release ( pCadaver, size ); +} diff --git a/src/ca/oldSubscription.cpp b/src/ca/oldSubscription.cpp index 80aa97ec4..ce7455598 100644 --- a/src/ca/oldSubscription.cpp +++ b/src/ca/oldSubscription.cpp @@ -15,31 +15,17 @@ tsFreeList < struct oldSubscription, 1024 > oldSubscription::freeList; -oldSubscription::oldSubscription ( oldChannel &chanIn, caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : - chan (chanIn), pFunc (pFuncIn), pPrivate (pPrivateIn) -{ -} - oldSubscription::~oldSubscription () { } -oldChannel &oldSubscription::channel () -{ - return this->chan; -} - -void oldSubscription::completionNotify () -{ - cacNotify::completionNotify (); -} - -void oldSubscription::completionNotify (unsigned type, unsigned long count, const void *pData) +void oldSubscription::completionNotify ( cacChannelIO &io, + unsigned type, unsigned long count, const void *pData) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = &this->chan; + args.chid = & io; args.type = type; args.count = count; args.status = ECA_NORMAL; @@ -47,37 +33,38 @@ void oldSubscription::completionNotify (unsigned type, unsigned long count, cons ( *this->pFunc ) (args); } -void oldSubscription::exceptionNotify ( int status, const char * /* pContext */ ) +void oldSubscription::exceptionNotify ( cacChannelIO &io, + int status, const char * /* pContext */ ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = &this->chan; - args.type = 0; + args.chid = & io; + args.type = TYPENOTCONN; args.count = 0; args.status = status; args.dbr = 0; ( *this->pFunc ) (args); } -void oldSubscription::exceptionNotify ( int status, const char *pContext, - unsigned type, unsigned long count ) +void oldSubscription::exceptionNotify ( cacChannelIO &io, + int status, const char *pContext, + unsigned type, unsigned long count ) { - cacNotify::exceptionNotify ( status, pContext, type, count ); + struct event_handler_args args; + + args.usr = this->pPrivate; + args.chid = & io; + args.type = type; + args.count = count; + args.status = status; + args.dbr = 0; + ( *this->pFunc ) (args); } -void oldSubscription::destroy () +void oldSubscription::release () { delete this; } -void * oldSubscription::operator new ( size_t size ) -{ - return oldSubscription::freeList.allocate ( size ); -} - -void oldSubscription::operator delete ( void *pCadaver, size_t size ) -{ - oldSubscription::freeList.release ( pCadaver, size ); -} diff --git a/src/ca/putCallback.cpp b/src/ca/putCallback.cpp index 16ef20d3f..c6e01c5a2 100644 --- a/src/ca/putCallback.cpp +++ b/src/ca/putCallback.cpp @@ -20,64 +20,68 @@ tsFreeList < class putCallback, 1024 > putCallback::freeList; -putCallback::putCallback (oldChannel &chanIn, caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : - chan (chanIn), pFunc (pFuncIn), pPrivate (pPrivateIn) -{ -} - putCallback::~putCallback () { } -void putCallback::destroy () +void putCallback::release () { delete this; } -void putCallback::completionNotify () +void putCallback::completionNotify ( cacChannelIO &io ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = &this->chan; - args.type = 0; - args.count = 0; + args.chid = & io; + args.type = TYPENOTCONN; + args.count = 0; args.status = ECA_NORMAL; args.dbr = 0; (*this->pFunc) (args); } -void putCallback::completionNotify ( unsigned type, - unsigned long count, const void *pData ) -{ - cacNotify::completionNotify ( type, count, pData ); -} - -void putCallback::exceptionNotify (int status, const char * /* pContext */ ) +void putCallback::completionNotify ( cacChannelIO &io, unsigned type, + unsigned long count, const void *pData ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = &this->chan; - args.type = 0; + args.chid = & io; + args.type = type; + args.count = count; + args.status = ECA_NORMAL; + args.dbr = 0; + (*this->pFunc) (args); +} + +void putCallback::exceptionNotify ( cacChannelIO &io, + int status, const char * /* pContext */ ) +{ + struct event_handler_args args; + + args.usr = this->pPrivate; + args.chid = & io; + args.type = TYPENOTCONN; args.count = 0; args.status = status; args.dbr = 0; (*this->pFunc) (args); } -void putCallback::exceptionNotify ( int status, +void putCallback::exceptionNotify ( cacChannelIO &io, int status, const char *pContext, unsigned type, unsigned long count ) { - cacNotify::exceptionNotify ( status, pContext, type, count ); + struct event_handler_args args; + + args.usr = this->pPrivate; + args.chid = & io; + args.type = type; + args.count = count; + args.status = status; + args.dbr = 0; + (*this->pFunc) (args); } -void * putCallback::operator new ( size_t size ) -{ - return putCallback::freeList.allocate ( size ); -} -void putCallback::operator delete ( void *pCadaver, size_t size ) -{ - putCallback::freeList.release ( pCadaver, size ); -} diff --git a/src/ca/syncGroupNotify.cpp b/src/ca/syncGroupNotify.cpp index 1edfaac3b..b4fffea97 100644 --- a/src/ca/syncGroupNotify.cpp +++ b/src/ca/syncGroupNotify.cpp @@ -41,7 +41,7 @@ syncGroupNotify::syncGroupNotify ( CASG &sgIn, void *pValueIn ) : this->sg.mutex.unlock (); } -void syncGroupNotify::destroy () +void syncGroupNotify::release () { delete this; } @@ -53,8 +53,10 @@ syncGroupNotify::~syncGroupNotify () this->sg.mutex.unlock (); } -void syncGroupNotify::completionNotify () +void syncGroupNotify::completionNotify ( cacChannelIO & ) { + bool done; + if ( this->magic != CASG_MAGIC ) { ca_printf ("cac: sync group io_complete(): bad sync grp op magic number?\n"); return; @@ -64,21 +66,28 @@ void syncGroupNotify::completionNotify () if ( this->seqNo == this->sg.seqNo ) { assert ( this->sg.opPendCount > 0u ); this->sg.opPendCount--; + done = this->sg.opPendCount == 0; + } + else { + done = true; } this->sg.mutex.unlock (); - if ( this->sg.opPendCount == 0 ) { + if ( done ) { this->sg.sem.signal (); } } -void syncGroupNotify::completionNotify ( unsigned type, unsigned long count, const void *pData ) +void syncGroupNotify::completionNotify ( cacChannelIO &, + unsigned type, unsigned long count, const void *pData ) { if ( this->magic != CASG_MAGIC ) { ca_printf ("cac: sync group io_complete(): bad sync grp op magic number?\n"); return; } + bool complete; + this->sg.mutex.lock (); if ( this->seqNo == this->sg.seqNo ) { /* @@ -86,14 +95,18 @@ void syncGroupNotify::completionNotify ( unsigned type, unsigned long count, con */ if ( this->pValue ) { size_t size = dbr_size_n ( type, count ); - memcpy (this->pValue, pData, size); + memcpy ( this->pValue, pData, size ); } assert ( this->sg.opPendCount > 0u ); this->sg.opPendCount--; + complete = this->sg.opPendCount == 0; + } + else { + complete = true; } this->sg.mutex.unlock (); - if ( this->sg.opPendCount == 0 ) { + if ( complete ) { this->sg.sem.signal (); } } @@ -104,27 +117,20 @@ void syncGroupNotify::show ( unsigned /* level */ ) const this->pValue, this->magic, this->seqNo, &this->sg); } -void syncGroupNotify::exceptionNotify ( int status, const char *pContext ) +void syncGroupNotify::exceptionNotify ( cacChannelIO &io, + int status, const char *pContext ) { ca_signal_formated ( status, __FILE__, __LINE__, - "CA Sync Group request failed because \"%s\"\n", pContext); + "CA Sync Group request to channel %s failed because \"%s\"\n", + io.pName (), pContext); } -void syncGroupNotify::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count ) +void syncGroupNotify::exceptionNotify ( cacChannelIO &io, + int status, const char *pContext, unsigned type, unsigned long count ) { ca_signal_formated ( status, __FILE__, __LINE__, - "CA Sync Group request failed with type=%d count=%ld because \"%s\"\n", - type, count, pContext); -} - -void syncGroupNotify::lock () const -{ - this->sg.mutex.lock (); -} - -void syncGroupNotify::unlock () const -{ - this->sg.mutex.unlock (); + "CA Sync Group request failed with channel=%s type=%d count=%ld because \"%s\"\n", + io.pName (), type, count, pContext); } void * syncGroupNotify::operator new (size_t size) diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp index 11f1fde11..e3432c983 100644 --- a/src/ca/tcpiiu.cpp +++ b/src/ca/tcpiiu.cpp @@ -508,6 +508,14 @@ bool tcpiiu::initiateConnect ( const osiSockAddr &addrIn, unsigned minorVersion, socket_close ( this->sock ); return false; } + + CAFDHANDLER *fdRegFunc; + void *fdRegArg; + this->pCAC ()->getFDRegCallback ( fdRegFunc, fdRegArg ); + if ( fdRegFunc ) { + ( *fdRegFunc ) ( fdRegArg, this->sock, TRUE ); + } + return true; } @@ -594,7 +602,6 @@ void tcpiiu::cleanShutdown () else { this->state = iiu_disconnected; } - } else if ( this->state == iiu_connecting ) { int status = socket_close ( this->sock ); @@ -662,6 +669,13 @@ void tcpiiu::disconnect () this->ioTable.numEntriesInstalled () ); } + CAFDHANDLER *fdRegFunc; + void *fdRegArg; + this->pCAC ()->getFDRegCallback ( fdRegFunc, fdRegArg ); + if ( fdRegFunc ) { + ( *fdRegFunc ) ( fdRegArg, this->sock, FALSE ); + } + this->cleanShutdown (); // wait for send thread to exit @@ -1157,7 +1171,7 @@ void tcpiiu::readRespAction () void tcpiiu::clearChannelRespAction () { - this->pCAC ()->channelDestroy ( this->curMsg.m_available ); + // currently a noop } void tcpiiu::exceptionRespAction () @@ -1421,7 +1435,7 @@ int tcpiiu::writeRequest ( nciu &chan, unsigned type, unsigned nElem, const void } if ( this->sendQue.flushThreshold ( postcnt + 16u ) ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } epicsAutoMutex autoMutex ( this->mutex ); @@ -1484,7 +1498,7 @@ int tcpiiu::writeNotifyRequest ( nciu &chan, cacNotify ¬ify, unsigned type, } if ( this->sendQue.flushThreshold ( postcnt + 16u ) ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } epicsAutoMutex autoMutex ( this->mutex ); @@ -1532,7 +1546,7 @@ int tcpiiu::readCopyRequest ( nciu &chan, unsigned type, unsigned nElem, void *p } if ( this->sendQue.flushThreshold ( 16u ) ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } epicsAutoMutex autoMutex ( this->mutex ); @@ -1543,8 +1557,9 @@ int tcpiiu::readCopyRequest ( nciu &chan, unsigned type, unsigned nElem, void *p status = ECA_DISCONNCHID; } else { - netReadCopyIO *pIO = new netReadCopyIO ( chan, type, nElem, pValue, - this->pCAC ()->readSequenceOfOutstandingIO () ); + unsigned seqNo = this->pCAC ()->readSequenceOfOutstandingIO (); + netReadCopyIO *pIO = new netReadCopyIO ( chan, type, + nElem, pValue, seqNo ); if ( ! pIO ) { status = ECA_ALLOCMEM; } @@ -1575,7 +1590,7 @@ int tcpiiu::readNotifyRequest ( nciu &chan, cacNotify ¬ify, } if ( this->sendQue.flushThreshold ( 16u ) ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } epicsAutoMutex autoMutex ( this->mutex ); @@ -1668,7 +1683,7 @@ int tcpiiu::clearChannelRequest ( nciu &chan ) int status; if ( this->sendQue.flushThreshold ( 16u ) ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } epicsAutoMutex autoMutex ( this->mutex ); @@ -1707,7 +1722,7 @@ int tcpiiu::subscriptionRequest ( netSubscription &subscr, bool userThread ) if ( this->sendQue.flushThreshold ( 32u ) ) { if ( userThread ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } else { this->flush (); @@ -1748,7 +1763,7 @@ void tcpiiu::subscriptionCancelRequest ( netSubscription &subscr, bool userThrea { if ( this->sendQue.flushThreshold ( 16u ) ) { if ( userThread ) { - this->flushToWire ( true ); + this->threadContextSensitiveFlushToWire ( true ); } else { this->flush (); @@ -1775,10 +1790,8 @@ void tcpiiu::lastChannelDetachNotify () this->cleanShutdown (); } -bool tcpiiu::flushToWire ( bool userThread ) +bool tcpiiu::threadContextSensitiveFlushToWire ( bool userThread ) { - bool success = true; - // the recv thread is not permitted to flush as this // can result in a push / pull deadlock on the TCP pipe, // but in that case we still schedual the flush through @@ -1787,6 +1800,12 @@ bool tcpiiu::flushToWire ( bool userThread ) this->flush (); return true; } + return this->flushToWire ( userThread ); +} + +bool tcpiiu::flushToWire ( bool userThread ) +{ + bool success = true; // enable callback processing prior to taking the flush lock if ( userThread ) { @@ -1984,13 +2003,43 @@ void tcpiiu::disconnectAllIO ( nciu &chan ) } } -void tcpiiu::uninstallIO ( baseNMIU &io ) +// +// care is taken to not hold the lock while deleting the +// IO so that subscription delete request (sent by the +// IO's destructor) do not deadlock +// +bool tcpiiu::destroyAllIO ( nciu &chan ) +{ + tsDLList < baseNMIU > eventQ; + { + epicsAutoMutex autoMutex ( this->mutex ); + if ( chan.verifyIIU ( *this ) ) { + while ( baseNMIU *pIO = eventQ.get () ) { + this->ioTable.remove ( *pIO ); + eventQ.add ( *pIO ); + } + } + else { + return false; + } + } + while ( baseNMIU *pIO = eventQ.get () ) { + pIO->destroy (); + } + return true; +} + +bool tcpiiu::uninstallIO ( baseNMIU &io ) { epicsAutoMutex autoMutex ( this->mutex ); - if ( io.channel ().verifyConnected ( *this ) ) { + if ( io.channel ().verifyIIU ( *this ) ) { this->ioTable.remove ( io ); } + else { + return false; + } io.channel ().tcpiiuPrivateListOfIO::eventq.remove ( io ); + return true; } double tcpiiu::beaconPeriod () const