From 502620ee4edba87f5591748db12d9f80334787ea Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Tue, 19 Oct 2004 20:49:47 +0000 Subject: [PATCH] eliminated redundancy with original ca client API --- src/ca/oldAccess.h | 292 +++++++----------- src/ca/oldChannelNotify.cpp | 577 +++++++++++++++++++++++++++++++----- 2 files changed, 616 insertions(+), 253 deletions(-) diff --git a/src/ca/oldAccess.h b/src/ca/oldAccess.h index 63fd385bf..df83d0559 100644 --- a/src/ca/oldAccess.h +++ b/src/ca/oldAccess.h @@ -55,16 +55,60 @@ public: void destructor ( epicsGuard < epicsMutex > & cbGuard, epicsGuard < epicsMutex > & guard ); - void setPrivatePointer ( - epicsGuard < epicsMutex > &, void * ); - void * privatePointer ( - epicsGuard < epicsMutex > & ) const; - int changeConnCallBack ( - epicsGuard < epicsMutex > &, caCh *pfunc ); - int replaceAccessRightsEvent ( - epicsGuard < epicsMutex > &, caArh *pfunc ); - const char * pName ( - epicsGuard < epicsMutex > & ) const; + + // legacy C API + friend unsigned epicsShareAPI ca_get_host_name ( + chid pChan, char * pBuf, unsigned bufLength ); + friend const char * epicsShareAPI ca_host_name ( + chid pChan ); + friend const char * epicsShareAPI ca_name ( + chid pChan ); + friend void epicsShareAPI ca_set_puser ( + chid pChan, void * puser ); + friend void * epicsShareAPI ca_puser ( + chid pChan ); + friend int epicsShareAPI ca_change_connection_event ( + chid pChan, caCh * pfunc ); + friend int epicsShareAPI ca_replace_access_rights_event ( + chid pChan, caArh *pfunc ); + friend int epicsShareAPI ca_array_get ( chtype type, + arrayElementCount count, chid pChan, void * pValue ); + friend int epicsShareAPI ca_array_get_callback ( chtype type, + arrayElementCount count, chid pChan, + caEventCallBackFunc *pfunc, void *arg ); + friend int epicsShareAPI ca_array_put ( + chtype type, arrayElementCount count, + chid pChan, const void * pValue ); + friend int epicsShareAPI ca_array_put_callback ( + chtype type, arrayElementCount count, + chid pChan, const void *pValue, + caEventCallBackFunc *pfunc, void *usrarg ); + friend double epicsShareAPI ca_beacon_period ( + chid pChan ); + friend unsigned epicsShareAPI ca_search_attempts ( + chid pChan ); + friend unsigned epicsShareAPI ca_write_access ( + chid pChan ); + friend unsigned epicsShareAPI ca_read_access ( + chid pChan ); + friend short epicsShareAPI ca_field_type ( + chid pChan ); + friend arrayElementCount epicsShareAPI ca_element_count ( + chid pChan ); + friend int epicsShareAPI ca_v42_ok ( + chid pChan ); + friend int epicsShareAPI ca_create_subscription ( + chtype type, arrayElementCount count, chid pChan, + long mask, caEventCallBackFunc * pCallBack, + void * pCallBackArg, evid * monixptr ); + friend enum channel_state epicsShareAPI ca_state ( + chid pChan ); + friend double epicsShareAPI ca_receive_watchdog_delay ( + chid pChan ); + + unsigned getName ( + epicsGuard < epicsMutex > &, + char * pBuf, unsigned bufLen ) const throw (); void show ( epicsGuard < epicsMutex > &, unsigned level ) const; @@ -77,22 +121,10 @@ public: epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, cacReadNotify ¬ify, cacChannel::ioid *pId = 0 ); - void read ( - epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, - void *pValue ); - void write ( - epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, - const void *pValue ); void write ( epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void *pValue, cacWriteNotify &, cacChannel::ioid *pId = 0 ); - void subscribe ( - epicsGuard < epicsMutex > &, - unsigned type, arrayElementCount count, unsigned mask, - cacStateNotify &, cacChannel::ioid & ); void ioCancel ( epicsGuard < epicsMutex > & callbackControl, epicsGuard < epicsMutex > & mutualExclusionGuard, @@ -100,29 +132,6 @@ public: void ioShow ( epicsGuard < epicsMutex > & guard, const cacChannel::ioid &, unsigned level ) const; - short nativeType ( - epicsGuard < epicsMutex > & ) const; - arrayElementCount nativeElementCount ( - epicsGuard < epicsMutex > & ) const; - caAccessRights accessRights ( - epicsGuard < epicsMutex > & ) const; - unsigned searchAttempts ( - epicsGuard < epicsMutex > & ) const; - double beaconPeriod ( - epicsGuard < epicsMutex > & ) const; - double receiveWatchdogDelay ( - epicsGuard < epicsMutex > & ) const; - bool ca_v42_ok ( - epicsGuard < epicsMutex > & ) const; - bool connected ( - epicsGuard < epicsMutex > & ) const; - bool previouslyConnected ( - epicsGuard < epicsMutex > & ) const; - void hostName ( - epicsGuard < epicsMutex > &, - char *pBuf, unsigned bufLength ) const; // defaults to local host name - const char * pHostName ( - epicsGuard < epicsMutex > & ) const; // deprecated - please do not use ca_client_context & getClientCtx (); void * operator new ( size_t size, tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & ); @@ -243,26 +252,28 @@ private: void operator delete ( void * ); }; -struct oldSubscription : public cacStateNotify { +struct oldSubscription : private cacStateNotify { public: - oldSubscription ( - oldChannelNotify &, caEventCallBackFunc *pFunc, void *pPrivate ); + oldSubscription ( + epicsGuard < epicsMutex > & guard, + oldChannelNotify & chanIn, cacChannel & io, + unsigned type, arrayElementCount nElem, unsigned mask, + caEventCallBackFunc * pFuncIn, void * pPrivateIn, + evid * ); ~oldSubscription (); - void begin ( epicsGuard < epicsMutex > & guard, unsigned type, - arrayElementCount nElem, unsigned mask ); oldChannelNotify & channel () const; + void cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ); void * operator new ( size_t size, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & ); epicsPlacementDeleteOperator (( void *, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & )) - void ioCancel ( epicsGuard < epicsMutex > & cbGuard, - epicsGuard < epicsMutex > & guard ); private: oldChannelNotify & chan; cacChannel::ioid id; caEventCallBackFunc * pFunc; void * pPrivate; - bool subscribed; void current ( epicsGuard < epicsMutex > &, unsigned type, arrayElementCount count, const void *pData ); @@ -333,6 +344,34 @@ public: void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & ); epicsMutex & mutexRef () const; + friend int epicsShareAPI ca_create_channel ( + const char * name_str, caCh * conn_func, void * puser, + capri priority, chid * chanptr ); + friend int epicsShareAPI ca_clear_channel ( chid pChan ); + friend int epicsShareAPI ca_array_get ( chtype type, + arrayElementCount count, chid pChan, void * pValue ); + friend int epicsShareAPI ca_array_get_callback ( chtype type, + arrayElementCount count, chid pChan, + caEventCallBackFunc *pfunc, void *arg ); + friend int epicsShareAPI ca_array_put ( chtype type, + arrayElementCount count, chid pChan, const void * pValue ); + friend int epicsShareAPI ca_array_put_callback ( chtype type, + arrayElementCount count, chid pChan, const void * pValue, + caEventCallBackFunc *pfunc, void *usrarg ); + friend int epicsShareAPI ca_create_subscription ( + chtype type, arrayElementCount count, chid pChan, + long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, + evid *monixptr ); + + // legacy C API + friend int epicsShareAPI ca_flush_io (); + friend int epicsShareAPI ca_clear_subscription ( evid pMon ); + friend int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ); + friend int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid ); + friend int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeout ); + friend int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid ); + friend int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ); + // exceptions class noSocket {}; private: @@ -368,55 +407,13 @@ private: cacContext & createNetworkContext ( epicsMutex & mutualExclusion, epicsMutex & callbackControl ); void clearSubscriptionPrivate ( - evid pMon, epicsGuard < epicsMutex > & cbGuard ); + epicsGuard < epicsMutex > & cbGuard, oldSubscription & subscr ); ca_client_context ( const ca_client_context & ); ca_client_context & operator = ( const ca_client_context & ); static cacService * pDefaultService; static epicsMutex defaultServiceInstallMutex; - - friend int epicsShareAPI ca_create_channel ( - const char * name_str, caCh * conn_func, void * puser, - capri priority, chid * chanptr ); - friend int epicsShareAPI ca_clear_channel ( chid pChan ); - friend int epicsShareAPI ca_array_get ( chtype type, - arrayElementCount count, chid pChan, void * pValue ); - friend int epicsShareAPI ca_array_get_callback ( chtype type, - arrayElementCount count, chid pChan, - caEventCallBackFunc *pfunc, void *arg ); - friend int epicsShareAPI ca_array_put ( chtype type, - arrayElementCount count, chid pChan, const void * pValue ); - friend int epicsShareAPI ca_array_put_callback ( chtype type, - arrayElementCount count, chid pChan, const void * pValue, - caEventCallBackFunc *pfunc, void *usrarg ); - friend int epicsShareAPI ca_create_subscription ( - chtype type, arrayElementCount count, chid pChan, - long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, - evid *monixptr ); - friend int epicsShareAPI ca_clear_subscription ( evid pMon ); - friend int epicsShareAPI ca_flush_io (); - friend int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ); - friend int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid ); - friend int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeout ); - friend int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid ); - friend int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ); - friend int epicsShareAPI ca_change_connection_event ( chid pChan, caCh *pfunc ); - friend int epicsShareAPI ca_replace_access_rights_event ( chid pChan, caArh *pfunc ); - friend void epicsShareAPI ca_get_host_name ( chid pChan, char *pBuf, unsigned bufLength ); - friend const char * epicsShareAPI ca_host_name ( chid pChan ); - friend int epicsShareAPI ca_v42_ok ( chid pChan ); - friend short epicsShareAPI ca_field_type ( chid pChan ); - friend arrayElementCount epicsShareAPI ca_element_count ( chid pChan ); - friend enum channel_state epicsShareAPI ca_state ( chid pChan ); - friend void epicsShareAPI ca_set_puser ( chid pChan, void *puser ); - friend void * epicsShareAPI ca_puser ( chid pChan ); - friend unsigned epicsShareAPI ca_read_access ( chid pChan ); - friend unsigned epicsShareAPI ca_write_access ( chid pChan ); - friend unsigned epicsShareAPI ca_search_attempts ( chid pChan ); - friend double epicsShareAPI ca_beacon_period ( chid pChan ); - friend double epicsShareAPI ca_receive_watchdog_delay ( chid pChan ); - friend const char * epicsShareAPI ca_name ( chid pChan ); }; int fetchClientContext ( ca_client_context * * ppcac ); @@ -426,10 +423,11 @@ inline ca_client_context & oldChannelNotify::getClientCtx () return this->cacCtx; } -inline const char * oldChannelNotify::pName ( - epicsGuard < epicsMutex > & guard ) const +inline unsigned oldChannelNotify::getName ( + epicsGuard < epicsMutex > & guard, + char * pBuf, unsigned bufLen ) const throw () { - return this->io.pName ( guard ); + return this->io.getName ( guard, pBuf, bufLen ); } inline void oldChannelNotify::show ( @@ -468,75 +466,6 @@ inline void oldChannelNotify::ioShow ( this->io.ioShow ( guard, id, level ); } -inline short oldChannelNotify::nativeType ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.nativeType ( guard ); -} - -inline arrayElementCount oldChannelNotify::nativeElementCount ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.nativeElementCount ( guard ); -} - -inline caAccessRights oldChannelNotify::accessRights ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.accessRights ( guard ); -} - -inline unsigned oldChannelNotify::searchAttempts ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.searchAttempts ( guard ); -} - -inline double oldChannelNotify::beaconPeriod ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.beaconPeriod ( guard ); -} - -inline double oldChannelNotify::receiveWatchdogDelay ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.receiveWatchdogDelay ( guard ); -} - -inline bool oldChannelNotify::ca_v42_ok ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.ca_v42_ok ( guard ); -} - -inline bool oldChannelNotify::connected ( - epicsGuard < epicsMutex > & guard ) const -{ - guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - return this->currentlyConnected; -} - -inline bool oldChannelNotify::previouslyConnected ( - epicsGuard < epicsMutex > & guard ) const -{ - guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - return this->prevConnected; -} - -inline void oldChannelNotify::hostName ( - epicsGuard < epicsMutex > & guard, - char *pBuf, unsigned bufLength ) const -{ - this->io.hostName ( guard, pBuf, bufLength ); -} - -inline const char * oldChannelNotify::pHostName ( - epicsGuard < epicsMutex > & guard ) const -{ - return this->io.pHostName ( guard ); -} - inline void * oldChannelNotify::operator new ( size_t size, tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList ) { @@ -551,24 +480,6 @@ inline void oldChannelNotify::operator delete ( void *pCadaver, } #endif -inline oldSubscription::oldSubscription ( - oldChannelNotify & chanIn, caEventCallBackFunc * pFuncIn, - void * pPrivateIn ) : - chan ( chanIn ), id ( UINT_MAX ), pFunc ( pFuncIn ), - pPrivate ( pPrivateIn ), subscribed ( false ) -{ -} - -inline void oldSubscription::begin ( - epicsGuard < epicsMutex > & guard, unsigned type, - arrayElementCount nElem, unsigned mask ) -{ - this->subscribed = true; - this->chan.subscribe ( guard, type, nElem, mask, *this, this->id ); - // dont touch this pointer after this point because the - // 1st update callback might cancel the subscription -} - inline void * oldSubscription::operator new ( size_t size, tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList ) { @@ -583,6 +494,13 @@ inline void oldSubscription::operator delete ( void *pCadaver, } #endif +inline void oldSubscription::cancel ( + epicsGuard < epicsMutex > & cbGuard, + epicsGuard < epicsMutex > & guard ) +{ + this->chan.ioCancel ( cbGuard, guard, this->id ); +} + inline oldChannelNotify & oldSubscription::channel () const { return this->chan; @@ -632,7 +550,7 @@ inline void getCallback::operator delete ( void * pCadaver, inline bool ca_client_context::preemptiveCallbakIsEnabled () const { - return ! this->pCallbackGuard.get (); + return this->pCallbackGuard.get () == 0; } inline bool ca_client_context::ioComplete () const diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp index 4296b7795..95b95f75a 100644 --- a/src/ca/oldChannelNotify.cpp +++ b/src/ca/oldChannelNotify.cpp @@ -37,6 +37,7 @@ #include "iocinf.h" #include "oldAccess.h" #include "cac.h" +#include "autoPtrFreeList.h" extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args ) { @@ -77,63 +78,6 @@ void oldChannelNotify::destructor ( this->~oldChannelNotify (); } -int oldChannelNotify::changeConnCallBack ( - epicsGuard < epicsMutex > & guard, caCh * pfunc ) -{ - guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - if ( ! this->currentlyConnected ) { - if ( pfunc ) { - if ( ! this->pConnCallBack ) { - this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo ); - } - } - else { - if ( this->pConnCallBack ) { - this->cacCtx.incrementOutstandingIO ( guard, this->ioSeqNo ); - } - } - } - pConnCallBack = pfunc; - - return ECA_NORMAL; -} - -void oldChannelNotify::setPrivatePointer ( - epicsGuard < epicsMutex > & guard, void *pPrivateIn ) -{ - guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - this->pPrivate = pPrivateIn; -} - -void * oldChannelNotify::privatePointer ( - epicsGuard < epicsMutex > & guard ) const -{ - guard.assertIdenticalMutex ( this->cacCtx.mutexRef () ); - return this->pPrivate; -} - -int oldChannelNotify::replaceAccessRightsEvent ( - epicsGuard < epicsMutex > & guard, caArh * pfunc ) -{ - // The order of the following is significant to guarantee that the - // access rights handler is always gets called even if the channel connects - // while this is running. There is some very small chance that the - // handler could be called twice here with the same access rights state, but - // that will not upset the application. - this->pAccessRightsFunc = pfunc ? pfunc : cacNoopAccesRightsHandler; - caAccessRights tmp = this->io.accessRights ( guard ); - - if ( this->currentlyConnected ) { - struct access_rights_handler_args args; - args.chid = this; - args.ar.read_access = tmp.readPermit (); - args.ar.write_access = tmp.writePermit (); - epicsGuardRelease < epicsMutex > unguard ( guard ); - ( *this->pAccessRightsFunc ) ( args ); - } - return ECA_NORMAL; -} - void oldChannelNotify::connectNotify ( epicsGuard < epicsMutex > & guard ) { @@ -238,6 +182,231 @@ void oldChannelNotify::operator delete ( void * ) __FILE__, __LINE__ ); } +/* + * ca_get_host_name () + */ +unsigned epicsShareAPI ca_get_host_name ( + chid pChan, char * pBuf, unsigned bufLength ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef() ); + return pChan->io.getHostName ( guard, pBuf, bufLength ); +} + +/* + * ca_host_name () + * + * !!!! not thread safe !!!! + * + */ +const char * epicsShareAPI ca_host_name ( + chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.pHostName ( guard ); +} + +/* + * ca_set_puser () + */ +void epicsShareAPI ca_set_puser ( + chid pChan, void * puser ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + pChan->pPrivate = puser; +} + +/* + * ca_get_puser () + */ +void * epicsShareAPI ca_puser ( + chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->pPrivate; +} + +/* + * Specify an event subroutine to be run for connection events + */ +int epicsShareAPI ca_change_connection_event ( chid pChan, caCh * pfunc ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + if ( ! pChan->currentlyConnected ) { + if ( pfunc ) { + if ( ! pChan->pConnCallBack ) { + pChan->cacCtx.decrementOutstandingIO ( guard, pChan->ioSeqNo ); + } + } + else { + if ( pChan->pConnCallBack ) { + pChan->cacCtx.incrementOutstandingIO ( guard, pChan->ioSeqNo ); + } + } + } + pChan->pConnCallBack = pfunc; + return ECA_NORMAL; +} + +/* + * ca_replace_access_rights_event + */ +int epicsShareAPI ca_replace_access_rights_event ( + chid pChan, caArh *pfunc ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + + // The order of the following is significant to guarantee that the + // access rights handler is always gets called even if the channel connects + // while this is running. There is some very small chance that the + // handler could be called twice here with the same access rights state, but + // that will not upset the application. + pChan->pAccessRightsFunc = pfunc ? pfunc : cacNoopAccesRightsHandler; + caAccessRights tmp = pChan->io.accessRights ( guard ); + + if ( pChan->currentlyConnected ) { + struct access_rights_handler_args args; + args.chid = pChan; + args.ar.read_access = tmp.readPermit (); + args.ar.write_access = tmp.writePermit (); + epicsGuardRelease < epicsMutex > unguard ( guard ); + ( *pChan->pAccessRightsFunc ) ( args ); + } + return ECA_NORMAL; +} + +/* + * ca_array_get () + */ +int epicsShareAPI ca_array_get ( chtype type, + arrayElementCount count, chid pChan, void *pValue ) +{ + int caStatus; + try { + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + pChan->eliminateExcessiveSendBacklog ( + pChan->getClientCtx().pCallbackGuard.get(), guard ); + autoPtrFreeList < getCopy, 0x400, epicsMutexNOOP > pNotify + ( pChan->getClientCtx().getCopyFreeList, + new ( pChan->getClientCtx().getCopyFreeList ) + getCopy ( guard, pChan->getClientCtx(), *pChan, + tmpType, count, pValue ) ); + pChan->io.read ( guard, type, count, *pNotify, 0 ); + pNotify.release (); + caStatus = ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + caStatus = ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + caStatus = ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + caStatus = ECA_BADCOUNT; + } + catch ( cacChannel::noReadAccess & ) + { + caStatus = ECA_NORDACCESS; + } + catch ( cacChannel::notConnected & ) + { + caStatus = ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + caStatus = ECA_UNAVAILINSERV; + } + catch ( cacChannel::requestTimedOut & ) + { + caStatus = ECA_TIMEOUT; + } + catch ( std::bad_alloc & ) + { + caStatus = ECA_ALLOCMEM; + } + catch ( cacChannel::msgBodyCacheTooSmall & ) { + caStatus = ECA_TOLARGE; + } + catch ( ... ) + { + caStatus = ECA_GETFAIL; + } + return caStatus; +} + +/* + * ca_array_get_callback () + */ +int epicsShareAPI ca_array_get_callback ( chtype type, + arrayElementCount count, chid pChan, + caEventCallBackFunc *pfunc, void *arg ) +{ + int caStatus; + try { + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + pChan->eliminateExcessiveSendBacklog ( + pChan->getClientCtx().pCallbackGuard.get(), guard ); + autoPtrFreeList < getCallback, 0x400, epicsMutexNOOP > pNotify + ( pChan->getClientCtx().getCallbackFreeList, + new ( pChan->getClientCtx().getCallbackFreeList ) + getCallback ( *pChan, pfunc, arg ) ); + pChan->io.read ( guard, tmpType, count, *pNotify, 0 ); + pNotify.release (); + caStatus = ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + caStatus = ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + caStatus = ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + caStatus = ECA_BADCOUNT; + } + catch ( cacChannel::noReadAccess & ) + { + caStatus = ECA_NORDACCESS; + } + catch ( cacChannel::notConnected & ) + { + caStatus = ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + caStatus = ECA_UNAVAILINSERV; + } + catch ( cacChannel::requestTimedOut & ) + { + caStatus = ECA_TIMEOUT; + } + catch ( std::bad_alloc & ) + { + caStatus = ECA_ALLOCMEM; + } + catch ( cacChannel::msgBodyCacheTooSmall ) { + caStatus = ECA_TOLARGE; + } + catch ( ... ) + { + caStatus = ECA_GETFAIL; + } + return caStatus; +} + void oldChannelNotify::read ( epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, @@ -246,11 +415,206 @@ void oldChannelNotify::read ( this->io.read ( guard, type, count, notify, pId ); } -void oldChannelNotify::write ( - epicsGuard < epicsMutex > & guard, - unsigned type, arrayElementCount count, const void * pValue ) +/* + * ca_array_put_callback () + */ +int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count, + chid pChan, const void *pValue, caEventCallBackFunc *pfunc, void *usrarg ) { - this->io.write ( guard, type, count, pValue ); + int caStatus; + try { + if ( type < 0 ) { + return ECA_BADTYPE; + } + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + pChan->eliminateExcessiveSendBacklog ( + pChan->getClientCtx().pCallbackGuard.get(), guard ); + unsigned tmpType = static_cast < unsigned > ( type ); + autoPtrFreeList < putCallback, 0x400, epicsMutexNOOP > pNotify + ( pChan->getClientCtx().putCallbackFreeList, + new ( pChan->getClientCtx().putCallbackFreeList ) + putCallback ( *pChan, pfunc, usrarg ) ); + pChan->io.write ( guard, tmpType, count, pValue, *pNotify, 0 ); + pNotify.release (); + caStatus = ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + caStatus = ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + caStatus = ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + caStatus = ECA_BADCOUNT; + } + catch ( cacChannel::noWriteAccess & ) + { + caStatus = ECA_NOWTACCESS; + } + catch ( cacChannel::notConnected & ) + { + caStatus = ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + caStatus = ECA_UNAVAILINSERV; + } + catch ( cacChannel::requestTimedOut & ) + { + caStatus = ECA_TIMEOUT; + } + catch ( std::bad_alloc & ) + { + caStatus = ECA_ALLOCMEM; + } + catch ( ... ) + { + caStatus = ECA_PUTFAIL; + } + return caStatus; +} + +/* + * ca_array_put () + */ +int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count, + chid pChan, const void * pValue ) +{ + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + + int caStatus; + try { + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + pChan->eliminateExcessiveSendBacklog ( + pChan->getClientCtx().pCallbackGuard.get(), guard ); + pChan->io.write ( guard, tmpType, count, pValue ); + caStatus = ECA_NORMAL; + } + catch ( cacChannel::badString & ) + { + caStatus = ECA_BADSTR; + } + catch ( cacChannel::badType & ) + { + caStatus = ECA_BADTYPE; + } + catch ( cacChannel::outOfBounds & ) + { + caStatus = ECA_BADCOUNT; + } + catch ( cacChannel::noWriteAccess & ) + { + caStatus = ECA_NOWTACCESS; + } + catch ( cacChannel::notConnected & ) + { + caStatus = ECA_DISCONN; + } + catch ( cacChannel::unsupportedByService & ) + { + caStatus = ECA_UNAVAILINSERV; + } + catch ( cacChannel::requestTimedOut & ) + { + caStatus = ECA_TIMEOUT; + } + catch ( std::bad_alloc & ) + { + caStatus = ECA_ALLOCMEM; + } + catch ( ... ) + { + caStatus = ECA_PUTFAIL; + } + return caStatus; +} + +int epicsShareAPI ca_create_subscription ( + chtype type, arrayElementCount count, chid pChan, + long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg, + evid * monixptr ) +{ + if ( type < 0 ) { + return ECA_BADTYPE; + } + unsigned tmpType = static_cast < unsigned > ( type ); + + if ( INVALID_DB_REQ (type) ) { + return ECA_BADTYPE; + } + + if ( pCallBack == NULL ) { + return ECA_BADFUNCPTR; + } + + static const long maskMask = 0xffff; + if ( ( mask & maskMask ) == 0) { + return ECA_BADMASK; + } + + if ( mask & ~maskMask ) { + return ECA_BADMASK; + } + + try { + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + try { + // if this stalls out on a live circuit then an exception + // can be forthcoming which we must ignore (this is a + // special case preserving legacy ca_create_subscription + // behavior) + pChan->eliminateExcessiveSendBacklog ( + pChan->getClientCtx().pCallbackGuard.get(), guard ); + } + catch ( cacChannel::notConnected & ) { + // intentionally ignored (its ok to subscribe when not connected) + } + new ( pChan->getClientCtx().subscriptionFreeList ) + oldSubscription ( + guard, *pChan, pChan->io, tmpType, count, mask, + pCallBack, pCallBackArg, monixptr ); + // dont touch object created after above new because + // the first callback might have canceled, and therefore + // destroyed, it + 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_UNAVAILINSERV; + } + catch ( std::bad_alloc & ) + { + return ECA_ALLOCMEM; + } + catch ( cacChannel::msgBodyCacheTooSmall & ) { + return ECA_TOLARGE; + } + catch ( ... ) + { + return ECA_INTERNAL; + } } void oldChannelNotify::write ( @@ -260,12 +624,93 @@ void oldChannelNotify::write ( this->io.write ( guard, type, count, pValue, notify, pId ); } -void oldChannelNotify::subscribe ( - epicsGuard < epicsMutex > & guard, unsigned type, - arrayElementCount count, unsigned mask, cacStateNotify & notify, - cacChannel::ioid & idOut) +/* + * ca_field_type() + */ +short epicsShareAPI ca_field_type ( chid pChan ) { - this->io.subscribe ( guard, type, count, mask, notify, &idOut ); + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.nativeType ( guard ); +} + +/* + * ca_element_count () + */ +arrayElementCount epicsShareAPI ca_element_count ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.nativeElementCount ( guard ); +} + +/* + * ca_state () + */ +enum channel_state epicsShareAPI ca_state ( chid pChan ) // X aCC 361 +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + if ( pChan->io.connected ( guard ) ) { + return cs_conn; + } + else if ( pChan->prevConnected ){ + return cs_prev_conn; + } + else { + return cs_never_conn; + } +} + +/* + * ca_read_access () + */ +unsigned epicsShareAPI ca_read_access ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.accessRights(guard).readPermit(); +} + +/* + * ca_write_access () + */ +unsigned epicsShareAPI ca_write_access ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.accessRights(guard).writePermit(); +} + +/* + * ca_name () + */ +const char * epicsShareAPI ca_name ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.pName ( guard ); +} + +unsigned epicsShareAPI ca_search_attempts ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.searchAttempts ( guard ); +} + +double epicsShareAPI ca_beacon_period ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.beaconPeriod ( guard ); +} + +double epicsShareAPI ca_receive_watchdog_delay ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.receiveWatchdogDelay ( guard ); +} + +/* + * ca_v42_ok(chid chan) + */ +int epicsShareAPI ca_v42_ok ( chid pChan ) +{ + epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () ); + return pChan->io.ca_v42_ok ( guard ); }