API changes
This commit is contained in:
@@ -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).
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
// Example EPICS CA server
|
||||
//
|
||||
|
||||
#include <exServer.h>
|
||||
#include "exServer.h"
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ©In) :
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
#include <exServer.h>
|
||||
#include <gddApps.h>
|
||||
#include "exServer.h"
|
||||
#include "gddApps.h"
|
||||
|
||||
#define myPI 3.14159265358979323846
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 ®, 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);
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
//
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,5 +1,5 @@
|
||||
|
||||
#include <casdef.h>
|
||||
#include "casdef.h"
|
||||
|
||||
//
|
||||
// this needs to be here (and not in casOpaqueAddrIL.h) if we
|
||||
|
||||
+10
-18
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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,8 +2,8 @@
|
||||
#ifndef dgInBufILh
|
||||
#define dgInBufILh
|
||||
|
||||
#include <casOpaqueAddrIL.h>
|
||||
#include <inBufIL.h>
|
||||
#include "casOpaqueAddrIL.h"
|
||||
#include "inBufIL.h"
|
||||
|
||||
//
|
||||
// dgInBuf::clear()
|
||||
|
||||
@@ -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,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
@@ -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 ®In,
|
||||
casEventMask maskIn, const char *pName);
|
||||
virtual ~casEventMaskEntry();
|
||||
void show (unsigned level);
|
||||
void show (unsigned level) const;
|
||||
|
||||
virtual void destroy();
|
||||
private:
|
||||
casEventRegistry ®
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//
|
||||
// CA server
|
||||
//
|
||||
#include <server.h>
|
||||
#include "server.h"
|
||||
|
||||
//
|
||||
// casServerReg
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
//
|
||||
// single threaded code NOOPs the mutex class
|
||||
//
|
||||
#include <osiMutexNOOP.h>
|
||||
#include "osiMutexNOOP.h"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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> ©In) :
|
||||
pEntry(copyIn.pEntry) {}
|
||||
|
||||
tsDLIterBD<T> & operator = (T *pNewEntry)
|
||||
{
|
||||
this->pEntry = pNewEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tsDLIterBD<T> &operator = (const tsDLIterBD<T> ©In)
|
||||
{
|
||||
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
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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> ©In) :
|
||||
pEntry(copyIn.pEntry) {}
|
||||
|
||||
tsDLIterBD<T> & operator = (T *pNewEntry)
|
||||
{
|
||||
this->pEntry = pNewEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tsDLIterBD<T> &operator = (const tsDLIterBD<T> ©In)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user