diff --git a/src/ca/CASG.cpp b/src/ca/CASG.cpp index cc32594ff..11dcf9289 100644 --- a/src/ca/CASG.cpp +++ b/src/ca/CASG.cpp @@ -29,13 +29,14 @@ #include "iocinf.h" #include "oldAccess.h" +#include "autoPtrDestroy.h" +#include "oldChannelNotify_IL.h" tsFreeList < struct CASG, 128 > CASG::freeList; epicsMutex CASG::freeListMutex; CASG::CASG ( cac &cacIn ) : - opPendCount ( 0u ), seqNo ( 0u ), - client ( cacIn ), magic ( CASG_MAGIC ) + client ( cacIn ), magic ( CASG_MAGIC ) { client.installCASG ( *this ); } @@ -48,14 +49,7 @@ void CASG::destroy () CASG::~CASG () { if ( this->verify () ) { - { - epicsAutoMutex locker ( this->mutex ); - tsDLIterBD notify = this->ioList.firstIter (); - while ( notify.valid () ) { - notify->release (); - notify = this->ioList.firstIter (); - } - } + this->reset (); this->client.uninstallCASG ( *this ); this->magic = 0; } @@ -74,7 +68,6 @@ bool CASG::verify () const */ int CASG::block ( double timeout ) { - unsigned long initialSeqNo = this->seqNo; epicsTime cur_time; epicsTime beg_time; double delay; @@ -94,15 +87,11 @@ int CASG::block ( double timeout ) this->client.enableCallbackPreemption (); - status = ECA_NORMAL; while ( 1 ) { { epicsAutoMutex locker ( this->mutex ); - if ( this->seqNo != initialSeqNo ) { - break; - } - if ( this->opPendCount == 0u ) { - this->seqNo++; + if ( this->ioList.count() == 0u ) { + status = ECA_NORMAL; break; } } @@ -114,10 +103,7 @@ int CASG::block ( double timeout ) * recv backlog at least once */ status = ECA_TIMEOUT; - { - epicsAutoMutex locker ( this->mutex ); - this->seqNo++; - } + this->reset (); break; } @@ -139,20 +125,21 @@ int CASG::block ( double timeout ) void CASG::reset () { epicsAutoMutex locker ( this->mutex ); - this->opPendCount = 0; - this->seqNo++; + syncGroupNotify *pNotify; + while ( ( pNotify = this->ioList.get () ) ) { + pNotify->destroy ( * this ); + } } -void CASG::show ( unsigned level) const +void CASG::show ( unsigned level ) const { - printf ( "Sync Group: id=%u, magic=%u, opPend=%lu, seqNo=%lu\n", - this->getId (), this->magic, this->opPendCount, this->seqNo ); - + printf ( "Sync Group: id=%u, magic=%u, opPend=%lu\n", + this->getId (), this->magic, this->ioList.count () ); if ( level ) { epicsAutoMutex locker ( this->mutex ); tsDLIterConstBD < syncGroupNotify > notify = this->ioList.firstIter (); while ( notify.valid () ) { - notify->show (level); + notify->show ( level - 1u ); notify++; } } @@ -160,7 +147,128 @@ void CASG::show ( unsigned level) const bool CASG::ioComplete () const { - return ( this->opPendCount == 0u ); + return ( this->ioList.count () == 0u ); +} + +int CASG::put ( chid pChan, unsigned type, unsigned long count, const void *pValue ) +{ + try { + epicsAutoMutex locker ( this->mutex ); + syncGroupNotify *pNotify = syncGroupWriteNotify::factory ( + this->freeListWriteOP, *this, pChan, type, count, pValue ); + if ( pNotify ) { + this->ioList.add ( *pNotify ); + return ECA_NORMAL; + } + else { + return ECA_ALLOCMEM; + } + } + catch ( cacChannel::badString & ) + { + return ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::noWriteAccess & ) + { + return ECA_NOWTACCESS; + } + catch ( cacChannel::notConnected & ) + { + return ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { + return ECA_ALLOCMEM; + } + catch ( ... ) + { + return ECA_INTERNAL; + } +} + +int CASG::get ( chid pChan, unsigned type, unsigned long count, void *pValue ) +{ + + try { + epicsAutoMutex locker ( this->mutex ); + syncGroupNotify * pNotify = syncGroupReadNotify::factory ( + this->freeListReadOP, *this, pChan, type, count, pValue ); + if ( pNotify ) { + this->ioList.add ( *pNotify ); + return ECA_NORMAL; + } + else { + return ECA_ALLOCMEM; + } + } + catch ( cacChannel::badString & ) + { + return ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::noReadAccess & ) + { + return ECA_NORDACCESS; + } + catch ( cacChannel::notConnected & ) + { + return ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { + return ECA_ALLOCMEM; + } + catch ( ... ) + { + return ECA_INTERNAL; + } +} + +void CASG::destroyIO ( syncGroupNotify ¬ify ) +{ + unsigned requestsIncomplete; + { + epicsAutoMutex locker ( this->mutex ); + this->ioList.remove ( notify ); + requestsIncomplete = this->ioList.count (); + notify.destroy ( *this ); + } + if ( requestsIncomplete == 0u ) { + this->sem.signal (); + } +} + +void CASG::recycleSyncGroupWriteNotify ( syncGroupWriteNotify &io ) +{ + this->freeListWriteOP.release ( &io, sizeof ( io ) ); +} + +void CASG::recycleSyncGroupReadNotify ( syncGroupReadNotify &io ) +{ + this->freeListReadOP.release ( &io, sizeof ( io ) ); } void * CASG::operator new (size_t size) @@ -175,29 +283,3 @@ void CASG::operator delete (void *pCadaver, size_t size) CASG::freeList.release ( pCadaver, size ); } -int CASG::put (chid pChan, unsigned type, unsigned long count, const void *pValue) -{ - syncGroupNotify *pNotify = new syncGroupNotify ( *this, 0); - if ( ! pNotify ) { - return ECA_ALLOCMEM; - } - 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) -{ - syncGroupNotify *pNotify = new syncGroupNotify ( *this, pValue); - if ( ! pNotify ) { - return ECA_ALLOCMEM; - } - 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 b19196a92..efc4f8e5a 100644 --- a/src/ca/Makefile +++ b/src/ca/Makefile @@ -14,10 +14,10 @@ INC += db_access.h INC += addrList.h INC += cacIO.h -LIBSRCS += cacChannelIO.cpp +LIBSRCS += cacChannel.cpp LIBSRCS += cacChannelNotify.cpp LIBSRCS += cacNotify.cpp -LIBSRCS += cacNotifyIO.cpp +LIBSRCS += cacDataNotify.cpp LIBSRCS += cacServiceList.cpp LIBSRCS += access.cpp LIBSRCS += recvProcessThread.cpp @@ -47,6 +47,8 @@ LIBSRCS += putCallback.cpp LIBSRCS += syncgrp.cpp LIBSRCS += CASG.cpp LIBSRCS += syncGroupNotify.cpp +LIBSRCS += syncGroupReadNotify.cpp +LIBSRCS += syncGroupWriteNotify.cpp LIBSRCS += localHostName.cpp LIBSRCS += comQueRecv.cpp LIBSRCS += comQueSend.cpp diff --git a/src/ca/access.cpp b/src/ca/access.cpp index 2986eea3b..55088afd1 100644 --- a/src/ca/access.cpp +++ b/src/ca/access.cpp @@ -27,6 +27,8 @@ #include "oldAccess.h" #include "cac_IL.h" #include "baseNMIU_IL.h" +#include "autoPtrDestroy.h" +#include "oldChannelNotify_IL.h" epicsThreadPrivateId caClientContextId; @@ -141,7 +143,7 @@ extern "C" epicsShareFunc int epicsShareAPI ca_context_create ( int preemptiveCa // // ca_register_service () // -epicsShareFunc int epicsShareAPI ca_register_service ( cacServiceIO *pService ) +epicsShareFunc int epicsShareAPI ca_register_service ( cacService *pService ) { cac *pcac; int caStatus = fetchClientContext (&pcac); @@ -236,25 +238,32 @@ extern "C" int epicsShareAPI ca_search_and_connect ( return ECA_EMPTYSTR; } - oldChannelNotify *pChanNotify = new oldChannelNotify ( conn_func, puser ); + oldChannelNotify *pChanNotify = new oldChannelNotify ( *pcac, name_str, conn_func, puser ); if ( ! pChanNotify ) { return ECA_ALLOCMEM; } - cacChannelIO *pIO = pcac->createChannelIO ( name_str, *pChanNotify ); - if ( pIO ) { - *chanptr = pIO; + if ( pChanNotify->ioAttachOK() ) { + *chanptr = pChanNotify; // make sure that their chan pointer is set prior to // calling connection call backs - pIO->initiateConnect (); + pChanNotify->initiateConnect (); return ECA_NORMAL; } else { - pChanNotify->release (); + pChanNotify->destroy (); return ECA_ALLOCMEM; } } +/* + * ca_clear_channel () + */ +extern "C" int epicsShareAPI ca_clear_channel ( chid pChan ) +{ + pChan->destroy (); + return ECA_NORMAL; +} /* * ca_array_get () @@ -273,17 +282,49 @@ extern "C" int epicsShareAPI ca_array_get ( chtype type, } unsigned tmpType = static_cast < unsigned > ( type ); - getCopy *pNotify = new getCopy ( *pcac, tmpType, count, pValue ); - if ( ! pNotify ) { + autoPtrDestroy < getCopy > pNotify + ( new getCopy ( *pcac, tmpType, count, pValue ) ); + if ( ! pNotify.get() ) { return ECA_ALLOCMEM; } - int status = pChan->read ( type, count, *pNotify ); - if ( status != ECA_NORMAL ) { - pNotify->release (); + try { + pChan->read ( type, count, *pNotify ); + pNotify.release (); + return ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + return ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::noReadAccess & ) + { + return ECA_NORDACCESS; + } + catch ( cacChannel::notConnected & ) + { + return ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { + return ECA_ALLOCMEM; + } + catch ( ... ) + { + return ECA_GETFAIL; } - - return status; } /* @@ -293,44 +334,159 @@ extern "C" int epicsShareAPI ca_array_get_callback ( chtype type, unsigned long count, chid pChan, caEventCallBackFunc *pfunc, void *arg ) { - getCallback *pNotify = new getCallback ( pfunc, arg ); - if ( ! pNotify ) { + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + + autoPtrDestroy < getCallback > pNotify + ( new getCallback ( *pChan, pfunc, arg ) ); + if ( ! pNotify.get() ) { return ECA_ALLOCMEM; } - int status = pChan->read ( type, count, *pNotify ); - if ( status != ECA_NORMAL ) { - pNotify->release (); + try { + pChan->read ( tmpType, count, *pNotify ); + pNotify.release (); + return ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + return ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::noReadAccess & ) + { + return ECA_NORDACCESS; + } + catch ( cacChannel::notConnected & ) + { + return ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { + return ECA_ALLOCMEM; + } + catch ( ... ) + { + return ECA_GETFAIL; } - - return status; } /* * ca_array_put_callback () */ extern "C" int epicsShareAPI ca_array_put_callback ( chtype type, unsigned long count, - chid pChan, const void *pvalue, caEventCallBackFunc *pfunc, void *usrarg ) + chid pChan, const void *pValue, caEventCallBackFunc *pfunc, void *usrarg ) { - putCallback *pNotify = new putCallback ( pfunc, usrarg ); - if ( ! pNotify ) { + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + + autoPtrDestroy < putCallback > pNotify + ( new putCallback ( *pChan, pfunc, usrarg ) ); + if ( ! pNotify.get() ) { return ECA_ALLOCMEM; } - int status = pChan->write ( type, count, pvalue, *pNotify ); - if ( status != ECA_NORMAL ) { - pNotify->release (); + try { + pChan->write ( tmpType, count, pValue, *pNotify ); + pNotify.release (); + return ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + return ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::noWriteAccess & ) + { + return ECA_NOWTACCESS; + } + catch ( cacChannel::notConnected & ) + { + return ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { + return ECA_ALLOCMEM; + } + catch ( ... ) + { + return ECA_PUTFAIL; } - return status; } /* * ca_array_put () */ extern "C" int epicsShareAPI ca_array_put ( chtype type, unsigned long count, - chid pChan, const void *pvalue ) + chid pChan, const void *pValue ) { - return pChan->write ( type, count, pvalue ); + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + + try { + pChan->write ( tmpType, count, pValue ); + return ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + return ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::noWriteAccess & ) + { + return ECA_NOWTACCESS; + } + catch ( cacChannel::notConnected & ) + { + return ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { + return ECA_ALLOCMEM; + } + catch ( ... ) + { + return ECA_PUTFAIL; + } } /* @@ -338,13 +494,8 @@ extern "C" int epicsShareAPI ca_array_put ( chtype type, unsigned long count, */ extern "C" int epicsShareAPI ca_change_connection_event ( chid pChan, caCh *pfunc ) { - oldChannelNotify * pNotify = pChan->notify ().pOldChannelNotify (); - if ( pNotify ) { - return pNotify->changeConnCallBack ( *pChan, pfunc ); - } - else { - return ECA_INTERNAL; - } + return pChan->changeConnCallBack ( pfunc ); + return ECA_INTERNAL; } /* @@ -352,14 +503,7 @@ extern "C" int epicsShareAPI ca_change_connection_event ( chid pChan, caCh *pfun */ extern "C" int epicsShareAPI ca_replace_access_rights_event ( chid pChan, caArh *pfunc ) { - oldChannelNotify * pNotify = pChan->notify ().pOldChannelNotify (); - if ( pNotify ) { - return pNotify->replaceAccessRightsEvent ( *pChan, pfunc ); - } - else { - return ECA_INTERNAL; - } - + return pChan->replaceAccessRightsEvent ( pfunc ); } /* @@ -387,7 +531,10 @@ extern "C" int epicsShareAPI ca_add_masked_array_event ( ca_real, ca_real, ca_real, evid *monixptr, long mask ) { - static const long maskMask = 0xffff; + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); if ( INVALID_DB_REQ (type) ) { return ECA_BADTYPE; @@ -397,6 +544,7 @@ extern "C" int epicsShareAPI ca_add_masked_array_event ( return ECA_BADFUNCPTR; } + static const long maskMask = 0xffff; if ( ( mask & maskMask ) == 0) { return ECA_BADMASK; } @@ -419,23 +567,47 @@ extern "C" int epicsShareAPI ca_add_masked_array_event ( return ECA_TOLARGE; } - oldSubscription *pSubsr = new oldSubscription ( pCallBack, pCallBackArg ); - if ( ! pSubsr ) { + try { + autoPtrDestroy < oldSubscription > pSubsr + ( new oldSubscription ( + *pChan, tmpType, count, mask, pCallBack, pCallBackArg ) ); + if ( ! pSubsr.get () ) { + return ECA_ALLOCMEM; + } + + if ( monixptr ) { + *monixptr = pSubsr.release (); + } + return ECA_NORMAL; + } + catch ( cacChannel::badType & ) + { + return ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + return ECA_BADCOUNT; + } + catch ( cacChannel::badEventSelection & ) + { + return ECA_BADMASK; + } + catch ( cacChannel::noReadAccess & ) + { + return ECA_NORDACCESS; + } + catch ( cacChannel::unsupportedByService & ) + { + return ECA_NOTINSERVICE; + } + catch ( cacChannel::noMemory & ) + { return ECA_ALLOCMEM; } - - cacNotifyIO *pIO; - int status = pChan->subscribe ( type, count, mask, *pSubsr, pIO ); - if ( status == ECA_NORMAL ) { - if ( monixptr ) { - *monixptr = pIO; - } + catch ( ... ) + { + return ECA_INTERNAL; } - else { - pSubsr->release (); - } - - return status; } /* @@ -443,22 +615,13 @@ extern "C" int epicsShareAPI ca_add_masked_array_event ( */ extern "C" int epicsShareAPI ca_clear_event ( evid pMon ) { - pMon->cancel (); + pMon->destroy (); return ECA_NORMAL; } extern "C" chid epicsShareAPI ca_evid_to_chid ( evid pMon ) { - return & pMon->channelIO (); -} - -/* - * ca_clear_channel () - */ -extern "C" int epicsShareAPI ca_clear_channel ( chid pChan ) -{ - delete pChan; - return ECA_NORMAL; + return & pMon->channel (); } /* @@ -750,25 +913,31 @@ extern "C" unsigned long epicsShareAPI ca_element_count (chid pChan) */ extern "C" epicsShareFunc enum channel_state epicsShareAPI ca_state (chid pChan) { - return pChan->state (); + if ( pChan->connected() ) { + return cs_conn; + } + else if ( pChan->previouslyConnected() ){ + return cs_prev_conn; + } + else { + return cs_never_conn; + } } /* * ca_set_puser () */ -extern "C" epicsShareFunc void epicsShareAPI ca_set_puser (chid pChan, void *puser) +extern "C" epicsShareFunc void epicsShareAPI ca_set_puser ( chid pChan, void *puser ) { - oldChannelNotify *pNotify = pChan->notify ().pOldChannelNotify (); - pNotify->setPrivatePointer ( puser ); + pChan->setPrivatePointer ( puser ); } /* * ca_get_puser () */ -extern "C" epicsShareFunc void * epicsShareAPI ca_puser (chid pChan) +extern "C" epicsShareFunc void * epicsShareAPI ca_puser ( chid pChan ) { - oldChannelNotify *pNotify = pChan->notify ().pOldChannelNotify (); - return pNotify->privatePointer (); + return pChan->privatePointer (); } /* @@ -776,12 +945,7 @@ extern "C" epicsShareFunc void * epicsShareAPI ca_puser (chid pChan) */ extern "C" epicsShareFunc unsigned epicsShareAPI ca_read_access (chid pChan) { - if ( pChan->accessRights ().read_access ) { - return true; - } - else { - return false; - } + return pChan->accessRights().readPermit(); } /* @@ -789,12 +953,7 @@ extern "C" epicsShareFunc unsigned epicsShareAPI ca_read_access (chid pChan) */ extern "C" epicsShareFunc unsigned epicsShareAPI ca_write_access (chid pChan) { - if ( pChan->accessRights ().write_access ) { - return true; - } - else { - return false; - } + return pChan->accessRights().writePermit(); } /* diff --git a/src/ca/autoPtrDestroy.h b/src/ca/autoPtrDestroy.h new file mode 100644 index 000000000..ac15ad961 --- /dev/null +++ b/src/ca/autoPtrDestroy.h @@ -0,0 +1,72 @@ + +/* + * $Id$ + * + * + * L O S A L A M O S + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * + * Copyright, The Regents of the University of California. + * + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + */ + +#ifndef autoPtrDestroyh +#define autoPtrDestroyh + +template < class T > +class autoPtrDestroy { +public: + autoPtrDestroy ( T * ); + ~autoPtrDestroy (); + T & operator * () const; + T * operator -> () const; + T * get () const; + T * release (); +private: + T *p; +}; + +template < class T > +inline autoPtrDestroy::autoPtrDestroy ( T *pIn ) : + p ( pIn ) {} + +template < class T > +inline autoPtrDestroy::~autoPtrDestroy () +{ + if ( this->p ) { + p->destroy (); + } +} + +template < class T > +inline T & autoPtrDestroy::operator * () const +{ + return * this->p; +} + +template < class T > +inline T * autoPtrDestroy::operator -> () const +{ + return this->p; +} + +template < class T > +inline T * autoPtrDestroy::get () const +{ + return this->p; +} + +template < class T > +inline T * autoPtrDestroy::release () +{ + T *pTmp = this->p; + this->p = 0; + return pTmp; +} + +#endif // #ifdef autoPtrDestroyh diff --git a/src/ca/autoPtrRecycle_IL.h b/src/ca/autoPtrRecycle_IL.h new file mode 100644 index 000000000..3078f6c98 --- /dev/null +++ b/src/ca/autoPtrRecycle_IL.h @@ -0,0 +1,60 @@ + +/* + * $Id$ + * + * + * L O S A L A M O S + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * + * Copyright, The Regents of the University of California. + * + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + */ + +#ifndef autoPtrRecycleILh +#define autoPtrRecycleILh + +template < class T > +inline autoPtrRecycle::autoPtrRecycle ( cacRecycle &rIn, T *pIn ) : + p ( pIn ), r ( rIn ) {} + +template < class T > +inline autoPtrRecycle::~autoPtrRecycle () +{ + if ( this->p ) { + baseNMIU *pb = this->p; + pb->destroy ( this->r ); + } +} + +template < class T > +inline T & autoPtrRecycle::operator * () const +{ + return * this->p; +} + +template < class T > +inline T * autoPtrRecycle::operator -> () const +{ + return this->p; +} + +template < class T > +inline T * autoPtrRecycle::get () const +{ + return this->p; +} + +template < class T > +inline T * autoPtrRecycle::release () +{ + T *pTmp = this->p; + this->p = 0; + return pTmp; +} + +#endif // #ifdef autoPtrRecycleILh diff --git a/src/ca/baseNMIU.cpp b/src/ca/baseNMIU.cpp index e42570c4a..c0b2dd9ee 100644 --- a/src/ca/baseNMIU.cpp +++ b/src/ca/baseNMIU.cpp @@ -14,8 +14,8 @@ #include "nciu_IL.h" #include "baseNMIU_IL.h" -baseNMIU::baseNMIU ( cacNotify ¬ifyIn, nciu &chanIn ) : - cacNotifyIO ( notifyIn ), chan ( chanIn ) +baseNMIU::baseNMIU ( nciu &chanIn ) : + chan ( chanIn ) { } @@ -30,13 +30,7 @@ class netSubscription * baseNMIU::isSubscription () void baseNMIU::show ( unsigned /* level */ ) const { - printf ( "CA IO primitive at %p for channel %s\n", - static_cast ( this ), this->chan.pName () ); + printf ( "CA IO primitive at %p\n", + static_cast ( this ) ); } -cacChannelIO & baseNMIU::channelIO () const -{ - return this->chan; -} - - diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp index 14bc9b925..7a999ed61 100644 --- a/src/ca/cac.cpp +++ b/src/ca/cac.cpp @@ -12,6 +12,7 @@ #include "osiProcess.h" #include "osiSigPipeIgnore.h" +#include "epics_auto_ptr.h" #include "iocinf.h" #include "cac_IL.h" @@ -26,6 +27,40 @@ #include "netWriteNotifyIO_IL.h" #include "netReadNotifyIO_IL.h" #include "netSubscription_IL.h" +#include "autoPtrRecycle_IL.h" + +// TCP protocol jump table +const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = +{ + &cac::noopAction, + &cac::eventRespAction, + &cac::badTCPRespAction, + &cac::readRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::exceptionRespAction, + &cac::clearChannelRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::readNotifyRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::claimCIURespAction, + &cac::writeNotifyRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::accessRightsRespAction, + &cac::echoRespAction, + &cac::badTCPRespAction, + &cac::badTCPRespAction, + &cac::verifyAndDisconnectChan, + &cac::verifyAndDisconnectChan +}; // // cac::cac () @@ -41,8 +76,11 @@ cac::cac ( bool enablePreemptiveCallbackIn ) : pudpiiu ( 0 ), pSearchTmr ( 0 ), pRepeaterSubscribeTmr ( 0 ), + ioNotifyInProgressId ( 0 ), initializingThreadsPriority ( epicsThreadGetPrioritySelf () ), - enablePreemptiveCallback ( enablePreemptiveCallbackIn ) + threadsBlockingOnNotifyCompletion ( 0u ), + enablePreemptiveCallback ( enablePreemptiveCallbackIn ), + ioInProgress ( false ) { long status; unsigned abovePriority; @@ -129,7 +167,7 @@ cac::~cac () } { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); if ( this->pudpiiu ) { // this blocks until the UDP thread exits so that // it will not sneak in any new clients @@ -140,45 +178,26 @@ cac::~cac () // // shutdown all tcp connections and wait for threads to exit // - { - epicsAutoMutex autoMutex ( this->iiuListMutex ); - - tsDLIterBD piiu = this->iiuList.firstIter (); - while ( piiu.valid () ) { - tsDLIterBD pnext = piiu; - pnext++; - { - epicsAutoMutex autoMutexTmp ( this->defaultMutex ); + while ( true ) { + tcpiiu * piiu; + { + epicsAutoMutex autoMutex ( this->mutex ); + if ( ( piiu = this->iiuList.get() ) ) { piiu->disconnectAllChan ( limboIIU ); } - piiu->disconnect (); - piiu->suicide (); - piiu = pnext; } - - piiu = this->iiuListLimbo.firstIter (); - while ( piiu.valid () ) { - tsDLIterBD pnext = piiu; - pnext++; - piiu->suicide (); - piiu = pnext; + if ( ! piiu ) { + break; } + piiu->destroy (); } - if ( this->pRecvProcThread ) { - delete this->pRecvProcThread; - } - - if ( this->pRepeaterSubscribeTmr ) { - delete this->pRepeaterSubscribeTmr; - } - - if ( this->pSearchTmr ) { - delete this->pSearchTmr; - } + delete this->pRecvProcThread; + delete this->pRepeaterSubscribeTmr; + delete this->pSearchTmr; { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); if ( this->pudpiiu ) { // @@ -186,16 +205,14 @@ cac::~cac () // up new clients. // this->pudpiiu->disconnectAllChan ( limboIIU ); - delete this->pudpiiu; } } - // - // free user name string - // - if ( this->pUserName ) { - delete [] this->pUserName; + if ( ! this->enablePreemptiveCallback && this->fdRegFunc ) { + this->pudpiiu->fdDestroyNotify ( this->fdRegFunc, this->fdRegArg ); } + delete this->pudpiiu; + delete this->pUserName; this->beaconTable.traverse ( &bhe::destroy ); @@ -213,7 +230,7 @@ cac::~cac () void cac::processRecvBacklog () { - epicsAutoMutex autoMutex ( this->iiuListMutex ); + epicsAutoMutex autoMutex ( this->mutex ); tsDLIterBD < tcpiiu > piiu = this->iiuList.firstIter (); while ( piiu.valid () ) { @@ -225,10 +242,7 @@ void cac::processRecvBacklog () bhe *pBHE = piiu->getBHE (); if ( pBHE ) { - { - epicsAutoMutex autoMutexTmp ( this->defaultMutex ); - this->beaconTable.remove ( *pBHE ); - } + this->beaconTable.remove ( *pBHE ); pBHE->destroy (); } @@ -238,19 +252,29 @@ void cac::processRecvBacklog () genLocalExcep ( *this, ECA_DISCONN, hostNameTmp ); } - { - epicsAutoMutex autoMutexTmp ( this->defaultMutex ); - piiu->disconnectAllChan ( *this->pudpiiu ); + piiu->disconnectAllChan ( *this->pudpiiu ); + + // make certain that: + // 1) this is called from the appropriate thread + // 2) lock is not held while in call back + if ( ! this->enablePreemptiveCallback && this->fdRegFunc ) { + CAFDHANDLER *func = this->fdRegFunc; + void *arg = this->fdRegArg; + epicsAutoMutexRelease autoRelease ( mutex ); + piiu->fdDestroyNotify ( func, arg ); } - - piiu->disconnect (); - this->iiuList.remove ( *piiu ); - this->iiuListLimbo.add ( *piiu ); + piiu->destroy (); this->pSearchTmr->resetPeriod ( CA_RECAST_DELAY ); } else { + // make certain that: + // 1) this is called from the appropriate thread + // 2) lock is not held while in call back + if ( ! this->enablePreemptiveCallback && this->fdRegFunc ) { + piiu->fdCreateNotify ( this->mutex, this->fdRegFunc, this->fdRegArg ); + } piiu->processIncoming (); } @@ -258,12 +282,12 @@ void cac::processRecvBacklog () } } +// +// set the push pending flag on all virtual circuits +// void cac::flushRequest () { - /* - * set the push pending flag on all virtual circuits - */ - epicsAutoMutex autoMutex ( this->iiuListMutex ); + epicsAutoMutex autoMutex ( this->mutex ); tsDLIterBD piiu = this->iiuList.firstIter (); while ( piiu.valid () ) { piiu->flushRequest (); @@ -273,14 +297,13 @@ void cac::flushRequest () unsigned cac::connectionCount () const { - epicsAutoMutex autoMutex ( this->iiuListMutex ); + epicsAutoMutex autoMutex ( this->mutex ); return this->iiuList.count (); } void cac::show ( unsigned level ) const { - epicsAutoMutex autoMutex1 ( this->iiuListMutex ); - epicsAutoMutex autoMutex2 ( this->defaultMutex ); + epicsAutoMutex autoMutex2 ( this->mutex ); ::printf ( "Channel Access Client Context at %p for user %s\n", static_cast ( this ), this->pUserName ); @@ -338,9 +361,7 @@ void cac::show ( unsigned level ) const if ( level > 3u ) { ::printf ( "Default mutex:\n"); - this->defaultMutex.show ( level - 4u ); - ::printf ( "Virtual circuit list mutex:\n"); - this->iiuListMutex.show ( level - 4u ); + this->mutex.show ( level - 4u ); } } @@ -356,7 +377,7 @@ void cac::signalRecvActivity () */ void cac::beaconNotify ( const inetAddrID &addr ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); unsigned port; bhe *pBHE; @@ -464,7 +485,7 @@ int cac::pendIO ( const double &timeout ) this->ioCounter.cleanUp (); { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); if ( this->pudpiiu ) { this->pudpiiu->connectTimeoutNotify (); } @@ -511,40 +532,10 @@ bool cac::ioComplete () const } } -void cac::accessRightsNotify ( unsigned id, const caar &ar ) -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - nciu * pChan = this->chanTable.lookup ( id ); - if ( pChan ) { - pChan->accessRightsStateChange ( ar ); - } -} - -bool cac::connectChannel ( bool v44Ok, unsigned id, - unsigned nativeType, unsigned long nativeCount, unsigned sid ) -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - nciu * pChan = this->chanTable.lookup ( id ); - if ( pChan ) { - unsigned sidTmp; - if ( v44Ok ) { - sidTmp = sid; - } - else { - sidTmp = pChan->getSID (); - } - pChan->connect ( nativeType, nativeCount, sidTmp ); - return true; - } - else { - return false; - } -} - // this is to only be used by early protocol revisions bool cac::connectChannel ( unsigned id ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); nciu * pChan = this->chanTable.lookup ( id ); if ( pChan ) { pChan->connect (); @@ -555,32 +546,21 @@ bool cac::connectChannel ( unsigned id ) } } -void cac::disconnectChannel ( unsigned id ) -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - nciu * pChan = this->chanTable.lookup ( id ); - if ( pChan ) { - assert ( this->pudpiiu && this->pSearchTmr ); - pChan->disconnect ( *this->pudpiiu ); - this->pSearchTmr->resetPeriod ( CA_RECAST_DELAY ); - } -} - void cac::installCASG ( CASG &sg ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); this->sgTable.add ( sg ); } void cac::uninstallCASG ( CASG &sg ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); this->sgTable.remove ( sg ); } CASG * cac::lookupCASG ( unsigned id ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); CASG * psg = this->sgTable.lookup ( id ); if ( psg ) { if ( ! psg->verify () ) { @@ -590,13 +570,13 @@ CASG * cac::lookupCASG ( unsigned id ) return psg; } -void cac::exceptionNotify ( int status, const char *pContext, +void cac::exception ( int status, const char *pContext, const char *pFileName, unsigned lineNo ) { ca_signal_with_file_and_lineno ( status, pContext, pFileName, lineNo ); } -void cac::exceptionNotify ( int status, const char *pContext, +void cac::exception ( int status, const char *pContext, unsigned type, unsigned long count, const char *pFileName, unsigned lineNo ) { @@ -604,45 +584,40 @@ void cac::exceptionNotify ( int status, const char *pContext, pContext, type, count ); } -void cac::registerService ( cacServiceIO &service ) +void cac::registerService ( cacService &service ) { this->services.registerService ( service ); } -cacChannelIO * cac::createChannelIO ( const char *pName, cacChannelNotify &chan ) +cacChannel & cac::createChannel ( const char *pName, cacChannelNotify &chan ) { - cacChannelIO *pIO; + cacChannel *pIO; - pIO = this->services.createChannelIO ( pName, chan ); + pIO = this->services.createChannel ( pName, chan ); if ( ! pIO ) { - pIO = cacGlobalServiceList.createChannelIO ( pName, chan ); + pIO = cacGlobalServiceList.createChannel ( pName, chan ); if ( ! pIO ) { if ( ! this->pudpiiu || ! this->pSearchTmr ) { if ( ! this->setupUDP () ) { - return 0; + throw ECA_INTERNAL; } } - nciu *pNetChan = new nciu ( *this, limboIIU, chan, pName ); - if ( pNetChan ) { - if ( ! pNetChan->fullyConstructed () ) { - delete static_cast < cacChannelIO * > ( pNetChan ); - return 0; - } - else { - return pNetChan; - } + epics_auto_ptr < cacChannel > pNetChan + ( new nciu ( *this, limboIIU, chan, pName ) ); + if ( pNetChan.get() ) { + return *pNetChan.release (); } else { - return 0; + throw std::bad_alloc (); } } } - return pIO; + return *pIO; } void cac::installNetworkChannel ( nciu & chan, netiiu * & piiu ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); this->chanTable.add ( chan ); this->pudpiiu->attachChannel ( chan ); piiu = this->pudpiiu; @@ -651,30 +626,33 @@ void cac::installNetworkChannel ( nciu & chan, netiiu * & piiu ) bool cac::setupUDP () { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); - if ( this->pudpiiu ) { - return true; - } - - this->pudpiiu = new udpiiu ( *this ); if ( ! this->pudpiiu ) { - return false; + this->pudpiiu = new udpiiu ( *this ); + if ( ! this->pudpiiu ) { + return false; + } + if ( ! this->enablePreemptiveCallback && this->fdRegFunc ) { + CAFDHANDLER *func = this->fdRegFunc; + void *arg = this->fdRegArg; + epicsAutoMutexRelease autoRelease ( this->mutex ); + this->pudpiiu->fdCreateNotify ( func, arg ); + } } - this->pSearchTmr = new searchTimer ( *this->pudpiiu, *this->pTimerQueue, this->defaultMutex ); if ( ! this->pSearchTmr ) { - delete this->pudpiiu; - this->pudpiiu = 0; - return false; + this->pSearchTmr = new searchTimer ( *this->pudpiiu, *this->pTimerQueue, this->mutex ); + if ( ! this->pSearchTmr ) { + return false; + } } - this->pRepeaterSubscribeTmr = new repeaterSubscribeTimer ( *this->pudpiiu, *this->pTimerQueue ); if ( ! this->pRepeaterSubscribeTmr ) { - delete this->pSearchTmr; - delete this->pudpiiu; - this->pudpiiu = 0; - return false; + this->pRepeaterSubscribeTmr = new repeaterSubscribeTimer ( *this->pudpiiu, *this->pTimerQueue ); + if ( ! this->pRepeaterSubscribeTmr ) { + return false; + } } return true; @@ -682,7 +660,7 @@ bool cac::setupUDP () void cac::registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); this->fdRegFunc = pFunc; this->fdRegArg = pArg; } @@ -703,7 +681,7 @@ void cac::disableCallbackPreemption () void cac::changeExceptionEvent ( caExceptionHandler *pfunc, void *arg ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); if ( pfunc ) { this->ca_exception_func = pfunc; this->ca_exception_arg = arg; @@ -738,7 +716,7 @@ void cac::genLocalExcepWFL (long stat, const char *ctx, const char *pFile, unsig args.lineNo = lineNo; { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); pExceptionFunc = this->ca_exception_func; args.usr = this->ca_exception_arg; } @@ -756,7 +734,7 @@ void cac::repeaterSubscribeConfirmNotify () void cac::replaceErrLogHandler ( caPrintfFunc *ca_printf_func ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); if ( ca_printf_func ) { this->pVPrintfFunc = ca_printf_func; } @@ -776,9 +754,7 @@ bool cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid, } { - // lock order is significant here - epicsAutoMutex autoMutex1 ( this->iiuListMutex ); - epicsAutoMutex autoMutex2 ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); nciu *chan; /* @@ -826,19 +802,16 @@ bool cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid, } if ( ! piiu ) { - piiu = iiuListLimbo.get (); + piiu = new tcpiiu ( *this, this->connTMO, *this->pTimerQueue ); if ( ! piiu ) { - piiu = new tcpiiu ( *this, this->connTMO, *this->pTimerQueue ); - if ( ! piiu ) { - return true; - } + return true; } if ( piiu->fullyConstructed () ) { this->iiuList.add ( *piiu ); if ( ! piiu->initiateConnect ( addr, minorVersionNumber, *pBHE, this->ipToAEngine ) ) { this->iiuList.remove ( *piiu ); - this->iiuListLimbo.add ( *piiu ); + piiu->destroy (); return true; } } @@ -869,7 +842,7 @@ bool cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid, void cac::uninstallChannel ( nciu & chan ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); nciu *pChan = this->chanTable.remove ( chan ); assert ( pChan = &chan ); this->flushIfRequired ( chan ); @@ -877,19 +850,6 @@ void cac::uninstallChannel ( nciu & chan ) chan.getPIIU()->detachChannel ( chan ); } -void cac::getFDRegCallback ( CAFDHANDLER *&fdRegFuncOut, void *&fdRegArgOut ) const -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - if ( this->enablePreemptiveCallback ) { - fdRegFuncOut = 0; - fdRegArgOut = 0; - } - else { - fdRegFuncOut = this->fdRegFunc; - fdRegArgOut = this->fdRegArg; - } -} - int cac::printf ( const char *pformat, ... ) { va_list theArgs; @@ -926,7 +886,7 @@ void cac::flushIfRequired ( nciu &chan ) } } if ( flushPermit ) { - chan.getPIIU()->blockUntilSendBacklogIsReasonable ( this->defaultMutex ); + chan.getPIIU()->blockUntilSendBacklogIsReasonable ( this->mutex ); } else { this->flushRequest (); @@ -937,249 +897,320 @@ void cac::flushIfRequired ( nciu &chan ) } } -int cac::writeRequest ( nciu &chan, unsigned type, unsigned nElem, const void *pValue ) +void cac::writeRequest ( nciu &chan, unsigned type, unsigned nElem, const void *pValue ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); this->flushIfRequired ( chan ); - return chan.getPIIU()->writeRequest ( chan, type, nElem, pValue ); + chan.getPIIU()->writeRequest ( chan, type, nElem, pValue ); } -int cac::writeNotifyRequest ( nciu &chan, cacNotify ¬ify, - unsigned type, unsigned nElem, const void *pValue ) +cacChannel::ioid cac::writeNotifyRequest ( nciu &chan, unsigned type, unsigned nElem, + const void *pValue, cacNotify ¬ify ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); - netWriteNotifyIO *pIO = netWriteNotifyIO::factory ( - this->freeListWriteNotifyIO, chan, notify ); - if ( pIO ) { + epicsAutoMutex autoMutex ( this->mutex ); + autoPtrRecycle < netWriteNotifyIO > pIO ( *this, netWriteNotifyIO::factory ( + this->freeListWriteNotifyIO, chan, notify ) ); + if ( pIO.get() ) { this->ioTable.add ( *pIO ); chan.cacPrivateListOfIO::eventq.add ( *pIO ); this->flushIfRequired ( chan ); - int status = chan.getPIIU()->writeNotifyRequest ( - chan, *pIO, type, nElem, pValue ); - if ( status != ECA_NORMAL ) { - this->destroyWriteNotifyIO ( *pIO ); - } - return status; + chan.getPIIU()->writeNotifyRequest ( + chan, *pIO, type, nElem, pValue ); + return pIO.release()->getId (); } else { - return ECA_ALLOCMEM; + throw cacChannel::noMemory (); } } -int cac::readNotifyRequest ( nciu &chan, cacNotify ¬ify, unsigned type, unsigned nElem ) +cacChannel::ioid cac::readNotifyRequest ( nciu &chan, unsigned type, unsigned nElem, cacDataNotify ¬ify ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); - - netReadNotifyIO *pIO = netReadNotifyIO::factory ( - this->freeListReadNotifyIO, chan, notify ); - if ( pIO ) { + epicsAutoMutex autoMutex ( this->mutex ); + autoPtrRecycle < netReadNotifyIO > pIO ( *this, netReadNotifyIO::factory ( + this->freeListReadNotifyIO, chan, notify ) ); + if ( pIO.get() ) { this->flushIfRequired ( chan ); this->ioTable.add ( *pIO ); chan.cacPrivateListOfIO::eventq.add ( *pIO ); - int status = chan.getPIIU()->readNotifyRequest ( chan, *pIO, type, nElem ); - if ( status != ECA_NORMAL ) { - this->destroyReadNotifyIO ( *pIO ); - } - return status; + chan.getPIIU()->readNotifyRequest ( chan, *pIO, type, nElem ); + return pIO.release()->getId (); } else { - return ECA_ALLOCMEM; + throw cacChannel::noMemory (); + } +} + +void cac::ioCancel ( nciu &chan, const cacChannel::ioid &id ) +{ + bool signalNeeded; + { + epicsAutoMutex autoMutex ( this->mutex ); + baseNMIU * pmiu = this->ioTable.remove ( id ); + if ( pmiu ) { + chan.cacPrivateListOfIO::eventq.remove ( *pmiu ); + pmiu->destroy ( *this ); + } + assert ( this->threadsBlockingOnNotifyCompletion < UINT_MAX ); + this->threadsBlockingOnNotifyCompletion++; + while ( this->ioInProgress && this->ioNotifyInProgressId == id ) { + epicsAutoMutex autoMutexRelease ( this->mutex ); + this->notifyCompletionEvent.wait ( 0.5 ); + } + assert ( this->threadsBlockingOnNotifyCompletion > 0u ); + this->threadsBlockingOnNotifyCompletion--; + signalNeeded = this->threadsBlockingOnNotifyCompletion > 0u; + } + if ( signalNeeded ) { + this->notifyCompletionEvent.signal (); + } +} + +void cac::ioShow ( const cacChannel::ioid &id, unsigned level ) const +{ + epicsAutoMutex autoMutex ( this->mutex ); + baseNMIU * pmiu = this->ioTable.lookup ( id ); + if ( pmiu ) { + pmiu->show ( level ); } } bool cac::ioCompletionNotify ( unsigned id, unsigned type, unsigned long count, const void *pData ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.lookup ( id ); - if ( pmiu ) { - pmiu->notify().completionNotify ( pmiu->channel(), type, count, pData ); - return true; - } - else { + if ( ! pmiu ) { return false; } + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->completion ( type, count, pData ); + } + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } bool cac::ioExceptionNotify ( unsigned id, int status, const char *pContext ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.lookup ( id ); - if ( pmiu ) { - pmiu->notify().exceptionNotify ( pmiu->channel(), status, pContext ); - return true; - } - else { + if ( ! pmiu ) { return false; } + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->exception ( status, pContext ); + } + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } bool cac::ioExceptionNotify ( unsigned id, int status, const char *pContext, unsigned type, unsigned long count ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.lookup ( id ); - if ( pmiu ) { - pmiu->notify().exceptionNotify ( pmiu->channel(), - status, pContext, type, count ); - return true; - } - else { + if ( ! pmiu ) { return false; } + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->exception ( status, pContext, type, count ); + } + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } bool cac::ioCompletionNotifyAndDestroy ( unsigned id ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.remove ( id ); - if ( pmiu ) { - pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); - pmiu->notify().completionNotify ( pmiu->channel() ); - pmiu->destroy ( *this ); - return true; - } - else { + if ( ! pmiu ) { return false; } + pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->completion (); + } + pmiu->destroy ( *this ); + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } bool cac::ioCompletionNotifyAndDestroy ( unsigned id, unsigned type, unsigned long count, const void *pData ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.remove ( id ); - if ( pmiu ) { - pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); - pmiu->notify().completionNotify ( pmiu->channel(), type, count, pData ); - pmiu->destroy ( *this ); - return true; - } - else { + if ( ! pmiu ) { return false; } + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->completion ( type, count, pData ); + } + pmiu->destroy ( *this ); + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } bool cac::ioExceptionNotifyAndDestroy ( unsigned id, int status, const char *pContext ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.remove ( id ); - if ( pmiu ) { - pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); - pmiu->notify().exceptionNotify ( pmiu->channel (), status, pContext ); - pmiu->destroy ( *this ); - return true; - } - else { + if ( ! pmiu ) { return false; } + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->exception ( status, pContext ); + } + pmiu->destroy ( *this ); + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } bool cac::ioExceptionNotifyAndDestroy ( unsigned id, int status, const char *pContext, unsigned type, unsigned long count ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); baseNMIU * pmiu = this->ioTable.remove ( id ); - if ( pmiu ) { - pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); - pmiu->notify().exceptionNotify ( pmiu->channel(), status, - pContext, type, count ); - pmiu->destroy ( *this ); - return true; - } - else { + if ( ! pmiu ) { return false; } + assert ( ! this->ioInProgress ); + this->ioInProgress = true; + this->ioNotifyInProgressId = id; + pmiu->channel().cacPrivateListOfIO::eventq.remove ( *pmiu ); + { + epicsAutoMutexRelease ( this->mutex ); + pmiu->exception ( status, pContext, type, count ); + } + pmiu->destroy ( *this ); + // threads blocked canceling this IO will wait + // until we stop processing this IO + this->ioInProgress = false; + if ( this->threadsBlockingOnNotifyCompletion ) { + this->notifyCompletionEvent.signal (); + } + return true; } // resubscribe for monitors from this channel void cac::connectAllIO ( nciu &chan ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); - tsDLIterBD < baseNMIU > pNetIO = - chan.cacPrivateListOfIO::eventq.firstIter (); - while ( pNetIO.valid () ) { - tsDLIterBD < baseNMIU > next = pNetIO; - next++; - class netSubscription *pSubscr = pNetIO->isSubscription (); - if ( pSubscr ) { - chan.getPIIU()->subscriptionRequest ( *pSubscr ); + tsDLList < baseNMIU > tmpList; + { + epicsAutoMutex autoMutex ( this->mutex ); + tsDLIterBD < baseNMIU > pNetIO = + chan.cacPrivateListOfIO::eventq.firstIter (); + while ( pNetIO.valid () ) { + tsDLIterBD < baseNMIU > next = pNetIO; + next++; + class netSubscription *pSubscr = pNetIO->isSubscription (); + if ( pSubscr ) { + chan.getPIIU()->subscriptionRequest ( chan, *pSubscr ); + } + else { + // it shouldnt be here at this point - so uninstall it + this->ioTable.remove ( *pNetIO ); + chan.cacPrivateListOfIO::eventq.remove ( *pNetIO ); + tmpList.add ( *pNetIO ); + } + pNetIO = next; } - else { - // it shouldnt be here at this point - so uninstall it - this->ioTable.remove ( *pNetIO ); - chan.cacPrivateListOfIO::eventq.remove ( *pNetIO ); - pNetIO->notify().exceptionNotify ( pNetIO->channel(), ECA_DISCONN, chan.pHostName() ); - pNetIO.pointer()->destroy ( *this ); - } - pNetIO = next; + chan.getPIIU()->flushRequest (); + } + while ( baseNMIU *pIO = tmpList.get () ) { + pIO->exception ( ECA_INTERNAL, "strange IO exists when connecting channel?" ); + pIO->destroy ( *this ); } - chan.getPIIU()->flushRequest (); } // cancel IO operations and monitor subscriptions void cac::disconnectAllIO ( nciu &chan ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); - tsDLIterBD < baseNMIU > pNetIO = - chan.cacPrivateListOfIO::eventq.firstIter (); - while ( pNetIO.valid () ) { - tsDLIterBD < baseNMIU > next = pNetIO; - next++; - if ( ! pNetIO->isSubscription () ) { - // no use after disconnected - so uninstall it - this->ioTable.remove ( *pNetIO ); - chan.cacPrivateListOfIO::eventq.remove ( *pNetIO ); - pNetIO->notify().exceptionNotify ( pNetIO->channel(), ECA_DISCONN, chan.pHostName() ); - pNetIO.pointer()->destroy ( *this ); + tsDLList < baseNMIU > tmpList; + { + epicsAutoMutex autoMutex ( this->mutex ); + tsDLIterBD < baseNMIU > pNetIO = + chan.cacPrivateListOfIO::eventq.firstIter (); + while ( pNetIO.valid () ) { + tsDLIterBD < baseNMIU > next = pNetIO; + next++; + if ( ! pNetIO->isSubscription () ) { + // no use after disconnected - so uninstall it + this->ioTable.remove ( *pNetIO ); + chan.cacPrivateListOfIO::eventq.remove ( *pNetIO ); + tmpList.add ( *pNetIO ); + } + pNetIO = next; } - pNetIO = next; + } + while ( baseNMIU *pIO = tmpList.get () ) { + pIO->exception ( ECA_DISCONN, chan.pHostName() ); + pIO->destroy ( *this ); } } void cac::destroyAllIO ( nciu &chan ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); + epicsAutoMutex autoMutex ( this->mutex ); while ( baseNMIU *pIO = chan.cacPrivateListOfIO::eventq.get() ) { this->ioTable.remove ( *pIO ); this->flushIfRequired ( chan ); class netSubscription *pSubscr = pIO->isSubscription (); if ( pSubscr ) { - pIO->channel().getPIIU()->subscriptionCancelRequest ( *pSubscr ); + chan.getPIIU()->subscriptionCancelRequest ( chan, *pSubscr ); } pIO->destroy ( *this ); } } -void cac::destroyReadNotifyIO ( netReadNotifyIO &io ) -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - baseNMIU *pIO = this->ioTable.remove ( io ); - assert ( static_cast < baseNMIU * > ( &io ) == pIO ); - io.channel().cacPrivateListOfIO::eventq.remove ( io ); - io.destroy ( *this ); -} - -void cac::destroyWriteNotifyIO ( netWriteNotifyIO &io ) -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - baseNMIU *pIO = this->ioTable.remove ( io ); - assert ( static_cast < baseNMIU * > ( &io ) == pIO ); - io.channel().cacPrivateListOfIO::eventq.remove ( io ); - io.destroy ( *this ); -} - -void cac::destroySubscription ( netSubscription &io ) -{ - epicsAutoMutex autoMutex ( this->defaultMutex ); - baseNMIU *pIO = this->ioTable.remove ( io ); - assert ( static_cast < baseNMIU * > ( &io ) == pIO ); - io.channel().cacPrivateListOfIO::eventq.remove ( io ); - this->flushIfRequired ( io.channel() ); - io.channel().getPIIU()->subscriptionCancelRequest ( io ); - io.destroy ( *this ); -} - void cac::recycleReadNotifyIO ( netReadNotifyIO &io ) { this->freeListReadNotifyIO.release ( &io, sizeof ( io ) ); @@ -1195,20 +1226,254 @@ void cac::recycleSubscription ( netSubscription &io ) this->freeListSubscription.release ( &io, sizeof ( io ) ); } -cacNotifyIO * cac::subscriptionRequest ( nciu &chan, unsigned type, - unsigned long nElem, unsigned mask, cacNotify ¬ify ) +cacChannel::ioid cac::subscriptionRequest ( nciu &chan, unsigned type, + unsigned long nElem, unsigned mask, cacDataNotify ¬ify ) { - epicsAutoMutex autoMutex ( this->defaultMutex ); - netSubscription *pSubcr = netSubscription::factory ( - this->freeListSubscription, chan, type, nElem, mask, notify ); - if ( pSubcr ) { - pSubcr->channel().cacPrivateListOfIO::eventq.add ( *pSubcr ); - this->ioTable.add ( *pSubcr ); - if ( pSubcr->channel().connected() ) { - this->flushIfRequired ( pSubcr->channel() ); - pSubcr->channel().getPIIU()->subscriptionRequest ( *pSubcr ); + epicsAutoMutex autoMutex ( this->mutex ); + autoPtrRecycle < netSubscription > pIO ( *this, netSubscription::factory ( + this->freeListSubscription, chan, type, nElem, mask, notify ) ); + if ( pIO.get() ) { + chan.cacPrivateListOfIO::eventq.add ( *pIO ); + this->ioTable.add ( *pIO ); + if ( chan.connected() ) { + this->flushIfRequired ( chan ); + chan.getPIIU()->subscriptionRequest ( chan, *pIO ); } + cacChannel::ioid id = pIO->getId (); + pIO.release(); + return id; + } + else { + throw cacChannel::noMemory(); } - return pSubcr; } +bool cac::noopAction ( tcpiiu &iiu, const caHdr &, void *pMsgBdy ) +{ + return true; +} + +bool cac::echoRespAction ( tcpiiu &iiu, const caHdr &, void *pMsgBdy ) +{ + return true; +} + +bool cac::writeNotifyRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + int caStatus = hdr.m_cid; + if ( caStatus == ECA_NORMAL ) { + return this->ioCompletionNotifyAndDestroy ( hdr.m_available ); + } + else { + return this->ioExceptionNotifyAndDestroy ( hdr.m_available, + caStatus, "write notify request rejected" ); + } +} + +bool cac::readNotifyRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + + /* + * the channel id field is abused for + * read notify status starting with CA V4.1 + */ + int caStatus; + if ( iiu.ca_v41_ok() ) { + caStatus = hdr.m_cid; + } + else { + caStatus = ECA_NORMAL; + } + + /* + * convert the data buffer from net + * format to host format + */ +# ifdef CONVERSION_REQUIRED + if ( hdr.m_dataType < NELEMENTS ( cac_dbr_cvrt ) ) { + ( *cac_dbr_cvrt[ hdr.m_dataType ] ) ( + pMsgBdy, pMsgBdy, false, hdr.m_count); + } + else { + caStatus = htonl ( ECA_BADTYPE ); + } +# endif + + if ( caStatus == ECA_NORMAL ) { + return this->ioCompletionNotifyAndDestroy ( hdr.m_available, + hdr.m_dataType, hdr.m_count, pMsgBdy ); + } + else { + return this->ioExceptionNotifyAndDestroy ( hdr.m_available, + caStatus, "read failed", hdr.m_dataType, hdr.m_count ); + } +} + +bool cac::eventRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + int caStatus; + + /* + * m_postsize = 0 used to be a confirmation, but is + * now a noop because the IO block is immediately + * deleted + */ + if ( ! hdr.m_postsize ) { + return true; + } + + /* + * the channel id field is abused for + * read notify status starting with CA V4.1 + */ + if ( iiu.ca_v41_ok() ) { + caStatus = hdr.m_cid; + } + else { + caStatus = ECA_NORMAL; + } + + /* + * convert the data buffer from net format to host format + */ +# ifdef CONVERSION_REQUIRED + if ( hdr.m_dataType < NELEMENTS ( cac_dbr_cvrt ) ) { + ( *cac_dbr_cvrt [ hdr.m_dataType ] )( + pMsgBdy, pMsgBdy, false, hdr.m_count); + } + else { + caStatus = htonl ( ECA_BADTYPE ); + } +# endif + + if ( caStatus == ECA_NORMAL ) { + return this->ioCompletionNotify ( hdr.m_available, + hdr.m_dataType, hdr.m_count, pMsgBdy ); + } + else { + return this->ioExceptionNotify ( hdr.m_available, + caStatus, "subscription update failed", + hdr.m_dataType, hdr.m_count ); + } +} + +bool cac::readRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + return this->ioCompletionNotifyAndDestroy ( hdr.m_available, + hdr.m_dataType, hdr.m_count, pMsgBdy ); +} + +bool cac::clearChannelRespAction ( tcpiiu &iiu, const caHdr &, void *pMsgBdy ) +{ + return true; // currently a noop +} + +bool cac::exceptionRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + const caHdr * req = reinterpret_cast < const caHdr * > ( pMsgBdy ); + char context[255]; + char hostName[64]; + + const char *pName = reinterpret_cast < const char * > ( req + 1 ); + + iiu.hostName ( hostName, sizeof(hostName) ); + sprintf ( context, "detected by: %s for: %s", + hostName, pName); + + switch ( ntohs ( req->m_cmmd ) ) { + case CA_PROTO_READ_NOTIFY: + return this->ioExceptionNotifyAndDestroy ( ntohl ( req->m_available ), + ntohl ( hdr.m_available ), context, + ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); + case CA_PROTO_READ: + return this->ioExceptionNotifyAndDestroy ( ntohl (req->m_available), + ntohl ( hdr.m_available ), context, + ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); + case CA_PROTO_WRITE_NOTIFY: + return this->ioExceptionNotifyAndDestroy ( ntohl (req->m_available), + ntohl ( hdr.m_available ), context, + ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); + case CA_PROTO_WRITE: + this->exception ( ntohl ( hdr.m_available ), + context, ntohs ( req->m_dataType ), ntohs ( req->m_count ), __FILE__, __LINE__); + return true; + case CA_PROTO_EVENT_ADD: + return this->ioExceptionNotify ( ntohl ( req->m_available ), + ntohl ( hdr.m_available ), context, + ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); + case CA_PROTO_EVENT_CANCEL: + return this->ioExceptionNotifyAndDestroy ( ntohl ( req->m_available ), + ntohl ( hdr.m_available ), context ); + default: + this->exception ( ntohl ( hdr.m_available ), + context, __FILE__, __LINE__ ); + return true; + } +} + +bool cac::accessRightsRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + nciu * pChan = this->chanTable.lookup ( hdr.m_cid ); + if ( pChan ) { + unsigned ar = hdr.m_available; + caAccessRights accessRights ( + ( ar & CA_PROTO_ACCESS_RIGHT_READ ) ? true : false, + ( ar & CA_PROTO_ACCESS_RIGHT_WRITE ) ? true : false); + pChan->accessRightsStateChange ( accessRights ); + } + return true; +} + +bool cac::claimCIURespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + nciu * pChan = this->chanTable.lookup ( hdr.m_cid ); + if ( pChan ) { + unsigned sidTmp; + if ( iiu.ca_v44_ok() ) { + sidTmp = hdr.m_available; + } + else { + sidTmp = pChan->getSID (); + } + pChan->connect ( hdr.m_dataType, hdr.m_count, sidTmp ); + return true; + } + else { + return false; + } +} + +bool cac::verifyAndDisconnectChan ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + nciu * pChan = this->chanTable.lookup ( hdr.m_cid ); + if ( pChan ) { + assert ( this->pudpiiu && this->pSearchTmr ); + pChan->disconnect ( *this->pudpiiu ); + this->pSearchTmr->resetPeriod ( CA_RECAST_DELAY ); + } + return true; +} + +bool cac::badTCPRespAction ( tcpiiu &iiu, const caHdr &hdr, void *pMsgBdy ) +{ + char hostName[64]; + iiu.hostName ( hostName, sizeof(hostName) ); + ca_printf ( "CAC: Undecipherable TCP message ( bad response type %u ) from %s\n", + hdr.m_cmmd, hostName ); + return false; +} + +void cac::executeResponse ( tcpiiu &iiu, caHdr &hdr, char *pMshBody ) +{ + // execute the response message + pProtoStubTCP pStub; + if ( hdr.m_cmmd >= NELEMENTS ( cac::tcpJumpTableCAC ) ) { + pStub = &cac::badTCPRespAction; + } + else { + pStub = cac::tcpJumpTableCAC [hdr.m_cmmd]; + } + ( this->*pStub ) ( iiu, hdr, pMshBody ); +} + + diff --git a/src/ca/cacChannel.cpp b/src/ca/cacChannel.cpp new file mode 100644 index 000000000..c820965f6 --- /dev/null +++ b/src/ca/cacChannel.cpp @@ -0,0 +1,70 @@ + + +/* $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 + */ + +#include + +#include "iocinf.h" + +cacChannel::~cacChannel () +{ +} + +caAccessRights cacChannel::accessRights () const +{ + static caAccessRights ar ( true, true ); + return ar; +} + +void cacChannel::notifyStateChangeFirstConnectInCountOfOutstandingIO () +{ +} + +unsigned cacChannel::searchAttempts () const +{ + return 0u; +} + +double cacChannel::beaconPeriod () const +{ + return - DBL_MAX; +} + +bool cacChannel::ca_v42_ok () const +{ + return true; +} + +bool cacChannel::connected () const +{ + return true; +} + +bool cacChannel::previouslyConnected () const +{ + return true; +} + +void cacChannel::hostName ( char *pBuf, unsigned bufLength ) const +{ + if ( bufLength ) { + localHostNameAtLoadTime.copy ( pBuf, bufLength ); + } +} + +// deprecated - please do not use +const char * cacChannel::pHostName () const +{ + return localHostNameAtLoadTime.pointer (); +} + + diff --git a/src/ca/cacChannelIO.cpp b/src/ca/cacChannelIO.cpp deleted file mode 100644 index cafbd7756..000000000 --- a/src/ca/cacChannelIO.cpp +++ /dev/null @@ -1,72 +0,0 @@ - - -/* $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 - */ - -#include - -#include "iocinf.h" - -cacChannelIO::~cacChannelIO () -{ -} - -channel_state cacChannelIO::state () const -{ - return cs_conn; -} - -caar cacChannelIO::accessRights () const -{ - // static here avoids undefined memory read warning from - // error checking codes - static caar ar = { true, true }; - return ar; -} - -void cacChannelIO::notifyStateChangeFirstConnectInCountOfOutstandingIO () -{ -} - -unsigned cacChannelIO::searchAttempts () const -{ - return 0u; -} - -double cacChannelIO::beaconPeriod () const -{ - return - DBL_MAX; -} - -bool cacChannelIO::ca_v42_ok () const -{ - return true; -} - -bool cacChannelIO::connected () const -{ - return true; -} - -void cacChannelIO::hostName ( char *pBuf, unsigned bufLength ) const -{ - if ( bufLength ) { - localHostNameAtLoadTime.copy ( pBuf, bufLength ); - } -} - -// deprecated - please do not use -const char * cacChannelIO::pHostName () const -{ - return localHostNameAtLoadTime.pointer (); -} - - diff --git a/src/ca/cacChannelNotify.cpp b/src/ca/cacChannelNotify.cpp index cebd9cdd7..88028cd56 100644 --- a/src/ca/cacChannelNotify.cpp +++ b/src/ca/cacChannelNotify.cpp @@ -20,19 +20,19 @@ cacChannelNotify::~cacChannelNotify () { } -void cacChannelNotify::connectNotify ( cacChannelIO & ) +void cacChannelNotify::connectNotify ( cacChannel & ) { } -void cacChannelNotify::disconnectNotify ( cacChannelIO & ) +void cacChannelNotify::disconnectNotify ( cacChannel & ) { } -void cacChannelNotify::accessRightsNotify ( cacChannelIO &, const caar & ) +void cacChannelNotify::accessRightsNotify ( cacChannel &, const caAccessRights & ) { } -void cacChannelNotify::exceptionNotify ( cacChannelIO &io, int status, const char *pContext ) +void cacChannelNotify::exception ( cacChannel &io, int status, const char *pContext ) { ca_signal_formated ( status, __FILE__, __LINE__, "channel=%s context=\"%s\"\n", io.pHostName (), pContext ); @@ -42,8 +42,3 @@ bool cacChannelNotify::includeFirstConnectInCountOfOutstandingIO () const { return false; } - -class oldChannelNotify * cacChannelNotify::pOldChannelNotify () -{ - return 0; -} diff --git a/src/ca/cacNotifyIO.cpp b/src/ca/cacDataNotify.cpp similarity index 81% rename from src/ca/cacNotifyIO.cpp rename to src/ca/cacDataNotify.cpp index df837a566..c98eebd46 100644 --- a/src/ca/cacNotifyIO.cpp +++ b/src/ca/cacDataNotify.cpp @@ -12,8 +12,6 @@ #include "iocinf.h" -cacNotifyIO::~cacNotifyIO () +cacDataNotify::~cacDataNotify () { - this->callback.release (); -} - +} \ No newline at end of file diff --git a/src/ca/cacIO.h b/src/ca/cacIO.h index c9be02a9a..e7662cdef 100644 --- a/src/ca/cacIO.h +++ b/src/ca/cacIO.h @@ -15,134 +15,217 @@ * 505 665 1831 */ +// +// Open Issues +// ----------- +// +// 1) A status code from the old client side interface is passed +// to the exception notify callback. Should we just pass a string? +// If so, then how do they detect the type of error and recover. +// +// 2) Some exception types are present here but there is no common +// exception base class in use. +// +// 3) Should I be passing the channel reference in cacChannelNotify? +// +// 4) Should the code for caAccessRights not be inline so that this +// interface is version independent. +// +// #include "tsDLList.h" #include "epicsMutex.h" #include "shareLib.h" -struct cacChannelIO; -struct cacNotifyIO; +class cacChannel; -// in the future we should probably not include the type and the count in this interface +// this should not be passing caerr.h status to the exception callback class epicsShareClass cacNotify { public: virtual ~cacNotify () = 0; - virtual void release () = 0; - virtual void completionNotify ( cacChannelIO & ); - virtual void completionNotify ( cacChannelIO &, unsigned type, - unsigned long count, const void *pData ); - virtual void exceptionNotify ( cacChannelIO &, - int status, const char *pContext ); - virtual void exceptionNotify ( cacChannelIO &, - int status, const char *pContext, unsigned type, unsigned long count ); + virtual void completion () = 0; + virtual void exception ( int status, const char *pContext ) = 0; }; -// this name is probably poor -struct epicsShareClass cacNotifyIO { +// 1) this should not be passing caerr.h status to the exception callback +// 2) obviously the data should be passed here using the new data access API +class epicsShareClass cacDataNotify { public: - cacNotifyIO ( cacNotify & ); - cacNotify & notify () const; - virtual void cancel () = 0; - virtual void show ( unsigned level ) const = 0; - // the following commits us to deleting the IO when the channel is deleted :-( - virtual cacChannelIO & channelIO () const = 0; -protected: - virtual ~cacNotifyIO () = 0; + virtual ~cacDataNotify () = 0; + virtual void completion ( unsigned type, + unsigned long count, const void *pData ) = 0; + virtual void exception ( int status, + const char *pContext, unsigned type, unsigned long count ) = 0; +}; + +class caAccessRights { +public: + caAccessRights ( + bool readPermit = false, + bool writePermit = false, + bool operatorConfirmationRequest = false); + void setReadPermit (); + void setWritePermit (); + void setOperatorConfirmationRequest (); + void clrReadPermit (); + void clrWritePermit (); + void clrOperatorConfirmationRequest (); + bool readPermit () const; + bool writePermit () const; + bool operatorConfirmationRequest () const; private: - cacNotify &callback; + unsigned f_readPermit:1; + unsigned f_writePermit:1; + unsigned f_operatorConfirmationRequest:1; }; class epicsShareClass cacChannelNotify { public: virtual ~cacChannelNotify () = 0; - virtual void release () = 0; - virtual void connectNotify ( cacChannelIO & ); - virtual void disconnectNotify ( cacChannelIO & ); - virtual void accessRightsNotify ( cacChannelIO &, const caar & ); - virtual void exceptionNotify ( cacChannelIO &, int status, const char *pContext ); - // not for public consumption +// is it useful to pass the channel IO here ????? + virtual void connectNotify ( cacChannel & ); + virtual void disconnectNotify ( cacChannel & ); + virtual void accessRightsNotify ( cacChannel &, const caAccessRights & ); + virtual void exception ( cacChannel &, int status, const char *pContext ); + // not for public consumption -- can we get rid of this virtual bool includeFirstConnectInCountOfOutstandingIO () const; - virtual class oldChannelNotify * pOldChannelNotify (); }; // // Notes -// 1) these routines should be changed to throw exceptions and not return -// ECA_XXXX style status in the future. +// 1) This interface assumes that when a channel is deleted then all +// attached IO is deleted. This is left over from the old interface, +// but perhaps is a bad practce that should be eliminated? If so, +// then the IO should not store or use a pointer to the channel. // -struct epicsShareClass cacChannelIO { +class epicsShareClass cacChannel { public: - cacChannelIO ( cacChannelNotify & ); + typedef unsigned ioid; + enum ioStatus { iosSynch, iosAsynch }; + + cacChannel ( cacChannelNotify & ); cacChannelNotify & notify () const; - virtual ~cacChannelIO () = 0; + virtual ~cacChannel () = 0; virtual const char *pName () const = 0; virtual void show ( unsigned level ) const = 0; virtual void initiateConnect () = 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, cacNotifyIO *& ) = 0; + virtual void write ( unsigned type, unsigned long count, + const void *pValue ) = 0; + virtual ioStatus read ( unsigned type, unsigned long count, + cacDataNotify &, ioid * = 0 ) = 0; + virtual ioStatus write ( unsigned type, unsigned long count, + const void *pValue, cacNotify &, ioid * = 0 ) = 0; + virtual void subscribe ( unsigned type, unsigned long count, + unsigned mask, cacDataNotify &, ioid * = 0 ) = 0; + virtual void ioCancel ( const ioid & ) = 0; + virtual void ioShow ( const ioid &, unsigned level ) const = 0; virtual short nativeType () const = 0; virtual unsigned long nativeElementCount () const = 0; - virtual channel_state state () const; // defaults to always connected - virtual caar accessRights () const; // defaults to unrestricted access + virtual caAccessRights 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 void hostName (char *pBuf, unsigned bufLength) const; // defaults to local host name - virtual const char * pHostName () const; // deprecated - please do not use - virtual void notifyStateChangeFirstConnectInCountOfOutstandingIO (); // deprecated - please do not use + virtual bool previouslyConnected () const; // defaults to true + virtual void hostName ( char *pBuf, unsigned bufLength ) const; // defaults to local host name + + virtual const char * pHostName () const; + virtual void notifyStateChangeFirstConnectInCountOfOutstandingIO (); + + // exceptions + class badString {}; + class badType {}; + class outOfBounds {}; + class badEventSelection {}; + class noWriteAccess {}; + class noReadAccess {}; + class notConnected {}; + class unsupportedByService {}; + class noMemory {}; + private: cacChannelNotify & callback; }; -struct cacServiceIO : public tsDLNode < cacServiceIO > { +struct cacService : public tsDLNode < cacService > { public: - virtual cacChannelIO *createChannelIO ( + virtual cacChannel * createChannel ( const char *pName, cacChannelNotify & ) = 0; virtual void show ( unsigned level ) const = 0; }; class cacServiceList { public: - epicsShareFunc void registerService ( cacServiceIO &service ); - epicsShareFunc cacChannelIO * createChannelIO ( + epicsShareFunc void registerService ( cacService &service ); + epicsShareFunc cacChannel * createChannel ( const char *pName, cacChannelNotify & ); epicsShareFunc void show ( unsigned level ) const; private: - tsDLList < cacServiceIO > services; + tsDLList < cacService > services; mutable epicsMutex mutex; }; epicsShareExtern cacServiceList cacGlobalServiceList; -epicsShareFunc int epicsShareAPI ca_register_service ( struct cacServiceIO *pService ); +epicsShareFunc int epicsShareAPI ca_register_service ( struct cacService *pService ); -inline cacNotifyIO::cacNotifyIO ( cacNotify ¬ify ) : +inline cacChannel::cacChannel ( cacChannelNotify ¬ify ) : callback ( notify ) { } -inline cacNotify & cacNotifyIO::notify () const +inline cacChannelNotify & cacChannel::notify () const { return this->callback; } -inline cacChannelIO::cacChannelIO ( cacChannelNotify ¬ify ) : - callback ( notify ) +inline caAccessRights::caAccessRights ( + bool readPermit, bool writePermit, bool operatorConfirmationRequest) : + f_readPermit ( readPermit ), f_writePermit ( writePermit ), + f_operatorConfirmationRequest ( operatorConfirmationRequest ) {} + +inline void caAccessRights::setReadPermit () { + this->f_readPermit = true; } -inline cacChannelNotify & cacChannelIO::notify () const +inline void caAccessRights::setWritePermit () { - return this->callback; + this->f_writePermit = true; } +inline void caAccessRights::setOperatorConfirmationRequest () +{ + this->f_operatorConfirmationRequest = true; +} + +inline void caAccessRights::clrReadPermit () +{ + this->f_readPermit = false; +} + +inline void caAccessRights::clrWritePermit () +{ + this->f_writePermit = false; +} + +inline void caAccessRights::clrOperatorConfirmationRequest () +{ + this->f_operatorConfirmationRequest = false; +} + +inline bool caAccessRights::readPermit () const +{ + return this->f_readPermit; +} + +inline bool caAccessRights::writePermit () const +{ + return this->f_writePermit; +} + +inline bool caAccessRights::operatorConfirmationRequest () const +{ + return this->f_operatorConfirmationRequest; +} diff --git a/src/ca/cacNotify.cpp b/src/ca/cacNotify.cpp index 99737c55c..7dff1b791 100644 --- a/src/ca/cacNotify.cpp +++ b/src/ca/cacNotify.cpp @@ -15,29 +15,3 @@ cacNotify::~cacNotify () { } - -void cacNotify::completionNotify ( cacChannelIO &chan ) -{ - ca_printf ( "CAC: IO completion for channel %s with no handler installed?\n", - chan.pName () ); -} - -void cacNotify::completionNotify ( cacChannelIO &chan, - unsigned type, unsigned long count, const void *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 ( cacChannelIO &chan, int status, const char *pContext ) -{ - ca_signal_formated ( status, __FILE__, __LINE__, "%s channel=%s\n", - pContext, chan.pName () ); -} - -void cacNotify::exceptionNotify ( cacChannelIO &chan, int status, - const char *pContext, unsigned type, unsigned long 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/cacServiceList.cpp b/src/ca/cacServiceList.cpp index 5ce0c863e..57312def4 100644 --- a/src/ca/cacServiceList.cpp +++ b/src/ca/cacServiceList.cpp @@ -19,21 +19,21 @@ epicsShareDef cacServiceList cacGlobalServiceList; -void cacServiceList::registerService ( cacServiceIO &service ) +void cacServiceList::registerService ( cacService &service ) { epicsAutoMutex locker ( this->mutex ); this->services.add ( service ); } -cacChannelIO * cacServiceList::createChannelIO ( +cacChannel * cacServiceList::createChannel ( const char *pName, cacChannelNotify &chan ) { - cacChannelIO *pChanIO = 0; + cacChannel *pChanIO = 0; epicsAutoMutex locker ( this->mutex ); - tsDLIterBD < cacServiceIO > iter = this->services.firstIter (); + tsDLIterBD < cacService > iter = this->services.firstIter (); while ( iter.valid () ) { - pChanIO = iter->createChannelIO ( pName, chan ); + pChanIO = iter->createChannel ( pName, chan ); if ( pChanIO ) { break; } @@ -46,7 +46,7 @@ cacChannelIO * cacServiceList::createChannelIO ( void cacServiceList::show ( unsigned level ) const { epicsAutoMutex locker ( this->mutex ); - tsDLIterConstBD < cacServiceIO > iter = this->services.firstIter (); + tsDLIterConstBD < cacService > iter = this->services.firstIter (); while ( iter.valid () ) { iter->show ( level ); iter++; diff --git a/src/ca/cac_IL.h b/src/ca/cac_IL.h index 53e08cda9..bdd29bcb4 100644 --- a/src/ca/cac_IL.h +++ b/src/ca/cac_IL.h @@ -66,11 +66,10 @@ inline unsigned cac::sequenceNumberOfOutstandingIO () const return this->ioCounter.sequenceNumber (); } -inline epicsMutex & cac::mutex () +inline epicsMutex & cac::mutexRef () { - return this->defaultMutex; + return this->mutex; } - #endif // cac_ILh diff --git a/src/ca/cadef.h b/src/ca/cadef.h index a6c9b2fb5..81d26f8f4 100644 --- a/src/ca/cadef.h +++ b/src/ca/cadef.h @@ -47,10 +47,10 @@ extern "C" { #endif -typedef struct cacChannelIO *chid; +typedef struct oldChannelNotify *chid; typedef chid chanId; /* for when the structures field name is "chid" */ typedef long chtype; -typedef struct cacNotifyIO *evid; +typedef struct oldSubscription *evid; typedef double ca_real; /* Format for the arguments to user connection handlers */ diff --git a/src/ca/caerr.h b/src/ca/caerr.h index 324063bc6..973b4a7c4 100644 --- a/src/ca/caerr.h +++ b/src/ca/caerr.h @@ -115,6 +115,7 @@ #define ECA_BADCHID DEFMSG(CA_K_ERROR, 51) #define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52) #define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 53) +#define ECA_NOTINSERVICE DEFMSG(CA_K_WARNING, 54) #ifndef CA_ERROR_GLBLSOURCE epicsShareExtern READONLY char *ca_message_text[]; @@ -175,7 +176,8 @@ READONLY char *ca_message_text[] "Data conversion between client's type and the server's type failed", "Invalid channel identifier", "Invalid function pointer", -"Thread is already attached to a client context" +"Thread is already attached to a client context", +"No support in service", }; #endif diff --git a/src/ca/comQueSend.cpp b/src/ca/comQueSend.cpp index a26a9b4ac..7e77be8e0 100644 --- a/src/ca/comQueSend.cpp +++ b/src/ca/comQueSend.cpp @@ -90,7 +90,7 @@ void comQueSend::clear () // to the que while some other thread is flushing // and therefore prevents deadlocks, and it also // allows proper status to be returned) -int comQueSend::reserveSpace ( unsigned msgSize ) +void comQueSend::reserveSpace ( unsigned msgSize ) { unsigned bytesReserved; @@ -102,15 +102,9 @@ int comQueSend::reserveSpace ( unsigned msgSize ) } while ( bytesReserved < msgSize ) { - if ( reservoir.addOneBuffer () ) { - bytesReserved += comBuf::capacityBytes (); - } - else { - return ECA_ALLOCMEM; - } + reservoir.addOneBuffer (); + bytesReserved += comBuf::capacityBytes (); } - - return ECA_NORMAL; } void comQueSend::copy_dbr_string ( const void *pValue, unsigned nElem ) diff --git a/src/ca/comQueSend_IL.h b/src/ca/comQueSend_IL.h index e27ba5684..0f38196e5 100644 --- a/src/ca/comQueSend_IL.h +++ b/src/ca/comQueSend_IL.h @@ -18,6 +18,8 @@ #ifndef comQueSend_ILh #define comQueSend_ILh +#include + #include "comBuf_IL.h" inline bufferReservoir::~bufferReservoir () @@ -30,16 +32,13 @@ inline comBuf *bufferReservoir::fetchOneBuffer () return this->reservedBufs.get (); } -inline bool bufferReservoir::addOneBuffer () +inline void bufferReservoir::addOneBuffer () { comBuf *pBuf = new comBuf; - if ( pBuf ) { - this->reservedBufs.add ( *pBuf ); - return true; - } - else { - return false; + if ( ! pBuf ) { + throw std::bad_alloc(); } + this->reservedBufs.add ( *pBuf ); } inline unsigned bufferReservoir::nBytes () diff --git a/src/ca/getCallback.cpp b/src/ca/getCallback.cpp index 026a38364..7af0439cf 100644 --- a/src/ca/getCallback.cpp +++ b/src/ca/getCallback.cpp @@ -21,58 +21,42 @@ tsFreeList < class getCallback, 1024 > getCallback::freeList; epicsMutex getCallback::freeListMutex; +getCallback::getCallback ( oldChannelNotify &chanIn, + caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : + chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +{ +} + getCallback::~getCallback () { } -void getCallback::release () -{ - delete this; -} - -// eliminates SUN PRO warning -void getCallback::completionNotify ( cacChannelIO &io ) -{ - this->cacNotify::completionNotify ( io ); -} - -void getCallback::completionNotify ( cacChannelIO &io, +void getCallback::completion ( unsigned type, unsigned long count, const void *pData ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = & io; + args.chid = &this->chan; args.type = type; args.count = count; args.status = ECA_NORMAL; args.dbr = pData; ( *this->pFunc ) ( args ); + delete this; } -void getCallback::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 getCallback::exceptionNotify ( cacChannelIO &io, +void getCallback::exception ( int status, const char * /* pContext */, unsigned type, unsigned long count ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = & io; + args.chid = &this->chan; args.type = type; args.count = count; args.status = status; args.dbr = 0; ( *this->pFunc ) ( args ); + delete this; } diff --git a/src/ca/getCopy.cpp b/src/ca/getCopy.cpp index 9644f9411..99884d58b 100644 --- a/src/ca/getCopy.cpp +++ b/src/ca/getCopy.cpp @@ -34,17 +34,7 @@ getCopy::~getCopy () { } -void getCopy::release () -{ - delete this; -} - -void getCopy::completionNotify ( cacChannelIO &io ) -{ - this->cacNotify::completionNotify ( io ); -} - -void getCopy::completionNotify ( cacChannelIO &chan, unsigned typeIn, +void getCopy::completion ( unsigned typeIn, unsigned long countIn, const void *pDataIn ) { if ( this->type == typeIn ) { @@ -52,22 +42,19 @@ void getCopy::completionNotify ( cacChannelIO &chan, unsigned typeIn, this->cacCtx.decrementOutstandingIO ( this->readSeq ); } else { - this->exceptionNotify ( chan, ECA_INTERNAL, - "bad data type match in get copy back response" ); + this->exception ( ECA_INTERNAL, + "bad data type match in get copy back response", + typeIn, countIn); } + delete this; } - -void getCopy::exceptionNotify ( cacChannelIO &chan, - int status, const char *pContext ) -{ - this->cacNotify::exceptionNotify ( chan, status, pContext ); -} - -void getCopy::exceptionNotify ( cacChannelIO &chan, +void getCopy::exception ( int status, const char *pContext, unsigned typeIn, unsigned long countIn ) { - this->cacNotify::exceptionNotify ( chan, status, pContext, typeIn, countIn ); + this->cacCtx.exception ( status, pContext, typeIn, + countIn, __FILE__, __LINE__ ); + delete this; } void getCopy::show ( unsigned level ) const diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h index a84215c61..1b5341506 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -153,7 +153,7 @@ struct msgDescriptor { class bufferReservoir { public: ~bufferReservoir (); - bool addOneBuffer (); + void addOneBuffer (); comBuf *fetchOneBuffer (); unsigned nBytes (); void drain (); @@ -166,7 +166,7 @@ public: comQueSend ( wireSendAdapter & ); ~comQueSend (); void clear (); - int reserveSpace ( unsigned msgSize ); + void reserveSpace ( unsigned msgSize ); unsigned occupiedBytes () const; bool flushEarlyThreshold ( unsigned nBytesThisMsg ) const; bool flushBlockThreshold ( unsigned nBytesThisMsg ) const; @@ -209,9 +209,9 @@ private: class caClient { public: - virtual void exceptionNotify (int status, const char *pContext, + virtual void exception (int status, const char *pContext, const char *pFileName, unsigned lineNo) = 0; - virtual void exceptionNotify (int status, const char *pContext, + virtual void exception (int status, const char *pContext, unsigned type, unsigned long count, const char *pFileName, unsigned lineNo) = 0; }; @@ -220,35 +220,31 @@ class netiiu; class tcpiiu; class baseNMIU; -// -// fields in class nciu which really belong to tcpiiu -// class cacPrivateListOfIO { private: tsDLList < class baseNMIU > eventq; friend class cac; }; -class nciu : public cacChannelIO, public tsDLNode < nciu >, +class nciu : public cacChannel, public tsDLNode < nciu >, public chronIntIdRes < nciu >, public cacPrivateListOfIO { public: nciu ( class cac &, netiiu &, cacChannelNotify &, const char *pNameIn ); - bool fullyConstructed () const; void connect ( unsigned nativeType, unsigned long nativeCount, unsigned sid ); void connect (); void disconnect ( netiiu &newiiu ); bool searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisChannel ); - int createChannelRequest (); + void createChannelRequest (); bool isAttachedToVirtaulCircuit ( const osiSockAddr & ); bool identifierEquivelence ( unsigned idToMatch ); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); void resetRetryCount (); unsigned getRetrySeqNo () const; - void accessRightsStateChange ( const caar &arIn ); + void accessRightsStateChange ( const caAccessRights & ); ca_uint32_t getSID () const; ca_uint32_t getCID () const; netiiu * getPIIU (); @@ -262,11 +258,12 @@ public: const char * pHostName () const; // deprecated - please do not use unsigned long nativeElementCount () const; bool connected () const; + bool previouslyConnected () const; protected: ~nciu (); // force pool allocation private: cac &cacCtx; - caar accessRightState; + caAccessRights accessRightState; unsigned count; char *pNameStr; netiiu *piiu; @@ -276,45 +273,54 @@ private: unsigned short nameLength; // channel name length unsigned short typeCode; unsigned f_connected:1; - unsigned f_fullyConstructed:1; unsigned f_previousConn:1; // T if connected in the past unsigned f_claimSent:1; unsigned f_firstConnectDecrementsOutstandingIO:1; unsigned f_connectTimeOutSeen:1; void initiateConnect (); - int read ( unsigned type, - unsigned long count, cacNotify ¬ify ); - int write ( unsigned type, - unsigned long count, const void *pValue ); - int write ( unsigned type, - unsigned long count, const void *pValue, cacNotify & ); - int subscribe ( unsigned type, unsigned long nElem, - unsigned mask, cacNotify ¬ify, - cacNotifyIO *&pNotifyIO ); + ioStatus read ( unsigned type, unsigned long count, + cacDataNotify &, ioid * ); + void write ( unsigned type, unsigned long count, + const void *pValue ); + ioStatus write ( unsigned type, unsigned long count, + const void *pValue, cacNotify &, ioid * ); + void subscribe ( unsigned type, unsigned long nElem, + unsigned mask, cacDataNotify ¬ify, ioid * ); + void ioCancel ( const ioid & ); + void ioShow ( const ioid &, unsigned level ) const; short nativeType () const; - channel_state state () const; - caar accessRights () const; + caAccessRights accessRights () const; unsigned searchAttempts () const; double beaconPeriod () const; bool ca_v42_ok () const; void hostName ( char *pBuf, unsigned bufLength ) const; void notifyStateChangeFirstConnectInCountOfOutstandingIO (); + static void stringVerify ( const char *pStr, const unsigned count ); static tsFreeList < class nciu, 1024 > freeList; static epicsMutex freeListMutex; }; -class baseNMIU : public cacNotifyIO, public tsDLNode < baseNMIU >, +class baseNMIU : public tsDLNode < baseNMIU >, public chronIntIdRes < baseNMIU > { public: - baseNMIU ( cacNotify ¬ifyIn, nciu &chan ); + baseNMIU ( nciu &chan ); virtual class netSubscription * isSubscription (); 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 completion ( unsigned type, + unsigned long count, const void *pData ) = 0; + virtual void exception ( int status, + const char *pContext, unsigned type, unsigned long count ) = 0; void show ( unsigned level ) const; ca_uint32_t getID () const; nciu & channel () const; - cacChannelIO & channelIO () const; protected: virtual ~baseNMIU () = 0; +// +// perhpas we should not store the channel here and instead fetch it out of the +// notify +// nciu &chan; }; @@ -323,21 +329,27 @@ public: static netSubscription * factory ( tsFreeList < class netSubscription, 1024 > &, nciu &chan, unsigned type, unsigned long count, - unsigned mask, cacNotify ¬ify ); + unsigned mask, cacDataNotify ¬ify ); void show ( unsigned level ) const; - unsigned long getCount () const; + unsigned long getCount ( nciu & ) const; unsigned getType () const; unsigned getMask () const; - void destroy ( cacRecycle & ); + void destroy ( class cacRecycle & ); + void completion (); + void exception ( int status, const char *pContext ); + void completion ( unsigned type, + unsigned long count, const void *pData ); + void exception ( int status, + const char *pContext, unsigned type, unsigned long count ); protected: + ~netSubscription (); private: const unsigned long count; + cacDataNotify ¬ify; const unsigned type; const unsigned mask; netSubscription ( nciu &chan, unsigned type, unsigned long count, - unsigned mask, cacNotify ¬ify ); - ~netSubscription (); - void cancel (); + unsigned mask, cacDataNotify ¬ify ); class netSubscription * isSubscription (); void * operator new ( size_t, tsFreeList < class netSubscription, 1024 > & ); @@ -351,13 +363,20 @@ class netReadNotifyIO : public baseNMIU { public: static netReadNotifyIO * factory ( tsFreeList < class netReadNotifyIO, 1024 > &, - nciu &chan, cacNotify ¬ify ); + nciu &chan, cacDataNotify ¬ify ); void show ( unsigned level ) const; - void destroy ( cacRecycle & ); -private: - netReadNotifyIO ( nciu &chan, cacNotify ¬ify ); + void destroy ( class cacRecycle & ); + void completion (); + void exception ( int status, const char *pContext ); + void completion ( unsigned type, + unsigned long count, const void *pData ); + void exception ( int status, + const char *pContext, unsigned type, unsigned long count ); +protected: ~netReadNotifyIO (); - void cancel (); +private: + cacDataNotify ¬ify; + netReadNotifyIO ( nciu &chan, cacDataNotify ¬ify ); void * operator new ( size_t, tsFreeList < class netReadNotifyIO, 1024 > & ); # if ! defined ( NO_PLACEMENT_DELETE ) @@ -372,11 +391,18 @@ public: tsFreeList < class netWriteNotifyIO, 1024 > &, nciu &chan, cacNotify ¬ify ); void show ( unsigned level ) const; - void destroy ( cacRecycle & ); -private: - netWriteNotifyIO ( nciu &chan, cacNotify ¬ify ); + void destroy ( class cacRecycle & ); + void completion (); + void exception ( int status, const char *pContext ); + void completion ( unsigned type, + unsigned long count, const void *pData ); + void exception ( int status, + const char *pContext, unsigned type, unsigned long count ); +protected: ~netWriteNotifyIO (); - void cancel (); +private: + cacNotify ¬ify; + netWriteNotifyIO ( nciu &chan, cacNotify ¬ify ); void * operator new ( size_t, tsFreeList < class netWriteNotifyIO, 1024 > & ); # if ! defined ( NO_PLACEMENT_DELETE ) @@ -449,15 +475,15 @@ public: virtual bool ca_v42_ok () const; virtual bool ca_v41_ok () const; virtual bool pushDatagramMsg ( const caHdr &hdr, const void *pExt, ca_uint16_t extsize); - virtual int writeRequest ( nciu &, unsigned type, unsigned nElem, const void *pValue); - virtual int writeNotifyRequest ( nciu &, netWriteNotifyIO &, unsigned type, unsigned nElem, const void *pValue ); - virtual int readNotifyRequest ( nciu &, netReadNotifyIO &, unsigned type, unsigned nElem ); - virtual int createChannelRequest ( nciu & ); + virtual void writeRequest ( nciu &, unsigned type, unsigned nElem, const void *pValue ); + virtual void writeNotifyRequest ( nciu &, netWriteNotifyIO &, unsigned type, unsigned nElem, const void *pValue ); + virtual void readNotifyRequest ( nciu &, netReadNotifyIO &, unsigned type, unsigned nElem ); + virtual void createChannelRequest ( nciu & ); virtual void connectAllIO ( nciu &chan ); virtual void disconnectAllIO ( nciu &chan ); - virtual int clearChannelRequest ( nciu & ); - virtual void subscriptionRequest ( netSubscription &subscr ); - virtual void subscriptionCancelRequest ( netSubscription &subscr ); + virtual void clearChannelRequest ( nciu & ); + virtual void subscriptionRequest ( nciu &, netSubscription &subscr ); + virtual void subscriptionCancelRequest ( nciu &, netSubscription &subscr ); virtual double beaconPeriod () const; virtual void flushRequest (); virtual bool flushBlockThreshold () const; @@ -541,6 +567,9 @@ public: // exceptions class noSocket {}; class noMemory {}; + + void fdCreateNotify ( CAFDHANDLER *func, void *pArg ); + void fdDestroyNotify ( CAFDHANDLER *func, void *pArg ); private: char xmitBuf [MAX_UDP_SEND]; char recvBuf [MAX_UDP_RECV]; @@ -585,7 +614,6 @@ public: void connectNotify (); void cancel (); void show ( unsigned level ) const; - private: const double period; epicsTimer &timer; @@ -655,8 +683,8 @@ public: bool initiateConnect ( const osiSockAddr &addrIn, unsigned minorVersion, class bhe &bhe, ipAddrToAsciiEngine &engineIn ); void connect (); - void disconnect (); - void suicide (); + void processIncoming (); + void destroy (); void cleanShutdown (); void forcedShutdown (); void beaconAnomalyNotify (); @@ -670,7 +698,6 @@ public: virtual void show ( unsigned level ) const; bool setEchoRequestPending (); - void processIncoming (); bool ca_v41_ok () const; bool ca_v42_ok () const; bool ca_v44_ok () const; @@ -681,6 +708,9 @@ public: bool alive () const; double beaconPeriod () const; bhe * getBHE () const; + + void fdCreateNotify ( epicsMutex &mutex, CAFDHANDLER *func, void *pArg ); + void fdDestroyNotify ( CAFDHANDLER *func, void *pArg ); private: tcpRecvWatchdog recvDog; tcpSendWatchdog sendDog; @@ -720,38 +750,21 @@ private: void lastChannelDetachNotify (); // send protocol stubs - int echoRequest (); - int noopRequest (); - int disableFlowControlRequest (); - int enableFlowControlRequest (); - int hostNameSetRequest (); - int userNameSetRequest (); - int writeRequest ( nciu &, unsigned type, unsigned nElem, const void *pValue ); - int writeNotifyRequest ( nciu &, netWriteNotifyIO &, unsigned type, unsigned nElem, const void *pValue ); - int readNotifyRequest ( nciu &, netReadNotifyIO &, unsigned type, unsigned nElem ); - int createChannelRequest ( nciu & ); - int clearChannelRequest ( nciu & ); - void subscriptionRequest ( netSubscription &subscr ); - void subscriptionCancelRequest ( netSubscription &subscr ); - - // recv protocol stubs - bool noopAction (); - bool echoRespAction (); - bool writeNotifyRespAction (); - bool readNotifyRespAction (); - bool eventRespAction (); - bool readRespAction (); - bool clearChannelRespAction (); - bool exceptionRespAction (); - bool accessRightsRespAction (); - bool claimCIURespAction (); - bool verifyAndDisconnectChan (); - bool badTCPRespAction (); + void echoRequest (); + void noopRequest (); + void disableFlowControlRequest (); + void enableFlowControlRequest (); + void hostNameSetRequest (); + void userNameSetRequest (); + void writeRequest ( nciu &, unsigned type, unsigned nElem, const void *pValue ); + void writeNotifyRequest ( nciu &, netWriteNotifyIO &, unsigned type, unsigned nElem, const void *pValue ); + void readNotifyRequest ( nciu &, netReadNotifyIO &, unsigned type, unsigned nElem ); + void createChannelRequest ( nciu & ); + void clearChannelRequest ( nciu & ); + void subscriptionRequest ( nciu &, netSubscription &subscr ); + void subscriptionCancelRequest ( nciu &, netSubscription &subscr ); bool flush (); // only to be called by the send thread - - typedef bool ( tcpiiu::*pProtoStubTCP ) (); - static const pProtoStubTCP tcpJumpTableCAC []; }; class inetAddrID { @@ -839,60 +852,107 @@ private: static const unsigned CASG_MAGIC = 0xFAB4CAFE; -class syncGroupNotify : public cacNotify, public tsDLNode < syncGroupNotify > { +// used to control access to CASG's recycle routines which +// should only be indirectly invoked by CASG when its lock +// is applied +class casgRecycle { public: - syncGroupNotify ( struct CASG &sgIn, void *pValue ); - void release (); - void show ( unsigned level ) 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; - static epicsMutex freeListMutex; + virtual void recycleSyncGroupWriteNotify ( class syncGroupWriteNotify &io ) = 0; + virtual void recycleSyncGroupReadNotify ( class syncGroupReadNotify &io ) = 0; }; -/* - * one per synch group - */ -struct CASG : public chronIntIdRes < CASG > { +class syncGroupNotify : public tsDLNode < syncGroupNotify > { +public: + syncGroupNotify ( struct CASG &sgIn, chid ); + virtual void destroy ( casgRecycle & ) = 0; + void show ( unsigned level ) const; +protected: + chid chan; + struct CASG &sg; + const unsigned magic; + cacChannel::ioid id; + bool idIsValid; + ~syncGroupNotify (); +}; + +class syncGroupReadNotify : public syncGroupNotify, public cacDataNotify { +public: + static syncGroupReadNotify * factory ( + tsFreeList < class syncGroupReadNotify, 128 > &, + struct CASG &, chid, unsigned type, + unsigned long count, void *pValueIn ); + void destroy ( casgRecycle & ); + void show ( unsigned level ) const; +protected: + virtual ~syncGroupReadNotify (); +private: + void *pValue; + syncGroupReadNotify ( struct CASG &sgIn, chid, + unsigned type, unsigned long count, void *pValueIn ); + void * operator new ( size_t, + tsFreeList < class syncGroupReadNotify, 128 > & ); +# if ! defined ( NO_PLACEMENT_DELETE ) + void operator delete ( void *, size_t, + tsFreeList < class syncGroupReadNotify, 128 > & ); +# endif + void completion ( + unsigned type, unsigned long count, const void *pData ); + void exception ( + int status, const char *pContext, unsigned type, unsigned long count ); +}; + +class syncGroupWriteNotify : public syncGroupNotify, public cacNotify { +public: + static syncGroupWriteNotify * factory ( + tsFreeList < class syncGroupWriteNotify, 128 > &, + struct CASG &, chid, unsigned type, + unsigned long count, const void *pValueIn ); + void destroy ( casgRecycle & ); + void show ( unsigned level ) const; +protected: + virtual ~syncGroupWriteNotify (); // allocate only from pool +private: + void *pValue; + syncGroupWriteNotify ( struct CASG &, chid, unsigned type, + unsigned long count, const void *pValueIn ); + void * operator new ( size_t, + tsFreeList < class syncGroupWriteNotify, 128 > & ); +# if ! defined ( NO_PLACEMENT_DELETE ) + void operator delete ( void *, size_t, + tsFreeList < class syncGroupWriteNotify, 128 > & ); +# endif + void completion (); + void exception (int status, const char *pContext ); +}; + +struct CASG : public chronIntIdRes < CASG >, private casgRecycle { public: CASG (cac &cacIn); + bool ioComplete () const; void destroy (); bool verify () const; - bool ioComplete () const; int block ( double timeout ); void reset (); void show ( unsigned level ) const; int get ( chid pChan, unsigned type, unsigned long count, void *pValue ); int put ( chid pChan, unsigned type, unsigned long count, const void *pValue ); + void destroyIO ( syncGroupNotify & ); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); +protected: + ~CASG (); private: + tsDLList < syncGroupNotify > ioList; epicsMutex mutable mutex; epicsEvent sem; - tsDLList < syncGroupNotify > ioList; - unsigned long opPendCount; - unsigned long seqNo; cac &client; unsigned magic; - ~CASG (); + tsFreeList < class syncGroupReadNotify, 128 > freeListReadOP; + tsFreeList < class syncGroupWriteNotify, 128 > freeListWriteOP; + void recycleSyncGroupWriteNotify ( syncGroupWriteNotify &io ); + void recycleSyncGroupReadNotify ( syncGroupReadNotify &io ); static tsFreeList < struct CASG, 128 > freeList; static epicsMutex freeListMutex; - friend class syncGroupNotify; }; class ioCounterNet { @@ -914,7 +974,7 @@ private: }; // used to control access to cac's recycle routines which -// should only be indirectly invoked by CAC whenits lock +// should only be indirectly invoked by CAC when its lock // is applied class cacRecycle { public: @@ -923,13 +983,20 @@ public: virtual void recycleSubscription ( netSubscription &io ) = 0; }; -// -// If multiple lock are applied simultaneously then they -// must be applied in this order to avoid deadlocks -// -// cac::iiuListMutex -// cac::defaultMutex: -// +template < class T > +class autoPtrRecycle { +public: + autoPtrRecycle ( cacRecycle &, T * ); + ~autoPtrRecycle (); + T & operator * () const; + T * operator -> () const; + T * get () const; + T * release (); +private: + T *p; + cacRecycle &r; +}; + class cac : public caClient, private cacRecycle { public: @@ -955,30 +1022,17 @@ public: void flushRequest (); int pendIO ( const double &timeout ); int pendEvent ( const double &timeout ); - bool ioCompletionNotify ( unsigned id, unsigned type, - unsigned long count, const void *pData ); - bool ioExceptionNotify ( unsigned id, - int status, const char *pContext ); - bool ioExceptionNotify ( unsigned id, int status, - const char *pContext, unsigned type, unsigned long count ); - bool ioCompletionNotifyAndDestroy ( unsigned id ); - bool ioCompletionNotifyAndDestroy ( unsigned id, - unsigned type, unsigned long count, const void *pData ); - bool ioExceptionNotifyAndDestroy ( unsigned id, - int status, const char *pContext ); - bool ioExceptionNotifyAndDestroy ( unsigned id, - int status, const char *pContext, unsigned type, unsigned long count ); void connectAllIO ( nciu &chan ); void disconnectAllIO ( nciu &chan ); void destroyAllIO ( nciu &chan ); - void destroyReadNotifyIO ( netReadNotifyIO &io ); - void destroyWriteNotifyIO ( netWriteNotifyIO &io ); - void destroySubscription ( netSubscription &io ); + void executeResponse ( tcpiiu &, caHdr &, char *pMshBody ); + void ioCancel ( nciu &chan, const cacChannel::ioid &id ); + void ioShow ( const cacChannel::ioid &id, unsigned level ) const; // exception routines - void exceptionNotify ( int status, const char *pContext, + void exception ( int status, const char *pContext, const char *pFileName, unsigned lineNo ); - void exceptionNotify ( int status, const char *pContext, + void exception ( int status, const char *pContext, unsigned type, unsigned long count, const char *pFileName, unsigned lineNo ); void changeExceptionEvent ( caExceptionHandler *pfunc, void *arg ); @@ -986,24 +1040,23 @@ public: // channel routines bool connectChannel ( unsigned id ); - bool connectChannel ( bool v44Ok, unsigned id, - unsigned nativeType, unsigned long nativeCount, unsigned sid ); - void disconnectChannel ( unsigned id ); void installNetworkChannel ( nciu &, netiiu *&piiu ); bool lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid, unsigned typeCode, unsigned long count, unsigned minorVersionNumber, const osiSockAddr & ); - void accessRightsNotify ( unsigned id, const caar & ); void uninstallChannel ( nciu & ); - cacChannelIO * createChannelIO ( const char *name_str, cacChannelNotify &chan ); - void registerService ( cacServiceIO &service ); + cacChannel & createChannel ( const char *name_str, cacChannelNotify &chan ); + void registerService ( cacService &service ); // IO request stubs - int writeRequest ( nciu &, unsigned type, unsigned nElem, const void *pValue ); - int writeNotifyRequest ( nciu &, cacNotify &, unsigned type, unsigned nElem, const void *pValue ); - int readNotifyRequest ( nciu &, cacNotify &, unsigned type, unsigned nElem ); - cacNotifyIO * subscriptionRequest ( nciu &chan, unsigned type, unsigned long nElem, - unsigned mask, cacNotify ¬ify ); + void writeRequest ( nciu &, unsigned type, + unsigned nElem, const void *pValue ); + cacChannel::ioid writeNotifyRequest ( nciu &, unsigned type, + unsigned nElem, const void *pValue, cacNotify & ); + cacChannel::ioid readNotifyRequest ( nciu &, unsigned type, + unsigned nElem, cacDataNotify & ); + cacChannel::ioid subscriptionRequest ( nciu &, unsigned type, + unsigned long nElem, unsigned mask, cacDataNotify & ); // sync group routines CASG * lookupCASG ( unsigned id ); @@ -1012,7 +1065,6 @@ public: // fd call back registration void registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg ); - void getFDRegCallback ( CAFDHANDLER *&fdRegFunc, void *&fdRegArg ) const; // callback preemption control void enableCallbackPreemption (); @@ -1030,14 +1082,13 @@ public: const char * userNamePointer () const; unsigned getInitializingThreadsPriority () const; - epicsMutex & mutex (); + epicsMutex & mutexRef (); private: ioCounterNet ioCounter; ipAddrToAsciiEngine ipToAEngine; cacServiceList services; tsDLList iiuList; - tsDLList iiuListLimbo; chronIntIdResTable < nciu > chanTable; chronIntIdResTable @@ -1057,10 +1108,8 @@ private: freeListSubscription; epicsTime programBeginTime; double connTMO; - // defaultMutex can be applied if iiuListMutex is already applied - mutable epicsMutex defaultMutex; - // iiuListMutex must not be applied if defaultMutex is already applied - mutable epicsMutex iiuListMutex; + mutable epicsMutex mutex; + epicsEvent notifyCompletionEvent; epicsTimerQueueActive *pTimerQueue; caExceptionHandler *ca_exception_func; void *ca_exception_arg; @@ -1072,13 +1121,47 @@ private: udpiiu *pudpiiu; searchTimer *pSearchTmr; repeaterSubscribeTimer *pRepeaterSubscribeTmr; + unsigned ioNotifyInProgressId; unsigned initializingThreadsPriority; + unsigned threadsBlockingOnNotifyCompletion; bool enablePreemptiveCallback; + bool ioInProgress; bool setupUDP (); void flushIfRequired ( nciu & ); // lock must be applied void recycleReadNotifyIO ( netReadNotifyIO &io ); void recycleWriteNotifyIO ( netWriteNotifyIO &io ); void recycleSubscription ( netSubscription &io ); + + bool ioCompletionNotify ( unsigned id, unsigned type, + unsigned long count, const void *pData ); + bool ioExceptionNotify ( unsigned id, + int status, const char *pContext ); + bool ioExceptionNotify ( unsigned id, int status, + const char *pContext, unsigned type, unsigned long count ); + bool ioCompletionNotifyAndDestroy ( unsigned id ); + bool ioCompletionNotifyAndDestroy ( unsigned id, + unsigned type, unsigned long count, const void *pData ); + bool ioExceptionNotifyAndDestroy ( unsigned id, + int status, const char *pContext ); + bool ioExceptionNotifyAndDestroy ( unsigned id, + int status, const char *pContext, unsigned type, unsigned long count ); + + // recv protocol stubs + bool noopAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool echoRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool writeNotifyRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool readNotifyRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool eventRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool readRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool clearChannelRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool exceptionRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool accessRightsRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool claimCIURespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool verifyAndDisconnectChan ( tcpiiu &, const caHdr &, void *pMsgBdy ); + bool badTCPRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy ); + typedef bool ( cac::*pProtoStubTCP ) ( + tcpiiu &, const caHdr &, void *pMsgBdy ); + static const pProtoStubTCP tcpJumpTableCAC []; }; /* diff --git a/src/ca/nciu.cpp b/src/ca/nciu.cpp index a267597c9..8a9cc92fe 100644 --- a/src/ca/nciu.cpp +++ b/src/ca/nciu.cpp @@ -19,6 +19,8 @@ * lock. */ +#include + #include "iocinf.h" #include "nciu_IL.h" @@ -30,13 +32,10 @@ tsFreeList < class nciu, 1024 > nciu::freeList; epicsMutex nciu::freeListMutex; -static const caar defaultAccessRights = { false, false }; - nciu::nciu ( cac &cacIn, netiiu &iiuIn, cacChannelNotify &chanIn, const char *pNameIn ) : - cacChannelIO ( chanIn ), + cacChannel ( chanIn ), cacCtx ( cacIn ), - accessRightState ( defaultAccessRights ), count ( 0 ), piiu ( &iiuIn ), sid ( UINT_MAX ), @@ -45,7 +44,6 @@ nciu::nciu ( cac &cacIn, netiiu &iiuIn, cacChannelNotify &chanIn, nameLength ( strlen ( pNameIn ) + 1 ), typeCode ( USHRT_MAX ), f_connected ( false ), - f_fullyConstructed ( true ), f_previousConn ( false ), f_claimSent ( false ), f_firstConnectDecrementsOutstandingIO ( false ), @@ -58,18 +56,13 @@ nciu::nciu ( cac &cacIn, netiiu &iiuIn, cacChannelNotify &chanIn, this->pNameStr = new char [ this->nameLength ]; if ( ! this->pNameStr ) { - this->f_fullyConstructed = false; - return; + throw std::bad_alloc (); } strcpy ( this->pNameStr, pNameIn ); } nciu::~nciu () { - if ( ! this->fullyConstructed () ) { - return; - } - // care is taken so that a lock is not applied during this phase this->cacCtx.destroyAllIO ( *this ); this->cacCtx.uninstallChannel ( *this ); @@ -127,8 +120,8 @@ void nciu::connect ( unsigned nativeType, * will always be access */ if ( ! v41Ok ) { - this->accessRightState.read_access = true; - this->accessRightState.write_access = true; + this->accessRightState.setReadPermit(); + this->accessRightState.setWritePermit(); } // resubscribe for monitors from this channel @@ -143,7 +136,7 @@ void nciu::connect ( unsigned nativeType, * their call back here */ if ( ! v41Ok ) { - this->notify ().accessRightsNotify ( *this, this->accessRightState ); + this->notify().accessRightsNotify ( *this, this->accessRightState ); } } @@ -158,8 +151,8 @@ void nciu::disconnect ( netiiu &newiiu ) this->typeCode = USHRT_MAX; this->count = 0u; this->sid = UINT_MAX; - this->accessRightState.read_access = false; - this->accessRightState.write_access = false; + this->accessRightState.clrReadPermit(); + this->accessRightState.clrWritePermit(); this->f_claimSent = false; if ( this->f_connected ) { @@ -174,8 +167,8 @@ void nciu::disconnect ( netiiu &newiiu ) /* * look for events that have an event cancel in progress */ - this->notify ().disconnectNotify ( *this ); - this->notify ().accessRightsNotify ( *this, this->accessRightState ); + this->notify().disconnectNotify ( *this ); + this->notify().accessRightsNotify ( *this, this->accessRightState ); } this->resetRetryCount (); @@ -223,130 +216,123 @@ unsigned nciu::nameLen () const return this->nameLength; } -int nciu::createChannelRequest () +void nciu::createChannelRequest () { - int status = this->piiu->createChannelRequest ( *this ); - if ( status == ECA_NORMAL ) { - this->f_claimSent = true; - } - return status; + this->piiu->createChannelRequest ( *this ); + this->f_claimSent = true; } -int nciu::read ( unsigned type, unsigned long countIn, cacNotify ¬ify ) +cacChannel::ioStatus nciu::read ( unsigned type, unsigned long countIn, + cacDataNotify ¬ify, ioid *pId ) { // // fail out if their arguments are invalid // if ( ! this->f_connected ) { - return ECA_DISCONNCHID; + throw notConnected (); } if ( INVALID_DB_REQ (type) ) { - return ECA_BADTYPE; + throw badType (); } - if ( ! this->accessRightState.read_access ) { - return ECA_NORDACCESS; + if ( ! this->accessRightState.readPermit() ) { + throw noReadAccess (); } if ( countIn > UINT_MAX ) { - return ECA_BADCOUNT; + throw outOfBounds (); } + if ( countIn == 0 ) { countIn = this->count; } - return this->cacCtx.readNotifyRequest ( *this, notify, type, countIn ); + ioid tmpId = this->cacCtx.readNotifyRequest ( *this, type, countIn, notify ); + if ( pId ) { + *pId = tmpId; + } + return cacChannel::iosAsynch; } -/* - * check_a_dbr_string() - */ -static int check_a_dbr_string ( const char *pStr, const unsigned count ) +void nciu::stringVerify ( const char *pStr, const unsigned count ) { for ( unsigned i = 0; i < count; i++ ) { unsigned int strsize = 0; while ( pStr[strsize++] != '\0' ) { if ( strsize >= MAX_STRING_SIZE ) { - return ECA_STRTOBIG; + throw badString(); } } pStr += MAX_STRING_SIZE; } - - return ECA_NORMAL; } -int nciu::write ( unsigned type, unsigned long countIn, const void *pValue ) +void nciu::write ( unsigned type, + unsigned long countIn, const void *pValue ) { - // check this first so thet get a decent diagnostic - if ( ! this->f_connected ) { - return ECA_DISCONNCHID; - } - - if ( ! this->accessRightState.write_access ) { - return ECA_NOWTACCESS; + if ( ! this->accessRightState.writePermit() ) { + throw noWriteAccess(); } if ( countIn > this->count || countIn == 0 ) { - return ECA_BADCOUNT; + throw outOfBounds(); } if ( type == DBR_STRING ) { - int status = check_a_dbr_string ( (char *) pValue, countIn ); - if ( status != ECA_NORMAL ) { - return status; - } + nciu::stringVerify ( (char *) pValue, countIn ); } - return this->cacCtx.writeRequest ( *this, type, countIn, pValue ); + this->cacCtx.writeRequest ( *this, type, countIn, pValue ); } -int nciu::write ( unsigned type, unsigned long countIn, const void *pValue, cacNotify ¬ify ) +cacChannel::ioStatus nciu::write ( unsigned type, unsigned long countIn, + const void *pValue, cacNotify ¬ify, ioid *pId ) { - // check this first so thet get a decent diagnostic - if ( ! this->f_connected ) { - return ECA_DISCONNCHID; - } - - if ( ! this->accessRightState.write_access ) { - return ECA_NOWTACCESS; + if ( ! this->accessRightState.writePermit() ) { + throw noWriteAccess(); } if ( countIn > this->count || countIn == 0 ) { - return ECA_BADCOUNT; + throw outOfBounds(); } if ( type == DBR_STRING ) { - int status = check_a_dbr_string ( (char *) pValue, countIn ); - if ( status != ECA_NORMAL ) { - return status; - } + nciu::stringVerify ( (char *) pValue, countIn ); } - return this->cacCtx.writeNotifyRequest ( *this, notify, type, countIn, pValue ); + ioid tmpId = this->cacCtx.writeNotifyRequest ( *this, type, countIn, pValue, notify ); + if ( pId ) { + *pId = tmpId; + } + return cacChannel::iosAsynch; } -int nciu::subscribe ( unsigned type, unsigned long nElem, - unsigned mask, cacNotify ¬ify, - cacNotifyIO *&pNotifyIO ) +void nciu::subscribe ( unsigned type, unsigned long nElem, + unsigned mask, cacDataNotify ¬ify, ioid *pId ) { if ( INVALID_DB_REQ(type) ) { - return ECA_BADTYPE; + throw badType(); } if ( mask > 0xffff || mask == 0u ) { - return ECA_BADMASK; + throw badEventSelection(); } - cacNotifyIO * pIO = this->cacCtx.subscriptionRequest ( - *this, type, nElem, mask, notify ); - if ( pIO ) { - pNotifyIO = pIO; - return ECA_NORMAL;; - } - else { - return ECA_ALLOCMEM; + ioid tmpId = this->cacCtx.subscriptionRequest ( + *this, type, nElem, mask, notify ); + if ( pId ) { + *pId = tmpId; } } +void nciu::ioCancel ( const ioid &id ) +{ + this->cacCtx.ioCancel ( *this, id ); +} + +void nciu::ioShow ( const ioid &id, unsigned level ) const +{ + this->cacCtx.ioShow ( id, level ); +} + void nciu::initiateConnect () { this->notifyStateChangeFirstConnectInCountOfOutstandingIO (); @@ -355,26 +341,26 @@ void nciu::initiateConnect () void nciu::hostName ( char *pBuf, unsigned bufLength ) const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); this->piiu->hostName ( pBuf, bufLength ); } // deprecated - please do not use, this is _not_ thread safe const char * nciu::pHostName () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); return this->piiu->pHostName (); // ouch ! } bool nciu::ca_v42_ok () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); return this->piiu->ca_v42_ok (); } short nciu::nativeType () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); short type; if ( this->f_connected ) { if ( this->typeCode < SHRT_MAX ) { @@ -392,7 +378,7 @@ short nciu::nativeType () const unsigned long nciu::nativeElementCount () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); unsigned long countOut; if ( this->f_connected ) { countOut = this->count; @@ -403,44 +389,28 @@ unsigned long nciu::nativeElementCount () const return countOut; } -channel_state nciu::state () const +caAccessRights nciu::accessRights () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); - channel_state stateOut; - if ( this->f_connected ) { - stateOut = cs_conn; - } - else if ( this->f_previousConn ) { - stateOut = cs_prev_conn; - } - else { - stateOut = cs_never_conn; - } - return stateOut; -} - -caar nciu::accessRights () const -{ - epicsAutoMutex locker ( this->cacCtx.mutex() ); - caar tmp = this->accessRightState; + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); + caAccessRights tmp = this->accessRightState; return tmp; } unsigned nciu::searchAttempts () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); return this->retry; } double nciu::beaconPeriod () const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); return this->piiu->beaconPeriod (); } void nciu::notifyStateChangeFirstConnectInCountOfOutstandingIO () { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); // test is performed via a callback so that locking is correct if ( ! this->f_connectTimeOutSeen && ! this->f_previousConn ) { if ( this->notify ().includeFirstConnectInCountOfOutstandingIO () ) { @@ -460,7 +430,7 @@ void nciu::notifyStateChangeFirstConnectInCountOfOutstandingIO () void nciu::show ( unsigned level ) const { - epicsAutoMutex locker ( this->cacCtx.mutex() ); + epicsAutoMutex locker ( this->cacCtx.mutexRef() ); if ( this->f_connected ) { char hostNameTmp [256]; this->hostName ( hostNameTmp, sizeof ( hostNameTmp ) ); @@ -471,8 +441,8 @@ void nciu::show ( unsigned level ) const printf ( ", native type %s, native element count %u", dbf_type_to_text ( tmpTypeCode ), this->count ); printf ( ", %sread access, %swrite access", - this->accessRightState.read_access ? "" : "no ", - this->accessRightState.write_access ? "" : "no "); + this->accessRightState.readPermit() ? "" : "no ", + this->accessRightState.writePermit() ? "" : "no "); } printf ( "\n" ); } @@ -490,9 +460,11 @@ void nciu::show ( unsigned level ) const printf ( "\tsearch retry number=%u, search retry sequence number=%u\n", this->retry, this->retrySeqNo ); printf ( "\tname length=%u\n", this->nameLength ); - printf ( "\tfully cunstructed boolean=%u\n", this->f_fullyConstructed ); } } + + + diff --git a/src/ca/nciu_IL.h b/src/ca/nciu_IL.h index 91751af58..cc2159ba8 100644 --- a/src/ca/nciu_IL.h +++ b/src/ca/nciu_IL.h @@ -32,11 +32,6 @@ inline void nciu::operator delete ( void *pCadaver, size_t size ) nciu::freeList.release ( pCadaver, size ); } -inline bool nciu::fullyConstructed () const -{ - return this->f_fullyConstructed; -} - inline bool nciu::identifierEquivelence ( unsigned idToMatch ) { return idToMatch == this->id; @@ -47,10 +42,10 @@ inline void nciu::resetRetryCount () this->retry = 0u; } -inline void nciu::accessRightsStateChange ( const caar &arIn ) +inline void nciu::accessRightsStateChange ( const caAccessRights &arIn ) { this->accessRightState = arIn; - this->notify ().accessRightsNotify ( *this, arIn ); + this->notify().accessRightsNotify ( *this, arIn ); } inline ca_uint32_t nciu::getSID () const @@ -81,8 +76,6 @@ inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn, this->typeCode = typeIn; this->count = countIn; this->sid = sidIn; - this->accessRightState.read_access = true; - this->accessRightState.write_access = true; } inline bool nciu::connected () const @@ -90,6 +83,11 @@ inline bool nciu::connected () const return this->f_connected; } +inline bool nciu::previouslyConnected () const +{ + return this->f_previousConn; +} + inline bool nciu::isAttachedToVirtaulCircuit ( const osiSockAddr &addrIn ) { return this->piiu->isVirtaulCircuit ( this->pNameStr, addrIn ); diff --git a/src/ca/netReadNotifyIO.cpp b/src/ca/netReadNotifyIO.cpp index d11245d8f..ca62a9c29 100644 --- a/src/ca/netReadNotifyIO.cpp +++ b/src/ca/netReadNotifyIO.cpp @@ -15,8 +15,8 @@ #include "nciu_IL.h" #include "baseNMIU_IL.h" -netReadNotifyIO::netReadNotifyIO ( nciu &chan, cacNotify ¬ifyIn ) : - baseNMIU ( notifyIn, chan ) +netReadNotifyIO::netReadNotifyIO ( nciu &chan, cacDataNotify ¬ify ) : + baseNMIU ( chan ), notify ( notify ) { } @@ -33,15 +33,33 @@ void netReadNotifyIO::show ( unsigned level ) const } } -void netReadNotifyIO::cancel () -{ - this->chan.getClient().destroyReadNotifyIO ( *this ); -} - void netReadNotifyIO::destroy ( cacRecycle & recycle ) { this->~netReadNotifyIO(); recycle.recycleReadNotifyIO ( *this ); } +void netReadNotifyIO::completion () +{ + this->chan.getClient().printf ( "Read response w/o data ?\n" ); +} + +void netReadNotifyIO::exception ( int status, const char *pContext ) +{ + this->notify.exception ( status, pContext, UINT_MAX, 0 ); +} + +void netReadNotifyIO::completion ( unsigned type, + unsigned long count, const void *pData ) +{ + this->notify.completion ( type, count, pData ); +} + +void netReadNotifyIO::exception ( int status, + const char *pContext, unsigned type, unsigned long count ) +{ + this->notify.exception ( status, pContext, type, count ); +} + + diff --git a/src/ca/netReadNotifyIO_IL.h b/src/ca/netReadNotifyIO_IL.h index c8ca4fa47..2829bfc13 100644 --- a/src/ca/netReadNotifyIO_IL.h +++ b/src/ca/netReadNotifyIO_IL.h @@ -20,7 +20,7 @@ inline netReadNotifyIO * netReadNotifyIO::factory ( tsFreeList < class netReadNotifyIO, 1024 > &freeList, - nciu &chan, cacNotify ¬ify ) + nciu &chan, cacDataNotify ¬ify ) { return new ( freeList ) netReadNotifyIO ( chan, notify ); } diff --git a/src/ca/netSubscription.cpp b/src/ca/netSubscription.cpp index 10fafb7cc..d14ec8cb7 100644 --- a/src/ca/netSubscription.cpp +++ b/src/ca/netSubscription.cpp @@ -15,10 +15,11 @@ #include "nciu_IL.h" #include "baseNMIU_IL.h" -netSubscription::netSubscription ( nciu &chan, unsigned typeIn, unsigned long countIn, - unsigned maskIn, cacNotify ¬ifyIn ) : - baseNMIU ( notifyIn, chan ), - count ( countIn ), type ( typeIn ), mask ( maskIn ) +netSubscription::netSubscription ( nciu &chan, + unsigned typeIn, unsigned long countIn, + unsigned maskIn, cacDataNotify ¬ifyIn ) : + baseNMIU ( chan ), count ( countIn ), + notify ( notifyIn ), type ( typeIn ), mask ( maskIn ) { } @@ -26,11 +27,6 @@ netSubscription::~netSubscription () { } -void netSubscription::cancel () -{ - this->chan.getClient().destroySubscription ( *this ); -} - void netSubscription::destroy ( cacRecycle &recycle ) { this->~netSubscription (); @@ -52,3 +48,27 @@ void netSubscription::show ( unsigned level ) const this->baseNMIU::show ( level - 1u ); } } + +void netSubscription::completion () +{ + this->chan.getClient().printf ( "subscription update w/o data ?\n" ); +} + +void netSubscription::exception ( int status, const char *pContext ) +{ + this->notify.exception ( status, pContext, UINT_MAX, 0 ); +} + +void netSubscription::completion ( unsigned type, + unsigned long count, const void *pData ) +{ + this->notify.completion ( type, count, pData ); +} + +void netSubscription::exception ( int status, + const char *pContext, unsigned type, unsigned long count ) +{ + this->notify.exception ( status, pContext, type, count ); +} + + diff --git a/src/ca/netSubscription_IL.h b/src/ca/netSubscription_IL.h index b3b9b1e50..db73f1cb3 100644 --- a/src/ca/netSubscription_IL.h +++ b/src/ca/netSubscription_IL.h @@ -21,7 +21,7 @@ inline netSubscription * netSubscription::factory ( tsFreeList < class netSubscription, 1024 > &freeList, nciu &chan, unsigned type, unsigned long count, - unsigned mask, cacNotify ¬ify ) + unsigned mask, cacDataNotify ¬ify ) { return new ( freeList ) netSubscription ( chan, type, count, mask, notify ); @@ -46,9 +46,9 @@ inline void netSubscription::operator delete ( void *pCadaver, size_t size, } #endif -inline unsigned long netSubscription::getCount () const +inline unsigned long netSubscription::getCount ( nciu &chan ) const { - unsigned long nativeCount = this->chan.nativeElementCount (); + unsigned long nativeCount = chan.nativeElementCount (); if ( this->count == 0u || this->count > nativeCount ) { return nativeCount; } diff --git a/src/ca/netWriteNotifyIO.cpp b/src/ca/netWriteNotifyIO.cpp index 5881dddc8..d55995d4b 100644 --- a/src/ca/netWriteNotifyIO.cpp +++ b/src/ca/netWriteNotifyIO.cpp @@ -16,7 +16,7 @@ #include "baseNMIU_IL.h" netWriteNotifyIO::netWriteNotifyIO ( nciu &chan, cacNotify ¬ifyIn ) : - baseNMIU ( notifyIn, chan ) + baseNMIU ( chan ), notify ( notifyIn ) { } @@ -33,15 +33,35 @@ void netWriteNotifyIO::show ( unsigned level ) const } } -void netWriteNotifyIO::cancel () -{ - this->chan.getClient().destroyWriteNotifyIO ( *this ); -} - void netWriteNotifyIO::destroy ( cacRecycle & recycle ) { this->~netWriteNotifyIO (); recycle.recycleWriteNotifyIO ( *this ); } +void netWriteNotifyIO::completion () +{ + this->notify.completion (); +} + +void netWriteNotifyIO::exception ( int status, const char *pContext ) +{ + this->notify.exception ( status, pContext ); +} + +void netWriteNotifyIO::completion ( unsigned type, + unsigned long count, const void *pData ) +{ + this->chan.getClient().printf ( "Write response with data ?\n" ); +} + +void netWriteNotifyIO::exception ( int status, + const char *pContext, unsigned type, unsigned long count ) +{ + this->notify.exception ( status, pContext ); +} + + + + diff --git a/src/ca/netiiu.cpp b/src/ca/netiiu.cpp index a1afa03d4..aadc1781e 100644 --- a/src/ca/netiiu.cpp +++ b/src/ca/netiiu.cpp @@ -119,36 +119,34 @@ void netiiu::lastChannelDetachNotify () { } -int netiiu::writeRequest ( nciu &, unsigned, unsigned, const void * ) +void netiiu::writeRequest ( nciu &, unsigned, unsigned, const void * ) { - return ECA_DISCONNCHID; + throw cacChannel::notConnected(); } -int netiiu::writeNotifyRequest ( nciu &, netWriteNotifyIO &, unsigned, unsigned, const void * ) +void netiiu::writeNotifyRequest ( nciu &, netWriteNotifyIO &, unsigned, unsigned, const void * ) { - return ECA_DISCONNCHID; + throw cacChannel::notConnected(); } -int netiiu::readNotifyRequest ( nciu &, netReadNotifyIO &, unsigned, unsigned ) +void netiiu::readNotifyRequest ( nciu &, netReadNotifyIO &, unsigned, unsigned ) { - return ECA_DISCONNCHID; + throw cacChannel::notConnected(); } -int netiiu::createChannelRequest ( nciu & ) -{ - return ECA_DISCONNCHID; -} - -int netiiu::clearChannelRequest ( nciu & ) -{ - return ECA_DISCONNCHID; -} - -void netiiu::subscriptionRequest ( netSubscription & ) +void netiiu::createChannelRequest ( nciu & ) { } -void netiiu::subscriptionCancelRequest ( netSubscription & ) +void netiiu::clearChannelRequest ( nciu & ) +{ +} + +void netiiu::subscriptionRequest ( nciu &, netSubscription & ) +{ +} + +void netiiu::subscriptionCancelRequest ( nciu &, netSubscription & ) { } diff --git a/src/ca/oldAccess.h b/src/ca/oldAccess.h index ca311f21d..0bf248bce 100644 --- a/src/ca/oldAccess.h +++ b/src/ca/oldAccess.h @@ -15,41 +15,72 @@ * 505 665 1831 */ - -class oldChannelNotify : public cacChannelNotify { +struct oldChannelNotify : public cacChannelNotify { public: - oldChannelNotify ( caCh *pConnCallBackIn, void *pPrivateIn ); - void release (); + oldChannelNotify ( cac &, const char *pName, caCh *pConnCallBackIn, void *pPrivateIn ); + void destroy (); + bool ioAttachOK (); void setPrivatePointer ( void * ); void * privatePointer () const; - int changeConnCallBack ( cacChannelIO &, caCh *pfunc ); - int replaceAccessRightsEvent ( cacChannelIO &chan, caArh *pfunc ); + int changeConnCallBack ( caCh *pfunc ); + int replaceAccessRightsEvent ( caArh *pfunc ); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); + + const char *pName () const; + void show ( unsigned level ) const; + void initiateConnect (); + void read ( + unsigned type, unsigned long count, + cacDataNotify ¬ify, cacChannel::ioid *pId = 0 ); + void read ( + unsigned type, unsigned long count, + void *pValue ); + void write ( + unsigned type, unsigned long count, + const void *pValue ); + void write ( + unsigned type, unsigned long count, const void *pValue, + cacNotify &, cacChannel::ioid *pId = 0 ); + void subscribe ( + unsigned type, unsigned long count, unsigned mask, + cacDataNotify &, cacChannel::ioid & ); + void ioCancel ( const cacChannel::ioid & ); + void ioShow ( const cacChannel::ioid &, unsigned level ) const; + short nativeType () const; + unsigned long nativeElementCount () const; + caAccessRights accessRights () const; // defaults to unrestricted access + unsigned searchAttempts () const; // defaults to zero + double beaconPeriod () const; // defaults to negative DBL_MAX + bool ca_v42_ok () const; + bool connected () const; + bool previouslyConnected () const; + void hostName ( char *pBuf, unsigned bufLength ) const; // defaults to local host name + const char * pHostName () const; // deprecated - please do not use protected: ~oldChannelNotify (); // must allocate from pool private: + cacChannel &io; caCh *pConnCallBack; void *pPrivate; caArh *pAccessRightsFunc; - void connectNotify ( cacChannelIO &chan ); - void disconnectNotify ( cacChannelIO &chan ); - void accessRightsNotify ( cacChannelIO &chan, const caar & ); + void connectNotify ( cacChannel &chan ); + void disconnectNotify ( cacChannel &chan ); + void accessRightsNotify ( cacChannel &chan, const caAccessRights & ); bool includeFirstConnectInCountOfOutstandingIO () const; - class oldChannelNotify * pOldChannelNotify (); - static tsFreeList < class oldChannelNotify, 1024 > freeList; + static tsFreeList < struct oldChannelNotify, 1024 > freeList; static epicsMutex freeListMutex; }; -class getCopy : public cacNotify { +class getCopy : public cacDataNotify { public: getCopy ( cac &cacCtx, unsigned type, unsigned long count, void *pValue ); - void release (); + void destroy (); + void show ( unsigned level ) const; void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); - void show ( unsigned level ) const; protected: ~getCopy (); // allocate only out of pool private: @@ -58,34 +89,30 @@ private: void *pValue; unsigned readSeq; unsigned type; - void completionNotify ( cacChannelIO & ); - void completionNotify ( cacChannelIO &, + void completion ( unsigned type, unsigned long count, const void *pData); - void exceptionNotify ( cacChannelIO &, - int status, const char *pContext); - void exceptionNotify ( cacChannelIO &, + void exception ( int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < class getCopy, 1024 > freeList; static epicsMutex freeListMutex; }; -class getCallback : public cacNotify { +class getCallback : public cacDataNotify { public: - getCallback ( caEventCallBackFunc *pFunc, void *pPrivate ); - void release (); + getCallback ( oldChannelNotify &chanIn, + caEventCallBackFunc *pFunc, void *pPrivate ); + void destroy (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); protected: ~getCallback (); // allocate only out of pool private: + oldChannelNotify &chan; caEventCallBackFunc *pFunc; void *pPrivate; - void completionNotify ( cacChannelIO & ); - void completionNotify ( cacChannelIO &, + void completion ( unsigned type, unsigned long count, const void *pData); - void exceptionNotify ( cacChannelIO &, - int status, const char *pContext); - void exceptionNotify ( cacChannelIO &, + void exception ( int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < class getCallback, 1024 > freeList; static epicsMutex freeListMutex; @@ -93,51 +120,90 @@ private: class putCallback : public cacNotify { public: - putCallback ( caEventCallBackFunc *pFunc, void *pPrivate ); - void release (); + putCallback ( oldChannelNotify &, + caEventCallBackFunc *pFunc, void *pPrivate ); + void destroy (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); protected: ~putCallback (); // allocate only out of pool private: + oldChannelNotify &chan; caEventCallBackFunc *pFunc; void *pPrivate; - void completionNotify ( cacChannelIO & ); - void completionNotify ( cacChannelIO &, - unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( cacChannelIO &, + void completion (); + void exception ( int status, const char *pContext ); - void exceptionNotify ( cacChannelIO &, - int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < class putCallback, 1024 > freeList; static epicsMutex freeListMutex; }; -struct oldSubscription : public cacNotify { +struct oldSubscription : public cacDataNotify { public: - oldSubscription ( caEventCallBackFunc *pFunc, void *pPrivate ); - void release (); + oldSubscription ( + oldChannelNotify &, + unsigned type, unsigned long nElem, unsigned mask, + caEventCallBackFunc *pFunc, void *pPrivate ); + bool ioAttachOK (); + void destroy (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); + oldChannelNotify &channel () const; protected: ~oldSubscription (); // must allocate from pool private: + oldChannelNotify &chan; + cacChannel::ioid id; caEventCallBackFunc *pFunc; void *pPrivate; - void completionNotify ( cacChannelIO & ); - void completionNotify ( cacChannelIO &, + bool subscribed; + void completion ( unsigned type, unsigned long count, const void *pData ); - void exceptionNotify ( cacChannelIO &, - int status, const char *pContext ); - void exceptionNotify ( cacChannelIO &, + void exception ( int status, const char *pContext, unsigned type, unsigned long count ); static tsFreeList < struct oldSubscription, 1024 > freeList; static epicsMutex freeListMutex; }; -inline getCallback::getCallback ( caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : - pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +inline oldSubscription::oldSubscription ( + oldChannelNotify &chanIn, + unsigned type, unsigned long nElem, unsigned mask, + caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : + chan ( chanIn ), id ( 0 ), pFunc ( pFuncIn ), + pPrivate ( pPrivateIn ), subscribed ( false ) { + this->chan.subscribe ( type, nElem, mask, *this, this->id ); + this->subscribed = true; +} + +inline void oldSubscription::destroy () +{ + if ( this->subscribed ) { + this->chan.ioCancel ( this->id ); + } + delete this; +} + +inline void * oldSubscription::operator new ( size_t size ) +{ + epicsAutoMutex locker ( oldSubscription::freeListMutex ); + return oldSubscription::freeList.allocate ( size ); +} + +inline void oldSubscription::operator delete ( void *pCadaver, size_t size ) +{ + epicsAutoMutex locker ( oldSubscription::freeListMutex ); + oldSubscription::freeList.release ( pCadaver, size ); +} + +inline oldChannelNotify & oldSubscription::channel () const +{ + return this->chan; +} + +inline void getCopy::destroy () +{ + delete this; } inline void * getCopy::operator new ( size_t size ) @@ -152,21 +218,9 @@ inline void getCopy::operator delete ( void *pCadaver, size_t size ) getCopy::freeList.release ( pCadaver, size ); } -inline void * getCallback::operator new ( size_t size ) -{ - epicsAutoMutex locker ( getCallback::freeListMutex ); - return getCallback::freeList.allocate ( size ); -} - -inline void getCallback::operator delete ( void *pCadaver, size_t size ) -{ - epicsAutoMutex locker ( getCallback::freeListMutex ); - getCallback::freeList.release ( pCadaver, size ); -} - -inline putCallback::putCallback ( caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : - pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +inline void putCallback::destroy () { + delete this; } inline void * putCallback::operator new ( size_t size ) @@ -181,19 +235,19 @@ 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 getCallback::destroy () { + delete this; } -inline void * oldSubscription::operator new ( size_t size ) +inline void * getCallback::operator new ( size_t size ) { - epicsAutoMutex locker ( oldSubscription::freeListMutex ); - return oldSubscription::freeList.allocate ( size ); + epicsAutoMutex locker ( getCallback::freeListMutex ); + return getCallback::freeList.allocate ( size ); } -inline void oldSubscription::operator delete ( void *pCadaver, size_t size ) +inline void getCallback::operator delete ( void *pCadaver, size_t size ) { - epicsAutoMutex locker ( oldSubscription::freeListMutex ); - oldSubscription::freeList.release ( pCadaver, size ); + epicsAutoMutex locker ( getCallback::freeListMutex ); + getCallback::freeList.release ( pCadaver, size ); } diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp index 70dce2b9f..6b2972f09 100644 --- a/src/ca/oldChannelNotify.cpp +++ b/src/ca/oldChannelNotify.cpp @@ -18,7 +18,7 @@ #include "iocinf.h" #include "oldAccess.h" -tsFreeList < class oldChannelNotify, 1024 > oldChannelNotify::freeList; +tsFreeList < struct oldChannelNotify, 1024 > oldChannelNotify::freeList; epicsMutex oldChannelNotify::freeListMutex; extern "C" void cacNoopConnHandler ( struct connection_handler_args ) @@ -29,19 +29,17 @@ extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args ) { } -oldChannelNotify::oldChannelNotify ( caCh *pConnCallBackIn, void *pPrivateIn ) : -pConnCallBack ( pConnCallBackIn ? pConnCallBackIn : cacNoopConnHandler ), +oldChannelNotify::oldChannelNotify ( cac &cacIn, const char *pName, + caCh *pConnCallBackIn, void *pPrivateIn ) : + io ( cacIn.createChannel ( pName, *this ) ), + pConnCallBack ( pConnCallBackIn ? pConnCallBackIn : cacNoopConnHandler ), pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler ) { } oldChannelNotify::~oldChannelNotify () { -} - -void oldChannelNotify::release () -{ - delete this; + delete & this->io; } void oldChannelNotify::setPrivatePointer ( void *pPrivateIn ) @@ -54,16 +52,16 @@ void * oldChannelNotify::privatePointer () const return this->pPrivate; } -int oldChannelNotify::changeConnCallBack ( cacChannelIO &chan, caCh *pfunc ) +int oldChannelNotify::changeConnCallBack ( caCh *pfunc ) { this->pConnCallBack = pfunc ? pfunc : cacNoopConnHandler; // test for NOOP connection handler does _not_ occur here because the // lock is not applied - chan.notifyStateChangeFirstConnectInCountOfOutstandingIO (); + this->io.notifyStateChangeFirstConnectInCountOfOutstandingIO (); return ECA_NORMAL; } -int oldChannelNotify::replaceAccessRightsEvent ( cacChannelIO &chan, caArh *pfunc ) +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 @@ -71,36 +69,39 @@ int oldChannelNotify::replaceAccessRightsEvent ( cacChannelIO &chan, caArh *pfun // 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 () ) { + if ( this->io.connected () ) { struct access_rights_handler_args args; - args.chid = &chan; - args.ar = chan.accessRights (); + args.chid = this; + caAccessRights tmp = this->io.accessRights (); + args.ar.read_access = tmp.readPermit (); + args.ar.write_access = tmp.writePermit (); ( *pfunc ) ( args ); } return ECA_NORMAL; } -void oldChannelNotify::connectNotify ( cacChannelIO &chan ) +void oldChannelNotify::connectNotify ( cacChannel & ) { struct connection_handler_args args; - args.chid = &chan; + args.chid = this; args.op = CA_OP_CONN_UP; ( *this->pConnCallBack ) ( args ); } -void oldChannelNotify::disconnectNotify ( cacChannelIO &chan ) +void oldChannelNotify::disconnectNotify ( cacChannel & ) { struct connection_handler_args args; - args.chid = &chan; + args.chid = this; args.op = CA_OP_CONN_DOWN; ( *this->pConnCallBack ) ( args ); } -void oldChannelNotify::accessRightsNotify ( cacChannelIO &chan, const caar &ar ) +void oldChannelNotify::accessRightsNotify ( cacChannel &, const caAccessRights &ar ) { struct access_rights_handler_args args; - args.chid = &chan; - args.ar = ar; + args.chid = this; + args.ar.read_access = ar.readPermit(); + args.ar.write_access = ar.writePermit(); ( *this->pAccessRightsFunc ) ( args ); } @@ -109,11 +110,6 @@ bool oldChannelNotify::includeFirstConnectInCountOfOutstandingIO () const return ( this->pConnCallBack == cacNoopConnHandler ); } -class oldChannelNotify * oldChannelNotify::pOldChannelNotify () -{ - return this; -} - void * oldChannelNotify::operator new ( size_t size ) { epicsAutoMutex locker ( oldChannelNotify::freeListMutex ); diff --git a/src/ca/oldChannelNotify_IL.h b/src/ca/oldChannelNotify_IL.h new file mode 100644 index 000000000..8443a79a6 --- /dev/null +++ b/src/ca/oldChannelNotify_IL.h @@ -0,0 +1,131 @@ + +/* + * $Id$ + * + * + * L O S A L A M O S + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * + * Copyright, The Regents of the University of California. + * + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + */ + +#ifndef oldChannelNotifyILh +#define oldChannelNotifyILh + +inline bool oldChannelNotify::ioAttachOK () +{ + return &this->io ? true : false; +} + +inline void oldChannelNotify::destroy () +{ + delete this; +} + +inline const char *oldChannelNotify::pName () const +{ + return this->io.pName (); +} + +inline void oldChannelNotify::show ( unsigned level ) const +{ + this->io.show ( level ); +} + +inline void oldChannelNotify::initiateConnect () +{ + this->io.initiateConnect (); +} + +inline void oldChannelNotify::read ( unsigned type, unsigned long count, + cacDataNotify ¬ify, cacChannel::ioid *pId ) +{ + this->io.read ( type, count, notify, pId ); +} + +inline void oldChannelNotify::write ( unsigned type, + unsigned long count, const void *pValue ) +{ + this->io.write ( type, count, pValue ); +} + +inline void oldChannelNotify::write ( unsigned type, unsigned long count, + const void *pValue, cacNotify ¬ify, cacChannel::ioid *pId ) +{ + this->io.write ( type, count, pValue, notify, pId ); +} + +inline void oldChannelNotify::subscribe ( unsigned type, + unsigned long count, unsigned mask, cacDataNotify ¬ify, + 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 +{ + this->io.ioShow ( id, level ); +} + +inline short oldChannelNotify::nativeType () const +{ + return this->io.nativeType (); +} + +inline unsigned long oldChannelNotify::nativeElementCount () const +{ + return this->io.nativeElementCount (); +} + +inline caAccessRights oldChannelNotify::accessRights () const +{ + return this->io.accessRights (); +} + +inline unsigned oldChannelNotify::searchAttempts () const +{ + return this->io.searchAttempts (); +} + +inline double oldChannelNotify::beaconPeriod () const +{ + return this->io.beaconPeriod (); +} + +inline bool oldChannelNotify::ca_v42_ok () const +{ + return this->io.ca_v42_ok (); +} + +inline bool oldChannelNotify::connected () const +{ + return this->io.connected (); +} + +inline bool oldChannelNotify::previouslyConnected () const +{ + return this->io.previouslyConnected (); +} + +inline void oldChannelNotify::hostName ( char *pBuf, unsigned bufLength ) const +{ + this->io.hostName ( pBuf, bufLength ); +} + +inline const char * oldChannelNotify::pHostName () const +{ + return this->io.pHostName (); +} + +#endif // ifndef oldChannelNotifyILh diff --git a/src/ca/oldSubscription.cpp b/src/ca/oldSubscription.cpp index 71d3f65b1..02e9eceda 100644 --- a/src/ca/oldSubscription.cpp +++ b/src/ca/oldSubscription.cpp @@ -12,66 +12,42 @@ #include "iocinf.h" #include "oldAccess.h" +#include "oldChannelNotify_IL.h" tsFreeList < struct oldSubscription, 1024 > oldSubscription::freeList; epicsMutex oldSubscription::freeListMutex; oldSubscription::~oldSubscription () { + this->chan.ioCancel ( this->id ); } -// eliminates sun pro warning -void oldSubscription::completionNotify ( cacChannelIO &io ) -{ - this->cacNotify::completionNotify ( io ); -} - -void oldSubscription::completionNotify ( cacChannelIO &io, +void oldSubscription::completion ( unsigned type, unsigned long count, const void *pData) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = & io; + args.chid = &this->chan; args.type = type; args.count = count; args.status = ECA_NORMAL; args.dbr = pData; ( *this->pFunc ) (args); } - -void oldSubscription::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 oldSubscription::exceptionNotify ( cacChannelIO &io, +void oldSubscription::exception ( int status, const char * /* pContext */, unsigned type, unsigned long count ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = & io; + args.chid = &this->chan; args.type = type; args.count = count; args.status = status; args.dbr = 0; - ( *this->pFunc ) (args); + ( *this->pFunc ) ( args ); } -void oldSubscription::release () -{ - delete this; -} - - diff --git a/src/ca/putCallback.cpp b/src/ca/putCallback.cpp index 93619234d..382acd108 100644 --- a/src/ca/putCallback.cpp +++ b/src/ca/putCallback.cpp @@ -21,68 +21,43 @@ tsFreeList < class putCallback, 1024 > putCallback::freeList; epicsMutex putCallback::freeListMutex; +putCallback::putCallback ( oldChannelNotify &chanIn, + caEventCallBackFunc *pFuncIn, void *pPrivateIn ) : + chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn ) +{ +} + putCallback::~putCallback () { } -void putCallback::release () -{ - delete this; -} - -void putCallback::completionNotify ( cacChannelIO &io ) +void putCallback::completion () { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = & io; + args.chid = & this->chan; args.type = TYPENOTCONN; args.count = 0; args.status = ECA_NORMAL; args.dbr = 0; - (*this->pFunc) (args); + ( *this->pFunc ) (args); + delete this; } -void putCallback::completionNotify ( cacChannelIO &io, unsigned type, - unsigned long count, const void * /* pData */ ) -{ - struct event_handler_args args; - - args.usr = this->pPrivate; - args.chid = & io; - args.type = type; - args.count = count; - args.status = ECA_NORMAL; - args.dbr = 0; - (*this->pFunc) (args); -} - -void putCallback::exceptionNotify ( cacChannelIO &io, +void putCallback::exception ( int status, const char * /* pContext */ ) { struct event_handler_args args; args.usr = this->pPrivate; - args.chid = & io; + args.chid = & this->chan; args.type = TYPENOTCONN; args.count = 0; args.status = status; args.dbr = 0; - (*this->pFunc) (args); -} - -void putCallback::exceptionNotify ( cacChannelIO &io, int status, - const char * /* pContext */, unsigned type, unsigned long 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); + ( *this->pFunc ) (args); + delete this; } diff --git a/src/ca/syncGroupNotify.cpp b/src/ca/syncGroupNotify.cpp index 66e8bb7e0..b18714f20 100644 --- a/src/ca/syncGroupNotify.cpp +++ b/src/ca/syncGroupNotify.cpp @@ -29,120 +29,27 @@ */ #include "iocinf.h" +#include "oldAccess.h" +#include "oldChannelNotify_IL.h" -tsFreeList < class syncGroupNotify, 1024 > syncGroupNotify::freeList; -epicsMutex syncGroupNotify::freeListMutex; - -syncGroupNotify::syncGroupNotify ( CASG &sgIn, void *pValueIn ) : - sg (sgIn), magic (CASG_MAGIC), pValue (pValueIn), seqNo ( sgIn.seqNo ) +syncGroupNotify::syncGroupNotify ( CASG &sgIn, chid chanIn ) : + chan ( chanIn ), sg ( sgIn ), + magic ( CASG_MAGIC ), id ( 0u ), idIsValid ( false ) { - epicsAutoMutex locker ( this->sg.mutex ); - this->sg.ioList.add (*this); - this->sg.opPendCount++; -} - -void syncGroupNotify::release () -{ - delete this; } syncGroupNotify::~syncGroupNotify () { - epicsAutoMutex locker ( this->sg.mutex ); - this->sg.ioList.remove (*this); -} - -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; - } - - { - epicsAutoMutex locker ( this->sg.mutex ); - if ( this->seqNo == this->sg.seqNo ) { - assert ( this->sg.opPendCount > 0u ); - this->sg.opPendCount--; - done = this->sg.opPendCount == 0; - } - else { - done = true; - } - } - - if ( done ) { - this->sg.sem.signal (); - } -} - -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; - - { - epicsAutoMutex locker ( this->sg.mutex ); - if ( this->seqNo == this->sg.seqNo ) { - /* - * Update the user's variable - */ - if ( this->pValue ) { - size_t size = dbr_size_n ( type, count ); - memcpy ( this->pValue, pData, size ); - } - assert ( this->sg.opPendCount > 0u ); - this->sg.opPendCount--; - complete = this->sg.opPendCount == 0; - } - else { - complete = true; - } - } - - if ( complete ) { - this->sg.sem.signal (); + if ( this->idIsValid ) { + this->chan->ioCancel ( this->id ); } } void syncGroupNotify::show ( unsigned /* level */ ) const { - printf ( "pending sg op: pVal=%p, magic=%u seqNo=%lu sg=%p\n", - this->pValue, this->magic, this->seqNo, + printf ( "pending sg op: chan=%s magic=%u sg=%p\n", + this->chan->pName(), this->magic, static_cast ( &this->sg ) ); } -void syncGroupNotify::exceptionNotify ( cacChannelIO &io, - int status, const char *pContext ) -{ - ca_signal_formated ( status, __FILE__, __LINE__, - "CA Sync Group request to channel %s failed because \"%s\"\n", - io.pName (), pContext); -} - -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 channel=%s type=%d count=%ld because \"%s\"\n", - io.pName (), type, count, pContext); -} - -void * syncGroupNotify::operator new (size_t size) -{ - return syncGroupNotify::freeList.allocate ( size ); -} - -void syncGroupNotify::operator delete (void *pCadaver, size_t size) -{ - syncGroupNotify::freeList.release ( pCadaver, size ); -} - diff --git a/src/ca/syncGroupReadNotify.cpp b/src/ca/syncGroupReadNotify.cpp new file mode 100644 index 000000000..8a02452ef --- /dev/null +++ b/src/ca/syncGroupReadNotify.cpp @@ -0,0 +1,113 @@ + +/* + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + */ + +#include "iocinf.h" +#include "oldAccess.h" +#include "oldChannelNotify_IL.h" + +syncGroupReadNotify::syncGroupReadNotify ( CASG &sgIn, chid pChan, + unsigned type, unsigned long count, void *pValueIn ) : + syncGroupNotify ( sgIn, pChan ), pValue ( pValueIn ) +{ + pChan->read ( type, count, *this, &this->id ); + this->idIsValid = true; +} + +syncGroupReadNotify * syncGroupReadNotify::factory ( + tsFreeList < class syncGroupReadNotify, 128 > &freeList, + struct CASG &sg, chid chan, unsigned type, + unsigned long count, void *pValueIn ) +{ + return new ( freeList ) syncGroupReadNotify ( sg, chan, type, + count, pValueIn); +} + +void syncGroupReadNotify::destroy ( casgRecycle &recycle ) +{ + this->~syncGroupReadNotify (); + recycle.recycleSyncGroupReadNotify ( * this ); +} + +syncGroupReadNotify::~syncGroupReadNotify () +{ +} + +void syncGroupReadNotify::completion ( + 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; + } + + if ( this->pValue ) { + size_t size = dbr_size_n ( type, count ); + memcpy ( this->pValue, pData, size ); + } + + this->idIsValid = false; + this->sg.destroyIO ( *this ); +} + +void syncGroupReadNotify::exception ( + int status, const char *pContext, unsigned type, unsigned long count ) +{ + ca_signal_formated ( status, __FILE__, __LINE__, + "CA sync group read request failed with chan=%s type=%d count=%ld because \"%s\"\n", + this->chan->pName(), type, count, pContext); + // + // 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 + // CASG::block() times out or unit they call CASG::reset(). + // +} + +void syncGroupReadNotify::show ( unsigned level ) const +{ + printf ( "pending sg read op: pVal=%p\n", this->pValue ); + if ( level > 0u ) { + this->syncGroupNotify::show ( level - 1u ); + } +} + +void * syncGroupReadNotify::operator new ( size_t size, + tsFreeList < class syncGroupReadNotify, 128 > & freeList ) +{ + return freeList.allocate ( size ); +} + +# if ! defined ( NO_PLACEMENT_DELETE ) +void syncGroupReadNotify::operator delete ( void *pCadaver, size_t size, + tsFreeList < class syncGroupWriteNotify, 128 > &freeList ) +{ + freeList.release ( pCadaver, size ); +} +# endif + diff --git a/src/ca/syncGroupWriteNotify.cpp b/src/ca/syncGroupWriteNotify.cpp new file mode 100644 index 000000000..893dac218 --- /dev/null +++ b/src/ca/syncGroupWriteNotify.cpp @@ -0,0 +1,106 @@ + +/* + * $Id$ + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + */ + +#include "iocinf.h" +#include "oldAccess.h" +#include "oldChannelNotify_IL.h" + +syncGroupWriteNotify::syncGroupWriteNotify ( CASG &sgIn, chid pChan, unsigned type, + unsigned long count, const void *pValueIn ) : + syncGroupNotify ( sgIn, pChan ) +{ + pChan->write ( type, count, pValueIn, *this, &this->id ); + this->idIsValid = true; +} + +syncGroupWriteNotify * syncGroupWriteNotify::factory ( + tsFreeList < class syncGroupWriteNotify, 128 > &freeList, + struct CASG &sg, chid chan, unsigned type, + unsigned long count, const void *pValueIn ) +{ + return new ( freeList ) syncGroupWriteNotify ( sg, chan, type, + count, pValueIn); +} + +void syncGroupWriteNotify::destroy ( casgRecycle & recycle ) +{ + this->~syncGroupWriteNotify (); + recycle.recycleSyncGroupWriteNotify ( * this ); +} + +syncGroupWriteNotify::~syncGroupWriteNotify () +{ +} + +void syncGroupWriteNotify::completion () +{ + if ( this->magic != CASG_MAGIC ) { + ca_printf ("cac: sync group io_complete(): bad sync grp op magic number?\n"); + return; + } + + this->idIsValid = false; + this->sg.destroyIO ( *this ); +} + +void syncGroupWriteNotify::exception ( + int status, const char *pContext ) +{ + ca_signal_formated ( status, __FILE__, __LINE__, + "CA sync group write request for channel \"%s\" failed because \"%s\"\n", + this->chan->pName(), pContext); + // + // 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 + // CASG::block() times out or unit they call CASG::reset(). + // +} + +void syncGroupWriteNotify::show ( unsigned level ) const +{ + printf ( "pending write sg op\n" ); + if ( level > 0u ) { + this->syncGroupNotify::show ( level - 1u ); + } +} + +void * syncGroupWriteNotify::operator new ( size_t size, + tsFreeList < class syncGroupWriteNotify, 128 > & freeList ) +{ + return freeList.allocate ( size ); +} + +# if ! defined ( NO_PLACEMENT_DELETE ) +void syncGroupWriteNotify::operator delete ( void *pCadaver, size_t size, + tsFreeList < class syncGroupWriteNotify, 128 > &freeList ) +{ + freeList.release ( pCadaver, size ); +} +# endif diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp index 7e58d8dcd..4a164b763 100644 --- a/src/ca/tcpiiu.cpp +++ b/src/ca/tcpiiu.cpp @@ -34,39 +34,6 @@ static const char nillBytes [] = 0, 0, 0, 0 }; -// TCP protocol jump table -const tcpiiu::pProtoStubTCP tcpiiu::tcpJumpTableCAC [] = -{ - &tcpiiu::noopAction, - &tcpiiu::eventRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::readRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::exceptionRespAction, - &tcpiiu::clearChannelRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::readNotifyRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::claimCIURespAction, - &tcpiiu::writeNotifyRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::accessRightsRespAction, - &tcpiiu::echoRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::badTCPRespAction, - &tcpiiu::verifyAndDisconnectChan, - &tcpiiu::verifyAndDisconnectChan -}; - // // cacSendThreadTCP () // @@ -87,7 +54,7 @@ extern "C" void cacSendThreadTCP ( void *pParam ) } { - epicsAutoMutex autoMutex ( piiu->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( piiu->pCAC()->mutexRef() ); flowControlLaborNeeded = piiu->busyStateDetected != piiu->flowControlActive; echoLaborNeeded = piiu->echoRequestPending; piiu->echoRequestPending = false; @@ -95,17 +62,13 @@ extern "C" void cacSendThreadTCP ( void *pParam ) if ( flowControlLaborNeeded ) { if ( piiu->flowControlActive ) { - int status = piiu->disableFlowControlRequest (); - if ( status == ECA_NORMAL ) { - piiu->flowControlActive = false; - } + piiu->disableFlowControlRequest (); + piiu->flowControlActive = false; debugPrintf ( ( "fc off\n" ) ); } else { - int status = piiu->enableFlowControlRequest (); - if ( status == ECA_NORMAL ) { - piiu->flowControlActive = true; - } + piiu->enableFlowControlRequest (); + piiu->flowControlActive = true; debugPrintf ( ( "fc on\n" ) ); } } @@ -241,7 +204,7 @@ extern "C" void cacRecvThreadTCP ( void *pParam ) piiu->connect (); { - epicsAutoMutex autoMutex ( piiu->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( piiu->pCAC()->mutexRef() ); if ( piiu->state == iiu_connected ) { unsigned priorityOfSend; epicsThreadBooleanStatus tbs; @@ -272,7 +235,7 @@ extern "C" void cacRecvThreadTCP ( void *pParam ) while ( piiu->state == iiu_connected ) { if ( nBytes >= maxBytesPendingTCP ) { epicsEventMustWait ( piiu->recvThreadRingBufferSpaceAvailableSignal ); - epicsAutoMutex autoMutex ( piiu->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( piiu->pCAC()->mutexRef() ); nBytes = piiu->recvQue.occupiedBytes (); } else { @@ -282,7 +245,7 @@ extern "C" void cacRecvThreadTCP ( void *pParam ) if ( nBytesIn ) { bool msgHeaderButNoBody; { - epicsAutoMutex autoMutex ( piiu->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( piiu->pCAC()->mutexRef() ); nBytes = piiu->recvQue.occupiedBytes (); msgHeaderButNoBody = piiu->msgHeaderAvailable; piiu->recvQue.pushLastComBufReceived ( *pComBuf ); @@ -316,14 +279,14 @@ extern "C" void cacRecvThreadTCP ( void *pParam ) } else { pComBuf->destroy (); - epicsAutoMutex autoMutex ( piiu->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( piiu->pCAC()->mutexRef() ); nBytes = piiu->recvQue.occupiedBytes (); } } else { // no way to be informed when memory is available epicsThreadSleep ( 0.5 ); - epicsAutoMutex autoMutex ( piiu->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( piiu->pCAC()->mutexRef() ); nBytes = piiu->recvQue.occupiedBytes (); } } @@ -523,7 +486,7 @@ void tcpiiu::connect () this->sendDog.cancel (); - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( this->pCAC()->mutexRef() ); if ( this->state == iiu_connecting ) { // put the iiu into the connected state @@ -569,7 +532,7 @@ void tcpiiu::cleanShutdown () this->sendDog.cancel (); this->recvDog.cancel (); - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( this->pCAC()->mutexRef() ); if ( this->state == iiu_connected ) { int status = ::shutdown ( this->sock, SD_BOTH ); @@ -614,7 +577,7 @@ void tcpiiu::forcedShutdown () this->sendDog.cancel (); this->recvDog.cancel (); - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( this->pCAC()->mutexRef() ); if ( this->state != iiu_disconnected ) { // force abortive shutdown sequence (discard outstanding sends @@ -645,16 +608,14 @@ void tcpiiu::forcedShutdown () this->pCAC ()->signalRecvActivity (); } -void tcpiiu::disconnect () +// +// tcpiiu::~tcpiiu () +// +tcpiiu::~tcpiiu () { - assert ( this->fullyConstructedFlag ); - - CAFDHANDLER *fdRegFunc; - void *fdRegArg; - this->pCAC ()->getFDRegCallback ( fdRegFunc, fdRegArg ); - if ( fdRegFunc ) { - ( *fdRegFunc ) ( fdRegArg, this->sock, false ); - } + if ( ! this->fullyConstructedFlag ) { + return; + } this->cleanShutdown (); @@ -719,7 +680,7 @@ void tcpiiu::disconnect () * free message body cache */ { - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( this->pCAC()->mutexRef() ); if ( this->pCurData ) { delete [] this->pCurData; @@ -746,17 +707,6 @@ void tcpiiu::disconnect () while ( this->blockingForFlush ) { epicsThreadSleep ( 0.1 ); } -} - - -// -// tcpiiu::~tcpiiu () -// -tcpiiu::~tcpiiu () -{ - if ( ! this->fullyConstructedFlag ) { - return; - } epicsEventDestroy ( this->sendThreadExitSignal ); epicsEventDestroy ( this->recvThreadExitSignal ); @@ -769,7 +719,7 @@ tcpiiu::~tcpiiu () } } -void tcpiiu::suicide () +void tcpiiu::destroy () { delete this; } @@ -801,13 +751,13 @@ bool tcpiiu::isVirtaulCircuit ( const char *pChannelName, const osiSockAddr &add } if ( ! match ) { - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); char acc[64]; if ( this->pHostNameCache ) { this->pHostNameCache->hostName ( acc, sizeof ( acc ) ); assert ( this->pCAC () ); msgForMultiplyDefinedPV *pMsg = new msgForMultiplyDefinedPV ( - *this->pCAC (), pChannelName, acc, addr ); + *this->pCAC (), pChannelName, acc, addrIn ); if ( pMsg ) { this->pCAC ()->ipAddrToAsciiAsynchronousRequestInstall ( *pMsg ); } @@ -819,7 +769,7 @@ bool tcpiiu::isVirtaulCircuit ( const char *pChannelName, const osiSockAddr &add void tcpiiu::show ( unsigned level ) const { - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); char buf[256]; if ( this->pHostNameCache ) { this->pHostNameCache->hostName ( buf, sizeof ( buf ) ); @@ -863,7 +813,7 @@ void tcpiiu::show ( unsigned level ) const bool tcpiiu::setEchoRequestPending () { { - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); this->echoRequestPending = true; } this->flushRequest (); @@ -880,10 +830,10 @@ bool tcpiiu::setEchoRequestPending () /* * tcpiiu::hostNameSetRequest () */ -int tcpiiu::hostNameSetRequest () +void tcpiiu::hostNameSetRequest () { if ( ! CA_V41 ( CA_PROTOCOL_VERSION, this->minorProtocolVersion ) ) { - return ECA_NORMAL; + return; } const char *pName = localHostNameAtLoadTime.pointer (); @@ -895,31 +845,27 @@ int tcpiiu::hostNameSetRequest () this->flushRequest (); } - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); - int status = this->sendQue.reserveSpace ( postSize + 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_HOST_NAME ); // cmd - this->sendQue.pushUInt16 ( postSize ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( static_cast ( 0u ) ); // cid - this->sendQue.pushUInt32 ( static_cast ( 0u ) ); // available + this->sendQue.reserveSpace ( postSize + 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_HOST_NAME ); // cmd + this->sendQue.pushUInt16 ( postSize ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( static_cast ( 0u ) ); // cid + this->sendQue.pushUInt32 ( static_cast ( 0u ) ); // available - this->sendQue.pushString ( pName, size ); - this->sendQue.pushString ( nillBytes, postSize - size ); - } - - return status; + this->sendQue.pushString ( pName, size ); + this->sendQue.pushString ( nillBytes, postSize - size ); } /* * tcpiiu::userNameSetRequest () */ -int tcpiiu::userNameSetRequest () +void tcpiiu::userNameSetRequest () { if ( ! CA_V41 ( CA_PROTOCOL_VERSION, this->minorProtocolVersion ) ) { - return ECA_NORMAL; + return; } const char *pName = this->pCAC ()->userNamePointer (); @@ -931,493 +877,206 @@ int tcpiiu::userNameSetRequest () this->flushRequest (); } - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); - int status = this->sendQue.reserveSpace ( postSize + 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_CLIENT_NAME ); // cmd - this->sendQue.pushUInt16 ( postSize ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( 0u ); // cid - this->sendQue.pushUInt32 ( 0u ); // available + this->sendQue.reserveSpace ( postSize + 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_CLIENT_NAME ); // cmd + this->sendQue.pushUInt16 ( postSize ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( 0u ); // cid + this->sendQue.pushUInt32 ( 0u ); // available - this->sendQue.pushString ( pName, size ); - this->sendQue.pushString ( nillBytes, postSize - size ); - } - - return status; + this->sendQue.pushString ( pName, size ); + this->sendQue.pushString ( nillBytes, postSize - size ); } -int tcpiiu::disableFlowControlRequest () +void tcpiiu::disableFlowControlRequest () { if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest (); } - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_EVENTS_ON ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( 0u ); // cid - this->sendQue.pushUInt32 ( 0u ); // available - } - - return status; + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_EVENTS_ON ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( 0u ); // cid + this->sendQue.pushUInt32 ( 0u ); // available } -int tcpiiu::enableFlowControlRequest () +void tcpiiu::enableFlowControlRequest () { if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest (); } - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_EVENTS_OFF ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( 0u ); // cid - this->sendQue.pushUInt32 ( 0u ); // available - } - - return status; + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_EVENTS_OFF ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( 0u ); // cid + this->sendQue.pushUInt32 ( 0u ); // available } -int tcpiiu::noopRequest () +void tcpiiu::noopRequest () { if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest (); } - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_NOOP ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( 0u ); // cid - this->sendQue.pushUInt32 ( 0u ); // available - } - - return status; + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_NOOP ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( 0u ); // cid + this->sendQue.pushUInt32 ( 0u ); // available } -int tcpiiu::echoRequest () +void tcpiiu::echoRequest () { if ( this->sendQue.flushEarlyThreshold ( 16u ) ) { this->flushRequest (); } - epicsAutoMutex locker ( this->pCAC()->mutex() ); + epicsAutoMutex locker ( this->pCAC()->mutexRef() ); - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_ECHO ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( 0u ); // cid - this->sendQue.pushUInt32 ( 0u ); // available - } - - return status; + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_ECHO ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( 0u ); // cid + this->sendQue.pushUInt32 ( 0u ); // available } -bool tcpiiu::noopAction () -{ - return true; -} - -bool tcpiiu::echoRespAction () -{ - return true; -} - -bool tcpiiu::writeNotifyRespAction () -{ - int status = this->curMsg.m_cid; - if ( status == ECA_NORMAL ) { - return this->pCAC()->ioCompletionNotifyAndDestroy ( this->curMsg.m_available ); - } - else { - return this->pCAC()->ioExceptionNotifyAndDestroy ( this->curMsg.m_available, - status, "write notify request rejected" ); - } -} - -bool tcpiiu::readNotifyRespAction () -{ - int v41; - int status; - - /* - * convert the data buffer from net - * format to host format - */ -# ifdef CONVERSION_REQUIRED - if ( this->curMsg.m_dataType < NELEMENTS ( cac_dbr_cvrt ) ) { - ( *cac_dbr_cvrt[ this->curMsg.m_dataType ] ) ( - this->pCurData, this->pCurData, false, this->curMsg.m_count); - } - else { - this->curMsg.m_cid = htonl ( ECA_BADTYPE ); - } -# endif - - /* - * the channel id field is abused for - * read notify status starting - * with CA V4.1 - */ - v41 = CA_V41 ( CA_PROTOCOL_VERSION, this->minorProtocolVersion ); - if (v41) { - status = this->curMsg.m_cid; - } - else { - status = ECA_NORMAL; - } - - if ( status == ECA_NORMAL ) { - return this->pCAC()->ioCompletionNotifyAndDestroy ( this->curMsg.m_available, - this->curMsg.m_dataType, this->curMsg.m_count, this->pCurData ); - } - else { - return this->pCAC()->ioExceptionNotifyAndDestroy ( this->curMsg.m_available, - status, "read failed", this->curMsg.m_dataType, this->curMsg.m_count ); - } -} - -bool tcpiiu::eventRespAction () -{ - /* - * m_postsize = 0 used to be a confirmation, but is - * now a noop because the IO block is immediately - * deleted - */ - if ( ! this->curMsg.m_postsize ) { - return true; - } - - /* - * convert the data buffer from net format to host format - */ -# ifdef CONVERSION_REQUIRED - if ( this->curMsg.m_dataType < NELEMENTS ( cac_dbr_cvrt ) ) { - ( *cac_dbr_cvrt [ this->curMsg.m_dataType ] )( - this->pCurData, this->pCurData, false, - this->curMsg.m_count); - } - else { - this->curMsg.m_cid = htonl ( ECA_BADTYPE ); - } -# endif - - /* - * the channel id field is abused for - * read notify status starting - * with CA V4.1 - */ - int status; - int v41 = CA_V41 ( CA_PROTOCOL_VERSION, this->minorProtocolVersion ); - if ( v41 ) { - status = this->curMsg.m_cid; - } - else { - status = ECA_NORMAL; - } - if ( status == ECA_NORMAL ) { - return this->pCAC()->ioCompletionNotify ( this->curMsg.m_available, - this->curMsg.m_dataType, this->curMsg.m_count, this->pCurData ); - } - else { - return this->pCAC()->ioExceptionNotify ( this->curMsg.m_available, - status, "subscription update failed", - this->curMsg.m_dataType, this->curMsg.m_count ); - } -} - -bool tcpiiu::readRespAction () -{ - return this->pCAC()->ioCompletionNotifyAndDestroy ( this->curMsg.m_available, - this->curMsg.m_dataType, this->curMsg.m_count, this->pCurData ); -} - -bool tcpiiu::clearChannelRespAction () -{ - return true; // currently a noop -} - -bool tcpiiu::exceptionRespAction () -{ - const caHdr * req = reinterpret_cast < const caHdr * > ( this->pCurData ); - char context[255]; - char hostName[64]; - - { - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); - - const char *pName = reinterpret_cast < const char * > ( req + 1 ); - - if ( this->pHostNameCache ) { - this->pHostNameCache->hostName ( hostName, sizeof ( hostName ) ); - if ( this->curMsg.m_postsize > sizeof (caHdr) ) { - sprintf ( context, "detected by: %s for: %s", - hostName, pName); - } - else{ - sprintf ( context, "for: %s", pName ); - } - } - else { - sprintf ( context, "for: %s", pName ); - } - } - - switch ( ntohs ( req->m_cmmd ) ) { - case CA_PROTO_READ_NOTIFY: - return this->pCAC()->ioExceptionNotifyAndDestroy ( ntohl ( req->m_available ), - ntohl ( this->curMsg.m_available ), context, - ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); - case CA_PROTO_READ: - return this->pCAC()->ioExceptionNotifyAndDestroy ( ntohl (req->m_available), - ntohl ( this->curMsg.m_available ), context, - ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); - case CA_PROTO_WRITE_NOTIFY: - return this->pCAC()->ioExceptionNotifyAndDestroy ( ntohl (req->m_available), - ntohl ( this->curMsg.m_available ), context, - ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); - case CA_PROTO_WRITE: - this->pCAC()->exceptionNotify ( ntohl ( this->curMsg.m_available ), - context, ntohs ( req->m_dataType ), ntohs ( req->m_count ), __FILE__, __LINE__); - return true; - case CA_PROTO_EVENT_ADD: - return this->pCAC()->ioExceptionNotify ( ntohl ( req->m_available ), - ntohl ( this->curMsg.m_available ), context, - ntohs ( req->m_dataType ), ntohs ( req->m_count ) ); - case CA_PROTO_EVENT_CANCEL: - return this->pCAC()->ioExceptionNotifyAndDestroy ( ntohl ( req->m_available ), - ntohl ( this->curMsg.m_available ), context ); - default: - this->pCAC()->exceptionNotify ( ntohl ( this->curMsg.m_available ), - context, __FILE__, __LINE__ ); - return true; - } -} - -bool tcpiiu::accessRightsRespAction () -{ - static caar init; - caar arBitField = init; // shut up bounds checker - unsigned ar = this->curMsg.m_available; - - arBitField.read_access = ( ar & CA_PROTO_ACCESS_RIGHT_READ ) ? 1 : 0; - arBitField.write_access = ( ar & CA_PROTO_ACCESS_RIGHT_WRITE ) ? 1 : 0; - - this->pCAC ()->accessRightsNotify ( this->curMsg.m_cid, arBitField ); - - return true; -} - -bool tcpiiu::claimCIURespAction () -{ - return this->pCAC ()->connectChannel ( this->ca_v44_ok (), this->curMsg.m_cid, - this->curMsg.m_dataType, this->curMsg.m_count, this->curMsg.m_available ); -} - -bool tcpiiu::verifyAndDisconnectChan () -{ - this->pCAC ()->disconnectChannel ( this->curMsg.m_cid ); - return true; -} - -bool tcpiiu::badTCPRespAction () -{ - char hostName[64]; - bool hostNameInit; - { - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); - if ( this->pHostNameCache ) { - this->pHostNameCache->hostName ( hostName, sizeof ( hostName ) ); - hostNameInit = true; - } - else { - hostNameInit = false; - } - } - - if ( hostNameInit ) { - ca_printf ( "CAC: Undecipherable TCP message ( bad response type %u ) from %s\n", - hostName, this->curMsg.m_cmmd); - } - else { - ca_printf ( "CAC: Undecipherable TCP message ( bad response type %u )\n", - this->curMsg.m_cmmd); - } - return false; -} - -/* - * tcpiiu::processIncoming () - */ +// +// tcpiiu::processIncoming() +// void tcpiiu::processIncoming () { - // force fd reg callback to occur through the - // recv process thread - if ( this->fdRegCallbackNeeded ) { - this->fdRegCallbackNeeded = false; - CAFDHANDLER *fdRegFunc; - void *fdRegArg; - this->pCAC ()->getFDRegCallback ( fdRegFunc, fdRegArg ); - if ( fdRegFunc ) { - ( *fdRegFunc ) ( fdRegArg, this->sock, true ); - } - } - while ( 1 ) { unsigned nBytes; - bool signalNeeded; // // fetch a complete message header // - { - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + nBytes = this->recvQue.occupiedBytes (); - nBytes = this->recvQue.occupiedBytes (); + if ( ! this->msgHeaderAvailable ) { + + this->msgHeaderAvailable = this->recvQue.copyOutBytes ( + &this->curMsg, sizeof ( this->curMsg ) ); if ( ! this->msgHeaderAvailable ) { - - this->msgHeaderAvailable = this->recvQue.copyOutBytes ( - &this->curMsg, sizeof ( this->curMsg ) ); - - if ( ! this->msgHeaderAvailable ) { - return; - } - - // - // fix endian of bytes - // - this->curMsg.m_cmmd = ntohs ( this->curMsg.m_cmmd ); - this->curMsg.m_postsize = ntohs ( this->curMsg.m_postsize ); - this->curMsg.m_dataType = ntohs ( this->curMsg.m_dataType ); - this->curMsg.m_count = ntohs ( this->curMsg.m_count ); - this->curMsg.m_cid = ntohl ( this->curMsg.m_cid ); - this->curMsg.m_available = ntohl ( this->curMsg.m_available ); - - debugPrintf ( - ( "%s Cmd=%3d Type=%3d Count=%4d Size=%4d", - this->pHostName (), - this->curMsg.m_cmmd, - this->curMsg.m_dataType, - this->curMsg.m_count, - this->curMsg.m_postsize) ); - - debugPrintf ( - ( " Avail=%8x Cid=%6d\n", - this->curMsg.m_available, - this->curMsg.m_cid) ); - } - - // - // dont allow huge msg body until - // the client library supports it - // - if ( this->curMsg.m_postsize > ( unsigned ) MAX_TCP ) { - this->msgHeaderAvailable = false; - ca_printf ( "CAC: message body was too large ( disconnecting )\n" ); - this->cleanShutdown (); return; } // - // make sure we have a large enough message body cache + // fix endian of bytes // - if ( this->curMsg.m_postsize > this->curDataMax ) { + this->curMsg.m_cmmd = ntohs ( this->curMsg.m_cmmd ); + this->curMsg.m_postsize = ntohs ( this->curMsg.m_postsize ); + this->curMsg.m_dataType = ntohs ( this->curMsg.m_dataType ); + this->curMsg.m_count = ntohs ( this->curMsg.m_count ); + this->curMsg.m_cid = ntohl ( this->curMsg.m_cid ); + this->curMsg.m_available = ntohl ( this->curMsg.m_available ); - /* - * scalar DBR_STRING is sometimes clipped to the - * actual string size so make sure this cache is - * as large as one DBR_STRING so they will - * not page fault if they read MAX_STRING_SIZE - * bytes (instead of the actual string size). - */ - unsigned cacheSize = this->curMsg.m_postsize * 2u; - if ( cacheSize < MAX_STRING_SIZE ) { - cacheSize = MAX_STRING_SIZE; - } + debugPrintf ( + ( "%s Cmd=%3d Type=%3d Count=%4d Size=%4d", + this->pHostName (), + this->curMsg.m_cmmd, + this->curMsg.m_dataType, + this->curMsg.m_count, + this->curMsg.m_postsize) ); - char *pData = new char [cacheSize]; - if ( ! pData ) { - ca_printf ("CAC: not enough memory for message body cache (disconnecting)\n"); - this->cleanShutdown (); - return; - } - if ( this->pCurData ) { - delete [] this->pCurData; - } - this->pCurData = pData; - this->curDataMax = cacheSize; + debugPrintf ( + ( " Avail=%8x Cid=%6d\n", + this->curMsg.m_available, + this->curMsg.m_cid) ); + } + + // + // dont allow huge msg body until + // the client library supports it + // + if ( this->curMsg.m_postsize > ( unsigned ) MAX_TCP ) { + this->msgHeaderAvailable = false; + ca_printf ( "CAC: message body was too large ( disconnecting )\n" ); + this->cleanShutdown (); + return; + } + + // + // make sure we have a large enough message body cache + // + if ( this->curMsg.m_postsize > this->curDataMax ) { + + /* + * scalar DBR_STRING is sometimes clipped to the + * actual string size so make sure this cache is + * as large as one DBR_STRING so they will + * not page fault if they read MAX_STRING_SIZE + * bytes (instead of the actual string size). + */ + unsigned cacheSize = this->curMsg.m_postsize * 2u; + if ( cacheSize < MAX_STRING_SIZE ) { + cacheSize = MAX_STRING_SIZE; } - if ( this->curMsg.m_postsize > 0u ) { - bool msgBodyAvailable = this->recvQue.copyOutBytes ( - this->pCurData, this->curMsg.m_postsize ); - if ( ! msgBodyAvailable ) { - return; - } + char *pData = new char [cacheSize]; + if ( ! pData ) { + ca_printf ("CAC: not enough memory for message body cache (disconnecting)\n"); + this->cleanShutdown (); + return; } + if ( this->pCurData ) { + delete [] this->pCurData; + } + this->pCurData = pData; + this->curDataMax = cacheSize; + } - if ( nBytes >= maxBytesPendingTCP && - this->recvQue.occupiedBytes () < maxBytesPendingTCP ) { - signalNeeded = true; - } - else { - signalNeeded = false; + if ( this->curMsg.m_postsize > 0u ) { + bool msgBodyAvailable = this->recvQue.copyOutBytes ( + this->pCurData, this->curMsg.m_postsize ); + if ( ! msgBodyAvailable ) { + return; } } - if ( signalNeeded ) { + if ( nBytes >= maxBytesPendingTCP && + this->recvQue.occupiedBytes () < maxBytesPendingTCP ) { epicsEventSignal ( this->recvThreadRingBufferSpaceAvailableSignal ); } - /* - * execute the response message - */ - pProtoStubTCP pStub; - if ( this->curMsg.m_cmmd >= NELEMENTS ( tcpJumpTableCAC ) ) { - pStub = &tcpiiu::badTCPRespAction; - } - else { - pStub = tcpJumpTableCAC [this->curMsg.m_cmmd]; - } - ( this->*pStub ) (); + this->pCAC()->executeResponse ( *this, this->curMsg, this->pCurData ); this->msgHeaderAvailable = false; } } -int tcpiiu::writeRequest ( nciu &chan, unsigned type, unsigned nElem, const void *pValue ) +void tcpiiu::writeRequest ( nciu &chan, unsigned type, unsigned nElem, const void *pValue ) { if ( ! chan.connected () ) { - return ECA_DISCONNCHID; + throw cacChannel::notConnected(); } if ( ! this->sendQue.dbr_type_ok ( type ) ) { - return ECA_BADTYPE; + throw cacChannel::badType(); } if ( nElem > 0xffff) { - return ECA_BADCOUNT; + throw cacChannel::outOfBounds(); } bool stringOptim; @@ -1434,46 +1093,42 @@ int tcpiiu::writeRequest ( nciu &chan, unsigned type, unsigned nElem, const void unsigned postcnt = CA_MESSAGE_ALIGN ( size ); if ( postcnt > 0xffff ) { - return ECA_BADCOUNT; + throw cacChannel::unsupportedByService(); } - int status = this->sendQue.reserveSpace ( postcnt + 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_WRITE ); // cmd - this->sendQue.pushUInt16 ( postcnt ); // postsize - this->sendQue.pushUInt16 ( type ); // dataType - this->sendQue.pushUInt16 ( nElem ); // count - this->sendQue.pushUInt32 ( chan.getSID () ); // cid - this->sendQue.pushUInt32 ( ~0UL ); // available - if ( stringOptim ) { - this->sendQue.pushString ( static_cast < const char * > ( pValue ), size ); - } - else { - this->sendQue.push_dbr_type ( type, pValue, nElem ); - } - this->sendQue.pushString ( nillBytes, postcnt - size ); + this->sendQue.reserveSpace ( postcnt + 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_WRITE ); // cmd + this->sendQue.pushUInt16 ( postcnt ); // postsize + this->sendQue.pushUInt16 ( type ); // dataType + this->sendQue.pushUInt16 ( nElem ); // count + this->sendQue.pushUInt32 ( chan.getSID () ); // cid + this->sendQue.pushUInt32 ( ~0UL ); // available + if ( stringOptim ) { + this->sendQue.pushString ( static_cast < const char * > ( pValue ), size ); } - - return status; + else { + this->sendQue.push_dbr_type ( type, pValue, nElem ); + } + this->sendQue.pushString ( nillBytes, postcnt - size ); } -int tcpiiu::writeNotifyRequest ( nciu &chan, netWriteNotifyIO &io, unsigned type, +void tcpiiu::writeNotifyRequest ( nciu &chan, netWriteNotifyIO &io, unsigned type, unsigned nElem, const void *pValue ) { if ( ! chan.connected () ) { - return ECA_DISCONNCHID; + throw cacChannel::notConnected(); } if ( ! this->ca_v41_ok () ) { - return ECA_NOSUPPORT; + throw cacChannel::unsupportedByService(); } if ( ! this->sendQue.dbr_type_ok ( type ) ) { - return ECA_BADTYPE; + throw cacChannel::badType(); } if ( nElem > 0xffff ) { - return ECA_BADCOUNT; + throw cacChannel::unsupportedByService(); } ca_uint32_t size; @@ -1489,55 +1144,49 @@ int tcpiiu::writeNotifyRequest ( nciu &chan, netWriteNotifyIO &io, unsigned type } ca_uint32_t postcnt = CA_MESSAGE_ALIGN ( size ); if ( postcnt > 0xffff ) { - return ECA_BADCOUNT; + throw cacChannel::unsupportedByService(); } - int status = this->sendQue.reserveSpace ( postcnt + 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_WRITE_NOTIFY ); // cmd - this->sendQue.pushUInt16 ( postcnt ); // postsize - this->sendQue.pushUInt16 ( type ); // dataType - this->sendQue.pushUInt16 ( nElem ); // count - this->sendQue.pushUInt32 ( chan.getSID () ); // cid - this->sendQue.pushUInt32 ( io.getID () ); // available - if ( stringOptim ) { - this->sendQue.pushString ( static_cast < const char * > ( pValue ), size ); - } - else { - this->sendQue.push_dbr_type ( type, pValue, nElem ); - } - this->sendQue.pushString ( nillBytes, postcnt - size ); + this->sendQue.reserveSpace ( postcnt + 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_WRITE_NOTIFY ); // cmd + this->sendQue.pushUInt16 ( postcnt ); // postsize + this->sendQue.pushUInt16 ( type ); // dataType + this->sendQue.pushUInt16 ( nElem ); // count + this->sendQue.pushUInt32 ( chan.getSID () ); // cid + this->sendQue.pushUInt32 ( io.getID () ); // available + if ( stringOptim ) { + this->sendQue.pushString ( static_cast < const char * > ( pValue ), size ); } - return status; + else { + this->sendQue.push_dbr_type ( type, pValue, nElem ); + } + this->sendQue.pushString ( nillBytes, postcnt - size ); } -int tcpiiu::readNotifyRequest ( nciu &chan, netReadNotifyIO &io, +void tcpiiu::readNotifyRequest ( nciu &chan, netReadNotifyIO &io, unsigned type, unsigned nElem ) { if ( ! chan.connected () ) { - return ECA_DISCONNCHID; + throw cacChannel::notConnected(); } if ( nElem > 0xffff) { - return ECA_BADCOUNT; - } + throw cacChannel::unsupportedByService(); + } if ( type > 0xffff) { - return ECA_BADTYPE; - } + throw cacChannel::unsupportedByService(); + } - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_READ_NOTIFY ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( type ); // dataType - this->sendQue.pushUInt16 ( nElem ); // count - this->sendQue.pushUInt32 ( chan.getSID () ); // cid - this->sendQue.pushUInt32 ( io.getID () ); // available - } - return status; + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_READ_NOTIFY ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( type ); // dataType + this->sendQue.pushUInt16 ( nElem ); // count + this->sendQue.pushUInt32 ( chan.getSID () ); // cid + this->sendQue.pushUInt32 ( io.getID () ); // available } -int tcpiiu::createChannelRequest ( nciu &chan ) +void tcpiiu::createChannelRequest ( nciu &chan ) { const char *pName; unsigned nameLength; @@ -1556,57 +1205,49 @@ int tcpiiu::createChannelRequest ( nciu &chan ) unsigned postCnt = CA_MESSAGE_ALIGN ( nameLength ); if ( postCnt > 0xffff ) { - return ECA_INTERNAL; + throw cacChannel::unsupportedByService(); } - int status = this->sendQue.reserveSpace ( postCnt + 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_CLAIM_CIU ); // cmd - this->sendQue.pushUInt16 ( postCnt ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( identity ); // cid - // - // The available field is used (abused) - // here to communicate the minor version number - // starting with CA 4.1. - // - this->sendQue.pushUInt32 ( CA_MINOR_VERSION ); // available - if ( nameLength ) { - this->sendQue.pushString ( pName, nameLength ); - } - if ( postCnt > nameLength ) { - this->sendQue.pushString ( nillBytes, postCnt - nameLength ); - } + this->sendQue.reserveSpace ( postCnt + 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_CLAIM_CIU ); // cmd + this->sendQue.pushUInt16 ( postCnt ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( identity ); // cid + // + // The available field is used (abused) + // here to communicate the minor version number + // starting with CA 4.1. + // + this->sendQue.pushUInt32 ( CA_MINOR_VERSION ); // available + if ( nameLength ) { + this->sendQue.pushString ( pName, nameLength ); + } + if ( postCnt > nameLength ) { + this->sendQue.pushString ( nillBytes, postCnt - nameLength ); } - - return status; } -int tcpiiu::clearChannelRequest ( nciu &chan ) +void tcpiiu::clearChannelRequest ( nciu &chan ) { - if ( ! chan.connected () ) { - return ECA_DISCONNCHID; - } - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_CLEAR_CHANNEL ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( 0u ); // dataType - this->sendQue.pushUInt16 ( 0u ); // count - this->sendQue.pushUInt32 ( chan.getSID () ); // cid - this->sendQue.pushUInt32 ( chan.getCID () ); // available - } - return status; + // we go ahead and send this even if the channel isnt connected + // because we dont want to leak the resource in the server + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_CLEAR_CHANNEL ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( 0u ); // dataType + this->sendQue.pushUInt16 ( 0u ); // count + this->sendQue.pushUInt32 ( chan.getSID () ); // cid + this->sendQue.pushUInt32 ( chan.getCID () ); // available } // // this routine return void because if this internally fails the best response // is to try again the next time that we reconnect // -void tcpiiu::subscriptionRequest ( netSubscription & subscr ) +void tcpiiu::subscriptionRequest ( nciu &chan, netSubscription & subscr ) { - if ( ! subscr.channel().connected() ) { + if ( ! chan.connected() ) { return; } @@ -1620,43 +1261,39 @@ void tcpiiu::subscriptionRequest ( netSubscription & subscr ) return; } - unsigned long count = subscr.getCount (); + unsigned long count = subscr.getCount ( chan ); if ( count == 0u || count > 0xffff ) { this->pCAC()->printf ( "CAC: subscriptionRequest() ignored because of unexpected bad count that was checked earlier\n" ); return; } - int status = this->sendQue.reserveSpace ( 32u ); - if ( status == ECA_NORMAL ) { + this->sendQue.reserveSpace ( 32u ); - // header - this->sendQue.pushUInt16 ( CA_PROTO_EVENT_ADD ); // cmd - this->sendQue.pushUInt16 ( 16u ); // postsize - this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getType () ) ); // dataType - this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( count ) ); // count - this->sendQue.pushUInt32 ( subscr . channel () . getSID () ); // cid - this->sendQue.pushUInt32 ( subscr . getID () ); // available + // header + this->sendQue.pushUInt16 ( CA_PROTO_EVENT_ADD ); // cmd + this->sendQue.pushUInt16 ( 16u ); // postsize + this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getType () ) ); // dataType + this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( count ) ); // count + this->sendQue.pushUInt32 ( chan.getSID() ); // cid + this->sendQue.pushUInt32 ( subscr.getID() ); // available - // extension - this->sendQue.pushFloat32 ( 0.0 ); // m_lval - this->sendQue.pushFloat32 ( 0.0 ); // m_hval - this->sendQue.pushFloat32 ( 0.0 ); // m_toval - this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getMask () ) ); // m_mask - this->sendQue.pushUInt16 ( 0u ); // m_pad - } + // extension + this->sendQue.pushFloat32 ( 0.0 ); // m_lval + this->sendQue.pushFloat32 ( 0.0 ); // m_hval + this->sendQue.pushFloat32 ( 0.0 ); // m_toval + this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getMask () ) ); // m_mask + this->sendQue.pushUInt16 ( 0u ); // m_pad } -void tcpiiu::subscriptionCancelRequest ( netSubscription &subscr ) +void tcpiiu::subscriptionCancelRequest ( nciu &chan, netSubscription &subscr ) { - int status = this->sendQue.reserveSpace ( 16u ); - if ( status == ECA_NORMAL ) { - this->sendQue.pushUInt16 ( CA_PROTO_EVENT_CANCEL ); // cmd - this->sendQue.pushUInt16 ( 0u ); // postsize - this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getType () ) ); // dataType - this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getCount () ) ); // count - this->sendQue.pushUInt32 ( subscr.channel ().getSID () ); // cid - this->sendQue.pushUInt32 ( subscr.getID () ); // available - } + this->sendQue.reserveSpace ( 16u ); + this->sendQue.pushUInt16 ( CA_PROTO_EVENT_CANCEL ); // cmd + this->sendQue.pushUInt16 ( 0u ); // postsize + this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getType () ) ); // dataType + this->sendQue.pushUInt16 ( static_cast < ca_uint16_t > ( subscr.getCount ( chan ) ) ); // count + this->sendQue.pushUInt32 ( chan.getSID () ); // cid + this->sendQue.pushUInt32 ( subscr.getID() ); // available } void tcpiiu::lastChannelDetachNotify () @@ -1670,7 +1307,7 @@ bool tcpiiu::flush () comBuf * pBuf; { - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( this->pCAC()->mutexRef() ); pBuf = this->sendQue.popNextComBufToSend (); if ( ! pBuf ) { if ( this->blockingForFlush ) { @@ -1686,7 +1323,7 @@ bool tcpiiu::flush () pBuf->destroy (); if ( ! success ) { - epicsAutoMutex autoMutex ( this->pCAC()->mutex() ); + epicsAutoMutex autoMutex ( this->pCAC()->mutexRef() ); while ( ( pBuf = this->sendQue.popNextComBufToSend () ) ) { pBuf->destroy (); } diff --git a/src/ca/tcpiiu_IL.h b/src/ca/tcpiiu_IL.h index c574b7993..29f7211db 100644 --- a/src/ca/tcpiiu_IL.h +++ b/src/ca/tcpiiu_IL.h @@ -23,7 +23,6 @@ inline bool tcpiiu::fullyConstructed () const inline void tcpiiu::hostName ( char *pBuf, unsigned bufLength ) const { - epicsAutoMutex locker ( this->pCAC()->mutex() ); if ( this->pHostNameCache ) { this->pHostNameCache->hostName ( pBuf, bufLength ); } @@ -80,3 +79,16 @@ inline void tcpiiu::beaconArrivalNotify () { this->recvDog.beaconArrivalNotify (); } + +inline void tcpiiu::fdCreateNotify ( epicsMutex &mutex, CAFDHANDLER *func, void *pArg ) +{ + if ( this->fdRegCallbackNeeded ) { + epicsAutoMutexRelease autoRelease ( mutex ); + ( *func ) ( pArg, this->sock, true ); + } +} + +inline void tcpiiu::fdDestroyNotify ( CAFDHANDLER *func, void *pArg ) +{ + ( *func ) ( pArg, this->sock, false ); +} \ No newline at end of file diff --git a/src/ca/udpiiu.cpp b/src/ca/udpiiu.cpp index 95be8de66..3fbb6bab8 100644 --- a/src/ca/udpiiu.cpp +++ b/src/ca/udpiiu.cpp @@ -162,13 +162,6 @@ udpiiu::udpiiu ( cac &cac ) : } caStartRepeaterIfNotInstalled ( this->repeaterPort ); - - CAFDHANDLER *fdRegFunc; - void *fdRegArg; - this->pCAC ()->getFDRegCallback ( fdRegFunc, fdRegArg ); - if ( fdRegFunc ) { - ( *fdRegFunc ) ( fdRegArg, this->sock, true ); - } } /* @@ -182,13 +175,6 @@ udpiiu::~udpiiu () epicsEventDestroy ( this->recvThreadExitSignal ); ellFree ( &this->dest ); - - CAFDHANDLER *fdRegFunc; - void *fdRegArg; - this->pCAC ()->getFDRegCallback ( fdRegFunc, fdRegArg ); - if ( fdRegFunc ) { - ( *fdRegFunc ) ( fdRegArg, this->sock, false ); - } if ( ! this->sockCloseCompleted ) { socket_close ( this->sock ); diff --git a/src/ca/udpiiu_IL.h b/src/ca/udpiiu_IL.h index 84bd0250e..2fe1137cd 100644 --- a/src/ca/udpiiu_IL.h +++ b/src/ca/udpiiu_IL.h @@ -28,5 +28,15 @@ inline unsigned udpiiu::getPort () const return this->localPort; } +inline void udpiiu::fdCreateNotify ( CAFDHANDLER *func, void *pArg ) +{ + ( *func ) ( pArg, this->sock, true ); +} + +inline void udpiiu::fdDestroyNotify ( CAFDHANDLER *func, void *pArg ) +{ + ( *func ) ( pArg, this->sock, false ); +} + #endif // udpiiu_ILh