API changes

This commit is contained in:
Jeff Hill
1997-04-10 19:43:15 +00:00
parent 414c8ed603
commit 5c4d82cacc
94 changed files with 3266 additions and 1662 deletions
+75
View File
@@ -118,3 +118,78 @@ The defaults in base class casPV implement identical behavior
to the past if these routines are not supplied by the derived
class.
Changes between epics 3.13 Beta 6 and 3.13 Beta ????
**** API Change ****
o The member function "casChannel::postEvent()" has been replaced by
"casChannel::postAccessRightsEvent()". An access rights state change
event is now posted to the client each time that
"casChannel::postAccessRightsEvent()" is called.
o The virtual functions "casChannel::interestRegister()"
and "casChannel::interestDelete()" have been eliminated.
o The constructor "caServer::caServer()" no-longer has an argument specifying
the maximum PV name length. It also no longer has an argument specifying
the maximum simultaneous IO operations. THIS IS LIKELY TO BREAK YOUR CODE
BECAUSE THE FIRST TWO ARGUMENTS WERE REMOVED AND THERE ARE DEFAULT ARGUMENTS.
This change was made because we would like to remove all limits on
the PV name length (real or perceived). We also felt that if a server
tool wishes to postpone an asynchronious IO operation then it
should return S_casApp_postponeAsyncIO from caServer::pvExistTest() and
caServer::createPV() (instead of relying on the server to keep track of
the number of simultaneous asynchronous IO operations). This provides a
less complex and more flexible API.
o The member function "casPV::casPV(caServer &cas)" replaces the member
function "casPV::casPV(const casCtx &ctx, const char * const pPVName)".
o The virtual member function
"caServer::createPV(const casCtx &ctx, const char *pPVName)"
has been replaced by the virtual member function
"pvCreateReturn createPV (const casCtx &ctx, const char *pPVAliasName)"
This change was made in order to allow asynchronous completion of a
PV create operation.
o The data type (class) pvExistReturn has been changed to an enum -
"enum pvExistReturn {pverExistsHere, pverDoesNotExistHere,
pverAsyncCompletion, pverNoMemoryForAsyncOP}"
This impacts the virtual member function
"pvExistTest (const casCtx &ctx, const char *pPVAliasName)"
o The server tool is now required to supply the virtual function
"casPV::getName()" so that the server is able to identify the process
variable when diagnostics are printed.
o The virtual function casPV::maxSimultAsyncOps() has been eliminated
in favor of allowing the server tool to return S_casApp_postponeAsyncIO
from casPV::read() or casPV::write() when there are too many simultaneous
asynchronous IO operations and the server tool would like to postpone
the current (and future) request(s) until one of the outstanding asynchronous
IO operations (read or write) completes.
o All "show()" virtual member functions in the interface classes
have had the "const" attribute added.
**** Semantic Change ****
o IMPORTANT: It is now the responsibility of the server tool to detect attempts
by the server lib to create a 2nd PV with the same canonical name as an
existing PV and avoid this by returning a pointer to the first PV created.
Likewise, if there are several aliases for one canonical PV name then it is
the responsibility of the server tool to return "pvExistsHere" from
"caServerDerived::pvExistTest()" for each of the aliases. Likewise, if there
are several aliases for one canonical PV name then it is the responsibility
of the server tool to return a single PV with the canonical name from
"caServerDerived::createPV()" (even if createPV() is called multiple times
each with a different alias name). This change was made to simplify the API
and to eliminate redundant data structures and labor occurring within the server
tool and the server library.
o PV creation is now allowed to complete asynchronously
o It is now the responsibility of the server tool to limit the
number of simultaneous asynchronous IO operations allowed (by returning
S_casApp_postponeAsyncIO).
+3
View File
@@ -21,6 +21,9 @@ PROD := excas
include $(TOP)/config/RULES.Host
pexcas: $(PROD_OBJS) $(PRODDEPLIBS)
$(PURIFY) $(PROD_LINKER) $(PROD_OBJS) $(LDLIBS)
clean::
@$(RM) excas
@$(RM) fexcas
+13 -10
View File
@@ -4,16 +4,7 @@
// (asynchrronous process variable)
//
#include <exServer.h>
//
// exAsyncPV::maxSimultAsyncOps()
// (virtual replacement for the default)
//
unsigned exAsyncPV::maxSimultAsyncOps () const
{
return 500u;
}
#include "exServer.h"
//
// exAsyncPV::read()
@@ -23,6 +14,12 @@ caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncReadIO *pIO;
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
pIO = new exAsyncReadIO(ctx, *this, valueIn);
if (!pIO) {
return S_casApp_noMemory;
@@ -39,6 +36,12 @@ caStatus exAsyncPV::write (const casCtx &ctx, gdd &valueIn)
{
exAsyncWriteIO *pIO;
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
pIO = new exAsyncWriteIO(ctx, *this, valueIn);
if (!pIO) {
return S_casApp_noMemory;
+1 -1
View File
@@ -3,5 +3,5 @@
// Example EPICS CA server
//
#include <exServer.h>
#include "exServer.h"
+44 -17
View File
@@ -2,25 +2,33 @@
// Example EPICS CA server
//
#include <exServer.h>
#include <gddApps.h>
#include "exServer.h"
#include "gddApps.h"
osiTime exPV::currentTime;
//
// exPV::exPV()
//
exPV::exPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV::exPV (caServer &casIn, pvInfo &setup, aitBool preCreateFlag) :
pValue(NULL),
pScanTimer(NULL),
info(setup),
casPV(ctxIn, setup.getName().string()),
interest(aitFalse)
casPV(casIn),
interest(aitFalse),
preCreate(preCreateFlag)
{
//
// no dataless PV allowed
//
assert (this->info.getElementCount()>=1u);
//
// start a very slow background scan
// (we will speed this up to the normal rate when
// someone is watching the PV)
//
this->pScanTimer =
new exScanTimer (this->getScanPeriod(), *this);
}
//
@@ -36,6 +44,19 @@ exPV::~exPV()
this->pValue->unreference();
this->pValue = NULL;
}
this->info.destroyPV();
}
//
// exPV::destroy()
// this is replaced by a noop since we are
// pre-creating most of the PVs during init in this simple server
//
void exPV::destroy()
{
if (!this->preCreate) {
delete this;
}
}
//
@@ -102,7 +123,7 @@ osiBool exScanTimer::again() const
//
const osiTime exScanTimer::delay() const
{
return pv.getScanRate();
return pv.getScanPeriod();
}
//
@@ -132,19 +153,26 @@ caStatus exPV::interestRegister()
return S_casApp_success;
}
if (!this->pScanTimer) {
this->interest = aitTrue;
//
// If a slow scan is pending then reschedule it
// with the specified scan period.
//
if (this->pScanTimer) {
this->pScanTimer->reschedule(this->info.getScanPeriod());
}
else {
this->pScanTimer = new exScanTimer
(this->info.getScanRate(), *this);
(this->info.getScanPeriod(), *this);
if (!this->pScanTimer) {
errPrintf (S_cas_noMemory, __FILE__, __LINE__,
"Scan init for %s failed\n",
this->info.getName().string());
this->info.getName());
return S_cas_noMemory;
}
}
this->interest = aitTrue;
return S_casApp_success;
}
@@ -153,17 +181,16 @@ caStatus exPV::interestRegister()
//
void exPV::interestDelete()
{
if (this->pScanTimer) {
delete this->pScanTimer;
this->pScanTimer = NULL;
}
this->interest = aitFalse;
if (this->pScanTimer) {
this->pScanTimer->reschedule(this->getScanPeriod());
}
}
//
// exPV::show()
//
void exPV::show(unsigned level)
void exPV::show(unsigned level) const
{
if (level>1u) {
if (this->pValue) {
+4 -3
View File
@@ -1,10 +1,11 @@
#include <exServer.h>
#include <gddApps.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#include "exServer.h"
#include "gddApps.h"
#define myPI 3.14159265358979323846
//
@@ -31,7 +32,7 @@ void exScalarPV::scan()
gdd *pDD;
float newValue;
float limit;
//
// update current time (so we are not required to do
// this every time that we write the PV which impacts
+248 -80
View File
@@ -7,124 +7,267 @@
// Example EPICS CA server
//
#include <exServer.h>
const pvInfo exServer::pvList[] = {
pvInfo (1.0e-1, "jane", 10.0f, 0.0f, excasIoSync, 1u),
pvInfo (2.0, "fred", 10.0f, -10.0f, excasIoSync, 1u),
pvInfo (1.0e-1, "janet", 10.0f, 0.0f, excasIoAsync, 1u),
pvInfo (2.0, "freddy", 10.0f, -10.0f, excasIoAsync, 1u),
pvInfo (2.0, "alan", 10.0f, -10.0f, excasIoSync, 100u),
pvInfo (20.0, "albert", 10.0f, -10.0f, excasIoSync, 1000u)
};
#include "exServer.h"
//
// static data for exServer
//
gddAppFuncTable<exPV> exServer::ft;
//
// static list of pre-created PVs
//
pvInfo exServer::pvList[] = {
pvInfo (1.0e-1, "jane", 10.0f, 0.0f, excasIoSync, 1u),
pvInfo (2.0, "fred", 10.0f, -10.0f, excasIoSync, 1u),
pvInfo (1.0e-1, "janet", 10.0f, 0.0f, excasIoAsync, 1u),
pvInfo (2.0, "freddy", 10.0f, -10.0f, excasIoAsync, 1u),
pvInfo (2.0, "alan", 10.0f, -10.0f, excasIoSync, 100u),
pvInfo (20.0, "albert", 10.0f, -10.0f, excasIoSync, 1000u)
};
//
// static on-the-fly PVs
//
pvInfo exServer::bill (2.0, "bill", 10.0f, -10.0f, excasIoSync, 1u);
pvInfo exServer::billy (2.0, "billy", 10.0f, -10.0f, excasIoAsync, 1u);
//
// exServer::exServer()
//
exServer::exServer(unsigned pvMaxNameLength, unsigned pvCountEstimate,
unsigned maxSimultaneousIO) :
caServer(pvMaxNameLength, pvCountEstimate, maxSimultaneousIO)
exServer::exServer(const char * const pvPrefix, unsigned aliasCount) :
caServer(NELEMENTS(this->pvList)+2u),
simultAsychIOCount(0u)
{
ft.installReadFunc("status",exPV::getStatus);
ft.installReadFunc("severity",exPV::getSeverity);
ft.installReadFunc("seconds",exPV::getSeconds);
ft.installReadFunc("nanoseconds",exPV::getNanoseconds);
ft.installReadFunc("precision",exPV::getPrecision);
ft.installReadFunc("graphicHigh",exPV::getHighLimit);
ft.installReadFunc("graphicLow",exPV::getLowLimit);
ft.installReadFunc("controlHigh",exPV::getHighLimit);
ft.installReadFunc("controlLow",exPV::getLowLimit);
ft.installReadFunc("alarmHigh",exPV::getHighLimit);
ft.installReadFunc("alarmLow",exPV::getLowLimit);
ft.installReadFunc("alarmHighWarning",exPV::getHighLimit);
ft.installReadFunc("alarmLowWarning",exPV::getLowLimit);
ft.installReadFunc("units",exPV::getUnits);
ft.installReadFunc("value",exPV::getValue);
ft.installReadFunc("enums",exPV::getEnums);
unsigned i;
exPV *pPV;
pvInfo *pPVI;
pvInfo *pPVAfter =
&exServer::pvList[NELEMENTS(exServer::pvList)];
int resLibStatus;
char pvAlias[256];
const char * const pNameFmtStr = "%.100s%.20s";
const char * const pAliasFmtStr = "%.100s%.20s%u";
ft.installReadFunc ("status", &exPV::getStatus);
ft.installReadFunc ("severity", &exPV::getSeverity);
ft.installReadFunc ("seconds", &exPV::getSeconds);
ft.installReadFunc ("nanoseconds", &exPV::getNanoseconds);
ft.installReadFunc ("precision", &exPV::getPrecision);
ft.installReadFunc ("graphicHigh", &exPV::getHighLimit);
ft.installReadFunc ("graphicLow", &exPV::getLowLimit);
ft.installReadFunc ("controlHigh", &exPV::getHighLimit);
ft.installReadFunc ("controlLow", &exPV::getLowLimit);
ft.installReadFunc ("alarmHigh", &exPV::getHighLimit);
ft.installReadFunc ("alarmLow", &exPV::getLowLimit);
ft.installReadFunc ("alarmHighWarning", &exPV::getHighLimit);
ft.installReadFunc ("alarmLowWarning", &exPV::getLowLimit);
ft.installReadFunc ("units", &exPV::getUnits);
ft.installReadFunc ("value", &exPV::getValue);
ft.installReadFunc ("enums", &exPV::getEnums);
//
// hash table size may need adjustment here?
//
resLibStatus = this->stringResTbl.init(NELEMENTS(this->pvList)*(aliasCount+1u)+2u);
if (resLibStatus) {
fprintf(stderr, "CAS: string resource id table init failed\n");
//
// should throw an exception once this is portable
//
assert(resLibStatus==0);
}
//
// pre-create all of the simple PVs that this server will export
//
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
pPV = pPVI->createPV (*this, aitTrue);
if (!pPV) {
fprintf(stderr, "Unable to create new PV \"%s\"\n",
pPVI->getName());
}
//
// Install canonical (root) name
//
sprintf(pvAlias, pNameFmtStr, pvPrefix, pPVI->getName());
this->installAliasName(*pPVI, pvAlias);
//
// Install numbered alias names
//
for (i=0u; i<aliasCount; i++) {
sprintf(pvAlias, pAliasFmtStr, pvPrefix,
pPVI->getName(), i);
this->installAliasName(*pPVI, pvAlias);
}
}
//
// Install create on-the-fly PVs
// into the PV name hash table
//
sprintf(pvAlias, pNameFmtStr, pvPrefix, bill.getName());
this->installAliasName(bill, pvAlias);
sprintf(pvAlias, pNameFmtStr, pvPrefix, billy.getName());
this->installAliasName(billy, pvAlias);
}
//
// exServer::installAliasName()
//
void exServer::installAliasName(pvInfo &info, const char *pAliasName)
{
pvEntry *pEntry;
pEntry = new pvEntry(info, *this, pAliasName);
if (pEntry) {
int resLibStatus;
resLibStatus = this->stringResTbl.add(*pEntry);
if (resLibStatus==0) {
return;
}
else {
delete pEntry;
}
}
fprintf(stderr,
"Unable to enter PV=\"%s\" Alias=\"%s\" in PV name alias hash table\n",
info.getName(), pAliasName);
}
//
// exServer::pvExistTest()
//
pvExistReturn exServer::pvExistTest(const casCtx &ctxIn, const char *pPVName)
pvExistReturn exServer::pvExistTest(const casCtx& ctxIn, const char *pPVName)
{
const pvInfo *pPVI;
//
// lifetime of id is shorter than lifetime of pName
//
stringId id(pPVName, stringId::refString);
pvEntry *pPVE;
pPVI = exServer::findPV(pPVName);
if (pPVI) {
if (pPVI->getIOType()==excasIoAsync) {
exAsyncExistIO *pIO;
pIO = new exAsyncExistIO(*pPVI, ctxIn);
if (pIO) {
return pvExistReturn(S_casApp_asyncCompletion);
}
else {
return pvExistReturn(S_casApp_noMemory);
}
}
const char *pName = pPVI->getName();
return pvExistReturn(S_casApp_success, pName);
//
// Look in hash table for PV name (or PV alias name)
//
pPVE = this->stringResTbl.lookup(id);
if (!pPVE) {
return pverDoesNotExistHere;
}
return pvExistReturn(S_casApp_pvNotFound);
}
pvInfo &pvi(pPVE->getInfo());
//
// findPV()
//
const pvInfo *exServer::findPV(const char *pName)
{
const pvInfo *pPVI;
const pvInfo *pPVAfter =
&exServer::pvList[NELEMENTS(exServer::pvList)];
//
// Initiate async IO if this is an async PV
//
if (pvi.getIOType() == excasIoSync) {
return pverExistsHere;
}
else {
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
return pverDoesNotExistHere;
}
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
if (strcmp (pName, pPVI->getName().string()) == '\0') {
return pPVI;
this->simultAsychIOCount++;
exAsyncExistIO *pIO;
pIO = new exAsyncExistIO(pvi, ctxIn, *this);
if (pIO) {
return pverAsyncCompletion;
}
else {
return pverDoesNotExistHere;
}
}
return NULL;
}
//
// exServer::createPV()
//
casPV *exServer::createPV (const casCtx &ctxIn, const char *pPVName)
pvCreateReturn exServer::createPV (const casCtx &ctx, const char *pName)
{
const pvInfo *pInfo;
exPV *pPV;
//
// lifetime of id is shorter than lifetime of pName
//
stringId id(pName, stringId::refString);
exPV *pPV;
pvEntry *pPVE;
pInfo = exServer::findPV(pPVName);
if (!pInfo) {
return NULL;
pPVE = this->stringResTbl.lookup(id);
if (!pPVE) {
return pvCreateReturn(S_casApp_pvNotFound);
}
pvInfo &pvi(pPVE->getInfo());
//
// If this is a synchronous PV create the PV now
//
if (pvi.getIOType() == excasIoSync) {
pPV = pvi.createPV(*this, aitFalse);
if (!pPV) {
pvCreateReturn(S_casApp_noMemory);
}
return pvCreateReturn(*pPV);
}
//
// Initiate async IO if this is an async PV
//
else {
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
return pvCreateReturn(S_casApp_postponeAsyncIO);
}
this->simultAsychIOCount++;
exAsyncCreateIO *pIO =
new exAsyncCreateIO(pvi, *this, ctx);
if (pIO) {
return pvCreateReturn(S_casApp_asyncCompletion);
}
else {
return pvCreateReturn(S_casApp_noMemory);
}
}
}
//
// pvInfo::createPV()
//
exPV *pvInfo::createPV (exServer &exCAS, aitBool preCreateFlag)
{
if (this->pPV) {
return this->pPV;
}
exPV *pNewPV;
//
// create an instance of the appropriate class
// depending on the io type and the number
// of elements
//
if (pInfo->getElementCount()==1u) {
switch (pInfo->getIOType()){
if (this->elementCount==1u) {
switch (this->ioType){
case excasIoSync:
pPV = new exScalarPV (ctxIn, *pInfo);
pNewPV = new exScalarPV (exCAS, *this, preCreateFlag);
break;
case excasIoAsync:
pPV = new exAsyncPV (ctxIn, *pInfo);
pNewPV = new exAsyncPV (exCAS, *this, preCreateFlag);
break;
default:
pPV = NULL;
pNewPV = NULL;
break;
}
}
else {
pPV = new exVectorPV (ctxIn, *pInfo);
if (this->ioType==excasIoSync) {
pNewPV = new exVectorPV (exCAS, *this, preCreateFlag);
}
else {
pNewPV = NULL;
}
}
//
@@ -132,21 +275,23 @@ casPV *exServer::createPV (const casCtx &ctxIn, const char *pPVName)
// the constructor because the base class's
// pure virtual function would be called)
//
if (pPV) {
pPV->scan();
if (pNewPV) {
this->pPV = pNewPV;
pNewPV->scan();
}
return pPV;
return pNewPV;
}
//
// exServer::show()
// exServer::show()
//
void exServer::show (unsigned level)
void exServer::show (unsigned level) const
{
//
// server tool specific show code goes here
//
this->stringResTbl.show(level);
//
// print information about ca server libarary
@@ -170,12 +315,10 @@ void exOSITimer::destroy()
//
void exAsyncExistIO::expire()
{
const char *pName = pvi.getName();
//
// post IO completion
//
this->postIOCompletion (pvExistReturn(S_cas_success, pName));
this->postIOCompletion (pverExistsHere);
}
//
@@ -186,3 +329,28 @@ const char *exAsyncExistIO::name() const
return "exAsyncExistIO";
}
//
// exAsyncCreateIO::expire()
// (a virtual function that runs when the base timer expires)
//
void exAsyncCreateIO::expire()
{
exPV *pPV;
pPV = this->pvi.createPV(this->cas, aitFalse);
if (pPV) {
this->postIOCompletion (pvCreateReturn(*pPV));
}
else {
this->postIOCompletion (pvCreateReturn(S_casApp_noMemory));
}
}
//
// exAsyncCreateIO::name()
//
const char *exAsyncCreateIO::name() const
{
return "exAsyncCreateIO";
}
+201 -46
View File
@@ -26,37 +26,38 @@
//
// EPICS
//
#include <epicsAssert.h>
#include <casdef.h>
#include <gddAppFuncTable.h>
#include <osiTimer.h>
#ifndef max
#define max(A,B) ((A)<(B)?(B):(A))
#endif
#ifndef min
#define min(A,B) ((A)>(B)?(B):(A))
#endif
#include "epicsAssert.h"
#include "casdef.h"
#include "gddAppFuncTable.h"
#include "osiTimer.h"
#include "resourceLib.h"
#include "minmax.h"
#ifndef NELEMENTS
# define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif
#define LOCAL static
#define maxSimultAsyncIO 1000u
//
// info about all pv in this server
//
enum excasIoType {excasIoSync, excasIoAsync};
class exPV;
class exServer;
//
// pvInfo
//
class pvInfo {
public:
pvInfo (double scanRateIn, const char *pName,
pvInfo (double scanPeriodIn, const char *pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn,
excasIoType ioTypeIn, unsigned countIn) :
scanRate(scanRateIn), name(pName), hopr(hoprIn),
lopr(loprIn), ioType(ioTypeIn), elementCount(countIn)
scanPeriod(scanPeriodIn), pName(pNameIn),
hopr(hoprIn), lopr(loprIn), ioType(ioTypeIn),
elementCount(countIn), pPV(0)
{
}
@@ -65,29 +66,64 @@ public:
// for this class
//
pvInfo (const pvInfo &copyIn) :
scanRate(copyIn.scanRate), name(copyIn.name),
scanPeriod(copyIn.scanPeriod), pName(copyIn.pName),
hopr(copyIn.hopr), lopr(copyIn.lopr),
ioType(copyIn.ioType), elementCount(copyIn.elementCount)
ioType(copyIn.ioType), elementCount(copyIn.elementCount),
pPV(copyIn.pPV)
{
}
const double getScanRate () const { return this->scanRate; }
const aitString &getName () const { return this->name; }
const double getScanPeriod () const { return this->scanPeriod; }
const char *getName () const { return this->pName; }
const double getHopr () const { return this->hopr; }
const double getLopr () const { return this->lopr; }
const excasIoType getIOType () const { return this->ioType; }
const unsigned getElementCount() const { return this->elementCount; }
void destroyPV() { this->pPV=NULL; }
exPV *createPV (exServer &exCAS, aitBool preCreateFlag);
private:
const double scanRate;
const aitString name;
const double scanPeriod;
const char *pName;
const double hopr;
const double lopr;
const excasIoType ioType;
const unsigned elementCount;
exPV *pPV;
};
class exPV;
//
// pvEntry
//
// o entry in the string hash table for the pvInfo
// o Since there may be aliases then we may end up
// with several of this class all referencing
// the same pv info class (justification
// for this breaking out into a seperate class
// from pvInfo)
//
class pvEntry : public stringId, public tsSLNode<pvEntry> {
public:
pvEntry (pvInfo &infoIn, exServer &casIn, const char *pAliasName) :
stringId(pAliasName), info(infoIn), cas(casIn)
{
assert(this->stringId::resourceName()!=NULL);
}
inline ~pvEntry();
pvInfo &getInfo() const { return this->info; }
void destroy ()
{
//
// always created with new
//
delete this;
}
private:
pvInfo &info;
exServer &cas;
};
//
// exScanTimer
@@ -107,13 +143,12 @@ private:
//
// exPV
//
class exPV : public casPV {
class exPV : public casPV, public tsSLNode<exPV> {
public:
exPV (const casCtx &ctxIn, const pvInfo &setup);
exPV (caServer &cas, pvInfo &setup, aitBool preCreateFlag);
virtual ~exPV();
void show(unsigned level);
void show(unsigned level) const;
//
// Called by the server libary each time that it wishes to
@@ -170,20 +205,43 @@ public:
//
aitTimeStamp getTS();
const float getScanRate()
//
// If no one is watching scan the PV with 10.0
// times the specified period
//
const float getScanPeriod()
{
return this->info.getScanRate();
double curPeriod;
curPeriod = this->info.getScanPeriod();
if (!this->interest) {
curPeriod *= 10.0L;
}
return curPeriod;
}
caStatus read (const casCtx &, gdd &protoIn);
caStatus write (const casCtx &, gdd &protoIn);
void destroy();
const pvInfo &getPVInfo()
{
return this->info;
}
const char *getName() const
{
return this->info.getName();
}
protected:
gdd *pValue;
exScanTimer *pScanTimer;
const pvInfo & info;
pvInfo & info;
aitBool interest;
aitBool preCreate;
static osiTime currentTime;
virtual caStatus updateValue (gdd &value) = 0;
@@ -194,8 +252,8 @@ protected:
//
class exScalarPV : public exPV {
public:
exScalarPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup) {}
exScalarPV (caServer &cas, pvInfo &setup, aitBool preCreateFlag) :
exPV (cas, setup, preCreateFlag) {}
void scan();
private:
caStatus updateValue (gdd &value);
@@ -206,8 +264,8 @@ private:
//
class exVectorPV : public exPV {
public:
exVectorPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup) {}
exVectorPV (caServer &cas, pvInfo &setup, aitBool preCreateFlag) :
exPV (cas, setup, preCreateFlag) {}
void scan();
unsigned maxDimension() const;
@@ -222,20 +280,46 @@ private:
//
class exServer : public caServer {
public:
exServer(unsigned pvMaxNameLength, unsigned pvCountEstimate=0x3ff,
unsigned maxSimultaneousIO=1u);
void show (unsigned level);
pvExistReturn pvExistTest (const casCtx &ctxIn, const char *pPVName);
casPV *createPV (const casCtx &ctxIn, const char *pPVName);
exServer(const char * const pvPrefix, unsigned aliasCount);
void show (unsigned level) const;
pvExistReturn pvExistTest (const casCtx&, const char *pPVName);
pvCreateReturn createPV (const casCtx &ctx, const char *pPVName);
static const pvInfo *findPV(const char *pName);
void installAliasName(pvInfo &info, const char *pAliasName);
inline void removeAliasName(pvEntry &entry);
static gddAppFuncTableStatus read(exPV &pv, gdd &value)
{
return exServer::ft.read(pv, value);
}
//
// removeIO
//
void removeIO()
{
if (this->simultAsychIOCount>0u) {
this->simultAsychIOCount--;
}
else {
fprintf(stderr, "inconsistent simultAsychIOCount?\n");
}
}
private:
static const pvInfo pvList[];
resTable<pvEntry,stringId> stringResTbl;
unsigned simultAsychIOCount;
//
// list of pre-created PVs
//
static pvInfo pvList[];
//
// on-the-fly PVs
//
static pvInfo bill;
static pvInfo billy;
static gddAppFuncTable<exPV> ft;
};
@@ -247,8 +331,9 @@ public:
//
// exAsyncPV()
//
exAsyncPV (const casCtx &ctxIn, const pvInfo &setup) :
exScalarPV (ctxIn, setup) {}
exAsyncPV (caServer &cas, pvInfo &setup, aitBool preCreateFlag) :
exScalarPV (cas, setup, preCreateFlag),
simultAsychIOCount(0u) {}
//
// read
@@ -260,8 +345,20 @@ public:
//
caStatus write(const casCtx &ctxIn, gdd &value);
unsigned maxSimultAsyncOps () const;
//
// removeIO
//
void removeIO()
{
if (this->simultAsychIOCount>0u) {
this->simultAsychIOCount--;
}
else {
fprintf(stderr, "inconsistent simultAsychIOCount?\n");
}
}
private:
unsigned simultAsychIOCount;
};
//
@@ -332,6 +429,7 @@ public:
~exAsyncWriteIO()
{
this->pv.removeIO();
this->value.unreference();
}
@@ -365,6 +463,7 @@ public:
~exAsyncReadIO()
{
this->pv.removeIO();
this->proto.unreference();
}
@@ -391,8 +490,14 @@ public:
//
// exAsyncExistIO()
//
exAsyncExistIO(const pvInfo &pviIn, const casCtx &ctxIn) :
casAsyncPVExistIO(ctxIn), pvi(pviIn) {}
exAsyncExistIO(const pvInfo &pviIn, const casCtx &ctxIn,
exServer &casIn) :
casAsyncPVExistIO(ctxIn), pvi(pviIn), cas(casIn) {}
~exAsyncExistIO()
{
this->cas.removeIO();
}
//
// expire()
@@ -404,6 +509,56 @@ public:
const char *name() const;
private:
const pvInfo &pvi;
exServer &cas;
};
//
// exAsyncCreateIO
// (PV create async IO)
//
class exAsyncCreateIO : public casAsyncPVCreateIO, public exOSITimer {
public:
//
// exAsyncCreateIO()
//
exAsyncCreateIO(pvInfo &pviIn, exServer &casIn,
const casCtx &ctxIn) :
casAsyncPVCreateIO(ctxIn), pvi(pviIn), cas(casIn) {}
~exAsyncCreateIO()
{
this->cas.removeIO();
}
//
// expire()
// (a virtual function that runs when the base timer expires)
// see exServer.cc
//
void expire();
const char *name() const;
private:
pvInfo &pvi;
exServer &cas;
};
//
// exServer::removeAliasName()
//
inline void exServer::removeAliasName(pvEntry &entry)
{
pvEntry *pE;
pE = this->stringResTbl.remove(entry);
assert(pE = &entry);
}
//
// pvEntry::~pvEntry()
//
inline pvEntry::~pvEntry()
{
this->cas.removeAliasName(*this);
}
+2 -2
View File
@@ -1,6 +1,6 @@
#include <exServer.h>
#include <gddApps.h>
#include "exServer.h"
#include "gddApps.h"
#define myPI 3.14159265358979323846
+16 -5
View File
@@ -1,17 +1,19 @@
#include <exServer.h>
#include <fdManager.h>
#include "exServer.h"
#include "fdManager.h"
//
// main()
// (example single threaded ca server tool main loop)
//
int main (int argc, const char **argv)
extern int main (int argc, const char **argv)
{
osiTime begin(osiTime::getCurrent());
exServer *pCAS;
unsigned debugLevel = 0u;
float executionTime;
char pvPrefix[128] = "";
unsigned aliasCount = 1u;
aitBool forever = aitTrue;
int i;
@@ -23,12 +25,20 @@ int main (int argc, const char **argv)
forever = aitFalse;
continue;
}
printf ("usage: %s -d<debug level> -t<execution time>\n",
if (sscanf(argv[i],"-p %127s", pvPrefix)==1) {
continue;
}
if (sscanf(argv[i],"-c %u", &aliasCount)==1) {
continue;
}
printf (
"usage: %s [-d<debug level> -t<execution time> -p<PV name prefix> -c<numbered alias count>]\n",
argv[0]);
return (1);
}
pCAS = new exServer(32u,5u,500u);
pCAS = new exServer(pvPrefix, aliasCount);
if (!pCAS) {
return (-1);
}
@@ -56,6 +66,7 @@ int main (int argc, const char **argv)
delay = osiTime::getCurrent() - begin;
}
}
pCAS->show(2u);
delete pCAS;
return (0);
}
+5 -2
View File
@@ -9,11 +9,13 @@
#include "exServer.h"
#include "gddAppFuncTable.cc"
#include "resourceLib.cc"
//
// Sun C++ 4.1 still appears to be lacking support in this area
// if the compiler supports explicit instantiation of
// template member functions
//
#if !defined(__SUNPRO_CC)
#if defined(EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
@@ -22,5 +24,6 @@
// member functions into "templInst.o"
//
template class gddAppFuncTable <exPV>;
template class resTable <pvEntry,stringId>;
#endif
+6 -1
View File
@@ -3,14 +3,19 @@
// Author: Jeff HIll (LANL)
//
// $Log$
// Revision 1.1 1996/12/06 22:20:22 jhill
// moved down one level
//
// Revision 1.2 1996/09/16 18:22:09 jhill
// added cvs log entries
//
//
#include <exServer.h>
#include <vxWorks.h>
#include <taskLib.h>
#include "exServer.h"
//
// so we can call this from the vxWorks shell
//
+12 -15
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.4 1996/11/02 00:53:53 jhill
* many improvements
*
* Revision 1.3 1996/09/16 18:23:56 jhill
* vxWorks port changes
*
@@ -41,26 +44,18 @@
*
*/
#include <server.h>
#include <caServerIIL.h> // caServerI in line func
#include <dbMapper.h> // ait to dbr types
#include <gddAppTable.h> // EPICS application type table
#include "server.h"
#include "caServerIIL.h" // caServerI in line func
#include "dbMapper.h" // ait to dbr types
#include "gddAppTable.h" // EPICS application type table
//
// NOTES
// .01 All use of member pCAS in this file must first verify
// that we successfully created a caServerI in
// the constructor
//
//
// caServer::caServer()
//
caServer::caServer(unsigned pvMaxNameLengthIn, unsigned pvCountEstimateIn,
unsigned maxSimultaneousIOIn) :
pCAS (new caServerI(*this, pvMaxNameLengthIn,
pvCountEstimateIn, maxSimultaneousIOIn)),
caServer::caServer(unsigned pvCountEstimateIn) :
pCAS (new caServerI(*this, pvCountEstimateIn)),
valueEventMask(this->registerEvent("value")),
logEventMask(this->registerEvent("log")),
alarmEventMask(this->registerEvent("alarm"))
@@ -112,7 +107,7 @@ casEventMask caServer::registerEvent (const char *pName)
//
// caServer::show()
//
void caServer::show(unsigned level)
void caServer::show(unsigned level) const
{
if (this->pCAS) {
this->pCAS->show(level);
@@ -149,6 +144,8 @@ unsigned caServer::getDebugLevel ()
}
}
//
// casRes::~casRes()
//
// This must be virtual so that derived destructor will
// be run indirectly. Therefore it cannot be inline.
+35 -50
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.6 1996/11/02 00:53:54 jhill
* many improvements
*
* Revision 1.5 1996/09/16 18:23:56 jhill
* vxWorks port changes
*
@@ -50,8 +53,8 @@
#define CAS_VERSION_GLOBAL
#define caServerGlobal
#include <server.h>
#include <casCtxIL.h> // casCtx in line func
#include "server.h"
#include "casCtxIL.h" // casCtx in line func
static const osiTime CAServerMaxBeaconPeriod (5.0 /* sec */);
static const osiTime CAServerMinBeaconPeriod (1.0e-3 /* sec */);
@@ -60,9 +63,8 @@ static const osiTime CAServerMinBeaconPeriod (1.0e-3 /* sec */);
//
// caServerI::show()
//
void caServerI::show (unsigned level)
void caServerI::show (unsigned level) const
{
casStrmClient *pClient;
int bytes_reserved;
printf( "Channel Access Server Status V%d.%d\n",
@@ -71,16 +73,19 @@ void caServerI::show (unsigned level)
this->osiMutex::show(level);
this->osiLock();
tsDLFwdIter<casStrmClient> iterCl(this->clientList);
while ( (pClient = iterCl.next()) ) {
pClient->show(level);
const tsDLIterBD<casStrmClient> eolSC;
tsDLIterBD<casStrmClient> iterCl(this->clientList.first());
while ( iterCl!=eolSC ) {
iterCl->show(level);
++iterCl;
}
this->dgClient.show(level);
casIntfOS *pIF;
tsDLFwdIter<casIntfOS> iterIF(this->intfList);
while ( (pIF = iterIF.next()) ) {
pIF->show(level);
const tsDLIterBD<casIntfOS> eolIOS;
tsDLIterBD<casIntfOS> iterIF(this->intfList.first());
while ( iterIF!=eolIOS ) {
iterIF->show(level);
++iterIF;
}
this->osiUnlock();
@@ -113,11 +118,6 @@ void caServerI::show (unsigned level)
this->osiLock();
this->uintResTable<casRes>::show(level);
this->osiUnlock();
printf(
"The server's character string resource id conversion table:\n");
this->osiLock();
this->stringResTbl.show(level);
this->osiUnlock();
}
// @@@@@@ caPrintAddrList(&destAddr);
@@ -129,8 +129,7 @@ void caServerI::show (unsigned level)
//
// caServerI::caServerI()
//
caServerI::caServerI (caServer &tool, unsigned maxNameLength,
unsigned nPV, unsigned maxSimultIO) :
caServerI::caServerI (caServer &tool, unsigned nPV) :
caServerOS(*this),
casEventRegistry(* (osiMutex *) this),
dgClient(*this),
@@ -141,18 +140,14 @@ caServerI::caServerI (caServer &tool, unsigned maxNameLength,
//
beaconPeriod(CAServerMinBeaconPeriod),
adapter(tool),
pvCount(0u),
debugLevel(0u),
nExistTestInProg(0u),
pvMaxNameLength(maxNameLength),
pvCountEstimate(nPV<100u?100u:nPV),
maxSimultaneousIO(maxSimultIO),
haveBeenInitialized(FALSE)
{
caStatus status;
assert(&adapter);
ctx.setServer(this);
//ctx.setServer(this);
status = this->init();
if (status) {
@@ -200,21 +195,12 @@ caStatus caServerI::init()
//
// hash table size may need adjustment here?
//
resLibStatus = this->uintResTable<casRes>::init(this->pvCountEstimate*8u);
resLibStatus = this->uintResTable<casRes>::init(this->pvCountEstimate*2u);
if (resLibStatus) {
ca_printf("CAS: integer resource id table init failed\n");
return S_cas_noMemory;
}
//
// hash table size may need adjustment here?
//
resLibStatus = this->stringResTbl.init(this->pvCountEstimate*2u);
if (resLibStatus) {
ca_printf("CAS: string resource id table init failed\n");
return S_cas_noMemory;
}
this->haveBeenInitialized = TRUE;
return S_cas_success;
}
@@ -232,13 +218,18 @@ caServerI::~caServerI()
//
// delete all clients
//
casClient *pClient;
tsDLFwdIter<casStrmClient> iter(this->clientList);
pClient = iter.next();
while (pClient) {
casClient *pNextClient = iter.next();
delete pClient;
pClient = pNextClient;
tsDLIterBD<casStrmClient> iter(this->clientList.first());
tsDLIterBD<casStrmClient> eol;
tsDLIterBD<casStrmClient> tmp;
while ( iter!=eol ) {
tmp = iter;
++tmp;
//
// destructor takes client out of list
//
casStrmClient *pC = iter;
delete pC;
iter = tmp;
}
casIntfOS *pIF;
@@ -247,11 +238,6 @@ caServerI::~caServerI()
}
this->osiUnlock();
//
// verify that we didnt leak a PV
//
assert (this->pvCount==0u);
}
@@ -380,8 +366,6 @@ caStatus caServerI::addAddr(const caAddr &caAddr, int autoBeaconAddr,
//
void caServerI::sendBeacon()
{
casIntfOS *pIntf;
//
// send a broadcast beacon over each configured
// interface unless EPICS_CA_AUTO_ADDR_LIST specifies
@@ -389,9 +373,10 @@ void caServerI::sendBeacon()
// addresses.
//
this->osiLock();
tsDLFwdIter<casIntfOS> iter(this->intfList);
while ( (pIntf = iter.next()) ) {
pIntf->requestBeacon();
tsDLIterBD<casIntfOS> iter(this->intfList.first());
while ( iter ) {
iter->requestBeacon();
iter++;
}
this->osiUnlock();
+5 -72
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.3 1996/11/02 00:53:56 jhill
* many improvements
*
* Revision 1.2 1996/09/16 18:23:57 jhill
* vxWorks port changes
*
@@ -93,83 +96,13 @@ inline casChannelI *caServerI::resIdToChannel(const caResId &id)
return (casChannelI *) pRes;
}
//
// caServerI::pvExistTestPossible()
//
inline aitBool caServerI::pvExistTestPossible()
{
if (this->nExistTestInProg < this->maxSimultaneousIO) {
return aitTrue;
}
return aitFalse;
}
//
// find the channel associated with a resource id
//
inline pvExistReturn caServerI::pvExistTest(
inline casPVExistReturn caServerI::pvExistTest(
const casCtx &ctxIn, const char *pPVName)
{
this->osiLock();
if (pvExistTestPossible()) {
this->nExistTestInProg++;
osiUnlock();
return (*this)->pvExistTest(ctxIn, pPVName);
}
else {
osiUnlock();
return pvExistReturn(S_cas_ioBlocked);
}
}
//
// caServerI::pvExistTestCompletion()
//
inline void caServerI::pvExistTestCompletion()
{
this->osiLock();
this->nExistTestInProg--;
this->osiUnlock();
this->ioBlockedList::signal();
}
//
// install a PV into the server
//
inline void caServerI::installPV (casPVI &pv)
{
int resLibStatus;
this->osiLock ();
this->pvCount++;
resLibStatus = this->stringResTbl.add (pv);
this->osiUnlock ();
assert (resLibStatus==0);
}
//
// remove PV from the server
//
inline void caServerI::removePV(casPVI &pv)
{
casPVI *pPV;
this->osiLock();
casVerify (this->pvCount>=1u);
this->pvCount--;
pPV = this->stringResTbl.remove (pv);
this->osiUnlock();
casVerify (pPV!=0);
casVerify (pPV==&pv);
}
//
// caServerI::getPVMaxNameLength()
//
inline unsigned caServerI::getPVMaxNameLength() const
{
return this->pvMaxNameLength;
return casPVExistReturn((*this)->pvExistTest(ctxIn, pPVName));
}
//
+10 -11
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.2 1996/11/06 22:15:53 jhill
* allow monitor init read to using rd async io
*
* Revision 1.1 1996/11/02 01:01:02 jhill
* installed
*
@@ -37,12 +40,12 @@
*/
#include <server.h>
#include <casAsyncIOIIL.h> // casAsyncIOI in line func
#include <casChannelIIL.h> // casChannelI in line func
#include <casOpaqueAddrIL.h> // casOpaqueAddr in line func
#include <casCtxIL.h> // casCtx in line func
#include <casCoreClientIL.h> // casCoreClient in line func
#include "server.h"
#include "casAsyncIOIIL.h" // casAsyncIOI in line func
#include "casChannelIIL.h" // casChannelI in line func
#include "casOpaqueAddrIL.h" // casOpaqueAddr in line func
#include "casCtxIL.h" // casCtx in line func
#include "casCoreClientIL.h" // casCoreClient in line func
//
// casAsyncExIOI::casAsyncExIOI()
@@ -69,7 +72,7 @@ casAsyncExIOI::~casAsyncExIOI()
//
// casAsyncExIOI::postIOCompletion()
//
caStatus casAsyncExIOI::postIOCompletion(const pvExistReturn &retValIn)
caStatus casAsyncExIOI::postIOCompletion(const pvExistReturn retValIn)
{
this->retVal = retValIn;
return this->postIOCompletionI();
@@ -94,10 +97,6 @@ caStatus casAsyncExIOI::cbFuncAsyncIO()
this->dgOutAddr.get(), this->msg, this->retVal);
break;
case CA_PROTO_CLAIM_CIU:
status = this->client.createChanResponse(this->msg, this->retVal);
break;
default:
this->reportInvalidAsynchIO(this->msg.m_cmmd);
status = S_cas_internal;
+4 -1
View File
@@ -29,13 +29,16 @@
*
* History
* $Log$
* Revision 1.2 1996/11/02 00:53:57 jhill
* many improvements
*
* Revision 1.1.1.1 1996/06/20 00:28:14 jhill
* ca server installation
*
*
*/
#include<server.h>
#include"server.h"
//
// This must be virtual so that derived destructor will
+37 -8
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.5 1996/12/13 00:08:35 jhill
* dont unlock after destroy
*
* Revision 1.4 1996/11/02 00:53:58 jhill
* many improvements
*
@@ -36,10 +39,10 @@
*/
#include <server.h>
#include <casEventSysIL.h> // casEventSys in line func
#include <casAsyncIOIIL.h> // casAsyncIOI in line func
#include <casCtxIL.h> // casCtx in line func
#include "server.h"
#include "casEventSysIL.h" // casEventSys in line func
#include "casAsyncIOIIL.h" // casAsyncIOI in line func
#include "casCtxIL.h" // casCtx in line func
//
// casAsyncIOI::casAsyncIOI()
@@ -52,6 +55,19 @@ casAsyncIOI::casAsyncIOI(casCoreClient &clientIn, casAsyncIO &ioExternalIn) :
ioComplete(FALSE),
serverDelete(FALSE)
{
//
// catch situation where they create more than one
// async IO object per request
//
if (client.asyncIOFlag) {
errMessage(S_cas_badParameter,
"- duplicate async IO creation");
this->duplicate = TRUE;
}
else {
client.asyncIOFlag = TRUE;
this->duplicate = FALSE;
}
}
//
@@ -165,6 +181,18 @@ caStatus casAsyncIOI::postIOCompletionI()
{
this->lock();
if (this->duplicate) {
errMessage(S_cas_badParameter,
"- duplicate async IO");
//
// dont use "this" after potentially destroying the
// object here
//
this->serverDelete = TRUE;
(*this)->destroy();
return S_cas_redundantPost;
}
//
// verify that they dont post completion more than once
//
@@ -194,7 +222,7 @@ caStatus casAsyncIOI::postIOCompletionI()
// casAsyncIOI::getCAS()
// (not inline because this is used by the interface class)
//
caServer *casAsyncIOI::getCAS()
caServer *casAsyncIOI::getCAS() const
{
return this->client.getCAS().getAdapter();
}
@@ -215,13 +243,13 @@ int casAsyncIOI::readOP()
//
void casAsyncIOI::destroyIfReadOP()
{
casCoreClient &client = this->client;
casCoreClient &clientCopy = this->client;
//
// client lock used because this object's
// lock may be destroyed
//
client.osiLock();
clientCopy.osiLock();
if (this->readOP()) {
this->serverDelete = TRUE;
@@ -232,7 +260,8 @@ void casAsyncIOI::destroyIfReadOP()
// NO REF TO THIS OBJECT BELOW HERE
// BECAUSE OF THE DELETE ABOVE
//
client.osiUnlock();
clientCopy.osiUnlock();
}
//
+7 -4
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.2 1996/11/06 22:15:54 jhill
* allow monitor init read to using rd async io
*
* Revision 1.1 1996/11/02 01:01:03 jhill
* installed
*
@@ -45,10 +48,10 @@
*/
#include <server.h>
#include <casAsyncIOIIL.h> // casAsyncIOI in line func
#include <casChannelIIL.h> // casChannelI in line func
#include <casCtxIL.h> // casCtxI in line func
#include "server.h"
#include "casAsyncIOIIL.h" // casAsyncIOI in line func
#include "casChannelIIL.h" // casChannelI in line func
#include "casCtxIL.h" // casCtxI in line func
//
// casAsyncRdIOI::casAsyncRdIOI()
+7 -4
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.2 1996/11/06 22:15:56 jhill
* allow monitor init read to using rd async io
*
* Revision 1.1 1996/11/02 01:01:04 jhill
* installed
*
@@ -36,10 +39,10 @@
*/
#include <server.h>
#include <casAsyncIOIIL.h> // casAsyncIOI in line func
#include <casChannelIIL.h> // casChannelI in line func
#include <casCtxIL.h> // casCtx in line func
#include "server.h"
#include "casAsyncIOIIL.h" // casAsyncIOI in line func
#include "casChannelIIL.h" // casChannelI in line func
#include "casCtxIL.h" // casCtx in line func
//
// casAsyncWtIOI::casAsyncWtIOI()
+12 -1
View File
@@ -29,11 +29,14 @@
*
* History
* $Log$
* Revision 1.1 1996/11/02 01:01:05 jhill
* installed
*
*
*
*/
#include <casdef.h>
#include "casdef.h"
//
// This must be virtual so that derived destructor will
@@ -59,3 +62,11 @@ casAsyncPVExistIO::~casAsyncPVExistIO()
{
}
//
// This must be virtual so that derived destructor will
// be run indirectly. Therefore it cannot be inline.
//
casAsyncPVCreateIO::~casAsyncPVCreateIO()
{
}
+5 -2
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.2 1996/11/02 00:54:01 jhill
* many improvements
*
* Revision 1.1.1.1 1996/06/20 00:28:15 jhill
* ca server installation
*
@@ -36,8 +39,8 @@
*/
#include <server.h>
#include <casEventSysIL.h> // casEventSys in line func
#include "server.h"
#include "casEventSysIL.h" // casEventSys in line func
//
// casChanDelEv()
+14 -27
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.4 1996/09/04 20:17:34 jhill
* use ptr not ref to satisfy MSVISC++
*
* Revision 1.3 1996/08/13 22:52:31 jhill
* changes for MVC++
*
@@ -42,9 +45,9 @@
*/
#include <server.h>
#include <casChannelIIL.h> // casChannelI inline func
#include <casPVListChanIL.h> // casPVListChan inline func
#include "server.h"
#include "casChannelIIL.h" // casChannelI inline func
#include "casPVListChanIL.h" // casPVListChan inline func
//
// casChannel::casChannel()
@@ -73,14 +76,6 @@ casPV *casChannel::getPV()
}
}
//
// casChannel::postEvent()
//
void casChannel::postEvent (const casEventMask &select, gdd &event)
{
this->casChannelI::postEvent(select, event);
}
//
// casChannel::setOwner()
//
@@ -92,21 +87,6 @@ void casChannel::setOwner(const char * const /* pUserName */,
//
}
//
// casChannel::interestRegister()
//
caStatus casChannel::interestRegister()
{
return S_casApp_success;
}
//
// casChannel::interestDelete()
//
void casChannel::interestDelete()
{
}
//
// casChannel::readAccess()
//
@@ -135,7 +115,7 @@ aitBool casChannel::confirmationRequested() const
//
// casChannel::show()
//
void casChannel::show(unsigned level)
void casChannel::show(unsigned level) const
{
if (level>2u) {
printf("casChannel: read access = %d\n",
@@ -155,4 +135,11 @@ void casChannel::destroy()
delete this;
}
//
// casChannel::postAccessRightsEvent()
//
void casChannel::postAccessRightsEvent()
{
this->casChannelI::postAccessRightsEvent();
}
+99 -52
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.3 1996/11/02 00:54:02 jhill
* many improvements
*
* Revision 1.2 1996/09/04 20:18:03 jhill
* init new chan member
*
@@ -38,11 +41,11 @@
*
*/
#include <server.h>
#include <casEventSysIL.h> // casEventSys inline func
#include <casAsyncIOIIL.h> // casAsyncIOI inline func
#include <casPVIIL.h> // casPVI inline func
#include <casCtxIL.h> // casCtx inline func
#include "server.h"
#include "casEventSysIL.h" // casEventSys inline func
#include "casAsyncIOIIL.h" // casAsyncIOI inline func
#include "casPVIIL.h" // casPVI inline func
#include "casCtxIL.h" // casCtx inline func
//
@@ -52,7 +55,9 @@ casChannelI::casChannelI(const casCtx &ctx, casChannel &chanAdapter) :
client(* (casStrmClient *) ctx.getClient()),
pv(*ctx.getPV()),
chan(chanAdapter),
cid(ctx.getMsg()->m_cid)
cid(ctx.getMsg()->m_cid),
clientDestroyPending(FALSE),
accessRightsEvPending(FALSE)
{
assert(&this->client);
assert(&this->pv);
@@ -67,8 +72,6 @@ casChannelI::casChannelI(const casCtx &ctx, casChannel &chanAdapter) :
//
casChannelI::~casChannelI()
{
casAsyncIOI *pIO;
casMonitor *pMonitor;
casChanDelEv *pCDEV;
caStatus status;
@@ -77,31 +80,34 @@ casChannelI::~casChannelI()
//
// cancel any pending asynchronous IO
//
tsDLFwdIter<casAsyncIOI> iterIO(this->ioInProgList);
pIO = iterIO.next();
while (pIO) {
casAsyncIOI *pNextIO;
tsDLIterBD<casAsyncIOI> iterAIO(this->ioInProgList.first());
const tsDLIterBD<casAsyncIOI> eolAIO;
tsDLIterBD<casAsyncIOI> tmpAIO;
while ( iterAIO!=eolAIO ) {
//
// destructor removes from this list
//
pNextIO = iterIO.next();
pIO->destroy();
pIO = pNextIO;
tmpAIO = iterAIO;
++tmpAIO;
iterAIO->destroy();
iterAIO = tmpAIO;
}
//
// cancel the monitors
//
tsDLFwdIter<casMonitor> iterMon(this->monitorList);
pMonitor = iterMon.next();
while (pMonitor) {
casMonitor *pNextMon;
tsDLIterBD<casMonitor> iterMon(this->monitorList.first());
const tsDLIterBD<casMonitor> eolMon;
tsDLIterBD<casMonitor> tmpMon;
while ( iterMon!=eolMon ) {
casMonitor *pMonitor;
//
// destructor removes from this list
//
pNextMon = iterMon.next();
pMonitor = tmpMon = iterMon;
++tmpMon;
delete pMonitor;
pMonitor = pNextMon;
iterMon = tmpMon;
}
this->client.removeChannel(*this);
@@ -112,9 +118,9 @@ casChannelI::~casChannelI()
this->pv.deleteSignal();
//
// if its an old client and there is no memory
// we disconnect them here (and delete the client)
// - therefore dont use member client after this point
// If we are not in the process of deleting the client
// then inform the client that we have deleted its
// channel
//
if (!this->clientDestroyPending) {
pCDEV = new casChanDelEv(this->getCID());
@@ -124,10 +130,19 @@ casChannelI::~casChannelI()
else {
status = this->client.disconnectChan (this->getCID());
if (status) {
errMessage(status, NULL);
if (status == S_cas_disconnect) {
this->client.destroy();
}
//
// At this point there is no space in pool
// for a tiny object and there is also
// no outgoing buffer space in which to place
// a message in which we inform the client
// that his channel was deleted.
//
// => disconnect this client via the event
// queue because deleting the client here
// will result in bugs because no doubt this
// could be called by a client member function.
//
this->client.setDestroyPending();
}
}
}
@@ -141,23 +156,22 @@ casChannelI::~casChannelI()
//
void casChannelI::clearOutstandingReads()
{
casAsyncIOI *pIO;
this->lock();
//
// cancel any pending asynchronous IO
//
tsDLFwdIter<casAsyncIOI> iterIO(this->ioInProgList);
pIO = iterIO.next();
while (pIO) {
casAsyncIOI *pNextIO;
tsDLIterBD<casAsyncIOI> iterIO(this->ioInProgList.first());
tsDLIterBD<casAsyncIOI> eolIO;
tsDLIterBD<casAsyncIOI> tmp;
while (iterIO!=eolIO) {
//
// destructor removes from this list
//
pNextIO = iterIO.next();
pIO->destroyIfReadOP();
pIO = pNextIO;
tmp = iterIO;
++tmp;
iterIO->destroyIfReadOP();
iterIO = tmp;
}
this->unlock();
@@ -169,12 +183,12 @@ void casChannelI::clearOutstandingReads()
//
void casChannelI::postAllModifiedEvents()
{
casMonitor *pMon;
this->lock();
tsDLFwdIter<casMonitor> iter(this->monitorList);
while ( (pMon=iter.next()) ) {
pMon->postIfModified();
tsDLIterBD<casMonitor> iter(this->monitorList.first());
tsDLIterBD<casMonitor> eol;
while ( iter!=eol ) {
iter->postIfModified();
++iter;
}
this->unlock();
}
@@ -183,21 +197,19 @@ void casChannelI::postAllModifiedEvents()
//
// casChannelI::show()
//
void casChannelI::show(unsigned level)
void casChannelI::show(unsigned level) const
{
casMonitor *pMon;
this->lock();
tsDLFwdIter<casMonitor> iter(this->monitorList);
if ( (pMon = iter.next()) ) {
tsDLIterBD<casMonitor> iter(this->monitorList.first());
tsDLIterBD<casMonitor> eol;
if ( iter!=eol ) {
printf("List of CA events (monitors) for \"%s\".\n",
this->pv.resourceName());
this->pv->getName());
}
while (pMon) {
pMon->show(level);
pMon = iter.next();
while ( iter!=eol ) {
iter->show(level);
++iter;
}
(*this)->show(level);
@@ -205,3 +217,38 @@ void casChannelI::show(unsigned level)
this->unlock();
}
//
// casChannelI::cbFunc()
//
// access rights event call back
//
caStatus casChannelI::cbFunc(casEventSys &)
{
caStatus stat;
stat = this->client.accessRightsResponse(this);
if (stat==S_cas_success) {
this->accessRightsEvPending = FALSE;
}
return stat;
}
//
// casChannelI::destroy()
//
// call the destroy in the server tool
//
void casChannelI::destroy()
{
this->chan.destroy();
}
//
// casChannelI::resourceType()
//
casResType casChannelI::resourceType() const
{
return casChanT;
}
+31 -16
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.5 1996/11/02 00:54:03 jhill
* many improvements
*
* Revision 1.4 1996/09/16 18:23:59 jhill
* vxWorks port changes
*
@@ -48,12 +51,13 @@
#ifndef casChannelIIL_h
#define casChannelIIL_h
#include <casCoreClientIL.h>
#include "casCoreClientIL.h"
#include "casEventSysIL.h"
//
// casChannelI::operator -> ()
//
inline casChannel * casChannelI::operator -> ()
inline casChannel * casChannelI::operator -> () const
{
return &this->chan;
}
@@ -61,7 +65,7 @@ inline casChannel * casChannelI::operator -> ()
//
// casChannelI::lock()
//
inline void casChannelI::lock()
inline void casChannelI::lock() const
{
this->client.osiLock();
}
@@ -69,7 +73,7 @@ inline void casChannelI::lock()
//
// casChannelI::unlock()
//
inline void casChannelI::unlock()
inline void casChannelI::unlock() const
{
this->client.osiUnlock();
}
@@ -79,12 +83,12 @@ inline void casChannelI::unlock()
//
inline void casChannelI::postEvent(const casEventMask &select, gdd &event)
{
casMonitor *pMon;
this->lock();
tsDLFwdIter<casMonitor> iter(this->monitorList);
while ( (pMon = iter.next()) ) {
pMon->post(select, event);
tsDLIterBD<casMonitor> iter(this->monitorList.first());
const tsDLIterBD<casMonitor> eol;
while ( iter!=eol ) {
iter->post(select, event);
++iter;
}
this->unlock();
}
@@ -124,14 +128,15 @@ inline void casChannelI::addMonitor(casMonitor &mon)
//
inline casMonitor *casChannelI::findMonitor(const caResId clientIdIn)
{
casMonitor *pMon;
this->lock();
tsDLFwdIter<casMonitor> iter(this->monitorList);
while ( (pMon = iter.next()) ) {
if ( clientIdIn == pMon->getClientId()) {
tsDLIterBD<casMonitor> iter(this->monitorList.first());
tsDLIterBD<casMonitor> eol;
while ( iter!=eol ) {
if ( clientIdIn == iter->getClientId()) {
casMonitor *pMon = iter;
return pMon;
}
++iter;
}
this->unlock();
return NULL;
@@ -146,7 +151,7 @@ inline void casChannelI::clientDestroy()
(*this)->destroy();
}
#include <casPVIIL.h>
#include "casPVIIL.h"
//
// functions that use casPVIIL.h below here
@@ -158,7 +163,6 @@ inline void casChannelI::clientDestroy()
inline void casChannelI::installAsyncIO(casAsyncIOI &io)
{
this->lock();
this->pv.registerIO();
this->ioInProgList.add(io);
this->unlock();
}
@@ -183,6 +187,17 @@ inline const caResId casChannelI::getSID()
return this->uintId::getId();
}
//
// casChannelI::postAccessRightsEvent()
//
inline void casChannelI::postAccessRightsEvent()
{
if (!this->accessRightsEvPending) {
this->accessRightsEvPending = TRUE;
this->client.addToEventQueue(*this);
}
}
#endif // casChannelIIL_h
+39 -33
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.6 1996/12/11 00:58:35 jhill
* better diagnostic
*
* Revision 1.5 1996/11/02 00:54:04 jhill
* many improvements
*
@@ -47,13 +50,15 @@
*
*/
#include <stdarg.h>
#include <server.h>
#include <casClientIL.h> // inline func for casClient
#include <casEventSysIL.h> // inline func for casEventSys
#include <casCtxIL.h> // inline func for casCtx
#include <inBufIL.h> // inline func for inBuf
#include <db_access.h>
#include "server.h"
#include "casClientIL.h" // inline func for casClient
#include "casEventSysIL.h" // inline func for casEventSys
#include "casCtxIL.h" // inline func for casCtx
#include "inBufIL.h" // inline func for inBuf
#include "casPVIIL.h" // inline func for casPVI
#include "db_access.h"
VERSIONID(camsgtaskc,"%W% %G%")
@@ -124,59 +129,60 @@ void casClient::loadProtoJumpTable()
//
// Request Protocol Jump Table
// (use of & here is more portable)
//
casClient::msgHandlers[CA_PROTO_NOOP] =
casClient::noopAction;
&casClient::noopAction;
casClient::msgHandlers[CA_PROTO_EVENT_ADD] =
casClient::eventAddAction;
&casClient::eventAddAction;
casClient::msgHandlers[CA_PROTO_EVENT_CANCEL] =
casClient::eventCancelAction;
&casClient::eventCancelAction;
casClient::msgHandlers[CA_PROTO_READ] =
casClient::readAction;
&casClient::readAction;
casClient::msgHandlers[CA_PROTO_WRITE] =
casClient::writeAction;
&casClient::writeAction;
casClient::msgHandlers[CA_PROTO_SNAPSHOT] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_SEARCH] =
casClient::searchAction;
&casClient::searchAction;
casClient::msgHandlers[CA_PROTO_BUILD] =
casClient::ignoreMsgAction;
&casClient::ignoreMsgAction;
casClient::msgHandlers[CA_PROTO_EVENTS_OFF] =
casClient::eventsOffAction;
&casClient::eventsOffAction;
casClient::msgHandlers[CA_PROTO_EVENTS_ON] =
casClient::eventsOnAction;
&casClient::eventsOnAction;
casClient::msgHandlers[CA_PROTO_READ_SYNC] =
casClient::readSyncAction;
&casClient::readSyncAction;
casClient::msgHandlers[CA_PROTO_ERROR] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_CLEAR_CHANNEL] =
casClient::clearChannelAction;
&casClient::clearChannelAction;
casClient::msgHandlers[CA_PROTO_RSRV_IS_UP] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_NOT_FOUND] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_READ_NOTIFY] =
casClient::readNotifyAction;
&casClient::readNotifyAction;
casClient::msgHandlers[CA_PROTO_READ_BUILD] =
casClient::ignoreMsgAction;
&casClient::ignoreMsgAction;
casClient::msgHandlers[REPEATER_CONFIRM] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_CLAIM_CIU] =
casClient::claimChannelAction;
&casClient::claimChannelAction;
casClient::msgHandlers[CA_PROTO_WRITE_NOTIFY] =
casClient::writeNotifyAction;
&casClient::writeNotifyAction;
casClient::msgHandlers[CA_PROTO_CLIENT_NAME] =
casClient::clientNameAction;
&casClient::clientNameAction;
casClient::msgHandlers[CA_PROTO_HOST_NAME] =
casClient::hostNameAction;
&casClient::hostNameAction;
casClient::msgHandlers[CA_PROTO_ACCESS_RIGHTS] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_ECHO] =
casClient::echoAction;
&casClient::echoAction;
casClient::msgHandlers[REPEATER_REGISTER] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_CLAIM_CIU_FAILED] =
casClient::uknownMessageAction;
&casClient::uknownMessageAction;
casClient::msgHandlersInit = TRUE;
}
@@ -552,7 +558,7 @@ void casClient::dumpMsg(const caHdr *mp, const void *dp)
pciu = this->resIdToChannel(mp->m_cid);
if (pciu) {
strncpy(pPVName, pciu->getPVI().resourceName(), sizeof(pPVName));
strncpy(pPVName, pciu->getPVI()->getName(), sizeof(pPVName));
if (&pciu->getClient()!=this) {
strncat(pPVName, "!Bad Client!", sizeof(pPVName));
}
+16 -6
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.3 1996/12/11 00:59:37 jhill
* added bad chan attachment detection
*
* Revision 1.2 1996/11/02 00:54:06 jhill
* many improvements
*
@@ -42,8 +45,8 @@
#ifndef casClientIL_h
#define casClientIL_h
#include <caServerIIL.h> // caServerI inline func
#include <casCtxIL.h> // caServerI inline func
#include "caServerIIL.h" // caServerI inline func
#include "casCtxIL.h" // caServerI inline func
//
// find the channel associated with a resource id
@@ -56,6 +59,15 @@ inline casChannelI *casClient::resIdToChannel(const caResId &id)
// look up the id in a hash table
//
pChan = this->ctx.getServer()->resIdToChannel(id);
//
// update the context
//
this->ctx.setChannel(pChan);
if (!pChan) {
return NULL;
}
//
// If the channel isnt attached to this client then
// something has gone wrong
@@ -63,13 +75,11 @@ inline casChannelI *casClient::resIdToChannel(const caResId &id)
if (&pChan->getClient()!=this) {
return NULL;
}
//
// update the context
//
this->ctx.setChannel(pChan);
if (pChan) {
this->ctx.setPV(&pChan->getPVI());
}
this->ctx.setPV(&pChan->getPVI());
return pChan;
}
+24 -2
View File
@@ -29,13 +29,16 @@
*
* History
* $Log$
* Revision 1.1.1.1 1996/06/20 00:28:15 jhill
* ca server installation
*
*
*/
#include <server.h>
#include "server.h"
#include <casChannelIIL.h>
#include "casChannelIIL.h"
//
@@ -81,3 +84,22 @@ caStatus casClientMon::callBack(gdd &value)
return status;
}
//
// casClientMon::destroy()
//
// this class is always created inside the server
// lib with new
//
void casClientMon::destroy()
{
delete this;
}
//
// casClientMon::resourceType()
//
casResType casClientMon::resourceType() const
{
return casClientMonT;
}
+24 -18
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.4 1996/11/02 00:54:07 jhill
* many improvements
*
* Revision 1.3 1996/09/16 18:23:59 jhill
* vxWorks port changes
*
@@ -42,13 +45,13 @@
*/
#include <server.h>
#include <caServerIIL.h> // caServerI in line func
#include <casAsyncIOIIL.h> // casAsyncIOI in line func
#include <casEventSysIL.h> // casEventSys in line func
#include <casCtxIL.h> // casCtx in line func
#include <inBufIL.h> // inBuf in line func
#include <outBufIL.h> // outBuf in line func
#include "server.h"
#include "caServerIIL.h" // caServerI in line func
#include "casAsyncIOIIL.h" // casAsyncIOI in line func
#include "casEventSysIL.h" // casEventSys in line func
#include "casCtxIL.h" // casCtx in line func
#include "inBufIL.h" // inBuf in line func
#include "outBufIL.h" // outBuf in line func
//
// casCoreClient::init()
@@ -124,27 +127,26 @@ void casCoreClient::loadProtoJumpTable()
//
casCoreClient::~casCoreClient()
{
casAsyncIOI *pCurIO;
if (this->ctx.getServer()->getDebugLevel()>0u) {
ca_printf ("CAS: Connection Terminated\n");
}
this->osiLock();
tsDLFwdIter<casAsyncIOI> iterIO(this->ioInProgList);
tsDLIterBD<casAsyncIOI> iterIO(this->ioInProgList.first());
tsDLIterBD<casAsyncIOI> tmpIO;
tsDLIterBD<casAsyncIOI> eolIO;
//
// cancel any pending asynchronous IO
//
pCurIO = iterIO.next();
while (pCurIO) {
casAsyncIOI *pNextIO;
while (iterIO!=eolIO) {
//
// destructor removes from this list
//
pNextIO = iterIO.next();
pCurIO->destroy();
pCurIO = pNextIO;
tmpIO = iterIO;
++tmpIO;
iterIO->destroy();
iterIO = tmpIO;
}
this->osiUnlock();
@@ -180,11 +182,11 @@ void casCoreClient::show (unsigned level) const
// asynchronous completion
//
caStatus casCoreClient::asyncSearchResponse(casDGIntfIO &,
const caAddr &, const caHdr &, const pvExistReturn &)
const caAddr &, const caHdr &, const pvExistReturn)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::createChanResponse(const caHdr &, const pvExistReturn &)
caStatus casCoreClient::createChanResponse(const caHdr &, const pvCreateReturn &)
{
return S_casApp_noSupport;
}
@@ -213,6 +215,10 @@ caStatus casCoreClient::monitorResponse(casChannelI *, const caHdr &,
{
return S_casApp_noSupport;
}
caStatus casCoreClient::accessRightsResponse(casChannelI *)
{
return S_casApp_noSupport;
}
//
// casCoreClient::installChannel()
+4
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.1 1996/11/02 01:01:06 jhill
* installed
*
*
*/
@@ -74,6 +77,7 @@ inline void casCoreClient::removeAsyncIO(casAsyncIOI &ioIn)
{
this->osiLock();
this->ioInProgList.remove(ioIn);
this->ctx.getServer()->ioBlockedList::signal();
this->osiUnlock();
}
+9 -9
View File
@@ -1,19 +1,19 @@
#include <server.h>
#include "server.h"
//
// casCtx::show()
//
void casCtx::show (unsigned level) const
{
printf ("casCtx at %x\n", (unsigned) this);
if (level >= 1u) {
printf ("\tpMsg = %x\n", (unsigned) &this->msg);
printf ("\tpData = %x\n", (unsigned) pData);
printf ("\tpCAS = %x\n", (unsigned) pCAS);
printf ("\tpClient = %x\n", (unsigned) pClient);
printf ("\tpChannel = %x\n", (unsigned) pChannel);
printf ("\tpPV = %x\n", (unsigned) pPV);
printf ("casCtx at %lx\n", (unsigned long) this);
if (level >= 3u) {
printf ("\tpMsg = %lx\n", (unsigned long) &this->msg);
printf ("\tpData = %lx\n", (unsigned long) pData);
printf ("\tpCAS = %lx\n", (unsigned long) pCAS);
printf ("\tpClient = %lx\n", (unsigned long) pClient);
printf ("\tpChannel = %lx\n", (unsigned long) pChannel);
printf ("\tpPV = %lx\n", (unsigned long) pPV);
}
}
+1 -1
View File
@@ -7,7 +7,7 @@
//
inline casCtx::casCtx() :
pData(NULL), pCAS(NULL), pClient(NULL),
pChannel(NULL), pPV(NULL)
pChannel(NULL), pPV(NULL), nAsyncIO(0u)
{
memset(&this->msg, 0, sizeof(this->msg));
}
+71 -51
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.8 1997/01/10 21:17:53 jhill
* code around gnu g++ inline bug when -O isnt used
*
* Revision 1.7 1996/11/02 00:54:08 jhill
* many improvements
*
@@ -53,14 +56,14 @@
*
*/
#include <server.h>
#include <caServerIIL.h> // caServerI inline func
#include <casClientIL.h> // casClient inline func
#include <dgOutBufIL.h> // dgOutBuf inline func
#include <dgInBufIL.h> // dgInBuf inline func
#include <casCtxIL.h> // casCtx inline func
#include <casCoreClientIL.h> // casCoreClient inline func
#include <gddApps.h>
#include "server.h"
#include "caServerIIL.h" // caServerI inline func
#include "casClientIL.h" // casClient inline func
#include "dgOutBufIL.h" // dgOutBuf inline func
#include "dgInBufIL.h" // dgInBuf inline func
#include "casCtxIL.h" // casCtx inline func
#include "casCoreClientIL.h" // casCoreClient inline func
#include "gddApps.h"
//
// CA Server Datagram (DG) Client
@@ -124,32 +127,68 @@ caStatus casDGClient::searchAction()
void *dp = this->ctx.getData();
const char *pChanName = (const char *) dp;
caStatus status;
pvExistReturn pver;
if (this->ctx.getServer()->getDebugLevel()>2u) {
printf("client is searching for \"%s\"\n", pChanName);
}
//
// verify that we have sufficent memory for a PV and a
// monitor prior to calling PV exist test so that when
// the server runs out of memory we dont reply to
// search requests, and therefore dont thrash through
// caServer::pvExistTest() and casCreatePV::createPV()
//
#ifdef vxWorks
# error code needs to be implemented here when we port
# error to memory limited environment
#endif
//
// ask the server tool if this PV exists
//
pvExistReturn retVal =
this->asyncIOFlag = 0u;
casPVExistReturn retVal =
this->ctx.getServer()->pvExistTest(this->ctx, pChanName);
if (retVal.getStatus() == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (retVal.getStatus()==S_cas_ioBlocked) {
//
// If too many exist test IO operations are in progress
// then we will just ignore this request (and wait for
// the client to try again later)
//
status = S_cas_success;
}
else {
status = this->searchResponse(*mp, retVal);
if (retVal.getStatus()!=S_cas_success) {
return retVal.getStatus();
}
return S_cas_success;
//
// prevent problems when they initiate
// async IO but dont return status
// indicating so (and vise versa)
//
pver = retVal.getAppStat();
if (this->asyncIOFlag) {
pver = pverAsyncCompletion;
}
else if (pver == pverAsyncCompletion) {
pver = pverDoesNotExistHere;
errMessage(S_cas_badParameter,
"- expected asynch IO creation from caServer::pvExistTest()");
}
//
// otherwise we assume sync IO operation was initiated
//
switch (pver) {
case pverDoesNotExistHere:
case pverAsyncCompletion:
status = S_cas_success;
break;
case pverExistsHere:
status = this->searchResponse(*mp, retVal.getAppStat());
break;
default:
status = S_cas_badParameter;
break;
}
return status;
}
@@ -157,18 +196,22 @@ caStatus casDGClient::searchAction()
// caStatus casDGClient::searchResponse()
//
caStatus casDGClient::searchResponse(const caHdr &msg,
const pvExistReturn &retVal)
const pvExistReturn retVal)
{
caStatus status;
caHdr *search_reply;
unsigned short *pMinorVersion;
this->ctx.getServer()->pvExistTestCompletion();
//
// normal search failure is ignored
//
if (retVal.getStatus()==S_casApp_pvNotFound) {
if (retVal==pverDoesNotExistHere) {
return S_cas_success;
}
if (retVal!=pverExistsHere) {
fprintf(stderr,
"async exist completion with invalid return code \"pverAsynchCompletion\"?\n");
return S_cas_success;
}
@@ -199,29 +242,6 @@ caStatus casDGClient::searchResponse(const caHdr &msg,
return status;
}
//
// check for bad parameters
//
if (retVal.getStatus()) {
errMessage(retVal.getStatus(),NULL);
return S_cas_success;
}
if (retVal.getString()) {
if (retVal.getString()[0]=='\0') {
errMessage(S_cas_badParameter,
"PV name descr is empty");
return S_cas_success;
}
if (this->ctx.getServer()->getDebugLevel()>2u) {
printf("Search request matched for PV=\"%s\"\n",
retVal.getString());
}
}
else {
errMessage(S_cas_badParameter, "PV name descr is nill");
return S_cas_success;
}
/*
* obtain space for the reply message
*/
@@ -381,7 +401,7 @@ void casDGClient::processDG(casDGIntfIO &inMsgIO, casDGIntfIO &outMsgIO)
// casDGClient::asyncSearchResp()
//
caStatus casDGClient::asyncSearchResponse(casDGIntfIO &outMsgIO, const caAddr &outAddr,
const caHdr &msg, const pvExistReturn &retVal)
const caHdr &msg, const pvExistReturn retVal)
{
caStatus stat;
+22 -6
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.5 1996/12/11 01:01:56 jhill
* casEventMaskEntry constr does res tbl add
*
* Revision 1.4 1996/12/06 22:32:11 jhill
* force virtual destructor
*
@@ -45,11 +48,11 @@
*/
#include <epicsAssert.h>
#include "epicsAssert.h"
#include <stdio.h>
#include <limits.h>
#include <server.h>
#include "server.h"
#ifdef TEST
main ()
@@ -132,8 +135,12 @@ inline casEventMask casEventRegistry::maskAllocator()
//
casEventMask casEventRegistry::registerEvent(const char *pName)
{
//
// NOTE: pName outlives id here
// (so the refString option is ok)
//
stringId id (pName, stringId::refString);
casEventMaskEntry *pEntry;
stringId id (pName);
casEventMask mask;
if (!this->hasBeenInitialized) {
@@ -171,7 +178,7 @@ casEventMask casEventRegistry::registerEvent(const char *pName)
//
// casEventMask::show()
//
void casEventMask::show(unsigned level)
void casEventMask::show(unsigned level) const
{
if (level>0u) {
printf ("casEventMask = %x\n", this->mask);
@@ -186,7 +193,7 @@ casEventMask::casEventMask (casEventRegistry &reg, const char *pName)
//
// casEventRegistry::show()
//
void casEventRegistry::show(unsigned level)
void casEventRegistry::show(unsigned level) const
{
if (!this->hasBeenInitialized) {
printf ("casEventRegistry: not initialized\n");
@@ -209,6 +216,7 @@ casEventMaskEntry::casEventMaskEntry(
{
int stat;
assert(this->resourceName()!=NULL);
stat = this->reg.add(*this);
assert(stat==0);
}
@@ -226,10 +234,18 @@ casEventMaskEntry::~casEventMaskEntry()
this->reg.remove (*this);
}
//
// casEventMaskEntry::destroy()
//
void casEventMaskEntry::destroy()
{
delete this;
}
//
// casEventMaskEntry::show()
//
void casEventMaskEntry::show (unsigned level)
void casEventMaskEntry::show (unsigned level) const
{
this->casEventMask::show(level);
this->stringId::show(level);
+4 -1
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.4 1996/12/11 01:02:35 jhill
* removed casEventMaskEntry def
*
* Revision 1.3 1996/12/06 22:32:10 jhill
* force virtual destructor
*
@@ -72,7 +75,7 @@ public:
this->clear();
}
void show (unsigned level);
void show (unsigned level) const;
int eventsSelected()
{
+18 -2
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.4 1996/11/02 00:54:12 jhill
* many improvements
*
* Revision 1.3 1996/09/16 18:24:01 jhill
* vxWorks port changes
*
@@ -49,8 +52,8 @@
/*
* EPICS
*/
#include <server.h>
#include <casEventSysIL.h> // casMonitor inline func
#include "server.h"
#include "casEventSysIL.h" // casMonitor inline func
//
// casEventSys::show()
@@ -167,6 +170,19 @@ casProcCond casEventSys::process()
this->mutex.osiUnlock();
//
// allows the derived class to be informed that it
// needs to delete itself via the event system
//
// this gets the server out of nasty situations
// where the client needs to be deleted but
// the caller may be using the client's "this"
// pointer.
//
if (this->destroyPending) {
cond = casProcDisconnect;
}
return cond;
}
+17 -1
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.3 1996/11/02 00:54:13 jhill
* many improvements
*
* Revision 1.2 1996/09/16 18:24:02 jhill
* vxWorks port changes
*
@@ -54,7 +57,8 @@ inline casEventSys::casEventSys (casCoreClient &coreClientIn) :
coreClient(coreClientIn),
numEventBlocks(0u),
maxLogEntries(individualEventEntries),
eventsOff(aitFalse)
eventsOff(aitFalse),
destroyPending(aitFalse)
{
}
@@ -115,6 +119,18 @@ void casEventSys::setEventsOff()
this->eventsOff = aitTrue;
}
//
// casEventSys::setDestroyPending()
//
void casEventSys::setDestroyPending()
{
this->destroyPending = aitTrue;
//
// wakes up the event queue consumer
//
this->coreClient.eventSignal();
}
//
// casEventSys::insertEventQueue()
//
+75 -75
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* 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()
*
@@ -96,7 +99,8 @@ class casRes : public uintRes<casRes>
public:
virtual ~casRes();
virtual casResType resourceType() const = 0;
virtual void show (unsigned level) = 0;
virtual void show (unsigned level) const = 0;
virtual void destroy() = 0;
private:
};
@@ -136,7 +140,7 @@ class casMonitor;
class casMonEvent : public casEvent {
public:
//
// only used when this part of another structure
// only used when this is part of another structure
// (and we need to postpone true construction)
//
inline casMonEvent ();
@@ -145,8 +149,9 @@ public:
//
// ~casMonEvent ()
// (not inline because this is virtual in the base class)
//
inline ~casMonEvent ();
~casMonEvent ();
caStatus cbFunc(casEventSys &);
@@ -180,7 +185,7 @@ public:
void post(const casEventMask &select, gdd &value);
virtual void show (unsigned level);
virtual void show (unsigned level) const;
virtual caStatus callBack(gdd &value)=0;
caResId getClientId() const
@@ -260,6 +265,7 @@ class casAsyncIO;
class casAsyncReadIO;
class casAsyncWriteIO;
class casAsyncPVExistIO;
class casAsyncPVCreateIO;
class casAsyncIOI : public casEvent, public tsDLNode<casAsyncIOI> {
public:
@@ -279,7 +285,7 @@ public:
void destroyIfReadOP();
caServer *getCAS();
caServer *getCAS() const;
inline void destroy();
@@ -294,6 +300,7 @@ private:
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)
@@ -411,7 +418,7 @@ public:
//
// place notification of IO completion on the event queue
//
caStatus postIOCompletion(const pvExistReturn &retVal);
caStatus postIOCompletion(const pvExistReturn retVal);
caStatus cbFuncAsyncIO();
casAsyncIO &getAsyncIO();
@@ -422,16 +429,43 @@ private:
const casOpaqueAddr 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;
class casChannelI : public tsDLNode<casChannelI>, public casRes {
//
// 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();
void show (unsigned level);
casCoreClient &getClient() const
{
return this->client;
@@ -475,20 +509,27 @@ public:
inline void postEvent (const casEventMask &select, gdd &event);
casResType resourceType() const
{
return casChanT;
}
virtual casResType resourceType() const;
inline void lock();
inline void unlock();
virtual void show (unsigned level) const;
virtual void destroy();
inline void lock() const;
inline void unlock() const;
inline void clientDestroy();
inline casChannel * operator -> ();
inline casChannel * operator -> () const;
void clearOutstandingReads();
//
// access rights event call back
//
caStatus cbFunc(casEventSys &);
inline void postAccessRightsEvent();
protected:
tsDLList<casMonitor> monitorList;
tsDLList<casAsyncIOI> ioInProgList;
@@ -497,6 +538,7 @@ protected:
casChannel &chan;
caResId const cid; // client id
unsigned clientDestroyPending:1;
unsigned accessRightsEvPending:1;
};
//
@@ -514,23 +556,22 @@ class casCtx;
class casChannel;
class casPV;
//
// casPVI
//
class casPVI :
public stringId, // server PV name table installation
public tsSLNode<casPVI>, // server PV name table installation
public tsSLNode<casPVI>, // server resource table installation
public casRes, // server resource table installation
public ioBlockedList // list of clients io blocked on this pv
{
public:
//
// The PV name here must be the canonical and unique name
// for the PV in this system
//
casPVI (caServerI &cas, const char * const pNameIn, casPV &pvAdapter);
casPVI (caServer &cas, casPV &pvAdapter);
virtual ~casPVI();
//
// for use by the server library
//
inline caServerI &getCAS();
inline caServerI &getCAS() const;
//
// CA only does 1D arrays for now (and the new server
@@ -547,7 +588,6 @@ public:
//
// only for use by casAsyncIOI
//
inline void registerIO();
inline void unregisterIO();
//
@@ -565,22 +605,25 @@ public:
//
inline void deleteSignal();
void show(unsigned level);
inline void postEvent (const casEventMask &select, gdd &event);
inline casPV *interfaceObjectPointer() const;
caServer *getExtServer();
caServer *getExtServer() const;
//
// bestDBRType()
//
inline caStatus bestDBRType (unsigned &dbrType);
inline aitBool okToBeginNewIO() const;
inline casPV * operator -> () const;
virtual casResType resourceType() const;
virtual void show(unsigned level) const;
virtual void destroy();
private:
tsDLList<casPVListChan> chanList;
caServerI &cas;
@@ -589,50 +632,7 @@ private:
unsigned nIOAttached;
unsigned destroyInProgress:1;
inline void lock();
inline void unlock();
inline void lock() const;
inline void unlock() const;
};
//
// inline functions associated with the return arg from
// caServer::pvExistTest()
//
inline pvExistReturn::pvExistReturn(caStatus status,
char* pCanonicalNameStr) :
stat(status), str(pCanonicalNameStr)
{
}
inline pvExistReturn::pvExistReturn(caStatus status,
const char* pCanonicalNameStr) :
stat(status), str(pCanonicalNameStr)
{
}
inline pvExistReturn::pvExistReturn(pvExistReturn &init) :
stat(init.stat), str(init.str)
{
}
inline pvExistReturn::pvExistReturn(const pvExistReturn &init) :
stat(init.stat), str(init.str)
{
}
inline const caStatus pvExistReturn::getStatus() const
{
return this->stat;
}
inline const char* pvExistReturn::getString() const
{
return str.string();
}
inline pvExistReturn& pvExistReturn::operator=(pvExistReturn &rhs)
{
this->stat = rhs.stat;
this->str = rhs.str;
return *this;
}
inline pvExistReturn& pvExistReturn::operator=(const pvExistReturn &rhs)
{
this->stat = rhs.stat;
this->str = rhs.str;
return *this;
}
+15 -4
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.3 1996/11/02 00:54:16 jhill
* many improvements
*
* Revision 1.2 1996/06/26 21:18:55 jhill
* now matches gdd api revisions
*
@@ -39,10 +42,10 @@
*/
#include <server.h>
#include <casEventSysIL.h> // casEventSys in line func
#include <casMonEventIL.h> // casMonEvent in line func
#include <casCtxIL.h> // casCtx in line func
#include "server.h"
#include "casEventSysIL.h" // casEventSys in line func
#include "casMonEventIL.h" // casMonEvent in line func
#include "casCtxIL.h" // casCtx in line func
//
// casMonEvent::cbFunc()
@@ -91,4 +94,12 @@ void casMonEvent::assign (casMonitor &monitor, gdd *pValueIn)
this->id = monitor.casRes::getId();
}
//
// ~casMonEvent ()
// (this is not in line because it is virtual in the base)
//
casMonEvent::~casMonEvent ()
{
this->clear();
}
+3 -14
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.2 1996/11/02 00:54:17 jhill
* many improvements
*
* Revision 1.1.1.1 1996/06/20 00:28:16 jhill
* ca server installation
*
@@ -39,12 +42,6 @@
#ifndef casMonEventIL_h
#define casMonEventIL_h
//
// All functions here moved to casMonEvent.cc until
// I can determine what is causing them to end up
// undefined
//
//
// casMonEvent::casMonEvent()
//
@@ -109,14 +106,6 @@ inline void casMonEvent::clear()
this->id = 0u;
}
//
// ~casMonEvent ()
//
inline casMonEvent::~casMonEvent ()
{
this->clear();
}
//
// casMonEvent::getValue()
//
+11 -7
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.6 1996/11/02 00:54:18 jhill
* many improvements
*
* Revision 1.5 1996/09/16 18:24:03 jhill
* vxWorks port changes
*
@@ -48,11 +51,11 @@
*/
#include <server.h>
#include <casChannelIIL.h> // casChannelI inline func
#include <casEventSysIL.h> // casEventSys inline func
#include <casMonEventIL.h> // casMonEvent inline func
#include <casCtxIL.h> // casCtx inline func
#include "server.h"
#include "casChannelIIL.h" // casChannelI inline func
#include "casEventSysIL.h" // casEventSys inline func
#include "casMonEventIL.h" // casMonEvent inline func
#include "casCtxIL.h" // casCtx inline func
//
@@ -269,12 +272,13 @@ caStatus casMonitor::executeEvent(casMonEvent *pEV)
//
// casMonitor::show(unsigned level)
//
void casMonitor::show(unsigned level)
void casMonitor::show(unsigned level) const
{
if (level>0u) {
if (level>1u) {
printf(
"\tmonitor type=%u count=%lu client id=%u enabled=%u OVF=%u nPend=%u\n",
dbrType, nElem, clientId, enabled, ovf, nPend);
this->mask.show(level);
}
}
+4 -1
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.3 1996/11/02 00:54:19 jhill
* many improvements
*
* Revision 1.2 1996/09/16 18:24:04 jhill
* vxWorks port changes
*
@@ -41,7 +44,7 @@
#include<server.h>
#include"server.h"
class casMsgIO {
public:
+1 -1
View File
@@ -1,5 +1,5 @@
#include <casdef.h>
#include "casdef.h"
//
// this needs to be here (and not in casOpaqueAddrIL.h) if we
+10 -18
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.5 1996/12/06 22:34:22 jhill
* add maxDimension() and maxBound()
*
* Revision 1.4 1996/11/02 00:54:21 jhill
* many improvements
*
@@ -51,14 +54,13 @@
// 1) Always verify that pPVI isnt nill prior to using it
//
#include <server.h>
#include <casPVIIL.h> // casPVI inline func
#include <casCtxIL.h> // casCtx inline func
#include "server.h"
#include "casPVIIL.h" // casPVI inline func
#include "casCtxIL.h" // casCtx inline func
casPV::casPV (const casCtx &ctx, const char * const pPVName) :
casPVI (*ctx.getServer(), pPVName, *this)
casPV::casPV (caServer &casIn) :
casPVI (casIn, *this)
{
}
casPV::~casPV()
@@ -68,24 +70,14 @@ casPV::~casPV()
//
// casPV::show()
//
void casPV::show(unsigned level)
void casPV::show(unsigned level) const
{
if (level>2u) {
printf ("casPV: Max simultaneous async io = %d\n",
this->maxSimultAsyncOps());
printf ("casPV: Best external type = %d\n",
this->bestExternalType());
}
}
//
// casPV::maxSimultAsyncOps()
//
unsigned casPV::maxSimultAsyncOps() const
{
return 1u;
}
//
// casPV::interestRegister()
//
@@ -192,7 +184,7 @@ void casPV::postEvent (const casEventMask &select, gdd &event)
// for virtual casPV::destroy()
// ***************
//
caServer *casPV::getCAS()
caServer *casPV::getCAS() const
{
return this->casPVI::getExtServer();
}
+48 -20
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.7 1996/12/12 18:55:38 jhill
* fixed client initiated pv delete calls interestDelete() VF bug
*
* Revision 1.6 1996/12/06 22:35:06 jhill
* added destroyInProgress flag
*
@@ -59,18 +62,25 @@
//
// casPVI::casPVI()
//
casPVI::casPVI(caServerI &casIn, const char * const pNameIn,
casPV &pvAdapterIn) :
stringId(pNameIn),
cas(casIn),
casPVI::casPVI(caServer &casIn, casPV &pvAdapterIn) :
cas(*casIn.pCAS),
pv(pvAdapterIn),
nMonAttached(0u),
nIOAttached(0u),
destroyInProgress(FALSE)
{
//
// we would like to throw an exception for this one
// (but this is not portable)
//
assert(&this->cas);
//
// this will always be true
//
assert(&this->pv);
this->cas.installPV(*this);
this->cas.installItem(*this);
}
@@ -79,29 +89,29 @@ casPVI::casPVI(caServerI &casIn, const char * const pNameIn,
//
casPVI::~casPVI()
{
casPVListChan *pChan;
casPVListChan *pNextChan;
this->lock();
this->cas.removeItem(*this);
assert(!this->destroyInProgress);
this->destroyInProgress = TRUE;
//
// delete any attached channels
//
tsDLFwdIter<casPVListChan> iter(this->chanList);
pChan = iter.next();
while (pChan) {
tsDLIterBD<casPVListChan> iter(this->chanList.first());
const tsDLIterBD<casPVListChan> eol;
tsDLIterBD<casPVListChan> tmp;
while (iter!=eol) {
//
// deleting the channel removes it from the list
//
pNextChan = iter.next();
(*pChan)->destroy();
pChan = pNextChan;
}
this->cas.removePV(*this);
tmp = iter;
++tmp;
(*iter)->destroy();
iter = tmp;
}
this->unlock();
@@ -122,12 +132,14 @@ casPVI::~casPVI()
//
// casPVI::show()
//
void casPVI::show(unsigned level)
void casPVI::show(unsigned level) const
{
this->lock();
printf("\"%s\"\n", this->resourceName());
if (level>1u) {
printf ("CA Server PV: nChanAttached=%u nMonAttached=%u nIOAttached=%u\n",
this->chanList.count(), this->nMonAttached, this->nIOAttached);
}
(*this)->show(level);
this->unlock();
@@ -174,9 +186,25 @@ void casPVI::unregisterEvent()
// (not inline because details of caServerI must not
// leak into server tool)
//
caServer *casPVI::getExtServer()
caServer *casPVI::getExtServer() const
{
return this->cas.getAdapter();
}
//
// casPVI::destroy()
//
// call the destroy in the server tool
//
void casPVI::destroy()
{
this->pv.destroy();
}
// casPVI::resourceType()
//
casResType casPVI::resourceType() const
{
return casPVT;
}
+12 -37
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.9 1997/01/09 22:22:30 jhill
* MSC cannot use the default constructor
*
* Revision 1.8 1996/12/06 22:36:17 jhill
* use destroyInProgress flag now functional nativeCount()
*
@@ -68,7 +71,7 @@
//
// casPVI::getCAS()
//
inline caServerI &casPVI::getCAS()
inline caServerI &casPVI::getCAS() const
{
return this->cas;
}
@@ -95,7 +98,7 @@ casPV * casPVI::operator -> () const
//
// casPVI::lock()
//
inline void casPVI::lock()
inline void casPVI::lock() const
{
//
// NOTE:
@@ -109,7 +112,7 @@ inline void casPVI::lock()
//
// casPVI::unlock()
//
inline void casPVI::unlock()
inline void casPVI::unlock() const
{
this->cas.osiUnlock();
}
@@ -134,39 +137,11 @@ inline void casPVI::removeChannel(casPVListChan &chan)
this->unlock();
}
//
// okToBeginNewIO()
//
inline aitBool casPVI::okToBeginNewIO() const
{
if (this->nIOAttached >= (*this)->maxSimultAsyncOps()) {
return aitFalse;
}
else {
return aitTrue;
}
}
//
// casPVI::registerIO()
//
inline void casPVI::registerIO()
{
this->lock();
casVerify (this->nIOAttached < (*this)->maxSimultAsyncOps());
this->nIOAttached++;
this->unlock();
}
//
// casPVI::unregisterIO()
//
inline void casPVI::unregisterIO()
{
this->lock();
assert(this->nIOAttached>0u);
this->nIOAttached--;
this->unlock();
this->ioBlockedList::signal();
}
@@ -216,7 +191,7 @@ inline caStatus casPVI::bestDBRType (unsigned &dbrType)
return S_cas_success;
}
#include <casChannelIIL.h> // inline func for casChannelI
#include "casChannelIIL.h" // inline func for casChannelI
//
// functions that use casChannelIIL.h below here
@@ -227,8 +202,6 @@ inline caStatus casPVI::bestDBRType (unsigned &dbrType)
//
inline void casPVI::postEvent (const casEventMask &select, gdd &event)
{
casPVListChan *pChan;
if (this->nMonAttached==0u) {
return;
}
@@ -240,9 +213,11 @@ inline void casPVI::postEvent (const casEventMask &select, gdd &event)
event.markConstant();
this->lock();
tsDLFwdIter<casPVListChan> iter(this->chanList);
while ( (pChan = iter.next()) ) {
pChan->postEvent(select, event);
tsDLIterBD<casPVListChan> iter(this->chanList.first());
const tsDLIterBD<casPVListChan> eol;
while ( iter != eol ) {
iter->postEvent(select, event);
++iter;
}
this->unlock();
}
+5 -2
View File
@@ -30,6 +30,9 @@
*
* History
* $Log$
* Revision 1.2 1997/01/10 21:17:58 jhill
* code around gnu g++ inline bug when -O isnt used
*
* Revision 1.1 1996/12/06 22:36:18 jhill
* use destroyInProgress flag now functional nativeCount()
*
@@ -37,8 +40,8 @@
*
*/
#include <server.h>
#include <casPVIIL.h>
#include "server.h"
#include "casPVIIL.h"
//
// this needs to be here (and not in dgInBufIL.h) if we
+4 -1
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.4 1997/01/10 21:17:59 jhill
* code around gnu g++ inline bug when -O isnt used
*
* Revision 1.3 1997/01/09 22:29:17 jhill
* installed hostBuild branch
*
@@ -45,7 +48,7 @@
#ifndef casPVListChanIL_h
#define casPVListChanIL_h
#include <casPVIIL.h>
#include "casPVIIL.h"
//
// empty for now since casPVListChan::casPVListChan()
+314 -282
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.14 1996/12/12 18:56:27 jhill
* doc
*
* Revision 1.13 1996/12/11 01:03:52 jhill
* removed redundant bad client attach detect
*
@@ -111,58 +114,13 @@ caStatus casStrmClient::verifyRequest (casChannelI *&pChan)
//
// element count out of range ?
//
if (mp->m_count > pChan->getPVI().nativeCount()) {
if (mp->m_count > pChan->getPVI().nativeCount() || mp->m_count==0u) {
return this->sendErr(mp, ECA_BADCOUNT, NULL);
}
//
// If too many IO operations are in progress against this pv
// then we will need to wait until later to initiate this
// request.
//
if (pChan->getPVI().okToBeginNewIO()!=aitTrue) {
pChan->getPVI().addItemToIOBLockedList(*this);
return S_cas_ioBlocked;
}
else {
return S_cas_validRequest;
}
return S_cas_validRequest;
}
//
// casStrmClient::createChannel()
//
inline caStatus casStrmClient::createChannel (const char *pName)
{
caStatus status;
/*
* Verify that the server still has this channel
* and that we have it's correct official name.
* I assume that we may have found this server by
* contacting a name resolution service so we need to
* verify that the specified channel still exists here.
*/
pvExistReturn retVal =
this->ctx.getServer()->pvExistTest(this->ctx, pName);
if (retVal.getStatus() == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (retVal.getStatus() == S_cas_ioBlocked) {
this->ctx.getServer()->addItemToIOBLockedList(*this);
status = S_cas_ioBlocked;
}
else {
//
// All use of the string in retVal below ends up getting
// copied (not referenced) so we are ok if they wrap
// pName through into retVal
//
status = this->createChanResponse (*this->ctx.getMsg(), retVal);
}
return status;
}
@@ -222,9 +180,6 @@ caStatus casStrmClient::init()
//
casStrmClient::~casStrmClient()
{
casChannelI *pChan;
casChannelI *pNextChan;
this->osiLock();
//
@@ -243,15 +198,17 @@ casStrmClient::~casStrmClient()
//
// delete all channel attached
//
tsDLFwdIter<casChannelI> iter(this->chanList);
pChan = iter.next();
while (pChan) {
tsDLIterBD<casChannelI> iter(this->chanList.first());
const tsDLIterBD<casChannelI> eol;
tsDLIterBD<casChannelI> tmp;
while (iter!=eol) {
//
// destroying the channel removes it from the list
//
pNextChan = iter();
pChan->clientDestroy();
pChan = pNextChan;
tmp = iter;
++tmp;
iter->clientDestroy();
iter = tmp;
}
this->osiUnlock();
@@ -322,12 +279,15 @@ caStatus casStrmClient::readAction ()
pDesc = NULL;
status = this->read(pDesc);
if (status==S_casApp_success && pDesc) {
if (status==S_casApp_success) {
status = this->readResponse(pChan, *mp, pDesc, S_cas_success);
}
else if (status == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (status == S_casApp_postponeAsyncIO) {
pChan->getPVI().addItemToIOBLockedList(*this);
}
else {
status = this->sendErrWithEpicsStatus(mp, status, ECA_GETFAIL);
}
@@ -429,9 +389,15 @@ caStatus casStrmClient::readNotifyAction ()
pDesc = NULL;
status = this->read(pDesc);
if (status == S_casApp_asyncCompletion) {
if (status == S_casApp_success) {
status = this->readNotifyResponse(pChan, *mp, pDesc, status);
}
else if (status == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (status == S_casApp_postponeAsyncIO) {
pChan->getPVI().addItemToIOBLockedList(*this);
}
else {
status = this->readNotifyResponse(pChan, *mp, pDesc, status);
}
@@ -540,20 +506,13 @@ caStatus casStrmClient::monitorResponse (casChannelI *pChan,
const caHdr &msg, gdd *pDesc, const caStatus completionStatus)
{
caStatus completionStatusCopy = completionStatus;
gdd *pDBRDD = NULL;
caHdr *pReply;
unsigned size;
caStatus status;
int strcnt;
gdd *pDBRDD;
gddStatus gdds;
//
// verify read access
//
if (!(*pChan)->readAccess()) {
completionStatusCopy = S_cas_noRead;
}
size = dbr_size_n (msg.m_type, msg.m_count);
status = this->allocMsg(size, &pReply);
if (status) {
@@ -564,7 +523,7 @@ caStatus casStrmClient::monitorResponse (casChannelI *pChan,
// instead
//
status = sendErr(&msg, ECA_TOLARGE,
"unable to xmit enevt info");
"unable to xmit event");
}
return status;
}
@@ -575,18 +534,22 @@ caStatus casStrmClient::monitorResponse (casChannelI *pChan,
*pReply = msg;
pReply->m_postsize = size;
//
// verify read access
//
if (!(*pChan)->readAccess()) {
completionStatusCopy = S_cas_noRead;
}
//
// cid field abused to store the status here
//
if (completionStatusCopy == S_cas_success) {
if (pDesc) {
status = createDBRDD(msg.m_type, msg.m_count, pDBRDD);
if (status != S_cas_success) {
pDBRDD = NULL;
completionStatusCopy = status;
}
else {
completionStatusCopy = createDBRDD(msg.m_type,
msg.m_count, pDBRDD);
if (completionStatusCopy==S_cas_success) {
gdds = gddApplicationTypeTable::
app_table.smartCopy(pDBRDD, pDesc);
if (gdds) {
@@ -627,10 +590,14 @@ caStatus casStrmClient::monitorResponse (casChannelI *pChan,
}
}
else {
errMessage(completionStatusCopy, "monitor response");
errMessage(completionStatusCopy, "- in monitor response");
if (completionStatusCopy== S_cas_noRead) {
pReply->m_cid = ECA_NORDACCESS;
}
else if (completionStatusCopy==S_cas_noMemory) {
pReply->m_cid = ECA_ALLOCMEM;
}
else {
pReply->m_cid = ECA_GETFAIL;
}
@@ -688,11 +655,11 @@ caStatus casStrmClient::writeAction()
// initiate the write operation
//
status = this->write();
if (status==S_casApp_success) {
if (status==S_casApp_success || status == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (status == S_casApp_asyncCompletion) {
status = S_cas_success;
else if (status==S_casApp_postponeAsyncIO) {
pChan->getPVI().addItemToIOBLockedList(*this);
}
else {
status = this->sendErrWithEpicsStatus(mp, status, ECA_PUTFAIL);
@@ -760,6 +727,9 @@ caStatus casStrmClient::writeNotifyAction()
if (status == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (status==S_casApp_postponeAsyncIO) {
pChan->getPVI().addItemToIOBLockedList(*this);
}
else {
status = casStrmClient::writeNotifyResponse(pChan, *mp,
status);
@@ -811,7 +781,6 @@ caStatus casStrmClient::hostNameAction()
{
const caHdr *mp = this->ctx.getMsg();
char *pName = (char *) this->ctx.getData();
casChannelI *pciu;
unsigned size;
char *pMalloc;
@@ -837,9 +806,11 @@ caStatus casStrmClient::hostNameAction()
}
this->pHostName = pMalloc;
tsDLFwdIter<casChannelI> iter(this->chanList);
while ( (pciu = iter.next()) ) {
(*pciu)->setOwner(this->pUserName, this->pHostName);
tsDLIterBD<casChannelI> iter(this->chanList.first());
const tsDLIterBD<casChannelI> eol;
while ( iter!=eol ) {
(*iter)->setOwner(this->pUserName, this->pHostName);
++iter;
}
this->osiUnlock();
@@ -855,7 +826,6 @@ caStatus casStrmClient::clientNameAction()
{
const caHdr *mp = this->ctx.getMsg();
char *pName = (char *) this->ctx.getData();
casChannelI *pciu;
unsigned size;
char *pMalloc;
@@ -882,9 +852,11 @@ caStatus casStrmClient::clientNameAction()
}
this->pUserName = pMalloc;
tsDLFwdIter<casChannelI> iter(this->chanList);
while ( (pciu = iter.next()) ) {
(*pciu)->setOwner(this->pUserName, this->pHostName);
tsDLIterBD<casChannelI> iter(this->chanList.first());
const tsDLIterBD<casChannelI> eol;
while ( iter!=eol ) {
(*iter)->setOwner(this->pUserName, this->pHostName);
++iter;
}
this->osiUnlock();
@@ -900,8 +872,8 @@ caStatus casStrmClient::claimChannelAction()
{
const caHdr *mp = this->ctx.getMsg();
char *pName = (char *) this->ctx.getData();
int status;
unsigned nameLength;
caStatus status;
/*
* The available field is used (abused)
@@ -922,7 +894,7 @@ caStatus casStrmClient::claimChannelAction()
// new API was added to the server (they must
// now use clients at EPICS 3.12 or higher)
//
status = this->sendErr(mp, ECA_DEFUNCT,
this->sendErr(mp, ECA_DEFUNCT,
"R3.11 connect sequence from old client was ignored");
return S_cas_badProtocol; // disconnect client
}
@@ -941,13 +913,146 @@ caStatus casStrmClient::claimChannelAction()
return S_cas_badProtocol; // disconnect client
}
status = this->createChannel (pName);
if (status == S_casApp_asyncCompletion) {
//
// asynchronous completion
//
status = S_cas_success;
//
// prevent problems such as the PV being deleted before the
// channel references it
//
this->osiLock();
this->asyncIOFlag = 0u;
const pvCreateReturn pvcr =
(*this->ctx.getServer())->createPV (this->ctx, pName);
//
// prevent problems when they initiate
// async IO but dont return status
// indicating so (and vise versa)
//
if (this->asyncIOFlag) {
status = S_cas_success;
}
else if (pvcr.getStatus() == S_casApp_asyncCompletion) {
status = this->createChanResponse(*mp,
pvCreateReturn(S_cas_badParameter));
errMessage(S_cas_badParameter,
"- expected asynch IO creation from caServer::createPV()");
}
else if (pvcr.getStatus() == S_casApp_postponeAsyncIO) {
status = S_casApp_postponeAsyncIO;
this->ctx.getServer()->addItemToIOBLockedList(*this);
}
else {
status = this->createChanResponse(*mp, pvcr);
}
this->osiUnlock();
return status;
}
//
// casStrmClient::createChanResponse()
//
// LOCK must be applied
//
caStatus casStrmClient::createChanResponse(const caHdr &hdr, const pvCreateReturn &pvcr)
{
casPVI *pPV;
casChannel *pChan;
casChannelI *pChanI;
caHdr *claim_reply;
caHdr *dummy;
unsigned dbrType;
caStatus status;
if (pvcr.getStatus() != S_cas_success) {
return this->channelCreateFailed(&hdr, pvcr.getStatus());
}
pPV = pvcr.getPV();
//
// If status is ok and the PV isnt set then guess that the
// pv isnt in this server
//
if (pPV == NULL) {
return this->channelCreateFailed(&hdr, S_casApp_pvNotFound);
}
//
// NOTE:
// We are allocating enough space for both the claim
// response and the access response so that we know for
// certain that they will both be sent together.
//
status = this->allocMsg (sizeof(caHdr), &dummy);
if (status) {
return status;
}
//
// create server tool XXX derived from casChannel
//
this->ctx.setPV(pPV);
pChan = (*pPV)->createChannel(this->ctx,
this->pUserName, this->pHostName);
if (!pChan) {
pvcr.getPV()->deleteSignal();
return this->channelCreateFailed(&hdr, S_cas_noMemory);
}
this->osiUnlock();
pChanI = (casChannelI *) pChan;
//
// NOTE:
// We are certain that the request will complete
// here because we allocated enough space for this
// and the claim response above.
//
status = casStrmClient::accessRightsResponse(pChanI);
if (status) {
errMessage(status, "incompplete channel create?");
pChanI->clientDestroy();
return this->channelCreateFailed(&hdr, status);
}
status = pPV->bestDBRType(dbrType);
if (status) {
errMessage(status, "best external dbr type fetch failed");
pChanI->clientDestroy();
return this->channelCreateFailed(&hdr, status);
}
//
// NOTE:
// We are allocated enough space for both the claim
// response and the access response so that we know for
// certain that they will both be sent together.
// Nevertheles, some (old) clients do not receive
// an access rights response so we allocate again
// here to be certain that we are at the correct place in
// the protocol buffer.
//
// The 3rd arg indicates - dont lock the buffer again
//
status = this->allocMsg (0u, &claim_reply, FALSE);
//
// Not sending the access rights response and the claim
// response is a severe error which is avoided by
// the first (oversize) allocMsg
//
assert (status==S_cas_success);
*claim_reply = nill_msg;
claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU;
claim_reply->m_type = dbrType;
claim_reply->m_count = pPV->nativeCount();
claim_reply->m_cid = hdr.m_cid;
claim_reply->m_available = pChanI->getSID();
//
// Unlock the buffer (and convert it to network format
//
this->commitMsg();
return status;
}
@@ -965,7 +1070,15 @@ caStatus createStatus)
caStatus status;
caHdr *reply;
errMessage (createStatus, "- Server unable to create a new PV");
if (createStatus == S_casApp_asyncCompletion) {
errMessage(S_cas_badParameter,
"- no asynchronous IO create in createPV() ?");
errMessage(S_cas_badParameter,
"- or S_casApp_asyncCompletion was async IO competion code ?");
}
else {
errMessage (createStatus, "- Server unable to create a new PV");
}
if (CA_V46(CA_PROTOCOL_VERSION,this->minor_version_number)) {
status = allocMsg (0u, &reply);
@@ -1012,7 +1125,7 @@ caStatus casStrmClient::disconnectChan(caResId id)
}
else {
ca_printf(
"Disconnecting old client when server tool deleted its channel or PV\n");
"Disconnecting old client because of internal channel or PV delete\n");
createStatus = S_cas_disconnect;
}
@@ -1026,8 +1139,6 @@ caStatus casStrmClient::disconnectChan(caResId id)
//
caStatus casStrmClient::eventsOnAction ()
{
casChannelI *pciu;
this->setEventsOn();
//
@@ -1035,9 +1146,11 @@ caStatus casStrmClient::eventsOnAction ()
// should be a queue of modified events
//
this->osiLock();
tsDLFwdIter<casChannelI> iter(this->chanList);
while ( (pciu = iter.next()) ) {
pciu->postAllModifiedEvents();
tsDLIterBD<casChannelI> iter(this->chanList.first());
const tsDLIterBD<casChannelI> eol;
while ( iter!=eol ) {
iter->postAllModifiedEvents();
++iter;
}
this->osiUnlock();
@@ -1069,15 +1182,9 @@ caStatus casStrmClient::eventAddAction ()
caStatus status;
casEventMask mask;
pciu = this->resIdToChannel(mp->m_cid);
if (!pciu) {
logBadId(mp, (void *) pMonInfo);
return S_cas_internal;
}
if (mp->m_count==0u) {
this->sendErr(mp, ECA_BADCOUNT, "event add request");
return S_cas_success;
status = casStrmClient::verifyRequest (pciu);
if (status != S_cas_validRequest) {
return status;
}
//
@@ -1102,21 +1209,38 @@ caStatus casStrmClient::eventAddAction ()
return S_cas_success;
}
pMonitor = new casClientMon(*pciu, mp->m_available,
mp->m_count, mp->m_type, mask, *this);
if (!pMonitor) {
this->sendErr(mp, ECA_ALLOCMEM, NULL);
return S_cas_internal;
}
//
// always send immediate monitor response at event add
// Attempt to read the first monitored value prior to creating
// the monitor object so that if the server tool chooses
// to postpone asynchronous IO we can safely restart this
// request later.
//
pDD = NULL;
status = this->read(pDD);
if (status == S_casApp_asyncCompletion) {
//
// always send immediate monitor response at event add
//
if (status == S_casApp_success) {
status = this->monitorResponse (pciu, *mp, pDD, status);
}
else if (status == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (status == S_casApp_postponeAsyncIO) {
//
// try again later
//
pciu->getPVI().addItemToIOBLockedList(*this);
}
else if (status == S_casApp_noMemory) {
//
// If we cant send the first monitor value because
// there isnt pool space for a gdd then delete
// (disconnect) the channel
//
(*pciu)->destroy();
return S_cas_success;
}
else {
status = this->monitorResponse (pciu, *mp, pDD, status);
}
@@ -1127,6 +1251,21 @@ caStatus casStrmClient::eventAddAction ()
assert(gddStatus==0);
}
if (status==S_cas_success) {
pMonitor = new casClientMon(*pciu, mp->m_available,
mp->m_count, mp->m_type, mask, *this);
if (!pMonitor) {
this->sendErr(mp, ECA_ALLOCMEM, NULL);
//
// If we cant allocate space for a monitor then
// delete (disconnect) the channel
//
(*pciu)->destroy();
status = S_cas_success;
}
}
return status;
}
@@ -1283,7 +1422,6 @@ caStatus casStrmClient::readSyncAction()
const caHdr *mp = this->ctx.getMsg();
int status;
caHdr *reply;
casChannelI *pChan;
//
// This messages indicates that the client
@@ -1292,9 +1430,11 @@ caStatus casStrmClient::readSyncAction()
// a read.
//
this->osiLock();
tsDLFwdIter<casChannelI> iter(this->chanList);
while ( (pChan = iter.next()) ) {
pChan->clearOutstandingReads();
tsDLIterBD<casChannelI> iter(this->chanList.first());
const tsDLIterBD<casChannelI> eol;
while ( iter!=eol ) {
iter->clearOutstandingReads();
++iter;
}
this->osiUnlock();
@@ -1381,6 +1521,11 @@ caStatus casStrmClient::write()
return status;
}
//
// clear async IO flag
//
this->asyncIOFlag = 0u;
//
// DBR_STRING is stored outside the DD so it
// lumped in with arrays
@@ -1392,6 +1537,25 @@ caStatus casStrmClient::write()
status = this->writeScalarData();
}
//
// prevent problems when they initiate
// async IO but dont return status
// indicating so (and vise versa)
//
if (this->asyncIOFlag) {
if (status!=S_casApp_asyncCompletion) {
fprintf(stderr,
"Application returned %d from casPV::write() - expected S_casApp_asyncCompletion\n",
status);
status = S_casApp_asyncCompletion;
}
}
else if (status == S_casApp_asyncCompletion) {
status = S_cas_badParameter;
errMessage(status,
"- expected asynch IO creation from casPV::write()");
}
(*pPV)->endTransaction();
return status;
@@ -1544,7 +1708,9 @@ caStatus casStrmClient::read(gdd *&pDescRet)
return status;
}
assert(pDescRet);
if (!pDescRet) {
return S_cas_noMemory;
}
//
// the PV state must not be modified during a transaction
@@ -1554,17 +1720,38 @@ caStatus casStrmClient::read(gdd *&pDescRet)
return status;
}
//
// clear the async IO flag
//
this->asyncIOFlag = 0u;
//
// call the server tool's virtual function
//
status = (*this->ctx.getPV())->read(this->ctx, *pDescRet);
//
// prevent problems when they initiate
// async IO but dont return status
// indicating so (and vise versa)
//
if (this->asyncIOFlag) {
if (status!=S_casApp_asyncCompletion) {
fprintf(stderr,
"Application returned %d from casPV::read() - expected S_casApp_asyncCompletion\n",
status);
status = S_casApp_asyncCompletion;
}
}
else if (status == S_casApp_asyncCompletion) {
status = S_cas_badParameter;
errMessage(status,
"- expected asynch IO creation from casPV::read()");
}
if (status) {
pDescRet->unreference();
pDescRet = NULL;
if (status!=S_casApp_asyncCompletion) {
errMessage(status,
" - response from server tool\n");
}
}
(*this->ctx.getPV())->endTransaction();
@@ -1695,161 +1882,6 @@ const char *casStrmClient::hostName() const
return this->pHostName?this->pHostName:"?";
}
//
// casStrmClient::createChanResponse()
//
caStatus casStrmClient::createChanResponse(const caHdr &msg,
const pvExistReturn &retVal)
{
casChannel *pChan;
casChannelI *pChanI;
casPVI *pPV;
caHdr *claim_reply;
caHdr *dummy;
unsigned dbrType;
caStatus status;
this->ctx.getServer()->pvExistTestCompletion();
if (retVal.getStatus()) {
return this->channelCreateFailed(&msg, retVal.getStatus());
}
if (!retVal.getString()) {
return this->channelCreateFailed(&msg, S_cas_badParameter);
}
if (retVal.getString()[0]=='\0') {
return this->channelCreateFailed(&msg, S_cas_badParameter);
}
//
// NOTE:
// We are allocating enough space for both the claim
// response and the access response so that we know for
// certain that they will both be sent together.
//
status = this->allocMsg (sizeof(caHdr), &dummy);
if (status) {
return status;
}
//
// prevent problems such as the PV being deleted before the
// channel references it
//
this->osiLock();
pPV = this->ctx.getServer()->createPV(retVal.getString());
if (!pPV) {
this->osiUnlock();
return this->channelCreateFailed(&msg, S_cas_noMemory);
}
//
// create server tool XXX derived from casChannel
//
this->ctx.setPV(pPV);
pChan = (*pPV)->createChannel(this->ctx,
this->pUserName, this->pHostName);
if (!pChan) {
this->osiUnlock();
pPV->deleteSignal();
return this->channelCreateFailed(&msg, S_cas_noMemory);
}
this->osiUnlock();
pChanI = (casChannelI *) pChan;
//
// NOTE:
// We are certain that the request will complete
// here because we allocated enough space for this
// and the claim response above.
//
status = casStrmClient::accessRightsResponse(pChanI);
if (status) {
errMessage(status, "incompplete channel create?");
pChanI->clientDestroy();
return this->channelCreateFailed(&msg, status);
}
status = pPV->bestDBRType(dbrType);
if (status) {
errMessage(status, "best external dbr type fetch failed");
pChanI->clientDestroy();
return this->channelCreateFailed(&msg, status);
}
//
// NOTE:
// We are allocated enough space for both the claim
// response and the access response so that we know for
// certain that they will both be sent together.
// Nevertheles, some (old) clients do not receive
// an access rights response so we allocate again
// here to be certain that we are at the correct place in
// the protocol buffer.
//
status = this->allocMsg (sizeof(caHdr), &claim_reply,
FALSE /* dont lock the out buffer again*/);
//
// Not sending the access rights response and the claim
// response is a severe error which is avoided by
// the first (oversize) allocMsg
//
assert (status==S_cas_success);
*claim_reply = nill_msg;
claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU;
claim_reply->m_type = dbrType;
claim_reply->m_count = pPV->nativeCount();
claim_reply->m_cid = msg.m_cid;
claim_reply->m_available = pChanI->getSID();
//
// Unlock the buffer (and convert it to network format
//
this->commitMsg();
return status;
}
//
// caServerI::createPV ()
//
casPVI *caServerI::createPV (const char *pName)
{
casPVI *pPVI;
//
// create resource id
// (this does a malloc to obtain space for the string)
//
stringId id (pName);
this->osiLock ();
pPVI = this->stringResTbl.lookup (id);
if (!pPVI) {
casPV *pPV;
pPV = (*this)->createPV (this->ctx, pName);
if (pPV) {
pPVI = (casPVI *) pPV;
}
}
//
// lock shouldnt be released until we finish creating and
// installing the PV
//
this->osiUnlock ();
return pPVI;
}
//
// caServerI::roomForNewChannel()
//
+180 -101
View File
@@ -30,6 +30,9 @@
* Modification Log:
* -----------------
* $Log$
* Revision 1.11 1997/01/09 22:24:46 jhill
* eliminate MSVC++ warning resulting from passing *this to a base
*
* Revision 1.10 1996/12/06 22:36:26 jhill
* use destroyInProgress flag now functional nativeCount()
*
@@ -72,9 +75,6 @@
* .08 Need a mechanism by which an error detail string can be returned
* to the server from a server app (in addition to the normal
* error constant)
* .10 Need a new env var in which the app specifies a set of interfaces
* to use - or perhaps just a list of networks that we will accept
* clients from.
* .12 Should the server have an interface so that all PV names
* can be obtained (even ones created after init)? This
* would be used to implement update of directory services and
@@ -134,7 +134,6 @@ typedef aitUint32 caStatus;
#define S_cas_badElementCount (M_cas | 6) /*Bad element count*/
#define S_cas_noConvert (M_cas | 7) /*No conversion between src & dest types*/
#define S_cas_badWriteType (M_cas | 8) /*Src type inappropriate for write*/
#define S_cas_ioBlocked (M_cas | 9) /*Blocked for io completion*/
#define S_cas_partialMessage (M_cas | 10) /*Partial message*/
#define S_cas_noContext (M_cas | 11) /*Context parameter is required*/
#define S_cas_disconnect (M_cas | 12) /*Lost connection to server*/
@@ -167,40 +166,40 @@ typedef aitUint32 caStatus;
#define S_casApp_pvNotFound (M_casApp | 2) /*PV not found*/
#define S_casApp_badPVId (M_casApp | 3) /*Unknown PV identifier*/
#define S_casApp_noSupport (M_casApp | 4) /*No application support for op*/
#define S_casApp_asyncCompletion (M_casApp | 5) /*Operation will complete asynchronously*/
#define S_casApp_asyncCompletion (M_casApp | 5) /*will complete asynchronously*/
#define S_casApp_badDimension (M_casApp | 6) /*bad matrix size in request*/
#define S_casApp_canceledAsyncIO (M_casApp | 7) /*asynchronous io canceled*/
#define S_casApp_outOfBounds (M_casApp | 8) /*operation was out of bounds*/
#define S_casApp_undefined (M_casApp | 9) /*undefined value*/
#define S_casApp_postponeAsyncIO (M_casApp | 10) /*postpone asynchronous IO*/
//
// pvExistReturn
// Only for use with caServer::pvExistTest()
// pv exist test return
//
class pvExistReturn {
// If the server tool does not wish to start another simultaneous
// asynchronous IO operation or if there is not enough memory
// to do so return pverDoesNotExistHere (and the client will
// retry the request later).
//
enum pvExistReturn {pverExistsHere, pverDoesNotExistHere,
pverAsyncCompletion};
class casPV;
class pvCreateReturn {
public:
//
// for use by the server tool when creating a return value
//
inline pvExistReturn(caStatus status=S_casApp_pvNotFound,
const char* pCanonicalNameStr=0);
inline pvExistReturn(caStatus status, char* pCanonicalNameStr);
//
// for use by the server lib when extracting the result
//
inline const caStatus getStatus() const;
inline const char *getString() const;
//
// these make certain that copy and assignment are correct
//
inline pvExistReturn(pvExistReturn &init);
inline pvExistReturn(const pvExistReturn &init);
inline pvExistReturn& operator=(pvExistReturn &rhs);
inline pvExistReturn& operator=(const pvExistReturn &rhs);
private:
caStatus stat;
aitString str;
pvCreateReturn()
{ this->pPV = NULL; this->stat = S_cas_badParameter; }
pvCreateReturn(caStatus statIn)
{ this->pPV = NULL; this->stat = statIn; }
pvCreateReturn(casPV &pv)
{ this->pPV = &pv; this->stat = S_casApp_success; }
const caStatus getStatus() const { return this->stat; }
casPV *getPV() const { return this->pPV; }
private:
casPV *pPV;
caStatus stat;
};
#include "casEventMask.h" // EPICS event select class
@@ -221,10 +220,9 @@ private:
// We do not use private inheritance here in order
// to avoid os/io dependent -I during server tool compile
//
caServerI *pCAS;
caServerI *pCAS;
public:
caServer (unsigned pvMaxNameLength, unsigned pvCountEstimate=0x3ff,
unsigned maxSimultaneousIO=1u);
caServer (unsigned pvCountEstimate=1024u);
virtual ~caServer();
//caStatus enableClients ();
@@ -238,46 +236,64 @@ public:
//
// show()
//
virtual void show (unsigned level);
virtual void show (unsigned level) const;
//
// pvExistTest()
//
// The request is allowed to complete asynchronously
// (see Asynchronous IO Classes below).
//
// The server tool is encouraged to accept multiple PV name
// aliases for the same PV here. However, one unique canonical name
// must be selected by the server tool and returned to the
// server lib for each PV. The server will use this canonical
// name to prevent internal duplication of data structures for
// process variables that have multiple aliases.
// aliases for the same PV here.
//
// o returns S_casApp_success and a valid canonical name string
// when the PV is in this server tool
// example return from this procedure:
// return pverExistsHere; // server has PV
// return pverDoesNotExistHere; // server does know of this PV
// return pverAsynchCompletion; // deferred result
// return pverNoMemoryForAsyncOP; // unable to defer result
//
// o returns S_casApp_pvNotFound if the PV does not exist in
// the server tool
//
// Examples:
// caServerXXX::pvExistTest(const casCtx &ctx, const char *pPVName)
// {
// return pvExistReturn(S_casApp_success, pPVName); // common
// return pvExistReturn(S_casApp_pvNotFound); // no PV by that name
//
// const char *pConstName = "myPVName";
// char pName[9] = "myPVName";
// return pvExistReturn(S_casApp_success, pConstName); // efficient
// return pvExistReturn(S_casApp_asyncCompletion); // not now
// }
// Return S_casApp_postponeAsyncIO if too many simultaneous
// asynchronous IO operations are pending aginst the server.
// The server library will retry the request whenever an
// asynchronous IO operation (create or exist) completes
// against the server.
//
virtual pvExistReturn pvExistTest (const casCtx &ctx,
const char *pPVName)=0;
const char *pPVAliasName) = 0;
//
// createPV() is called each time that a PV is attached to
// by a client for the first time. The server tool must create
// a casPV object (or a derived class) each time that this
// routine is called
//
virtual casPV *createPV (const casCtx &ctx, const char *pPVName)=0;
// createPV() is called _every_ time that a PV is attached to
// by a client. The name supplied here may be a PV canonical
// (base) name or it may instead be a PV alias name.
//
// The request is allowed to complete asynchronously
// (see Asynchronous IO Classes below).
//
// IMPORTANT:
// o It is the responsability of the server tool
// to detect attempts by the server lib to create a 2nd PV with
// the same name as an existing PV. It is also the responsability
// of the server tool to detect attempts by the server lib to
// create a 2nd PV with a name that is an alias of an existing PV.
// In these situations the server tool should avoid PV duplication
// by returning a pointer to an existing PV (and not create a new
// PV).
//
// example return from this procedure:
// return pvCreateReturn(*pPV); // success
// return pvCreateReturn(S_casApp_pvNotFound); // no PV by that name here
// return pvCreateReturn(S_casApp_noMemory); // no resource to create pv
// return pvCreateReturn(S_casApp_asyncCompletion); // deferred completion
//
// Return S_casApp_postponeAsyncIO if too many simultaneous
// asynchronous IO operations are pending aginst the server.
// The server library will retry the request whenever an
// asynchronous IO operation (create or exist) completes
// against the server.
//
virtual pvCreateReturn createPV (const casCtx &ctx,
const char *pPVAliasName) = 0;
//
// common event masks
@@ -286,6 +302,12 @@ public:
const casEventMask valueEventMask; // DBE_VALUE
const casEventMask logEventMask; // DBE_LOG
const casEventMask alarmEventMask; // DBE_ALARM
//
// this is only used by casPVI::casPVI() too convert from
// caServer to a caServerI
//
friend class casPVI;
};
//
@@ -294,19 +316,26 @@ public:
// Deletion Responsibility
// -------- --------------
// o the server lib will not call "delete" directly for any
// casPV created by the server tool because we dont know
// that "new" was called to create the object
// casPV because we dont know that "new" was called to create
// the object
// o The server tool is responsible for reclaiming storage for any
// casPV it creates. The destroy() virtual function will
// assist the server tool with this responsibility. The
// virtual function casPV::destroy() does a "delete this".
// o The virtual function "destroy()" is called by the server lib
// each time that the last client attachment to the PV object is removed.
// o The destructor for this object will cancel any
// client attachment to this PV (and reclaim any resources
// allocated by the server library on its behalf)
//
// NOTE: if the server tool precreates the PV during initialization
// then it may decide to provide a "destroy()" implementation in the
// derived class which is a noop.
//
class casPV : private casPVI {
public:
casPV (const casCtx &ctx, const char * const pPVName);
casPV (caServer &cas);
virtual ~casPV ();
//
@@ -314,13 +343,7 @@ public:
// caServer::show() is called and the level is high
// enough
//
virtual void show (unsigned level);
//
// The maximum number of simultaneous asynchronous IO operations
// allowed for this PV
//
virtual unsigned maxSimultAsyncOps () const;
virtual void show (unsigned level) const;
//
// Called by the server libary each time that it wishes to
@@ -356,21 +379,33 @@ public:
//
// read
//
// asychronous completion iis allowed
// The request is allowed to complete asynchronously
// (see Asynchronous IO Classes below).
//
// RULE: if this completes asynchronously and the server tool references
// its data into the prototype descriptor passed in the args to read()
// then this data must _not_ be modified while the reference count
// on the prototype is greater than zero.
//
// Return S_casApp_postponeAsyncIO if too many simultaneous
// asynchronous IO operations are pending aginst the PV.
// The server library will retry the request whenever an
// asynchronous IO operation (read or write) completes
// against the PV.
//
virtual caStatus read (const casCtx &ctx, gdd &prototype);
//
// write
//
// asychronous completion iis allowed
// (ie the server tool is allowed to cache the data and actually
// complete the write operation at some time in the future)
// The request is allowed to complete asynchronously
// (see Asynchronous IO Classes below).
//
// Return S_casApp_postponeAsyncIO if too many simultaneous
// asynchronous IO operations are pending aginst the PV.
// The server library will retry the request whenever an
// asynchronous IO operation (read or write) completes
// against the PV.
//
virtual caStatus write (const casCtx &ctx, gdd &value);
@@ -455,7 +490,11 @@ public:
//
// peek at the pv name
//
//inline char *getName() const
// NOTE if there are several aliases for the same PV
// this routine should return the canonical (base)
// name for the PV
//
virtual const char *getName() const = 0;
//
// Find the server associated with this PV
@@ -466,7 +505,13 @@ public:
// for virtual casPV::destroy()
// ***************
//
caServer *getCAS();
caServer *getCAS() const;
//
// only used when caStrmClient converts between
// casPV * and casPVI *
//
friend class casStrmClient;
};
//
@@ -497,16 +542,6 @@ public:
virtual void setOwner(const char * const pUserName,
const char * const pHostName);
//
// called when the first client begins to monitor the PV
//
virtual caStatus interestRegister();
//
// called when the last client stops monitoring the PV
//
virtual void interestDelete();
//
// the following are encouraged to change during an channel's
// lifetime
@@ -522,7 +557,7 @@ public:
// caServer::show() is called and the level is high
// enough
//
virtual void show(unsigned level);
virtual void show(unsigned level) const;
//
// destroy() is called when
@@ -535,10 +570,10 @@ public:
virtual void destroy();
//
// server tool calls this to indicate change of channel state
// (ie access rights changed)
// server tool calls this to indicate change in access
// rights has occurred
//
void postEvent (const casEventMask &select, gdd &event);
void postAccessRightsEvent();
//
// Find the PV associated with this channel
@@ -550,6 +585,12 @@ public:
// ***************
//
casPV *getPV();
//
// only used when casStrmClient converts between
// casChannel * and casChannelI *
//
friend class casStrmClient;
};
//
@@ -560,12 +601,13 @@ public:
// Virtual Function Asynchronous IO Class
// ----------------- ---------------------
// caServer::pvExistTest() casAsyncPVExistIO
// caServer::createPV() casAsyncCreatePVIO
// casPV::read() casAsyncReadIO
// casPV::write() casAsyncWriteIO
//
// To initiate asynchronous completion create a corresponding
// asynchronous IO object from the table above from within
// one of the above virtual functions and return the status code
// asynchronous IO object from within one of the virtual
// functions shown in the table above and return the status code
// S_casApp_asyncCompletion. Use the member function
// "postIOCompletion()" to inform the server library that the
// requested operation has completed.
@@ -661,7 +703,7 @@ public:
// into a server
// ***************
//
caServer *getCAS()
caServer *getCAS() const
{
return this->casAsyncRdIOI::getCAS();
}
@@ -712,7 +754,7 @@ public:
// into a server
// ***************
//
caServer *getCAS()
caServer *getCAS() const
{
return this->casAsyncWtIOI::getCAS();
}
@@ -727,9 +769,6 @@ public:
//
// casAsyncPVExistIO()
//
// Any DD ptr supplied here is used if postIOCompletion()
// is called with a nill DD pointer
//
casAsyncPVExistIO(const casCtx &ctx) :
casAsyncExIOI(ctx, *this) {}
@@ -743,7 +782,7 @@ public:
// (this function does not delete the casAsyncIO object).
// Only the first call to this function has any effect.
//
caStatus postIOCompletion(const pvExistReturn &retValIn)
caStatus postIOCompletion(const pvExistReturn retValIn)
{
return this->casAsyncExIOI::postIOCompletion (retValIn);
}
@@ -755,11 +794,51 @@ public:
// into a server
// ***************
//
caServer *getCAS()
caServer *getCAS() const
{
return this->casAsyncExIOI::getCAS();
}
};
//
// casAsyncPVCreateIO
// - for use with caServer::createPV()
//
class casAsyncPVCreateIO : public casAsyncIO, private casAsyncPVCIOI {
public:
//
// casAsyncPVCreateIO()
//
casAsyncPVCreateIO(const casCtx &ctx) :
casAsyncPVCIOI(ctx, *this) {}
//
// force virtual destructor
//
virtual ~casAsyncPVCreateIO();
//
// place notification of IO completion on the event queue
// (this function does not delete the casAsyncIO object).
// Only the first call to this function has any effect.
//
caStatus postIOCompletion(const pvCreateReturn &retValIn)
{
return this->casAsyncPVCIOI::postIOCompletion (retValIn);
}
//
// Find the server associated with this async IO
// ****WARNING****
// this returns NULL if the async io isnt currently installed
// into a server
// ***************
//
caServer *getCAS() const
{
return this->casAsyncPVCreateIO::getCAS();
}
};
#endif // ifdef includecasdefh (this must be the last line in this file)
+3 -3
View File
@@ -1,7 +1,7 @@
#include <server.h>
#include <inBufIL.h>
#include <casOpaqueAddrIL.h>
#include "server.h"
#include "inBufIL.h"
#include "casOpaqueAddrIL.h"
//
// this needs to be here (and not in dgInBufIL.h) if we
+2 -2
View File
@@ -2,8 +2,8 @@
#ifndef dgInBufILh
#define dgInBufILh
#include <casOpaqueAddrIL.h>
#include <inBufIL.h>
#include "casOpaqueAddrIL.h"
#include "inBufIL.h"
//
// dgInBuf::clear()
+3 -3
View File
@@ -1,7 +1,7 @@
#include <server.h>
#include <casOpaqueAddrIL.h>
#include <outBufIL.h>
#include "server.h"
#include "casOpaqueAddrIL.h"
#include "outBufIL.h"
//
// this needs to be here (and not in dgInBufIL.h) if we
+2 -2
View File
@@ -2,8 +2,8 @@
#ifndef dgOutBufILh
#define dgOutBufILh
#include <casOpaqueAddrIL.h>
#include <outBufIL.h>
#include "casOpaqueAddrIL.h"
#include "outBufIL.h"
//
// All of the functions in this file moved to dgOutBuf.cc because
+62 -48
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.15 1997/01/10 21:18:05 jhill
* code around gnu g++ inline bug when -O isnt used
*
* Revision 1.14 1996/12/11 00:57:56 jhill
* moved casEventMaskEntry here
*
@@ -133,12 +136,16 @@ enum casProcCond {casProcOk, casProcDisconnect};
/*
* maximum peak log entries for each event block (registartion)
* (events cached into the last queue entry if over flow occurs)
* (if this exceeds 256 then the casMonitor::nPend must
* be assigned a new data type)
*/
#define individualEventEntries 16u
/*
* maximum average log entries for each event block (registartion)
* (events cached into the last queue entry if over flow occurs)
* (if this exceeds 256 then the casMonitor::nPend must
* be assigned a new data type)
*/
#define averageEventEntries 4u
@@ -159,7 +166,9 @@ public:
inline caStatus init();
~casEventSys();
virtual ~casEventSys();
virtual void destroy()=0;
void show(unsigned level) const;
casProcCond process();
@@ -185,6 +194,8 @@ public:
inline void setEventsOff();
inline void setDestroyPending();
private:
tsDLList<casEvent> eventLogQue;
osiMutex mutex;
@@ -192,6 +203,7 @@ private:
unsigned numEventBlocks; // N event blocks installed
unsigned maxLogEntries; // max log entries
unsigned char eventsOff;
unsigned char destroyPending;
};
//
@@ -206,15 +218,14 @@ public:
caStatus callBack(gdd &value);
casResType resourceType() const
{
return casClientMonT;
}
virtual casResType resourceType() const;
caResId getId() const
{
return this->casRes::getId();
}
virtual void destroy();
private:
};
@@ -249,6 +260,7 @@ public:
inline void setChannel(casChannelI *p);
void show (unsigned level) const;
private:
caHdr msg; // ca message header
void *pData; // pointer to data following header
@@ -256,6 +268,7 @@ private:
casCoreClient *pClient;
casChannelI *pChannel;
casPVI *pPV;
unsigned nAsyncIO; // checks for improper use of async io
};
enum casFillCondition{
@@ -426,6 +439,12 @@ private:
//
class casCoreClient : public osiMutex, public ioBlocked,
public casEventSys {
//
// allows casAsyncIOI constructor to check for asynch IO duplicates
//
friend casAsyncIOI::casAsyncIOI(casCoreClient &clientIn, casAsyncIO &ioExternalIn);
public:
casCoreClient(caServerI &serverInternal);
caStatus init();
@@ -451,14 +470,15 @@ public:
virtual caStatus monitorResponse(casChannelI *,
const caHdr &, gdd *, const caStatus);
virtual caStatus accessRightsResponse(casChannelI *);
//
// one virtual function for each CA request type that has
// asynchronous completion
//
virtual caStatus asyncSearchResponse(casDGIntfIO &outMsgIO,
const caAddr &outAddr, const caHdr &, const pvExistReturn &);
virtual caStatus createChanResponse(const caHdr &,
const pvExistReturn &);
const caAddr &outAddr, const caHdr &, const pvExistReturn);
virtual caStatus createChanResponse(const caHdr &, const pvCreateReturn &);
virtual caStatus readResponse(casChannelI *, const caHdr &,
gdd *, const caStatus);
virtual caStatus readNotifyResponse(casChannelI *, const caHdr &,
@@ -476,6 +496,7 @@ public:
virtual casDGIntfIO* fetchOutIntf();
protected:
casCtx ctx;
unsigned char asyncIOFlag;
private:
tsDLList<casAsyncIOI> ioInProgList;
@@ -613,7 +634,7 @@ public:
// one function for each CA request type that has
// asynchronous completion
//
virtual caStatus createChanResponse(const caHdr &, const pvExistReturn &);
virtual caStatus createChanResponse(const caHdr &, const pvCreateReturn &);
caStatus readResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
caStatus readNotifyResponse(casChannelI *pChan, const caHdr &msg,
@@ -753,11 +774,11 @@ private:
//
caStatus searchFailResponse(const caHdr *pMsg);
caStatus searchResponse(const caHdr &, const pvExistReturn &);
caStatus searchResponse(const caHdr &, const pvExistReturn);
caStatus asyncSearchResponse(casDGIntfIO &outMsgIO,
const caAddr &outAddr, const caHdr &msg,
const pvExistReturn &retVal);
const pvExistReturn);
caAddr fetchRespAddr();
casDGIntfIO* fetchOutIntf();
@@ -781,7 +802,9 @@ public:
casEventMaskEntry (casEventRegistry &regIn,
casEventMask maskIn, const char *pName);
virtual ~casEventMaskEntry();
void show (unsigned level);
void show (unsigned level) const;
virtual void destroy();
private:
casEventRegistry &reg;
};
@@ -804,7 +827,7 @@ public:
casEventMask registerEvent (const char *pName);
void show (unsigned level);
void show (unsigned level) const;
private:
osiMutex &mutex;
@@ -819,6 +842,27 @@ private:
class casClientMon;
//
// casPVExistReturn
//
// special return code for the server internal version of pvExistTest()
//
class casPVExistReturn {
public:
casPVExistReturn(pvExistReturn appIn)
{app=appIn; stat = S_cas_success; }
casPVExistReturn(caStatus statIn)
{app=pverDoesNotExistHere; stat = statIn; }
caStatus getStatus() const {return stat;}
pvExistReturn getAppStat() const {return app;}
private:
pvExistReturn app;
caStatus stat;
};
//
// caServerI
//
class caServerI :
public osiMutex, // osiMutex must be first because it is used
// by ioBlockedList and casEventRegistry
@@ -828,8 +872,7 @@ class caServerI :
private uintResTable<casRes>,
public casEventRegistry {
public:
caServerI(caServer &tool, unsigned pvMaxNameLength,
unsigned pvCountEstimate, unsigned maxSimultaneousIO);
caServerI(caServer &tool, unsigned pvCountEstimate);
caStatus init(); //constructor does not return status
~caServerI();
@@ -854,18 +897,6 @@ public:
void removeClient(casStrmClient *pClient);
unsigned getMaxSimultaneousIO() const {return this->maxSimultaneousIO;}
//
// install a PV into the server
//
inline void installPV(casPVI &pv);
//
// remove PV from the server
//
inline void removePV(casPVI &pv);
//
// is there space for a new channel
//
@@ -878,20 +909,14 @@ public:
unsigned getDebugLevel() const { return debugLevel; }
inline void setDebugLevel(unsigned debugLevelIn);
inline pvExistReturn pvExistTest (const casCtx &ctx, const char *pPVName);
inline void pvExistTestCompletion();
inline aitBool pvExistTestPossible();
casPVI *createPV(const char *pName);
inline casPVExistReturn pvExistTest (const casCtx &ctx, const char *pPVName);
osiTime getBeaconPeriod() const { return this->beaconPeriod; }
void show(unsigned level);
void show(unsigned level) const;
inline casRes *lookupRes(const caResId &idIn, casResType type);
inline unsigned getPVMaxNameLength() const;
inline caServer *getAdapter();
inline void installItem(casRes &res);
@@ -913,27 +938,16 @@ private:
void advanceBeaconPeriod();
casDGOS dgClient;
casCtx ctx;
//casCtx ctx;
tsDLList<casStrmClient> clientList;
tsDLList<casIntfOS> intfList;
resTable<casPVI,stringId> stringResTbl;
osiTime beaconPeriod;
caServer &adapter;
unsigned pvCount;
unsigned debugLevel;
unsigned nExistTestInProg;
// max number of IO ops pending simultaneously
// (for operations that are not directed at a particular PV)
const unsigned pvMaxNameLength;
// the estimated number of proces variables default = ???
// the estimated number of proces variables default = 1024u
const unsigned pvCountEstimate;
// the maximum number of characters in a pv name
// default = none - required initialization parameter
const unsigned maxSimultaneousIO;
unsigned char haveBeenInitialized;
};
+4 -1
View File
@@ -6,6 +6,9 @@
*
*
* $Log$
* Revision 1.1 1996/11/02 01:01:27 jhill
* installed
*
* Revision 1.2 1996/08/05 19:28:49 jhill
* space became tab
*
@@ -19,7 +22,7 @@
//
// CA server
//
#include <server.h>
#include "server.h"
//
// casBeaconTimer
+2 -2
View File
@@ -10,8 +10,8 @@
//
// CA server
//
#include <server.h>
#include <casIODIL.h> // IO Depen in line func
#include "server.h"
#include "casIODIL.h" // IO Depen in line func
//
// casDGReadReg
+18 -7
View File
@@ -6,6 +6,9 @@
*
*
* $Log$
* Revision 1.1 1996/11/02 01:01:29 jhill
* installed
*
* Revision 1.3 1996/09/16 18:27:50 jhill
* vxWorks port changes
*
@@ -21,8 +24,8 @@
//
// CA server
//
#include <server.h>
#include <casClientIL.h>
#include "server.h"
#include "casClientIL.h"
class casDGEvWakeup : public osiTimer {
public:
@@ -71,12 +74,20 @@ void casDGEvWakeup::expire()
cond = this->os.eventSysProcess();
if (cond != casProcOk) {
//
// if "this" is being used above this
// routine on the stack then problems
// will result if we delete "this" here
// ok to delete the client here
// because casStreamEvWakeup::expire()
// is called by the timer queue system
// and therefore we are not being
// called from a client member function
// higher up on the stack
//
// delete &this->os;
ca_printf("DG event sys process failed\n");
this->os.destroy();
//
// must not touch the "this" pointer
// from this point on however
//
return;
}
}
+1 -1
View File
@@ -11,7 +11,7 @@
//
// CA server
//
#include <server.h>
#include "server.h"
//
// casServerReg
+5 -2
View File
@@ -7,6 +7,9 @@
// Some BSD calls have crept in here
//
// $Log$
// Revision 1.1 1996/11/02 01:01:32 jhill
// installed
//
// Revision 1.3 1996/09/04 22:04:07 jhill
// moved netdb.h include here
//
@@ -21,8 +24,8 @@
#ifndef includeCASOSDH
#define includeCASOSDH
#include <osiTimer.h>
#include <fdManager.h>
#include "osiTimer.h"
#include "fdManager.h"
class caServerI;
class caServerOS;
+52 -27
View File
@@ -4,6 +4,9 @@
//
//
// $Log$
// Revision 1.4 1996/12/12 21:24:17 jhill
// moved casStreamOS *pStrmOS decl down
//
// Revision 1.3 1996/12/12 19:02:36 jhill
// fixed send does not get armed after complete flush bug
//
@@ -26,10 +29,10 @@
//
// CA server
//
#include <server.h>
#include <casClientIL.h> // casClient inline func
#include <inBufIL.h> // inBuf inline func
#include <outBufIL.h> // outBuf inline func
#include "server.h"
#include "casClientIL.h" // casClient inline func
#include "inBufIL.h" // inBuf inline func
#include "outBufIL.h" // outBuf inline func
//
// casStreamReadReg
@@ -174,12 +177,20 @@ void casStreamEvWakeup::expire()
cond = this->os.casEventSys::process();
if (cond != casProcOk) {
//
// if "this" is being used above this
// routine on the stack then problems
// will result if we delete "this" here
// ok to delete the client here
// because casStreamEvWakeup::expire()
// is called by the timer queue system
// and therefore we are not being
// called from a client member function
// higher up on the stack
//
// delete &this->os;
ca_printf("strm event sys process failed\n");
this->os.destroy();
//
// must not touch the "this" pointer
// from this point on however
//
return;
}
}
@@ -506,21 +517,22 @@ void casStreamWriteReg::callBack()
// attempt to flush the output buffer
//
flushCond = os.flush();
switch (flushCond) {
case casFlushCompleted:
case casFlushPartial:
if ( flushCond==casFlushCompleted ||
flushCond==casFlushPartial) {
if (os.sendBlocked) {
os.sendBlocked = FALSE;
}
break;
case casFlushNone:
break;
case casFlushDisconnect:
}
else if (flushCond==casFlushDisconnect) {
return;
break;
default:
}
#if defined(DEBUG)
else if (flushCond==casFlushNone) {
}
else {
assert(0);
}
#endif
//
// If we are unable to flush out all of the events
@@ -531,7 +543,20 @@ void casStreamWriteReg::callBack()
//
procCond = this->os.casEventSys::process();
if (procCond != casProcOk) {
ca_printf("strm event sys process failed\n");
//
// ok to delete the client here
// because casStreamWriteReg::callBack()
// is called by the fdManager system
// and therefore we are not being
// called from a client member function
// higher up on the stack
//
this->os.destroy();
//
// must not touch "this" pointer
// after the destroy however
//
return;
}
# if defined(DEBUG)
@@ -592,20 +617,20 @@ casProcCond casStreamOS::processInput()
# endif
status = this->processMsg();
switch (status) {
case S_cas_sendBlocked:
case S_cas_partialMessage:
case S_cas_ioBlocked:
case S_cas_success:
if ( status==S_cas_success ||
status==S_cas_sendBlocked ||
status==S_casApp_postponeAsyncIO ||
status==S_cas_partialMessage) {
if (this->inBuf::bytesAvailable()==0u) {
this->armSend ();
}
this->armRecv();
return casProcOk;
break;
default:
}
else {
errMessage (status,
"unexpected problem with client's input - forcing disconnect");
"unexpected problem with client's input - forcing disconnect");
return casProcDisconnect;
}
}
+8 -3
View File
@@ -7,12 +7,15 @@
// (for single threaded version of the server)
//
// $Log$
// Revision 1.1 1996/11/02 01:01:34 jhill
// installed
//
//
#include <stdio.h>
#include <casdef.h>
#include <osiMutexNOOP.h>
#include "casdef.h"
#include "osiMutexNOOP.h"
//
@@ -35,7 +38,9 @@ ioBlocked::~ioBlocked()
//
void ioBlocked::ioBlockedSignal()
{
fprintf(stderr, "in virtual base ioBlocked::ioBlockedSignal() ?\n");
//
// NOOP
//
}
//
+1 -1
View File
@@ -2,5 +2,5 @@
//
// single threaded code NOOPs the mutex class
//
#include <osiMutexNOOP.h>
#include "osiMutexNOOP.h"
+3 -3
View File
@@ -10,9 +10,10 @@
#include "resourceLib.cc"
//
// Sun C++ 4.1 still appears to be lacking support in this area
// if the compiler supports explicit instantiation of
// template member functions
//
#if !defined(__SUNPRO_CC)
#if defined(EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
@@ -21,7 +22,6 @@
// functions into "templInst.o"
//
template class resTable <casEventMaskEntry, stringId>;
template class resTable <casPVI, stringId>;
template class resTable <casRes, uintId>;
#endif
+38 -30
View File
@@ -5,6 +5,9 @@
//
//
// $Log$
// Revision 1.3 1996/11/02 00:54:42 jhill
// many improvements
//
// Revision 1.2 1996/06/21 02:12:40 jhill
// SOLARIS port
//
@@ -15,10 +18,10 @@
#include <ctype.h>
#include <server.h>
#include <sigPipeIgnore.h>
#include "server.h"
#include "sigPipeIgnore.h"
static char *getToken(char **ppString);
static char *getToken(const char **ppString, char *pBuf, unsigned bufSIze);
int caServerIO::staticInitialized;
@@ -49,8 +52,8 @@ inline void caServerIO::staticInit()
//
caStatus caServerIO::init(caServerI &cas)
{
ENV_PARAM buf;
char *pStr;
char buf[64u];
const char *pStr;
char *pToken;
caStatus stat;
unsigned short port;
@@ -65,21 +68,30 @@ caStatus caServerIO::init(caServerI &cas)
// clients to find the server). If this also isnt available
// then use a hard coded default - CA_SERVER_PORT.
//
if (envParamIsEmpty(&EPICS_CAS_SERVER_PORT)) {
port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT);
if (envGetConfigParamPtr(&EPICS_CAS_SERVER_PORT)) {
port = caFetchPortConfig(&EPICS_CAS_SERVER_PORT, CA_SERVER_PORT);
}
else {
port = caFetchPortConfig(&EPICS_CAS_SERVER_PORT, CA_SERVER_PORT);
port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT);
}
memset((char *)&addr,0,sizeof(addr));
addr.sa.sa_family = AF_INET;
addr.in.sin_port = ntohs (port);
pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST,
sizeof(buf.dflt), buf.dflt);
if (strstr(pStr,"no")||strstr(pStr,"NO")) {
autoBeaconAddr = FALSE;
pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf);
if (pStr) {
if (strstr(pStr,"no")||strstr(pStr,"NO")) {
autoBeaconAddr = FALSE;
}
else if (strstr(pStr,"yes")||strstr(pStr,"YES")) {
autoBeaconAddr = TRUE;
}
else {
fprintf(stderr,
"CAS: EPICS_CA_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr);
autoBeaconAddr = TRUE;
}
}
else {
autoBeaconAddr = TRUE;
@@ -89,12 +101,11 @@ caStatus caServerIO::init(caServerI &cas)
// bind to the the interfaces specified - otherwise wildcard
// with INADDR_ANY and allow clients to attach from any interface
//
pStr = envGetConfigParam(&EPICS_CAS_INTF_ADDR_LIST,
sizeof(buf.dflt), buf.dflt);
pStr = envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST);
if (pStr) {
int configAddrOnceFlag = TRUE;
stat = S_cas_noInterface;
while ( (pToken = getToken(&pStr)) ) {
while ( (pToken = getToken(&pStr, buf, sizeof(buf))) ) {
addr.in.sin_addr.s_addr = inet_addr(pToken);
if (addr.in.sin_addr.s_addr == ~0ul) {
ca_printf(
@@ -136,35 +147,32 @@ void caServerIO::show (unsigned /* level */) const
//
// getToken()
//
static char *getToken(char **ppString)
static char *getToken(const char **ppString, char *pBuf, unsigned bufSIze)
{
char *pToken;
char *pStr;
const char *pToken;
unsigned i;
pToken = *ppString;
while(isspace(*pToken)&&*pToken){
pToken++;
}
pStr = pToken;
while(!isspace(*pStr)&&*pStr){
pStr++;
for (i=0u; i<bufSIze; i++) {
if (isspace(pToken[i]) || pToken[i]=='\0') {
pBuf[i] = '\0';
break;
}
pBuf[i] = pToken[i];
}
if(isspace(*pStr)){
*pStr = '\0';
*ppString = pStr+1;
}
else{
*ppString = pStr;
assert(*pStr == '\0');
}
*ppString = &pToken[i];
if(*pToken){
return pToken;
return pBuf;
}
else{
return NULL;
}
}
+2 -2
View File
@@ -28,8 +28,8 @@
* History
*/
#include <server.h>
#include <dgInBufIL.h> // in line func for dgInBuf
#include "server.h"
#include "dgInBufIL.h" // in line func for dgInBuf
//
// casDGIO::clientHostName()
+31 -9
View File
@@ -34,7 +34,7 @@
//
//
#include <server.h>
#include "server.h"
//
// casDGIntfIO::casDGIntfIO()
@@ -89,6 +89,28 @@ caStatus casDGIntfIO::init(const caAddr &addr, unsigned connectWithThisPortIn,
return S_cas_internal;
}
{
/*
*
* this allows for faster connects by queuing
* additional incomming UDP search frames
*
* this allocates a 32k buffer
* (uses a power of two)
*/
int size = 1u<<15u;
status = setsockopt(
this->sock,
SOL_SOCKET,
SO_RCVBUF,
(char *)&size,
sizeof(size));
if (status<0) {
errMessage(S_cas_internal,
"CAS: unable to set cast socket size\n");
}
}
/*
* release the port in case we exit early. Also if
* on a kernel with MULTICAST mods then we can have
@@ -109,12 +131,12 @@ caStatus casDGIntfIO::init(const caAddr &addr, unsigned connectWithThisPortIn,
//
// Fetch port configuration from EPICS environment variables
//
if (envParamIsEmpty(&EPICS_CAS_SERVER_PORT)) {
serverPort = caFetchPortConfig(&EPICS_CA_SERVER_PORT,
if (envGetConfigParamPtr(&EPICS_CAS_SERVER_PORT)) {
serverPort = caFetchPortConfig(&EPICS_CAS_SERVER_PORT,
CA_SERVER_PORT);
}
else {
serverPort = caFetchPortConfig(&EPICS_CAS_SERVER_PORT,
serverPort = caFetchPortConfig(&EPICS_CA_SERVER_PORT,
CA_SERVER_PORT);
}
beaconPort = caFetchPortConfig(&EPICS_CA_REPEATER_PORT,
@@ -168,14 +190,14 @@ caStatus casDGIntfIO::init(const caAddr &addr, unsigned connectWithThisPortIn,
* by default use EPICS_CA_ADDR_LIST for the
* beacon address list
*/
ENV_PARAM *pParam = &EPICS_CA_ADDR_LIST;
const ENV_PARAM *pParam;
if (envParamIsEmpty(&EPICS_CAS_INTF_ADDR_LIST) &&
envParamIsEmpty(&EPICS_CAS_BEACON_ADDR_LIST)) {
pParam = &EPICS_CA_ADDR_LIST;
if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) ||
envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) {
pParam = &EPICS_CAS_BEACON_ADDR_LIST;
}
else {
pParam = &EPICS_CAS_BEACON_ADDR_LIST;
pParam = &EPICS_CA_ADDR_LIST;
}
/*
+4 -1
View File
@@ -6,9 +6,12 @@
//
//
// $Log$
// Revision 1.1 1996/11/02 01:01:41 jhill
// installed
//
//
#include <server.h>
#include "server.h"
//
// 5 appears to be a TCP/IP built in maximum
+4 -1
View File
@@ -5,6 +5,9 @@
//
//
// $Log$
// Revision 1.8 1997/01/10 00:00:01 jhill
// close() => socket_close()
//
// Revision 1.7.2.1 1996/11/25 16:33:00 jhill
// close() => socket_close()
//
@@ -31,7 +34,7 @@
//
//
#include <server.h>
#include "server.h"
//
+41 -11
View File
@@ -11,19 +11,21 @@
#include <errno.h>
#include <string.h>
#include <sigPipeIgnore.h>
#include "sigPipeIgnore.h"
typedef void (*pSigFunc) ();
static pSigFunc pReplacedFunc;
#ifdef WIN32
#ifndef UNIX // all os except UNIX
void installSigPipeIgnore (void)
{
}
#else // WIN32
#else // it is UNIX
static void localInstallSigPipeIgnore (void);
/*
* ignoreSigPipe ()
@@ -33,6 +35,11 @@ static void ignoreSigPipe (int param)
if (pReplacedFunc) {
(*pReplacedFunc) (param);
}
/*
* some versios of unix reset to SIG_DFL
* each time that the signal occurs
*/
localInstallSigPipeIgnore ();
}
/*
@@ -45,15 +52,38 @@ void installSigPipeIgnore (void)
if (init) {
return;
}
pReplacedFunc = signal (SIGPIPE, ignoreSigPipe);
if (pReplacedFunc == SIG_ERR) {
char *pFmt = "replace of SIGPIPE failed beacuse\n";
fprintf (stderr, pFmt, __FILE__, strerror(errno));
}
localInstallSigPipeIgnore();
init = 1;
}
#endif // WIN32
/*
* localInstallSigPipeIgnore ()
*
* dont allow disconnect to terminate process
* when running in UNIX environment
*
* allow error to be returned to sendto()
* instead of handling disconnect at interrupt
*/
static void localInstallSigPipeIgnore (void)
{
pSigFunc sigRet;
sigRet = signal (SIGPIPE, ignoreSigPipe);
if (sigRet==SIG_ERR) {
fprintf (stderr, "%s replace of SIGPIPE failed beacuse %s\n",
__FILE__, strerror(errno));
}
else if (sigRet!=SIG_DFL && sigRet!=SIG_IGN) {
pReplacedFunc = sigRet;
}
/*
* no infinite loops
*/
if (pReplacedFunc==ignoreSigPipe) {
pReplacedFunc = NULL;
}
}
#endif // UNIX
+2
View File
@@ -5,6 +5,8 @@ INC += resourceLib.h
INC += resourceLib.cc
INC += tsDLList.h
INC += tsSLList.h
INC += tsBTree.h
INC += minmax.h
include $(TOP)/config/RULES.Host
+47
View File
@@ -6,4 +6,51 @@ resourceLib.h - hash table template
the test subdir contains examples
Since I am using templates the linked lists are type safe
(no casting of pointers ala ellList and dllList).
Also, the node class in embedded in the item on the
list (more efficent use of pool).
The file resourceLib.h provides a core hashing library
"resTable <itemClass, idClass>" where "itemClass" objects
are stored in the hash table and "idClass" is the data type
of the key for the hash table. The identifier class provides
the hash alg. I have provided simple string "stringId" and
unsigned integer "uintId" key types in resourceLib.h. It
is easy to implement a new key class.
There are examples under cxxTemplate/test. The list/hashing
templates all depend on a particular inheritance hierarchy.
If the inheritance hierarchy is wrong nothing will compile.
For instance, in tsDLList.h the template data type "T"
must derive from tsDLNode<T>. Likewise, in tsSLList.h
"T" must derive from tsSLNode<T>. Likewise, in resourceLib.h
class "T" (the type stored in the hash table) must derive
from class "ID" (the hash table key type) and also derive from
tsSLNode<T>.
So far, the only confusion I have run into with templates has been:
1) strange compiler messages - unrelated to cause of course -
when I get the class declaration order wrong (so that the
compiler has trouble instantiating the template).
2) sun pro/dec/att compilers use a template database and
gnu/msvc++ compilers use explicit template instantiation.
Therefore blocks of code of this sort are required:
#include "resourceLib.h" // template def
#include "resourceLib.cc" // template functions (that are not inline)
#if defined (EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
//
// This explicitly instantiates the template class's member
// functions into "templInst.o"
//
template class resTable<fred,uintId>;
template class resTable<jane,stringId>;
#endif
+22
View File
@@ -0,0 +1,22 @@
//
// simple inline template functions to replace the min() and max()
// macros
//
//
// ??? g++ 2.7.2 -Winline is unable to in line these tiny functions ???
//
template <class T>
inline const T &max(const T &a, const T &b)
{
return (a>b) ? a : b;
}
template <class T>
inline const T &min(const T &a, const T &b)
{
return (a<b) ? a : b;
}
+76 -15
View File
@@ -30,6 +30,9 @@
*
* History
* $Log$
* Revision 1.2 1996/12/06 22:26:34 jhill
* added auto cleanup of installed classes to destroy
*
* Revision 1.1 1996/11/02 01:07:48 jhill
* installed
*
@@ -83,31 +86,37 @@ void resTable<T,ID>::destroyAllEntries()
tsSLList<T> *pList = this->pTable;
while (pList<&this->pTable[this->hashIdMask+1]) {
tsSLIter<T> iter(*pList);
T *pItem;
T *pNextItem;
pItem = iter();
while (pItem) {
pNextItem = iter();
delete pItem;
pItem = pNextItem;
{
tsSLIter<T> iter(*pList);
pItem = iter();
while (pItem) {
pNextItem = iter();
pItem->destroy();
pItem = pNextItem;
}
}
//
// Check to see if a defective class is
// installed that does not remove itself
// from the table when it is destroyed.
//
iter.reset();
while ( (pItem=iter()) ) {
fprintf(stderr,
{
tsSLIterRm<T> iter(*pList);
while ( (pItem=iter()) ) {
fprintf(stderr,
"Warning: Defective class still in resTable<T,ID> after it was destroyed\n");
//
// remove defective class
//
iter.remove();
this->nInUse--;
//
// remove defective class
//
iter.remove();
this->nInUse--;
}
}
pList++;
}
}
@@ -116,7 +125,7 @@ void resTable<T,ID>::destroyAllEntries()
// resTable<T,ID>::show
//
template <class T, class ID>
void resTable<T,ID>::show (unsigned level)
void resTable<T,ID>::show (unsigned level) const
{
tsSLList<T> *pList;
double X;
@@ -160,5 +169,57 @@ void resTable<T,ID>::show (unsigned level)
}
}
//
// resTable<T,ID>::traverse
//
// pCB is a pointer to a member function
//
template <class T, class ID>
void resTable<T,ID>::traverse (void (T::*pCB)())
{
tsSLList<T> *pList;
pList = this->pTable;
while (pList < &this->pTable[this->hashIdMask+1]) {
tsSLIter<T> iter(*pList);
T *pItem;
while ( (pItem = iter()) ) {
(pItem->*pCB) ();
}
pList++;
}
}
//
// this needs to be instanciated only once (normally in libCom)
//
#ifdef INSTANCIATE_RES_LIB_STATIC
//
// The hash algorithm is a modification of the algorithm described in
// Fast Hashing of Variable Length Text Strings, Peter K. Pearson,
// Communications of the ACM, June 1990
// The modifications were designed by Marty Kraimer
//
unsigned char stringId::T[256] = {
39,159,180,252, 71, 6, 13,164,232, 35,226,155, 98,120,154, 69,
157, 24,137, 29,147, 78,121, 85,112, 8,248,130, 55,117,190,160,
176,131,228, 64,211,106, 38, 27,140, 30, 88,210,227,104, 84, 77,
75,107,169,138,195,184, 70, 90, 61,166, 7,244,165,108,219, 51,
9,139,209, 40, 31,202, 58,179,116, 33,207,146, 76, 60,242,124,
254,197, 80,167,153,145,129,233,132, 48,246, 86,156,177, 36,187,
45, 1, 96, 18, 19, 62,185,234, 99, 16,218, 95,128,224,123,253,
42,109, 4,247, 72, 5,151,136, 0,152,148,127,204,133, 17, 14,
182,217, 54,199,119,174, 82, 57,215, 41,114,208,206,110,239, 23,
189, 15, 3, 22,188, 79,113,172, 28, 2,222, 21,251,225,237,105,
102, 32, 56,181,126, 83,230, 53,158, 52, 59,213,118,100, 67,142,
220,170,144,115,205, 26,125,168,249, 66,175, 97,255, 92,229, 91,
214,236,178,243, 46, 44,201,250,135,186,150,221,163,216,162, 43,
11,101, 34, 37,194, 25, 50, 12, 87,198,173,240,193,171,143,231,
111,141,191,103, 74,245,223, 20,161,235,122, 63, 89,149, 73,238,
134, 68, 93,183,241, 81,196, 49,192, 65,212, 94,203, 10,200, 47
};
#endif // INSTANCIATE_RES_LIB_STATIC
#endif // INCresourceLibcc
+164 -58
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.7 1996/12/06 22:26:36 jhill
* added auto cleanup of installed classes to destroy
*
* Revision 1.6 1996/11/02 01:07:17 jhill
* many improvements
*
@@ -69,7 +72,7 @@ typedef unsigned resTableIndex;
#define resTableIndexBitWidth (sizeof(resTableIndex)*CHAR_BIT)
//
// class T must derive class ID
// class T must derive from class ID and also from class tsSLNode<T>
//
// NOTE: Classes installed into this table should have
// a virtual destructor so that the delete in ~resTable() will
@@ -78,8 +81,6 @@ typedef unsigned resTableIndex;
template <class T, class ID>
class resTable {
public:
enum resTableDelFlag {rtdfDelete, rtdfNoDelete};
resTable() :
pTable(0), hashIdMask(0), hashIdNBits(0), nInUse(0) {}
@@ -94,10 +95,19 @@ public:
}
}
//
// destroy all res in the table
//
void destroyAllEntries();
void show (unsigned level);
//
// call T::show(level) for each res in the table
//
void show (unsigned level) const;
//
// add a res to the table
//
int add (T &res)
{
//
@@ -113,19 +123,34 @@ public:
return 0;
}
//
// remove a res from the table
//
T *remove (const ID &idIn)
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->find(list, idIn, rtdfDelete);
return this->findDelete(list, idIn);
}
//
// find an res in the table
//
T *lookup (const ID &idIn)
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->find(list, idIn);
}
//
// Call (pT->*pCB) () for each item in the table
//
// where pT is a pointer to type T and pCB is
// a pointer to a memmber function of T with
// no parameters and returning void
//
void traverse(void (T::*pCB)());
private:
tsSLList<T> *pTable;
unsigned hashIdMask;
@@ -147,8 +172,7 @@ private:
// iterator points to the item found upon return
// (or NULL if nothing matching was found)
//
T *find (tsSLList<T> &list, const ID &idIn,
resTableDelFlag df=rtdfNoDelete)
T *find (tsSLList<T> &list, const ID &idIn)
{
tsSLIter<T> iter(list);
T *pItem;
@@ -157,10 +181,33 @@ private:
while ( (pItem = iter()) ) {
pId = pItem;
if (*pId == idIn) {
if (df==rtdfDelete) {
iter.remove();
this->nInUse--;
}
break;
}
}
return pItem;
}
//
// findDelete
// searches from where the iterator points to the
// end of the list for idIn
//
// iterator points to the item found upon return
// (or NULL if nothing matching was found)
//
// removes the item if it finds it
//
T *findDelete (tsSLList<T> &list, const ID &idIn)
{
tsSLIterRm<T> iter(list);
T *pItem;
ID *pId;
while ( (pItem = iter()) ) {
pId = pItem;
if (*pId == idIn) {
iter.remove();
this->nInUse--;
break;
}
}
@@ -211,16 +258,6 @@ protected:
unsigned id;
};
//
// resource with unsigned chronological identifier
//
template <class ITEM>
class uintRes : public uintId, public tsSLNode<ITEM> {
friend class uintResTable<ITEM>;
public:
uintRes(unsigned idIn=UINT_MAX) : uintId(idIn) {}
};
//
// special resource table which uses
// unsigned integer keys allocated in chronological sequence
@@ -232,24 +269,39 @@ class uintResTable : public resTable<ITEM, uintId> {
public:
uintResTable() : allocId(1u) {} // hashing is faster close to zero
//
// NOTE: This detects (and avoids) the case where
// the PV id wraps around and we attempt to have two
// resources with the same id.
//
void installItem(ITEM &item)
{
int resTblStatus;
do {
item.uintId::id = this->allocId++;
resTblStatus = this->add(item);
}
while (resTblStatus);
}
inline void installItem(ITEM &item);
private:
unsigned allocId;
};
//
// resource with unsigned chronological identifier
//
template <class ITEM>
class uintRes : public uintId, public tsSLNode<ITEM> {
friend class uintResTable<ITEM>;
public:
uintRes(unsigned idIn=UINT_MAX) : uintId(idIn) {}
};
//
// uintRes<ITEM>::installItem()
//
// NOTE: This detects (and avoids) the case where
// the PV id wraps around and we attempt to have two
// resources with the same id.
//
template <class ITEM>
inline void uintResTable<ITEM>::installItem(ITEM &item)
{
int resTblStatus;
do {
item.uintRes<ITEM>::id = allocId++;
resTblStatus = this->add(item);
}
while (resTblStatus);
}
//
// pointer identifier
//
@@ -292,40 +344,89 @@ private:
//
// character string identifier
//
// NOTE: to be robust in situations where the new()
// in the constructor might fail a careful consumer
// of this class should check to see if the
// stringId::resourceName() below
// returns a valid (non--NULL) string pointer.
// Eventually an exception will be thrown if
// new fails (when this is portable).
//
class stringId {
public:
stringId (char const * const idIn) :
pStr(new char [strlen(idIn)+1u])
enum allocationType {copyString, refString};
//
// allocCopyString()
//
static inline char * allocCopyString(const char * const pStr)
{
if (this->pStr!=NULL) {
strcpy(this->pStr, idIn);
char *pNewStr = new char [strlen(pStr)+1u];
if (pNewStr) {
strcpy (pNewStr, pStr);
}
return pNewStr;
}
//
// stringId() constructor
//
// Use typeIn==refString only if the string passed in will exist
// and remain constant during the entire lifespan of the stringId
// object.
//
stringId (char const * const idIn, allocationType typeIn=copyString) :
pStr(typeIn==copyString?allocCopyString(idIn):idIn),
allocType(typeIn) {}
~ stringId()
{
if (this->pStr!=NULL) {
delete [] this->pStr;
if (this->allocType==copyString) {
if (this->pStr!=NULL) {
delete [] (char *) this->pStr;
}
}
}
//
// The hash algorithm is a modification of the algorithm described in
// Fast Hashing of Variable Length Text Strings, Peter K. Pearson,
// Communications of the ACM, June 1990
// The modifications were designed by Marty Kraimer
//
resTableIndex resourceHash(unsigned nBitsId) const
{
resTableIndex hashid;
unsigned i;
if (this->pStr==NULL) {
return 0u;
}
hashid = 0u;
for (i=0u; this->pStr[i]; i++) {
hashid += this->pStr[i] * (i+1u);
unsigned h0 = 0u;
unsigned h1 = 0u;
unsigned c;
unsigned i;
for (i=0u; (c = this->pStr[i]); i++) {
//
// odd
//
if (i&1u) {
h1 = this->T[h1 ^ c];
}
//
// even
//
else {
h0 = this->T[h0 ^ c];
}
}
hashid = hashid % (1u<<nBitsId);
return hashid;
//
// does not work well for more than 65k entries ?
// (because some indexes in the table will not be produced)
//
if (nBitsId>=8u) {
h1 = h1 << (nBitsId-8u);
}
return h1 ^ h0;
}
int operator == (const stringId &idIn)
@@ -338,22 +439,27 @@ public:
}
}
//
// return the pointer to the string
// (also used to test to see if "new()"
// failed in the constructor
//
const char * resourceName()
{
return this->pStr;
}
void show (unsigned)
void show (unsigned level) const
{
printf ("resource id = %s\n", this->pStr);
if (level>2u) {
printf ("resource id = %s\n", this->pStr);
}
}
private:
char * const pStr;
const char * const pStr;
allocationType const allocType;
static unsigned char T[256];
};
#if defined(__SUNPRO_CC) || defined(EXPAND_TEMPLATES_HERE)
# include "resourceLib.cc"
#endif
#endif // INCresourceLibh
+3 -1
View File
@@ -2,8 +2,10 @@
TOP = ../../../..
include $(TOP)/config/CONFIG_BASE
CXXCMPLR = STRICT
TESTPROD := resourceLibTest tsDLListBench tsDLListTest tsDLListTest \
tsSLListBench tsSLListTest
tsSLListBench tsSLListTest minmaxTest
include $(TOP)/config/RULES.Host
+28
View File
@@ -0,0 +1,28 @@
#include <assert.h>
#include "minmax.h"
main ()
{
float f1 = 3.3;
float f2 = 3.4;
float f3;
f3 = min(f1,f2);
assert(f3==f1);
f3 = max(f1,f2);
assert(f3==f2);
int i1 = 3;
int i2 = 4;
int i3;
i3 = min(i1,i2);
assert(i3==i1);
i3 = max(i1,i2);
assert(i3==i2);
}
+28 -6
View File
@@ -5,6 +5,7 @@
#include <stdio.h>
#include "resourceLib.h"
#define INSTANCIATE_RES_LIB_STATIC
#include "resourceLib.cc"
#ifdef SUNOS4
@@ -21,6 +22,10 @@ public:
{
printf("fred %s\n", pName);
}
void destroy()
{
// always on stack so noop
}
private:
const char * const pName;
};
@@ -28,12 +33,28 @@ private:
class jane : public stringId, public tsSLNode<jane> {
public:
jane (const char *pNameIn) : stringId(pNameIn) {}
void testTraverse();
void destroy()
{
// always on stack so noop
}
};
//
// Sun C++ 4.1 still appears to be lacking support in this area
// jane::testTraverse()
//
#if !defined(__SUNPRO_CC)
void jane::testTraverse()
{
printf("Traverse Test\n");
this->show(10);
}
//
// explicitly instantiates on compilers that support this
//
#if defined(EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
@@ -55,14 +76,14 @@ main()
resTable<jane,stringId> strTbl;
fred fred1("fred1",0x1000a432);
fred fred2("fred2",0x0000a432);
jane jane1("jane1");
jane jane2("jane2");
jane jane1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
jane jane2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
fred *pFred;
jane *pJane;
uintId uintId1(0x1000a432);
uintId uintId2(0x0000a432);
stringId strId1("jane1");
stringId strId2("jane2");
stringId strId1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
stringId strId2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
int status;
status = intTbl.init(8);
@@ -157,6 +178,7 @@ main()
printf("It took %15.10f u sec per string hash lookup\n", duration);
strTbl.show(10u);
strTbl.traverse(&jane::testTraverse);
strTbl.remove(strId1);
strTbl.remove(strId2);
-2
View File
@@ -40,7 +40,6 @@ main ()
}
clk = clock();
iter = list;
while ( (pFred = iter()) ) {
pFred->inc();
}
@@ -52,7 +51,6 @@ main ()
pFred = new fred();
clk = clock();
iter = list;
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
+4 -4
View File
@@ -70,18 +70,18 @@ main ()
pJane->show();
}
iter = list;
iter.reset();
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
iter = list;
iter.reset();
while ( (pFredBack = iter()) ) {
iter.remove();
}
assert(list.count()==0);
janeFwdIter = janeList;
janeFwdIter.reset();
while ( (pFredBack = janeFwdIter()) ) {
janeFwdIter.remove();
}
@@ -91,7 +91,7 @@ main ()
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
janeBwdIter = janeList;
janeBwdIter.reset();
while ( (pFredBack = janeBwdIter()) ) {
janeBwdIter.remove();
}
+10 -7
View File
@@ -32,7 +32,6 @@ private:
main ()
{
tsSLList<fred> list;
tsSLIter<fred> iter(list);
fred *pFred;
unsigned i;
clock_t clk;
@@ -45,9 +44,11 @@ main ()
}
clk = clock();
iter = list;
while ( (pFred = iter()) ) {
pFred->inc();
{
tsSLIter<fred> iter(list);
while ( (pFred = iter()) ) {
pFred->inc();
}
}
diff = clock() - clk;
delay = diff;
@@ -57,9 +58,11 @@ main ()
pFred = new fred();
clk = clock();
iter = list;
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
{
tsSLIter<fred> iter(list);
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
}
diff = clock() - clk;
delay = diff;
+35 -17
View File
@@ -22,12 +22,10 @@ private:
main ()
{
tsSLList<fred> list;
tsSLIter<fred> iter(list);
fred *pFred;
fred *pFredII;
fred *pFredBack;
tsSLList<jane> janeList;
tsSLIter<jane> janeIter(janeList);
jane *pJane;
pFred = new fred("A");
@@ -35,8 +33,11 @@ main ()
list.add(*pFred);
list.add(*pFredII);
pFredBack = iter();
assert(pFredBack == pFredII);
{
tsSLIter<fred> iter(list);
pFredBack = iter();
assert(pFredBack == pFredII);
}
list.remove(*pFredII); // removes *pFred !!
list.add(*pFred);
pFredBack = list.get();
@@ -45,9 +46,11 @@ main ()
assert (pFredBack == pFredII);
list.add(*pFredII);
list.add(*pFred);
iter.reset();
while ( (pFredBack = iter()) ) {
iter.remove();
{
tsSLIterRm<fred> iter(list);
while ( (pFredBack = iter()) ) {
iter.remove();
}
}
pFredBack = list.get();
assert (pFredBack == 0);
@@ -56,8 +59,11 @@ main ()
list.add(* new fred("C"));
list.add(* new fred("D"));
while ( (pFredBack = iter()) ) {
pFredBack->show();
{
tsSLIter<fred> iter(list);
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
}
pJane = new jane("JA");
@@ -65,19 +71,31 @@ main ()
pJane = new jane("JB");
janeList.add(*pJane);
while ( (pJane = janeIter()) ) {
pJane->show();
{
tsSLIter<jane> janeIter(janeList);
while ( (pJane = janeIter()) ) {
pJane->show();
}
}
while ( (pFredBack = iter()) ) {
pFredBack->show();
{
tsSLIter<fred> iter(list);
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
}
while ( (pFredBack = iter()) ) {
iter.remove();
{
tsSLIterRm<fred> iter(list);
while ( (pFredBack = iter()) ) {
iter.remove();
}
}
pFredBack = iter();
assert(pFredBack==NULL);
{
tsSLIter<fred> iter(list);
pFredBack = iter();
assert(pFredBack==NULL);
}
}
+145 -48
View File
@@ -31,6 +31,9 @@
*
* History
* $Log$
* Revision 1.6 1997/01/22 21:13:49 jhill
* fixed class decl order for VMS
*
* Revision 1.5 1996/11/02 01:07:19 jhill
* many improvements
*
@@ -54,10 +57,12 @@
//
// tsDLNode<T>
// NOTE: T must derive from tsDLNode<T>
//
template <class T>
class tsDLNode {
friend class tsDLList<T>;
friend class tsDLIterBD<T>;
friend class tsDLIter<T>;
friend class tsDLFwdIter<T>;
friend class tsDLBwdIter<T>;
@@ -79,6 +84,7 @@ private:
//
// tsDLList<T>
// NOTE: T must derive from tsDLNode<T>
//
template <class T>
class tsDLList {
@@ -293,9 +299,10 @@ public:
// and the node number (beginning with zero if
// it is)
//
int find(T &item);
int find(T &item) const;
T *first(void) const { return pFirst; }
T *first(void) const { return this->pFirst; }
T *last(void) const { return this->pLast; }
protected:
T *getFirst(void) const { return pFirst; }
@@ -306,6 +313,98 @@ private:
unsigned itemCount;
};
//
// tsDLIterBD<T>
// (a bi-directional iterator in the style of the STL)
//
template <class T>
class tsDLIterBD {
public:
tsDLIterBD () :
pEntry(0) {}
tsDLIterBD (T *pInitialEntry) :
pEntry(pInitialEntry) {}
tsDLIterBD (class tsDLIterBD<T> &copyIn) :
pEntry(copyIn.pEntry) {}
tsDLIterBD<T> & operator = (T *pNewEntry)
{
this->pEntry = pNewEntry;
return *this;
}
tsDLIterBD<T> &operator = (const tsDLIterBD<T> &copyIn)
{
this->pEntry = copyIn.pEntry;
return *this;
}
int operator == (const tsDLIterBD<T> &rhs) const
{
return (this->pEntry == rhs.pEntry);
}
int operator != (const tsDLIterBD<T> &rhs) const
{
return (this->pEntry != rhs.pEntry);
}
T & operator * () const
{
return *this->pEntry;
}
T * operator -> () const
{
return this->pEntry;
}
operator T* () const
{
return this->pEntry;
}
//
// prefix ++
//
T *operator ++ ()
{
return this->pEntry = this->pEntry->tsDLNode<T>::pNext;
}
//
// postfix ++
//
T *operator ++ (int)
{
T *pE = this->pEntry;
this->pEntry = this->pEntry->tsDLNode<T>::pNext;
return pE;
}
//
// prefix --
//
T *operator -- ()
{
return this->pEntry = pEntry->tsDLNode<T>::pPrev;
}
//
// postfix --
//
T *operator -- (int)
{
T *pE = this->pEntry;
this->pEntry = pEntry->tsDLNode<T>::pPrev;
return pE;
}
private:
T *pEntry;
};
//
// tsDLIter<T>
//
@@ -320,7 +419,7 @@ private:
template <class T>
class tsDLIter {
public:
tsDLIter (const tsDLList<T> &listIn) :
tsDLIter (const tsDLList<T> & listIn) :
pCurrent(0), pList(&listIn) {}
void reset ()
@@ -328,28 +427,28 @@ public:
this->pCurrent = 0;
}
void reset (tsDLList<T> &listIn)
{
this->reset();
this->pList = &listIn;
}
void reset (tsDLList<T> &listIn)
{
this->reset();
this->pList = &listIn;
}
void operator = (tsDLList<T> &listIn)
{
this->reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->reset(listIn);
}
T * next ()
{
T *pCur = this->pCurrent;
if (pCur==0) {
pCur = this->pList->pFirst;
}
else {
pCur = pCur->tsDLNode<T>::pNext;
}
this->pCurrent = pCur;
return pCur;
T *pCur = this->pCurrent;
if (pCur==0) {
pCur = this->pList->pFirst;
}
else {
pCur = pCur->tsDLNode<T>::pNext;
}
this->pCurrent = pCur;
return pCur;
}
T * prev ()
@@ -383,8 +482,8 @@ public:
}
protected:
T *pCurrent;
const tsDLList<T> *pList;
T *pCurrent;
const tsDLList<T> *pList;
};
//
@@ -412,14 +511,14 @@ public:
{
this->tsDLIter<T>::reset();
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
T * operator () ()
{
return this->tsDLIter<T>::next();
@@ -448,9 +547,10 @@ public:
if (pCur) {
//
// strip const
// strip const (we didnt declare the
// list const in the constructor)
//
tsDLList<T> *pMutableList =
tsDLList<T> * pMutableList =
(tsDLList<T> *) this->pList;
//
@@ -487,18 +587,14 @@ public:
tsDLBwdIter(tsDLList<T> &listIn) :
tsDLIter<T>(listIn) {}
void reset ()
{
this->tsDLIter<T>::reset();
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
T * operator () ()
{
return this->tsDLIter<T>::prev();
@@ -528,9 +624,10 @@ public:
if (pCur) {
//
// strip const
// strip const (we didnt declare the
// list const in the constructor)
//
tsDLList<T> *pMutableList =
tsDLList<T> * pMutableList =
(tsDLList<T> *) this->pList;
//
@@ -555,7 +652,7 @@ public:
// it is)
//
template <class T>
inline int tsDLList<T>::find(T &item)
inline int tsDLList<T>::find(T &item) const
{
tsDLFwdIter<T> iter(*this);
tsDLNode<T> *pItem;
+64 -40
View File
@@ -31,6 +31,9 @@
*
* History
* $Log$
* Revision 1.6 1997/01/22 21:14:21 jhill
* fixed class decl order for VMS
*
* Revision 1.5 1996/11/02 01:07:20 jhill
* many improvements
*
@@ -49,17 +52,15 @@
*
*/
#ifndef assert // allows epicsAssert.h
#include <assert.h>
#endif
//
// tsSLNode<>
// NOTE: T must derive from tsSLNode<T>
//
template <class T>
class tsSLNode {
friend class tsSLList<T>;
friend class tsSLIter<T>;
friend class tsSLIterRm<T>;
public:
tsSLNode() : pNext(0) {}
@@ -76,6 +77,7 @@ private:
//
// tsSLList<>
// NOTE: T must derive from tsSLNode<T>
//
template <class T>
class tsSLList : public tsSLNode<T> {
@@ -138,6 +140,9 @@ public:
//
// tsSLIter<T>
//
// A simple fast single link linked list iterator
// (which must not be called again after it returns NULL)
//
// Notes:
// 1) No direct access to pCurrent is provided since
// this might allow for confusion when an item
@@ -146,40 +151,22 @@ public:
//
template <class T>
class tsSLIter {
friend class tsSLIterRm<T>;
public:
tsSLIter(tsSLList<T> &listIn) :
pCurrent(0), pPrevious(0), pList(&listIn) {}
void reset()
{
this->pCurrent = 0;
this->pPrevious = 0;
}
void reset (tsSLList<T> &listIn)
{
this->pList = &listIn;
this->reset();
}
void operator = (tsSLList<T> &listIn)
{
this->reset(listIn);
}
tsSLIter(const tsSLList<T> &listIn) : pCurrent(&listIn) {}
//
// move iterator forward
//
// **** NOTE ****
// This may be called continuously until it returns
// NULL. Attempts to call this again after it has
// returned NULL will fail
//
T * next ()
{
T *pNewCur;
if (this->pCurrent) {
this->pPrevious = this->pCurrent;
}
else {
this->pPrevious = this->pList;
}
this->pCurrent = pNewCur = this->pPrevious->pNext;
this->pCurrent = pNewCur = this->pCurrent->pNext;
return pNewCur;
}
@@ -191,6 +178,48 @@ public:
return this->next();
}
private:
const tsSLNode<T> *pCurrent;
};
//
// tsSLIterRm<T>
// (A tsSLIter<T> that allows removing a node)
//
// adds remove method (and does not construct
// with const list)
//
// Notes:
// 1) No direct access to pCurrent is provided since
// this might allow for confusion when an item
// is removed (and pCurrent ends up pointing at
// an item that has been seen before)
//
//
template <class T>
class tsSLIterRm : private tsSLIter<T> {
public:
tsSLIterRm(tsSLList<T> &listIn) :
tsSLIter<T>(listIn), pPrevious(0) {}
//
// move iterator forward
//
T * next ()
{
// strip const
this->pPrevious = (tsSLNode<T> *) this->pCurrent;
return tsSLIter<T>::next();
}
//
// move iterator forward
//
T * operator () ()
{
return this->tsSLIterRm<T>::next();
}
//
// remove current node
// (and move current to be the previos item -
@@ -203,20 +232,15 @@ public:
// This may be called once for each cycle of the
// iterator. Attempts to call this twice without
// moving the iterator forward inbetween the two
// calls will assert fail
// calls will fail
//
void remove ()
{
if (this->pCurrent) {
assert(this->pPrevious);
this->pPrevious->pNext = this->pCurrent->pNext;
this->pCurrent = this->pPrevious;
this->pPrevious = 0;
}
this->pPrevious->pNext = this->pCurrent->pNext;
this->pCurrent = this->pPrevious;
this->pPrevious = 0;
}
private:
tsSLNode<T> *pCurrent;
tsSLNode<T> *pPrevious;
tsSLList<T> *pList;
tsSLNode<T> *pPrevious;
};
+47
View File
@@ -6,4 +6,51 @@ resourceLib.h - hash table template
the test subdir contains examples
Since I am using templates the linked lists are type safe
(no casting of pointers ala ellList and dllList).
Also, the node class in embedded in the item on the
list (more efficent use of pool).
The file resourceLib.h provides a core hashing library
"resTable <itemClass, idClass>" where "itemClass" objects
are stored in the hash table and "idClass" is the data type
of the key for the hash table. The identifier class provides
the hash alg. I have provided simple string "stringId" and
unsigned integer "uintId" key types in resourceLib.h. It
is easy to implement a new key class.
There are examples under cxxTemplate/test. The list/hashing
templates all depend on a particular inheritance hierarchy.
If the inheritance hierarchy is wrong nothing will compile.
For instance, in tsDLList.h the template data type "T"
must derive from tsDLNode<T>. Likewise, in tsSLList.h
"T" must derive from tsSLNode<T>. Likewise, in resourceLib.h
class "T" (the type stored in the hash table) must derive
from class "ID" (the hash table key type) and also derive from
tsSLNode<T>.
So far, the only confusion I have run into with templates has been:
1) strange compiler messages - unrelated to cause of course -
when I get the class declaration order wrong (so that the
compiler has trouble instantiating the template).
2) sun pro/dec/att compilers use a template database and
gnu/msvc++ compilers use explicit template instantiation.
Therefore blocks of code of this sort are required:
#include "resourceLib.h" // template def
#include "resourceLib.cc" // template functions (that are not inline)
#if defined (EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
//
// This explicitly instantiates the template class's member
// functions into "templInst.o"
//
template class resTable<fred,uintId>;
template class resTable<jane,stringId>;
#endif
+164 -58
View File
@@ -29,6 +29,9 @@
*
* History
* $Log$
* Revision 1.7 1996/12/06 22:26:36 jhill
* added auto cleanup of installed classes to destroy
*
* Revision 1.6 1996/11/02 01:07:17 jhill
* many improvements
*
@@ -69,7 +72,7 @@ typedef unsigned resTableIndex;
#define resTableIndexBitWidth (sizeof(resTableIndex)*CHAR_BIT)
//
// class T must derive class ID
// class T must derive from class ID and also from class tsSLNode<T>
//
// NOTE: Classes installed into this table should have
// a virtual destructor so that the delete in ~resTable() will
@@ -78,8 +81,6 @@ typedef unsigned resTableIndex;
template <class T, class ID>
class resTable {
public:
enum resTableDelFlag {rtdfDelete, rtdfNoDelete};
resTable() :
pTable(0), hashIdMask(0), hashIdNBits(0), nInUse(0) {}
@@ -94,10 +95,19 @@ public:
}
}
//
// destroy all res in the table
//
void destroyAllEntries();
void show (unsigned level);
//
// call T::show(level) for each res in the table
//
void show (unsigned level) const;
//
// add a res to the table
//
int add (T &res)
{
//
@@ -113,19 +123,34 @@ public:
return 0;
}
//
// remove a res from the table
//
T *remove (const ID &idIn)
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->find(list, idIn, rtdfDelete);
return this->findDelete(list, idIn);
}
//
// find an res in the table
//
T *lookup (const ID &idIn)
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->find(list, idIn);
}
//
// Call (pT->*pCB) () for each item in the table
//
// where pT is a pointer to type T and pCB is
// a pointer to a memmber function of T with
// no parameters and returning void
//
void traverse(void (T::*pCB)());
private:
tsSLList<T> *pTable;
unsigned hashIdMask;
@@ -147,8 +172,7 @@ private:
// iterator points to the item found upon return
// (or NULL if nothing matching was found)
//
T *find (tsSLList<T> &list, const ID &idIn,
resTableDelFlag df=rtdfNoDelete)
T *find (tsSLList<T> &list, const ID &idIn)
{
tsSLIter<T> iter(list);
T *pItem;
@@ -157,10 +181,33 @@ private:
while ( (pItem = iter()) ) {
pId = pItem;
if (*pId == idIn) {
if (df==rtdfDelete) {
iter.remove();
this->nInUse--;
}
break;
}
}
return pItem;
}
//
// findDelete
// searches from where the iterator points to the
// end of the list for idIn
//
// iterator points to the item found upon return
// (or NULL if nothing matching was found)
//
// removes the item if it finds it
//
T *findDelete (tsSLList<T> &list, const ID &idIn)
{
tsSLIterRm<T> iter(list);
T *pItem;
ID *pId;
while ( (pItem = iter()) ) {
pId = pItem;
if (*pId == idIn) {
iter.remove();
this->nInUse--;
break;
}
}
@@ -211,16 +258,6 @@ protected:
unsigned id;
};
//
// resource with unsigned chronological identifier
//
template <class ITEM>
class uintRes : public uintId, public tsSLNode<ITEM> {
friend class uintResTable<ITEM>;
public:
uintRes(unsigned idIn=UINT_MAX) : uintId(idIn) {}
};
//
// special resource table which uses
// unsigned integer keys allocated in chronological sequence
@@ -232,24 +269,39 @@ class uintResTable : public resTable<ITEM, uintId> {
public:
uintResTable() : allocId(1u) {} // hashing is faster close to zero
//
// NOTE: This detects (and avoids) the case where
// the PV id wraps around and we attempt to have two
// resources with the same id.
//
void installItem(ITEM &item)
{
int resTblStatus;
do {
item.uintId::id = this->allocId++;
resTblStatus = this->add(item);
}
while (resTblStatus);
}
inline void installItem(ITEM &item);
private:
unsigned allocId;
};
//
// resource with unsigned chronological identifier
//
template <class ITEM>
class uintRes : public uintId, public tsSLNode<ITEM> {
friend class uintResTable<ITEM>;
public:
uintRes(unsigned idIn=UINT_MAX) : uintId(idIn) {}
};
//
// uintRes<ITEM>::installItem()
//
// NOTE: This detects (and avoids) the case where
// the PV id wraps around and we attempt to have two
// resources with the same id.
//
template <class ITEM>
inline void uintResTable<ITEM>::installItem(ITEM &item)
{
int resTblStatus;
do {
item.uintRes<ITEM>::id = allocId++;
resTblStatus = this->add(item);
}
while (resTblStatus);
}
//
// pointer identifier
//
@@ -292,40 +344,89 @@ private:
//
// character string identifier
//
// NOTE: to be robust in situations where the new()
// in the constructor might fail a careful consumer
// of this class should check to see if the
// stringId::resourceName() below
// returns a valid (non--NULL) string pointer.
// Eventually an exception will be thrown if
// new fails (when this is portable).
//
class stringId {
public:
stringId (char const * const idIn) :
pStr(new char [strlen(idIn)+1u])
enum allocationType {copyString, refString};
//
// allocCopyString()
//
static inline char * allocCopyString(const char * const pStr)
{
if (this->pStr!=NULL) {
strcpy(this->pStr, idIn);
char *pNewStr = new char [strlen(pStr)+1u];
if (pNewStr) {
strcpy (pNewStr, pStr);
}
return pNewStr;
}
//
// stringId() constructor
//
// Use typeIn==refString only if the string passed in will exist
// and remain constant during the entire lifespan of the stringId
// object.
//
stringId (char const * const idIn, allocationType typeIn=copyString) :
pStr(typeIn==copyString?allocCopyString(idIn):idIn),
allocType(typeIn) {}
~ stringId()
{
if (this->pStr!=NULL) {
delete [] this->pStr;
if (this->allocType==copyString) {
if (this->pStr!=NULL) {
delete [] (char *) this->pStr;
}
}
}
//
// The hash algorithm is a modification of the algorithm described in
// Fast Hashing of Variable Length Text Strings, Peter K. Pearson,
// Communications of the ACM, June 1990
// The modifications were designed by Marty Kraimer
//
resTableIndex resourceHash(unsigned nBitsId) const
{
resTableIndex hashid;
unsigned i;
if (this->pStr==NULL) {
return 0u;
}
hashid = 0u;
for (i=0u; this->pStr[i]; i++) {
hashid += this->pStr[i] * (i+1u);
unsigned h0 = 0u;
unsigned h1 = 0u;
unsigned c;
unsigned i;
for (i=0u; (c = this->pStr[i]); i++) {
//
// odd
//
if (i&1u) {
h1 = this->T[h1 ^ c];
}
//
// even
//
else {
h0 = this->T[h0 ^ c];
}
}
hashid = hashid % (1u<<nBitsId);
return hashid;
//
// does not work well for more than 65k entries ?
// (because some indexes in the table will not be produced)
//
if (nBitsId>=8u) {
h1 = h1 << (nBitsId-8u);
}
return h1 ^ h0;
}
int operator == (const stringId &idIn)
@@ -338,22 +439,27 @@ public:
}
}
//
// return the pointer to the string
// (also used to test to see if "new()"
// failed in the constructor
//
const char * resourceName()
{
return this->pStr;
}
void show (unsigned)
void show (unsigned level) const
{
printf ("resource id = %s\n", this->pStr);
if (level>2u) {
printf ("resource id = %s\n", this->pStr);
}
}
private:
char * const pStr;
const char * const pStr;
allocationType const allocType;
static unsigned char T[256];
};
#if defined(__SUNPRO_CC) || defined(EXPAND_TEMPLATES_HERE)
# include "resourceLib.cc"
#endif
#endif // INCresourceLibh
@@ -0,0 +1,28 @@
#include <assert.h>
#include "minmax.h"
main ()
{
float f1 = 3.3;
float f2 = 3.4;
float f3;
f3 = min(f1,f2);
assert(f3==f1);
f3 = max(f1,f2);
assert(f3==f2);
int i1 = 3;
int i2 = 4;
int i3;
i3 = min(i1,i2);
assert(i3==i1);
i3 = max(i1,i2);
assert(i3==i2);
}
@@ -5,6 +5,7 @@
#include <stdio.h>
#include "resourceLib.h"
#define INSTANCIATE_RES_LIB_STATIC
#include "resourceLib.cc"
#ifdef SUNOS4
@@ -21,6 +22,10 @@ public:
{
printf("fred %s\n", pName);
}
void destroy()
{
// always on stack so noop
}
private:
const char * const pName;
};
@@ -28,12 +33,28 @@ private:
class jane : public stringId, public tsSLNode<jane> {
public:
jane (const char *pNameIn) : stringId(pNameIn) {}
void testTraverse();
void destroy()
{
// always on stack so noop
}
};
//
// Sun C++ 4.1 still appears to be lacking support in this area
// jane::testTraverse()
//
#if !defined(__SUNPRO_CC)
void jane::testTraverse()
{
printf("Traverse Test\n");
this->show(10);
}
//
// explicitly instantiates on compilers that support this
//
#if defined(EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
@@ -55,14 +76,14 @@ main()
resTable<jane,stringId> strTbl;
fred fred1("fred1",0x1000a432);
fred fred2("fred2",0x0000a432);
jane jane1("jane1");
jane jane2("jane2");
jane jane1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
jane jane2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
fred *pFred;
jane *pJane;
uintId uintId1(0x1000a432);
uintId uintId2(0x0000a432);
stringId strId1("jane1");
stringId strId2("jane2");
stringId strId1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
stringId strId2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
int status;
status = intTbl.init(8);
@@ -157,6 +178,7 @@ main()
printf("It took %15.10f u sec per string hash lookup\n", duration);
strTbl.show(10u);
strTbl.traverse(&jane::testTraverse);
strTbl.remove(strId1);
strTbl.remove(strId2);
@@ -40,7 +40,6 @@ main ()
}
clk = clock();
iter = list;
while ( (pFred = iter()) ) {
pFred->inc();
}
@@ -52,7 +51,6 @@ main ()
pFred = new fred();
clk = clock();
iter = list;
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
+4 -4
View File
@@ -70,18 +70,18 @@ main ()
pJane->show();
}
iter = list;
iter.reset();
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
iter = list;
iter.reset();
while ( (pFredBack = iter()) ) {
iter.remove();
}
assert(list.count()==0);
janeFwdIter = janeList;
janeFwdIter.reset();
while ( (pFredBack = janeFwdIter()) ) {
janeFwdIter.remove();
}
@@ -91,7 +91,7 @@ main ()
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
janeBwdIter = janeList;
janeBwdIter.reset();
while ( (pFredBack = janeBwdIter()) ) {
janeBwdIter.remove();
}
+10 -7
View File
@@ -32,7 +32,6 @@ private:
main ()
{
tsSLList<fred> list;
tsSLIter<fred> iter(list);
fred *pFred;
unsigned i;
clock_t clk;
@@ -45,9 +44,11 @@ main ()
}
clk = clock();
iter = list;
while ( (pFred = iter()) ) {
pFred->inc();
{
tsSLIter<fred> iter(list);
while ( (pFred = iter()) ) {
pFred->inc();
}
}
diff = clock() - clk;
delay = diff;
@@ -57,9 +58,11 @@ main ()
pFred = new fred();
clk = clock();
iter = list;
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
{
tsSLIter<fred> iter(list);
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
}
diff = clock() - clk;
delay = diff;
+35 -17
View File
@@ -22,12 +22,10 @@ private:
main ()
{
tsSLList<fred> list;
tsSLIter<fred> iter(list);
fred *pFred;
fred *pFredII;
fred *pFredBack;
tsSLList<jane> janeList;
tsSLIter<jane> janeIter(janeList);
jane *pJane;
pFred = new fred("A");
@@ -35,8 +33,11 @@ main ()
list.add(*pFred);
list.add(*pFredII);
pFredBack = iter();
assert(pFredBack == pFredII);
{
tsSLIter<fred> iter(list);
pFredBack = iter();
assert(pFredBack == pFredII);
}
list.remove(*pFredII); // removes *pFred !!
list.add(*pFred);
pFredBack = list.get();
@@ -45,9 +46,11 @@ main ()
assert (pFredBack == pFredII);
list.add(*pFredII);
list.add(*pFred);
iter.reset();
while ( (pFredBack = iter()) ) {
iter.remove();
{
tsSLIterRm<fred> iter(list);
while ( (pFredBack = iter()) ) {
iter.remove();
}
}
pFredBack = list.get();
assert (pFredBack == 0);
@@ -56,8 +59,11 @@ main ()
list.add(* new fred("C"));
list.add(* new fred("D"));
while ( (pFredBack = iter()) ) {
pFredBack->show();
{
tsSLIter<fred> iter(list);
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
}
pJane = new jane("JA");
@@ -65,19 +71,31 @@ main ()
pJane = new jane("JB");
janeList.add(*pJane);
while ( (pJane = janeIter()) ) {
pJane->show();
{
tsSLIter<jane> janeIter(janeList);
while ( (pJane = janeIter()) ) {
pJane->show();
}
}
while ( (pFredBack = iter()) ) {
pFredBack->show();
{
tsSLIter<fred> iter(list);
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
}
while ( (pFredBack = iter()) ) {
iter.remove();
{
tsSLIterRm<fred> iter(list);
while ( (pFredBack = iter()) ) {
iter.remove();
}
}
pFredBack = iter();
assert(pFredBack==NULL);
{
tsSLIter<fred> iter(list);
pFredBack = iter();
assert(pFredBack==NULL);
}
}
+145 -48
View File
@@ -31,6 +31,9 @@
*
* History
* $Log$
* Revision 1.6 1997/01/22 21:13:49 jhill
* fixed class decl order for VMS
*
* Revision 1.5 1996/11/02 01:07:19 jhill
* many improvements
*
@@ -54,10 +57,12 @@
//
// tsDLNode<T>
// NOTE: T must derive from tsDLNode<T>
//
template <class T>
class tsDLNode {
friend class tsDLList<T>;
friend class tsDLIterBD<T>;
friend class tsDLIter<T>;
friend class tsDLFwdIter<T>;
friend class tsDLBwdIter<T>;
@@ -79,6 +84,7 @@ private:
//
// tsDLList<T>
// NOTE: T must derive from tsDLNode<T>
//
template <class T>
class tsDLList {
@@ -293,9 +299,10 @@ public:
// and the node number (beginning with zero if
// it is)
//
int find(T &item);
int find(T &item) const;
T *first(void) const { return pFirst; }
T *first(void) const { return this->pFirst; }
T *last(void) const { return this->pLast; }
protected:
T *getFirst(void) const { return pFirst; }
@@ -306,6 +313,98 @@ private:
unsigned itemCount;
};
//
// tsDLIterBD<T>
// (a bi-directional iterator in the style of the STL)
//
template <class T>
class tsDLIterBD {
public:
tsDLIterBD () :
pEntry(0) {}
tsDLIterBD (T *pInitialEntry) :
pEntry(pInitialEntry) {}
tsDLIterBD (class tsDLIterBD<T> &copyIn) :
pEntry(copyIn.pEntry) {}
tsDLIterBD<T> & operator = (T *pNewEntry)
{
this->pEntry = pNewEntry;
return *this;
}
tsDLIterBD<T> &operator = (const tsDLIterBD<T> &copyIn)
{
this->pEntry = copyIn.pEntry;
return *this;
}
int operator == (const tsDLIterBD<T> &rhs) const
{
return (this->pEntry == rhs.pEntry);
}
int operator != (const tsDLIterBD<T> &rhs) const
{
return (this->pEntry != rhs.pEntry);
}
T & operator * () const
{
return *this->pEntry;
}
T * operator -> () const
{
return this->pEntry;
}
operator T* () const
{
return this->pEntry;
}
//
// prefix ++
//
T *operator ++ ()
{
return this->pEntry = this->pEntry->tsDLNode<T>::pNext;
}
//
// postfix ++
//
T *operator ++ (int)
{
T *pE = this->pEntry;
this->pEntry = this->pEntry->tsDLNode<T>::pNext;
return pE;
}
//
// prefix --
//
T *operator -- ()
{
return this->pEntry = pEntry->tsDLNode<T>::pPrev;
}
//
// postfix --
//
T *operator -- (int)
{
T *pE = this->pEntry;
this->pEntry = pEntry->tsDLNode<T>::pPrev;
return pE;
}
private:
T *pEntry;
};
//
// tsDLIter<T>
//
@@ -320,7 +419,7 @@ private:
template <class T>
class tsDLIter {
public:
tsDLIter (const tsDLList<T> &listIn) :
tsDLIter (const tsDLList<T> & listIn) :
pCurrent(0), pList(&listIn) {}
void reset ()
@@ -328,28 +427,28 @@ public:
this->pCurrent = 0;
}
void reset (tsDLList<T> &listIn)
{
this->reset();
this->pList = &listIn;
}
void reset (tsDLList<T> &listIn)
{
this->reset();
this->pList = &listIn;
}
void operator = (tsDLList<T> &listIn)
{
this->reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->reset(listIn);
}
T * next ()
{
T *pCur = this->pCurrent;
if (pCur==0) {
pCur = this->pList->pFirst;
}
else {
pCur = pCur->tsDLNode<T>::pNext;
}
this->pCurrent = pCur;
return pCur;
T *pCur = this->pCurrent;
if (pCur==0) {
pCur = this->pList->pFirst;
}
else {
pCur = pCur->tsDLNode<T>::pNext;
}
this->pCurrent = pCur;
return pCur;
}
T * prev ()
@@ -383,8 +482,8 @@ public:
}
protected:
T *pCurrent;
const tsDLList<T> *pList;
T *pCurrent;
const tsDLList<T> *pList;
};
//
@@ -412,14 +511,14 @@ public:
{
this->tsDLIter<T>::reset();
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
T * operator () ()
{
return this->tsDLIter<T>::next();
@@ -448,9 +547,10 @@ public:
if (pCur) {
//
// strip const
// strip const (we didnt declare the
// list const in the constructor)
//
tsDLList<T> *pMutableList =
tsDLList<T> * pMutableList =
(tsDLList<T> *) this->pList;
//
@@ -487,18 +587,14 @@ public:
tsDLBwdIter(tsDLList<T> &listIn) :
tsDLIter<T>(listIn) {}
void reset ()
{
this->tsDLIter<T>::reset();
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
void operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
T * operator () ()
{
return this->tsDLIter<T>::prev();
@@ -528,9 +624,10 @@ public:
if (pCur) {
//
// strip const
// strip const (we didnt declare the
// list const in the constructor)
//
tsDLList<T> *pMutableList =
tsDLList<T> * pMutableList =
(tsDLList<T> *) this->pList;
//
@@ -555,7 +652,7 @@ public:
// it is)
//
template <class T>
inline int tsDLList<T>::find(T &item)
inline int tsDLList<T>::find(T &item) const
{
tsDLFwdIter<T> iter(*this);
tsDLNode<T> *pItem;
+64 -40
View File
@@ -31,6 +31,9 @@
*
* History
* $Log$
* Revision 1.6 1997/01/22 21:14:21 jhill
* fixed class decl order for VMS
*
* Revision 1.5 1996/11/02 01:07:20 jhill
* many improvements
*
@@ -49,17 +52,15 @@
*
*/
#ifndef assert // allows epicsAssert.h
#include <assert.h>
#endif
//
// tsSLNode<>
// NOTE: T must derive from tsSLNode<T>
//
template <class T>
class tsSLNode {
friend class tsSLList<T>;
friend class tsSLIter<T>;
friend class tsSLIterRm<T>;
public:
tsSLNode() : pNext(0) {}
@@ -76,6 +77,7 @@ private:
//
// tsSLList<>
// NOTE: T must derive from tsSLNode<T>
//
template <class T>
class tsSLList : public tsSLNode<T> {
@@ -138,6 +140,9 @@ public:
//
// tsSLIter<T>
//
// A simple fast single link linked list iterator
// (which must not be called again after it returns NULL)
//
// Notes:
// 1) No direct access to pCurrent is provided since
// this might allow for confusion when an item
@@ -146,40 +151,22 @@ public:
//
template <class T>
class tsSLIter {
friend class tsSLIterRm<T>;
public:
tsSLIter(tsSLList<T> &listIn) :
pCurrent(0), pPrevious(0), pList(&listIn) {}
void reset()
{
this->pCurrent = 0;
this->pPrevious = 0;
}
void reset (tsSLList<T> &listIn)
{
this->pList = &listIn;
this->reset();
}
void operator = (tsSLList<T> &listIn)
{
this->reset(listIn);
}
tsSLIter(const tsSLList<T> &listIn) : pCurrent(&listIn) {}
//
// move iterator forward
//
// **** NOTE ****
// This may be called continuously until it returns
// NULL. Attempts to call this again after it has
// returned NULL will fail
//
T * next ()
{
T *pNewCur;
if (this->pCurrent) {
this->pPrevious = this->pCurrent;
}
else {
this->pPrevious = this->pList;
}
this->pCurrent = pNewCur = this->pPrevious->pNext;
this->pCurrent = pNewCur = this->pCurrent->pNext;
return pNewCur;
}
@@ -191,6 +178,48 @@ public:
return this->next();
}
private:
const tsSLNode<T> *pCurrent;
};
//
// tsSLIterRm<T>
// (A tsSLIter<T> that allows removing a node)
//
// adds remove method (and does not construct
// with const list)
//
// Notes:
// 1) No direct access to pCurrent is provided since
// this might allow for confusion when an item
// is removed (and pCurrent ends up pointing at
// an item that has been seen before)
//
//
template <class T>
class tsSLIterRm : private tsSLIter<T> {
public:
tsSLIterRm(tsSLList<T> &listIn) :
tsSLIter<T>(listIn), pPrevious(0) {}
//
// move iterator forward
//
T * next ()
{
// strip const
this->pPrevious = (tsSLNode<T> *) this->pCurrent;
return tsSLIter<T>::next();
}
//
// move iterator forward
//
T * operator () ()
{
return this->tsSLIterRm<T>::next();
}
//
// remove current node
// (and move current to be the previos item -
@@ -203,20 +232,15 @@ public:
// This may be called once for each cycle of the
// iterator. Attempts to call this twice without
// moving the iterator forward inbetween the two
// calls will assert fail
// calls will fail
//
void remove ()
{
if (this->pCurrent) {
assert(this->pPrevious);
this->pPrevious->pNext = this->pCurrent->pNext;
this->pCurrent = this->pPrevious;
this->pPrevious = 0;
}
this->pPrevious->pNext = this->pCurrent->pNext;
this->pCurrent = this->pPrevious;
this->pPrevious = 0;
}
private:
tsSLNode<T> *pCurrent;
tsSLNode<T> *pPrevious;
tsSLList<T> *pList;
tsSLNode<T> *pPrevious;
};