598 lines
12 KiB
C++
598 lines
12 KiB
C++
/*
|
|
* $Id$
|
|
*
|
|
* Author Jeffrey O. Hill
|
|
* johill@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
|
|
*
|
|
*
|
|
* History
|
|
* $Log$
|
|
* Revision 1.11 1997/04/10 19:34:10 jhill
|
|
* API changes
|
|
*
|
|
* Revision 1.10 1997/01/10 21:17:55 jhill
|
|
* code around gnu g++ inline bug when -O isnt used
|
|
*
|
|
* Revision 1.9 1996/12/06 22:33:49 jhill
|
|
* virtual ~casPVI(), ~casPVListChan(), ~casChannelI()
|
|
*
|
|
* Revision 1.8 1996/11/02 00:54:14 jhill
|
|
* many improvements
|
|
*
|
|
* Revision 1.7 1996/09/16 18:24:02 jhill
|
|
* vxWorks port changes
|
|
*
|
|
* Revision 1.6 1996/09/04 20:21:41 jhill
|
|
* removed operator -> and added member pv
|
|
*
|
|
* Revision 1.5 1996/07/01 19:56:11 jhill
|
|
* one last update prior to first release
|
|
*
|
|
* Revision 1.4 1996/06/26 23:32:17 jhill
|
|
* changed where caProto.h comes from (again)
|
|
*
|
|
* Revision 1.3 1996/06/26 21:18:54 jhill
|
|
* now matches gdd api revisions
|
|
*
|
|
* Revision 1.2 1996/06/20 18:08:35 jhill
|
|
* changed where caProto.h comes from
|
|
*
|
|
* Revision 1.1.1.1 1996/06/20 00:28:15 jhill
|
|
* ca server installation
|
|
*
|
|
*
|
|
*/
|
|
|
|
//
|
|
// EPICS
|
|
//
|
|
#include "tsDLList.h"
|
|
#include "resourceLib.h"
|
|
#include "caProto.h"
|
|
|
|
typedef aitUint32 caResId;
|
|
|
|
class casEventSys;
|
|
class casChannelI;
|
|
|
|
//
|
|
// casEvent
|
|
//
|
|
class casEvent : public tsDLNode<casEvent> {
|
|
public:
|
|
virtual ~casEvent();
|
|
virtual caStatus cbFunc(casEventSys &)=0;
|
|
private:
|
|
};
|
|
|
|
class casChanDelEv : public casEvent {
|
|
public:
|
|
casChanDelEv(caResId idIn) : id(idIn) {}
|
|
~casChanDelEv();
|
|
caStatus cbFunc(casEventSys &);
|
|
private:
|
|
caResId id;
|
|
};
|
|
|
|
enum casResType {casChanT=1, casClientMonT, casPVT};
|
|
|
|
class casRes : public uintRes<casRes>
|
|
{
|
|
public:
|
|
virtual ~casRes();
|
|
virtual casResType resourceType() const = 0;
|
|
virtual void show (unsigned level) const = 0;
|
|
virtual void destroy() = 0;
|
|
private:
|
|
};
|
|
|
|
class ioBlockedList;
|
|
class osiMutex;
|
|
|
|
//
|
|
// ioBlocked
|
|
//
|
|
class ioBlocked : public tsDLNode<ioBlocked> {
|
|
friend class ioBlockedList;
|
|
public:
|
|
ioBlocked ();
|
|
virtual ~ioBlocked ();
|
|
private:
|
|
ioBlockedList *pList;
|
|
virtual void ioBlockedSignal ();
|
|
};
|
|
|
|
//
|
|
// ioBlockedList
|
|
//
|
|
class ioBlockedList : private tsDLList<ioBlocked> {
|
|
public:
|
|
ioBlockedList ();
|
|
~ioBlockedList ();
|
|
void signal ();
|
|
void removeItemFromIOBLockedList(ioBlocked &item);
|
|
void addItemToIOBLockedList(ioBlocked &item);
|
|
};
|
|
|
|
class casMonitor;
|
|
|
|
//
|
|
// casMonEvent
|
|
//
|
|
class casMonEvent : public casEvent {
|
|
public:
|
|
//
|
|
// only used when this is part of another structure
|
|
// (and we need to postpone true construction)
|
|
//
|
|
inline casMonEvent ();
|
|
inline casMonEvent (casMonitor &monitor, gdd &newValue);
|
|
inline casMonEvent (casMonEvent &initValue);
|
|
|
|
//
|
|
// ~casMonEvent ()
|
|
// (not inline because this is virtual in the base class)
|
|
//
|
|
~casMonEvent ();
|
|
|
|
caStatus cbFunc(casEventSys &);
|
|
|
|
//
|
|
// casMonEvent::getValue()
|
|
//
|
|
inline gdd *getValue() const;
|
|
|
|
inline void operator = (class casMonEvent &monEventIn);
|
|
|
|
inline void clear();
|
|
|
|
void assign (casMonitor &monitor, gdd *pValueIn);
|
|
private:
|
|
gdd *pValue;
|
|
caResId id;
|
|
};
|
|
|
|
|
|
//
|
|
// casMonitor()
|
|
//
|
|
class casMonitor : public tsDLNode<casMonitor>, public casRes {
|
|
public:
|
|
casMonitor(caResId clientIdIn, casChannelI &chan,
|
|
unsigned long nElem, unsigned dbrType,
|
|
const casEventMask &maskIn, osiMutex &mutexIn);
|
|
virtual ~casMonitor();
|
|
|
|
caStatus executeEvent(casMonEvent *);
|
|
|
|
void post(const casEventMask &select, gdd &value);
|
|
|
|
virtual void show (unsigned level) const;
|
|
virtual caStatus callBack(gdd &value)=0;
|
|
|
|
caResId getClientId() const
|
|
{
|
|
return this->clientId;
|
|
}
|
|
|
|
unsigned getType() const
|
|
{
|
|
return this->dbrType;
|
|
}
|
|
|
|
unsigned long getCount() const
|
|
{
|
|
return this->nElem;
|
|
}
|
|
casChannelI &getChannel() const
|
|
{
|
|
return this->ciu;
|
|
}
|
|
|
|
void postIfModified();
|
|
|
|
private:
|
|
casMonEvent overFlowEvent;
|
|
unsigned long const nElem;
|
|
osiMutex &mutex;
|
|
casChannelI &ciu;
|
|
const casEventMask mask;
|
|
gdd *pModifiedValue;
|
|
caResId const clientId;
|
|
unsigned char const dbrType;
|
|
unsigned char nPend;
|
|
unsigned ovf:1;
|
|
unsigned enabled:1;
|
|
|
|
void enable();
|
|
void disable();
|
|
|
|
void push (gdd &value);
|
|
};
|
|
|
|
//
|
|
// casMonitor::post()
|
|
// (check for NOOP case in line)
|
|
//
|
|
inline void casMonitor::post(const casEventMask &select, gdd &value)
|
|
{
|
|
casEventMask result(select&this->mask);
|
|
//
|
|
// NOOP if this event isnt selected
|
|
//
|
|
if (result.noEventsSelected()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// NOOP if currently disabled
|
|
//
|
|
if (!this->enabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// else push it on the queue
|
|
//
|
|
this->push(value);
|
|
}
|
|
|
|
|
|
class caServer;
|
|
class casCoreClient;
|
|
class casChannelI;
|
|
class casCtx;
|
|
class caServer;
|
|
class casAsyncIO;
|
|
class casAsyncReadIO;
|
|
class casAsyncWriteIO;
|
|
class casAsyncPVExistIO;
|
|
class casAsyncPVCreateIO;
|
|
|
|
class casAsyncIOI : public casEvent, public tsDLNode<casAsyncIOI> {
|
|
public:
|
|
casAsyncIOI (casCoreClient &client, casAsyncIO &ioExternal);
|
|
virtual ~casAsyncIOI();
|
|
|
|
//
|
|
// place notification of IO completion on the event queue
|
|
//
|
|
caStatus postIOCompletionI();
|
|
|
|
inline void lock();
|
|
inline void unlock();
|
|
|
|
virtual caStatus cbFuncAsyncIO()=0;
|
|
virtual int readOP();
|
|
|
|
void destroyIfReadOP();
|
|
|
|
caServer *getCAS() const;
|
|
|
|
inline void destroy();
|
|
|
|
void reportInvalidAsynchIO(unsigned);
|
|
|
|
protected:
|
|
casCoreClient &client;
|
|
casAsyncIO &ioExternal;
|
|
|
|
private:
|
|
unsigned inTheEventQueue:1;
|
|
unsigned posted:1;
|
|
unsigned ioComplete:1;
|
|
unsigned serverDelete:1;
|
|
unsigned duplicate:1;
|
|
//
|
|
// casEvent virtual call back function
|
|
// (called when IO completion event reaches top of event queue)
|
|
//
|
|
caStatus cbFunc(casEventSys &);
|
|
|
|
inline casAsyncIO * operator -> ();
|
|
};
|
|
|
|
//
|
|
// casAsyncRdIOI
|
|
//
|
|
// (server internal asynchronous read IO class)
|
|
//
|
|
class casAsyncRdIOI : public casAsyncIOI {
|
|
public:
|
|
casAsyncRdIOI(const casCtx &ctx, casAsyncReadIO &ioIn);
|
|
virtual ~casAsyncRdIOI();
|
|
|
|
void destroyIfReadOP();
|
|
|
|
caStatus cbFuncAsyncIO();
|
|
casAsyncIO &getAsyncIO();
|
|
|
|
caStatus postIOCompletion(caStatus completionStatus,
|
|
gdd &valueRead);
|
|
int readOP();
|
|
private:
|
|
caHdr const msg;
|
|
casChannelI &chan;
|
|
gdd *pDD;
|
|
caStatus completionStatus;
|
|
};
|
|
|
|
//
|
|
// casAsyncWtIOI
|
|
//
|
|
// (server internal asynchronous write IO class)
|
|
//
|
|
class casAsyncWtIOI : public casAsyncIOI {
|
|
public:
|
|
casAsyncWtIOI(const casCtx &ctx, casAsyncWriteIO &ioIn);
|
|
virtual ~casAsyncWtIOI();
|
|
|
|
//
|
|
// place notification of IO completion on the event queue
|
|
//
|
|
caStatus postIOCompletion(caStatus completionStatus);
|
|
|
|
caStatus cbFuncAsyncIO();
|
|
casAsyncIO &getAsyncIO();
|
|
private:
|
|
caHdr const msg;
|
|
casChannelI &chan;
|
|
caStatus completionStatus;
|
|
};
|
|
|
|
class casDGIntfIO;
|
|
|
|
//
|
|
// casAsyncExIOI
|
|
//
|
|
// (server internal asynchronous read IO class)
|
|
//
|
|
class casAsyncExIOI : public casAsyncIOI {
|
|
public:
|
|
casAsyncExIOI(const casCtx &ctx, casAsyncPVExistIO &ioIn);
|
|
virtual ~casAsyncExIOI();
|
|
|
|
//
|
|
// place notification of IO completion on the event queue
|
|
//
|
|
caStatus postIOCompletion(const pvExistReturn retVal);
|
|
|
|
caStatus cbFuncAsyncIO();
|
|
casAsyncIO &getAsyncIO();
|
|
private:
|
|
caHdr const msg;
|
|
pvExistReturn retVal;
|
|
casDGIntfIO * const pOutDGIntfIO;
|
|
const caNetAddr dgOutAddr;
|
|
};
|
|
|
|
//
|
|
// casAsyncPVCIOI
|
|
//
|
|
// (server internal asynchronous read IO class)
|
|
//
|
|
class casAsyncPVCIOI : public casAsyncIOI {
|
|
public:
|
|
casAsyncPVCIOI(const casCtx &ctx, casAsyncPVCreateIO &ioIn);
|
|
virtual ~casAsyncPVCIOI();
|
|
|
|
//
|
|
// place notification of IO completion on the event queue
|
|
//
|
|
caStatus postIOCompletion(const pvCreateReturn &retVal);
|
|
|
|
caStatus cbFuncAsyncIO();
|
|
casAsyncIO &getAsyncIO();
|
|
private:
|
|
caHdr const msg;
|
|
pvCreateReturn retVal;
|
|
};
|
|
|
|
class casChannel;
|
|
class casPVI;
|
|
|
|
//
|
|
// casChannelI
|
|
//
|
|
// this derives from casEvent so that access rights
|
|
// events can be posted
|
|
//
|
|
class casChannelI : public tsDLNode<casChannelI>, public casRes,
|
|
public casEvent {
|
|
public:
|
|
casChannelI (const casCtx &ctx, casChannel &chanAdapter);
|
|
virtual ~casChannelI();
|
|
|
|
casCoreClient &getClient() const
|
|
{
|
|
return this->client;
|
|
}
|
|
const caResId getCID()
|
|
{
|
|
return this->cid;
|
|
}
|
|
//
|
|
// fetch the unsigned integer server id for this PV
|
|
//
|
|
inline const caResId getSID();
|
|
|
|
void postAllModifiedEvents();
|
|
|
|
//
|
|
// addMonitor()
|
|
//
|
|
inline void addMonitor(casMonitor &mon);
|
|
|
|
//
|
|
// deleteMonitor()
|
|
//
|
|
inline void deleteMonitor(casMonitor &mon);
|
|
|
|
//
|
|
// findMonitor
|
|
// (it is reasonable to do a linear search here because
|
|
// sane clients will require only one or two monitors
|
|
// per channel)
|
|
//
|
|
inline casMonitor *findMonitor(const caResId clientIdIn);
|
|
|
|
casPVI &getPVI() const
|
|
{
|
|
return this->pv;
|
|
}
|
|
|
|
inline void installAsyncIO(casAsyncIOI &);
|
|
inline void removeAsyncIO(casAsyncIOI &);
|
|
|
|
inline void postEvent (const casEventMask &select, gdd &event);
|
|
|
|
virtual casResType resourceType() const;
|
|
|
|
virtual void show (unsigned level) const;
|
|
|
|
virtual void destroy();
|
|
|
|
inline void lock() const;
|
|
inline void unlock() const;
|
|
|
|
inline void clientDestroy();
|
|
|
|
inline casChannel * operator -> () const;
|
|
|
|
void clearOutstandingReads();
|
|
|
|
//
|
|
// access rights event call back
|
|
//
|
|
caStatus cbFunc(casEventSys &);
|
|
|
|
inline void postAccessRightsEvent();
|
|
protected:
|
|
tsDLList<casMonitor> monitorList;
|
|
tsDLList<casAsyncIOI> ioInProgList;
|
|
casCoreClient &client;
|
|
casPVI &pv;
|
|
casChannel &chan;
|
|
caResId const cid; // client id
|
|
unsigned clientDestroyPending:1;
|
|
unsigned accessRightsEvPending:1;
|
|
};
|
|
|
|
//
|
|
// class hierarchy added here solely because we need two list nodes
|
|
//
|
|
class casPVListChan : public casChannelI, public tsDLNode<casPVListChan>
|
|
{
|
|
public:
|
|
casPVListChan (const casCtx &ctx, casChannel &chanAdapter);
|
|
virtual ~casPVListChan();
|
|
};
|
|
|
|
class caServerI;
|
|
class casCtx;
|
|
class casChannel;
|
|
class casPV;
|
|
|
|
//
|
|
// casPVI
|
|
//
|
|
class casPVI :
|
|
public tsSLNode<casPVI>, // server resource table installation
|
|
public casRes, // server resource table installation
|
|
public ioBlockedList // list of clients io blocked on this pv
|
|
{
|
|
public:
|
|
casPVI (caServer &cas, casPV &pvAdapter);
|
|
virtual ~casPVI();
|
|
|
|
//
|
|
// for use by the server library
|
|
//
|
|
inline caServerI &getCAS() const;
|
|
|
|
//
|
|
// CA only does 1D arrays for now (and the new server
|
|
// temporarily does only scalers)
|
|
//
|
|
inline aitIndex nativeCount();
|
|
|
|
//
|
|
// only for use by casMonitor
|
|
//
|
|
caStatus registerEvent ();
|
|
void unregisterEvent ();
|
|
|
|
//
|
|
// only for use by casAsyncIOI
|
|
//
|
|
inline void unregisterIO();
|
|
|
|
//
|
|
// only for use by casChannelI
|
|
//
|
|
inline void installChannel(casPVListChan &chan);
|
|
|
|
//
|
|
// only for use by casChannelI
|
|
//
|
|
inline void removeChannel(casPVListChan &chan);
|
|
|
|
//
|
|
// check for none attached and delete self if so
|
|
//
|
|
inline void deleteSignal();
|
|
|
|
inline void postEvent (const casEventMask &select, gdd &event);
|
|
|
|
inline casPV *interfaceObjectPointer() const;
|
|
|
|
caServer *getExtServer() const;
|
|
|
|
//
|
|
// bestDBRType()
|
|
//
|
|
inline caStatus bestDBRType (unsigned &dbrType);
|
|
|
|
inline casPV * operator -> () const;
|
|
|
|
virtual casResType resourceType() const;
|
|
|
|
virtual void show(unsigned level) const;
|
|
|
|
virtual void destroy();
|
|
|
|
private:
|
|
tsDLList<casPVListChan> chanList;
|
|
caServerI &cas;
|
|
casPV &pv;
|
|
unsigned nMonAttached;
|
|
unsigned nIOAttached;
|
|
unsigned destroyInProgress:1;
|
|
|
|
inline void lock() const;
|
|
inline void unlock() const;
|
|
};
|
|
|