440 lines
15 KiB
C++
440 lines
15 KiB
C++
/*************************************************************************\
|
|
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
|
* National Laboratory.
|
|
* Copyright (c) 2002 The Regents of the University of California, as
|
|
* Operator of Los Alamos National Laboratory.
|
|
* EPICS BASE Versions 3.13.7
|
|
* and higher are distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
/*
|
|
*
|
|
*
|
|
* L O S A L A M O S
|
|
* Los Alamos National Laboratory
|
|
* Los Alamos, New Mexico 87545
|
|
*
|
|
* Copyright, 1986, The Regents of the University of California.
|
|
*
|
|
*
|
|
* Author Jeffrey O. Hill
|
|
* johill@lanl.gov
|
|
* 505 665 1831
|
|
*/
|
|
|
|
#ifndef cach
|
|
#define cach
|
|
|
|
#ifdef epicsExportSharedSymbols
|
|
# define cach_restore_epicsExportSharedSymbols
|
|
# undef epicsExportSharedSymbols
|
|
#endif
|
|
|
|
#include "compilerDependencies.h"
|
|
#include "ipAddrToAsciiAsynchronous.h"
|
|
#include "msgForMultiplyDefinedPV.h"
|
|
#include "epicsTimer.h"
|
|
#include "epicsEvent.h"
|
|
#include "freeList.h"
|
|
|
|
#ifdef cach_restore_epicsExportSharedSymbols
|
|
# define epicsExportSharedSymbols
|
|
# include "shareLib.h"
|
|
#endif
|
|
|
|
#include "nciu.h"
|
|
#include "comBuf.h"
|
|
#include "bhe.h"
|
|
#include "cacIO.h"
|
|
#include "netIO.h"
|
|
#include "localHostName.h"
|
|
#include "virtualCircuit.h"
|
|
|
|
class netWriteNotifyIO;
|
|
class netReadNotifyIO;
|
|
class netSubscription;
|
|
|
|
// used to control access to cac's recycle routines which
|
|
// should only be indirectly invoked by CAC when its lock
|
|
// is applied
|
|
class cacRecycle { // X aCC 655
|
|
public:
|
|
virtual void recycleReadNotifyIO (
|
|
epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0;
|
|
virtual void recycleWriteNotifyIO (
|
|
epicsGuard < epicsMutex > &, netWriteNotifyIO &io ) = 0;
|
|
virtual void recycleSubscription (
|
|
epicsGuard < epicsMutex > &, netSubscription &io ) = 0;
|
|
};
|
|
|
|
struct CASG;
|
|
class inetAddrID;
|
|
class caServerID;
|
|
struct caHdrLargeArray;
|
|
|
|
class cacComBufMemoryManager : public comBufMemoryManager
|
|
{
|
|
public:
|
|
cacComBufMemoryManager () {}
|
|
void * allocate ( size_t );
|
|
void release ( void * );
|
|
private:
|
|
tsFreeList < comBuf, 0x20 > freeList;
|
|
cacComBufMemoryManager ( const cacComBufMemoryManager & );
|
|
cacComBufMemoryManager & operator = ( const cacComBufMemoryManager & );
|
|
};
|
|
|
|
class notifyGuard {
|
|
public:
|
|
notifyGuard ( cacContextNotify & );
|
|
~notifyGuard ();
|
|
private:
|
|
cacContextNotify & notify;
|
|
notifyGuard ( const notifyGuard & );
|
|
notifyGuard & operator = ( const notifyGuard & );
|
|
};
|
|
|
|
class callbackManager : public notifyGuard {
|
|
public:
|
|
callbackManager (
|
|
cacContextNotify &,
|
|
epicsMutex & callbackControl );
|
|
epicsGuard < epicsMutex > cbGuard;
|
|
};
|
|
|
|
class cac :
|
|
public cacContext,
|
|
private cacRecycle,
|
|
private callbackForMultiplyDefinedPV
|
|
{
|
|
public:
|
|
cac (
|
|
epicsMutex & mutualExclusion,
|
|
epicsMutex & callbackControl,
|
|
cacContextNotify & );
|
|
virtual ~cac ();
|
|
|
|
// beacon management
|
|
void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime,
|
|
ca_uint32_t beaconNumber, unsigned protocolRevision );
|
|
unsigned beaconAnomaliesSinceProgramStart (
|
|
epicsGuard < epicsMutex > & ) const;
|
|
|
|
// IO management
|
|
void flush ( epicsGuard < epicsMutex > & guard );
|
|
bool executeResponse ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody );
|
|
|
|
// channel routines
|
|
void transferChanToVirtCircuit (
|
|
unsigned cid, unsigned sid,
|
|
ca_uint16_t typeCode, arrayElementCount count,
|
|
unsigned minorVersionNumber, const osiSockAddr &,
|
|
const epicsTime & currentTime );
|
|
cacChannel & createChannel (
|
|
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
|
cacChannelNotify &, cacChannel::priLev );
|
|
void destroyChannel (
|
|
epicsGuard < epicsMutex > & callbackControlGuard,
|
|
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
|
nciu & );
|
|
void initiateConnect (
|
|
epicsGuard < epicsMutex > &, nciu &, netiiu * & );
|
|
nciu * lookupChannel (
|
|
epicsGuard < epicsMutex > &, const cacChannel::ioid & );
|
|
|
|
// IO requests
|
|
void writeRequest ( epicsGuard < epicsMutex > &, nciu &, unsigned type,
|
|
arrayElementCount nElem, const void * pValue );
|
|
netWriteNotifyIO & writeNotifyRequest (
|
|
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
|
unsigned type, arrayElementCount nElem, const void * pValue,
|
|
cacWriteNotify & );
|
|
netReadNotifyIO & readNotifyRequest (
|
|
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
|
unsigned type, arrayElementCount nElem,
|
|
cacReadNotify & );
|
|
netSubscription & subscriptionRequest (
|
|
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
|
unsigned type, arrayElementCount nElem, unsigned mask,
|
|
cacStateNotify &, bool channelIsInstalled );
|
|
baseNMIU * destroyIO (
|
|
epicsGuard < epicsMutex > & cbGuard,
|
|
epicsGuard < epicsMutex > & guard,
|
|
const cacChannel::ioid & idIn,
|
|
nciu & chan );
|
|
void disconnectAllIO (
|
|
epicsGuard < epicsMutex > & cbGuard,
|
|
epicsGuard < epicsMutex > & guard,
|
|
nciu &, tsDLList < baseNMIU > & ioList );
|
|
|
|
void ioShow (
|
|
epicsGuard < epicsMutex > & guard,
|
|
const cacChannel::ioid &id, unsigned level ) const;
|
|
|
|
// sync group routines
|
|
CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id );
|
|
void installCASG ( epicsGuard < epicsMutex > &, CASG & );
|
|
void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & );
|
|
|
|
// exception generation
|
|
void exception (
|
|
epicsGuard < epicsMutex > & cbGuard,
|
|
epicsGuard < epicsMutex > & guard,
|
|
int status, const char * pContext,
|
|
const char * pFileName, unsigned lineNo );
|
|
|
|
// diagnostics
|
|
unsigned circuitCount ( epicsGuard < epicsMutex > & ) const;
|
|
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
|
|
int printf ( epicsGuard < epicsMutex > & callbackControl,
|
|
const char *pformat, ... ) const;
|
|
int vPrintf ( epicsGuard < epicsMutex > & callbackControl,
|
|
const char *pformat, va_list args ) const;
|
|
|
|
// buffer management
|
|
char * allocateSmallBufferTCP ();
|
|
void releaseSmallBufferTCP ( char * );
|
|
unsigned largeBufferSizeTCP () const;
|
|
char * allocateLargeBufferTCP ();
|
|
void releaseLargeBufferTCP ( char * );
|
|
|
|
// misc
|
|
const char * userNamePointer () const;
|
|
unsigned getInitializingThreadsPriority () const;
|
|
epicsMutex & mutexRef ();
|
|
void attachToClientCtx ();
|
|
void selfTest (
|
|
epicsGuard < epicsMutex > & ) const;
|
|
double beaconPeriod (
|
|
epicsGuard < epicsMutex > &,
|
|
const nciu & chan ) const;
|
|
static unsigned lowestPriorityLevelAbove ( unsigned priority );
|
|
static unsigned highestPriorityLevelBelow ( unsigned priority );
|
|
void destroyIIU ( tcpiiu & iiu );
|
|
|
|
private:
|
|
localHostName hostNameCache;
|
|
chronIntIdResTable < nciu > chanTable;
|
|
//
|
|
// !!!! There is at this point no good reason
|
|
// !!!! to maintain one IO table for all types of
|
|
// !!!! IO. It would probably be better to maintain
|
|
// !!!! an independent table for each IO type. The
|
|
// !!!! new adaptive sized hash table will not
|
|
// !!!! waste memory. Making this change will
|
|
// !!!! avoid virtual function overhead when
|
|
// !!!! accessing the different types of IO. This
|
|
// !!!! approach would also probably be safer in
|
|
// !!!! terms of detecting damaged protocol.
|
|
//
|
|
chronIntIdResTable < baseNMIU > ioTable;
|
|
resTable < bhe, inetAddrID > beaconTable;
|
|
resTable < tcpiiu, caServerID > serverTable;
|
|
tsDLList < tcpiiu > circuitList;
|
|
tsFreeList
|
|
< class tcpiiu, 32, epicsMutexNOOP >
|
|
freeListVirtualCircuit;
|
|
tsFreeList
|
|
< class netReadNotifyIO, 1024, epicsMutexNOOP >
|
|
freeListReadNotifyIO;
|
|
tsFreeList
|
|
< class netWriteNotifyIO, 1024, epicsMutexNOOP >
|
|
freeListWriteNotifyIO;
|
|
tsFreeList
|
|
< class netSubscription, 1024, epicsMutexNOOP >
|
|
freeListSubscription;
|
|
tsFreeList
|
|
< class nciu, 1024, epicsMutexNOOP >
|
|
channelFreeList;
|
|
tsFreeList
|
|
< class msgForMultiplyDefinedPV, 16 >
|
|
mdpvFreeList;
|
|
cacComBufMemoryManager comBufMemMgr;
|
|
bheFreeStore bheFreeList;
|
|
epicsTime programBeginTime;
|
|
double connTMO;
|
|
// **** lock hierarchy ****
|
|
// 1) callback lock must always be acquired before
|
|
// the primary mutex if both locks are needed
|
|
mutable epicsMutex & mutex;
|
|
mutable epicsMutex & cbMutex;
|
|
epicsEvent iiuUninstall;
|
|
ipAddrToAsciiEngine & ipToAEngine;
|
|
epicsTimerQueueActive & timerQueue;
|
|
char * pUserName;
|
|
class udpiiu * pudpiiu;
|
|
void * tcpSmallRecvBufFreeList;
|
|
void * tcpLargeRecvBufFreeList;
|
|
cacContextNotify & notify;
|
|
epicsThreadId initializingThreadsId;
|
|
unsigned initializingThreadsPriority;
|
|
unsigned maxRecvBytesTCP;
|
|
unsigned beaconAnomalyCount;
|
|
bool iiuUninstallInProgress;
|
|
|
|
void recycleReadNotifyIO (
|
|
epicsGuard < epicsMutex > &, netReadNotifyIO &io );
|
|
void recycleWriteNotifyIO (
|
|
epicsGuard < epicsMutex > &, netWriteNotifyIO &io );
|
|
void recycleSubscription (
|
|
epicsGuard < epicsMutex > &, netSubscription &io );
|
|
|
|
void disconnectChannel (
|
|
epicsGuard < epicsMutex > & cbGuard,
|
|
epicsGuard < epicsMutex > & guard, nciu & chan );
|
|
|
|
void ioExceptionNotify ( unsigned id, int status,
|
|
const char * pContext, unsigned type, arrayElementCount count );
|
|
void ioExceptionNotifyAndUninstall ( unsigned id, int status,
|
|
const char * pContext, unsigned type, arrayElementCount count );
|
|
|
|
void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
|
|
const char * pChannelName, const char * pAcc, const char * pRej );
|
|
|
|
// recv protocol stubs
|
|
bool versionAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool echoRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool writeNotifyRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool readNotifyRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool eventRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool readRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool clearChannelRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool exceptionRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool accessRightsRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool createChannelRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
bool badTCPRespAction ( callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
|
|
typedef bool ( cac::*pProtoStubTCP ) (
|
|
callbackManager &, tcpiiu &,
|
|
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
|
static const pProtoStubTCP tcpJumpTableCAC [];
|
|
|
|
bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
typedef bool ( cac::*pExcepProtoStubTCP ) (
|
|
callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
|
const char *pCtx, unsigned status );
|
|
static const pExcepProtoStubTCP tcpExcepJumpTableCAC [];
|
|
|
|
cac ( const cac & );
|
|
cac & operator = ( const cac & );
|
|
};
|
|
|
|
inline const char * cac::userNamePointer () const
|
|
{
|
|
return this->pUserName;
|
|
}
|
|
|
|
inline unsigned cac::getInitializingThreadsPriority () const
|
|
{
|
|
return this->initializingThreadsPriority;
|
|
}
|
|
|
|
inline epicsMutex & cac::mutexRef ()
|
|
{
|
|
return this->mutex;
|
|
}
|
|
|
|
inline int cac::vPrintf (
|
|
epicsGuard < epicsMutex > & callbackControl,
|
|
const char *pformat, va_list args ) const
|
|
{
|
|
callbackControl.assertIdenticalMutex ( this->cbMutex );
|
|
return this->notify.vPrintf ( pformat, args );
|
|
}
|
|
|
|
inline void cac::attachToClientCtx ()
|
|
{
|
|
this->notify.attachToClientCtx ();
|
|
}
|
|
|
|
inline char * cac::allocateSmallBufferTCP ()
|
|
{
|
|
// this locks internally
|
|
return ( char * ) freeListMalloc ( this->tcpSmallRecvBufFreeList );
|
|
}
|
|
|
|
inline void cac::releaseSmallBufferTCP ( char *pBuf )
|
|
{
|
|
// this locks internally
|
|
freeListFree ( this->tcpSmallRecvBufFreeList, pBuf );
|
|
}
|
|
|
|
inline unsigned cac::largeBufferSizeTCP () const
|
|
{
|
|
return this->maxRecvBytesTCP;
|
|
}
|
|
|
|
inline char * cac::allocateLargeBufferTCP ()
|
|
{
|
|
// this locks internally
|
|
return ( char * ) freeListMalloc ( this->tcpLargeRecvBufFreeList );
|
|
}
|
|
|
|
inline void cac::releaseLargeBufferTCP ( char *pBuf )
|
|
{
|
|
// this locks internally
|
|
freeListFree ( this->tcpLargeRecvBufFreeList, pBuf );
|
|
}
|
|
|
|
inline unsigned cac::beaconAnomaliesSinceProgramStart (
|
|
epicsGuard < epicsMutex > & guard ) const
|
|
{
|
|
guard.assertIdenticalMutex ( this->mutex );
|
|
return this->beaconAnomalyCount;
|
|
}
|
|
|
|
inline notifyGuard::notifyGuard ( cacContextNotify & notifyIn ) :
|
|
notify ( notifyIn )
|
|
{
|
|
this->notify.callbackProcessingInitiateNotify ();
|
|
}
|
|
|
|
inline notifyGuard::~notifyGuard ()
|
|
{
|
|
this->notify.callbackProcessingCompleteNotify ();
|
|
}
|
|
|
|
inline callbackManager::callbackManager (
|
|
cacContextNotify & notify, epicsMutex & callbackControl ) :
|
|
notifyGuard ( notify ), cbGuard ( callbackControl )
|
|
{
|
|
}
|
|
|
|
inline nciu * cac::lookupChannel (
|
|
epicsGuard < epicsMutex > & guard,
|
|
const cacChannel::ioid & idIn )
|
|
{
|
|
guard.assertIdenticalMutex ( this->mutex );
|
|
return this->chanTable.lookup ( idIn );
|
|
}
|
|
|
|
#endif // ifdef cach
|
|
|