ca server installation

This commit is contained in:
Jeff Hill
1996-06-20 00:28:19 +00:00
parent 14f53d7844
commit 4697f951b9
94 changed files with 18021 additions and 0 deletions

26
src/cas/.ftp Normal file
View File

@@ -0,0 +1,26 @@
open aota1
user jeffhill
prompt
macdef archcd
lcd O.sun4
mkdir [.cas]
cd [.cas]
lcd ~/epics/base/src/cas
mput *.c
mput *.h
lcd os/vms
mput *.c
mput *.h
put BUILD_VMS.COM
lcd ../../../libCom
mput *.c
mput *.h
$archcd
mput *.c
lcd ../../ca
mput *.h
mput *.c
lcd ../../include
mput *.h

11
src/cas/.ftp2 Normal file
View File

@@ -0,0 +1,11 @@
open aota1
user jeffhill
mkdir [.cas]
cd [.cas]
prompt
lcd ~/epics/base/src/cas
lcd os/vms
put BUILD_VMS.COM
lcd ../../../libCom
lcd ../ca
lcd ../../include

21
src/cas/Makefile Normal file
View File

@@ -0,0 +1,21 @@
#
# $Id$
#
# Lowest Level Directroy Makefile
# by Janet Anderson
#
# $Log$
# Revision 1.1 1994/09/07 19:26:34 jba
# New file
#
#
EPICS=../../..
include $(EPICS)/config/CONFIG_BASE
DIRS = build example
include $(EPICS)/config/RULES_ARCHS

62
src/cas/Makefile.Unix Normal file
View File

@@ -0,0 +1,62 @@
EPICS = ../../../..
SRC = ..
IOTYPE = bsdSocket
OSTYPE = posix
include Target.include
include $(EPICS)/config/CONFIG_BASE
USR_INCLUDES = -I../../ca -I../os/$(OSTYPE) -I../io/$(IOTYPE) -I../gdd -I../gdd/sun4
USR_LDLIBS = -lcas -lm
USR_LDFLAGS = -L.
DEPLIBS_BASE = $(EPICS_BASE_LIB)
GDDLIB = ../gdd/sun4/libgdd.a
#DEPLIBS = $(DEPLIBS_BASE)/libca.a $(DEPLIBS_BASE)/libCom.a $(DEPLIBS_BASE)/libDb.a $(DEPLIBS_BASE)/libCom.a $(GDDLIB)
DEPLIBS = $(DEPLIBS_BASE)/libca.a $(DEPLIBS_BASE)/libCom.a $(GDDLIB)
#CPLUSPLUS = G++
SRCS.cc += $(SRC)/caServer.cc
SRCS.cc += $(SRC)/casClient.cc
SRCS.cc += $(SRC)/casDGClient.cc
SRCS.cc += $(SRC)/casStreamClient.cc
SRCS.cc += $(SRC)/casPV.cc
SRCS.cc += $(SRC)/casPVI.cc
SRCS.cc += $(SRC)/casChannel.cc
SRCS.cc += $(SRC)/casChannelI.cc
SRCS.cc += $(SRC)/casClientMon.cc
SRCS.cc += $(SRC)/casMsgIO.cc
SRCS.cc += $(SRC)/casAsyncIO.cc
SRCS.cc += $(SRC)/casAsyncIOI.cc
SRCS.cc += $(SRC)/casEventSys.cc
SRCS.cc += $(SRC)/outBuf.cc
SRCS.cc += $(SRC)/inBuf.cc
SRCS.cc += $(SRC)/casMapDBR.cc
LIBOBJS += caServer.o
LIBOBJS += casClient.o
LIBOBJS += casDGClient.o
LIBOBJS += casStreamClient.o
LIBOBJS += casPV.o
LIBOBJS += casPVI.o
LIBOBJS += casChannel.o
LIBOBJS += casChannelI.o
LIBOBJS += casClientMon.o
LIBOBJS += casMsgIO.o
LIBOBJS += casAsyncIO.o
LIBOBJS += casAsyncIOI.o
LIBOBJS += casEventSys.o
LIBOBJS += outBuf.o
LIBOBJS += inBuf.o
LIBOBJS += casMapDBR.o
LIBNAME = libcas.a
include $(EPICS)/config/RULES.Unix
obj: $(LIBOBJS)
clean::
@$(RM) -rf Templates.DB

29
src/cas/README Normal file
View File

@@ -0,0 +1,29 @@
$Id$
README file for the EPICS Channel Access Server
Author Jeff Hill johill@lanl.gov
$Log$
Directory Structure
-------------------
o example - example server tool
o generic - generic server lib source code
o os - os dependnet server lib source code
o io - io dependnet server lib source code
o build - server lib object code
Internal Source Code Naming Conventions
---------------------------------------
o API class X will almost always have associated internal (usually
private base) class named XI
o for class X there will be
o X.h - the class declaration (and simple inlines)
o XIL.h - complex inline functions (that will not
compile with until the compiler has seen
the declarations of other classes)
o X.cc - all other source code for the class

21
src/cas/build/Makefile Normal file
View File

@@ -0,0 +1,21 @@
#
# $Id$
#
# Lowest Level Directroy Makefile
# by Janet Anderson
#
# $Log$
# Revision 1.1 1994/09/07 19:26:34 jba
# New file
#
#
EPICS=../../../..
include $(EPICS)/config/CONFIG_BASE
DIRS = posix-sockets
include $(EPICS)/config/RULES_ARCHS

View File

@@ -0,0 +1,78 @@
EPICS = ../../../..
CAS = ../../..
SRC = $(CAS)/generic
IOSRC = $(CAS)/io/bsdSocket
OSSRC = $(CAS)/os/posix
VPATH = $(SRC) $(IOSRC) $(OSSRC)
include Target.include
include $(EPICS)/config/CONFIG_BASE
USR_INCLUDES = -I$(CAS)/../ca -I$(OSSRC) -I$(IOSRC) -I$(CAS)/gdd
USR_LDLIBS = -lcas -lm
USR_LDFLAGS = -L.
DEPLIBS_BASE = $(EPICS_BASE_LIB)
#CPLUSPLUS = G++
SRCS.cc += $(SRC)/caServer.cc
SRCS.cc += $(SRC)/casClient.cc
SRCS.cc += $(SRC)/casDGClient.cc
SRCS.cc += $(SRC)/casStreamClient.cc
SRCS.cc += $(SRC)/casPV.cc
SRCS.cc += $(SRC)/casPVI.cc
SRCS.cc += $(SRC)/casChannel.cc
SRCS.cc += $(SRC)/casChannelI.cc
SRCS.cc += $(SRC)/casClientMon.cc
SRCS.cc += $(SRC)/casMsgIO.cc
SRCS.cc += $(SRC)/casAsyncIO.cc
SRCS.cc += $(SRC)/casAsyncIOI.cc
SRCS.cc += $(SRC)/casEventSys.cc
SRCS.cc += $(SRC)/outBuf.cc
SRCS.cc += $(SRC)/inBuf.cc
SRCS.cc += $(SRC)/casMapDBR.cc
SRCS.cc += $(OSSRC)/casDGOS.cc
SRCS.cc += $(OSSRC)/casServerOS.cc
SRCS.cc += $(OSSRC)/casStreamOS.cc
SRCS.cc += $(IOSRC)/casDGIO.cc
SRCS.cc += $(IOSRC)/casStreamIO.cc
SRCS.cc += $(IOSRC)/caServerIO.cc
LIBOBJS += caServer.o
LIBOBJS += casClient.o
LIBOBJS += casDGClient.o
LIBOBJS += casStreamClient.o
LIBOBJS += casPV.o
LIBOBJS += casPVI.o
LIBOBJS += casChannel.o
LIBOBJS += casChannelI.o
LIBOBJS += casClientMon.o
LIBOBJS += casMsgIO.o
LIBOBJS += casAsyncIO.o
LIBOBJS += casAsyncIOI.o
LIBOBJS += casEventSys.o
LIBOBJS += outBuf.o
LIBOBJS += inBuf.o
LIBOBJS += casMapDBR.o
LIBOBJS += casDGOS.o
LIBOBJS += casServerOS.o
LIBOBJS += casStreamOS.o
LIBOBJS += casDGIO.o
LIBOBJS += casStreamIO.o
LIBOBJS += caServerIO.o
LIBNAME = libcas.a
include $(EPICS)/config/RULES.Unix
obj: $(LIBOBJS)
clean::
@$(RM) -rf Templates.DB

View File

@@ -0,0 +1,19 @@
#
# $Id$
#
# Lowest Level Directroy Makefile
# by Janet Anderson
#
# $Log$
# Revision 1.1 1994/09/07 19:26:34 jba
# New file
#
#
EPICS=../../../../../
include $(EPICS)/config/CONFIG_BASE
include $(EPICS)/config/RULES_ARCHS

View File

@@ -0,0 +1,86 @@
EPICS = ../../../../../..
CAS = ../../..
SRC = $(CAS)/generic
IOSRC = $(CAS)/io/bsdSocket
OSSRC = $(CAS)/os/posix
VPATH = $(SRC) $(IOSRC) $(OSSRC)
include Target.include
include $(EPICS)/config/CONFIG_BASE
USR_INCLUDES = -I$(SRC) -I$(CAS)/../ca -I$(OSSRC) -I$(IOSRC) -I$(CAS)/gdd
DEPLIBS_BASE = $(EPICS_BASE_LIB)
INC += casdef.h
INC += caProto.h
INC += casEventMask.h
INC += casInternal.h
INC += gddAppFuncTable.h
SRCS.cc += $(SRC)/caServer.cc
SRCS.cc += $(SRC)/caServerI.cc
SRCS.cc += $(SRC)/casCoreClient.cc
SRCS.cc += $(SRC)/casClient.cc
SRCS.cc += $(SRC)/casDGClient.cc
SRCS.cc += $(SRC)/casStrmClient.cc
SRCS.cc += $(SRC)/casPV.cc
SRCS.cc += $(SRC)/casPVI.cc
SRCS.cc += $(SRC)/casChannel.cc
SRCS.cc += $(SRC)/casChannelI.cc
SRCS.cc += $(SRC)/casClientMon.cc
SRCS.cc += $(SRC)/casChanDeleteEvent.cc
SRCS.cc += $(SRC)/casMsgIO.cc
SRCS.cc += $(SRC)/casAsyncIO.cc
SRCS.cc += $(SRC)/casAsyncIOI.cc
SRCS.cc += $(SRC)/casEventSys.cc
SRCS.cc += $(SRC)/outBuf.cc
SRCS.cc += $(SRC)/inBuf.cc
SRCS.cc += $(SRC)/casMapDBR.cc
SRCS.cc += $(OSSRC)/caServerOS.cc
SRCS.cc += $(OSSRC)/casDGOS.cc
SRCS.cc += $(OSSRC)/casStreamOS.cc
SRCS.cc += $(IOSRC)/caServerIO.cc
SRCS.cc += $(IOSRC)/casDGIO.cc
SRCS.cc += $(IOSRC)/casStreamIO.cc
LIBOBJS += caServer.o
LIBOBJS += caServerI.o
LIBOBJS += casCoreClient.o
LIBOBJS += casClient.o
LIBOBJS += casDGClient.o
LIBOBJS += casStrmClient.o
LIBOBJS += casPV.o
LIBOBJS += casPVI.o
LIBOBJS += casChannel.o
LIBOBJS += casChannelI.o
LIBOBJS += casClientMon.o
LIBOBJS += casChanDeleteEvent.o
LIBOBJS += casMsgIO.o
LIBOBJS += casAsyncIO.o
LIBOBJS += casAsyncIOI.o
LIBOBJS += casEventSys.o
LIBOBJS += outBuf.o
LIBOBJS += inBuf.o
LIBOBJS += casMapDBR.o
LIBOBJS += caServerOS.o
LIBOBJS += casDGOS.o
LIBOBJS += casStreamOS.o
LIBOBJS += caServerIO.o
LIBOBJS += casDGIO.o
LIBOBJS += casStreamIO.o
LIBNAME = libcas.a
include $(EPICS)/config/RULES.Unix
obj: $(LIBOBJS)
clean::
@$(RM) -rf Templates.DB

18
src/cas/example/Makefile Normal file
View File

@@ -0,0 +1,18 @@
#
# $Id$
#
# Lowest Level Directroy Makefile
# by Janet Anderson
#
# $Log$
# Revision 1.1 1994/09/07 19:26:34 jba
# New file
#
#
EPICS=../../../..
include $(EPICS)/config/CONFIG_BASE
include $(EPICS)/config/RULES_ARCHS

View File

@@ -0,0 +1,92 @@
EPICS = ../../../../..
CAS = ../../
include Target.include
include $(EPICS)/config/CONFIG_BASE
#CPLUSPLUS = G++
GDD = $(CAS)/gdd
CAS_INCLUDES = -I$(CAS)/generic -I$(CAS)/../ca
USR_INCLUDES = -I$(GDD) $(CAS_INCLUDES)
ifeq ($(CPLUSPLUS),G++)
USR_LDLIBS = -lca -lCom -lgdd -lm -liberty
else
USR_LDLIBS = -lca -lCom -lgdd -lm
endif
USR_LDFLAGS = -L$(GDD)/sun4/
DEPLIBS_BASE = $(EPICS_BASE_LIB)
DEPLIBS = $(DEPLIBS_BASE)/libca.a $(DEPLIBS_BASE)/libCom.a $(GDD)/sun4/libgdd.a
SRCS.cc += ../exServer.cc
SRCS.cc += ../exPV.cc
SRCS.cc += ../exSyncPV.cc
SRCS.cc += ../exAsyncPV.cc
SRCS.cc += ../exChannel.cc
OBJS += exServer.o
OBJS += exPV.o
OBJS += exSyncPV.o
OBJS += exAsyncPV.o
OBJS += exChannel.o
#PROD += excas
include $(EPICS)/config/RULES.Unix
BUILDDIR = $(CAS)/build/singleThread/O.sun4/
GLOMBOBJ += $(BUILDDIR)caServer.o
GLOMBOBJ += $(BUILDDIR)caServerI.o
GLOMBOBJ += $(BUILDDIR)casCoreClient.o
GLOMBOBJ += $(BUILDDIR)casClient.o
GLOMBOBJ += $(BUILDDIR)casDGClient.o
GLOMBOBJ += $(BUILDDIR)casStrmClient.o
GLOMBOBJ += $(BUILDDIR)casPV.o
GLOMBOBJ += $(BUILDDIR)casPVI.o
GLOMBOBJ += $(BUILDDIR)casChannel.o
GLOMBOBJ += $(BUILDDIR)casChannelI.o
GLOMBOBJ += $(BUILDDIR)casClientMon.o
GLOMBOBJ += $(BUILDDIR)casChanDelEv.o
GLOMBOBJ += $(BUILDDIR)casMsgIO.o
GLOMBOBJ += $(BUILDDIR)casAsyncIO.o
GLOMBOBJ += $(BUILDDIR)casAsyncIOI.o
GLOMBOBJ += $(BUILDDIR)casEventSys.o
GLOMBOBJ += $(BUILDDIR)casMonitor.o
GLOMBOBJ += $(BUILDDIR)casMonEvent.o
GLOMBOBJ += $(BUILDDIR)outBuf.o
GLOMBOBJ += $(BUILDDIR)inBuf.o
GLOMBOBJ += $(BUILDDIR)osiTimer.o
GLOMBOBJ += $(BUILDDIR)osiTimerQueue.o
GLOMBOBJ += $(BUILDDIR)casEventMask.o
GLOMBOBJ += $(BUILDDIR)caServerOS.o
GLOMBOBJ += $(BUILDDIR)casDGOS.o
GLOMBOBJ += $(BUILDDIR)casStreamOS.o
GLOMBOBJ += $(BUILDDIR)fdMgr.o
GLOMBOBJ += $(BUILDDIR)osiTimeOSD.o
GLOMBOBJ += $(BUILDDIR)caServerIO.o
GLOMBOBJ += $(BUILDDIR)casDGIO.o
GLOMBOBJ += $(BUILDDIR)casStreamIO.o
GLOMBOBJ += $(BUILDDIR)sigPipeIgnore.o
all: excas
#PURIFY = /remote/lear_local/pure/purify-3.0a-sunos4/purify
nolib: $(OBJS) $(GLOMBOBJ) $(DEPLIBS)
$(PURIFY) $(LINK.cc) -o $@ $(OBJS) $(GLOMBOBJ) $(USR_LDFLAGS) $(USR_LDLIBS)
excas: $(OBJS) $(DEPLIBS) $(DEPLIBS_BASE)/libcas.a
$(LINK.cc) -o $@ $(OBJS) $(USR_LDFLAGS) -lcas $(USR_LDLIBS)
clean::
@$(RM) excas
@$(RM) nolib
@$(RM) -rf Templates.DB

View File

@@ -0,0 +1,93 @@
//
// Example EPICS CA server
//
#include <exServer.h>
//
// exAsyncPV::maxSimultAsyncOps()
// (virtual replacement for the default)
//
unsigned exAsyncPV::maxSimultAsyncOps () const
{
return 500u;
}
//
// exAsyncPV::read()
// (virtual replacement for the default)
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncIO *pIO;
pIO = new exAsyncReadIO(ctx, *this, valueIn);
if (!pIO) {
return S_casApp_noMemory;
}
return S_casApp_asyncCompletion;
}
//
// exAsyncPV::write()
// (virtual replacement for the default)
//
caStatus exAsyncPV::write (const casCtx &ctx, gdd &valueIn)
{
exAsyncIO *pIO;
pIO = new exAsyncWriteIO(ctx, *this, valueIn);
if (!pIO) {
return S_casApp_noMemory;
}
return S_casApp_asyncCompletion;
}
//
// exAsyncWriteIO::expire()
// (a virtual function that runs when the base timer expires)
//
void exAsyncWriteIO::expire()
{
caStatus status;
status = this->pv.update(*this->getValuePtr());
this->clrValue();
this->postIOCompletion (status);
}
//
// exAsyncReadIO::expire()
// (a virtual function that runs when the base timer expires)
//
void exAsyncReadIO::expire()
{
caStatus status;
gdd *pValue = this->getValuePtr();
//
// map between the prototype in and the
// current value
//
status = exServer::read(this->pv, *pValue);
//
// post IO completion
//
this->postIOCompletion(status);
}
//
// exAsyncExistIO::expire()
// (a virtual function that runs when the base timer expires)
//
void exAsyncExistIO::expire()
{
//
// post IO completion
//
this->postIOCompletion(S_cas_success);
}

View File

@@ -0,0 +1,7 @@
//
// Example EPICS CA server
//
#include <exServer.h>

353
src/cas/example/exPV.cc Normal file
View File

@@ -0,0 +1,353 @@
//
// Example EPICS CA server
//
#include <exServer.h>
const double myPI = 3.14159265358979323846;
//
// exPV::exPV()
//
exPV::exPV (const casCtx &ctxIn, const pvInfo &setup) :
pValue(NULL),
pScanTimer(NULL),
info(setup),
casPV(ctxIn, setup.getName().String()),
interest(aitFalse)
{
//
// load initial value
//
this->scanPV();
}
//
// exPV::~exPV()
//
exPV::~exPV()
{
if (this->pScanTimer) {
delete this->pScanTimer;
this->pScanTimer = NULL;
}
if (this->pValue) {
this->pValue->Unreference();
this->pValue = NULL;
}
}
//
// exPV::scanPV();
//
void exPV::scanPV()
{
caStatus status;
double radians;
gdd *pDD;
float newValue;
float limit;
caServer *pCAS = this->getCAS();
if (!pCAS) {
return;
}
pDD = new gddAtomic (gddAppType_value, aitEnumFloat32);
if (!pDD) {
return;
}
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (this->pValue) {
this->pValue->GetConvert(newValue);
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue = min (newValue, limit);
limit = (float) this->info.getLopr();
newValue = max (newValue, limit);
*pDD = newValue;
status = this->update (*pDD);
if (status) {
errMessage (status, "scan update failed\n");
}
pDD->Unreference();
}
//
// exScanTimer::expire ()
//
void exScanTimer::expire ()
{
pv.scanPV();
}
//
// exScanTimer::again()
//
osiBool exScanTimer::again()
{
return osiTrue;
}
//
// exScanTimer::delay()
//
const osiTime exScanTimer::delay()
{
return pv.getScanRate();
}
//
// exPV::update ()
//
caStatus exPV::update(gdd &valueIn)
{
gdd *pNewValue;
caServer *pCAS = this->getCAS();
osiTime cur (osiTime::getCurrent());
struct timespec t;
gddStatus gdds;
if (!pCAS) {
return S_casApp_noSupport;
}
//
// this does not modify the current value
// (because it may be referenced in the event queue)
//
pNewValue = new gdd (gddAppType_value, aitEnumFloat32);
if (!pNewValue) {
return S_casApp_noMemory;
}
# if DEBUG
printf("%s = %f\n", this->info.getName().String, valueIn);
# endif
gdds = gddApplicationTypeTable::
app_table.SmartCopy(pNewValue, &valueIn);
if (gdds) {
pNewValue->Unreference();
return S_cas_noConvert;
}
cur.get (t.tv_sec, t.tv_nsec);
pNewValue->SetTimeStamp(&t);
pNewValue->SetStat (epicsAlarmNone);
pNewValue->SetSevr (epicsSevNone);
//
// release old value and replace it
// with the new one
//
if (this->pValue) {
this->pValue->Unreference();
}
this->pValue = pNewValue;
if (this->interest==aitTrue) {
casEventMask select(pCAS->valueEventMask|pCAS->logEventMask);
this->postEvent (select, *this->pValue);
}
return S_casApp_success;
}
//
// exPV::bestExternalType()
//
aitEnum exPV::bestExternalType()
{
return aitEnumFloat64;
}
//
// exPV::interestRegister()
//
caStatus exPV::interestRegister()
{
caServer *pCAS = this->getCAS();
if (!pCAS) {
return S_casApp_success;
}
if (!this->pScanTimer) {
this->pScanTimer = new exScanTimer
(this->info.getScanRate(), *this);
if (!this->pScanTimer) {
errPrintf (S_cas_noMemory, __FILE__, __LINE__,
"Scan init for %s failed\n",
this->info.getName().String());
return S_cas_noMemory;
}
}
this->interest = aitTrue;
return S_casApp_success;
}
//
// exPV::interestDelete()
//
void exPV::interestDelete()
{
if (this->pScanTimer) {
delete this->pScanTimer;
this->pScanTimer = NULL;
}
this->interest = aitFalse;
}
//
// exPV::show()
//
void exPV::show(unsigned level)
{
if (level>1u) {
if (this->pValue) {
printf("exPV: cond=%d\n", this->pValue->GetStat());
printf("exPV: sevr=%d\n", this->pValue->GetSevr());
printf("exPV: value=%f\n", (double) *this->pValue);
}
printf("exPV: interest=%d\n", this->interest);
printf("exPV: pScanTimer=%x\n", (unsigned) this->pScanTimer);
}
}
//
// exPV::getStatus()
//
caStatus exPV::getStatus(gdd &value)
{
if (this->pValue) {
value.PutConvert(this->pValue->GetStat());
}
else {
value.PutConvert(epicsAlarmUDF);
}
return S_cas_success;
}
//
// exPV::getSeverity()
//
caStatus exPV::getSeverity(gdd &value)
{
if (this->pValue) {
value.PutConvert(this->pValue->GetSevr());
}
else {
value.PutConvert(epicsSevInvalid);
}
return S_cas_success;
}
//
// exPV::getTS()
//
inline aitTimeStamp exPV::getTS()
{
aitTimeStamp ts;
if (this->pValue) {
this->pValue->GetTimeStamp(&ts);
}
else {
osiTime cur(osiTime::getCurrent());
cur.get(ts.tv_sec, ts.tv_nsec);
}
return ts;
}
//
// exPV::getSeconds()
//
caStatus exPV::getSeconds(gdd &value)
{
aitUint32 sec (this->getTS().tv_sec);
value.PutConvert (sec);
return S_cas_success;
}
//
// exPV::getNanoseconds()
//
caStatus exPV::getNanoseconds(gdd &value)
{
aitUint32 nsec (this->getTS().tv_nsec);
value.PutConvert (nsec);
return S_cas_success;
}
//
// exPV::getPrecision()
//
caStatus exPV::getPrecision(gdd &prec)
{
prec.PutConvert(4u);
return S_cas_success;
}
//
// exPV::getHighLimit()
//
caStatus exPV::getHighLimit(gdd &value)
{
value.PutConvert(info.getHopr());
return S_cas_success;
}
//
// exPV::getLowLimit()
//
caStatus exPV::getLowLimit(gdd &value)
{
value.PutConvert(info.getLopr());
return S_cas_success;
}
//
// exPV::getUnits()
//
caStatus exPV::getUnits(gdd &units)
{
static aitString str("@#$%");
units.PutRef(str);
return S_cas_success;
}
//
// exPV::getValue()
//
caStatus exPV::getValue(gdd &value)
{
caStatus status;
if (this->pValue) {
gddStatus gdds;
gdds = gddApplicationTypeTable::
app_table.SmartCopy(&value, this->pValue);
if (gdds) {
status = S_cas_noConvert;
}
else {
status = S_cas_success;
}
}
else {
status = S_cas_noMemory;
}
return status;
}

182
src/cas/example/exServer.cc Normal file
View File

@@ -0,0 +1,182 @@
//
// fileDescriptorManager.process(delay);
// (the name of the global symbol has leaked in here)
//
//
// Example EPICS CA server
//
#include <exServer.h>
#include <fdMgr.h>
osiTime exServer::currentTime;
const pvInfo exServer::pvList[] = {
pvInfo (1.0e-4, "jane", 10.0f, 0.0f, excasIoSync),
pvInfo (2.0, "fred", 10.0f, -10.0f, excasIoSync),
pvInfo (1.0e-4, "janet", 10.0f, 0.0f, excasIoAsync),
pvInfo (2.0, "freddy", 10.0f, -10.0f, excasIoAsync)
};
//
// static data for exServer
//
gddAppFuncTable<exPV> exServer::ft;
//
// main()
//
int main (int argc, const char **argv)
{
osiTime delay(1u,0u);
exServer *pCAS;
pCAS = new exServer(32u,5u,500u);
if (!pCAS) {
exit(-1);
}
if (argc > 1) {
if (strcmp(argv[1],"-d")) {
pCAS->setDebugLevel(10u);
}
}
while (aitTrue) {
//
//
//
fileDescriptorManager.process(delay);
exServer::updateCurrentTime();
}
}
void exServer::updateCurrentTime()
{
exServer::currentTime = osiTime::getCurrent();
}
//
// exServer::exServer()
//
exServer::exServer(unsigned pvMaxNameLength, unsigned pvCountEstimate,
unsigned maxSimultaneousIO) :
caServer(pvMaxNameLength, pvCountEstimate, maxSimultaneousIO)
{
exServer::updateCurrentTime();
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);
}
//
// exServer::pvExistTest()
//
caStatus exServer::pvExistTest(const casCtx &ctxIn, const char *pPVName,
gdd &canonicalPVName)
{
const pvInfo *pPVI;
pPVI = exServer::findPV(pPVName);
if (pPVI) {
if (pPVI->getIOType()==excasIoAsync) {
exAsyncExistIO *pIO;
pIO = new exAsyncExistIO(pPVI, ctxIn, canonicalPVName);
if (pIO) {
return S_casApp_asyncCompletion;
}
else {
return S_casApp_noMemory;
}
}
/*
* there are no name aliases in this
* server's PV name syntax
*/
canonicalPVName.PutRef (&pPVI->getName());
return S_casApp_success;
}
return S_casApp_pvNotFound;
}
//
// findPV()
//
const pvInfo *exServer::findPV(const char *pName)
{
const pvInfo *pPVI;
const pvInfo *pPVAfter =
&exServer::pvList[NELEMENTS(exServer::pvList)];
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
if (strcmp (pName, pPVI->getName().String()) == '\0') {
return pPVI;
}
}
return NULL;
}
//
// exServer::createPV()
//
casPV *exServer::createPV (const casCtx &ctxIn, const char *pPVName)
{
const pvInfo *pInfo;
pInfo = exServer::findPV(pPVName);
if (!pInfo) {
return NULL;
}
switch (pInfo->getIOType()){
case excasIoSync:
return new exSyncPV (ctxIn, *pInfo);
case excasIoAsync:
return new exAsyncPV (ctxIn, *pInfo);
default:
return NULL;
}
}
//
// exServer::createPV()
//
void exServer::show (unsigned level)
{
//
// server tool specific show code goes here
//
//
// print information about ca server libarary
// internals
//
this->caServer::show(level);
}
//
// this is a noop that postpones the timer expiration
// destroy so the exAsyncIO class will hang around until the
// casAsyncIO::destroy() is called
//
void exAsyncIOTimer::destroy()
{
}

385
src/cas/example/exServer.h Normal file
View File

@@ -0,0 +1,385 @@
//
// Example EPICS CA server
//
//
// ANSI C
//
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
//
// SUN C++ does not have RAND_MAX yet
//
#if !defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
#if 0
#define RAND_MAX INT_MAX
#else
#define RAND_MAX SHRT_MAX
#endif
#endif
//
// 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
#ifndef NELEMENTS
# define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif
#define LOCAL static
//
// info about all pv in this server
//
enum excasIoType {excasIoSync, excasIoAsync};
class pvInfo {
public:
pvInfo (double scanRateIn, const char *pName,
aitFloat32 hoprIn, aitFloat32 loprIn,
excasIoType ioTypeIn) :
scanRate(scanRateIn), name(pName), hopr(hoprIn),
lopr(loprIn), ioType(ioTypeIn)
{
}
const double getScanRate () const { return this->scanRate; }
const aitString &getName () const { return this->name; }
const double getHopr () const { return this->hopr; }
const double getLopr () const { return this->lopr; }
const excasIoType getIOType () const { return this->ioType; }
private:
const double scanRate;
const aitString name;
const double hopr;
const double lopr;
const excasIoType ioType;
};
class exPV;
//
// exServer
//
class exServer : public caServer {
public:
exServer(unsigned pvMaxNameLength, unsigned pvCountEstimate=0x3ff,
unsigned maxSimultaneousIO=1u);
void show (unsigned level);
caStatus pvExistTest (const casCtx &ctxIn, const char *pPVName,
gdd &canonicalPVName);
casPV *createPV (const casCtx &ctxIn, const char *pPVName);
static const pvInfo *findPV(const char *pName);
static const osiTime &getCurrentTime()
{
return exServer::currentTime;
}
static void updateCurrentTime();
static gddAppFuncTableStatus read(exPV &pv, gdd &value)
{
return exServer::ft.read(pv, value);
}
private:
static const pvInfo pvList[];
static osiTime currentTime;
static gddAppFuncTable<exPV> ft;
};
//
// exScanTimer
//
class exScanTimer : public osiTimer {
public:
exScanTimer (double delayIn, exPV &pvIn) :
pv(pvIn), osiTimer(delayIn) {}
void expire ();
osiBool again();
const osiTime delay();
const char *name()
{
return "exScanTimer";
}
private:
exPV &pv;
};
//
// exPV
//
class exPV : public casPV {
public:
exPV (const casCtx &ctxIn, const pvInfo &setup);
virtual ~exPV();
void scanPV();
void show(unsigned level);
//
// Called by the server libary each time that it wishes to
// subscribe for PV the server tool via postEvent() below.
//
caStatus interestRegister();
//
// called by the server library each time that it wishes to
// remove its subscription for PV value change events
// from the server tool via caServerPostEvents()
//
void interestDelete();
aitEnum bestExternalType();
//
// chCreate() is called each time that a PV is attached to
// by a client. The server tool must create a casChannel object
// (or a derived class) each time that this routine is called
//
// If the operation must complete asynchronously then return
// the status code S_casApp_asyncCompletion and then
// create the casChannel object at some time in the future
//
//casChannel *createChannel ();
caStatus update (gdd &value);
//
// Std PV Attribute fetch support
//
gddAppFuncTableStatus getStatus(gdd &value);
gddAppFuncTableStatus getSeverity(gdd &value);
gddAppFuncTableStatus getSeconds(gdd &value);
gddAppFuncTableStatus getNanoseconds(gdd &value);
gddAppFuncTableStatus getPrecision(gdd &value);
gddAppFuncTableStatus getHighLimit(gdd &value);
gddAppFuncTableStatus getLowLimit(gdd &value);
gddAppFuncTableStatus getUnits(gdd &value);
gddAppFuncTableStatus getValue(gdd &value);
//
//
//
aitTimeStamp getTS();
const float getScanRate()
{
return this->info.getScanRate();
}
protected:
//
// private data
//
gdd *pValue;
exScanTimer *pScanTimer;
const pvInfo & info;
aitBool interest;
};
//
// exSyncPV
//
class exSyncPV : public exPV {
public:
exSyncPV (const casCtx &ctxIn, const pvInfo &setup);
~exSyncPV();
//
// read
//
// this is allowed to complete asychronously
//
caStatus read(const casCtx &ctxIn, gdd &value);
//
// write
//
// this is allowed to complete asychronously
//
caStatus write(const casCtx &ctxIn, gdd &value);
private:
};
//
// exAsyncPV
//
class exAsyncPV : public exPV {
public:
//
// exAsyncPV()
//
exAsyncPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup) {}
//
// read
//
// this is allowed to complete asychronously
//
caStatus read(const casCtx &ctxIn, gdd &value);
//
// write
//
// this is allowed to complete asychronously
//
caStatus write(const casCtx &ctxIn, gdd &value);
unsigned maxSimultAsyncOps () const;
private:
};
//
// exChannel
//
class exChannel : public casChannel{
public:
exChannel(const casCtx &ctxIn) : casChannel(ctxIn) {}
//void setOwner(const char *pUserName, const char *pHostName){};
//
// called when the first client begins to monitor the PV
//
caStatus interestRegister ()
{
return S_cas_success;
}
//
// called when the last client stops monitoring the PV
//
void interestDelete () {}
//
// the following are encouraged to change during an channel's
// lifetime
//
aitBool readAccess () const {return aitTrue;};
aitBool writeAccess () const {return aitTrue;};
private:
};
//
// exAsyncIOTimer
//
class exAsyncIOTimer : public osiTimer {
public:
exAsyncIOTimer (osiTime delayIn) : osiTimer(delayIn) {}
//
// this is a noop that postpones the timer expiration
// destroy so this object will hang around until the
// casAsyncIO::destroy() is called
//
void destroy();
const char *name()
{
return "exAsyncIOTimer";
}
};
//
// exAsyncIO()
//
class exAsyncIO : public casAsyncIO, public exAsyncIOTimer {
public:
exAsyncIO(const casCtx &ctxIn, gdd *pValue = 0) :
casAsyncIO(ctxIn, pValue),
exAsyncIOTimer(osiTime(0.010)) {} // 10 mSec
};
//
// exAsyncWriteIO
//
class exAsyncWriteIO : public exAsyncIO {
public:
//
// exAsyncWriteIO()
//
exAsyncWriteIO(const casCtx &ctxIn, exAsyncPV &pvIn, gdd &valueIn) :
exAsyncIO(ctxIn, &valueIn), pv(pvIn) {}
//
// expire()
// (a virtual function that runs when the base timer expires)
// see exAsyncPV.cc
//
void expire();
private:
exAsyncPV &pv;
};
//
// exAsyncReadIO
//
class exAsyncReadIO : public exAsyncIO {
public:
//
// exAsyncReadIO()
//
exAsyncReadIO(const casCtx &ctxIn, exAsyncPV &pvIn, gdd &protoIn) :
exAsyncIO(ctxIn, &protoIn), pv(pvIn) {}
//
// expire()
// (a virtual function that runs when the base timer expires)
// see exAsyncPV.cc
//
void expire();
private:
exAsyncPV &pv;
};
//
// exAsyncExistIO
// (PV exist async IO)
//
class exAsyncExistIO : public exAsyncIO {
public:
//
// exAsyncExistIO()
//
exAsyncExistIO(const pvInfo *pPVI,
const casCtx &ctxIn, gdd &canonicalPVName) :
exAsyncIO(ctxIn, &canonicalPVName)
{
canonicalPVName.PutRef(&pPVI->getName());
}
//
// expire()
// (a virtual function that runs when the base timer expires)
// see exAsyncPV.cc
//
void expire();
private:
};

View File

@@ -0,0 +1,38 @@
//
// Example EPICS CA server
//
#include <exServer.h>
//
// exSyncPV::exSyncPV()
//
exSyncPV::exSyncPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup)
{
}
//
// exSyncPV::~exSyncPV()
//
exSyncPV::~exSyncPV()
{
}
//
// exSyncPV::write()
//
caStatus exSyncPV::write (const casCtx &, gdd &valueIn)
{
return this->update (valueIn);
}
//
// exSyncPV::read()
//
caStatus exSyncPV::read (const casCtx &, gdd &protoIn)
{
return exServer::read(*this, protoIn);
}

846
src/cas/example/test.adl Normal file
View File

@@ -0,0 +1,846 @@
file {
name="test.dl"
}
display {
magic="305419896"
majv="2"
mnrv="2"
ndyng="0"
npc="6"
nstr="8"
ndynamic="12"
nplot="0"
nrd="0"
nes="0"
nkd="0"
object {
x="0"
y="0"
width="421"
height="306"
}
clr="0"
bclr="1"
nwords_dspy="1112"
nwords_sta="28"
nwords_cmap="36"
nwords_crules="106"
odyng="312"
osta="284"
odynamic="312"
oplot="1112"
ord="1112"
oes="1112"
okd="1112"
opc="58"
ostr="94"
ocmap="142"
ocrules="178"
style="solid"
fill="outline"
width="0"
clrmod="static"
vismod="static"
RISC_pad1="0"
RISC_pad2="0"
clrrule="alarm"
pv=""
cmap=""
}
"<<color map>>" {
ncolors="8"
dl_color {
r="255"
g="255"
b="255"
inten="255"
blink="off"
RISCpad="128"
}
dl_color {
r="0"
g="0"
b="0"
inten="0"
blink="off"
RISCpad="75"
}
dl_color {
r="255"
g="0"
b="0"
inten="255"
blink="off"
RISCpad="-14684"
}
dl_color {
r="255"
g="0"
b="0"
inten="255"
blink="on"
RISCpad="14744"
}
dl_color {
r="255"
g="255"
b="0"
inten="255"
blink="off"
RISCpad="-16536"
}
dl_color {
r="255"
g="255"
b="0"
inten="255"
blink="on"
RISCpad="-15536"
}
dl_color {
r="0"
g="0"
b="255"
inten="255"
blink="off"
RISCpad="-28408"
}
dl_color {
r="0"
g="0"
b="255"
inten="255"
blink="on"
RISCpad="0"
}
}
"<<color rules>>" {
nrules="1"
dl_color_rule {
name="alarm"
info[0] {
chan="$(C).SEVR"
value="MAJOR"
connector="use"
comparator="equals"
clr="2"
RISCpad="0"
}
info[1] {
chan="$(C).SEVR"
value="MINOR"
connector="use"
comparator="equals"
clr="4"
RISCpad="127"
}
info[2] {
chan="$(C).SEVR"
value="INFO"
connector="use"
comparator="equals"
clr="6"
RISCpad="44"
}
info[3] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-128"
}
info[4] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-1"
}
info[5] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-104"
}
info[6] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-1"
}
info[7] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="8"
}
info[8] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="120"
}
info[9] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="1"
}
info[10] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="7"
}
info[11] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="19"
}
info[12] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="48"
}
info[13] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="28"
}
info[14] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-88"
}
info[15] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="0"
}
fg_enable="on"
bg_enable="on"
default_fg="0"
default_bg="1"
}
}
"<<basic attribute>>" {
attr {
clr="0"
style="solid"
fill="outline"
width="0"
}
}
"text" {
object {
x="44"
y="16"
width="104"
height="14"
groupid="0"
}
textix="Sync"
align="horiz. left"
RISC_pad="0"
}
"text" {
object {
x="260"
y="13"
width="92"
height="17"
groupid="0"
}
textix="Async"
align="horiz. left"
RISC_pad="0"
}
"indicator" {
object {
x="15"
y="88"
width="170"
height="22"
groupid="0"
}
monitor {
chan="fred"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="16"
y="133"
width="169"
height="17"
groupid="0"
}
monitor {
chan="fred"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="15"
y="43"
width="168"
height="22"
groupid="0"
}
control {
chan="fred"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="215"
y="81"
width="170"
height="30"
groupid="0"
}
monitor {
chan="freddy"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="216"
y="133"
width="171"
height="18"
groupid="0"
}
monitor {
chan="freddy"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="215"
y="43"
width="168"
height="28"
groupid="0"
}
control {
chan="freddy"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="16"
y="225"
width="171"
height="19"
groupid="0"
}
monitor {
chan="jane"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="17"
y="259"
width="170"
height="20"
groupid="0"
}
monitor {
chan="jane"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="15"
y="187"
width="170"
height="19"
groupid="0"
}
control {
chan="jane"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="219"
y="218"
width="173"
height="23"
groupid="0"
}
monitor {
chan="janet"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="220"
y="257"
width="174"
height="20"
groupid="0"
}
monitor {
chan="janet"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="219"
y="188"
width="171"
height="21"
groupid="0"
}
control {
chan="janet"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="0"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}

6
src/cas/generic/README Normal file
View File

@@ -0,0 +1,6 @@
this directory contains the generic source for
the EPICS ca server

View File

@@ -0,0 +1,76 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef includeCasCommonDefH
#define includeCasCommonDefH
#ifndef NULL
#define NULL 0
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef OK
#define OK 0
#endif
#ifndef ERROR
#define ERROR (-1)
#endif
#ifndef NELEMENTS
#define NELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
#endif
#ifndef LOCAL
#define LOCAL static
#endif
#ifndef min
#define min(A,B) ((A)>(B)?(B):(A))
#endif
#ifndef max
#define max(A,B) ((A)<(B)?(B):(A))
#endif
#endif /* ifndef includeCasCommonDefH (last line in this file) */

226
src/cas/generic/caProto.h Normal file
View File

@@ -0,0 +1,226 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef __CAPROTO__
/* $Id$ */
/*
* History
* .01 01xx90 joh removed status field in favor of a independent m_cmmd-
* saves space on every successful operation
*
* .02 041390 joh moved server ports to above IPPORT_USERRESERVED
* see in.h
*
* .03 060391 joh Bumped protocol version to 4 to support changes for
* SPARC alignment in db_access.h
*
* .04 071291 joh New command added - claim channel in use block
*
* .05 011294 joh New command added - write notify
*
* .06 020194 joh New command added for CA V4.1 - client name
*
* .07 041194 joh New command added for CA V4.2 - access rights
*
* .08 050594 joh New command added for CA V4.3 - echo request
*
* .09 050594 joh New command added for CA V4.3 - repeater fanout regis
*
* .10 050594 joh New command added for CA V4.3 - wakeup the server
* $Log$
*
*/
#define __CAPROTO__
/* TCP/UDP port number (bumped each protocol change) */
#define CA_PROTOCOL_VERSION 4u
#define CA_MINOR_VERSION 7u
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
#if CA_PROTOCOL_VERSION == 4u
#define CA_V41(MAJOR,MINOR) ((MINOR)>=1u)
#define CA_V42(MAJOR,MINOR) ((MINOR)>=2u)
#define CA_V43(MAJOR,MINOR) ((MINOR)>=3u)
#define CA_V44(MAJOR,MINOR) ((MINOR)>=4u)
#define CA_V45(MAJOR,MINOR) ((MINOR)>=5u)
#define CA_V46(MAJOR,MINOR) ((MINOR)>=6u)
#define CA_V47(MAJOR,MINOR) ((MINOR)>=7u)
#elif CA_PROTOCOL_VERSION > 4u
#define CA_V41(MAJOR,MINOR) ( 1u )
#define CA_V42(MAJOR,MINOR) ( 1u )
#define CA_V43(MAJOR,MINOR) ( 1u )
#define CA_V44(MAJOR,MINOR) ( 1u )
#define CA_V45(MAJOR,MINOR) ( 1u )
#define CA_V46(MAJOR,MINOR) ( 1u )
#define CA_V47(MAJOR,MINOR) ( 1u )
#else
#define CA_V41(MAJOR,MINOR) ( 0u )
#define CA_V42(MAJOR,MINOR) ( 0u )
#define CA_V43(MAJOR,MINOR) ( 0u )
#define CA_V44(MAJOR,MINOR) ( 0u )
#define CA_V45(MAJOR,MINOR) ( 0u )
#define CA_V46(MAJOR,MINOR) ( 0u )
#define CA_V47(MAJOR,MINOR) ( 0u )
#endif
/*
* NOTE: These port numbers are only used if the CA repeater and
* CA server port numbers cant be obtained from the EPICS
* environment variables "EPICS_CA_REPEATER_PORT" and
* "EPICS_CA_SERVER_PORT"
*/
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u)
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u+1u)
#define MAX_UDP 1024u
#define MAX_TCP (MAX_UDP*16u) /* so waveforms fit */
#define MAX_MSG_SIZE (MAX_TCP) /* the larger of tcp and udp max */
/*
* architecture independent types
*
* (so far this works on all archs we have ported to)
*/
typedef unsigned short ca_uint16_t;
typedef unsigned int ca_uint32_t;
typedef float ca_float32_t;
typedef ca_uint32_t caResId;
/* values for m_cmmd */
#define CA_PROTO_NOOP 0u /* do nothing, but verify TCP */
#define CA_PROTO_EVENT_ADD 1u /* add an event */
#define CA_PROTO_EVENT_CANCEL 2u /* cancel an event */
#define CA_PROTO_READ 3u /* read and return a channel value*/
#define CA_PROTO_WRITE 4u /* write a channel value */
#define CA_PROTO_SNAPSHOT 5u /* snapshot of the system */
#define CA_PROTO_SEARCH 6u /* IOC channel search */
#define CA_PROTO_BUILD 7u /* build - obsolete */
#define CA_PROTO_EVENTS_OFF 8u /* flow control */
#define CA_PROTO_EVENTS_ON 9u /* flow control */
#define CA_PROTO_READ_SYNC 10u /* purge old reads */
#define CA_PROTO_ERROR 11u /* an operation failed */
#define CA_PROTO_CLEAR_CHANNEL 12u /* free chan resources */
#define CA_PROTO_RSRV_IS_UP 13u /* CA server has joined the net */
#define CA_PROTO_NOT_FOUND 14u /* channel not found */
#define CA_PROTO_READ_NOTIFY 15u /* add a one shot event */
#define CA_PROTO_READ_BUILD 16u /* read and build - obsolete */
#define REPEATER_CONFIRM 17u /* registration confirmation */
#define CA_PROTO_CLAIM_CIU 18u /* client claims resource in server */
#define CA_PROTO_WRITE_NOTIFY 19u /* notify after write chan value */
#define CA_PROTO_CLIENT_NAME 20u /* CA V4.1 identify client */
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
#define REPEATER_REGISTER 24u /* registr for repeater fan out */
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
#define CA_PROTO_CLAIM_CIU_FAILED 26u /* unable to create chan resource in server */
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
#define CA_PROTO_LAST_CMMD CA_PROTO_CLAIM_CIU_FAILED
/*
* for use with search and not_found (if search fails and
* its not a broadcast tell the client to look elesewhere)
*/
#define DOREPLY 10u
#define DONTREPLY 5u
/* size of object in bytes rounded up to nearest oct word */
#define OCT_ROUND(A) ((((unsigned long)(A))+7u)>>3u)
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
/* size of object in bytes rounded up to nearest long word */
#define QUAD_ROUND(A) (((unsigned long)(A))+3u)>>2u)
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
/* size of object in bytes rounded up to nearest short word */
#define BI_ROUND(A) ((((unsigned long)(A))+1u)>>1u)
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
/*
* For communicating access rights to the clients
*
* (placed in m_available hdr field of CA_PROTO_ACCESS_RIGHTS cmmd
*/
#define CA_PROTO_ACCESS_RIGHT_READ (1u<<0u)
#define CA_PROTO_ACCESS_RIGHT_WRITE (1u<<1u)
/*
* All structures passed in the protocol must have individual
* fields aligned on natural boundaries.
*
* NOTE: all structures declared in this file must have a
* byte count which is evenly divisible by 8 matching
* the largest atomic data type in db_access.h.
*/
#define CA_MESSAGE_ALIGN(A) (OCT_ROUND(A)<<3u)
/*
* the common part of each message sent/recv by the
* CA server.
*/
typedef struct ca_hdr {
ca_uint16_t m_cmmd; /* operation to be performed */
ca_uint16_t m_postsize; /* size of message extension */
ca_uint16_t m_type; /* operation data type */
ca_uint16_t m_count; /* operation data count */
ca_uint32_t m_cid; /* channel identifier */
ca_uint32_t m_available; /* undefined message location for use
* by client processes */
}caHdr;
/*
* for monitor (event) message extension
*/
struct mon_info{
ca_float32_t m_lval; /* low delta */
ca_float32_t m_hval; /* high delta */
ca_float32_t m_toval; /* period btween samples */
ca_uint16_t m_mask; /* event select mask */
ca_uint16_t m_pad; /* extend to 32 bits */
};
struct monops { /* monitor req opi to ioc */
caHdr m_header;
struct mon_info m_info;
};
/*
* PV names greater than this length assumed to be invalid
*/
#define unreasonablePVNameSize 500u
#endif /* __CAPROTO__ */

141
src/cas/generic/caServer.cc Normal file
View File

@@ -0,0 +1,141 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
//
// 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)),
valueEventMask(this->registerEvent("value")),
logEventMask(this->registerEvent("log")),
alarmEventMask(this->registerEvent("alarm"))
{
caStatus status;
static init;
if (!init) {
gddMakeMapDBR(gddApplicationTypeTable::app_table);
init = TRUE;
}
//
// OS and IO dependent
//
if (!this->pCAS) {
errMessage(S_cas_noMemory, NULL);
return;
}
status = this->pCAS->init();
if (status) {
errMessage(status, NULL);
delete this->pCAS;
this->pCAS = NULL;
return;
}
}
//
// caServer::~caServer()
//
caServer::~caServer()
{
if (this->pCAS) {
delete this->pCAS;
}
}
//
// caServer::registerEvent()
//
casEventMask caServer::registerEvent (const char *pName)
{
if (this->pCAS) {
return this->pCAS->registerEvent(pName);
}
else {
casEventMask emptyMask;
return emptyMask;
}
}
//
// caServer::show()
//
void caServer::show(unsigned level)
{
if (this->pCAS) {
this->pCAS->show(level);
}
}
//
// caServer::setDebugLevel()
//
void caServer::setDebugLevel (unsigned level)
{
if (pCAS) {
this->pCAS->setDebugLevel(level);
}
else {
errMessage(S_cas_noMemory, NULL);
}
}
//
// caServer::getDebugLevel()
//
unsigned caServer::getDebugLevel ()
{
if (pCAS) {
return this->pCAS->getDebugLevel();
}
else {
errMessage(S_cas_noMemory, NULL);
return 0u;
}
}

View File

@@ -0,0 +1,368 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#define CAS_VERSION_GLOBAL
#define caServerGlobal
#include <server.h>
VERSIONID(casAccessc,"%W% %G%")
//
// caServerI::show()
//
void caServerI::show (unsigned level)
{
casStrmClient *pClient;
tsDLIter<casStrmClient> iter(this->clientList);
int bytes_reserved;
printf( "Channel Access Server Status V%d.%d\n",
CA_PROTOCOL_VERSION, CA_MINOR_VERSION);
this->lock();
while ( (pClient = iter()) ) {
pClient->show(level);
}
this->dgClient.show(level);
this->unlock();
bytes_reserved = 0u;
#if 0
bytes_reserved += sizeof(casClient) *
ellCount(&this->freeClientQ);
bytes_reserved += sizeof(casChannel) *
ellCount(&this->freeChanQ);
bytes_reserved += sizeof(casEventBlock) *
ellCount(&this->freeEventQ);
bytes_reserved += sizeof(casAsyncIIO) *
ellCount(&this->freePendingIO);
#endif
if (level>=1) {
printf(
"There are currently %d bytes on the server's free list\n",
bytes_reserved);
#if 0
printf(
"%d client(s), %d channel(s), %d event(s) (monitors), and %d IO blocks\n",
ellCount(&this->freeClientQ),
ellCount(&this->freeChanQ),
ellCount(&this->freeEventQ),
ellCount(&this->freePendingIO));
#endif
printf(
"The server's integer resource id conversion table:\n");
this->lock();
this->uintResTable<casRes>::show(level);
this->unlock();
printf(
"The server's character string resource id conversion table:\n");
this->lock();
this->stringResTbl.show(level);
this->unlock();
}
// @@@@@@ caPrintAddrList(&destAddr);
return;
}
//
// caServerI::caServerI()
//
caServerI::caServerI (caServer &tool, unsigned maxNameLength,
unsigned nPV, unsigned maxSimultIO) :
dgClient(*this),
//
// Set up periodic beacon interval
// (exponential back off to a plateau
// from this intial period)
//
beaconPeriod(CAServerMinBeaconPeriod),
adapter(tool),
pvCount(0u),
debugLevel(0u),
nExistTestInProg(0u),
pvMaxNameLength(maxNameLength),
pvCountEstimate(nPV<100u?100u:nPV),
maxSimultaneousIO(maxSimultIO),
caServerOS(*this)
{
assert(&adapter);
ctx.setServer(this);
}
//
// caServerI::init()
//
caStatus caServerI::init()
{
int status;
int resLibStatus;
status = caServerIO::init();
if (status) {
return status;
}
status = caServerOS::init();
if (status) {
return status;
}
status = this->dgClient.init();
if (status) {
return status;
}
//
// hash table size may need adjustment here?
//
resLibStatus = this->uintResTable<casRes>::init(this->pvCountEstimate*8u);
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;
}
return S_cas_success;
}
/*
* caServerI::~caServerI()
*/
caServerI::~caServerI()
{
casClient *pClient;
this->lock();
//
// delete all clients
//
while ( (pClient = this->clientList.get()) ) {
delete pClient;
}
//
// verify that we didnt leak a PV
//
assert (this->pvCount==0u);
}
//
// caServerI::installClient()
//
void caServerI::installClient(casStrmClient *pClient)
{
this->lock();
this->clientList.add(*pClient);
this->unlock();
}
//
// caServerI::removeClient()
//
void caServerI::removeClient(casStrmClient *pClient)
{
this->lock();
this->clientList.remove(*pClient);
this->unlock();
}
//
// caServerI::connectCB()
//
void caServerI::connectCB()
{
casStreamOS *pNewClient;
casMsgIO *pIO;
caStatus status;
pIO = this->newStreamIO();
if (!pIO) {
errMessage(S_cas_noMemory, NULL);
return;
}
status = pIO->init();
if (status) {
errMessage(status, NULL);
delete pIO;
return;
}
pNewClient = new casStreamOS(*this, *pIO);
if (!pNewClient) {
errMessage(S_cas_noMemory, NULL);
return;
}
status = pNewClient->init();
if (status) {
errMessage(status, NULL);
delete pNewClient;
}
}
#if 0
//
// caServerI::elapsedTimeCompare()
//
int caServerI::elapsedTimeCompare(
const caTime &stamp1, const caTime &stamp2)
{
if (stamp1.sec == stamp2.sec) {
if (stamp1.nsec == stamp2.nsec) {
return 0;
}
else if (stamp1.nsec > stamp2.nsec) {
return 1;
}
return -1;
}
else if (stamp1.sec > stamp2.sec) {
return 1;
}
return -1;
}
#endif
#if 0
//
// caServerI::getElapsedTime()
//
caTime caServerI::getElapsedTime (const caTime &stamp)
{
caTime elapsed;
caTime current;
caTime local = stamp;
//
// OS dependent function - see casOSDInLine.h
//
current = caServerI::getTime();
//
// this indicates wrap around
//
if (local.sec>current.sec) {
unsigned long tmp;
tmp = ULONG_MAX - local.sec;
assert (tmp < ULONG_MAX - current.sec);
current.sec += tmp;
local.sec = 0;
}
//
// borrow
//
if (local.nsec > current.nsec) {
assert (current.sec>0);
assert (current.sec>=local.sec);
current.sec--;
assert (2*CAServerNSecInSec < ULONG_MAX);
current.nsec += CAServerNSecInSec;
}
elapsed.sec = current.sec - local.sec;
elapsed.nsec = current.nsec - local.nsec;
return elapsed;
}
#endif
//
// caServerI::advanceBeaconPeriod()
//
// compute delay to the next beacon
//
void caServerI::advanceBeaconPeriod()
{
//
// return if we are already at the plateau
//
if (this->beaconPeriod >= CAServerMaxBeaconPeriod) {
return;
}
this->beaconPeriod += this->beaconPeriod;
if (this->beaconPeriod >= CAServerMaxBeaconPeriod) {
this->beaconPeriod = CAServerMaxBeaconPeriod;
}
}
//
// casVerifyFunc()
//
void casVerifyFunc(const char *pFile, unsigned line, const char *pExp)
{
fprintf(stderr,
"We suspect internal problems at line %u in \"%s\" because \"%s\"==0\n",
line, pFile, pExp);
fprintf(stderr,
"Please forward above text to johill@lanl.gov - thanks\n");
}
//
// serverToolDebugFunc()
//
void serverToolDebugFunc(const char *pFile, unsigned line)
{
fprintf(stderr,
"Bad server tool response detected at line %u in \"%s\"\n",
line, pFile);
}

View File

@@ -0,0 +1,137 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef caServerIIL_h
#define caServerIIL_h
//
// caServerI::lookupRes()
//
inline casRes *caServerI::lookupRes(const caResId &idIn, casResType type)
{
uintId id(idIn);
casRes *pRes;
pRes = this->uintResTable<casRes>::lookup(id);
if (pRes) {
if (pRes->resourceType()!=type) {
pRes = 0;
}
}
return pRes;
}
//
// find the channel associated with a resource id
//
inline casChannelI *caServerI::resIdToChannel(const caResId &id)
{
casRes *pRes;
pRes = this->lookupRes(id, casChanT);
//
// safe to cast because we have checked the type code above
// (and we know that casChannelI derived from casRes)
//
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 caStatus caServerI::pvExistTest(const casCtx &ctxIn,
const char *pPVName, gdd &canonicalPVName)
{
if (!pvExistTestPossible()) {
return S_cas_ioBlocked;
}
this->nExistTestInProg++;
return (*this)->pvExistTest(ctxIn, pPVName, canonicalPVName);
}
//
// caServerI::pvExistTestCompletion()
//
inline void caServerI::pvExistTestCompletion()
{
this->nExistTestInProg--;
this->ioBlockedList::signal();
}
//
// install a PV into the server
//
inline void caServerI::installPV (casPVI &pv)
{
int resLibStatus;
this->lock ();
this->pvCount++;
resLibStatus = this->stringResTbl.add (pv);
this->unlock ();
assert (resLibStatus==0);
}
//
// remove PV from the server
//
inline void caServerI::removePV(casPVI &pv)
{
casPVI *pPV;
this->lock();
casVerify (this->pvCount>=1u);
this->pvCount--;
pPV = this->stringResTbl.remove (pv);
this->unlock();
casVerify (pPV!=0);
casVerify (pPV==&pv);
}
#endif // caServerIIL_h

View File

@@ -0,0 +1,45 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include<server.h>
//
// casAsyncIO::destroy()
//
void casAsyncIO::destroy()
{
delete this;
}

View File

@@ -0,0 +1,252 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casAsyncIOIIL.h> // casAsyncIOI inline func
#include <casChannelIIL.h> // casChannelI inline func
#include <casEventSysIL.h> // casEventSys inline func
//
// casAsyncIOI::casAsyncIOI()
//
casAsyncIOI::casAsyncIOI(const casCtx &ctx, casAsyncIO &ioIn, gdd *pDD) :
msg(*ctx.getMsg()), client(*ctx.getClient()),
pChan(ctx.getChannel()),
pDesc(pDD),
completionStatus(S_cas_internal),
inTheEventQueue(FALSE),
posted(FALSE),
ioComplete(FALSE),
serverDelete(FALSE)
{
assert (&this->client);
assert (&this->msg);
//
// casAsyncIOI must be a base of casAsyncIO
//
assert (this == (casAsyncIOI *)&ioIn);
if (this->pChan) {
this->pChan->installAsyncIO(*this);
}
else {
this->client.installAsyncIO(*this);
}
if (this->pDesc) {
int gddStatus;
gddStatus = this->pDesc->Reference();
assert(!gddStatus);
}
}
//
// casAsyncIOI::~casAsyncIOI()
//
// ways this gets destroyed:
// 1) io completes, this is pulled off the queue, and result
// is sent to the client
// 2) client, channel, or PV is deleted
// 3) server tool deletes the casAsyncIO obj
//
// Case 1) => normal completion
//
// Case 2)
// If the server deletes the channel or the PV then the
// client will get a disconnect msg for the channel
// involved and this will cause the io call back
// to be called with a disconnect error code.
// Therefore we dont need to force an IO canceled
// response here.
//
// Case 3)
// If for any reason the server tool needs to cancel an IO
// operation then it should post io completion with status
// S_casApp_canceledAsyncIO. Deleting the asyncronous io
// object prior to its being allowed to forward an IO termination
// message to the client will result in NO IO CALL BACK TO THE
// CLIENT PROGRAM (in this situation a warning message will be printed by
// the server lib).
//
casAsyncIOI::~casAsyncIOI()
{
this->lock();
if (!this->serverDelete) {
fprintf(stderr,
"WARNING: An async IO operation was deleted prematurely\n");
fprintf(stderr,
"WARNING: by the server tool. This results in no IO cancel\n");
fprintf(stderr,
"WARNING: message being sent to the client. PLease cancel\n");
fprintf(stderr,
"WARNING: IO by posting S_casApp_canceledAsyncIO instead of\n");
fprintf(stderr,
"WARNING: by deleting the async IO object.\n");
}
if (this->pChan) {
this->pChan->removeAsyncIO(*this);
}
else {
this->client.removeAsyncIO(*this);
}
//
// pulls itself out of the event queue
// if it is installed there
//
if (this->inTheEventQueue) {
this->client.casEventSys::removeFromEventQueue(*this);
}
if (this->pDesc) {
int gddStatus;
gddStatus = this->pDesc->Unreference();
assert (gddStatus==0);
this->pDesc = NULL;
}
this->unlock();
}
//
// casAsyncIOI::cbFunc()
// (called when IO completion event reaches top of event queue)
//
caStatus casAsyncIOI::cbFunc(class casEventSys &)
{
caStatus status;
this->lock();
this->inTheEventQueue = FALSE;
status = this->client.asyncIOCompletion(this->pChan,
this->msg, this->pDesc, this->completionStatus);
if (status == S_cas_sendBlocked) {
//
// causes this op to be pushed back on the queue
//
this->inTheEventQueue = TRUE;
this->unlock();
return status;
}
else if (status != S_cas_success) {
errMessage (status, "Asynch IO completion failed");
}
//
// dont use "this" after this delete
//
this->ioComplete = TRUE;
this->unlock();
this->setServerDelete();
(*this)->destroy();
return S_cas_success;
}
//
// casAsyncIOI::postIOCompletion()
//
caStatus casAsyncIOI::postIOCompletion(caStatus completionStatusIn, gdd *pValue)
{
this->lock();
//
// verify that they dont post completion more than once
//
if (this->posted) {
this->unlock();
return S_cas_redundantPost;
}
//
// dont call the server tool's cancel() when this object deletes
//
this->posted = TRUE;
this->completionStatus = completionStatusIn;
if (pValue) {
int gddStatus;
gddStatus = pValue->Reference();
assert(!gddStatus);
if (this->pDesc) {
gddStatus = this->pDesc->Unreference();
assert (gddStatus==0);
}
this->pDesc = pValue;
}
//
// No changes after the IO completes
//
if (this->pDesc) {
pDesc->MarkConstant();
}
//
// place this event in the event queue
// (this also signals the event consumer)
//
this->inTheEventQueue = TRUE;
this->client.casEventSys::addToEventQueue(*this);
this->unlock();
return S_cas_success;
}
//
// casAsyncIOI::getCAS()
// (not inline because this is used by the interface class)
//
caServer *casAsyncIOI::getCAS()
{
return this->client.getCAS().getAdapter();
}

View File

@@ -0,0 +1,56 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casAsyncIOIIL_h
#define casAsyncIOIIL_h
//
// void casAsyncIOI::lock()
//
inline void casAsyncIOI::lock()
{
client.lock();
}
//
// void casAsyncIOI::unlock()
//
inline void casAsyncIOI::unlock()
{
client.unlock();
}
#endif // casAsyncIOIIL_h

View File

@@ -0,0 +1,50 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
//
// casChanDelEv()
//
caStatus casChanDelEv::cbFunc(casEventSys &eSys)
{
caStatus status;
status = eSys.getCoreClient().disconnectChan(this->id);
if (status == S_cas_success) {
delete this;
}
return status;
}

View File

@@ -0,0 +1,149 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casChannelIIL.h> // casChannelI inline func
#include <casPVListChanIL.h> // casPVListChan inline func
//
// casChannel::casChannel()
//
casChannel::casChannel(const casCtx &ctx) :
casPVListChan (ctx, *this)
{
}
//
// casChannel::~casChannel()
//
casChannel::~casChannel()
{
}
casPV *casChannel::getPV()
{
casPVI &pvi((*this)->getPVI());
if (&pvi!=NULL) {
return pvi.intefaceObjectPointer();
}
else {
return NULL;
}
}
//
// casChannel::postEvent()
//
void casChannel::postEvent (const casEventMask &select, gdd &event)
{
(*this)->postEvent(select, event);
}
//
// casChannel::setOwner()
//
void casChannel::setOwner(const char * const /* pUserName */,
const char * const /* pHostName */)
{
//
// NOOP
//
}
//
// casChannel::interestRegister()
//
caStatus casChannel::interestRegister()
{
return S_casApp_success;
}
//
// casChannel::interestDelete()
//
void casChannel::interestDelete()
{
}
//
// casChannel::readAccess()
//
aitBool casChannel::readAccess () const
{
return aitTrue;
}
//
// casChannel::writeAccess()
//
aitBool casChannel::writeAccess() const
{
return aitTrue;
}
//
// casChannel::confirmationRequested()
//
aitBool casChannel::confirmationRequested() const
{
return aitFalse;
}
//
// casChannel::show()
//
void casChannel::show(unsigned level)
{
if (level>2u) {
printf("casChannel: read access = %d\n",
this->readAccess());
printf("casChannel: write access = %d\n",
this->writeAccess());
printf("casChannel: confirmation requested = %d\n",
this->confirmationRequested());
}
}
//
// casChannel::destroy()
//
void casChannel::destroy()
{
delete this;
}

View File

@@ -0,0 +1,174 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casEventSysIL.h> // casEventSys inline func
#include <casPVIIL.h> // casPVI inline func
//
// casChannelI::casChannelI()
//
casChannelI::casChannelI(const casCtx &ctx, casChannel &chanAdapter) :
client(* (casStrmClient *) ctx.getClient()),
pv(*ctx.getPV()),
cid(ctx.getMsg()->m_cid)
{
assert(&this->client);
assert(&this->pv);
//
// enforce that casChannelI is always a base of casChannel
//
assert(&chanAdapter == (casChannel *) this);
this->client.installChannel(*this);
}
//
// casChannelI::~casChannelI()
//
casChannelI::~casChannelI()
{
casAsyncIOI *pIO;
tsDLIter<casAsyncIOI> iterIO(this->ioInProgList);
casMonitor *pMonitor;
tsDLIter<casMonitor> iterMon(this->monitorList);
casChanDelEv *pCDEV;
caStatus status;
this->lock();
//
// cancel any pending asynchronous IO
//
pIO = iterIO();
while (pIO) {
casAsyncIOI *pNextIO;
//
// destructor removes from this list
//
pNextIO = iterIO();
pIO->setServerDelete();
(*pIO)->destroy();
pIO = pNextIO;
}
//
// cancel the monitors
//
pMonitor = iterMon();
while (pMonitor) {
casMonitor *pNextMon;
//
// destructor removes from this list
//
pNextMon = iterMon();
delete pMonitor;
pMonitor = pNextMon;
}
this->client.removeChannel(*this);
//
// force PV delete if this is the last channel attached
//
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 (!this->clientDestroyPending) {
pCDEV = new casChanDelEv(this->getCID());
if (pCDEV) {
this->client.casEventSys::addToEventQueue(*pCDEV);
}
else {
status = this->client.disconnectChan (this->getCID());
if (status) {
errMessage(status, NULL);
if (status == S_cas_disconnect) {
this->client.destroy();
}
}
}
}
this->unlock();
}
//
// casChannelI::postAllModifiedEvents()
//
void casChannelI::postAllModifiedEvents()
{
casMonitor *pMon;
tsDLIter<casMonitor> iter(this->monitorList);
this->lock();
while ( (pMon=iter()) ) {
pMon->postIfModified();
}
this->unlock();
}
//
// casChannelI::show()
//
void casChannelI::show(unsigned level)
{
casMonitor *pMon;
tsDLIter<casMonitor> iter(this->monitorList);
this->lock();
if ( (pMon = iter()) ) {
printf("List of CA events (monitors) for \"%s\".\n",
this->pv.resourceName());
}
while (pMon) {
pMon->show(level);
pMon = iter();
}
(*this)->show(level);
this->unlock();
}

View File

@@ -0,0 +1,171 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casChannelIIL_h
#define casChannelIIL_h
//
// casChannelI::lock()
//
inline void casChannelI::lock()
{
this->client.lock();
}
//
// casChannelI::unlock()
//
inline void casChannelI::unlock()
{
this->client.unlock();
}
//
// casChannelI::postEvent()
//
inline void casChannelI::postEvent(const casEventMask &select, gdd &event)
{
casMonitor *pMon;
tsDLIter<casMonitor> iter(this->monitorList);
this->lock();
while ( (pMon = iter()) ) {
pMon->post(select, event);
}
this->unlock();
}
//
// casChannelI::deleteMonitor()
//
inline void casChannelI::deleteMonitor(casMonitor &mon)
{
casRes *pRes;
this->lock();
this->getClient().casEventSys::removeMonitor();
this->monitorList.remove(mon);
pRes = this->getClient().getCAS().removeItem(mon);
assert(&mon == (casMonitor *)pRes);
this->unlock();
}
//
// casChannelI::addMonitor()
//
inline void casChannelI::addMonitor(casMonitor &mon)
{
this->lock();
this->monitorList.add(mon);
this->getClient().getCAS().installItem(mon);
this->getClient().casEventSys::installMonitor();
this->unlock();
}
//
// casChannelI::findMonitor
// (it is reasonable to do a linear search here because
// sane clients will require only one or two monitors
// per channel)
//
inline casMonitor *casChannelI::findMonitor(const caResId clientIdIn)
{
tsDLIter<casMonitor> iter(this->monitorList);
casMonitor *pMon;
while ( (pMon = iter()) ) {
if ( clientIdIn == pMon->getClientId()) {
return pMon;
}
}
return NULL;
}
//
// casChannelI::clientDestroy()
//
inline void casChannelI::clientDestroy()
{
this->clientDestroyPending=TRUE;
(*this)->destroy();
}
#include <casPVIIL.h> // casPVI inline func (for getIOOPSInProgress() )
//
// functions that use below here casPVIIL.h
//
//
// casChannelI::installAsyncIO()
//
inline void casChannelI::installAsyncIO(casAsyncIOI &io)
{
this->lock();
this->pv.registerIO();
this->ioInProgList.add(io);
this->unlock();
}
//
// casChannelI::removeAsyncIO()
//
inline void casChannelI::removeAsyncIO(casAsyncIOI &io)
{
this->lock();
this->ioInProgList.remove(io);
this->pv.unregisterIO();
this->unlock();
}
//
// casChannelI::getIOOPSInProgress()
//
inline unsigned casChannelI::getIOOPSInProgress() const
{
return this->pv.ioInProgress();
}
//
// casChannelI::getSID()
// fetch the unsigned integer server id for this PV
//
inline const caResId casChannelI::getSID()
{
return this->uintId::getId();
}
#endif // casChannelIIL_h

View File

@@ -0,0 +1,558 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casClientIL.h> // inline func for casClient
VERSIONID(camsgtaskc,"%W% %G%")
static const caHdr nill_msg = {0u,0u,0u,0u,0u,0u};
//
// static declartions for class casClient
//
int casClient::msgHandlersInit;
pCASMsgHandler casClient::msgHandlers[CA_PROTO_LAST_CMMD+1u];
//
// casClient::casClient()
//
casClient::casClient(caServerI &serverInternal, casMsgIO &msgIOIn) :
inBuf(msgIOIn, *this),
outBuf(msgIOIn, *this),
casCoreClient(serverInternal),
msgIO(msgIOIn)
{
//
// static member init
//
casClient::loadProtoJumpTable();
}
//
// casClient::init()
//
caStatus casClient::init()
{
unsigned serverDebugLevel;
caStatus status;
//
// call base class initializers
//
status = this->inBuf::init();
if (status) {
return status;
}
status = this->outBuf::init();
if (status) {
return status;
}
serverDebugLevel = this->ctx.getServer()->getDebugLevel();
if (serverDebugLevel>0u) {
ca_printf("CAS: created a new client for\n");
this->msgIO.show(serverDebugLevel);
}
return S_cas_success;
}
//
// casClient::loadProtoJumpTable()
//
void casClient::loadProtoJumpTable()
{
//
// Load the static protocol handler tables
//
if (casClient::msgHandlersInit) {
return;
}
//
// Request Protocol Jump Table
//
casClient::msgHandlers[CA_PROTO_NOOP] =
casClient::noopAction;
casClient::msgHandlers[CA_PROTO_EVENT_ADD] =
casClient::eventAddAction;
casClient::msgHandlers[CA_PROTO_EVENT_CANCEL] =
casClient::eventCancelAction;
casClient::msgHandlers[CA_PROTO_READ] =
casClient::readAction;
casClient::msgHandlers[CA_PROTO_WRITE] =
casClient::writeAction;
casClient::msgHandlers[CA_PROTO_SNAPSHOT] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_SEARCH] =
casClient::searchAction;
casClient::msgHandlers[CA_PROTO_BUILD] =
casClient::ignoreMsgAction;
casClient::msgHandlers[CA_PROTO_EVENTS_OFF] =
casClient::eventsOffAction;
casClient::msgHandlers[CA_PROTO_EVENTS_ON] =
casClient::eventsOnAction;
casClient::msgHandlers[CA_PROTO_READ_SYNC] =
casClient::readSyncAction;
casClient::msgHandlers[CA_PROTO_ERROR] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_CLEAR_CHANNEL] =
casClient::clearChannelAction;
casClient::msgHandlers[CA_PROTO_RSRV_IS_UP] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_NOT_FOUND] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_READ_NOTIFY] =
casClient::readNotifyAction;
casClient::msgHandlers[CA_PROTO_READ_BUILD] =
casClient::ignoreMsgAction;
casClient::msgHandlers[REPEATER_CONFIRM] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_CLAIM_CIU] =
casClient::claimChannelAction;
casClient::msgHandlers[CA_PROTO_WRITE_NOTIFY] =
casClient::writeNotifyAction;
casClient::msgHandlers[CA_PROTO_CLIENT_NAME] =
casClient::clientNameAction;
casClient::msgHandlers[CA_PROTO_HOST_NAME] =
casClient::hostNameAction;
casClient::msgHandlers[CA_PROTO_ACCESS_RIGHTS] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_ECHO] =
casClient::echoAction;
casClient::msgHandlers[REPEATER_REGISTER] =
casClient::uknownMessageAction;
casClient::msgHandlers[CA_PROTO_CLAIM_CIU_FAILED] =
casClient::uknownMessageAction;
casClient::msgHandlersInit = TRUE;
}
//
// casClient::~casClient ()
//
casClient::~casClient ()
{
}
//
// casClient::show()
//
void casClient::show(unsigned level)
{
printf ("casClient at %x\n", (unsigned) this);
this->casCoreClient::show(level);
this->inBuf::show(level);
this->outBuf::show(level);
this->msgIO.show(level);
}
/*
* casClient::processMsg()
*/
caStatus casClient::processMsg()
{
unsigned msgsize;
unsigned bytesLeft;
int status;
const caHdr *mp;
caHdr msg;
/*
* parse all any pending messages
*/
bytesLeft = this->inBuf::bytesPresent();
while (bytesLeft) {
if (bytesLeft < sizeof(*mp)) {
return S_cas_partialMessage;
}
mp = (caHdr *) this->inBuf::msgPtr();
this->ctx.setMsg(mp);
this->ctx.setData((void *)(mp+1u));
/*
* convert to local byte order
*/
msg.m_cmmd = ntohs (mp->m_cmmd);
msg.m_postsize = ntohs (mp->m_postsize);
msg.m_type = ntohs (mp->m_type);
msg.m_count = ntohs (mp->m_count);
msg.m_cid = ntohl (mp->m_cid);
msg.m_available = ntohl (mp->m_available);
msgsize = msg.m_postsize + sizeof(*mp);
if (msgsize > bytesLeft) {
return S_cas_partialMessage;
}
if (this->getCAS().getDebugLevel()> 2u) {
this->dumpMsg(&msg, (void *)(mp+1));
}
if (msg.m_cmmd >= NELEMENTS(casClient::msgHandlers)){
return this->uknownMessageAction ();
}
status = (this->*casClient::msgHandlers[mp->m_cmmd]) ();
if (status) {
return status;
}
this->inBuf::removeMsg(msgsize);
bytesLeft = this->inBuf::bytesPresent();
}
return S_cas_success;
}
/*
* casClient::ignoreMsgAction()
*/
caStatus casClient::ignoreMsgAction ()
{
return S_cas_success;
}
/*
* casClient::uknownMessageAction()
*/
caStatus casClient::uknownMessageAction ()
{
const caHdr *mp = this->ctx.getMsg();
ca_printf ("CAS: bad message type=%u\n", mp->m_cmmd);
this->dumpMsg (mp, this->ctx.getData() );
/*
* most clients dont recover from this
*/
this->sendErr (mp, ECA_INTERNAL, "Invalid Msg Type");
/*
* returning S_cas_internal here disconnects
* the client with the bad message
*/
return S_cas_internal;
}
//
// what gets called if the derived class does not supply a
// message handler for the message type (and it isnt a generic
// message)
//
caStatus casClient::eventAddAction ()
{return this->uknownMessageAction ();}
caStatus casClient::eventCancelAction ()
{return this->uknownMessageAction ();}
caStatus casClient::readAction ()
{return this->uknownMessageAction ();}
caStatus casClient::readNotifyAction ()
{return this->uknownMessageAction ();}
caStatus casClient::writeAction ()
{return this->uknownMessageAction ();}
caStatus casClient::searchAction ()
{return this->uknownMessageAction ();}
caStatus casClient::eventsOffAction ()
{return this->uknownMessageAction ();}
caStatus casClient::eventsOnAction ()
{return this->uknownMessageAction ();}
caStatus casClient::readSyncAction ()
{return this->uknownMessageAction ();}
caStatus casClient::clearChannelAction ()
{return this->uknownMessageAction ();}
caStatus casClient::claimChannelAction ()
{return this->uknownMessageAction ();}
caStatus casClient::writeNotifyAction ()
{return this->uknownMessageAction ();}
caStatus casClient::clientNameAction ()
{return this->uknownMessageAction ();}
caStatus casClient::hostNameAction ()
{return this->uknownMessageAction ();}
//
// echoAction()
//
caStatus casClient::echoAction ()
{
const caHdr *mp = this->ctx.getMsg();
void *dp = this->ctx.getData();
int status;
caHdr *reply;
status = this->allocMsg(mp->m_postsize, &reply);
if (status) {
if (status==S_cas_hugeRequest) {
status = sendErr(mp, ECA_TOLARGE, NULL);
}
return status;
}
*reply = *mp;
memcpy((char *) (reply+1), (char *) dp, mp->m_postsize);
this->commitMsg();
return S_cas_success;
}
/*
* casClient::noopAction()
*/
caStatus casClient::noopAction ()
{
return S_cas_success;
}
//
// casClient::sendErr()
//
caStatus casClient::sendErr(
const caHdr *curp,
const int reportedStatus,
const char *pformat,
...
)
{
va_list args;
casChannelI *pciu;
int size;
caHdr *reply;
char *pMsgString;
int status;
va_start(args, pformat);
/*
* allocate plenty of space for a sprintf() buffer
*/
status = this->allocMsg(1024u, &reply);
if(status){
return status;
}
reply[0] = nill_msg;
reply[0].m_cmmd = CA_PROTO_ERROR;
reply[0].m_available = reportedStatus;
switch (curp->m_cmmd) {
case CA_PROTO_SEARCH:
reply->m_cid = curp->m_cid;
break;
case CA_PROTO_EVENT_ADD:
case CA_PROTO_EVENT_CANCEL:
case CA_PROTO_READ:
case CA_PROTO_READ_NOTIFY:
case CA_PROTO_WRITE:
case CA_PROTO_WRITE_NOTIFY:
/*
*
* Verify the channel
*
*/
pciu = this->resIdToChannel(curp->m_cid);
if(pciu){
reply->m_cid = pciu->getCID();
}
else{
reply->m_cid = ~0u;
}
break;
case CA_PROTO_EVENTS_ON:
case CA_PROTO_EVENTS_OFF:
case CA_PROTO_READ_SYNC:
case CA_PROTO_SNAPSHOT:
default:
reply->m_cid = (caResId) ~0UL;
break;
}
/*
* copy back the request protocol
*/
reply[1] = *curp;
/*
* add their optional context string into the protocol
*/
if (pformat) {
pMsgString = (char *) (reply+2);
vsprintf(pMsgString, pformat, args);
size = strlen(pMsgString)+1;
}
else {
size = 0;
}
size += sizeof(*curp);
reply->m_postsize = size;
this->commitMsg();
return S_cas_success;
}
/*
* casClient::sendErrWithEpicsStatus()
*
* same as sendErr() except that we convert epicsStatus
* to a string and send that additional detail
*/
caStatus casClient::sendErrWithEpicsStatus(const caHdr *pMsg,
caStatus epicsStatus, caStatus clientStatus)
{
long status;
char buf[0x1ff];
status = errSymFind(epicsStatus, buf);
if (status) {
sprintf(buf, "UKN error code = 0X%u\n",
epicsStatus);
}
return this->sendErr(pMsg, clientStatus, buf);
}
/*
* casClient::logBadIdWithFileAndLineno()
*/
caStatus casClient::logBadIdWithFileAndLineno(
const caHdr *mp,
const void *dp,
const char *pFileName,
const unsigned lineno
)
{
int status;
this->dumpMsg(mp, dp);
status = this->sendErr(
mp,
ECA_INTERNAL,
"Bad Resource ID at %s.%d",
pFileName,
lineno);
return status;
}
//
// casClient::dumpMsg()
//
// Debug aid - print the header part of a message.
//
// dp arg allowed to be null
//
//
void casClient::dumpMsg(const caHdr *mp, const void *dp)
{
casChannelI *pciu;
char pName[64u];
char pPVName[64u];
this->msgIO.hostNameFromAddr (pName, sizeof (pName));
pciu = this->resIdToChannel(mp->m_cid);
if (pciu) {
strncpy(pPVName, pciu->getPVI().resourceName(), sizeof(pPVName));
pPVName[sizeof(pPVName)-1]='\0';
}
else {
sprintf(pPVName,"%u", mp->m_cid);
}
ca_printf(
"CAS %s on %s at %s: cmd=%d cid=%s typ=%d cnt=%d psz=%d avail=%x\n",
this->userName(),
this->hostName(),
pName,
mp->m_cmmd,
pPVName,
mp->m_type,
mp->m_count,
mp->m_postsize,
mp->m_available);
if (mp->m_cmmd==CA_PROTO_WRITE && mp->m_type==DBR_STRING && dp) {
ca_printf("CAS: The string written: %s \n", (char *)dp);
}
}
//
//
//
const char *casClient::hostName() const
{
return "?";
}
const char *casClient::userName() const
{
return "?";
}

View File

@@ -0,0 +1,65 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casClientIL_h
#define casClientIL_h
#include <caServerIIL.h> // caServerI inline func
//
// find the channel associated with a resource id
//
inline casChannelI *casClient::resIdToChannel(const caResId &id)
{
casChannelI *pChan;
pChan = this->ctx.getServer()->resIdToChannel(id);
this->ctx.setChannel(pChan);
if (pChan) {
this->ctx.setPV(&pChan->getPVI());
}
return pChan;
}
//
// casClient::getDebugLevel()
//
inline unsigned casClient::getDebugLevel()
{
return this->ctx.getServer()->getDebugLevel();
}
#endif // casClientIL_h

View File

@@ -0,0 +1,83 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casChannelIIL.h>
//
// casClientMon::casClientMon()
//
casClientMon::casClientMon(casChannelI &chan, caResId clientIdIn,
const unsigned long count, const unsigned type,
const casEventMask &maskIn, osiMutex &mutexIn) :
casMonitor(clientIdIn, chan, count, type, maskIn, mutexIn)
{
}
//
// casClientMon::~casClientMon()
//
casClientMon::~casClientMon()
{
}
//
// casClientMon::callBack()
//
caStatus casClientMon::callBack(gdd &value)
{
casCoreClient &client = this->getChannel().getClient();
caStatus status;
caHdr msg;
//
// reconstruct the msg header
//
msg.m_cmmd = CA_PROTO_EVENT_ADD;
msg.m_postsize = 0u;
msg.m_type = this->getType();
msg.m_count = this->getCount();
msg.m_cid = this->getChannel().getSID();
msg.m_available = this->getClientId();
status = client.monitorResponse (&this->getChannel(),
msg, &value, S_cas_success);
return status;
}

View File

@@ -0,0 +1,228 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <caServerIIL.h>
//
// static declartions for class casCoreClient
//
int casCoreClient::msgHandlersInit;
pAsyncIoCallBack casCoreClient::asyncIOJumpTable[CA_PROTO_LAST_CMMD+1u];
//
// casCoreClient::casCoreClient()
//
casCoreClient::casCoreClient(caServerI &serverInternal) : casEventSys(*this)
{
assert(&serverInternal);
ctx.setServer(&serverInternal);
ctx.setClient(this);
//
// static member init
//
casCoreClient::loadProtoJumpTable();
}
//
// casCoreClient::loadProtoJumpTable()
//
void casCoreClient::loadProtoJumpTable()
{
//
// Load the static protocol handler tables
//
if (casCoreClient::msgHandlersInit) {
return;
}
//
// Asynch Response Protocol Jump Table
//
casCoreClient::asyncIOJumpTable[CA_PROTO_SEARCH] =
casCoreClient::searchResponse;
casCoreClient::asyncIOJumpTable[CA_PROTO_CLAIM_CIU] =
casCoreClient::createChanResponse;
casCoreClient::asyncIOJumpTable[CA_PROTO_READ] =
casCoreClient::readResponse;
casCoreClient::asyncIOJumpTable[CA_PROTO_READ_NOTIFY] =
casCoreClient::readNotifyResponse;
casCoreClient::asyncIOJumpTable[CA_PROTO_WRITE] =
casCoreClient::writeResponse;
casCoreClient::asyncIOJumpTable[CA_PROTO_WRITE_NOTIFY] =
casCoreClient::writeNotifyResponse;
casCoreClient::asyncIOJumpTable[CA_PROTO_EVENT_ADD] =
casCoreClient::monitorResponse;
casCoreClient::msgHandlersInit = TRUE;
}
//
// casCoreClient::~casCoreClient()
//
casCoreClient::~casCoreClient()
{
tsDLIter<casAsyncIOI> iterIO(this->ioInProgList);
casAsyncIOI *pCurIO;
if (this->ctx.getServer()->getDebugLevel()>0u) {
ca_printf ("CAS: Connection Terminated\n");
}
//
// cancel any pending asynchronous IO
//
pCurIO = iterIO();
while (pCurIO) {
casAsyncIOI *pNextIO;
//
// destructor removes from this list
//
pNextIO = iterIO();
delete pCurIO;
pCurIO = pNextIO;
}
}
//
// casCoreClient::destroy()
//
void casCoreClient::destroy()
{
delete this;
}
//
// casCoreClient::disconnectChan()
//
caStatus casCoreClient::disconnectChan(caResId)
{
printf ("Disconnect Chan issued for inappropriate client type?\n");
return S_cas_success;
}
void casCoreClient::show (unsigned level)
{
printf ("Core client\n");
this->casEventSys::show (level);
printf ("\t%d io ops in progess\n", this->ioInProgList.count());
this->ctx.show (level);
}
//
// one of these for each CA request type that has
// asynchronous completion
//
caStatus casCoreClient::searchResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::createChanResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::readResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::readNotifyResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::writeResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::writeNotifyResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
caStatus casCoreClient::monitorResponse(casChannelI *, const caHdr &,
gdd *, const caStatus)
{
return S_casApp_noSupport;
}
//
// casCoreClient::installChannel()
//
void casCoreClient::installChannel(casChannelI &)
{
assert(0); // dont install channels on the wrong type of client
}
//
// casCoreClient::removeChannel()
//
void casCoreClient::removeChannel(casChannelI &)
{
assert(0); // dont install channels on the wrong type of client
}
//
// casCoreClient::lookupRes()
// (this shows up undefined if it is inline and compiled by g++?)
//
casRes *casCoreClient::lookupRes(const caResId &idIn, casResType type)
{
return this->ctx.getServer()->lookupRes(idIn, type);
}
//
// casCoreClient::asyncIOCompletion()
// (this shows up undefined if it is inline and compiled by g++?)
//
caStatus casCoreClient::asyncIOCompletion(casChannelI *pChan,
const caHdr &msg, gdd *pDesc, caStatus completionStatus)
{
pAsyncIoCallBack pCB;
pCB = casCoreClient::asyncIOJumpTable[msg.m_cmmd];
if (!pCB) {
return S_casApp_noSupport;
}
return (this->*pCB)(pChan, msg, pDesc, completionStatus);
}

View File

@@ -0,0 +1,289 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <caServerIIL.h> // caServerI inline func
#include <casClientIL.h> // casClient inline func
#include <gddApps.h>
//
// CA Server Datagram (DG) Client
//
//
// casDGClient::casDGClient()
//
casDGClient::casDGClient(caServerI &serverIn) :
casClient(serverIn, * (casDGIO *) this)
{
}
//
// casDGClient::destroy()
//
void casDGClient::destroy()
{
printf("Attempt to destroy the DG client was ignored\n");
}
//
// casDGClient::show()
//
void casDGClient::show(unsigned level)
{
this->casClient::show(level);
printf("casDGClient at %x\n", (unsigned) this);
}
//
// casDGClient::searchAction()
//
caStatus casDGClient::searchAction()
{
const caHdr *mp = this->ctx.getMsg();
void *dp = this->ctx.getData();
const char *pChanName = (const char *)dp;
gdd *pCanonicalName;
caStatus status;
int gddStatus;
if (this->ctx.getServer()->getDebugLevel()>2u) {
printf("client is searching for \"%s\"\n", pChanName);
}
//
// If we cant allocate a gdd large enogh to hold the
// longest PV name then just ignore this request
// (and let the client to try again later)
//
// set correct appl type here !!!!
pCanonicalName = new gddAtomic(0u, aitEnumString, 1u);
if (!pCanonicalName) {
return S_cas_success;
}
//
// ask the server tool if this PV exists
//
status = this->ctx.getServer()->pvExistTest(this->ctx,
pChanName, *pCanonicalName);
if (status == S_casApp_asyncCompletion) {
status = S_cas_success;
}
else if (status==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(NULL, *mp,
pCanonicalName, status);
}
//
// delete the PV name object
//
gddStatus = pCanonicalName->Unreference();
assert(gddStatus==0);
return S_cas_success;
}
//
// caStatus casDGClient::searchResponse()
//
caStatus casDGClient::searchResponse(casChannelI *nullPtr, const caHdr &msg,
gdd *pCanonicalName, const caStatus completionStatus)
{
caStatus status;
caHdr *search_reply;
unsigned short *pMinorVersion;
assert(nullPtr==NULL);
this->ctx.getServer()->pvExistTestCompletion();
//
// normal search failure is ignored
//
if (completionStatus==S_casApp_pvNotFound) {
return S_cas_success;
}
/*
* starting with V4.1 the count field is used (abused)
* by the client to store the minor version number of
* the client.
*
* Old versions expect alloc of channel in response
* to a search request. This is no longer supported.
*/
if ( !CA_V44(CA_PROTOCOL_VERSION,msg.m_count) ) {
//
// old connect protocol was dropped when the
// new API was added to the server (they must
// now use clients at EPICS 3.12 or higher)
//
status = this->sendErr(&msg, ECA_DEFUNCT,
"R3.11 connect sequence from old client was ignored");
return status;
}
//
// check for bad parameters
//
if (!pCanonicalName) {
errMessage(S_cas_badParameter, "PV name descr is nill");
return S_cas_success;
}
if (completionStatus) {
errMessage(completionStatus,NULL);
return S_cas_success;
}
if (this->ctx.getServer()->getDebugLevel()>2u) {
char *pCN;
pCN = *pCanonicalName;
if (pCN) {
printf("Search request matched for PV=\"%s\"\n", pCN);
}
}
/*
* obtain space for the reply message
*/
status = this->allocMsg(sizeof(*pMinorVersion), &search_reply);
if (status) {
return status;
}
/*
* type field is abused to carry the IP
* port number here CA_V44 or higher
* (this allows multiple CA servers on one
* host)
*/
*search_reply = msg;
search_reply->m_postsize = sizeof(*pMinorVersion);
search_reply->m_cid = ~0U;
search_reply->m_type = this->ctx.getServer()->serverPortNumber();
search_reply->m_count = 0ul;
/*
* Starting with CA V4.1 the minor version number
* is appended to the end of each search reply.
* This value is ignored by earlier clients.
*/
pMinorVersion = (unsigned short *) (search_reply+1);
*pMinorVersion = htons (CA_MINOR_VERSION);
this->commitMsg();
return S_cas_success;
}
//
// casDGClient::searchFailResponse()
// (only when requested by the client
// - when it isnt a reply to a broadcast)
//
caStatus casDGClient::searchFailResponse(const caHdr *mp)
{
int status;
caHdr *reply;
status = this->allocMsg(0u, &reply);
if(status){
return status;
}
*reply = *mp;
reply->m_cmmd = CA_PROTO_NOT_FOUND;
reply->m_postsize = 0u;
this->commitMsg();
return S_cas_success;
}
//
// caServerI::sendBeacon()
// (implemented here because this has knowledge of the protocol)
//
void caServerI::sendBeacon()
{
union {
caHdr msg;
char buf;
};
//
// create the message
//
memset(&buf, 0, sizeof(msg));
msg.m_cmmd = htons(CA_PROTO_RSRV_IS_UP);
//
// send it to all addresses on the beacon list
//
this->dgClient.sendDGBeacon(buf, sizeof(msg), msg.m_available);
//
// double the period between beacons (but dont exceed max)
//
this->advanceBeaconPeriod();
}
//
// casDGClient::ioSignal()
//
void casDGClient::ioBlockedSignal()
{
//
// NOOP
//
// The DG client never blocks - if we exceed the
// max simultaneous io in progress limit
// then we discard the current request
// (the client will resend later)
//
}

View File

@@ -0,0 +1,157 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <epicsAssert.h>
#include <stdio.h>
#include <limits.h>
#include <casdef.h>
#include <casEventMask.h>
#ifdef TEST
main ()
{
casEventRegistry reg;
casEventMask bill1 (reg, "bill");
casEventMask bill2 (reg, "bill");
casEventMask bill3 (reg, "bill");
casEventMask art1 (reg, "art");
casEventMask art2 (reg, "art");
casEventMask jane (reg, "jane");
casEventMask artBill;
casEventMask tmp;
bill1.show(10u);
reg.show(10u);
bill2.show(10u);
reg.show(10u);
bill3.show(10u);
reg.show(10u);
jane.show(10u);
reg.show(10u);
art1.show(10u);
reg.show(10u);
art2.show(10u);
reg.show(10u);
assert (bill1 == bill2);
assert (bill1 == bill3);
assert (jane != bill1);
assert (jane != art1);
assert (bill1 != art1);
assert (art1 == art2);
artBill = art1 | bill1;
tmp = artBill & art1;
assert (tmp.eventsSelected());
tmp = artBill & bill1;
assert (tmp.eventsSelected());
tmp = artBill&jane;
assert (tmp.noEventsSelected());
}
#endif
//
// casEventRegistry::maskAllocator()
//
inline casEventMask casEventRegistry::maskAllocator()
{
casEventMask evMask;
if (this->allocator>=CHAR_BIT*sizeof(casEventMask::mask)) {
return evMask;
}
evMask.mask = 1u<<(this->allocator++);
return evMask;
}
//
// casEventMask::registerEvent()
//
casEventMask casEventRegistry::registerEvent(const char *pName)
{
casEventMaskEntry *pEntry;
stringId id (pName);
int stat;
casEventMask mask;
if (!this->init) {
errMessage(S_cas_noMemory, "no memory during init?");
return mask;
}
pEntry = this->lookup (id);
if (pEntry) {
return *pEntry;
}
mask = this->maskAllocator();
if (mask.mask == 0u) {
errMessage(S_cas_tooManyEvents, NULL);
return mask;
}
pEntry = new casEventMaskEntry(mask, pName);
if (!pEntry) {
mask.mask = 0u;
errMessage(S_cas_noMemory, "mask bit was lost during init");
return mask;
}
stat = this->add(*pEntry);
assert(stat==0);
return *pEntry;
}
//
// casEventMask::show()
//
void casEventMask::show(unsigned level)
{
if (level>0u) {
printf ("casEventMask = %x\n", this->mask);
}
}
//
// casEventRegistry::show()
//
void casEventRegistry::show(unsigned level)
{
if (level>1u) {
printf ("init = %d bit allocator = %d\n",
this->init, this->allocator);
}
this->resTable <casEventMaskEntry, stringId>::show(level);
}

View File

@@ -0,0 +1,166 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casEventMaskH
#define casEventMaskH
#include <resourceLib.h>
class casEventMaskEntry;
class casEventRegistry;
class casEventMask {
friend inline casEventMask operator| (const casEventMask &lhs,
const casEventMask &rhs);
friend inline casEventMask operator& (const casEventMask &lhs,
const casEventMask &rhs);
friend inline int operator== (const casEventMask &lhs,
const casEventMask &rhs);
friend inline int operator!= (const casEventMask &lhs,
const casEventMask &rhs);
friend class casEventRegistry;
public:
void clear ()
{
this->mask = 0u;
}
casEventMask (casEventRegistry &reg, const char *pName);
casEventMask ()
{
this->clear();
}
void show (unsigned level);
int eventsSelected()
{
return this->mask!=0u;
}
int noEventsSelected()
{
return this->mask==0u;
}
inline void operator|= (const casEventMask &rhs);
inline void operator&= (const casEventMask &rhs);
private:
unsigned mask;
};
class casEventMaskEntry : public tsSLNode<casEventMaskEntry>,
public casEventMask, public stringId {
public:
casEventMaskEntry (casEventMask maskIn, const char *pName) :
casEventMask (maskIn), stringId (pName) {}
void show (unsigned level)
{
this->casEventMask::show(level);
this->stringId::show(level);
}
private:
};
class casEventRegistry : resTable <casEventMaskEntry, stringId> {
public:
casEventRegistry() : allocator(0)
{
int status;
status = this->resTable <casEventMaskEntry, stringId>::init(1u<<8u);
if (status) {
this->init = 0u;
return;
}
this->init = 1u;
}
~casEventRegistry()
{
this->destroyAllEntries();
}
casEventMask registerEvent (const char *pName);
void show (unsigned level);
private:
unsigned allocator;
unsigned char init;
casEventMask maskAllocator();
};
inline casEventMask::casEventMask (casEventRegistry &reg, const char *pName)
{
*this = reg.registerEvent (pName);
}
inline casEventMask operator| (const casEventMask &lhs, const casEventMask &rhs)
{
casEventMask result;
result.mask = lhs.mask | rhs.mask;
return result;
}
inline casEventMask operator& (const casEventMask &lhs, const casEventMask &rhs)
{
casEventMask result;
result.mask = lhs.mask & rhs.mask;
return result;
}
inline int operator== (const casEventMask &lhs, const casEventMask &rhs)
{
return lhs.mask == rhs.mask;
}
inline int operator!= (const casEventMask &lhs, const casEventMask &rhs)
{
return lhs.mask != rhs.mask;
}
inline void casEventMask::operator|= (const casEventMask &rhs) {
*this = *this | rhs;
}
inline void casEventMask::operator&= (const casEventMask &rhs) {
*this = *this & rhs;
}
#endif // casEventMaskH

View File

@@ -0,0 +1,170 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
/*
* ANSI C
*/
#include <string.h>
/*
* EPICS
*/
#include <server.h>
#include <casEventSysIL.h> // casMonitor inline func
#if 0
VERSIONID(caEventQueuec,"%W% %G%")
#endif
#if 0
#include <memDebugLib.h>
#endif
//
// casEventSys::show()
//
void casEventSys::show(unsigned level)
{
printf ("casEventSys at %x\n", (unsigned) this);
if (level>=1u) {
printf ("\thas coreClient at %x\n", (unsigned) &this->coreClient);
printf ("\tnumEventBlocks = %d, maxLogEntries = %d\n",
this->numEventBlocks, this->maxLogEntries);
printf ("\tthere are %d events in the queue\n",
this->eventLogQue.count());
printf ("\tevents off = %d\n", this->eventsOff);
}
}
//
// casEventSys::~casEventSys()
//
casEventSys::~casEventSys()
{
casEvent *pE;
this->mutex.lock();
/*
* They must cancel all active event blocks first
*/
assert (this->numEventBlocks==0);
while ( (pE = this->eventLogQue.get()) ) {
delete pE;
}
}
//
// casEventSys::installMonitor()
//
void casEventSys::installMonitor()
{
this->mutex.lock();
this->numEventBlocks++;
this->maxLogEntries += averageEventEntries;
this->mutex.unlock();
}
//
// casEventSys::removeMonitor()
//
void casEventSys::removeMonitor()
{
this->mutex.lock();
assert (this->numEventBlocks>=1u);
this->numEventBlocks--;
this->maxLogEntries -= averageEventEntries;
this->mutex.unlock();
}
//
// casEventSys::process()
//
casProcCond casEventSys::process()
{
casEvent *pEvent;
caStatus status;
casProcCond cond = casProcOk;
unsigned long nAccepted = 0u;
this->mutex.lock();
while ( (pEvent = this->eventLogQue.get()) ) {
status = pEvent->cbFunc(*this);
if (status==S_cas_success) {
/*
* only remove it after it was accepted by the
* client
*/
nAccepted++;
}
else if (status==S_cas_sendBlocked) {
/*
* not accepted so return to the head of the list
* (we will try again later)
*/
this->insertEventQueue(*pEvent);
cond = casProcOk;
break;
}
else if (status==S_cas_disconnect) {
cond = casProcDisconnect;
break;
}
else {
errMessage(status,
"unexpect error processing event");
cond = casProcDisconnect;
break;
}
}
/*
* call flush function if they provided one
*/
if (nAccepted > 0u) {
this->coreClient.eventFlush();
}
this->mutex.unlock();
return cond;
}

View File

@@ -0,0 +1,68 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casEventSysIL_h
#define casEventSysIL_h
//
// casEventSys::addToEventQueue()
//
inline void casEventSys::addToEventQueue(casEvent &event)
{
this->mutex.lock();
this->eventLogQue.add(event);
this->mutex.unlock();
//
// wakes up the event queue consumer
//
this->coreClient.eventSignal();
}
//
// casMonitor::resIdToMon()
//
inline casMonitor *casEventSys::resIdToMon(const caResId id)
{
casRes *pRes = this->coreClient.lookupRes(id, casClientMonT);
//
// safe to cast because we have checked the type code above
// (and we know that casMonitor derived from casRes)
//
return (casMonitor *) pRes;
}
#endif // casEventSysIL_h

View File

@@ -0,0 +1,587 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
//
// EPICS
//
#include <tsDLList.h>
#include <resourceLib.h>
#include <caProto.h>
typedef aitUint32 caResId;
class casEventSys;
class casChannelI;
//
// casEvent
//
class casEvent : public tsDLNode<casEvent> {
public:
virtual ~casEvent() {}
virtual caStatus cbFunc(casEventSys &)=0;
private:
};
class casChanDelEv : public casEvent {
public:
casChanDelEv(caResId idIn) : id(idIn) {}
caStatus cbFunc(casEventSys &);
private:
caResId id;
};
enum casResType {casChanT=1, casClientMonT, casPVT};
class casRes : public uintRes<casRes>
{
public:
virtual ~casRes() {}
virtual casResType resourceType() const = 0;
virtual void show (unsigned level) = 0;
private:
};
//
// ioBlocked
//
class ioBlocked : public tsDLNode<ioBlocked> {
friend class ioBlockedList;
public:
ioBlocked ();
virtual ~ioBlocked ();
void setBlocked (ioBlockedList &list);
private:
ioBlockedList *pList;
virtual void ioBlockedSignal () = 0;
};
//
// ioBlockedList
//
class ioBlockedList : public tsDLList<ioBlocked> {
friend class ioBlocked;
public:
~ioBlockedList ();
void signal ();
};
//
// ioBlockedList::~ioBlockedList ()
//
inline ioBlockedList::~ioBlockedList ()
{
ioBlocked *pB;
while ( (pB = this->get ()) ) {
pB->pList = NULL;
}
}
//
// ioBlockedList::signal ()
//
// works from a temporary list to avoid problems
// where the virtual function adds ites to the
// list
//
inline void ioBlockedList::signal ()
{
tsDLList<ioBlocked> tmp(*this);
ioBlocked *pB;
while ( (pB = tmp.get ()) ) {
pB->pList = NULL;
pB->ioBlockedSignal ();
}
}
//
// ioBlocked::ioBlocked ()
//
inline ioBlocked::ioBlocked() : pList (NULL)
{
}
//
// ioBlocked::~ioBlocked ()
//
inline ioBlocked::~ioBlocked ()
{
if (this->pList) {
this->pList->remove (*this);
this->pList = NULL;
}
}
//
// ioBlocked::setBlocked ()
//
inline void ioBlocked::setBlocked (ioBlockedList &list)
{
if (!this->pList) {
this->pList = &list;
list.add (*this);
}
else {
//
// requests to be in more than one
// list at at time are fatal
//
assert (&list == this->pList);
}
}
class casMonitor;
//
// casMonEvent
//
class casMonEvent : public casEvent {
public:
//
// only used when this part of another structure
// (and we need to postpone true construction)
//
casMonEvent () : pValue(NULL), id(0u) {}
casMonEvent (casMonitor &monitor, gdd &newValue);
casMonEvent (casMonEvent &initValue);
//
// ~casMonEvent ()
//
~casMonEvent ();
caStatus cbFunc(casEventSys &);
//
// casMonEvent::getValue()
//
gdd *getValue() const
{
return this->pValue;
}
void operator = (class casMonEvent &monEventIn)
{
int gddStatus;
if (this->pValue) {
gddStatus = this->pValue->Unreference();
assert (!gddStatus);
}
if (monEventIn.pValue) {
gddStatus = monEventIn.pValue->Reference();
assert (!gddStatus);
}
this->pValue = monEventIn.pValue;
this->id = monEventIn.id;
}
void clear()
{
int gddStatus;
if (this->pValue) {
gddStatus = this->pValue->Unreference();
assert (!gddStatus);
this->pValue = NULL;
}
this->id = 0u;
}
void assign (casMonitor &monitor, gdd *pValueIn);
private:
gdd *pValue;
caResId id;
};
class osiMutex;
//
// casMonitor()
//
class casMonitor : public tsDLNode<casMonitor>, public casRes {
public:
casMonitor(caResId clientIdIn, casChannelI &chan,
unsigned long nElem, unsigned dbrType,
const casEventMask &maskIn, osiMutex &mutexIn);
virtual ~casMonitor();
caStatus executeEvent(casMonEvent *);
void post(const casEventMask &select, gdd &value);
virtual void show (unsigned level);
virtual caStatus callBack(gdd &value)=0;
caResId getClientId() const
{
return this->clientId;
}
unsigned getType() const
{
return this->dbrType;
}
unsigned long getCount() const
{
return this->nElem;
}
casChannelI &getChannel() const
{
return this->ciu;
}
void postIfModified();
private:
casMonEvent overFlowEvent;
unsigned long const nElem;
osiMutex &mutex;
casChannelI &ciu;
const casEventMask mask;
gdd *pModifiedValue;
caResId const clientId;
unsigned char const dbrType;
unsigned char nPend;
unsigned ovf:1;
unsigned enabled:1;
void enable();
void disable();
void push (gdd &value);
};
//
// casMonitor::post()
// (check for NOOP case in line)
//
inline void casMonitor::post(const casEventMask &select, gdd &value)
{
casEventMask result(select&this->mask);
//
// NOOP if this event isnt selected
//
if (result.noEventsSelected()) {
return;
}
//
// NOOP if currently disabled
//
if (!this->enabled) {
return;
}
//
// else push it on the queue
//
this->push(value);
}
class casCoreClient;
class casAsyncIO;
class casChannelI;
class casCtx;
class caServer;
//
// casAsyncIOI
//
// (server internal asynchronous IO class)
//
//
// Operations may be completed asynchronously
// by the server tool if the virtual function creates a
// casAsyncIO object and returns the status code
// S_casApp_asyncCompletion
//
class casAsyncIOI : public casEvent, public tsDLNode<casAsyncIOI> {
public:
casAsyncIOI(const casCtx &ctx, casAsyncIO &ioIn, gdd *pDD=NULL);
virtual ~casAsyncIOI();
//
// place notification of IO completion on the event queue
//
caStatus postIOCompletion(caStatus completionStatus, gdd *pDesc=NULL);
caServer *getCAS();
//
// casAsyncIOI must always be a base for casAsyncIO
// (the constructor assert fails if this isnt the case)
//
casAsyncIO * operator -> ()
{
return (casAsyncIO *) this;
}
void setServerDelete()
{
this->serverDelete = 1u;
}
inline void lock();
inline void unlock();
gdd *getValuePtr ()
{
return this->pDesc;
}
void clrValue ()
{
if (this->pDesc) {
gddStatus status;
status = this->pDesc->Unreference();
assert(!status);
this->pDesc = NULL;
}
}
private:
//
// casEvent virtual call back function
// (called when IO completion event reaches top of event queue)
//
caStatus cbFunc(casEventSys &);
caHdr const msg;
casCoreClient &client;
casChannelI *pChan; // optional
gdd *pDesc; // optional
caStatus completionStatus;
unsigned inTheEventQueue:1;
unsigned posted:1;
unsigned ioComplete:1;
unsigned serverDelete:1;
};
class casCoreClient;
class casChannel;
class casPVI;
class casChannelI : public tsDLNode<casChannelI>, public casRes {
public:
casChannelI (const casCtx &ctx, casChannel &chanAdapter);
~casChannelI();
void show (unsigned level);
casCoreClient &getClient() const
{
return this->client;
}
const caResId getCID()
{
return this->cid;
}
//
// fetch the unsigned integer server id for this PV
//
inline const caResId getSID();
void postAllModifiedEvents();
//
// addMonitor()
//
inline void addMonitor(casMonitor &mon);
//
// deleteMonitor()
//
inline void deleteMonitor(casMonitor &mon);
//
// findMonitor
// (it is reasonable to do a linear search here because
// sane clients will require only one or two monitors
// per channel)
//
inline casMonitor *findMonitor(const caResId clientIdIn);
inline unsigned getIOOPSInProgress() const;
casPVI &getPVI() const
{
return this->pv;
}
inline void installAsyncIO(casAsyncIOI &);
inline void removeAsyncIO(casAsyncIOI &);
inline void postEvent (const casEventMask &select, gdd &event);
casResType resourceType() const
{
return casChanT;
}
//
// casChannelI must always be a base for casPV
// (the constructor assert fails if this isnt the case)
//
casChannel * operator -> ()
{
return (casChannel *) this;
}
inline void lock();
inline void unlock();
inline void clientDestroy();
protected:
tsDLList<casMonitor> monitorList;
tsDLList<casAsyncIOI> ioInProgList;
casCoreClient &client;
casPVI &pv;
caResId const cid; // client id
unsigned clientDestroyPending:1;
};
//
// class hierarchy added here solely because we need two list nodes
//
class casPVListChan : public casChannelI, public tsDLNode<casPVListChan>
{
public:
inline casPVListChan (const casCtx &ctx, casChannel &chanAdapter);
inline ~casPVListChan();
};
class caServer;
class caServerI;
class casCtx;
class casChannel;
class casPV;
class casPVI :
public stringId, // server PV name table installation
public tsSLNode<casPVI>, // server PV name 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 pName, casPV &pvAdapter);
~casPVI();
//
// for use by the server library
//
caServerI &getCAS() {return this->cas;}
static caStatus verifyPVName(gdd &name);
//
// CA only does 1D arrays for now (and the new server
// temporarily does only scalers)
//
aitIndex nativeCount() {return 1u; /* scaler */ }
//
// only for use by casMonitor
//
caStatus registerEvent ();
void unregisterEvent ();
//
// only for use by casAsyncIOI
//
inline void registerIO();
inline void unregisterIO();
//
// how many async IOs are outstanding?
//
unsigned ioInProgress() const
{
return this->nIOAttached;
}
//
// only for use by casChannelI
//
inline void installChannel(casPVListChan &chan);
//
// only for use by casChannelI
//
inline void removeChannel(casPVListChan &chan);
//
// check for none attached and delete self if so
//
inline void deleteSignal();
void show(unsigned level);
inline void postEvent (const casEventMask &select, gdd &event);
casPV *intefaceObjectPointer()
{
return (casPV *) this;
}
//
// casPVI must always be a base for casPV
// (the constructor assert fails if this isnt the case)
//
casPV * operator -> ()
{
return intefaceObjectPointer();
}
caServer *getExtServer();
//
// bestDBRType()
//
inline caStatus bestDBRType (unsigned &dbrType);
inline void lock();
inline void unlock();
private:
tsDLList<casPVListChan> chanList;
caServerI &cas;
unsigned nMonAttached;
unsigned nIOAttached;
};

View File

@@ -0,0 +1,120 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casEventSysIL.h>
//
// casMonEvent::casMonEvent()
//
casMonEvent::casMonEvent (casMonitor &monitor, gdd &newValue) :
pValue(&newValue),
id(monitor.casRes::getId())
{
int gddStatus;
gddStatus = this->pValue->Reference();
assert (!gddStatus);
}
//
// casMonEvent::casMonEvent()
//
casMonEvent::casMonEvent (casMonEvent &initValue) :
pValue(initValue.pValue),
id(initValue.id)
{
int gddStatus;
if (this->pValue) {
gddStatus = this->pValue->Reference();
assert (!gddStatus);
}
}
//
// ~casMonEvent ()
//
casMonEvent::~casMonEvent ()
{
this->clear();
}
//
// casMonEvent::cbFunc()
//
caStatus casMonEvent::cbFunc(casEventSys &eSys)
{
casMonitor *pMon;
caStatus status;
//
// ignore this event if it is stale (and there is
// no call back object associated with it
//
pMon = eSys.resIdToMon(this->id);
if (!pMon) {
/*
* we know this isnt an overflow event because those are
* removed from the queue when the call back object
* is deleted
*/
status = S_casApp_success;
delete this;
}
else {
status = pMon->executeEvent(this);
}
return status;
}
//
// casMonEvent::assign ()
//
void casMonEvent::assign (casMonitor &monitor, gdd *pValueIn)
{
int gddStatus;
if (this->pValue) {
gddStatus = this->pValue->Unreference();
assert (!gddStatus);
}
if (pValueIn) {
gddStatus = pValueIn->Reference();
assert (!gddStatus);
}
this->pValue = pValueIn;
this->id = monitor.casRes::getId();
}

View File

@@ -0,0 +1,47 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#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
//
#endif // casMonEventIL_h

View File

@@ -0,0 +1,284 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casChannelIIL.h> // casChannelI inline func
#include <casEventSysIL.h> // casEventSys inline func
#include <casMonEventIL.h> // casMonEvent inline func
//
// casMonitor::casMonitor()
//
casMonitor::casMonitor(caResId clientIdIn, casChannelI &chan,
unsigned long nElemIn, unsigned dbrTypeIn,
const casEventMask &maskIn, osiMutex &mutexIn) :
nElem(nElemIn),
mutex(mutexIn),
ciu(chan),
mask(maskIn),
pModifiedValue(NULL),
clientId(clientIdIn),
dbrType(dbrTypeIn),
nPend(0u),
ovf(FALSE),
enabled(FALSE)
{
//
// If these are nill it is a programmer error
//
assert (&this->ciu);
this->ciu.addMonitor(*this);
this->enable();
}
//
// casMonitor::~casMonitor()
//
casMonitor::~casMonitor()
{
casCoreClient &client = this->ciu.getClient();
this->mutex.lock();
//
// remove from the event system
//
if (this->ovf) {
client.removeFromEventQueue (this->overFlowEvent);
}
if (this->pModifiedValue) {
this->pModifiedValue->Unreference();
this->pModifiedValue = NULL;
}
this->ciu.deleteMonitor(*this);
}
//
// casMonitor::enable()
//
void casMonitor::enable()
{
caStatus status;
this->mutex.lock();
if (this->enabled) {
this->mutex.unlock();
return;
}
if (!this->ciu->readAccess()) {
this->mutex.unlock();
return;
}
this->enabled = TRUE;
status = this->ciu.getPVI().registerEvent();
if (status) {
errMessage(status,
"Server tool failed to register event\n");
}
this->mutex.unlock();
}
//
// casMonitor::disable()
//
void casMonitor::disable()
{
this->mutex.lock();
if (!this->enabled) {
this->mutex.unlock();
return;
}
this->enabled = FALSE;
this->ciu.getPVI().unregisterEvent();
this->mutex.unlock();
}
//
// casMonitor::push()
//
void casMonitor::push(gdd &newValue)
{
casCoreClient &client = this->ciu.getClient();
casMonEvent *pLog = NULL;
char full;
this->mutex.lock();
//
// get a new block if we havent exceeded quotas
//
full = (this->nPend>=individualEventEntries)
|| client.casEventSys::full();
if (!full) {
pLog = new casMonEvent(*this, newValue);
if (pLog) {
this->nPend++;
}
}
if (this->ovf) {
if (pLog) {
int gddStatus;
//
// swap values
// (ugly - but avoids purify ukn sym type problem)
// (better to create a temp event object)
//
gdd *pValue = this->overFlowEvent.getValue();
assert(pValue);
gddStatus = pValue->Reference();
assert(!gddStatus);
this->overFlowEvent = *pLog;
pLog->assign(*this, pValue);
gddStatus = pValue->Unreference();
assert(!gddStatus);
client.insertEventQueue(*pLog, &this->overFlowEvent);
}
else {
//
// replace the value with the current one
//
this->overFlowEvent.assign(*this, &newValue);
}
client.removeFromEventQueue(this->overFlowEvent);
pLog = &this->overFlowEvent;
}
else if (!pLog) {
/*
* no log block
*
* => use the over flow block in the event structure
*/
this->ovf = TRUE;
this->overFlowEvent.assign(*this, &newValue);
this->nPend++;
pLog = &this->overFlowEvent;
}
client.addToEventQueue(*pLog);
this->mutex.unlock();
}
//
// casMonitor::executeEvent()
//
caStatus casMonitor::executeEvent(casMonEvent *pEV)
{
caStatus status;
gdd *pVal;
pVal = pEV->getValue ();
assert (pVal);
this->mutex.lock();
if (this->ciu.getClient().getEventsOff()==aitFalse) {
status = this->callBack (*pVal);
}
else {
//
// If flow control is on save the last update
// (and send it later when flow control goes to
// no flow control)
//
if (this->pModifiedValue) {
this->pModifiedValue->Unreference ();
}
pVal->Reference ();
this->pModifiedValue = pVal;
status = S_cas_success;
}
this->mutex.unlock();
//
// if the event isnt accepted we will try
// again later (and the event returns to the queue)
//
if (status) {
return status;
}
//
// decrement the count of the number of events pending
//
this->nPend--;
//
// delete event object if it isnt a cache entry
// saved in the call back object
//
if (pEV == &this->overFlowEvent) {
assert (this->ovf==TRUE);
this->ovf = FALSE;
pEV->clear();
}
else {
delete pEV;
}
return S_cas_success;
}
//
// casMonitor::show(unsigned level)
//
void casMonitor::show(unsigned level)
{
if (level>0u) {
printf(
"\tmonitor type=%u count=%lu client id=%u enabled=%u OVF=%u nPend=%u\n",
dbrType, nElem, clientId, enabled, ovf, nPend);
}
}
//
// casMonitor::postIfModified()
// ( this shows up undefined if g++ compiled and it is inline)
//
void casMonitor::postIfModified()
{
this->mutex.lock();
if (this->pModifiedValue) {
this->callBack (*this->pModifiedValue);
this->pModifiedValue->Unreference ();
this->pModifiedValue = NULL;
}
this->mutex.unlock();
}

115
src/cas/generic/casMsgIO.cc Normal file
View File

@@ -0,0 +1,115 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include<server.h>
casMsgIO::casMsgIO()
{
elapsedAtLastSend = this->elapsedAtLastRecv
= osiTime::getCurrent ();
}
casMsgIO::~casMsgIO()
{
}
//
// casMsgIO::show(unsigned level)
//
void casMsgIO::show(unsigned level)
{
osiTime elapsed;
osiTime current;
double send_delay;
double recv_delay;
if(level>=1u){
current = osiTime::getCurrent ();
elapsed = current - this->elapsedAtLastSend;
send_delay = elapsed;
elapsed = current - this->elapsedAtLastRecv;
recv_delay = elapsed;
printf(
"\tSecs since last send %6.2f, Secs since last receive %6.2f\n",
send_delay, recv_delay);
}
}
xRecvStatus casMsgIO::xRecv(char *pBuf, bufSizeT nBytes, bufSizeT &nActualBytes)
{
xRecvStatus stat;
stat = this->osdRecv(pBuf, nBytes, nActualBytes);
if (stat==xRecvOK) {
this->elapsedAtLastRecv = osiTime::getCurrent();
}
return stat;
}
xSendStatus casMsgIO::xSend(char *pBuf, bufSizeT nBytes, bufSizeT &nActualBytes)
{
xSendStatus stat;
stat = this->osdSend(pBuf, nBytes, nActualBytes);
if (stat == xSendOK) {
this->elapsedAtLastSend = osiTime::getCurrent();
}
return stat;
}
void casMsgIO::sendBeacon(char & /*msg*/, bufSizeT /*length*/,
aitUint32 &/*m_avail*/)
{
printf("virtual base sendBeacon() called?\n");
}
int casMsgIO::getFileDescriptor() const
{
return -1; // some os will not have file descriptors
}
void casMsgIO::setNonBlocking()
{
printf("virtual base setNonBlocking() called?\n");
}
bufSizeT casMsgIO::incommingBytesPresent() const
{
return 0u;
}

168
src/cas/generic/casPV.cc Normal file
View File

@@ -0,0 +1,168 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
//
// Notes:
//
// 1) Always verify that pPVI isnt nill prior to using it
//
#include <server.h>
#include <casPVIIL.h> // casPVI inline func
casPV::casPV (const casCtx &ctx, const char * const pPVName) :
casPVI (*ctx.getServer(), pPVName, *this)
{
}
casPV::~casPV()
{
}
//
// casPV::show()
//
void casPV::show(unsigned level)
{
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()
//
caStatus casPV::interestRegister()
{
return S_casApp_success;
}
//
// casPV::interestDelete()
//
void casPV::interestDelete()
{
}
//
// casPV::beginTransaction()
//
caStatus casPV::beginTransaction()
{
return S_casApp_success;
}
//
// casPV::endTransaction()
//
void casPV::endTransaction()
{
}
//
// casPV::read()
//
caStatus casPV::read(const casCtx &, gdd &)
{
return S_casApp_noSupport;
}
//
// casPV::write()
//
caStatus casPV::write(const casCtx &, gdd &)
{
return S_casApp_noSupport;
}
//
// casPV::bestExternalType()
//
aitEnum casPV::bestExternalType()
{
return aitEnumString;
}
//
// casPV::createChannel()
//
casChannel *casPV::createChannel (const casCtx &ctx, const char * const,
const char * const)
{
return new casChannel (ctx);
}
//
// casPV::destroy()
//
void casPV::destroy()
{
delete this;
}
//
// Server tool calls this function to post a PV event.
//
void casPV::postEvent (const casEventMask &select, gdd &event)
{
(*this)->postEvent (select, event);
}
//
// Find the server associated with this PV
// ****WARNING****
// this returns NULL if the PV isnt currently installed
// into a server (this situation will exist only if
// the pv isnt deleted in a derived classes replacement
// for virtual casPV::destroy()
// ***************
//
caServer *casPV::getCAS()
{
return (*this)->getExtServer();
}

181
src/cas/generic/casPVI.cc Normal file
View File

@@ -0,0 +1,181 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include <server.h>
#include <casPVIIL.h> // casPVI inline func
#include <caServerIIL.h> // caServerI inline func
//
// casPVI::casPVI()
//
casPVI::casPVI(caServerI &casIn, const char * const pNameIn,
casPV &pvAdapterIn) :
cas(casIn),
stringId(pNameIn),
nMonAttached(0u),
nIOAttached(0u)
{
assert(&cas);
//
// casPVI must always be a base of casPV
//
assert(&pvAdapterIn == (casPV *)this);
this->cas.installPV(*this);
}
//
// casPVI::~casPVI()
//
casPVI::~casPVI()
{
casPVListChan *pChan;
casPVListChan *pNextChan;
tsDLIter<casPVListChan> iter(this->chanList);
this->lock();
//
// delete any attached channels
//
pChan = iter();
while (pChan) {
//
// deleting the channel removes it from the list
//
pNextChan = iter();
(*pChan)->destroy();
pChan = pNextChan;
}
this->cas.removePV(*this);
casVerify (this->nIOAttached==0u);
this->unlock();
}
//
// caPVI::verifyPVName()
//
caStatus casPVI::verifyPVName(gdd &name)
{
int gddStatus;
//
// verify up front that they have supplied
// a valid name (so that we wont fail
// in the PV constructor)
//
gddStatus = name.Reference();
if (gddStatus) {
serverToolDebug();
return S_cas_badPVName;
}
gddStatus = name.Unreference();
if (gddStatus) {
serverToolDebug();
return S_cas_badPVName;
}
if (name.PrimitiveType() != aitEnumString) {
serverToolDebug();
return S_cas_badPVName;
}
if (name.Dimension() != 1u) {
serverToolDebug();
return S_cas_badPVName;
}
return S_cas_success;
}
//
// casPVI::show()
//
void casPVI::show(unsigned level)
{
this->lock();
printf("\"%s\"\n", this->resourceName());
(*this)->show(level);
this->unlock();
}
//
// casPVI::registerEvent()
//
caStatus casPVI::registerEvent ()
{
caStatus status;
this->lock();
this->nMonAttached++;
if (this->nMonAttached==1u) {
status = (*this)->interestRegister();
}
else {
status = S_cas_success;
}
this->unlock();
return status;
}
//
// casPVI::unregisterEvent()
//
void casPVI::unregisterEvent()
{
this->nMonAttached--;
if (this->nMonAttached==0u) {
(*this)->interestDelete();
}
}
//
// casPVI::getExtServer()
// (not inline because details of caServerI must not
// leak into server tool)
//
caServer *casPVI::getExtServer()
{
return this->cas.getAdapter();
}

160
src/cas/generic/casPVIIL.h Normal file
View File

@@ -0,0 +1,160 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casPVIIL_h
#define casPVIIL_h
//
// casPVI::lock()
//
inline void casPVI::lock()
{
this->cas.lock();
}
//
// casPVI::unlock()
//
inline void casPVI::unlock()
{
this->cas.unlock();
}
//
// casPVI::installChannel()
//
inline void casPVI::installChannel(casPVListChan &chan)
{
this->lock();
this->chanList.add(chan);
this->unlock();
}
//
// casPVI::removeChannel()
//
inline void casPVI::removeChannel(casPVListChan &chan)
{
this->lock();
this->chanList.remove(chan);
this->unlock();
}
//
// 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();
}
//
// casPVI::deleteSignal()
// check for none attached and delete self if so
//
inline void casPVI::deleteSignal()
{
this->lock();
if (this->chanList.count()==0u) {
(*this)->destroy();
}
else {
this->unlock();
}
}
//
// casPVI::bestDBRType()
//
inline caStatus casPVI::bestDBRType (unsigned &dbrType)
{
int dbr;
dbr = gddAitToDbr[(*this)->bestExternalType()];
if (INVALID_DB_FIELD(dbr)) {
return S_cas_badType;
}
dbrType = dbr;
return S_cas_success;
}
#include <casChannelIIL.h> // inline func for casChannelI
//
// functions that use casChannelIIL.h below here
//
//
// casPVI::postEvent()
//
inline void casPVI::postEvent (const casEventMask &select, gdd &event)
{
casPVListChan *pChan;
if (this->nMonAttached==0u) {
return;
}
//
// the event queue is looking at the DD
// now so it must not be changed
//
event.MarkConstant();
tsDLIter<casPVListChan> iter(this->chanList);
while ( (pChan = iter()) ) {
pChan->postEvent(select, event);
}
}
#endif // casPVIIL_h

View File

@@ -0,0 +1,62 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef casPVListChanIL_h
#define casPVListChanIL_h
//
// casPVListChan::casPVListChan()
//
inline casPVListChan::casPVListChan
(const casCtx &ctx, casChannel &chanAdapterIn) :
casChannelI(ctx, chanAdapterIn)
{
this->pv.installChannel(*this);
}
//
// casPVListChan::~casPVListChan()
//
inline casPVListChan::~casPVListChan()
{
this->pv.removeChannel(*this);
//
// delete signal to PV occurs in
// casChannelI::~casChannelI
//
}
#endif // casPVListChanIL_h

File diff suppressed because it is too large Load Diff

557
src/cas/generic/casdef.h Normal file
View File

@@ -0,0 +1,557 @@
/*
* $Id$
*
* Author: Jeffrey O. Hill
* johill@lanl.gov
* (505) 665 1831
* Date: 1-95
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* $Log$
*
* TODO:
* .03 document new event types for limits change etc
* .04 certain things like native type cant be changed during
* pv id's life time or we will be required to have locking
* (doc this)
* .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
* wild cards? Problems here with knowing PV name structure and
* maximum permutations of name components.
* .16 go through this file and make sure that we are consistent about
* the use of const - use a pointer only in spots where NULL is
* allowed?
* NOTES:
* .01 When this code is used in a multi threaded situation we
* must be certain that the derived class's virtual function
* are not called between derived class destruction and base
* class destruction (or prevent problems if they are).
* Possible solutions
* 1) in the derived classes destructor set a variable which
* inhibits use of the derived classes virtual fnction.
* Each virtual function must check this inhibit bit and return
* an error if it is set
* 2) call a method on the base which prevents further use
* of it by the server from the derived class destructor.
* 3) some form of locking (similar to (1) above)
*/
#ifndef includecasdefh
#define includecasdefh
//
// EPICS
//
#include <alarm.h> // EPICS alarm severity/condition
#include <errMdef.h> // EPICS error codes
#include <gdd.h> // EPICS data descriptors
#if 0
#include <gddApps.h> // EPICS data descriptors appl data types
#include <gddAppTable.h> // EPICS application type table
#endif
typedef aitUint32 caStatus;
#include <casEventMask.h>
#include <casInternal.h>
/*
* ===========================================================
* for internal use by the server library
* (and potentially returned to the server application)
* ===========================================================
*/
#define S_cas_success 0
#define S_cas_internal (M_cas| 1) /*Internal failure*/
#define S_cas_noMemory (M_cas| 2) /*Memory allocation failed*/
#define S_cas_portInUse (M_cas| 3) /*IP port already in use*/
#define S_cas_hugeRequest (M_cas | 4) /*Requested op does not fit*/
#define S_cas_sendBlocked (M_cas | 5) /*Blocked for send q space*/
#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*/
#define S_cas_recvBlocked (M_cas | 13) /*Recv blocked*/
#define S_cas_badType (M_cas | 14) /*Bad data type*/
#define S_cas_timerDoesNotExist (M_cas | 15) /*Timer does not exist*/
#define S_cas_badEventType (M_cas | 16) /*Bad event type*/
#define S_cas_badResourceId (M_cas | 17) /*Bad resource identifier*/
#define S_cas_chanCreateFailed (M_cas | 18) /*Unable to create channel*/
#define S_cas_noRead (M_cas | 19) /*read access denied*/
#define S_cas_noWrite (M_cas | 20) /*write access denied*/
#define S_cas_noEventsSelected (M_cas | 21) /*no events selected*/
#define S_cas_noFD (M_cas | 22) /*no file descriptors available*/
#define S_cas_badProtocol (M_cas | 23) /*protocol from client was invalid*/
#define S_cas_redundantPost (M_cas | 24) /*redundundant io completion post*/
#define S_cas_badPVName (M_cas | 25) /*bad PV name from server tool*/
#define S_cas_badParameter (M_cas | 26) /*bad parameter from server tool*/
#define S_cas_validRequest (M_cas | 27) /*valid request*/
#define S_cas_tooManyEvents (M_cas | 28) /*maximum simult event types exceeded*/
/*
* ===========================================================
* returned by the application (to the server library)
* ===========================================================
*/
#define S_casApp_success 0
#define S_casApp_noMemory (M_casApp | 1) /*Memory allocation failed*/
#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_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*/
//
// casAsyncIO - Channel Access Asynchronous IO API Class
//
// The following virtual functions allow for asynchronous completion:
// caServer::pvExistTest()
// casPV::read()
// casPV::write()
// To initiate asynchronous completion create a casAsyncIO object
// inside one of the above virtual functions and return the status code
// S_casApp_asyncCompletion
//
// All asynchronous completion data must be returned in the
// gdd provided in the virtual functions parameters.
//
// Deletion Responsibility
// -------- --------------
// o the server lib will not call "delete" directly for any
// casAsyncIO created by the server tool because we dont know
// that "new" was called to create the object.
// o The server tool is responsible for reclaiming storage for any
// casAsyncIO it creates. The destroy virtual function will
// assist the server tool with this responsibility. The
// virtual function casAsyncIO::destroy() does a "delete this".
// o Avoid deleting the casAsyncIO immediately after calling
// postIOCompletion(). Instead proper operation requires that
// the server tool wait for the server lib to call destroy after
// the response is succesfully queued to the client
// o If for any reason the server tool needs to cancel an IO
// operation then it should post io completion with status
// S_casApp_canceledAsyncIO. Deleting the asyncronous io
// object prior to its being allowed to forward an IO termination
// message to the client will result in NO IO CALL BACK TO THE
// CLIENT PROGRAM (in this situation a warning message will be printed by
// the server lib).
//
class casAsyncIO : private casAsyncIOI {
public:
//
// casAsyncIO()
//
// Any DD ptr supplied here is used if postIOCompletion()
// is called with a nill DD pointer
//
casAsyncIO(const casCtx &ctx, gdd *pValue=0) :
casAsyncIOI(ctx, *this, pValue) {}
//
// force virtual destructor
//
virtual ~casAsyncIO() {}
//
// called by the server lib after the response message
// is succesfully queued to the client or when the
// IO operation is canceled (client disconnects etc).
//
// default destroy executes a "delete this".
//
virtual void destroy();
//
// 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(caStatus completionStatusIn, gdd *pValue=0)
{
return (*this)->postIOCompletion(completionStatusIn, pValue);
}
//
// Find the server associated with this async IO
// ****WARNING****
// this returns NULL if the async io isnt currently installed
// into a server
// ***************
//
caServer *getCAS()
{
return (*this)->getCAS();
}
//
// return gdd DD ptr stored in base
// (a mechanism to avoid duplicate storage of DD ptr
// - in the base and in the derived)
//
gdd *getValuePtr ()
{
return (*this)->getValuePtr();
}
//
// release any data optionally attached to the asynchronous IO
// object by the constructor - used when the asynchronous
// io saves data but does not return datai with the post
// (ie write)
//
void clrValue()
{
(*this)->clrValue();
}
private:
casAsyncIOI * operator -> ()
{
return (casAsyncIOI *) this;
}
};
//
// caServer - Channel Access Server API Class
//
class caServer {
private:
//
// private reference here inorder to avoid os
// dependent -I during server tool compile
//
caServerI *pCAS;
public:
caServer (unsigned pvMaxNameLength, unsigned pvCountEstimate=0x3ff,
unsigned maxSimultaneousIO=1u);
virtual ~caServer();
//
// Need VF that returns pointer to derived type ?
//
//caStatus enableClients ();
//caStatus disableClients ();
void setDebugLevel (unsigned level);
unsigned getDebugLevel ();
casEventMask registerEvent (const char *pName);
//
// for use when mapping between an event id and an event
// name. Event ids are used to select events.
//
//caEventId eventId (const char *pEventName, const gdd &prototype);
//const char *eventName (const caEventId &id);
//
// show()
//
virtual void show (unsigned level);
//
// The server tool is encouraged to accept multiple PV name
// aliases for the same PV here. However, a unique canonical name
// must be selected for each PV.
//
// returns S_casApp_success and fills in canonicalPVName
// if the PV is in this server tool
//
// returns S_casApp_pvNotFound if the PV does not exist in
// the server tool
//
// The server tool returns the unique canonical name for
// the pv into the gdd. A gdd is used here becuase this
// operation is allowed to complete asynchronously.
//
virtual caStatus pvExistTest (const casCtx &ctx, const char *pPVName,
gdd &canonicalPVName) = 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;
//
// common event masks
// (what is currently used by the CA clients)
//
const casEventMask valueEventMask; // DBE_VALUE
const casEventMask logEventMask; // DBE_LOG
const casEventMask alarmEventMask; // DBE_ALARM
};
//
// casPV() - Channel Access Server Process Variable API Class
//
// 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
// 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 destructor for this object will cancel any
// client attachment to this PV (and reclaim any resources
// allocated by the server library on its behalf)
//
class casPV : private casPVI {
public:
casPV (const casCtx &ctx, const char * const pPVName);
virtual ~casPV ();
//
// Need VF that returns pointer to derived type ?
//
//
// This is called for each PV in the server if
// 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;
//
// Called by the server libary each time that it wishes to
// subscribe for PV change notification from the server
// tool via postEvent() below.
//
virtual caStatus interestRegister ();
//
// called by the server library each time that it wishes to
// remove its subscription for PV value change events
// from the server tool via caServerPostEvents()
//
virtual void interestDelete ();
//
// called by the server library immediately before initiating
// a tranaction (PV state must not be modified during a
// transaction)
//
// HINT: their may be many read/write operatins performed within
// a single transaction if a large array is being transferred
//
virtual caStatus beginTransaction ();
//
// called by the server library immediately after completing
// a tranaction (PV state modification may resume after the
// transaction completes)
//
virtual void endTransaction ();
//
// read
//
// this is allowed to complete asychronously
//
// 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.
//
virtual caStatus read (const casCtx &ctx, gdd &prototype);
//
// write
//
// this is allowed to complete asychronously
// (ie the server tool is allowed to cache the data and actually
// complete the write operation at some time in the future)
//
virtual caStatus write (const casCtx &ctx, gdd &value);
//
// chCreate() is called each time that a PV is attached to
// by a client. The server tool may choose not to
// implement this routine (in which case the channel
// will be created by the server). If the server tool
// implements this function then it must create a casChannel object
// (or a derived class) each time that this routine is called
//
virtual casChannel *createChannel (const casCtx &ctx,
const char * const pUserName, const char * const pHostName);
//
// destroy() is called
// 1) each time that a PV transitions from
// a situation where clients are attached to a situation
// where no clients are attached.
// 2) once for all PVs that exist when the server is deleted
//
// the default destroy() executes "delete this"
//
virtual void destroy ();
//
// tbe best type for clients to use when accessing the
// value of the PV
//
virtual aitEnum bestExternalType ();
//
// Server tool calls this function to post a PV event.
//
void postEvent (const casEventMask &select, gdd &event);
//
// peek at the pv name
//
//inline char *getName() const
//
// Find the server associated with this PV
// ****WARNING****
// this returns NULL if the PV isnt currently installed
// into a server (this situation will exist only if
// the pv isnt deleted in a derived classes replacement
// for virtual casPV::destroy()
// ***************
//
caServer *getCAS();
private:
casPVI * operator -> ()
{
return (casPVI *) this;
}
};
//
// casChannel - Channel Access Server - Channel API Class
//
// Deletion Responsibility
// -------- --------------
// o the server lib will not call "delete" directly for any
// casChannel created by the server tool because we dont know
// that "new" was called to create the object
// o The server tool is responsible for reclaiming storage for any
// casChannel it creates. The destroy() virtual function will
// assist the server tool with this responsibility. The
// virtual function casChannel::destroy() does a "delete this".
// o The destructor for this object will cancel any
// client attachment to this channel (and reclaim any resources
// allocated by the server library on its behalf)
//
class casChannel : private casPVListChan {
public:
casChannel(const casCtx &ctx);
virtual ~casChannel();
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
//
virtual aitBool readAccess () const;
virtual aitBool writeAccess () const;
// return true to hint that the opi should ask the operator
// for confirmation prior writing to this PV
virtual aitBool confirmationRequested () const;
//
// This is called for each channel in the server if
// caServer::show() is called and the level is high
// enough
//
virtual void show(unsigned level);
//
// destroy() is called when
// 1) there is a client initiated channel delete
// 2) there is a server tool initiaed PV delete
// 3) there is a server tool initiated server delete
//
// the casChannel::destroy() executes a "delete this"
//
virtual void destroy();
//
// server tool calls this to indicate change of channel state
// (ie access rights changed)
//
void postEvent (const casEventMask &select, gdd &event);
//
// Find the PV associated with this channel
// ****WARNING****
// this returns NULL if the channel isnt currently installed
// into a PV (this situation will exist only if
// the channel isnt deleted in a derived classes replacement
// for virtual casChannel::destroy()
// ***************
//
casPV *getPV();
private:
casChannelI * operator -> ()
{
return (casChannelI *) this;
}
};
#endif /* ifdef includecasdefh (this must be the last line in this file) */

View File

@@ -0,0 +1,229 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
//
// ANSI C
//
#include <stdlib.h>
//
// GDD
//
#include <gdd.h>
#include <gddAppTable.h>
typedef aitUint32 gddAppFuncTableStatus;
#define S_gddAppFuncTable_Success 0u
#define S_gddAppFuncTable_badType (M_gddFuncTbl|1u) /*unregisted appl type*/
#define S_gddAppFuncTable_gddLimit (M_gddFuncTbl|2u) /*at gdd lib limit*/
#define S_gddAppFuncTable_noMemory (M_gddFuncTbl|3u) /*dynamic memory pool exhausted*/
#ifndef NELEMENTS
#define NELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
#endif
template <class PV>
class gddAppFuncTable {
public:
gddAppFuncTable();
//
// typedef for the app read function to be called
//
typedef gddAppFuncTableStatus (PV::*gddAppReadFunc)(gdd &value);
//
// installReadFunc()
// (g++ gags when these are coded outside the class def?)
//
gddAppFuncTableStatus installReadFunc(const unsigned type, gddAppReadFunc pMFuncIn)
{
//
// Attempt to expand the table if the app type will not fit
//
if (type>=this->maxAppType) {
this->newTbl(type);
if (type>=this->maxAppType) {
return S_gddAppFuncTable_noMemory;
}
}
this->pMFuncRead[type]=pMFuncIn;
return S_gddAppFuncTable_Success;
}
gddAppFuncTableStatus installReadFunc(const char * const pName, gddAppReadFunc pMFuncIn)
{
aitUint32 type;
gddStatus rc;
rc = gddApplicationTypeTable::
app_table.RegisterApplicationType (pName, type);
if (rc!=0 && rc!=gddErrorAlreadyDefined && rc!=gddErrorAlreadyAssigned) {
printf(
"at gdd lib limit => read of PV attribute \"%s\" will fail\n", pName);
return S_gddAppFuncTable_gddLimit;
}
# ifdef DEBUG
printf("installing PV attribute %s = %d\n", pName, type);
# endif
return this->installReadFunc(type, pMFuncIn);
}
//
//
//
gddAppFuncTableStatus read(PV &pv, gdd &value);
private:
//
// The total number of application tags to manage should be
// hidden from the application (eventually allow for auto
// expansion of the table)
//
gddAppReadFunc *pMFuncRead;
unsigned maxAppType;
void newTbl(unsigned neMaxType);
};
//
// gddAppFuncTable<PV>::gddAppFuncTable()
//
// The total number of application tags to manage should be
// hidden from the application
//
template <class PV>
inline gddAppFuncTable<PV>::gddAppFuncTable() :
pMFuncRead(NULL),
maxAppType(0u)
{
}
//
// gddAppFuncTable<PV>::newTbl()
//
// The total number of application tags to manage should be
// hidden from the application
//
template <class PV>
inline void gddAppFuncTable<PV>::newTbl(unsigned newApplTypeMax)
{
gddAppReadFunc *pMNewFuncTbl;
unsigned maxApp;
if(this->maxAppType>=newApplTypeMax) {
return;
}
maxApp = newApplTypeMax+(1u<<6u);
pMNewFuncTbl = new gddAppReadFunc[maxApp];
if (pMNewFuncTbl) {
if (this->pMFuncRead) {
memcpy( pMNewFuncTbl,
this->pMFuncRead,
this->maxAppType*sizeof(*pMNewFuncTbl));
delete [] this->pMFuncRead;
memset(&pMNewFuncTbl[this->maxAppType], 0,
(maxApp-this->maxAppType) *
sizeof(*pMNewFuncTbl));
}
else {
memset(pMNewFuncTbl, 0,
maxApp * sizeof(*pMNewFuncTbl));
}
this->pMFuncRead = pMNewFuncTbl;
this->maxAppType = maxApp;
}
}
//
// gddAppFuncTable<PV>::installReadFunc()
//
//
// gddAppFuncTable<PV>::read()
//
// (g++ generates "multiply defined symbols" message unless I set this
// to be inline)
//
template <class PV>
inline gddAppFuncTableStatus gddAppFuncTable<PV>::read(PV &pv, gdd &value)
{
gddAppFuncTableStatus status;
gddAppReadFunc pFunc;
unsigned type;
//
// if this gdd is a container then step through it
// and fetch all of the values inside
//
if (value.IsContainer()) {
gddContainer *pCont = (gddContainer *) &value;
gddCursor curs = pCont->GetCursor();
gdd *pItem;
status = S_gddAppFuncTable_Success;
for (pItem=curs.First(); pItem; pItem=curs.Next())
{
status = this->read(pv, *pItem);
if (status) {
break;
}
}
return status;
}
//
// otherwise call the function associated
// with this application type
//
type = value.ApplicationType();
if (type>=this->maxAppType) {
errPrintf (S_gddAppFuncTable_badType, __FILE__,
__LINE__, "- large appl type code = %u\n",
type);
return S_gddAppFuncTable_badType;
}
pFunc = this->pMFuncRead[type];
if (!pFunc) {
errPrintf (S_gddAppFuncTable_badType, __FILE__,
__LINE__, "- ukn appl type code = %u\n",
type);
return S_gddAppFuncTable_badType;
}
status = (pv.*pFunc)(value);
return status;
}

135
src/cas/generic/inBuf.cc Normal file
View File

@@ -0,0 +1,135 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include<server.h>
//
// inBuf::inBuf()
//
inBuf::inBuf(casMsgIO &virtualCircuit, osiMutex &mutexIn) :
mutex(mutexIn),
io(virtualCircuit)
{
assert(&this->io);
this->bytesInBuffer = 0u;
this->nextReadIndex = 0u;
this->bufSize = 0u;
this->pBuf = NULL;
}
//
// inBuf::init()
//
caStatus inBuf::init()
{
this->bufSize = io.optimumBufferSize();
this->pBuf = new char [this->bufSize];
if (!this->pBuf) {
this->bufSize = 0u;
return S_cas_noMemory;
}
return S_cas_success;
}
//
// inBuf::~inBuf()
//
inBuf::~inBuf()
{
if (this->pBuf) {
delete [] this->pBuf;
}
}
void inBuf::show(unsigned level)
{
if (level>1u) {
printf(
"\tUnprocessed request bytes = %d\n",
this->bytesAvailable());
}
}
casFillCondition inBuf::fill()
{
unsigned bytesReq;
unsigned bytesRecv;
xRecvStatus stat;
assert(this->pBuf);
//
// move back any prexisting data to the start of the buffer
//
if (this->nextReadIndex>0u) {
unsigned unprocessedBytes;
unprocessedBytes = this->bytesInBuffer - this->nextReadIndex;
//
// memmove() handles overlapping buffers
//
if (unprocessedBytes>0u) {
memmove (this->pBuf, this->pBuf+this->nextReadIndex,
unprocessedBytes);
}
this->bytesInBuffer = unprocessedBytes;
this->nextReadIndex = 0u;
}
//
// noop if the buffer is full
//
bytesReq = this->bufSize - this->bytesInBuffer;
if (bytesReq <= 0u) {
return casFillFull;
}
stat = this->io.xRecv( &this->pBuf[this->bytesInBuffer],
bytesReq, bytesRecv);
if (stat != xRecvOK) {
return casFillDisconnect;
}
if (bytesRecv==0u) {
return casFillNone;
}
assert (bytesRecv<=bytesReq);
this->bytesInBuffer += bytesRecv;
if (this->bufSize==this->bytesInBuffer) {
return casFillFull;
}
else {
return casFillPartial;
}
}

171
src/cas/generic/osiTimer.cc Normal file
View File

@@ -0,0 +1,171 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*
* NOTES:
* 1) this should use a binary tree to speed up inserts?
*/
#include <assert.h>
#include <stdio.h>
#include <osiTimer.h>
//
// osiTimer::arm()
//
void osiTimer::arm (const osiTime * const pInitialDelay)
{
tsDLIter<osiTimer> iter (staticTimerQueue.pending);
osiTimer *pTmr;
//
// calculate absolute expiration time
// (dont call base's delay() virtual func
// in the constructor)
//
if (pInitialDelay) {
this->exp = osiTime::getCurrent() + *pInitialDelay;
}
else {
this->exp = osiTime::getCurrent() + this->delay();
}
#ifdef DEBUG
double theDelay;
osiTime copy;
if (pInitialDelay) {
theDelay = *pInitialDelay;
}
else {
theDelay = this->delay();
}
printf ("Arm of \"%s\" with delay %lf at %x\n",
this->name(), theDelay, (unsigned)this);
#endif
//
// insert into the pending queue
//
// Finds proper time sorted location using
// a linear search.
// **** this should use a binary tree ????
//
while ( (pTmr = iter()) ) {
if (pTmr->exp >= this->exp) {
break;
}
}
if (pTmr) {
pTmr = pTmr->getPrev ();
staticTimerQueue.pending.insert (*this, pTmr);
}
else {
staticTimerQueue.pending.add (*this);
}
this->state = ositPending;
# ifdef DEBUG
staticTimerQueue.show(10u);
# endif
}
//
// osiTimer::~osiTimer()
//
osiTimer::~osiTimer()
{
switch (this->state) {
case ositPending:
staticTimerQueue.pending.remove(*this);
break;
case ositExpired:
staticTimerQueue.expired.remove(*this);
break;
case ositLimbo:
break;
default:
assert(0);
}
this->state = ositLimbo;
}
//
// osiTimer::again()
//
osiBool osiTimer::again()
{
//
// default is to run the timer only once
//
return osiFalse;
}
//
// osiTimer::destroy()
//
void osiTimer::destroy()
{
delete this;
}
//
// osiTimer::delay()
//
const osiTime osiTimer::delay()
{
//
// default to 1 sec
//
return osiTime (1.0);
}
void osiTimer::show (unsigned level)
{
osiTime cur(osiTime::getCurrent());
double delay;
printf ("osiTimer at %x for \"%s\" with again = %d\n",
(unsigned) this, this->name(), this->again());
if (this->exp >= cur) {
delay = this->exp - cur;
}
else {
delay = cur - this->exp;
delay = -delay;
}
if (level>=1u) {
printf ("\tdelay to expire = %f, state = %d\n",
delay, this->state);
}
}

View File

@@ -0,0 +1,172 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
//
// NOTES:
// 1) when making this safe for multi threading consider the possibility of
// object delete just after finding an active fdRegI on
// the list but before callBack().
//
//
#include <stdio.h>
#include <osiTimer.h>
osiTimerQueue staticTimerQueue;
//
// osiTimerQueue::delayToFirstExpire()
//
osiTime osiTimerQueue::delayToFirstExpire()
{
osiTimer *pTmr;
osiTime cur(osiTime::getCurrent());
osiTime delay;
pTmr = pending.first();
if (pTmr) {
if (pTmr->exp>=cur) {
delay = pTmr->exp - cur;
}
else {
delay = osiTime(0u,0u);
}
}
else {
//
// no timer in the queue - return a long delay - 30 min
//
delay = osiTime(30u * secPerMin, 0u);
}
#ifdef DEBUG
printf("delay to first item on the queue %lf\n", (double) delay);
#endif
return delay;
}
//
// osiTimerQueue::process()
//
void osiTimerQueue::process()
{
tsDLIter<osiTimer> iter (this->pending);
osiTimer *pTmr;
osiTimer *pNextTmr;
osiTime cur(osiTime::getCurrent());
// no recursion
if (this->inProcess) {
return;
}
this->inProcess = osiTrue;
pNextTmr = iter();
while ( (pTmr = pNextTmr) ) {
if (pTmr->exp >= cur) {
break;
}
pNextTmr = iter();
this->pending.remove(*pTmr);
pTmr->state = ositExpired;
this->expired.add(*pTmr);
}
//
// prevent problems if they access the
// above list while in an "expire()" call back
//
while ( (pTmr = this->expired.first()) ) {
#ifdef DEBUG
double diff = cur-pTmr->exp;
printf ("expired %x for \"%s\" with error %lf\n",
pTmr, pTmr->name(), diff);
#endif
pTmr->expire();
//
// verify that the current timer
// wasnt deleted in "expire()"
//
if (pTmr == this->expired.first()) {
this->expired.get();
pTmr->state = ositLimbo;
if (pTmr->again()) {
pTmr->arm();
}
else {
pTmr->destroy();
}
}
}
this->inProcess = osiFalse;
}
//
// osiTimerQueue::show()
//
void osiTimerQueue::show(unsigned level)
{
tsDLIter<osiTimer> iter (this->pending);
osiTimer *pTmr;
printf("osiTimerQueue with %d items pending and %d items expired\n",
this->pending.count(), this->expired.count());
while ( (pTmr = iter()) ) {
pTmr->show(level);
}
}
//
// osiTimerQueue::~osiTimerQueue()
//
osiTimerQueue::~osiTimerQueue()
{
osiTimer *pTmr;
//
// destroy any unexpired timers
//
while ( (pTmr = this->pending.get()) ) {
pTmr->destroy();
}
//
// destroy any expired timers
//
while ( (pTmr = this->expired.get()) ) {
pTmr->destroy();
}
}

234
src/cas/generic/outBuf.cc Normal file
View File

@@ -0,0 +1,234 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#include<server.h>
//
// outBuf::outBuf()
//
outBuf::outBuf(casMsgIO &virtualCircuit, osiMutex &mutexIn) :
io(virtualCircuit),
mutex(mutexIn)
{
assert(&io);
this->stack = 0u;
this->bufSize = 0u;
this->pBuf = NULL;
}
//
// outBuf::init()
//
caStatus outBuf::init()
{
this->bufSize = io.optimumBufferSize();
this->pBuf = new char [this->bufSize];
if (!this->pBuf) {
this->bufSize = 0u;
return S_cas_noMemory;
}
return S_cas_success;
}
//
// outBuf::~outBuf()
//
outBuf::~outBuf()
{
if (this->pBuf) {
delete [] this->pBuf;
}
}
//
// outBuf::allocMsg()
//
// allocates space in the outgoing message buffer
//
// (if space is avilable this leaves the send lock applied)
//
caStatus outBuf::allocMsg (
bufSizeT extsize, // extension size
caHdr **ppMsg
)
{
bufSizeT msgsize;
extsize = CA_MESSAGE_ALIGN(extsize);
msgsize = extsize + sizeof(caHdr);
if (msgsize>this->bufSize) {
return S_cas_hugeRequest;
}
this->mutex.lock();
if (this->stack + msgsize > this->bufSize) {
/*
* Try to flush the output queue
*/
this->flush();
/*
* If this failed then the fd is nonblocking
* and we will let select() take care of it
*/
if (this->stack + msgsize > this->bufSize) {
this->mutex.unlock();
this->sendBlockSignal();
return S_cas_sendBlocked;
}
}
/*
* it fits so commitMsg() will move the stack pointer forward
*/
*ppMsg = (caHdr *) &this->pBuf[this->stack];
return S_cas_success;
}
/*
* outBuf::commitMsg()
*/
void outBuf::commitMsg ()
{
caHdr *mp;
bufSizeT size;
bufSizeT extSize;
bufSizeT diff;
assert (this->bufSize);
mp = (caHdr *) &this->pBuf[this->stack];
extSize = CA_MESSAGE_ALIGN(mp->m_postsize);
assert((extSize&0x7)==0);
//
// Guarantee that all portions of outgoing messages
// (including alignment pad) are initialized
//
diff = extSize - mp->m_postsize;
if (diff>0u) {
char *pExt = (char *) (mp+1);
memset(pExt + mp->m_postsize, '\0', diff);
}
mp->m_postsize = extSize;
if (this->getDebugLevel()) {
ca_printf (
"CAS Response => cmd=%d id=%x typ=%d cnt=%d psz=%d avail=%x\n",
mp->m_cmmd,
mp->m_cid,
mp->m_type,
mp->m_count,
mp->m_postsize,
mp->m_available);
}
/*
* convert to network byte order
* (data following header is handled elsewhere)
*/
mp->m_cmmd = htons (mp->m_cmmd);
mp->m_postsize = htons (mp->m_postsize);
mp->m_count = htons (mp->m_count);
mp->m_cid = htonl (mp->m_cid);
mp->m_available = htonl (mp->m_available);
size = sizeof(caHdr) + mp->m_postsize;
this->stack += size;
assert (this->stack <= this->bufSize);
this->mutex.unlock();
}
//
// outBuf::flush()
//
casFlushCondition outBuf::flush()
{
bufSizeT nBytes;
xSendStatus stat;
if (this->stack<=0u) {
return casFlushCompleted;
}
stat = this->io.xSend(this->pBuf, this->stack, nBytes);
if (stat!=xSendOK) {
return casFlushDisconnect;
}
else if (nBytes >= this->stack) {
this->stack=0u;
return casFlushCompleted;
}
else if (nBytes) {
bufSizeT len;
len = this->stack-nBytes;
//
// memmove() is ok with overlapping buffers
//
memmove (this->pBuf, &this->pBuf[nBytes], len);
this->stack = len;
return casFlushPartial;
}
else {
return casFlushNone;
}
}
//
// outBuf::show(unsigned level)
//
void outBuf::show(unsigned level)
{
if (level>1u) {
printf(
"\tUndelivered response bytes =%d\n",
this->bytesPresent());
}
}

995
src/cas/generic/server.h Normal file
View File

@@ -0,0 +1,995 @@
/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* History
* $Log$
*
*/
#ifndef INCLserverh
#define INCLserverh
#ifdef __STDC__
# define VERSIONID(NAME,VERS) \
const char *EPICS_CAS_VID_ ## NAME = VERS;
#else /*__STDC__*/
# define VERSIONID(NAME,VERS) \
const char *EPICS_CAS_VID_/* */NAME = VERS;
#endif /*__STDC__*/
#if defined(CAS_VERSION_GLOBAL) && 0
# define HDRVERSIONID(NAME,VERS) VERSIONID(NAME,VERS)
#else /*CAS_VERSION_GLOBAL*/
# define HDRVERSIONID(NAME,VERS)
#endif /*CAS_VERSION_GLOBAL*/
HDRVERSIONID(serverh, "%W% %G%")
//
// ANSI C
//
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
//
// EPICS
//
#include <epicsAssert.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include <db_access.h>
//
// CA
//
#include <caCommonDef.h>
#include <caerr.h>
#include <casdef.h>
#include <osiTime.h>
//
// gdd
//
#include <dbMapper.h>
#include <gddApps.h>
//
// CAS
//
void casVerifyFunc(const char *pFile, unsigned line, const char *pExp);
void serverToolDebugFunc(const char *pFile, unsigned line);
#define serverToolDebug() {serverToolDebugFunc(__FILE__, __LINE__); }
#define casVerify(EXP) {if ((EXP)==0) casVerifyFunc(__FILE__, __LINE__, #EXP); }
caStatus createDBRDD(unsigned dbrType, aitIndex dbrCount, gdd *&pDescRet);
caStatus copyBetweenDD(gdd &dest, gdd &src);
//
// casMsgIO
//
enum xRecvStatus {xRecvOK, xRecvDisconnect};
enum xSendStatus {xSendOK, xSendDisconnect};
enum casIOState {casOnLine, casOffLine};
typedef unsigned bufSizeT;
class casMsgIO {
public:
casMsgIO();
virtual ~casMsgIO();
osiTime timeOfLastXmit() const;
osiTime timeOfLAstRecv() const;
//
// show status of IO subsystem
// (cant be const because a lock is taken)
//
void show (unsigned level);
//
// device dependent recv
//
xSendStatus xSend (char *pBuf, bufSizeT nBytesToSend,
bufSizeT &nBytesSent);
xRecvStatus xRecv (char *pBuf, bufSizeT nBytesToRecv,
bufSizeT &nByesRecv);
virtual caStatus init()=0;
virtual bufSizeT optimumBufferSize ()=0;
virtual bufSizeT incommingBytesPresent() const;
virtual casIOState state() const=0;
virtual void hostNameFromAddr (char *pBuf, unsigned bufSize)=0;
virtual int getFileDescriptor() const;
virtual void setNonBlocking();
//
// only for use with DG io
//
virtual void sendBeacon(char &msg, bufSizeT length,
aitUint32 &m_avail);
private:
//
// private data members
//
osiTime elapsedAtLastSend;
osiTime elapsedAtLastRecv;
virtual xSendStatus osdSend (const char *pBuf,
bufSizeT nBytesReq, bufSizeT &nBytesActual) =0;
virtual xRecvStatus osdRecv (char *pBuf,
bufSizeT nBytesReq, bufSizeT &nBytesActual) =0;
virtual void osdShow (unsigned level) const = 0;
};
#include <casIOD.h> // IO dependent
#include <casOSD.h> // OS dependent
enum casProcCond {casProcOk, casProcDisconnect};
/*
* maximum peak log entries for each event block (registartion)
* (events cached into the last queue entry if over flow occurs)
*/
const unsigned char individualEventEntries = 16u;
/*
* maximum average log entries for each event block (registartion)
* (events cached into the last queue entry if over flow occurs)
*/
const unsigned char averageEventEntries = 4u;
typedef caResId caEventId;
//
// fwd ref
//
class caServerI;
//
// casEventSys
//
class casEventSys {
public:
casEventSys (casCoreClient &coreClientIn) :
coreClient(coreClientIn),
numEventBlocks(0u),
maxLogEntries(individualEventEntries),
eventsOff(aitFalse)
{
}
~casEventSys();
void show(unsigned level);
casProcCond process();
//void cancelIODone (casAsyncIO *pEventToDelete);
void installMonitor();
void removeMonitor();
void removeFromEventQueue(casEvent &);
inline void addToEventQueue(casEvent &);
void insertEventQueue(casEvent &insert, casEvent *pPrev=NULL);
aitBool full();
inline casMonitor *resIdToMon(const caResId id);
casCoreClient &getCoreClient()
{
return this->coreClient;
}
aitBool getEventsOff () const
{
return this->eventsOff?aitTrue:aitFalse;
}
void setEventsOn()
{
this->eventsOff = aitFalse;
}
void setEventsOff()
{
this->eventsOff = aitTrue;
}
private:
tsDLList<casEvent> eventLogQue;
osiMutex mutex;
casCoreClient &coreClient;
unsigned numEventBlocks; // N event blocks installed
unsigned maxLogEntries; // max log entries
unsigned char eventsOff;
};
//
// casEventSys::insertEventQueue()
//
inline void casEventSys::insertEventQueue(casEvent &insert, casEvent *pPrevEvent)
{
this->mutex.lock();
this->eventLogQue.insert(insert, pPrevEvent);
this->mutex.unlock();
}
//
// casEventSys::removeFromEventQueue()
//
inline void casEventSys::removeFromEventQueue(casEvent &event)
{
this->mutex.lock();
this->eventLogQue.remove(event);
this->mutex.unlock();
}
//
// casEventSys::full()
//
inline aitBool casEventSys::full()
{
if (this->eventLogQue.count()>=this->maxLogEntries) {
return aitTrue;
}
else {
return aitFalse;
}
}
//
// casClientMon
//
class casClientMon : public casMonitor {
public:
casClientMon(casChannelI &, caResId clientId,
const unsigned long count, const unsigned type,
const casEventMask &maskIn, osiMutex &mutexIn);
~casClientMon();
caStatus callBack(gdd &value);
casResType resourceType() const
{
return casClientMonT;
}
caResId getId() const
{
return this->casRes::getId();
}
private:
};
//
// ndim == 0 => scaler
// otherwise pIndexArray points to an array of ndim items
//
#define nDimScaler 0U
class casCtx {
public:
casCtx() :
pMsg(NULL), pData(NULL), pCAS(NULL), pClient(NULL),
pChannel(NULL), pPV(NULL) {}
//
// get
//
const caHdr *getMsg() const {return this->pMsg;};
void *getData() const {return this->pData;};
caServerI * getServer() const {return this->pCAS;}
casCoreClient * getClient() const {return this->pClient;}
casPVI * getPV() const {return this->pPV;}
casChannelI * getChannel() const {return this->pChannel;}
//
// set
//
void setMsg(const caHdr *p) {this->pMsg = p;};
void setData(void *p) {this->pData = p;};
void setServer(caServerI *p)
{
this->pCAS = p;
}
void setClient(casCoreClient *p) {
this->pClient = p;
}
void setPV(casPVI *p) {this->pPV = p;}
void setChannel(casChannelI *p) {this->pChannel = p;}
void show (unsigned level)
{
printf ("casCtx at %x\n", (unsigned) this);
if (level >= 1u) {
printf ("\tpMsg = %x\n", (unsigned) pMsg);
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);
}
}
private:
const caHdr *pMsg; // ca message header
void *pData; // pointer to data following header
caServerI *pCAS;
casCoreClient *pClient;
casChannelI *pChannel;
casPVI *pPV;
};
enum casFillCondition{
casFillNone,
casFillPartial,
casFillFull,
casFillDisconnect};
//
// inBuf
//
class inBuf {
public:
inBuf(casMsgIO &, osiMutex &);
caStatus init(); //constructor does not return status
virtual ~inBuf();
bufSizeT bytesPresent() const {
return this->bytesInBuffer-this->nextReadIndex;
}
bufSizeT bytesAvailable() const {
bufSizeT bp;
bufSizeT ibp;
bp = this->bytesPresent();
ibp = this->io.incommingBytesPresent();
return bp + ibp;
}
aitBool full() const
{
if (this->bytesPresent()>=this->bufSize) {
return aitTrue;
}
return aitFalse;
}
void clear()
{
this->bytesInBuffer = 0u;
this->nextReadIndex = 0u;
}
//
//
//
char *msgPtr() const {return &this->pBuf[this->nextReadIndex];}
//
//
//
void removeMsg(unsigned nBytes) {
this->nextReadIndex += nBytes;
assert(this->nextReadIndex<=this->bytesInBuffer);
}
//
// fill the input buffer with any incoming messages
//
casFillCondition fill();
void show(unsigned level);
virtual unsigned getDebugLevel()=0;
private:
osiMutex &mutex;
casMsgIO &io;
char *pBuf;
bufSizeT bufSize;
bufSizeT bytesInBuffer;
bufSizeT nextReadIndex;
};
//
// outBuf
//
enum casFlushCondition{
casFlushNone,
casFlushPartial,
casFlushCompleted,
casFlushDisconnect};
class outBuf {
public:
outBuf (casMsgIO &, osiMutex &);
caStatus init(); //constructor does not return status
virtual ~outBuf();
//
// number of bytes in the output queue?
//
bufSizeT bytesPresent() const
{ return this->stack; }
//
// flush output queue
// (returns the number of bytes sent)
//
casFlushCondition flush();
//
// allocate message buffer space
// (leaves message buffer locked)
//
caStatus allocMsg (unsigned extsize, caHdr **ppMsg);
//
// commits message allocated with allocMsg()
//
void commitMsg ();
//
// release an allocated message (but dont send it)
//
void discardMsg () { this->mutex.unlock(); };
void show(unsigned level);
virtual unsigned getDebugLevel()=0;
virtual void sendBlockSignal()=0;
private:
casMsgIO &io;
osiMutex &mutex;
char *pBuf;
bufSizeT bufSize;
bufSizeT stack;
};
//
// casCoreClient
// (this will eventually support direct communication
// between the client lib and the server lib)
//
class casCoreClient;
typedef caStatus (casCoreClient::*pAsyncIoCallBack)
(casChannelI *pChan, const caHdr &, gdd *, const caStatus);
class casCoreClient : public osiMutex, public ioBlocked,
public casEventSys {
public:
casCoreClient(caServerI &serverInternal);
virtual ~casCoreClient();
virtual void destroy();
virtual caStatus disconnectChan(caResId id);
virtual void eventSignal() = 0;
virtual void eventFlush() = 0;
virtual caStatus start () = 0;
virtual void show (unsigned level);
virtual void installChannel (casChannelI &);
virtual void removeChannel (casChannelI &);
void installAsyncIO(casAsyncIOI &ioIn)
{
this->lock();
this->ioInProgList.add(ioIn);
this->unlock();
}
void removeAsyncIO(casAsyncIOI &ioIn)
{
this->lock();
this->ioInProgList.remove(ioIn);
this->unlock();
}
casRes *lookupRes(const caResId &idIn, casResType type);
caServerI &getCAS() const {return *this->ctx.getServer();}
caStatus asyncIOCompletion(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, caStatus completionStatus);
virtual caStatus monitorResponse(casChannelI *,
const caHdr &, gdd *, const caStatus);
protected:
casCtx ctx;
private:
tsDLList<casAsyncIOI> ioInProgList;
//
// one virtual function for each CA request type that has
// asynchronous completion
//
virtual caStatus searchResponse(casChannelI *, const caHdr &,
gdd *, const caStatus);
virtual caStatus createChanResponse(casChannelI *,
const caHdr &, gdd *, const caStatus);
virtual caStatus readResponse(casChannelI *, const caHdr &,
gdd *, const caStatus);
virtual caStatus readNotifyResponse(casChannelI *,
const caHdr &, gdd *, const caStatus);
virtual caStatus writeResponse(casChannelI *, const caHdr &,
gdd *, const caStatus);
virtual caStatus writeNotifyResponse(casChannelI *,
const caHdr &, gdd *, const caStatus);
//
// static members
//
static void loadProtoJumpTable();
static pAsyncIoCallBack asyncIOJumpTable[CA_PROTO_LAST_CMMD+1u];
static int msgHandlersInit;
};
//
// casClient
//
class casClient;
typedef caStatus (casClient::*pCASMsgHandler) ();
class casClient : public inBuf, public outBuf, public casCoreClient {
public:
casClient (caServerI &, casMsgIO &);
caStatus init(); //constructor does not return status
virtual ~casClient ();
void show(unsigned level);
//
// send error response to a message
//
caStatus sendErr(const caHdr *, const int reportedStatus,
const char *pFormat, ...);
unsigned getMinorVersion() const {return this->minor_version_number;}
//
// find the channel associated with a resource id
//
inline casChannelI *resIdToChannel(const caResId &id);
inline unsigned getDebugLevel();
int getFD() const
{
return this->msgIO.getFileDescriptor();
}
void setNonBlocking()
{
this->msgIO.setNonBlocking();
}
void sendBeacon(char &msg, bufSizeT length,
aitUint32 &m_avail)
{
this->msgIO.sendBeacon(msg, length, m_avail);
}
protected:
unsigned minor_version_number;
caStatus processMsg();
//
//
//
caStatus sendErrWithEpicsStatus(const caHdr *pMsg,
caStatus epicsStatus, caStatus clientStatus);
//
// logBadIdWithFileAndLineno()
//
# define logBadId(MP, DP) \
this->logBadIdWithFileAndLineno(MP, DP, __FILE__, __LINE__)
caStatus logBadIdWithFileAndLineno(const caHdr *mp,
const void *dp, const char *pFileName,
const unsigned lineno);
private:
casMsgIO &msgIO;
//
// dump message to stderr
//
void dumpMsg(const caHdr *mp, const void *dp);
//
// one function for each CA request type
//
caStatus uknownMessageAction ();
caStatus ignoreMsgAction ();
caStatus noopAction ();
virtual caStatus eventAddAction ();
virtual caStatus eventCancelAction ();
virtual caStatus readAction ();
virtual caStatus readNotifyAction ();
virtual caStatus writeAction ();
virtual caStatus searchAction ();
virtual caStatus eventsOffAction ();
virtual caStatus eventsOnAction ();
virtual caStatus readSyncAction ();
virtual caStatus clearChannelAction ();
virtual caStatus claimChannelAction ();
virtual caStatus writeNotifyAction ();
virtual caStatus clientNameAction ();
virtual caStatus hostNameAction ();
virtual caStatus echoAction ();
//
// obtain the user name and host from the derived class
//
virtual const char *hostName() const;
virtual const char *userName() const;
//
// static members
//
static void loadProtoJumpTable();
static pCASMsgHandler msgHandlers[CA_PROTO_LAST_CMMD+1u];
static int msgHandlersInit;
};
//
// casStrmClient
//
class casStrmClient : public casClient, public tsDLNode<casStrmClient> {
public:
casStrmClient (caServerI &, casMsgIO &);
caStatus init(); //constructor does not return status
~casStrmClient();
void show(unsigned level);
//
// installChannel()
//
void installChannel(casChannelI &chan);
//
// removeChannel()
//
void removeChannel(casChannelI &chan);
//
// one function for each CA request type that has
// asynchronous completion
//
caStatus createChanResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
caStatus readResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
caStatus readNotifyResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
caStatus writeResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
caStatus writeNotifyResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
caStatus monitorResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
//
//
//
caStatus noReadAccessEvent(casClientMon *);
//
// obtain the user name and host
//
const char *hostName () const;
const char *userName () const;
caStatus disconnectChan (caResId id);
private:
tsDLList<casChannelI> chanList;
char *pUserName;
char *pHostName;
struct cas_io_in_prog *ioBlockCache;
//
// createChannel()
//
caStatus createChannel (const char *pName);
//
// verify read/write requests
//
caStatus verifyRequest (casChannelI *&pChan);
//
// one function for each CA request type
//
caStatus eventAddAction ();
caStatus eventCancelAction ();
caStatus readAction ();
caStatus readNotifyAction ();
caStatus writeAction ();
caStatus eventsOffAction ();
caStatus eventsOnAction ();
caStatus readSyncAction ();
caStatus clearChannelAction ();
caStatus claimChannelAction ();
caStatus writeNotifyAction ();
caStatus clientNameAction ();
caStatus hostNameAction ();
//
// accessRightsResponse()
//
caStatus accessRightsResponse (casChannelI *pciu);
//
// these prepare the gdd based on what is in the ca hdr
//
caStatus read (gdd *&pDesc);
caStatus write ();
//
// channelCreateFailed()
//
caStatus channelCreateFailed (const caHdr *mp, caStatus createStatus);
caStatus writeArrayData();
caStatus writeScalerData();
caStatus writeString();
};
//
// casDGClient
//
class casDGClient : private casDGIO, public casClient {
public:
casDGClient (caServerI &serverIn);
caStatus init() //constructor does not return status
{
caStatus status;
//
// init the base classes
//
status = casDGIO::init();
if (status) {
return status;
}
status = this->casClient::init();
if (status) {
return status;
}
return this->start();
}
void show(unsigned level);
//
// only for use with DG io
//
void sendDGBeacon(char &msg, bufSizeT length,
aitUint32 &m_avail)
{
this->casClient::sendBeacon(msg, length, m_avail);
}
void destroy();
private:
void ioBlockedSignal(); // dummy
//
// one function for each CA request type
//
caStatus searchAction ();
//
// searchFailResponse()
//
caStatus searchFailResponse(const caHdr *pMsg);
caStatus searchResponse(casChannelI *pChan, const caHdr &msg,
gdd *pDesc, const caStatus status);
};
#include <casClientOS.h> // OS dependent
class casClientMon;
//
// caServerI
//
class caServerI : public caServerOS, public caServerIO,
public osiMutex, public ioBlockedList,
private uintResTable<casRes>,
public casEventRegistry {
public:
caServerI(caServer &tool, unsigned pvMaxNameLength,
unsigned pvCountEstimate, unsigned maxSimultaneousIO);
caStatus init(); //constructor does not return status
~caServerI();
//
// find the channel associated with a resource id
//
inline casChannelI *resIdToChannel(const caResId &id);
//
// find the PV associated with a resource id
//
casPVI *resIdToPV(const caResId &id);
//
// find the async IO associated with a resource id
//
casAsyncIO *resIdToAsyncIO(const caResId &id);
//
// find the client monitor associated with a resource id
//
casClientMon *resIdToClientMon(const caResId &idIn);
casDGClient &castClient() {return this->dgClient;}
void installClient(casStrmClient *pClient);
void removeClient(casStrmClient *pClient);
casStrmClient *firstClient() const
{
return clientList.first();
}
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
//
aitBool roomForNewChannel() const;
//
// only for use with DG io
//
void sendBeacon();
unsigned getDebugLevel() const { return debugLevel; }
void setDebugLevel(unsigned debugLevelIn)
{
this->debugLevel = debugLevelIn;
}
inline caStatus pvExistTest (const casCtx &ctx, const char *pPVName,
gdd &canonicalPVName);
inline void pvExistTestCompletion();
inline aitBool pvExistTestPossible();
casPVI *createPV(/* const */gdd &name);
osiTime getBeaconPeriod() const { return this->beaconPeriod; }
void show(unsigned level);
inline casRes *lookupRes(const caResId &idIn, casResType type);
unsigned getPVMaxNameLength() const
{
return this->pvMaxNameLength;
}
caServer *getAdapter()
{
return &this->adapter;
}
uintResTable<casRes> &getResTable() {return *this;}
void installItem(casRes &res)
{
this->uintResTable<casRes>::installItem(res);
}
casRes *removeItem(casRes &res)
{
return this->uintResTable<casRes>::remove(res);
}
//
// call virtual function in the interface class
//
caServer * operator -> ()
{
return this->getAdapter();
}
void connectCB();
private:
void advanceBeaconPeriod();
casDGOS dgClient;
casCtx ctx;
tsDLList<casStrmClient> clientList;
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 = ???
const unsigned pvCountEstimate;
// the maximum number of characters in a pv name
// default = none - required initialization parameter
const unsigned maxSimultaneousIO;
};
#define CAServerConnectPendQueueSize 10
const osiTime CAServerMaxBeaconPeriod (5.0 /* sec */);
const osiTime CAServerMinBeaconPeriod (1.0e-3 /* sec */);
/*
* If there is insufficent space to allocate an
* asynch IO in progress block then we will end up
* with pIoInProgress nill and activeAsyncIO true.
* This protects the app from simultaneous multiple
* invocation of async IO on the same PV.
*/
#define maxIOInProg 50
/*
* this really should be in another header file
*/
extern "C" {
void ca_printf (const char *pFormat, ...);
}
#endif /*INCLserverh*/

View File

@@ -0,0 +1,6 @@
this directory contains the bsd socket dependent source for
the EPICS ca server

View File

@@ -0,0 +1,217 @@
//
// $Id$
//
// verify connection state prior to doing anything in this file
//
//
// $Log$
//
#include <server.h>
#include <sigPipeIgnore.h>
const unsigned caServerConnectPendQueueSize = 10u;
int caServerIO::staticInitialized;
//
// caServerIO::staticInit()
//
inline void caServerIO::staticInit()
{
if (caServerIO::staticInitialized) {
return;
}
installSigPipeIgnore();
caServerIO::staticInitialized = TRUE;
}
//
// caServerIO::init()
//
caStatus caServerIO::init()
{
caAddr serverAddr;
int yes = TRUE;
int status;
int len;
int port;
caServerIO::staticInit();
/*
* Setup the server socket
*/
this->sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (this->sock<0) {
return S_cas_noFD;
}
/*
* release the port in case we exit early
*/
status = setsockopt (
this->sock,
SOL_SOCKET,
SO_REUSEADDR,
(char *) &yes,
sizeof (yes));
if (status<0) {
ca_printf("CAS: server set SO_REUSEADDR failed?\n",
strerror(SOCKERRNO));
return S_cas_internal;
}
memset ((char *)&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sa.sa_family = AF_INET;
serverAddr.in.sin_addr.s_addr = INADDR_ANY;
port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT);
serverAddr.in.sin_port = ntohs (port);
status = bind(
this->sock,
&serverAddr.sa,
sizeof(serverAddr.sa));
if (status<0) {
if (SOCKERRNO == EADDRINUSE) {
//
// force assignement of a default port
// (so the getsockname() call below will
// work correctly)
//
serverAddr.in.sin_port = ntohs (0);
status = bind(
this->sock,
&serverAddr.sa,
sizeof(serverAddr.sa));
if (status<0) {
ca_printf (
"CAS: default bind failed because \"%s\"\n",
strerror(SOCKERRNO));
return S_cas_portInUse;
}
}
else {
ca_printf("CAS: bind failed because \"%s\"\n",
strerror(SOCKERRNO));
return S_cas_portInUse;
}
}
len = sizeof (this->addr.sa);
status = getsockname (
this->sock,
&this->addr.sa,
&len);
if (status<0) {
ca_printf("CAS: getsockname failed because: %s\n",
strerror(SOCKERRNO));
return S_cas_internal;
}
//
// be sure of this now so that we can fetch the IP
// address and port number later
//
assert (this->addr.sa.sa_family == AF_INET);
status = listen(this->sock, caServerConnectPendQueueSize);
if(status < 0) {
ca_printf("CAS: Listen error %s\n",strerror(SOCKERRNO));
return S_cas_internal;
}
this->sockState = casOnLine;
return S_cas_success;
}
//
// caServerIO::serverPortNumber()
//
unsigned caServerIO::serverPortNumber() const
{
return (unsigned) ntohs(this->addr.in.sin_port);
}
//
// caServerIO::show()
//
void caServerIO::show (unsigned level)
{
printf ("caServerIO at %x\n", (unsigned) this);
if (level>1u) {
printf ("\tsock = %d, state = %d\n",
this->sock, this->sockState);
}
}
//
// caServerIO::newDGIO()
//
casMsgIO *caServerIO::newDGIO() const
{
casDGIO *pDG;
pDG = new casDGIO();
if (!pDG) {
return pDG;
}
return pDG;
}
//
// caServerIO::newStreamIO()
//
casMsgIO *caServerIO::newStreamIO() const
{
caAddr newAddr;
SOCKET newSock;
int length;
length = sizeof(newAddr.sa);
newSock = accept(this->sock, &newAddr.sa, &length);
if (newSock<0) {
if (SOCKERRNO!=EWOULDBLOCK) {
ca_printf(
"CAS: %s accept error %s\n",
__FILE__,
strerror(SOCKERRNO));
}
return NULL;
}
else if (sizeof(newAddr.sa)>(size_t)length) {
ca_printf("CAS: accept returned bad address len?\n");
return NULL;
}
return new casStreamIO(newSock, newAddr);
}
//
// caServerIO::setNonBlocking()
//
void caServerIO::setNonBlocking()
{
int status;
int yes = TRUE;
status = socket_ioctl(this->sock, FIONBIO, &yes);
if (status<0) {
ca_printf(
"%s:CAS: server non blocking IO set fail because \"%s\"\n",
__FILE__, strerror(SOCKERRNO));
this->sockState = casOffLine;
}
}
//
// caServerIO::getFD()
//
int caServerIO::getFD() const
{
return this->sock;
}

View File

@@ -0,0 +1,398 @@
/*
*
* Author: Jeffrey O. Hill
* hill@luke.lanl.gov
* (505) 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* History
*/
//
//
// Should I fetch the MTU from the outgoing interface?
//
//
#include <server.h>
//
// casDGIO::casDGIO()
//
casDGIO::casDGIO()
{
this->sockState=casOffLine;
ellInit(&this->destAddrList);
memset((char *)&this->lastRecvAddr, '\0', sizeof(this->lastRecvAddr));
this->sock = -1;
this->lastRecvAddrInit = FALSE;
}
//
// casDGIO::init()
//
caStatus casDGIO::init()
{
int yes = TRUE;
caAddr serverAddr;
int status;
unsigned short port;
this->sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (this->sock < 0) {
errMessage(S_cas_noMemory,
"CAS: unable to create cast socket\n");
return S_cas_noMemory;
}
status = setsockopt(
this->sock,
SOL_SOCKET,
SO_BROADCAST,
(char *)&yes,
sizeof(yes));
if (status<0) {
errMessage(S_cas_internal,
"CAS: unable to set up cast socket\n");
return S_cas_internal;
}
/*
* release the port in case we exit early. Also if
* on a kernel with MULTICAST mods then we can have
* two UDP servers on the same port number (requires
* setting SO_REUSEADDR prior to the bind step below).
*/
status = setsockopt(
this->sock,
SOL_SOCKET,
SO_REUSEADDR,
(char *) &yes,
sizeof (yes));
if (status<0) {
errMessage(S_cas_internal,
"CAS: unable to set SO_REUSEADDR on UDP socket?\n");
}
memset ((char *)&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sa.sa_family = AF_INET;
serverAddr.in.sin_addr.s_addr = INADDR_ANY;
port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT);
serverAddr.in.sin_port = htons (port);
status = bind(
this->sock,
&serverAddr.sa,
sizeof (serverAddr.sa));
if (status<0) {
errPrintf(S_cas_portInUse,
__FILE__, __LINE__,
"CAS: bind to the broadcast port = %u fail: %s\n",
(unsigned) port,
strerror(SOCKERRNO));
return S_cas_portInUse;
}
port = caFetchPortConfig(&EPICS_CA_REPEATER_PORT, CA_REPEATER_PORT);
caDiscoverInterfaces(
&this->destAddrList,
this->sock,
port);
caAddConfiguredAddr(
&this->destAddrList,
&EPICS_CA_ADDR_LIST,
this->sock,
port);
# if defined(DEBUG)
caPrintAddrList(&destAddrList);
# endif
this->sockState=casOnLine;
return S_cas_success;
}
//
// use an initialize routine ?
//
casDGIO::~casDGIO()
{
caAddrNode *pAddr;
if(this->sock>=0){
socket_close(this->sock);
}
while ( (pAddr = (caAddrNode *)ellGet(&this->destAddrList)) ) {
free((char *)pAddr);
}
}
//
// casDGIO::hostName()
//
void casDGIO::hostNameFromAddr (char *pBuf, unsigned bufSize)
{
hostNameFromIPAddr(&this->lastRecvAddr, pBuf, bufSize);
}
//
// casDGIO::show()
//
void casDGIO::osdShow (unsigned level) const
{
printf ("casDGIO at %x\n", (unsigned) this);
if (level>=1u) {
printf(
"client address=%x, port=%x\n",
(unsigned) ntohl(this->lastRecvAddr.in.sin_addr.s_addr),
ntohs(this->lastRecvAddr.in.sin_port));
}
}
//
// casDGIO::setNonBlocking()
//
void casDGIO::setNonBlocking()
{
int status;
int yes = TRUE;
if (this->sockState!=casOnLine) {
return;
}
status = socket_ioctl(this->sock, FIONBIO, &yes);
if (status<0) {
ca_printf("%s:CAS: UDP non blocking IO set fail because \"%s\"\n",
__FILE__, strerror(SOCKERRNO));
this->sockState = casOffLine;
}
}
//
// casDGIO::osdRecv()
//
xRecvStatus casDGIO::osdRecv(char *pBuf, bufSizeT size, bufSizeT &actualSize)
{
int status;
int addrSize;
if (this->sockState!=casOnLine) {
return xRecvDisconnect;
}
addrSize = sizeof(this->lastRecvAddr.sa);
status = recvfrom(this->sock, pBuf, size, 0,
&this->lastRecvAddr.sa, &addrSize);
if (status<0) {
if(SOCKERRNO == EWOULDBLOCK){
actualSize = 0u;
return xRecvOK;
}
else {
ca_printf("CAS: UDP recv error",strerror(SOCKERRNO));
actualSize = 0u;
return xRecvOK;
}
}
this->lastRecvAddrInit = TRUE;
#if 0
if(pRsrv->CASDEBUG>1){
char buf[64];
(*pRsrv->osm.hostName)
(&pCastClient->addr, buf, sizeof(buf));
ca_printf(
"CAS: incomming %d byte UDP msg from %s\n",
pCastClient->pRecv->cnt,
buf);
}
#endif
actualSize = (bufSizeT) status;
return xRecvOK;
}
//
// casDGIO::osdSend()
//
xSendStatus casDGIO::osdSend(const char *pBuf, bufSizeT size,
bufSizeT &actualSize)
{
int status;
int anerrno;
assert(this->lastRecvAddrInit);
#if 0
if(this->pCAS->debugLevel>2u){
char buf[64];
(*pCAS->osm.hostName) (
&this->addr,
buf,
sizeof(buf));
ca_printf(
"CAS: Sending a %d byte reply to %s\n",
this->pSend->stk,
buf);
}
#endif
if (this->sockState!=casOnLine) {
return xSendDisconnect;
}
if (size==0u) {
actualSize = 0u;
return xSendOK;
}
status = sendto(this->sock, pBuf, size, 0,
&this->lastRecvAddr.sa,
sizeof(this->lastRecvAddr.sa));
if (status>0) {
if (size != (unsigned) status) {
printf ("CAS: partial UDP msg discarded??\n");
}
}
else if (status==0) {
this->sockState = casOffLine;
printf ("CAS: UDP send returns zero??\n");
return xSendDisconnect;
}
else {
anerrno = SOCKERRNO;
if (anerrno != EWOULDBLOCK) {
ca_printf(
"CAS: UDP send failed \"%s\"\n",
strerror(anerrno));
}
}
actualSize = size;
return xSendOK;
}
//
// casDGIO::sendBeacon()
//
void casDGIO::sendBeacon(char &msg, unsigned length, aitUint32 &m_avail)
{
caAddrNode *pAddr;
int status;
if (this->sockState!=casOnLine) {
return;
}
for( pAddr = (caAddrNode *)ellFirst(&this->destAddrList);
pAddr;
pAddr = (caAddrNode *)ellNext(&pAddr->node)) {
m_avail = htonl(pAddr->srcAddr.in.sin_addr.s_addr);
status = sendto(
this->sock,
&msg,
length,
0,
&pAddr->destAddr.sa,
sizeof(pAddr->destAddr.sa));
if (status < 0) {
ca_printf(
"CAS:beacon error was \"%s\" at addr=%x sock=%d\n",
strerror(SOCKERRNO),
pAddr->destAddr.in.sin_addr.s_addr,
this->sock);
}
}
}
//
// casDGIO::optimumBufferSize()
//
// this returns 9000 on the suns - perhaps this will result in
// to much IP fragmentation
//
bufSizeT casDGIO::optimumBufferSize ()
{
#if 1
//
// must update client before the message size can be
// increased here
//
return MAX_UDP;
#else
int n;
int size;
int status;
if (this->sockState!=casOnLine) {
return MAX_UDP;
}
/* fetch the TCP send buffer size */
n = sizeof(size);
status = getsockopt(
this->sock,
SOL_SOCKET,
SO_SNDBUF,
(char *)&size,
&n);
if(status < 0 || n != sizeof(size)){
size = MAX_UDP;
}
if (size<=0) {
size = MAX_UDP;
}
return (bufSizeT) size;
#endif
}
//
// casDGIO::state()
//
casIOState casDGIO::state() const
{
return this->sockState;
}
//
// casDGIO::getFileDescriptor()
//
int casDGIO::getFileDescriptor() const
{
return this->sock;
}

View File

@@ -0,0 +1,155 @@
//
// $Id$
//
// casIOD.h - Channel Access Server IO Dependent for BSD sockets
//
//
// Some BSD calls have crept in here
//
// $Log$
//
#ifndef includeCASIODH
#define includeCASIODH
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#if 0 // func proto do not have args for C++
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifdef __cplusplus
}
#endif
#include <bsdProto.h>
typedef int SOCKET;
#define SOCKERRNO errno
#define socket_close(S) close(S)
#define socket_ioctl(A,B,C) ioctl(A,B,C)
// ca
#include <addrList.h>
void hostNameFromIPAddr (const caAddr *pAddr,
char *pBuf, unsigned bufSize);
//
// assuming al posix machines are IEEE fload will be wrong
//
#define ntohf(A) (A)
#define ntohd(A) (A)
#define htonf(A) (A)
#define htond(A) (A)
class caServerIO {
public:
caServerIO() : sockState(casOffLine), sock(-1) {}
~caServerIO()
{
if (this->sock>=0 && this->sockState==casOnLine) {
socket_close(this->sock);
}
}
caStatus init(); //constructor does not return status
//
// show status of IO subsystem
//
void show (unsigned level);
int getFD() const;
void setNonBlocking();
unsigned serverPortNumber() const;
//
// called when we expect that a virtual circuit for a
// client can be created
//
casMsgIO *newStreamIO() const;
//
// called to create datagram IO
//
casMsgIO *newDGIO() const;
private:
casIOState sockState;
SOCKET sock;
caAddr addr;
//
// static member data
//
static int staticInitialized;
//
// static member func
//
static inline void staticInit();
};
class casStreamIO : public casMsgIO {
public:
casStreamIO(const SOCKET s, const caAddr &a);
caStatus init();
~casStreamIO();
int getFileDescriptor() const;
void setNonBlocking();
bufSizeT optimumBufferSize ();
casIOState state() const;
void hostNameFromAddr (char *pBuf, unsigned bufSize);
xSendStatus osdSend (const char *pBuf,
bufSizeT nBytesReq, bufSizeT &nBytesActual);
xRecvStatus osdRecv (char *pBuf,
bufSizeT nBytesReq, bufSizeT &nBytesActual);
void osdShow (unsigned level) const;
bufSizeT incommingBytesPresent() const;
private:
casIOState sockState;
SOCKET sock;
caAddr addr;
};
class casDGIO : public casMsgIO {
public:
casDGIO();
caStatus init();
~casDGIO();
int getFileDescriptor() const;
void setNonBlocking();
bufSizeT optimumBufferSize ();
void sendBeacon(char &msg, bufSizeT length,
aitUint32 &m_avail);
casIOState state() const;
void hostNameFromAddr (char *pBuf, unsigned bufSize);
xSendStatus osdSend (const char *pBuf,
bufSizeT nBytesReq, bufSizeT &nBytesActual);
xRecvStatus osdRecv (char *pBuf,
bufSizeT nBytesReq, bufSizeT &nBytesActual);
void osdShow (unsigned level) const;
private:
ELLLIST destAddrList;
caAddr lastRecvAddr;
SOCKET sock;
casIOState sockState;
char lastRecvAddrInit;
};
// no additions below this line
#endif // includeCASIODH

View File

@@ -0,0 +1,382 @@
//
// $Id$
//
// verify connection state prior to doing anything in this file
//
//
// $Log$
//
#include <server.h>
//
// casStreamIO::casStreamIO()
//
casStreamIO::casStreamIO(const SOCKET s, const caAddr &a) :
sock(s), addr(a)
{
assert (sock>=0);
this->sockState = casOffLine;
}
//
// casStreamIO::init()
//
caStatus casStreamIO::init()
{
int yes = TRUE;
int status;
/*
* see TCP(4P) this seems to make unsollicited single events much
* faster. I take care of queue up as load increases.
*/
status = setsockopt(
this->sock,
IPPROTO_TCP,
TCP_NODELAY,
(char *)&yes,
sizeof(yes));
if (status<0) {
ca_printf(
"CAS: %s TCP_NODELAY option set failed %s\n",
__FILE__,
strerror(SOCKERRNO));
return S_cas_internal;
}
/*
* turn on KEEPALIVE so if the client crashes
* this task will find out and exit
*/
status = setsockopt(
sock,
SOL_SOCKET,
SO_KEEPALIVE,
(char *)&yes,
sizeof(yes));
if (status<0) {
ca_printf(
"CAS: %s SO_KEEPALIVE option set failed %s\n",
__FILE__,
strerror(SOCKERRNO));
return S_cas_internal;
}
#ifdef MATCHING_BUFFER_SIZES
/*
* set TCP buffer sizes to be synergistic
* with CA internal buffering
*/
i = MAX_MSG_SIZE;
status = setsockopt(
sock,
SOL_SOCKET,
SO_SNDBUF,
&i,
sizeof(i));
if(status < 0){
ca_printf("CAS: SO_SNDBUF set failed\n");
return S_cas_internal;
}
i = MAX_MSG_SIZE;
status = setsockopt(
sock,
SOL_SOCKET,
SO_RCVBUF,
(char *)&i,
sizeof(i));
if(status < 0){
ca_printf("CAS: SO_RCVBUF set failed\n");
return S_cas_internal;
}
#endif
this->sockState = casOnLine;
return S_cas_success;
}
//
// casStreamIO::~casStreamIO()
//
casStreamIO::~casStreamIO()
{
if (sock>=0) {
close(sock);
}
}
//
// casStreamIO::osdSend()
//
xSendStatus casStreamIO::osdSend(const char *pBuf, bufSizeT nBytes,
bufSizeT &nBytesActual)
{
int status;
#if 0
if(this->pCAS->debugLevel>2u){
char buf[64];
(*pCAS->osm.hostName) (
&this->addr,
buf,
sizeof(buf));
ca_printf(
"CAS: Sending a %d byte reply to %s\n",
this->pSend->stk,
buf);
}
#endif
if (this->sockState!=casOnLine) {
return xSendDisconnect;
}
if (nBytes<=0u) {
nBytesActual = 0u;
return xSendOK;
}
status = send (
this->sock,
pBuf,
nBytes,
0);
if (status == 0) {
this->sockState = casOffLine;
return xSendDisconnect;
}
else if (status<0) {
int anerrno = SOCKERRNO;
if (anerrno != EWOULDBLOCK) {
this->sockState = casOffLine;
}
nBytesActual = 0u;
return xSendOK;
}
nBytesActual = (bufSizeT) status;
return xSendOK;
}
//
// casStreamIO::osdRecv()
//
xRecvStatus casStreamIO::osdRecv(char *pBuf, bufSizeT nBytes,
bufSizeT &nBytesActual)
{
int nchars;
if (this->sockState!= casOnLine) {
return xRecvDisconnect;
}
nchars = recv(this->sock, pBuf, nBytes, 0);
if (nchars==0) {
this->sockState = casOffLine;
return xRecvDisconnect;
}
else if (nchars<0) {
/*
* normal conn lost conditions
*/
switch(SOCKERRNO){
case EWOULDBLOCK:
nBytesActual = 0u;
return xRecvOK;
case ECONNABORTED:
case ECONNRESET:
case ETIMEDOUT:
break;
default:
ca_printf(
"CAS: client disconnect because \"%s\"\n",
strerror(SOCKERRNO));
break;
}
this->sockState = casOffLine;
return xRecvDisconnect;
}
nBytesActual = (bufSizeT) nchars;
return xRecvOK;
}
//
// casStreamIO::show()
//
void casStreamIO::osdShow (unsigned level) const
{
printf ("casStreamIO at %x\n", (unsigned) this);
if (level>1u) {
printf (
"client address=%x, port=%x\n",
(unsigned) ntohl(this->addr.in.sin_addr.s_addr),
ntohs(this->addr.in.sin_port));
}
}
//
// casStreamIO::setNonBlocking()
//
void casStreamIO::setNonBlocking()
{
int status;
int yes = TRUE;
if (this->sockState!=casOnLine) {
return;
}
status = socket_ioctl(this->sock, FIONBIO, &yes);
if (status<0) {
ca_printf("%s:CAS: TCP non blocking IO set fail because \"%s\"\n",
__FILE__, strerror(SOCKERRNO));
this->sockState = casOffLine;
}
}
//
// casStreamIO::incommingBytesPresent()
//
bufSizeT casStreamIO::incommingBytesPresent() const
{
int status;
int nchars;
status = socket_ioctl(this->sock, FIONREAD, &nchars);
if (status<0) {
ca_printf("CAS: FIONREAD err %s\n", strerror(SOCKERRNO));
return 0u;
}
else if (nchars<0) {
return 0u;
}
else {
return (bufSizeT) status;
}
}
//
// casStreamIO::hostName()
//
void casStreamIO::hostNameFromAddr(char *pBuf, unsigned bufSize)
{
hostNameFromIPAddr(&this->addr, pBuf, bufSize);
}
//
// hostNameFromIPAddr()
//
void hostNameFromIPAddr (const caAddr *pAddr,
char *pBuf, unsigned bufSize)
{
char *pName;
assert (bufSize>0U);
if (pAddr->sa.sa_family != AF_INET) {
strncpy (pBuf, "UKN ADDR FAMILY", bufSize);
}
else {
int port = ntohs(pAddr->in.sin_port);
# define maxPortDigits 15U
char tmp[maxPortDigits+1];
unsigned size;
#if 0 // bypass this because of problems with SUNOS4 header files and C++
struct hostent *ent;
ent = gethostbyaddr(
(char *) &pAddr->in.sin_addr.s_addr,
sizeof(pAddr->in.sin_addr.s_addr),
AF_INET);
if (ent) {
pName = ent->h_name;
}
else {
pName = inet_ntoa (pAddr->in.sin_addr);
}
#else
pName = inet_ntoa (pAddr->in.sin_addr);
#endif
assert (bufSize>maxPortDigits);
size = bufSize - maxPortDigits;
strncpy (pBuf, pName, size);
pBuf[size] = '\0';
sprintf (tmp, ".%d", port);
strncat (pBuf, tmp, maxPortDigits);
}
pBuf[bufSize-1] = '\0';
assert(strlen(pBuf)<=bufSize);
}
//
// casStreamIO:::optimumBufferSize()
//
bufSizeT casStreamIO::optimumBufferSize ()
{
if (this->sockState!=casOnLine) {
return 0x400;
}
#if 0
int n;
int size;
int status;
/* fetch the TCP send buffer size */
n = sizeof(size);
status = getsockopt(
this->sock,
SOL_SOCKET,
SO_SNDBUF,
(char *)&size,
&n);
if(status < 0 || n != sizeof(size)){
size = 0x400;
}
if (size<=0) {
size = 0x400;
}
printf("the tcp buf size is %d\n", size);
return (bufSizeT) size;
#else
// this needs to be MAX_TCP (until we fix the array problem)
return (bufSizeT) MAX_TCP;
#endif
}
//
// casStreamIO::getFileDescriptor()
//
int casStreamIO::getFileDescriptor() const
{
return sock;
}
//
// casStreamIO::state()
//
casIOState casStreamIO::state() const
{
return this->sockState;
}

View File

@@ -0,0 +1,51 @@
/*
*
* escape into C to call signal because of a brain dead
* signal() func proto supplied in signal.h by gcc 2.7.2
*
*/
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sigPipeIgnore.h>
typedef void (*pSigFunc) ();
static pSigFunc pReplacedFunc;
/*
* ignoreSigPipe ()
*/
static void ignoreSigPipe (int param)
{
if (pReplacedFunc) {
(*pReplacedFunc) (param);
}
}
/*
* installSigPipeIgnore ()
*/
void installSigPipeIgnore (void)
{
static int init;
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));
}
init = 1;
}

View File

@@ -0,0 +1,16 @@
/*
* escape into C to call signal because of a brain dead
* signal() func proto supplied in signal.h by gcc 2.7.2
*/
#ifdef __cplusplus
extern "C" {
#endif
void installSigPipeIgnore (void);
#ifdef __cplusplus
}
#endif

6
src/cas/os/posix/README Normal file
View File

@@ -0,0 +1,6 @@
this directory contains the posix os dependent source for
the EPICS ca server

View File

@@ -0,0 +1,113 @@
/*
*
* caServerOS.c
* $Id$
*
*
* $Log$
*
*/
//
// CA server
//
#include <server.h>
#define nSecPerUSec 1000
//
// aServerOS::operator -> ()
//
inline caServerI * caServerOS::operator -> ()
{
return &this->cas;
}
//
// casBeaconTimer::expire()
//
void casBeaconTimer::expire()
{
os->sendBeacon ();
}
//
// casBeaconTimer::again()
//
osiBool casBeaconTimer::again()
{
return osiTrue;
}
//
// casBeaconTimer::delay()
//
const osiTime casBeaconTimer::delay()
{
return os->getBeaconPeriod();
}
//
// caServerOS::init()
//
caStatus caServerOS::init()
{
(*this)->setNonBlocking();
this->pRdReg = new casServerReg(*this);
if (!this->pRdReg) {
return S_cas_noMemory;
}
this->pBTmr = new casBeaconTimer((*this)->getBeaconPeriod(), *this);
if (!this->pBTmr) {
ca_printf("CAS: Unable to start server beacon\n");
return S_cas_noMemory;
}
return S_cas_success;
}
//
// caServerOS::~caServerOS()
//
caServerOS::~caServerOS()
{
if (this->pRdReg) {
delete this->pRdReg;
}
if (this->pBTmr) {
delete this->pBTmr;
}
}
//
// casServerReg::callBack()
//
void casServerReg::callBack()
{
assert(os.pRdReg);
os->connectCB();
}
//
// casServerReg::~casServerReg()
//
casServerReg::~casServerReg()
{
this->os.pRdReg = NULL;
}
//
// caServerOS::getFD()
//
int caServerOS::getFD()
{
return cas.caServerIO::getFD();
}

View File

@@ -0,0 +1,131 @@
class casStreamWriteReg;
class casStreamReadReg;
class casStreamEvWakeup;
//
// casStreamOS
//
class casStreamOS : public casStrmClient {
friend class casStreamReadReg;
friend class casStreamWriteReg;
friend class casStreamEvWakeup;
public:
casStreamOS(caServerI &, casMsgIO &);
caStatus init();
~casStreamOS();
//
// process any incomming messages
//
casProcCond processInput();
caStatus start();
void recvCB();
void sendCB();
void sendBlockSignal();
void ioBlockedSignal();
void eventSignal();
void eventFlush();
void show(unsigned level);
private:
casStreamWriteReg *pWtReg;
casStreamReadReg *pRdReg;
casStreamEvWakeup *pEvWk;
unsigned sendBlocked:1;
//
//
//
void armSend ();
void armRecv ();
void disarmSend();
void disarmRecv();
};
//
// casStreamReadReg
//
class casStreamReadReg : public fdReg {
public:
casStreamReadReg (casStreamOS &osIn) :
os (osIn),
fdReg (osIn.getFD(), fdrRead) {}
~casStreamReadReg ();
void show (unsigned level);
private:
casStreamOS &os;
void callBack ();
};
//
// casStreamWriteReg
//
class casStreamWriteReg : public fdReg {
public:
casStreamWriteReg (casStreamOS &osIn) :
os (osIn), fdReg (osIn.getFD(), fdrWrite, TRUE) {}
~casStreamWriteReg ();
void show (unsigned level);
private:
casStreamOS &os;
void callBack ();
};
class casDGReadReg;
class casDGEvWakeup;
//
// casDGOS
//
class casDGOS : public casDGClient {
friend class casDGReadReg;
friend class casDGEvWakeup;
public:
casDGOS(caServerI &cas);
caStatus init();
~casDGOS();
//
// process any incomming messages
//
casProcCond processInput();
caStatus start();
void recvCB();
void sendCB();
void sendBlockSignal() {}
void eventSignal();
void eventFlush();
void show(unsigned level);
private:
casDGReadReg *pRdReg;
casDGEvWakeup *pEvWk;
};
//
// casDGReadReg
//
class casDGReadReg : public fdReg {
public:
casDGReadReg (casDGOS &osIn) :
os (osIn), fdReg (osIn.getFD(), fdrRead) {}
~casDGReadReg ();
void show (unsigned level);
private:
casDGOS &os;
void callBack ();
};

235
src/cas/os/posix/casDGOS.cc Normal file
View File

@@ -0,0 +1,235 @@
/*
*
* casDGOS.c
* $Id$
*
*
* $Log$
*
*/
//
// CA server
//
#include <server.h>
#include <casClientIL.h> // casClient inline func
class casDGEvWakeup : public osiTimer {
public:
casDGEvWakeup(casDGOS &osIn) :
osiTimer(osiTime(0.0)), os(osIn) {}
~casDGEvWakeup()
{
os.pEvWk = NULL;
}
void expire();
void show (unsigned level);
const char *name()
{
return "casDGEvWakeup";
}
private:
casDGOS &os;
};
//
// casDGEvWakeup::show()
//
void casDGEvWakeup::show(unsigned level)
{
this->osiTimer::show(level);
printf("casDGEvWakeup at %x\n", (unsigned) this);
}
//
// casDGEvWakeup::expire()
//
void casDGEvWakeup::expire()
{
casProcCond cond;
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
//
// delete &this->os;
printf("DG event sys process failed\n");
}
}
//
// casDGOS::eventSignal()
//
void casDGOS::eventSignal()
{
if (!this->pEvWk) {
this->pEvWk = new casDGEvWakeup(*this);
if (!this->pEvWk) {
errMessage(S_cas_noMemory,
"casDGOS::eventSignal()");
}
}
}
//
// casDGOS::eventFlush()
//
void casDGOS::eventFlush()
{
this->flush();
}
//
// casDGOS::casDGOS()
//
casDGOS::casDGOS(caServerI &cas) :
casDGClient(cas),
pRdReg(NULL),
pEvWk(NULL)
{
}
//
// casDGOS::init()
//
caStatus casDGOS::init()
{
caStatus status;
//
// init the base classes
//
status = this->casDGClient::init();
return status;
}
//
// casDGOS::~casDGOS()
//
casDGOS::~casDGOS()
{
if (this->pRdReg) {
delete this->pRdReg;
}
if (this->pEvWk) {
delete this->pEvWk;
}
}
//
// casDGOS::show()
//
void casDGOS::show(unsigned level)
{
this->casDGClient::show(level);
printf ("casDGOS at %x\n", (unsigned) this);
if (this->pRdReg) {
this->pRdReg->show(level);
}
if (this->pEvWk) {
this->pEvWk->show(level);
}
}
/*
* casClientStart ()
*/
caStatus casDGOS::start()
{
this->pRdReg = new casDGReadReg (*this);
if (!this->pRdReg) {
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* casDGOS::processInput ()
* - a noop
*/
casProcCond casDGOS::processInput ()
{
return casProcOk;
}
//
// casDGReadReg::callBack()
//
void casDGReadReg::callBack()
{
caStatus status;
casFlushCondition flushCond;
casFillCondition fillCond;
assert (os.pRdReg);
//
// force all replies to be sent to the client
// that made the request
//
os.clear();
//
// read in new input
//
fillCond = os.fill();
if (fillCond == casFillDisconnect) {
casVerify(0);
return;
}
//
// verify that we have a message to process
//
if (os.inBuf::bytesPresent()>0u) {
//
// process the message
//
status = os.processMsg();
if (status) {
errMessage (status,
"unexpected error processing stateless protocol");
//
// clear the input buffer so this will
// not effect future input
//
os.clear();
}
else {
//
// force all replies to go to the sender
//
flushCond = os.flush();
if (flushCond!=casFlushCompleted) {
os.clear();
casVerify(0);
}
}
}
}
//
// casDGReadReg::~casDGReadReg()
//
casDGReadReg::~casDGReadReg()
{
this->os.pRdReg = NULL;
}
//
// casDGReadReg::show()
//
void casDGReadReg::show(unsigned level)
{
this->fdReg::show(level);
printf("casDGReadReg at %x\n", (unsigned) this);
}

100
src/cas/os/posix/casOSD.h Normal file
View File

@@ -0,0 +1,100 @@
//
// $Id$
//
// casOSD.h - Channel Access Server OS Dependent for posix
//
//
// Some BSD calls have crept in here
//
// $Log$
//
#ifndef includeCASOSDH
#define includeCASOSDH
#include <unistd.h>
#include <errno.h>
extern "C" {
//
// for htons() etc
//
# include <netinet/in.h>
} // extern "C"
#include <osiMutex.h>
#include <osiTimer.h>
#include <fdMgr.h>
class caServerI;
class caServerOS;
//
// casBeaconTimer
//
class casBeaconTimer : public osiTimer {
public:
casBeaconTimer (const osiTime &delay, caServerOS &osIn) :
osiTimer(delay), os (osIn) {}
void expire();
const osiTime delay();
osiBool again();
const char *name()
{
return "casBeaconTimer";
}
private:
caServerOS &os;
};
class casServerReg;
//
// caServerOS
//
class caServerOS {
friend class casServerReg;
public:
caServerOS (caServerI &casIn) :
cas (casIn), pRdReg (NULL), pBTmr (NULL) {}
caStatus init ();
~caServerOS ();
caStatus start ();
//caStatus process (const caTime &delay);
//caStatus installTimer (const caTime &delay,
// void (*pFunc)(void *pParam), void *pParam,
// caServerTimerId &id);
//caStatus deleteTimer (const caServerTimerId id);
void recvCB ();
void sendCB () {}; // NOOP satifies template
inline caServerI * operator -> ();
int getFD();
private:
caServerI &cas;
casServerReg *pRdReg;
casBeaconTimer *pBTmr;
};
class casServerReg : public fdReg {
public:
casServerReg (caServerOS &osIn) :
os (osIn), fdReg (osIn.getFD(), fdrRead) {}
~casServerReg ();
private:
caServerOS &os;
void callBack ();
};
// no additions below this line
#endif // includeCASOSDH

View File

@@ -0,0 +1,46 @@
/*
* $Id$
* Some of this isnt posix - its BSD
*
* $Log$
*/
#ifndef includeCasSpecificOSH
#define includeCasSpecificOSH
#include <singleThread.h>
#include <unistd.h>
#include <errno.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <bsdProto.h>
#ifdef __cplusplus
}
#endif
typedef int SOCKET;
#define SOCKERRNO errno
#define socket_close(S) close(S)
#define socket_ioctl(A,B,C) ioctl(A,B,C)
#define ntohf(A) (A)
#define ntohd(A) (A)
#define htonf(A) (A)
#define htond(A) (A)
#endif /* ifndef includeCasSpecificOSH (no new code below this line) */

View File

@@ -0,0 +1,456 @@
//
// casStreamOS.cc
// $Id$
//
//
// $Log$
//
//
//
// CA server
//
#include<server.h>
#include <casClientIL.h> // casClient inline func
class casStreamEvWakeup : public osiTimer {
public:
casStreamEvWakeup(casStreamOS &osIn) :
osiTimer(osiTime(0.0)), os(osIn) {}
~casStreamEvWakeup()
{
os.pEvWk = NULL;
}
void expire();
void show(unsigned level);
const char *name()
{
return "casStreamEvWakeup";
}
private:
casStreamOS &os;
};
//
// casStreamEvWakeup::show()
//
void casStreamEvWakeup::show(unsigned level)
{
printf ("casStreamEvWakeup at %x {\n", (unsigned) this);
this->osiTimer::show(level);
printf ("}\n");
}
//
// casStreamEvWakeup::expire()
//
void casStreamEvWakeup::expire()
{
casProcCond cond;
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
//
// delete &this->os;
printf("strm event sys process failed\n");
}
}
//
// casStreamOS::ioBlockedSignal()
//
void casStreamOS::ioBlockedSignal()
{
//
// in case there is something in the input buffer
// and currently nothing to be read from TCP
//
this->processInput();
//
// in case recv is not armed, there is space in
// the input buffer, and there eventually will
// be something to read from TCP
//
this->armRecv();
}
//
// casStreamOS::eventSignal()
//
void casStreamOS::eventSignal()
{
if (!this->pEvWk) {
this->pEvWk = new casStreamEvWakeup(*this);
if (!this->pEvWk) {
errMessage(S_cas_noMemory,
"casStreamOS::eventSignal()");
}
}
}
//
// casStreamOS::eventFlush()
//
void casStreamOS::eventFlush()
{
this->armSend();
}
//
// casStreamOS::casStreamOS()
//
casStreamOS::casStreamOS(caServerI &cas, casMsgIO &ioIn) :
casStrmClient(cas, ioIn)
{
this->pRdReg = NULL;
this->pWtReg = NULL;
this->pEvWk = NULL;
this->sendBlocked = FALSE;
}
//
// casStreamOS::init()
//
caStatus casStreamOS::init()
{
caStatus status;
//
// init the base classes
//
status = this->casStrmClient::init();
if (status) {
return status;
}
this->setNonBlocking();
return S_cas_success;
}
//
// casStreamOS::~casStreamOS()
//
casStreamOS::~casStreamOS()
{
//
// attempt to flush out any remaining messages
//
this->flush();
this->disarmSend();
this->disarmRecv();
if (this->pEvWk) {
delete this->pEvWk;
}
}
//
// casStreamOS::show()
//
void casStreamOS::show(unsigned level)
{
this->casStrmClient::show(level);
printf("casStreamOS at %x\n", (unsigned) this);
printf("\tsendBlocked = %d\n", this->sendBlocked);
if (this->pWtReg) {
this->pWtReg->show(level);
}
if (this->pRdReg) {
this->pRdReg->show(level);
}
if (this->pEvWk) {
this->pEvWk->show(level);
}
}
//
// casClientStart ()
//
caStatus casStreamOS::start()
{
this->armRecv();
return S_cas_success;
}
//
// casStreamOS::disarmRecv()
//
void casStreamOS::disarmRecv()
{
if (this->pRdReg) {
delete this->pRdReg;
# if defined(DEBUG)
printf ("Read off %d\n", this->getFD());
printf ("Recv backlog %u\n",
this->inBuf::bytesPresent());
printf ("Send backlog %u\n",
this->outBuf::bytesPresent());
# endif
}
}
//
// casStreamOS::armRecv ()
//
void casStreamOS::armRecv()
{
if (!this->pRdReg) {
if (this->inBuf::full()==aitTrue) {
return;
}
this->pRdReg = new casStreamReadReg(*this);
if (!this->pRdReg) {
errMessage(S_cas_noMemory, "armRecv()");
}
# if defined(DEBUG)
printf ("Read on %d\n", this->getFD());
printf ("Recv backlog %u\n",
this->inBuf::bytesPresent());
printf ("Send backlog %u\n",
this->outBuf::bytesPresent());
# endif
}
}
//
// casStreamReadReg::show()
//
void casStreamReadReg::show(unsigned level)
{
this->fdReg::show(level);
printf ("casStreamReadReg at %x\n", (unsigned) this);
}
//
// casStreamReadReg::callBack ()
//
void casStreamReadReg::callBack ()
{
casFillCondition fillCond;
casProcCond procCond;
assert (this->os.pRdReg);
//
// copy in new messages
//
fillCond = os.fill();
procCond = os.processInput();
if (fillCond == casFillDisconnect ||
procCond == casProcDisconnect) {
delete &this->os;
}
else if (os.inBuf::full()==aitTrue) {
//
// If there isnt any space then temporarily
// stop calling this routine until problem is resolved
// either by:
// (1) sending or
// (2) a blocked IO op unblocks
//
delete this;
}
//
// NO CODE HERE
// (see deletes above)
//
}
//
// casStreamReadReg::~casStreamReadReg
//
casStreamReadReg::~casStreamReadReg ()
{
this->os.pRdReg = NULL;
}
//
// casStreamOS::sendBlockSignal()
//
void casStreamOS::sendBlockSignal()
{
this->sendBlocked=TRUE;
this->armSend();
}
//
// casStreamOS::armSend()
//
void casStreamOS::armSend()
{
if (this->outBuf::bytesPresent()==0u) {
return;
}
if (!this->pWtReg) {
this->pWtReg = new casStreamWriteReg(*this);
if (!this->pWtReg) {
errMessage(S_cas_noMemory, "armSend() failed");
}
# if defined(DEBUG)
printf ("Write on %d\n", this->getFD());
printf ("Recv backlog %u\n",
this->inBuf::bytesPresent());
printf ("Send backlog %u\n",
this->outBuf::bytesPresent());
# endif
}
}
//
// casStreamOS::disarmSend()
//
void casStreamOS::disarmSend ()
{
if (this->pWtReg) {
delete this->pWtReg;
# if defined(DEBUG)
printf ("Write off %d\n", this->getFD());
printf ("Recv backlog %u\n",
this->inBuf::bytesPresent());
printf ("Send backlog %u\n",
this->outBuf::bytesPresent());
# endif
}
}
//
// casStreamWriteReg::show()
//
void casStreamWriteReg::show(unsigned level)
{
this->fdReg::show (level);
printf ("casStreamWriteReg at %x\n", (unsigned) this);
}
//
// casStreamWriteReg::callBack()
//
void casStreamWriteReg::callBack()
{
casFlushCondition flushCond;
casProcCond procCond;
assert (os.pWtReg);
//
// attempt to flush the output buffer
//
flushCond = os.flush();
switch (flushCond) {
case casFlushCompleted:
case casFlushPartial:
if (os.sendBlocked) {
os.sendBlocked = FALSE;
}
break;
case casFlushNone:
break;
case casFlushDisconnect:
return;
break;
default:
assert(0);
}
# if defined(DEBUG)
printf ("write attempted on %d result was %d\n",
os.getFD(), flushCond);
printf ("Recv backlog %u\n", os.inBuf::bytesPresent());
printf ("Send backlog %u\n", os.outBuf::bytesPresent());
# endif
//
// If we were able to send something then we need
// to process the input queue in case we were send
// blocked
//
procCond = this->os.processInput();
if (procCond == casProcDisconnect) {
delete &this->os;
}
else {
//
// anything left in the send buffer that
// still needs to be sent ?
// (once this starts sending it doesnt stop until
// the outgoing buf is empty)
//
if (flushCond!=casFlushCompleted) {
casStreamOS *pStrmOS = &this->os;
//
// force the delete now so that the
// arm will work
//
delete this;
pStrmOS->armSend();
}
}
//
// NO CODE HERE
// (see deletes above)
//
}
//
// casStreamWriteReg::~casStreamWriteReg ()
//
casStreamWriteReg::~casStreamWriteReg()
{
this->os.pWtReg = NULL;
}
//
// casStreamOS::processInput()
//
casProcCond casStreamOS::processInput()
{
caStatus status;
# ifdef DEBUG
printf(
"Resp bytes to send=%d, Req bytes pending %d\n",
this->outBuf::bytesPresent(),
this->inBuf::bytesPresent());
# endif
status = this->processMsg();
switch (status) {
case S_cas_sendBlocked:
case S_cas_partialMessage:
case S_cas_ioBlocked:
case S_cas_success:
if (this->inBuf::bytesAvailable()==0u) {
this->armSend ();
}
this->armRecv();
return casProcOk;
break;
default:
errMessage (status,
"unexpected error processing client's input");
return casProcDisconnect;
}
}

View File

@@ -0,0 +1,13 @@
//
// osiMutex - OS independent mutex
// (NOOP on single threaded OS)
//
class osiMutex {
public:
void lock() {};
void unlock() {};
private:
};

View File

@@ -0,0 +1,25 @@
#include <osiTime.h>
#include <sys/types.h>
#include <sys/time.h>
extern "C" {
int gettimeofday (struct timeval *tp, struct timezone *tzp);
}
//
// osiTime::getCurrent ()
//
osiTime osiTime::getCurrent ()
{
int status;
struct timeval tv;
struct timezone tzp;
status = gettimeofday (&tv, &tzp);
assert (status==0);
return osiTime(tv.tv_sec, tv.tv_usec * nSecPerUSec);
}

View File

@@ -0,0 +1,7 @@
WORK IN PROGRESS
this directory contains the posix RT os dependent source for
the EPICS ca server

View File

@@ -0,0 +1,203 @@
$!========================================================================
$!
$! Name : BUILD_VMS
$!
$! Purpose : To build the CA server library and test programs for
$! VAX/VMS. This procedure assumes the following:
$! - You have copied *.c and *.h from the Epics channel access
$! server source directory (base/src/cas) into this VMS directory
$! - You have copied *.c from the Epics
$! base/src/libCom directory into this VMS directory
$! - You have copied *.h from the base/include directory into this
$! VMS directory
$! - You are using Multinet for TCP/IP access. If not, the logical
$! name definitions below will need to be changed
$!
$!
$! Arguments : None
$!
$! Created 16-NOV-1993 Mark L. Rivers
$! 05-MAY-1994 Jeff O. Hill Updated for EPICS 3.12
$!
$!========================================================================
$!
$! Example FTP script moves sources from UNIX to VMS
$! (remove "$!" comment delimeters)
$!
$! open <HOST NAME>
$! user <USER NAME>
$! mkdir [.cas]
$! cd [.cas]
$! prompt
$! lcd ~/epics/base/src/cas
$! mput *.c
$! mput *.h
$! put BUILD_VMS.COM
$! lcd vms
$! mput *.c
$! mput *.h
$! lcd ../../libCom
$! mput *.c
$! mput *.h
$! lcd ../ca
$! mput *.h
$! mput *.c
$! lcd ../../include
$! mput *.h
$!========================================================================
$!
$ cwd = f$logical("sys$disk") + f$directory()
$ define /nolog sys multinet_root:[multinet.include.sys]
$ define /nolog vms multinet_root:[multinet.include.vms]
$ define /nolog net multinet_root:[multinet.include.net]
$ define /nolog netinet multinet_root:[multinet.include.netinet]
$ define /nolog arpa multinet_root:[multinet.include.arpa]
$ define /nolog tcp multinet_root:[multinet.include]
$!
$! Compile the functions and test programs
$! Define symbol for the CC command
$ call set_cc_command
$ if (p1 .nes. "")
$ then
$ cc_command 'p1'
$ else
$ cc_command casCreateCvrt
$ call linktmp casCreateCvrt
$ casCreateCvrt == "$" + cwd + "casCreateCvrt.exe"
$ casCreateCvrt casCvrt.c
$ cc_command -
exampleCaServer, -
singleThread, -
camessage, -
camsgtask, -
caserverio, -
caservertask, -
cast_server, -
online_notify, -
caEventQueue, -
caMemory, -
casAccess, -
casCvrt, -
mitfp, -
pvRead, -
pvWrite, -
cvtfast, -
errPrintfUNIX, -
fdmgr
$ cc_command -
ACCESS, -
CONN, -
CONVERT, -
FLOW_CONTROL, -
IOCINF, -
REPEATER, -
CAREPEATER, -
SERVICE, -
SYNCGRP,-
TEST_EVENT, -
BSD_DEPEN, -
IF_DEPEN, -
VMS_DEPEN, -
ELLLIB, -
BUCKETLIB, -
ENVSUBR, -
TSSUBR, -
NEXTFIELDSUBR, -
ASSERTUNIX, -
CATIME, -
ACCTST
$ endif
$
$!
$! Build an object library
$ library /create ca_server_library -
casAccess, -
singleThread, -
camessage, -
camsgtask, -
caserverio, -
caservertask, -
cast_server, -
online_notify, -
caEventQueue, -
casCvrt, -
mitfp, -
caMemory, -
pvRead, -
pvWrite, -
cvtfast, -
errPrintfUNIX, -
fdmgr
$ library /create ca_client_library -
IOCINF, -
ACCESS, -
CONN, -
CONVERT, -
FLOW_CONTROL, -
REPEATER, -
TEST_EVENT, -
SYNCGRP, -
SERVICE, -
IF_DEPEN, -
VMS_DEPEN, -
BSD_DEPEN, -
BUCKETLIB, -
TSSUBR, -
ENVSUBR, -
NEXTFIELDSUBR, -
ASSERTUNIX, -
ELLLIB
$! Link the example server
$ call link exampleCaServer
$
$! Setup DCL Foreign Command for UNIX cmd line params
$ excas == "$" + cwd + "exampleCaServer.exe"
$
$!
$ link: subroutine
$! Link differently for VAX and AXP
$ if f$getsyi("HW_MODEL") .ge. 1024
$ then
$ link 'p1', sys$input/options
ca_server_library/lib
ca_client_library/lib
multinet_socket_library/share
$ else
$ link 'p1', sys$input/options
ca_server_library/lib
ca_client_library/lib
multinet_socket_library/share
sys$share:vaxcrtl/share
$ endif
$ endsubroutine
$
$
$ linktmp: subroutine
$! Link differently for VAX and AXP
$ if f$getsyi("HW_MODEL") .ge. 1024
$ then
$ link 'p1'
$ else
$ link 'p1', sys$input/options
sys$share:vaxcrtl/share
$ endif
$ endsubroutine
$
$
$! This subroutine sets up "cc_command" to use different switches for
$! VAX (assumes VAX C compiler) and AXP (DEC C compiler).
$ set_cc_command : subroutine
$ if f$getsyi("HW_MODEL") .ge. 1024
$ then
$! turn of no prototype messages because MULTINET does not
$! supply prototypes.
$ cc_command:== cc /warn/float=d_float -
/include=([], [-.include], [-.libcom]) -
/define=(MULTINET=1)
$ else
$ cc_command:== cc /include=([], [-.include], [-.libcom]) -
/define=(MULTINET=1)
$ endif
$ endsubroutine
$! ************************************************************

7
src/cas/os/vms/README Normal file
View File

@@ -0,0 +1,7 @@
WORK IN PROGRESS
this directory contains the vms os dependent source for
the EPICS ca server

View File

@@ -0,0 +1,48 @@
#include <singleThread.h>
#include <sys/types.h>
#if defined (MULTINET)
# include "multinet_root:[multinet.include]errno.h"
#elif defined (WINTCP)
# include <tcp/errno.h>
#else
# include <errno.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#if defined(UCX) && 0
# include <sys/ucx$inetdef.h>
# include <ucx.h>
#else
# include <sys/ioctl.h>
#endif
#include <bsdProto.h>
typedef int SOCKET;
#if defined(WINTCP)
extern int uerrno;
# define SOCKERRNO uerrno
#elif defined(MULTINET)
# define SOCKERRNO socket_errno
#else
# define SOCKERRNO errno
#endif
#if defined (UCX)
# define socket_close(S) close (S)
# define socket_ioctl(A,B,C) ioctl (A,B,C)
#elif defined (WINTCP)
# define socket_close(S) netclose (S)
# define socket_ioctl(A,B,C) ioctl (A,B,C)
#endif /* UCX */
#include <mitfp.h>

3
src/cas/os/vms/login.com Normal file
View File

@@ -0,0 +1,3 @@
set display/create/node=xxxx.atdiv.lanl.gov/trans=tcpip

266
src/cas/os/vms/mitfp.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* mitfp.c - routines to convert between VAX float and big endian
* IEEE float
*
* Author: Jeffrey O. Hill
*
*
*/
#include <server.h>
/************************************************************************/
/* float convert */
/* (THIS ASSUMES IEEE IS THE NETWORK FLOATING POINT FORMAT) */
/************************************************************************/
struct ieeeflt{
unsigned mant :23;
unsigned exp :8;
unsigned sign :1;
};
/* Exponent sign bias */
#define IEEE_SB 127
/* Conversion Range */
/* -126<exp<127 with mantissa of form 1.mant */
#define EXPMINIEEE -126 /* min for norm # IEEE exponent */
struct mitflt{
unsigned mant1 :7;
unsigned exp :8;
unsigned sign :1;
unsigned mant2 :16;
};
/* Exponent sign bias */
#define MIT_SB 129
/* Conversion Ranges */
/* -128<exp<126 with mantissa of form 1.mant */
#define EXPMAXMIT 126 /* max MIT exponent */
#define EXPMINMIT -128 /* min MIT exponent */
/* (this includes mapping of fringe reals to zero or infinity) */
/* (byte swaps included in conversion */
/*
* htonf()
*/
float htonf(float mit)
{
float ieee;
struct mitflt *pMIT;
struct ieeeflt *pIEEE;
short *ptmp;
long exp;
long mant;
long sign;
pMIT = (struct mitflt *) &mit;
pIEEE = (struct ieeeflt *) &ieee;
sign = pMIT->sign;
if( ((short) pMIT->exp) < (EXPMINIEEE + MIT_SB) ){
exp = 0;
mant = 0;
sign = 0;
}
else{
exp = ((short) pMIT->exp) - (MIT_SB + IEEE_SB);
mant = (pMIT->mant1<<16) | pMIT->mant2;
}
pIEEE->mant = mant;
pIEEE->exp = exp;
pIEEE->sign = sign;
ptmp = (short *)pIEEE;
*ptmp = htons(*ptmp);
return ieee;
}
/*
* ntohf()
*
* sign must be forced to zero if the exponent is zero to prevent a reserved
* operand fault- joh 9-13-90
*/
float ntohf(float ieee)
{
float mit;
struct ieeeflt *pIEEE;
struct mitflt *pMIT;
short *ptmp;
long exp;
long mant2;
long mant1;
long sign;
pMIT = (struct mitflt *) &mit;
pIEEE = (struct ieeeflt *) &ieee;
ptmp = (short *)pIEEE;
*ptmp = htonl(*ptmp);
if( ((short) pIEEE->exp) > EXPMAXMIT + IEEE_SB){
sign = pIEEE->sign;
exp = EXPMAXMIT + MIT_SB;
mant2 = ~0;
mant1 = ~0;
}
else if( pIEEE->exp == 0){
sign = 0;
exp = 0;
mant2 = 0;
mant1 = 0;
}
else{
sign = pIEEE->sign;
exp = pIEEE->exp+MIT_SB-IEEE_SB;
mant2 = pIEEE->mant;
mant1 = pIEEE->mant>>(unsigned)16;
}
pMIT->exp = exp;
pMIT->mant2 = mant2;
pMIT->mant1 = mant1;
pMIT->sign = sign;
return mit;
}
/************************************************************************/
/* double convert */
/* (THIS ASSUMES IEEE IS THE NETWORK FLOATING POINT FORMAT) */
/************************************************************************/
/* (this includes mapping of fringe reals to zero or infinity) */
/* (byte swaps included in conversion */
struct ieeedbl{
unsigned int mant2 : 32;
unsigned int mant1 : 20;
unsigned int exp : 11;
unsigned int sign : 1;
};
#define IEEE_DBL_SB 1023
/* Conversion Range */
/* -1022<exp<1024 with mantissa of form 1.mant */
#define DBLEXPMINIEEE -1022 /* min for norm # IEEE exponent */
struct mitdbl{
unsigned int mant1 : 7;
unsigned int exp : 8;
unsigned int sign : 1;
unsigned int mant2 : 16;
unsigned int mant3 : 16;
unsigned int mant4 : 16;
};
/* Exponent sign bias */
#define MIT_DBL_SB 129
/* Conversion Ranges */
/* -128<exp<126 with mantissa of form 1.mant */
#define DBLEXPMAXMIT 126 /* max MIT exponent */
#define DBLEXPMINMIT -128 /* min MIT exponent */
/*
* htond()
*/
double htond(double mit)
{
double ieee;
struct mitdbl *pMIT;
struct ieeedbl *pIEEE;
long *ptmp;
long tmp;
pMIT = (struct mitdbl *)&mit;
pIEEE = (struct ieeedbl *)&ieee;
if( ((int)pMIT->exp) < (DBLEXPMINMIT+MIT_DBL_SB) ){
pIEEE->mant1 = 0;
pIEEE->mant2 = 0;
pIEEE->exp = 0;
pIEEE->sign = 0;
}
else{
pIEEE->exp = ((int)pMIT->exp)+(IEEE_DBL_SB-MIT_DBL_SB);
pIEEE->mant1 = (pMIT->mant1<<13) | (pMIT->mant2>>3);
pIEEE->mant2 = (pMIT->mant2<<29) | (pMIT->mant3<<13) |
(pMIT->mant4>>3);
pIEEE->sign = pMIT->sign;
}
/*
* byte swap to net order
*/
ptmp = (long *) pIEEE;
tmp = htonl(ptmp[0]);
ptmp[0] = htonl(ptmp[1]);
ptmp[1] = tmp;
return ieee;
}
/*
* sign must be forced to zero if the exponent is zero to prevent a reserved
* operand fault- joh 9-13-90
*/
double ntohd(double ieee)
{
double mit;
struct mitdbl *pMIT;
struct ieeedbl *pIEEE;
long *ptmp;
long tmp;
pMIT = (struct mitdbl *)&mit;
pIEEE = (struct ieeedbl *)&ieee;
/*
* Byte swap from net order to host order
*/
ptmp = (long *) pIEEE;
tmp = htonl(ptmp[0]);
ptmp[0] = htonl(ptmp[1]);
ptmp[1] = tmp;
if( ((int)pIEEE->exp) > (DBLEXPMAXMIT + IEEE_DBL_SB) ){
pMIT->sign = pIEEE->sign;
pMIT->exp = DBLEXPMAXMIT + MIT_DBL_SB;
pMIT->mant1 = ~0;
pMIT->mant2 = ~0;
pMIT->mant3 = ~0;
pMIT->mant4 = ~0;
}
else if( ((int)pIEEE->exp) < (DBLEXPMINMIT + IEEE_DBL_SB) ){
pMIT->sign = 0;
pMIT->exp = 0;
pMIT->mant1 = 0;
pMIT->mant2 = 0;
pMIT->mant3 = 0;
pMIT->mant4 = 0;
}
else{
pMIT->sign = pIEEE->sign;
pMIT->exp = ((int)pIEEE->exp)+(MIT_DBL_SB-IEEE_DBL_SB);
pMIT->mant1 = pIEEE->mant1>>13;
pMIT->mant2 = (pIEEE->mant1<<3) | (pIEEE->mant2>>29);
pMIT->mant3 = pIEEE->mant2>>13;
pMIT->mant4 = pIEEE->mant2<<3;
}
return mit;
}

275
src/cas/os/vms/mitfp.cc Normal file
View File

@@ -0,0 +1,275 @@
/*
* mitfp.c - routines to convert between VAX float and big endian
* IEEE float
*
* Author: Jeffrey O. Hill
*
*
*/
/*
* include htons() etc.
*/
#include <sys/types.h>
#include <netinet/in.h>
double htond(double mit);
double ntohd(double ieee);
float htonf(float mit);
float ntohf(float ieee);
/************************************************************************/
/* float convert */
/* (THIS ASSUMES IEEE IS THE NETWORK FLOATING POINT FORMAT) */
/************************************************************************/
struct ieeeflt{
unsigned mant :23;
unsigned exp :8;
unsigned sign :1;
};
/* Exponent sign bias */
#define IEEE_SB 127
/* Conversion Range */
/* -126<exp<127 with mantissa of form 1.mant */
#define EXPMINIEEE -126 /* min for norm # IEEE exponent */
struct mitflt{
unsigned mant1 :7;
unsigned exp :8;
unsigned sign :1;
unsigned mant2 :16;
};
/* Exponent sign bias */
#define MIT_SB 129
/* Conversion Ranges */
/* -128<exp<126 with mantissa of form 1.mant */
#define EXPMAXMIT 126 /* max MIT exponent */
#define EXPMINMIT -128 /* min MIT exponent */
/* (this includes mapping of fringe reals to zero or infinity) */
/* (byte swaps included in conversion */
/*
* htonf()
*/
float htonf(float mit)
{
float ieee;
struct mitflt *pMIT;
struct ieeeflt *pIEEE;
short *ptmp;
long exp;
long mant;
long sign;
pMIT = (struct mitflt *) &mit;
pIEEE = (struct ieeeflt *) &ieee;
sign = pMIT->sign;
if( ((short) pMIT->exp) < (EXPMINIEEE + MIT_SB) ){
exp = 0;
mant = 0;
sign = 0;
}
else{
exp = ((short) pMIT->exp) - (MIT_SB + IEEE_SB);
mant = (pMIT->mant1<<16) | pMIT->mant2;
}
pIEEE->mant = mant;
pIEEE->exp = exp;
pIEEE->sign = sign;
ptmp = (short *)pIEEE;
*ptmp = htons(*ptmp);
return ieee;
}
/*
* ntohf()
*
* sign must be forced to zero if the exponent is zero to prevent a reserved
* operand fault- joh 9-13-90
*/
float ntohf(float ieee)
{
float mit;
struct ieeeflt *pIEEE;
struct mitflt *pMIT;
short *ptmp;
long exp;
long mant2;
long mant1;
long sign;
pMIT = (struct mitflt *) &mit;
pIEEE = (struct ieeeflt *) &ieee;
ptmp = (short *)pIEEE;
*ptmp = htonl(*ptmp);
if( ((short) pIEEE->exp) > EXPMAXMIT + IEEE_SB){
sign = pIEEE->sign;
exp = EXPMAXMIT + MIT_SB;
mant2 = ~0;
mant1 = ~0;
}
else if( pIEEE->exp == 0){
sign = 0;
exp = 0;
mant2 = 0;
mant1 = 0;
}
else{
sign = pIEEE->sign;
exp = pIEEE->exp+MIT_SB-IEEE_SB;
mant2 = pIEEE->mant;
mant1 = pIEEE->mant>>(unsigned)16;
}
pMIT->exp = exp;
pMIT->mant2 = mant2;
pMIT->mant1 = mant1;
pMIT->sign = sign;
return mit;
}
/************************************************************************/
/* double convert */
/* (THIS ASSUMES IEEE IS THE NETWORK FLOATING POINT FORMAT) */
/************************************************************************/
/* (this includes mapping of fringe reals to zero or infinity) */
/* (byte swaps included in conversion */
struct ieeedbl{
unsigned int mant2 : 32;
unsigned int mant1 : 20;
unsigned int exp : 11;
unsigned int sign : 1;
};
#define IEEE_DBL_SB 1023
/* Conversion Range */
/* -1022<exp<1024 with mantissa of form 1.mant */
#define DBLEXPMINIEEE -1022 /* min for norm # IEEE exponent */
struct mitdbl{
unsigned int mant1 : 7;
unsigned int exp : 8;
unsigned int sign : 1;
unsigned int mant2 : 16;
unsigned int mant3 : 16;
unsigned int mant4 : 16;
};
/* Exponent sign bias */
#define MIT_DBL_SB 129
/* Conversion Ranges */
/* -128<exp<126 with mantissa of form 1.mant */
#define DBLEXPMAXMIT 126 /* max MIT exponent */
#define DBLEXPMINMIT -128 /* min MIT exponent */
/*
* htond()
*/
double htond(double mit)
{
double ieee;
struct mitdbl *pMIT;
struct ieeedbl *pIEEE;
long *ptmp;
long tmp;
pMIT = (struct mitdbl *)&mit;
pIEEE = (struct ieeedbl *)&ieee;
if( ((int)pMIT->exp) < (DBLEXPMINMIT+MIT_DBL_SB) ){
pIEEE->mant1 = 0;
pIEEE->mant2 = 0;
pIEEE->exp = 0;
pIEEE->sign = 0;
}
else{
pIEEE->exp = ((int)pMIT->exp)+(IEEE_DBL_SB-MIT_DBL_SB);
pIEEE->mant1 = (pMIT->mant1<<13) | (pMIT->mant2>>3);
pIEEE->mant2 = (pMIT->mant2<<29) | (pMIT->mant3<<13) |
(pMIT->mant4>>3);
pIEEE->sign = pMIT->sign;
}
/*
* byte swap to net order
*/
ptmp = (long *) pIEEE;
tmp = htonl(ptmp[0]);
ptmp[0] = htonl(ptmp[1]);
ptmp[1] = tmp;
return ieee;
}
/*
* sign must be forced to zero if the exponent is zero to prevent a reserved
* operand fault- joh 9-13-90
*/
double ntohd(double ieee)
{
double mit;
struct mitdbl *pMIT;
struct ieeedbl *pIEEE;
long *ptmp;
long tmp;
pMIT = (struct mitdbl *)&mit;
pIEEE = (struct ieeedbl *)&ieee;
/*
* Byte swap from net order to host order
*/
ptmp = (long *) pIEEE;
tmp = htonl(ptmp[0]);
ptmp[0] = htonl(ptmp[1]);
ptmp[1] = tmp;
if( ((int)pIEEE->exp) > (DBLEXPMAXMIT + IEEE_DBL_SB) ){
pMIT->sign = pIEEE->sign;
pMIT->exp = DBLEXPMAXMIT + MIT_DBL_SB;
pMIT->mant1 = ~0;
pMIT->mant2 = ~0;
pMIT->mant3 = ~0;
pMIT->mant4 = ~0;
}
else if( ((int)pIEEE->exp) < (DBLEXPMINMIT + IEEE_DBL_SB) ){
pMIT->sign = 0;
pMIT->exp = 0;
pMIT->mant1 = 0;
pMIT->mant2 = 0;
pMIT->mant3 = 0;
pMIT->mant4 = 0;
}
else{
pMIT->sign = pIEEE->sign;
pMIT->exp = ((int)pIEEE->exp)+(MIT_DBL_SB-IEEE_DBL_SB);
pMIT->mant1 = pIEEE->mant1>>13;
pMIT->mant2 = (pIEEE->mant1<<3) | (pIEEE->mant2>>29);
pMIT->mant3 = pIEEE->mant2>>13;
pMIT->mant4 = pIEEE->mant2<<3;
}
return mit;
}

8
src/cas/os/vms/mitfp.h Normal file
View File

@@ -0,0 +1,8 @@
double htond(double mit);
double ntohd(double ieee);
float htonf(float mit);
float ntohf(float ieee);

View File

@@ -0,0 +1,41 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#if defined(WINTCP) /* Wallangong */
# define socket_close(S) netclose(S)
# define socket_ioctl(A,B,C) ioctl(A,B,C)
# include <net/if.h>
# include <vms/inetiodef.h>
# include <sys/ioctl.h>
# include <tcp/errno.h>
# define SOCKERRNO uerrno
#elif defined(UCX) /* GeG 09-DEC-1992 */
# include <sys/ucx$inetdef.h>
# include <ucx.h>
# define socket_close(S) close(S)
# define socket_ioctl(A,B,C) ioctl(A,B,C)
# include <sys/errno.h>
# define SOCKERRNO errno
#else /* MULTINET */
# include <net/if.h>
# include <vms/inetiodef.h>
# include <sys/ioctl.h>
# include <tcp/errno.h>
# define SOCKERRNO socket_errno
#endif
/*
* NOOP out task watch dog for now
*/
#define taskwdInsert(A,B,C)
#define taskwdRemove(A)
#ifndef LOCAL
#define LOCAL static
#endif /*LOCAL*/

View File

@@ -0,0 +1,7 @@
WORK IN PROGRESS
this directory contains the vxWorks os dependent source for
the EPICS ca server

View File

@@ -0,0 +1,659 @@
/*
*
* vxWorks_depen.c
* %W% %G%
*
* vxWorks dependent routines for the CA server
*
*
*/
#include <server.h>
#include <inetLib.h>
VERSIONID(vxWorks_depenc,"%W% %G%")
#define MUTEX_SEM_OPTIONS \
(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE)
LOCAL int event_task(
struct event_user *evuser,
void (*init_func)(int arg),
int init_func_arg
);
LOCAL void osDepenTimerCB(void *pciu);
LOCAL void osDepenSendCB(void *pClient);
int caServerTask(struct rsrv *pRsrv);
LOCAL int caMaxFreeBlockPoll(void);
size_t caMaxFreeBlock;
###### no event flush currently (only needed in multi thread env) ####
status = caeqAddFlushEvent (client->evuser, XXXX, client);
assert (status==OK);
/*
* caGetElapsedTime()
*/
caStatus caGetElapsedTime(caElapsedTimeVal *pElapsed)
{
ULONG ticks;
ULONG rate;
ticks = tickGet();
rate = sysClkRateGet();
pElapsed->tv_sec = ticks * rate;
pElapsed->tv_usec = ((ticks % rate)*CAServerUSecInSec)/rate;
return S_cas_success;
}
/*
* caOutOfMemory()
*/
int caOutOfMemory(void)
{
int status;
static int pollTaskStarted;
if(!pollTaskStarted){
caMaxFreeBlock = memFindMax();
status = taskSpawn(
MAXFREEBLOCKTASKNAME,
MAXFREEBLOCKTASKPRI,
MAXFREEBLOCKTASKOPT,
MAXFREEBLOCKTASKSTACK,
caMaxFreeBlockPoll,
0,0,0,0,0,0,0,0,0,0);
if(status>=0){
pollTaskStarted = TRUE;
}
}
return (caMaxFreeBlock<MAX_BLOCK_THRESHOLD);
}
/*
* caMaxFreeBlockPoll()
*/
LOCAL int caMaxFreeBlockPoll(void)
{
while(TRUE){
caMaxFreeBlock = memFindMax();
taskDelay(MAXFREEBLOCKPOLL*sysClkRateGet());
}
}
/*
* casPutCBStartTimer()
*/
caStatus casPutCBStartTimer(
casChanInUse *pciu,
unsigned timeOutSec
)
{
struct client *pClient = pciu->client;
caserver *pRsrv = pClient->cc.pRsrv;
struct timeval tv;
if(pClient->cc.osSpecific.pPutCBAlarm){
tv.tv_sec = timeOutSec;
tv.tv_usec = 0;
pClient->cc.osSpecific.pPutCBAlarm
= fdmgr_add_timeout(
pRsrv->osSpecific.pfdctx,
&tv,
osDepenTimerCB,
pciu);
if(!pClient->cc.osSpecific.pPutCBAlarm){
return S_cas_noMemory;
}
}
return S_cas_success;
}
/*
* osDepenTimerCB()
*/
LOCAL void osDepenTimerCB(void *pParam)
{
casChanInUse *pciu = (casChanInUse *)pParam;
pciu->client->cc.osSpecific.pPutCBAlarm = NULL;
casPutCBTimer(pciu);
}
/*
* casPutCBCancelTimer()
*/
void casPutCBCancelTimer(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(pClient->cc.osSpecific.pPutCBAlarm){
status = fdmgr_clear_timeout(
pRsrv->osSpecific.pfdctx,
pClient->cc.osSpecific.pPutCBAlarm);
assert(status==0);
pClient->cc.osSpecific.pPutCBAlarm = NULL;
}
}
/*
* casDisableSocketRecvIOCallback()
*/
caStatus casDisableSocketRecvIOCallback(struct client *pClient)
{
int status;
if(pClient->cc.osSpecific.sockRecvIOCallbackEnabled){
status = fdmgr_clear_callback(
pClient->cc.pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_read);
assert(status==0);
pClient->cc.osSpecific.sockRecvIOCallbackEnabled = FALSE;
}
return S_cas_success;
}
/*
* casEnableSocketRecvIOCallback()
*/
caStatus casEnableSocketRecvIOCallback(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(!pClient->cc.osSpecific.sockRecvIOCallbackEnabled){
status = fdmgr_add_callback(
pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_read,
pClient->cc.pCB,
pClient);
if(status){
return S_cas_noMemory;
}
pClient->cc.osSpecific.sockRecvIOCallbackEnabled = TRUE;
}
return S_cas_success;
}
/*
* casWaitForIO ()
*/
caStatus casWaitForIO (struct rsrv *pRsrv, caTime *pDelay)
{
struct timeval tv;
tv.tv_sec = caTime->sec;
tv.tv_usec = caTime->nsec / NSecPerUsec;
status = fdmgr_pend_event(pRsrv->osSpecific.pfdctx, &tv);
if (status) {
return S_cas_internal;
}
return S_cas_success;
}
/*
* casArmSocketSendIOCallback()
*/
caStatus casArmSocketSendIOCallback(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(!pClient->cc.osSpecific.sockSendIOCallbackEnabled){
status = fdmgr_add_callback(
pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_write,
osDepenSendCB,
pClient);
if(status){
return S_cas_noMemory;
}
pClient->cc.osSpecific.sockSendIOCallbackEnabled = TRUE;
}
return S_cas_success;
}
/*
* casCancelSocketSendIOCallback()
*/
caStatus casCancelSocketSendIOCallback(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(pClient->cc.osSpecific.sockSendIOCallbackEnabled){
status = fdmgr_clear_callback(
pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_write);
assert(status==0);
pClient->cc.osSpecific.sockSendIOCallbackEnabled = FALSE;
}
return S_cas_success;
}
/*
* osDepenSendCB()
*/
LOCAL void osDepenSendCB(void *pParam)
{
struct client *pClient = (struct client *) pParam;
pClient->cc.osSpecific.sockSendIOCallbackEnabled = FALSE;
(*pClient->sendHandler)(pClient);
}
/*
* casOSSpecificDelete()
*/
void casOSSpecificDelete(struct rsrv *pRsrv)
{
int status;
if(taskIdVerify(pRsrv->osSpecific.selectTask) == OK){
taskwdRemove(taskDelete(pRsrv->osSpecific.selectTask));
taskDelete(pRsrv->osSpecific.selectTask);
}
if(pRsrv->osSpecific.clientQLock){
status = semDelete(pRsrv->osSpecific.clientQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.freeChanQLock){
status = semDelete(pRsrv->osSpecific.freeChanQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.freeEventQLock){
status = semDelete(pRsrv->osSpecific.freeEventQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.pvQLock){
status = semDelete(pRsrv->osSpecific.pvQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.pfdctx){
status = fdmgr_delete(pRsrv->osSpecific.pfdctx);
assert(status==OK);
}
}
/*
* casOSSpecificInit()
*/
caStatus casOSSpecificInit(struct rsrv *pRsrv)
{
pRsrv->osSpecific.clientQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.clientQLock){
return S_cas_noMemory;
}
pRsrv->osSpecific.freeChanQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.freeChanQLock){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.freeEventQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.freeEventQLock){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.pvQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.pvQLock){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.pfdctx = fdmgr_init();
if(!pRsrv->osSpecific.pfdctx){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* casOSSpecificStartServer()
*/
caStatus casOSSpecificStartServer(caserver *pRsrv)
{
int status;
status = fdmgr_add_callback(
pRsrv->osSpecific.pfdctx,
pRsrv->server_sock,
fdi_read,
rsrv_connect,
pRsrv);
if(status < 0){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
status = taskSpawn(
REQ_SRVR_NAME,
REQ_SRVR_PRI,
REQ_SRVR_OPT,
RSP_SRVR_STACK,
caServerTask,
(int)pRsrv,
0,0,0,0,0,0,0,0,0);
if(status == ERROR){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.selectTask = status;
return S_cas_success;
}
/*
* caServerTask()
*/
int caServerTask(caserver *pRsrv)
{
struct timeval tv;
caTime delay;
struct client *pClient;
int nchars;
int status;
taskwdInsert((int)taskIdCurrent,NULL,NULL);
while(TRUE){
delay.sec = 100;
delay.usec = 0;
status = caServerProcess (pRsrv, &delay);
assert (status == S_cas_success);
}
}
/*
* casSchedualBeacon()
*/
void casSchedualBeacon(struct rsrv *pRsrv)
{
fdmgrAlarm *tmp;
struct timeval tv;
tv.tv_sec = pRsrv->delayToNextBeacon.tv_sec;
tv.tv_usec = pRsrv->delayToNextBeacon.tv_usec;
tmp = fdmgr_add_timeout(
pRsrv->osSpecific.pfdctx,
&tv,
casSendBeacon,
pRsrv);
if(!tmp){
ca_printf("CAS: Unable to keep beacon going\n");
}
}
/*
* casOSSpecificClientInit()
*/
caStatus casOSSpecificClientInit(struct client *client)
{
client->cc.osSpecific.eventQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.eventQLock){
return S_cas_noMemory;
}
client->cc.osSpecific.chanQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.chanQLock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
client->cc.osSpecific.putNotifyLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.putNotifyLock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
client->cc.osSpecific.lock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.lock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
client->cc.osSpecific.accessRightsQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.accessRightsQLock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* casOSSpecificClientDelete()
*/
void casOSSpecificClientDelete(struct client *client)
{
int status;
if(client->cc.osSpecific.eventQLock){
status = semDelete(client->cc.osSpecific.eventQLock);
assert(status==OK);
}
if(client->cc.osSpecific.chanQLock){
status = semDelete(client->cc.osSpecific.chanQLock);
assert(status==OK);
}
if(client->cc.osSpecific.putNotifyLock){
status = semDelete(client->cc.osSpecific.putNotifyLock);
assert(status==OK);
}
if(client->cc.osSpecific.lock){
status = semDelete(client->cc.osSpecific.lock);
assert(status==OK);
}
if(client->cc.osSpecific.accessRightsQLock){
status = semDelete(client->cc.osSpecific.accessRightsQLock);
assert(status==OK);
}
}
/*
* caeqOSSpecificInit()
*/
caStatus caeqOSSpecificInit(caEventUser *evuser)
{
evuser->osSpecific.lock = semMCreate(MUTEX_SEM_OPTIONS);
if(!evuser->osSpecific.lock){
return S_cas_noMemory;
}
evuser->osSpecific.ppendsem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
if(!evuser->osSpecific.ppendsem){
semDelete(evuser->osSpecific.lock);
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* caeqOSSpecificDelete()
*/
void caeqOSSpecificDelete(caEventUser *evuser)
{
int status;
if(taskIdVerify(evuser->osSpecific.taskid)==OK){
taskwdRemove(evuser->osSpecific.taskid);
taskDelete(evuser->osSpecific.taskid);
}
status = semDelete(evuser->osSpecific.lock);
assert(status == OK);
status = semDelete(evuser->osSpecific.ppendsem);
assert(status == OK);
}
/*
* caeqOSSpecificPVInit ()
*/
caStatus caeqOSSpecificPVInit (casPVInUse *pPV)
{
pPV->osSpecific.lock = semMCreate(MUTEX_SEM_OPTIONS);
if (!pPV->osSpecific.lock) {
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* caeqOSSpecificPVDelete ()
*/
void caeqOSSpecificPVDelete (casPVInUse *pPV)
{
int status;
status = semDelete (pPV->osSpecific.lock);
assert (status == OK);
}
/*
* caeqOSSpecificEventNotify()
*/
void caeqOSSpecificEventNotify(caEventUser *evuser)
{
int status;
status = semGive(evuser->osSpecific.ppendsem);
assert(status == OK);
}
/*
* caeqStartEvents()
*/
int caeqStartEvents(
struct event_user *evuser,
char *taskname, /* defaulted if NULL */
void (*init_func)(),
int init_func_arg,
int priority_offset
)
{
int status;
int taskpri;
/* only one ca_pend_event thread may be started for each evuser ! */
while(!vxTas(&evuser->osSpecific.pendlck))
return ERROR;
status = taskPriorityGet(taskIdSelf(), &taskpri);
if(status == ERROR){
return ERROR;
}
taskpri += priority_offset;
if(!taskname){
taskname = EVENT_PEND_NAME;
}
status = taskSpawn(
taskname,
taskpri,
EVENT_PEND_OPT,
EVENT_PEND_STACK,
event_task,
(int)evuser,
(int)init_func,
(int)init_func_arg,
0,0,0,0,0,0,0);
if(status == ERROR){
return ERROR;
}
evuser->osSpecific.taskid = status;
return OK;
}
/*
* EVENT_TASK()
*/
LOCAL int event_task(
struct event_user *evuser,
void (*init_func)(int init_func_arg),
int init_func_arg
)
{
int status;
taskwdInsert((int)taskIdCurrent,NULL,NULL);
/* init hook */
if(init_func){
(*init_func)(init_func_arg);
}
/*
* No need to lock getix as I only allow one thread to call this
* routine at a time
*/
while(TRUE){
caeqEventProcess(evuser);
status = semTake(evuser->osSpecific.ppendsem, WAIT_FOREVER);
assert(status == OK);
}
}
/*
* caeqOSSpecificClose()
*/
void caeqOSSpecificClose(caEventUser *pEvUser)
{
return;
}
/*
* asciiIPAddr
*/
void asciiIPAddr (struct in_addr addr, char *pBuf, unsigned bufSize)
{
char pName[INET_ADDR_LEN];
inet_ntoa_b (addr, pName);
strncpy (pBuf, pName, bufSize);
pBuf[bufSize-1] = '\0';
}

View File

@@ -0,0 +1,659 @@
/*
*
* vxWorks_depen.c
* %W% %G%
*
* vxWorks dependent routines for the CA server
*
*
*/
#include<casdef.h>
#include <inetLib.h>
VERSIONID(vxWorks_depenc,"%W% %G%")
#define MUTEX_SEM_OPTIONS \
(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE)
LOCAL int event_task(
struct event_user *evuser,
void (*init_func)(int arg),
int init_func_arg
);
LOCAL void osDepenTimerCB(void *pciu);
LOCAL void osDepenSendCB(void *pClient);
int caServerTask(struct rsrv *pRsrv);
LOCAL int caMaxFreeBlockPoll(void);
size_t caMaxFreeBlock;
###### no event flush currently (only needed in multi thread env) ####
status = caeqAddFlushEvent (client->evuser, XXXX, client);
assert (status==OK);
/*
* caGetElapsedTime()
*/
caStatus caGetElapsedTime(caElapsedTimeVal *pElapsed)
{
ULONG ticks;
ULONG rate;
ticks = tickGet();
rate = sysClkRateGet();
pElapsed->tv_sec = ticks * rate;
pElapsed->tv_usec = ((ticks % rate)*CAServerUSecInSec)/rate;
return S_cas_success;
}
/*
* caOutOfMemory()
*/
int caOutOfMemory(void)
{
int status;
static int pollTaskStarted;
if(!pollTaskStarted){
caMaxFreeBlock = memFindMax();
status = taskSpawn(
MAXFREEBLOCKTASKNAME,
MAXFREEBLOCKTASKPRI,
MAXFREEBLOCKTASKOPT,
MAXFREEBLOCKTASKSTACK,
caMaxFreeBlockPoll,
0,0,0,0,0,0,0,0,0,0);
if(status>=0){
pollTaskStarted = TRUE;
}
}
return (caMaxFreeBlock<MAX_BLOCK_THRESHOLD);
}
/*
* caMaxFreeBlockPoll()
*/
LOCAL int caMaxFreeBlockPoll(void)
{
while(TRUE){
caMaxFreeBlock = memFindMax();
taskDelay(MAXFREEBLOCKPOLL*sysClkRateGet());
}
}
/*
* casPutCBStartTimer()
*/
caStatus casPutCBStartTimer(
casChanInUse *pciu,
unsigned timeOutSec
)
{
struct client *pClient = pciu->client;
caserver *pRsrv = pClient->cc.pRsrv;
struct timeval tv;
if(pClient->cc.osSpecific.pPutCBAlarm){
tv.tv_sec = timeOutSec;
tv.tv_usec = 0;
pClient->cc.osSpecific.pPutCBAlarm
= fdmgr_add_timeout(
pRsrv->osSpecific.pfdctx,
&tv,
osDepenTimerCB,
pciu);
if(!pClient->cc.osSpecific.pPutCBAlarm){
return S_cas_noMemory;
}
}
return S_cas_success;
}
/*
* osDepenTimerCB()
*/
LOCAL void osDepenTimerCB(void *pParam)
{
casChanInUse *pciu = (casChanInUse *)pParam;
pciu->client->cc.osSpecific.pPutCBAlarm = NULL;
casPutCBTimer(pciu);
}
/*
* casPutCBCancelTimer()
*/
void casPutCBCancelTimer(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(pClient->cc.osSpecific.pPutCBAlarm){
status = fdmgr_clear_timeout(
pRsrv->osSpecific.pfdctx,
pClient->cc.osSpecific.pPutCBAlarm);
assert(status==0);
pClient->cc.osSpecific.pPutCBAlarm = NULL;
}
}
/*
* casDisableSocketRecvIOCallback()
*/
caStatus casDisableSocketRecvIOCallback(struct client *pClient)
{
int status;
if(pClient->cc.osSpecific.sockRecvIOCallbackEnabled){
status = fdmgr_clear_callback(
pClient->cc.pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_read);
assert(status==0);
pClient->cc.osSpecific.sockRecvIOCallbackEnabled = FALSE;
}
return S_cas_success;
}
/*
* casEnableSocketRecvIOCallback()
*/
caStatus casEnableSocketRecvIOCallback(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(!pClient->cc.osSpecific.sockRecvIOCallbackEnabled){
status = fdmgr_add_callback(
pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_read,
pClient->cc.pCB,
pClient);
if(status){
return S_cas_noMemory;
}
pClient->cc.osSpecific.sockRecvIOCallbackEnabled = TRUE;
}
return S_cas_success;
}
/*
* casWaitForIO ()
*/
caStatus casWaitForIO (struct rsrv *pRsrv, caTime *pDelay)
{
struct timeval tv;
tv.tv_sec = caTime->sec;
tv.tv_usec = caTime->nsec / NSecPerUsec;
status = fdmgr_pend_event(pRsrv->osSpecific.pfdctx, &tv);
if (status) {
return S_cas_internal;
}
return S_cas_success;
}
/*
* casArmSocketSendIOCallback()
*/
caStatus casArmSocketSendIOCallback(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(!pClient->cc.osSpecific.sockSendIOCallbackEnabled){
status = fdmgr_add_callback(
pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_write,
osDepenSendCB,
pClient);
if(status){
return S_cas_noMemory;
}
pClient->cc.osSpecific.sockSendIOCallbackEnabled = TRUE;
}
return S_cas_success;
}
/*
* casCancelSocketSendIOCallback()
*/
caStatus casCancelSocketSendIOCallback(struct client *pClient)
{
caserver *pRsrv = pClient->cc.pRsrv;
int status;
if(pClient->cc.osSpecific.sockSendIOCallbackEnabled){
status = fdmgr_clear_callback(
pRsrv->osSpecific.pfdctx,
pClient->cc.sock,
fdi_write);
assert(status==0);
pClient->cc.osSpecific.sockSendIOCallbackEnabled = FALSE;
}
return S_cas_success;
}
/*
* osDepenSendCB()
*/
LOCAL void osDepenSendCB(void *pParam)
{
struct client *pClient = (struct client *) pParam;
pClient->cc.osSpecific.sockSendIOCallbackEnabled = FALSE;
(*pClient->sendHandler)(pClient);
}
/*
* casOSSpecificDelete()
*/
void casOSSpecificDelete(struct rsrv *pRsrv)
{
int status;
if(taskIdVerify(pRsrv->osSpecific.selectTask) == OK){
taskwdRemove(taskDelete(pRsrv->osSpecific.selectTask));
taskDelete(pRsrv->osSpecific.selectTask);
}
if(pRsrv->osSpecific.clientQLock){
status = semDelete(pRsrv->osSpecific.clientQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.freeChanQLock){
status = semDelete(pRsrv->osSpecific.freeChanQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.freeEventQLock){
status = semDelete(pRsrv->osSpecific.freeEventQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.pvQLock){
status = semDelete(pRsrv->osSpecific.pvQLock);
assert(status==OK);
}
if(pRsrv->osSpecific.pfdctx){
status = fdmgr_delete(pRsrv->osSpecific.pfdctx);
assert(status==OK);
}
}
/*
* casOSSpecificInit()
*/
caStatus casOSSpecificInit(struct rsrv *pRsrv)
{
pRsrv->osSpecific.clientQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.clientQLock){
return S_cas_noMemory;
}
pRsrv->osSpecific.freeChanQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.freeChanQLock){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.freeEventQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.freeEventQLock){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.pvQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!pRsrv->osSpecific.pvQLock){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.pfdctx = fdmgr_init();
if(!pRsrv->osSpecific.pfdctx){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* casOSSpecificStartServer()
*/
caStatus casOSSpecificStartServer(caserver *pRsrv)
{
int status;
status = fdmgr_add_callback(
pRsrv->osSpecific.pfdctx,
pRsrv->server_sock,
fdi_read,
rsrv_connect,
pRsrv);
if(status < 0){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
status = taskSpawn(
REQ_SRVR_NAME,
REQ_SRVR_PRI,
REQ_SRVR_OPT,
RSP_SRVR_STACK,
caServerTask,
(int)pRsrv,
0,0,0,0,0,0,0,0,0);
if(status == ERROR){
casOSSpecificDelete(pRsrv);
return S_cas_noMemory;
}
pRsrv->osSpecific.selectTask = status;
return S_cas_success;
}
/*
* caServerTask()
*/
int caServerTask(caserver *pRsrv)
{
struct timeval tv;
caTime delay;
struct client *pClient;
int nchars;
int status;
taskwdInsert((int)taskIdCurrent,NULL,NULL);
while(TRUE){
delay.sec = 100;
delay.usec = 0;
status = caServerProcess (pRsrv, &delay);
assert (status == S_cas_success);
}
}
/*
* casSchedualBeacon()
*/
void casSchedualBeacon(struct rsrv *pRsrv)
{
fdmgrAlarm *tmp;
struct timeval tv;
tv.tv_sec = pRsrv->delayToNextBeacon.tv_sec;
tv.tv_usec = pRsrv->delayToNextBeacon.tv_usec;
tmp = fdmgr_add_timeout(
pRsrv->osSpecific.pfdctx,
&tv,
casSendBeacon,
pRsrv);
if(!tmp){
ca_printf("CAS: Unable to keep beacon going\n");
}
}
/*
* casOSSpecificClientInit()
*/
caStatus casOSSpecificClientInit(struct client *client)
{
client->cc.osSpecific.eventQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.eventQLock){
return S_cas_noMemory;
}
client->cc.osSpecific.chanQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.chanQLock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
client->cc.osSpecific.putNotifyLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.putNotifyLock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
client->cc.osSpecific.lock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.lock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
client->cc.osSpecific.accessRightsQLock = semMCreate(MUTEX_SEM_OPTIONS);
if(!client->cc.osSpecific.accessRightsQLock){
casOSSpecificClientDelete(client);
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* casOSSpecificClientDelete()
*/
void casOSSpecificClientDelete(struct client *client)
{
int status;
if(client->cc.osSpecific.eventQLock){
status = semDelete(client->cc.osSpecific.eventQLock);
assert(status==OK);
}
if(client->cc.osSpecific.chanQLock){
status = semDelete(client->cc.osSpecific.chanQLock);
assert(status==OK);
}
if(client->cc.osSpecific.putNotifyLock){
status = semDelete(client->cc.osSpecific.putNotifyLock);
assert(status==OK);
}
if(client->cc.osSpecific.lock){
status = semDelete(client->cc.osSpecific.lock);
assert(status==OK);
}
if(client->cc.osSpecific.accessRightsQLock){
status = semDelete(client->cc.osSpecific.accessRightsQLock);
assert(status==OK);
}
}
/*
* caeqOSSpecificInit()
*/
caStatus caeqOSSpecificInit(caEventUser *evuser)
{
evuser->osSpecific.lock = semMCreate(MUTEX_SEM_OPTIONS);
if(!evuser->osSpecific.lock){
return S_cas_noMemory;
}
evuser->osSpecific.ppendsem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
if(!evuser->osSpecific.ppendsem){
semDelete(evuser->osSpecific.lock);
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* caeqOSSpecificDelete()
*/
void caeqOSSpecificDelete(caEventUser *evuser)
{
int status;
if(taskIdVerify(evuser->osSpecific.taskid)==OK){
taskwdRemove(evuser->osSpecific.taskid);
taskDelete(evuser->osSpecific.taskid);
}
status = semDelete(evuser->osSpecific.lock);
assert(status == OK);
status = semDelete(evuser->osSpecific.ppendsem);
assert(status == OK);
}
/*
* caeqOSSpecificPVInit ()
*/
caStatus caeqOSSpecificPVInit (casPVInUse *pPV)
{
pPV->osSpecific.lock = semMCreate(MUTEX_SEM_OPTIONS);
if (!pPV->osSpecific.lock) {
return S_cas_noMemory;
}
return S_cas_success;
}
/*
* caeqOSSpecificPVDelete ()
*/
void caeqOSSpecificPVDelete (casPVInUse *pPV)
{
int status;
status = semDelete (pPV->osSpecific.lock);
assert (status == OK);
}
/*
* caeqOSSpecificEventNotify()
*/
void caeqOSSpecificEventNotify(caEventUser *evuser)
{
int status;
status = semGive(evuser->osSpecific.ppendsem);
assert(status == OK);
}
/*
* caeqStartEvents()
*/
int caeqStartEvents(
struct event_user *evuser,
char *taskname, /* defaulted if NULL */
void (*init_func)(),
int init_func_arg,
int priority_offset
)
{
int status;
int taskpri;
/* only one ca_pend_event thread may be started for each evuser ! */
while(!vxTas(&evuser->osSpecific.pendlck))
return ERROR;
status = taskPriorityGet(taskIdSelf(), &taskpri);
if(status == ERROR){
return ERROR;
}
taskpri += priority_offset;
if(!taskname){
taskname = EVENT_PEND_NAME;
}
status = taskSpawn(
taskname,
taskpri,
EVENT_PEND_OPT,
EVENT_PEND_STACK,
event_task,
(int)evuser,
(int)init_func,
(int)init_func_arg,
0,0,0,0,0,0,0);
if(status == ERROR){
return ERROR;
}
evuser->osSpecific.taskid = status;
return OK;
}
/*
* EVENT_TASK()
*/
LOCAL int event_task(
struct event_user *evuser,
void (*init_func)(int init_func_arg),
int init_func_arg
)
{
int status;
taskwdInsert((int)taskIdCurrent,NULL,NULL);
/* init hook */
if(init_func){
(*init_func)(init_func_arg);
}
/*
* No need to lock getix as I only allow one thread to call this
* routine at a time
*/
while(TRUE){
caeqEventProcess(evuser);
status = semTake(evuser->osSpecific.ppendsem, WAIT_FOREVER);
assert(status == OK);
}
}
/*
* caeqOSSpecificClose()
*/
void caeqOSSpecificClose(caEventUser *pEvUser)
{
return;
}
/*
* asciiIPAddr
*/
void asciiIPAddr (struct in_addr addr, char *pBuf, unsigned bufSize)
{
char pName[INET_ADDR_LEN];
inet_ntoa_b (addr, pName);
strncpy (pBuf, pName, bufSize);
pBuf[bufSize-1] = '\0';
}

View File

@@ -0,0 +1,256 @@
#include <vxWorks.h>
#include <taskLib.h>
#include <errnoLib.h>
#include <logLib.h>
#include <tickLib.h>
#include <sysLib.h>
#include <vxLib.h>
#include <ioLib.h>
#include <usrLib.h>
#include <semLib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sockLib.h> /* for sendto() setsockopt() etc */
#include <netinet/in.h>
#include <netinet/tcp.h>
/*
* EPICS on vxWorks
*/
#include <task_params.h>
#include <taskwd.h>
#include <fdmgr.h>
extern size_t caMaxFreeBlock;
#define MAXFREEBLOCKPOLL 5 /* sec */
#define MAXFREEBLOCKTASKNAME "caMemPoll"
#define MAXFREEBLOCKTASKPRI 255
#define MAXFREEBLOCKTASKOPT (VX_FP_TASK)
#define MAXFREEBLOCKTASKSTACK 4095
/*
* per server locks
* ================
*/
#define LOCK_CLIENTQ(PRSRV) \
{ \
int status; \
status = semTake((PRSRV)->osSpecific.clientQLock, WAIT_FOREVER); \
assert(status==OK); \
}
#define UNLOCK_CLIENTQ(PRSRV) \
{ \
int status; \
status = semGive((PRSRV)->osSpecific.clientQLock); \
assert(status==OK); \
}
#define LOCK_FREE_CHAN_Q(PRSRV) \
{\
int status;\
status = semTake((PRSRV)->osSpecific.freeChanQLock, WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_FREE_CHAN_Q(PRSRV) \
{ \
int status;\
status = semGive((PRSRV)->osSpecific.freeChanQLock);\
assert(status==OK);\
}
#define LOCK_FREE_EVENT_Q(PRSRV) \
{\
int status;\
status = semTake((PRSRV)->osSpecific.freeEventQLock, WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_FREE_EVENT_Q(PRSRV) \
{ \
int status;\
status = semGive((PRSRV)->osSpecific.freeEventQLock);\
assert(status==OK);\
}
#define LOCK_PVQ(PRSRV) \
{ \
int status; \
status = semTake((PRSRV)->osSpecific.pvQLock, WAIT_FOREVER); \
assert(status==OK); \
}
#define UNLOCK_PVQ(PRSRV) \
{ \
int status;\
status = semGive((PRSRV)->osSpecific.pvQLock);\
assert(status==OK);\
}
/*
* per client locks
* ================
*/
#define SEND_LOCK(CLIENT) \
{\
int status;\
status = semTake((CLIENT)->cc.osSpecific.lock, WAIT_FOREVER);\
assert(status==OK);\
}
#define SEND_UNLOCK(CLIENT) \
{ \
int status;\
status = semGive((CLIENT)->cc.osSpecific.lock);\
assert(status==OK);\
}
#define LOCK_CHAN_Q(PCLIENT) \
{\
int status;\
status = semTake((PCLIENT)->cc.osSpecific.chanQLock, WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_CHAN_Q(PCLIENT) \
{ \
int status;\
status = semGive((PCLIENT)->cc.osSpecific.chanQLock);\
assert(status==OK);\
}
#define LOCK_EVENT_Q(PCLIENT) \
{\
int status;\
status = semTake((PCLIENT)->cc.osSpecific.eventQLock, WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_EVENT_Q(PCLIENT) \
{ \
int status;\
status = semGive((PCLIENT)->cc.osSpecific.eventQLock);\
assert(status==OK);\
}
#define LOCK_PUT_NOTIFY(PCLIENT) \
{\
int status;\
status = semTake((PCLIENT)->cc.osSpecific.putNotifyLock, WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_PUT_NOTIFY(PCLIENT) \
{ \
int status;\
status = semGive((PCLIENT)->cc.osSpecific.putNotifyLock);\
assert(status==OK);\
}
#define LOCK_ACCESS_RIGHTS_Q(PCLIENT) \
{\
int status;\
status = semTake((PCLIENT)->cc.osSpecific.accessRightsQLock, \
WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_ACCESS_RIGHTS_Q(PCLIENT) \
{ \
int status;\
status = semGive((PCLIENT)->cc.osSpecific.accessRightsQLock);\
assert(status==OK);\
}
/*
* event system locks
* ==================
*/
#define CA_EVENT_LOCK(PEVUSER) \
{ \
int status;\
status = semTake((PEVUSER)->osSpecific.lock, WAIT_FOREVER);\
assert(status==OK);\
}
#define CA_EVENT_UNLOCK(PEVUSER) \
{ \
int status;\
status = semGive((PEVUSER)->osSpecific.lock);\
assert(status==OK);\
}
#define LOCK_PV(PPV) \
{ \
int status;\
status = semTake((PPV)->osSpecific.lock, WAIT_FOREVER);\
assert(status==OK);\
}
#define UNLOCK_PV(PPV) \
{ \
int status;\
status = semGive((PPV)->osSpecific.lock);\
assert(status==OK);\
}
/*
* vxWorks specific addition to event_user struct
*/
typedef struct {
SEM_ID lock;
SEM_ID ppendsem;
int taskid;
char pendlck;
}caeqOsSpecific;
typedef struct {
SEM_ID lock;
}caPVOsSpecific;
/*
* vxWorks specific addition to rsrv struct
*/
typedef struct {
fdctx *pfdctx;
SEM_ID clientQLock;
SEM_ID pvQLock;
SEM_ID freeChanQLock;
SEM_ID freeEventQLock;
int selectTask;
}rsrvOsSpecific;
/*
* vxWorks specific addition to client struct
*/
typedef struct {
SEM_ID lock;
SEM_ID putNotifyLock;
SEM_ID chanQLock;
SEM_ID eventQLock;
SEM_ID accessRightsQLock;
fdmgrAlarm *pPutCBAlarm;
unsigned sockSendIOCallbackEnabled:1;
unsigned sockRecvIOCallbackEnabled:1;
}clientOsSpecific;
typedef int SOCKET;
#define SOCKERRNO errno
#define socket_close(S) close(S)
/* vxWorks still has brain dead func proto for ioctl() */
#define socket_ioctl(A,B,C) ioctl(A,B,(int)C)
/* leave task around for debugging if we fail */
#define abort(A) taskSuspend(0)

74
src/cas/test/buckTest.c Normal file
View File

@@ -0,0 +1,74 @@
#include <time.h>
#include <assert.h>
#include <stdio.h>
#include <bucketLib.h>
main()
{
unsigned id1;
unsigned id2;
char *pValSave1;
char *pValSave2;
int s;
BUCKET *pb;
char *pVal;
unsigned i;
clock_t start, finish;
double duration;
const int LOOPS = 500000;
pb = bucketCreate(8);
if(!pb){
return -1;
}
id1 = 0x1000a432;
pValSave1 = "fred";
s = bucketAddItemUnsignedId(pb, &id1, pValSave1);
assert (s == S_bucket_success);
pValSave2 = "jane";
id2 = 0x0000a432;
s = bucketAddItemUnsignedId(pb, &id2, pValSave2);
assert (s == S_bucket_success);
start = clock();
for(i=0; i<LOOPS; i++){
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id1);
assert(pVal == pValSave1);
pVal = bucketLookupItemUnsignedId(pb, &id2);
assert(pVal == pValSave2);
}
finish = clock();
duration = finish-start;
duration = duration/CLOCKS_PER_SEC;
printf("It took %15.10f total sec\n", duration);
duration = duration/LOOPS;
duration = duration/10;
duration = duration * 1e6;
printf("It took %15.10f u sec per hash lookup\n", duration);
bucketShow(pb);
return S_bucket_success;
}

View File

@@ -0,0 +1,65 @@
//
// gddAppFuncTable.h
//
// Author: Jeff Hill
//
//
//
//
#include <stdio.h>
#include <gddAppFuncTable.h>
class casPV {
public:
casPV(const char * const pNameIn) : pName(pNameIn) {};
gddAppFuncTableStatus cb(gdd &val);
protected:
const char * const pName;
};
class casPVII : public casPV {
public:
casPVII(const char * const pNameIn) : casPV(pNameIn) {};
gddAppFuncTableStatus cb0(gdd &val);
gddAppFuncTableStatus cb1(gdd &val);
};
main ()
{
gddAppFuncTableTable<casPVII> pvAttrDB;
unsigned appPrecision= pvAttrDB.RegisterApplicationType ("precision");
unsigned appValue = pvAttrDB.RegisterApplicationType ("value");
gddScaler *pPrec = new gddScaler (appPrecision, aitEnumFloat32);
gddScaler *pVal = new gddScaler (appValue, aitEnumFloat32);
casPV pv ("jane");
casPVII pvII ("fred");
casPVII pvIIa ("albert");
pvAttrDB.installReadFunc (appPrecision, casPVII::cb0);
pvAttrDB.installReadFunc (appValue, casPVII::cb1);
pvAttrDB.read (pvII, *pPrec);
pvAttrDB.read (pvII, *pVal);
pvAttrDB.read (pvIIa, *pPrec);
}
unsigned casPV::cb(gdd &value)
{
printf("Here for %s\n", pName);
return 0;
}
unsigned casPVII::cb0(gdd &value)
{
printf("Here in cb0 for %s\n", pName);
return 0;
}
unsigned casPVII::cb1(gdd &value)
{
printf("Here in cb1 for %s\n", pName);
return 0;
}

View File

@@ -0,0 +1,110 @@
#include <assert.h>
#include <time.h>
#include <stdio.h>
#include <resourceLib.h>
class uintId {
public:
uintId (unsigned idIn) : id(idIn) {}
resourceTableID resourceHash(unsigned nBitsId) const
{
unsigned src = this->id;
resourceTableID hashid;
hashid = src;
src = src >> nBitsId;
while (src) {
hashid = hashid ^ src;
src = src >> nBitsId;
}
//
// the result here is always masked to the
// proper size after it is returned to the resource class
//
return hashid;
}
int operator == (const uintId &idIn)
{
return this->id == idIn.id;
}
private:
unsigned const id;
};
class fred : public uintId, tsSLNode<fred> {
public:
fred (const char *pNameIn, unsigned idIn) :
pName(pNameIn), uintId(idIn) {}
private:
const char * const pName;
};
main()
{
unsigned i;
clock_t start, finish;
double duration;
const int LOOPS = 500000;
resourceTable<fred,uintId> tbl;
fred fred1("fred1",0x1000a432);
fred fred2("fred2",0x0000a432);
fred *pFred;
uintId id1(0x1000a432);
uintId id2(0x0000a432);
int status;
status = tbl.init(8);
if (status) {
return -1;
}
status = tbl.add(fred1);
assert (!status);
status = tbl.add(fred2);
assert (!status);
start = clock();
for(i=0; i<LOOPS; i++){
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id1);
assert(pFred==&fred1);
pFred = tbl.lookup(id2);
assert(pFred==&fred2);
}
finish = clock();
duration = finish-start;
duration /= CLOCKS_PER_SEC;
printf("It took %15.10f total sec\n", duration);
duration /= LOOPS;
duration /= 10;
duration *= 1e6;
printf("It took %15.10f u sec per hash lookup\n", duration);
tbl.show(10u);
tbl.remove(id1);
tbl.remove(id2);
return 0;
}

View File

@@ -0,0 +1,65 @@
#ifndef CLOCKS_PER_SEC
#define CLOCKS_PER_SEC 1000000
#endif
#include <tsDLList.h>
#include <assert.h>
#include <time.h>
#include <stdio.h>
class fred : public tsDLNode<fred> {
public:
fred() : count(0) {}
void inc () {count++;}
private:
unsigned count;
};
class jane : public fred, public tsDLNode<jane> {
public:
jane() {}
private:
};
#define LOOPCOUNT 100000
main ()
{
tsDLList<fred> list;
tsDLIter<fred> iter(list);
fred *pFred;
unsigned i;
clock_t clk;
clock_t diff;
double delay;
for (i=0; i<LOOPCOUNT; i++) {
pFred = new fred();
list.add(*pFred);
}
clk = clock();
iter = list;
while (pFred = iter()) {
pFred->inc();
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10lf\n", delay);
pFred = new fred();
clk = clock();
iter = list;
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10lf\n", delay);
}

View File

@@ -0,0 +1,72 @@
#include <tsDLList.h>
#include <assert.h>
#include <stdio.h>
class fred : public tsDLNode<fred> {
public:
fred(const char * const pNameIn) : pName(pNameIn){}
void show () {printf("%s\n", pName);}
private:
const char * const pName;
};
class jane : public fred, public tsDLNode<jane> {
public:
jane(const char * const pNameIn) : fred(pNameIn){}
private:
};
main ()
{
tsDLList<fred> list;
tsDLIter<fred> iter(list);
fred *pFred;
fred *pFredII;
fred *pFredBack;
tsDLList<jane> janeList;
tsDLIter<jane> janeIter(janeList);
jane *pJane;
pFred = new fred("A");
pFredII = new fred("B");
list.add(*pFred);
list.add(*pFredII);
pFredBack = list.first();
assert(pFredBack == pFred);
pFredBack = list.last();
assert(pFredBack == pFredII);
list.remove(*pFred);
list.add(*pFred);
pFredBack = list.get();
assert (pFredBack == pFredII);
pFredBack = list.get();
assert (pFredBack == pFred);
assert (list.count() == 0u);
list.add(*pFred);
list.add(*pFredII);
list.add(* new fred("C"));
list.add(* new fred("D"));
while (pFredBack = iter()) {
pFredBack->show();
}
pJane = new jane("JA");
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
while (pJane = janeIter()) {
pJane->show();
}
iter = list;
while (pFredBack = iter()) {
pFredBack->show();
}
}

773
src/cas/test/tsDLListTest.s Normal file
View File

@@ -0,0 +1,773 @@
!
.seg "data"
/* 000000 4 */ .align 1
!
! SUBROUTINE LI9
!
! OFFSET SOURCE LINE LABEL INSTRUCTION
LI9:
/* 000000 6 */ .ascii "A\0"
/* 0x0002 8 */ .align 1
!
! ENTRY LI10
!
LI10:
/* 0x0002 10 */ .ascii "B\0"
/* 0x0004 12 */ .align 4
!
! ENTRY LI11
!
LI11:
/* 0x0004 14 */ .ascii "Assertion failed: file \"%s\", line %d\n\0"
/* 0x002a 16 */ .align 4
!
! ENTRY LI12
!
LI12:
/* 0x002c 18 */ .ascii "tsDLListTest.cc\0"
/* 0x003c 20 */ .align 4
!
! ENTRY LI13
!
LI13:
/* 0x003c 22 */ .ascii "Assertion failed: file \"%s\", line %d\n\0"
/* 0x0062 24 */ .align 4
!
! ENTRY LI14
!
LI14:
/* 0x0064 26 */ .ascii "tsDLListTest.cc\0"
/* 0x0074 28 */ .align 4
!
! ENTRY LI15
!
LI15:
/* 0x0074 30 */ .ascii "Assertion failed: file \"%s\", line %d\n\0"
/* 0x009a 32 */ .align 4
!
! ENTRY LI16
!
LI16:
/* 0x009c 34 */ .ascii "tsDLListTest.cc\0"
/* 0x00ac 36 */ .align 4
!
! ENTRY LI17
!
LI17:
/* 0x00ac 38 */ .ascii "Assertion failed: file \"%s\", line %d\n\0"
/* 0x00d2 40 */ .align 4
!
! ENTRY LI18
!
LI18:
/* 0x00d4 42 */ .ascii "tsDLListTest.cc\0"
/* 0x00e4 44 */ .align 4
!
! ENTRY LI19
!
LI19:
/* 0x00e4 46 */ .ascii "Assertion failed: file \"%s\", line %d\n\0"
/* 0x010a 48 */ .align 4
!
! ENTRY LI20
!
LI20:
/* 0x010c 50 */ .ascii "tsDLListTest.cc\0"
/* 0x011c 52 */ .align 1
!
! ENTRY LI21
!
LI21:
/* 0x011c 54 */ .ascii "C\0"
/* 0x011e 56 */ .align 1
!
! ENTRY LI22
!
LI22:
/* 0x011e 58 */ .ascii "D\0"
/* 0x0120 60 */ .align 4
!
! ENTRY LI23
!
LI23:
/* 0x0120 62 */ .ascii "%s\n\0"
/* 0x0124 64 */ .align 1
!
! ENTRY LI24
!
LI24:
/* 0x0124 66 */ .ascii "JA\0"
/* 0x0127 68 */ .align 1
!
! ENTRY LI25
!
LI25:
/* 0x0127 70 */ .ascii "JB\0"
/* 0x012a 72 */ .align 4
!
! ENTRY LI26
!
LI26:
/* 0x012c 74 */ .ascii "%s\n\0"
/* 0x0130 76 */ .align 4
!
! ENTRY LI27
!
LI27:
/* 0x0130 78 */ .ascii "%s\n\0"
!
.seg "text"
/* 000000 0 */ .align 8
/* 000000 */ .skip 16
! FILE tsDLListTest.cc
! 4 !#include <tsDLList.h>
! 5 !#include <assert.h>
! 7 !class fred : public tsDLNode<fred> {
! 8 !public:
! 9 ! fred(const char * const pNameIn) : pName(pNameIn){}
! 10 ! void show () {printf("%s\n", pName);}
! 11 !private:
! 12 ! const char * const pName;
! 13 !};
! 15 !class jane : public fred, public tsDLNode<jane> {
! 16 !public:
! 17 ! jane(const char * const pNameIn) : fred(pNameIn){}
! 18 !private:
! 19 !};
! 21 !main ()
! 22 !{
!
! SUBROUTINE _main
!
! OFFSET SOURCE LINE LABEL INSTRUCTION
.global _main
_main:
/* 000000 */ save %sp,-136,%sp
! 23 ! tsDLList<fred> list;
! 24 ! tsDLIter<fred> iter(list);
! 25 ! fred *pFred;
! 26 ! fred *pFredII;
! 27 ! fred *pFredBack;
! 28 ! tsDLList<jane> janeList;
! 29 ! tsDLIter<jane> janeIter(janeList);
! 30 ! jane *pJane;
! 32 ! pFred = new fred("A");
/* 0x0004 32 */ sethi %hi(LI9),%o0
/* 0x0008 22 */ call __cinit_,0 ! Result = %g0
/* 0x000c 0 */ add %o0,%lo(LI9),%l1
/* 0x0010 23 */ add %fp,-12,%o0
/* 0x0014 24 */ add %fp,-20,%o1
/* 0x0018 23 */ st %g0,[%o0] ! volatile
/* 0x001c */ st %g0,[%o0+4] ! volatile
/* 0x0020 */ st %g0,[%o0+8] ! volatile
/* 0x0024 24 */ add %fp,-12,%o0
/* 0x0028 */ st %o0,[%o1] ! volatile
/* 0x002c 28 */ add %fp,-32,%o0
/* 0x0030 24 */ st %g0,[%o1+4] ! volatile
/* 0x0034 29 */ add %fp,-40,%o1
/* 0x0038 28 */ st %g0,[%o0] ! volatile
/* 0x003c */ st %g0,[%o0+4] ! volatile
/* 0x0040 */ st %g0,[%o0+8] ! volatile
/* 0x0044 29 */ add %fp,-32,%o0
/* 0x0048 */ st %o0,[%o1] ! volatile
/* 0x004c 32 */ or %g0,12,%o0
/* 0x0050 */ call ___0OnwUi,1 ! Result = %o0
/* 0x0054 29 */ st %g0,[%o1+4] ! volatile
/* 0x0058 32 */ orcc %g0,%o0,%l3
/* 0x005c */ be L77000004
/* 0x0060 */ or %g0,%l3,%o0
L77000002:
/* 0x0064 */ st %g0,[%o0] ! volatile
/* 0x0068 */ add %l1,0,%o1
/* 0x006c */ st %g0,[%o0+4] ! volatile
/* 0x0070 */ st %o1,[%l3+8] ! volatile
L77000004:
! 33 ! pFredII = new fred("B");
/* 0x0074 33 */ call ___0OnwUi,1 ! Result = %o0
/* 0x0078 */ or %g0,12,%o0
/* 0x007c */ orcc %g0,%o0,%l2
/* 0x0080 */ be L77000007
/* 0x0084 */ or %g0,%l2,%o0
L77000005:
/* 0x0088 */ st %g0,[%o0] ! volatile
/* 0x008c */ add %l1,2,%o1
/* 0x0090 */ st %g0,[%o0+4] ! volatile
/* 0x0094 */ st %o1,[%l2+8] ! volatile
L77000007:
! 35 ! list.add(*pFred);
/* 0x0098 35 */ add %fp,-12,%o0
/* 0x009c */ st %g0,[%l3] ! volatile
/* 0x00a0 */ ld [%o0+4],%o1 ! volatile
/* 0x00a4 */ st %o1,[%l3+4] ! volatile
/* 0x00a8 */ ld [%o0+8],%o2 ! volatile
/* 0x00ac */ cmp %o2,0
/* 0x00b0 */ bne L77000008
/* 0x00b4 */ or %g0,%l3,%o3
L77000009:
/* 0x00b8 */ ba L77000010
/* 0x00bc */ st %o3,[%o0] ! volatile
! 36 ! list.add(*pFredII);
! 37 ! pFredBack = list.first();
! 38 ! assert(pFredBack == pFred);
! 39 ! pFredBack = list.last();
! 40 ! assert(pFredBack == pFredII);
! 41 ! list.remove(*pFred);
! 42 ! list.add(*pFred);
! 43 ! pFredBack = list.get();
! 44 ! assert (pFredBack == pFredII);
! 45 ! pFredBack = list.get();
! 46 ! assert (pFredBack == pFred);
! 47 ! assert (list.count() == 0u);
! 48 ! list.add(*pFred);
! 49 ! list.add(*pFredII);
! 50 ! list.add(* new fred("C"));
! 51 ! list.add(* new fred("D"));
! 53 ! while (pFredBack = iter()) {
! 54 ! pFredBack->show();
! 55 ! }
! 57 ! pJane = new jane("JA");
! 58 ! janeList.add(*pJane);
! 59 ! pJane = new jane("JB");
! 60 ! janeList.add(*pJane);
! 62 ! while (pJane = janeIter()) {
! 63 ! pJane->show();
! 64 ! }
! 66 ! iter = list;
! 67 ! while (pFredBack = iter()) {
! 68 ! pFredBack->show();
L77000099:
/* 0x00c0 */ ret
/* 0x00c4 */ restore %g0,0,%o0
L77000008:
/* 0x00c8 */ ld [%o0+4],%o1 ! volatile
/* 0x00cc */ st %o3,[%o1] ! volatile
L77000010:
/* 0x00d0 */ st %o3,[%o0+4] ! volatile
/* 0x00d4 36 */ add %fp,-12,%o3
/* 0x00d8 35 */ ld [%o0+8],%o1 ! volatile
/* 0x00dc */ add %o1,1,%o1
/* 0x00e0 */ st %o1,[%o0+8] ! volatile
/* 0x00e4 36 */ st %g0,[%l2] ! volatile
/* 0x00e8 */ ld [%o3+4],%o1 ! volatile
/* 0x00ec */ st %o1,[%l2+4] ! volatile
/* 0x00f0 */ ld [%o3+8],%o2 ! volatile
/* 0x00f4 */ cmp %o2,0
/* 0x00f8 */ bne L77000011
/* 0x00fc */ or %g0,%l2,%o4
L77000012:
/* 0x0100 */ ba L77000013
/* 0x0104 */ st %o4,[%o3] ! volatile
L77000011:
/* 0x0108 */ ld [%o3+4],%o1 ! volatile
/* 0x010c */ st %o4,[%o1] ! volatile
L77000013:
/* 0x0110 */ st %o4,[%o3+4] ! volatile
/* 0x0114 38 */ sethi %hi(__iob),%o0
/* 0x0118 36 */ ld [%o3+8],%o1 ! volatile
/* 0x011c 0 */ add %o0,%lo(__iob),%l4
/* 0x0120 36 */ add %o1,1,%o1
/* 0x0124 */ st %o1,[%o3+8] ! volatile
/* 0x0128 37 */ add %fp,-12,%o0
/* 0x012c */ ld [%o0],%o0 ! volatile
/* 0x0130 38 */ cmp %o0,%l3
/* 0x0134 */ bne L77000014
/* 0x0138 */ or %g0,40,%l5
L77000015:
/* 0x013c 39 */ add %fp,-12,%o0
L900000116:
/* 0x0140 39 */ ld [%o0+4],%o0 ! volatile
/* 0x0144 40 */ cmp %o0,%l2
/* 0x0148 */ bne,a L900000115
/* 0x014c */ add %l4,0,%l0
L77000017:
/* 0x0150 41 */ add %fp,-12,%o0
L900000117:
/* 0x0154 41 */ ld [%o0+4],%o1 ! volatile
/* 0x0158 */ cmp %o1,%l3
/* 0x015c */ bne L77000019
/* 0x0160 */ or %g0,%l3,%o3
L77000018:
/* 0x0164 */ ld [%o3+4],%o1 ! volatile
/* 0x0168 */ ba L77000020
/* 0x016c */ st %o1,[%o0+4] ! volatile
L77000014:
/* 0x0170 */ add %l4,0,%l0
/* 0x0174 */ add %l5,%l0,%o0
/* 0x0178 */ add %l1,4,%o1
/* 0x017c */ add %l1,44,%o2
/* 0x0180 */ call _fprintf,4 ! Result = %g0
/* 0x0184 */ or %g0,38,%o3
/* 0x0188 */ call _exit,1 ! Result = %g0
/* 0x018c */ or %g0,1,%o0
/* 0x0190 */ ba L900000116
/* 0x0194 39 */ add %fp,-12,%o0
L900000115:
/* 0x0198 */ add %l5,%l0,%o0
/* 0x019c */ add %l1,60,%o1
/* 0x01a0 */ add %l1,100,%o2
/* 0x01a4 */ call _fprintf,4 ! Result = %g0
/* 0x01a8 */ or %g0,40,%o3
/* 0x01ac */ call _exit,1 ! Result = %g0
/* 0x01b0 */ or %g0,1,%o0
/* 0x01b4 */ ba L900000117
/* 0x01b8 41 */ add %fp,-12,%o0
L77000019:
/* 0x01bc */ ld [%o3+4],%o1 ! volatile
/* 0x01c0 */ ld [%o3],%o2 ! volatile
/* 0x01c4 */ st %o1,[%o2+4] ! volatile
L77000020:
/* 0x01c8 */ ld [%o0],%o1 ! volatile
/* 0x01cc */ cmp %o1,%o3
/* 0x01d0 */ bne,a L900000118
/* 0x01d4 */ ld [%o3],%o1 ! volatile
L77000021:
/* 0x01d8 */ ld [%o3],%o1 ! volatile
/* 0x01dc */ ba L77000023
/* 0x01e0 */ st %o1,[%o0] ! volatile
L900000118:
/* 0x01e4 */ ld [%o3+4],%o2 ! volatile
/* 0x01e8 */ st %o1,[%o2] ! volatile
L77000023:
/* 0x01ec */ ld [%o0+8],%o1 ! volatile
/* 0x01f0 */ add %o1,-1,%o1
/* 0x01f4 */ st %o1,[%o0+8] ! volatile
/* 0x01f8 42 */ add %fp,-12,%o0
/* 0x01fc */ st %g0,[%l3] ! volatile
/* 0x0200 */ ld [%o0+4],%o1 ! volatile
/* 0x0204 */ st %o1,[%l3+4] ! volatile
/* 0x0208 */ ld [%o0+8],%o2 ! volatile
/* 0x020c */ cmp %o2,0
/* 0x0210 */ bne L77000024
/* 0x0214 */ or %g0,%l3,%o3
L77000025:
/* 0x0218 */ ba L77000026
/* 0x021c */ st %o3,[%o0] ! volatile
L77000024:
/* 0x0220 */ ld [%o0+4],%o1 ! volatile
/* 0x0224 */ st %o3,[%o1] ! volatile
L77000026:
/* 0x0228 */ st %o3,[%o0+4] ! volatile
/* 0x022c */ ld [%o0+8],%o1 ! volatile
/* 0x0230 */ add %o1,1,%o1
/* 0x0234 */ st %o1,[%o0+8] ! volatile
/* 0x0238 43 */ add %fp,-12,%o0
/* 0x023c */ ld [%o0],%o3 ! volatile
/* 0x0240 */ cmp %o3,0
/* 0x0244 */ be,a L900000119
/* 0x0248 44 */ cmp %o3,%l2
L77000027:
/* 0x024c */ ld [%o0+4],%o1 ! volatile
/* 0x0250 */ cmp %o1,%o3
/* 0x0254 */ bne,a L900000120
/* 0x0258 */ ld [%o3+4],%o1 ! volatile
L77000028:
/* 0x025c */ ld [%o3+4],%o1 ! volatile
/* 0x0260 */ ba L77000030
/* 0x0264 */ st %o1,[%o0+4] ! volatile
L900000120:
/* 0x0268 */ ld [%o3],%o2 ! volatile
/* 0x026c */ st %o1,[%o2+4] ! volatile
L77000030:
/* 0x0270 */ ld [%o0],%o1 ! volatile
/* 0x0274 */ cmp %o1,%o3
/* 0x0278 */ bne,a L900000121
/* 0x027c */ ld [%o3],%o1 ! volatile
L77000031:
/* 0x0280 */ ld [%o3],%o1 ! volatile
/* 0x0284 */ ba L77000033
/* 0x0288 */ st %o1,[%o0] ! volatile
L900000121:
/* 0x028c */ ld [%o3+4],%o2 ! volatile
/* 0x0290 */ st %o1,[%o2] ! volatile
L77000033:
/* 0x0294 */ ld [%o0+8],%o1 ! volatile
/* 0x0298 44 */ cmp %o3,%l2
/* 0x029c 43 */ add %o1,-1,%o1
/* 0x02a0 */ st %o1,[%o0+8] ! volatile
L900000119:
/* 0x02a4 44 */ bne,a L900000122
/* 0x02a8 */ add %l4,0,%l0
L77000037:
/* 0x02ac 45 */ add %fp,-12,%o0
L900000125:
/* 0x02b0 45 */ ld [%o0],%o3 ! volatile
/* 0x02b4 */ cmp %o3,0
/* 0x02b8 */ be,a L900000123
/* 0x02bc 46 */ cmp %o3,%l3
L77000038:
/* 0x02c0 */ ld [%o0+4],%o1 ! volatile
/* 0x02c4 */ cmp %o1,%o3
/* 0x02c8 */ bne,a L900000124
/* 0x02cc */ ld [%o3+4],%o1 ! volatile
L77000039:
/* 0x02d0 */ ld [%o3+4],%o1 ! volatile
/* 0x02d4 */ ba L77000041
/* 0x02d8 */ st %o1,[%o0+4] ! volatile
L900000122:
/* 0x02dc */ add %l5,%l0,%o0
/* 0x02e0 */ add %l1,116,%o1
/* 0x02e4 */ add %l1,156,%o2
/* 0x02e8 */ call _fprintf,4 ! Result = %g0
/* 0x02ec */ or %g0,44,%o3
/* 0x02f0 */ call _exit,1 ! Result = %g0
/* 0x02f4 */ or %g0,1,%o0
/* 0x02f8 */ ba L900000125
/* 0x02fc 45 */ add %fp,-12,%o0
L900000124:
/* 0x0300 */ ld [%o3],%o2 ! volatile
/* 0x0304 */ st %o1,[%o2+4] ! volatile
L77000041:
/* 0x0308 */ ld [%o0],%o1 ! volatile
/* 0x030c */ cmp %o1,%o3
/* 0x0310 */ bne,a L900000126
/* 0x0314 */ ld [%o3],%o1 ! volatile
L77000042:
/* 0x0318 */ ld [%o3],%o1 ! volatile
/* 0x031c */ ba L77000044
/* 0x0320 */ st %o1,[%o0] ! volatile
L900000126:
/* 0x0324 */ ld [%o3+4],%o2 ! volatile
/* 0x0328 */ st %o1,[%o2] ! volatile
L77000044:
/* 0x032c */ ld [%o0+8],%o1 ! volatile
/* 0x0330 46 */ cmp %o3,%l3
/* 0x0334 45 */ add %o1,-1,%o1
/* 0x0338 */ st %o1,[%o0+8] ! volatile
L900000123:
/* 0x033c 46 */ bne,a L900000127
/* 0x0340 */ add %l4,0,%l0
L77000048:
/* 0x0344 47 */ or %g0,8,%o1
L900000129:
/* 0x0348 47 */ add %fp,-12,%o2
/* 0x034c */ ld [%o1+%o2],%o1 ! volatile
/* 0x0350 */ cmp %o1,0
/* 0x0354 */ bne,a L900000128
/* 0x0358 */ add %l4,0,%l0
L77000050:
/* 0x035c 48 */ add %fp,-12,%o0
L900000130:
/* 0x0360 48 */ st %g0,[%l3] ! volatile
/* 0x0364 */ ld [%o0+4],%o1 ! volatile
/* 0x0368 */ st %o1,[%l3+4] ! volatile
/* 0x036c */ ld [%o0+8],%o2 ! volatile
/* 0x0370 */ cmp %o2,0
/* 0x0374 */ bne L77000051
/* 0x0378 */ or %g0,%l3,%o3
L77000052:
/* 0x037c */ ba L77000053
/* 0x0380 */ st %o3,[%o0] ! volatile
L900000127:
/* 0x0384 */ add %l5,%l0,%o0
/* 0x0388 */ add %l1,172,%o1
/* 0x038c */ add %l1,212,%o2
/* 0x0390 */ call _fprintf,4 ! Result = %g0
/* 0x0394 */ or %g0,46,%o3
/* 0x0398 */ call _exit,1 ! Result = %g0
/* 0x039c */ or %g0,1,%o0
/* 0x03a0 */ ba L900000129
/* 0x03a4 47 */ or %g0,8,%o1
L900000128:
/* 0x03a8 */ add %l5,%l0,%o0
/* 0x03ac */ add %l1,228,%o1
/* 0x03b0 */ add %l1,268,%o2
/* 0x03b4 */ call _fprintf,4 ! Result = %g0
/* 0x03b8 */ or %g0,47,%o3
/* 0x03bc */ call _exit,1 ! Result = %g0
/* 0x03c0 */ or %g0,1,%o0
/* 0x03c4 */ ba L900000130
/* 0x03c8 48 */ add %fp,-12,%o0
L77000051:
/* 0x03cc */ ld [%o0+4],%o1 ! volatile
/* 0x03d0 */ st %o3,[%o1] ! volatile
L77000053:
/* 0x03d4 */ st %o3,[%o0+4] ! volatile
/* 0x03d8 */ ld [%o0+8],%o1 ! volatile
/* 0x03dc */ add %o1,1,%o1
/* 0x03e0 */ st %o1,[%o0+8] ! volatile
/* 0x03e4 49 */ add %fp,-12,%o0
/* 0x03e8 */ st %g0,[%l2] ! volatile
/* 0x03ec */ ld [%o0+4],%o1 ! volatile
/* 0x03f0 */ st %o1,[%l2+4] ! volatile
/* 0x03f4 */ ld [%o0+8],%o2 ! volatile
/* 0x03f8 */ cmp %o2,0
/* 0x03fc */ bne L77000054
/* 0x0400 */ or %g0,%l2,%o3
L77000055:
/* 0x0404 */ ba L77000056
/* 0x0408 */ st %o3,[%o0] ! volatile
L77000054:
/* 0x040c */ ld [%o0+4],%o1 ! volatile
/* 0x0410 */ st %o3,[%o1] ! volatile
L77000056:
/* 0x0414 */ st %o3,[%o0+4] ! volatile
/* 0x0418 50 */ add %fp,-12,%l2
/* 0x041c 49 */ ld [%o0+8],%l0 ! volatile
/* 0x0420 */ add %l0,1,%l0
/* 0x0424 */ st %l0,[%o0+8] ! volatile
/* 0x0428 50 */ call ___0OnwUi,1 ! Result = %o0
/* 0x042c */ or %g0,12,%o0
/* 0x0430 */ orcc %g0,%o0,%o3
/* 0x0434 */ be,a L900000131
/* 0x0438 */ st %g0,[%o3] ! volatile
L77000057:
/* 0x043c */ or %g0,%o3,%o0
/* 0x0440 */ add %l1,284,%o1
/* 0x0444 */ st %g0,[%o0] ! volatile
/* 0x0448 */ st %g0,[%o0+4] ! volatile
/* 0x044c */ st %o1,[%o3+8] ! volatile
/* 0x0450 */ st %g0,[%o3] ! volatile
L900000131:
/* 0x0454 */ ld [%l2+4],%o1 ! volatile
/* 0x0458 */ st %o1,[%o3+4] ! volatile
/* 0x045c */ ld [%l2+8],%o2 ! volatile
/* 0x0460 */ cmp %o2,0
/* 0x0464 */ bne,a L900000132
/* 0x0468 */ ld [%l2+4],%o1 ! volatile
L77000061:
/* 0x046c */ ba L77000062
/* 0x0470 */ st %o3,[%l2] ! volatile
L900000132:
/* 0x0474 */ st %o3,[%o1] ! volatile
L77000062:
/* 0x0478 */ st %o3,[%l2+4] ! volatile
/* 0x047c */ ld [%l2+8],%l0 ! volatile
/* 0x0480 */ add %l0,1,%l0
/* 0x0484 */ st %l0,[%l2+8] ! volatile
/* 0x0488 51 */ call ___0OnwUi,1 ! Result = %o0
/* 0x048c */ or %g0,12,%o0
/* 0x0490 */ orcc %g0,%o0,%o3
/* 0x0494 */ add %fp,-12,%l0
/* 0x0498 */ be,a L900000133
/* 0x049c */ st %g0,[%o3] ! volatile
L77000063:
/* 0x04a0 */ or %g0,%o3,%o0
/* 0x04a4 */ add %l1,286,%o1
/* 0x04a8 */ st %g0,[%o0] ! volatile
/* 0x04ac */ st %g0,[%o0+4] ! volatile
/* 0x04b0 */ st %o1,[%o3+8] ! volatile
/* 0x04b4 */ st %g0,[%o3] ! volatile
L900000133:
/* 0x04b8 */ ld [%l0+4],%o1 ! volatile
/* 0x04bc */ st %o1,[%o3+4] ! volatile
/* 0x04c0 */ ld [%l0+8],%o2 ! volatile
/* 0x04c4 */ cmp %o2,0
/* 0x04c8 */ bne,a L900000134
/* 0x04cc */ ld [%l0+4],%o1 ! volatile
L77000067:
/* 0x04d0 */ ba L77000068
/* 0x04d4 */ st %o3,[%l0] ! volatile
L900000134:
/* 0x04d8 */ st %o3,[%o1] ! volatile
L77000068:
/* 0x04dc */ st %o3,[%l0+4] ! volatile
/* 0x04e0 */ ld [%l0+8],%o1 ! volatile
/* 0x04e4 */ add %o1,1,%o1
/* 0x04e8 */ st %o1,[%l0+8] ! volatile
/* 0x04ec 53 */ add %fp,-20,%l0
/* 0x04f0 */ ba L900000135
/* 0x04f4 */ ld [%l0+4],%o1 ! volatile
L900000136:
/* 0x04f8 */ ld [%o0],%o1 ! volatile
/* 0x04fc */ st %o1,[%l0+4] ! volatile
L77000072:
/* 0x0500 */ ld [%l0+4],%o1 ! volatile
/* 0x0504 */ cmp %o1,0
/* 0x0508 */ be L77000074
/* 0x050c 54 */ add %l1,288,%o0
L77000073:
/* 0x0510 54 */ call _printf,2 ! Result = %g0
/* 0x0514 */ ld [%o1+8],%o1 ! volatile
/* 0x0518 53 */ ld [%l0+4],%o1 ! volatile
L900000135:
/* 0x051c */ cmp %o1,0
/* 0x0520 */ be,a L900000136
/* 0x0524 */ ld [%l0],%o0 ! volatile
L77000070:
/* 0x0528 */ ld [%l0+4],%o1 ! volatile
/* 0x052c */ ld [%o1],%o1 ! volatile
/* 0x0530 */ ba L77000072
/* 0x0534 */ st %o1,[%l0+4] ! volatile
L77000074:
/* 0x0538 57 */ call ___0OnwUi,1 ! Result = %o0
/* 0x053c */ or %g0,20,%o0
/* 0x0540 */ orcc %g0,%o0,%o4
/* 0x0544 */ be L77000077
/* 0x0548 */ or %g0,%o4,%o2
L77000075:
/* 0x054c */ or %g0,%o2,%o0
/* 0x0550 */ add %l1,292,%o1
/* 0x0554 */ st %g0,[%o0] ! volatile
/* 0x0558 */ st %g0,[%o0+4] ! volatile
/* 0x055c */ add %o4,12,%o0
/* 0x0560 */ st %o1,[%o2+8] ! volatile
/* 0x0564 */ st %g0,[%o0] ! volatile
/* 0x0568 */ st %g0,[%o0+4] ! volatile
L77000077:
/* 0x056c 58 */ add %o4,12,%o0
/* 0x0570 */ add %fp,-32,%o3
/* 0x0574 */ st %g0,[%o0] ! volatile
/* 0x0578 */ ld [%o3+4],%o1 ! volatile
/* 0x057c */ st %o1,[%o0+4] ! volatile
/* 0x0580 */ ld [%o3+8],%o2 ! volatile
/* 0x0584 */ cmp %o2,0
/* 0x0588 */ bne,a L900000137
/* 0x058c */ ld [%o3+4],%o1 ! volatile
L77000079:
/* 0x0590 */ ba L77000080
/* 0x0594 */ st %o4,[%o3] ! volatile
L900000137:
/* 0x0598 */ add %o1,12,%o1
/* 0x059c */ st %o4,[%o1] ! volatile
L77000080:
/* 0x05a0 */ st %o4,[%o3+4] ! volatile
/* 0x05a4 59 */ or %g0,20,%o0
/* 0x05a8 58 */ ld [%o3+8],%l0 ! volatile
/* 0x05ac */ add %l0,1,%l0
/* 0x05b0 59 */ call ___0OnwUi,1 ! Result = %o0
/* 0x05b4 58 */ st %l0,[%o3+8] ! volatile
/* 0x05b8 59 */ orcc %g0,%o0,%o4
/* 0x05bc */ be L77000083
/* 0x05c0 */ or %g0,%o4,%o2
L77000081:
/* 0x05c4 */ or %g0,%o2,%o0
/* 0x05c8 */ add %l1,295,%o1
/* 0x05cc */ st %g0,[%o0] ! volatile
/* 0x05d0 */ st %g0,[%o0+4] ! volatile
/* 0x05d4 */ add %o4,12,%o0
/* 0x05d8 */ st %o1,[%o2+8] ! volatile
/* 0x05dc */ st %g0,[%o0] ! volatile
/* 0x05e0 */ st %g0,[%o0+4] ! volatile
L77000083:
/* 0x05e4 60 */ add %o4,12,%o0
/* 0x05e8 */ add %fp,-32,%o3
/* 0x05ec */ st %g0,[%o0] ! volatile
/* 0x05f0 */ ld [%o3+4],%o1 ! volatile
/* 0x05f4 */ st %o1,[%o0+4] ! volatile
/* 0x05f8 */ ld [%o3+8],%o2 ! volatile
/* 0x05fc */ cmp %o2,0
/* 0x0600 */ bne,a L900000138
/* 0x0604 */ ld [%o3+4],%o1 ! volatile
L77000085:
/* 0x0608 */ ba L77000086
/* 0x060c */ st %o4,[%o3] ! volatile
L900000138:
/* 0x0610 */ add %o1,12,%o1
/* 0x0614 */ st %o4,[%o1] ! volatile
L77000086:
/* 0x0618 */ st %o4,[%o3+4] ! volatile
/* 0x061c 62 */ add %fp,-40,%l0
/* 0x0620 60 */ ld [%o3+8],%o1 ! volatile
/* 0x0624 */ add %o1,1,%o1
/* 0x0628 */ st %o1,[%o3+8] ! volatile
/* 0x062c 62 */ ba L900000139
/* 0x0630 */ ld [%l0+4],%o1 ! volatile
L900000140:
/* 0x0634 */ add %o1,12,%o1
/* 0x0638 */ ld [%o1],%o1 ! volatile
/* 0x063c */ st %o1,[%l0+4] ! volatile
L77000090:
/* 0x0640 */ ld [%l0+4],%o1 ! volatile
/* 0x0644 */ cmp %o1,0
/* 0x0648 */ be L77000092
/* 0x064c 63 */ add %l1,300,%o0
L77000091:
/* 0x0650 63 */ call _printf,2 ! Result = %g0
/* 0x0654 */ ld [%o1+8],%o1 ! volatile
/* 0x0658 62 */ ld [%l0+4],%o1 ! volatile
L900000139:
/* 0x065c */ cmp %o1,0
/* 0x0660 */ bne,a L900000140
/* 0x0664 */ ld [%l0+4],%o1 ! volatile
L77000089:
/* 0x0668 */ ld [%l0],%o0 ! volatile
/* 0x066c */ ld [%o0],%o1 ! volatile
/* 0x0670 */ ba L77000090
/* 0x0674 */ st %o1,[%l0+4] ! volatile
L77000092:
/* 0x0678 66 */ add %fp,-20,%o1
/* 0x067c */ add %fp,-12,%o0
/* 0x0680 */ st %g0,[%o1+4] ! volatile
/* 0x0684 67 */ add %fp,-20,%l0
/* 0x0688 66 */ ld [%o1],%o3 ! volatile
/* 0x068c */ ld [%o0],%o1 ! volatile
/* 0x0690 */ st %o1,[%o3] ! volatile
/* 0x0694 */ ld [%o0+4],%o2 ! volatile
/* 0x0698 */ st %o2,[%o3+4] ! volatile
/* 0x069c */ ld [%o0+8],%o1 ! volatile
/* 0x06a0 */ st %o1,[%o3+8] ! volatile
/* 0x06a4 67 */ ba L900000141
/* 0x06a8 */ ld [%l0+4],%o1 ! volatile
L900000142:
/* 0x06ac */ ld [%o0],%o1 ! volatile
/* 0x06b0 */ st %o1,[%l0+4] ! volatile
L77000096:
/* 0x06b4 */ ld [%l0+4],%o1 ! volatile
/* 0x06b8 */ cmp %o1,0
/* 0x06bc */ be L77000099
/* 0x06c0 68 */ add %l1,304,%o0
L77000097:
/* 0x06c4 68 */ call _printf,2 ! Result = %g0
/* 0x06c8 */ ld [%o1+8],%o1 ! volatile
/* 0x06cc 67 */ ld [%l0+4],%o1 ! volatile
L900000141:
/* 0x06d0 */ cmp %o1,0
/* 0x06d4 */ be,a L900000142
/* 0x06d8 */ ld [%l0],%o0 ! volatile
L77000094:
/* 0x06dc */ ld [%l0+4],%o1 ! volatile
/* 0x06e0 */ ld [%o1],%o1 ! volatile
/* 0x06e4 */ ba L77000096
/* 0x06e8 */ st %o1,[%l0+4] ! volatile
/* 0x06ec 0 */ unimp 65536
! Begin Disassembling Stabs
.stabs "ptf;ptx;ptk;Xa;O;s;V=3.0;R=<<C++4.0.1 (ccfe 1.0) 7/13/94>>",60,0,0,0 ! (/tmp/ccfe.20405.1.s:1)
.stabs "/tmp_mnt/home/lear1/hill/epics/base/src/cas/; /usr/lang//SC3.0.1/bin/CC -O -S -I. tsDLListTest.cc",52,0,0,0 ! (/tmp/ccfe.20405.1.s:2)
! End Disassembling Stabs
! Begin Disassembling Ident
! End Disassembling Ident

View File

@@ -0,0 +1,62 @@
#include <tsSLList.h>
#include <assert.h>
#include <time.h>
class fred : public tsSLNode<fred> {
public:
fred() : count(0) {}
void inc () {count++;}
private:
unsigned count;
};
class jane : public fred, public tsSLNode<jane> {
public:
jane() {}
private:
};
#define LOOPCOUNT 100000
main ()
{
tsSLList<fred> list;
tsSLIter<fred> iter(list);
fred *pFred;
unsigned i;
clock_t clk;
clock_t diff;
double delay;
for (i=0; i<LOOPCOUNT; i++) {
pFred = new fred();
list.add(*pFred);
}
clk = clock();
iter = list;
while (pFred = iter()) {
pFred->inc();
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10lf\n", delay);
pFred = new fred();
clk = clock();
iter = list;
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10lf\n", delay);
}

View File

@@ -0,0 +1,67 @@
#include <tsSLList.h>
#include <assert.h>
class fred : public tsSLNode<fred> {
public:
fred(const char * const pNameIn) : pName(pNameIn){}
void show () {printf("%s\n", pName);}
private:
const char * const pName;
};
class jane : public fred, public tsSLNode<jane> {
public:
jane(const char * const pNameIn) : fred(pNameIn){}
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");
pFredII = new fred("B");
list.add(*pFred);
list.add(*pFredII);
pFredBack = list.first();
assert(pFredBack == pFredII);
list.remove(*pFred, *pFredII);
list.add(*pFred);
pFredBack = list.get();
assert (pFredBack == pFred);
pFredBack = list.get();
assert (pFredBack == pFredII);
list.add(*pFred);
list.add(*pFredII);
list.add(* new fred("C"));
list.add(* new fred("D"));
while (pFredBack = iter()) {
pFredBack->show();
}
pJane = new jane("JA");
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
while (pJane = janeIter()) {
pJane->show();
}
while (pFredBack = iter()) {
pFredBack->show();
}
}