ca server installation
This commit is contained in:
26
src/cas/.ftp
Normal file
26
src/cas/.ftp
Normal 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
11
src/cas/.ftp2
Normal 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
21
src/cas/Makefile
Normal 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
62
src/cas/Makefile.Unix
Normal 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
29
src/cas/README
Normal 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
21
src/cas/build/Makefile
Normal 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
|
||||
|
||||
|
||||
78
src/cas/build/multiThread/Makefile.Unix
Normal file
78
src/cas/build/multiThread/Makefile.Unix
Normal 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
|
||||
|
||||
19
src/cas/build/singleThread/Makefile
Normal file
19
src/cas/build/singleThread/Makefile
Normal 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
|
||||
|
||||
|
||||
86
src/cas/build/singleThread/Makefile.Unix
Normal file
86
src/cas/build/singleThread/Makefile.Unix
Normal 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
18
src/cas/example/Makefile
Normal 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
|
||||
|
||||
92
src/cas/example/Makefile.Unix
Normal file
92
src/cas/example/Makefile.Unix
Normal 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
|
||||
|
||||
93
src/cas/example/exAsyncPV.cc
Normal file
93
src/cas/example/exAsyncPV.cc
Normal 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);
|
||||
}
|
||||
|
||||
7
src/cas/example/exChannel.cc
Normal file
7
src/cas/example/exChannel.cc
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
//
|
||||
// Example EPICS CA server
|
||||
//
|
||||
|
||||
#include <exServer.h>
|
||||
|
||||
353
src/cas/example/exPV.cc
Normal file
353
src/cas/example/exPV.cc
Normal 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
182
src/cas/example/exServer.cc
Normal 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
385
src/cas/example/exServer.h
Normal 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:
|
||||
};
|
||||
|
||||
|
||||
38
src/cas/example/exSyncPV.cc
Normal file
38
src/cas/example/exSyncPV.cc
Normal 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
846
src/cas/example/test.adl
Normal 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
6
src/cas/generic/README
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
this directory contains the generic source for
|
||||
the EPICS ca server
|
||||
|
||||
|
||||
76
src/cas/generic/caCommonDef.h
Normal file
76
src/cas/generic/caCommonDef.h
Normal 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
226
src/cas/generic/caProto.h
Normal 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
141
src/cas/generic/caServer.cc
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
368
src/cas/generic/caServerI.cc
Normal file
368
src/cas/generic/caServerI.cc
Normal 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);
|
||||
}
|
||||
|
||||
137
src/cas/generic/caServerIIL.h
Normal file
137
src/cas/generic/caServerIIL.h
Normal 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
|
||||
|
||||
45
src/cas/generic/casAsyncIO.cc
Normal file
45
src/cas/generic/casAsyncIO.cc
Normal 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;
|
||||
}
|
||||
|
||||
252
src/cas/generic/casAsyncIOI.cc
Normal file
252
src/cas/generic/casAsyncIOI.cc
Normal 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();
|
||||
}
|
||||
|
||||
56
src/cas/generic/casAsyncIOIIL.h
Normal file
56
src/cas/generic/casAsyncIOIIL.h
Normal 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
|
||||
|
||||
50
src/cas/generic/casChanDelEv.cc
Normal file
50
src/cas/generic/casChanDelEv.cc
Normal 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;
|
||||
}
|
||||
|
||||
149
src/cas/generic/casChannel.cc
Normal file
149
src/cas/generic/casChannel.cc
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
174
src/cas/generic/casChannelI.cc
Normal file
174
src/cas/generic/casChannelI.cc
Normal 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();
|
||||
}
|
||||
|
||||
171
src/cas/generic/casChannelIIL.h
Normal file
171
src/cas/generic/casChannelIIL.h
Normal 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
|
||||
|
||||
558
src/cas/generic/casClient.cc
Normal file
558
src/cas/generic/casClient.cc
Normal 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 "?";
|
||||
}
|
||||
|
||||
65
src/cas/generic/casClientIL.h
Normal file
65
src/cas/generic/casClientIL.h
Normal 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
|
||||
|
||||
83
src/cas/generic/casClientMon.cc
Normal file
83
src/cas/generic/casClientMon.cc
Normal 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;
|
||||
}
|
||||
|
||||
228
src/cas/generic/casCoreClient.cc
Normal file
228
src/cas/generic/casCoreClient.cc
Normal 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);
|
||||
}
|
||||
|
||||
289
src/cas/generic/casDGClient.cc
Normal file
289
src/cas/generic/casDGClient.cc
Normal 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)
|
||||
//
|
||||
}
|
||||
|
||||
157
src/cas/generic/casEventMask.cc
Normal file
157
src/cas/generic/casEventMask.cc
Normal 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);
|
||||
}
|
||||
|
||||
166
src/cas/generic/casEventMask.h
Normal file
166
src/cas/generic/casEventMask.h
Normal 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 ®, 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 ®, 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
|
||||
|
||||
170
src/cas/generic/casEventSys.cc
Normal file
170
src/cas/generic/casEventSys.cc
Normal 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;
|
||||
}
|
||||
|
||||
68
src/cas/generic/casEventSysIL.h
Normal file
68
src/cas/generic/casEventSysIL.h
Normal 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
|
||||
|
||||
587
src/cas/generic/casInternal.h
Normal file
587
src/cas/generic/casInternal.h
Normal 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;
|
||||
};
|
||||
|
||||
120
src/cas/generic/casMonEvent.cc
Normal file
120
src/cas/generic/casMonEvent.cc
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
47
src/cas/generic/casMonEventIL.h
Normal file
47
src/cas/generic/casMonEventIL.h
Normal 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
|
||||
|
||||
284
src/cas/generic/casMonitor.cc
Normal file
284
src/cas/generic/casMonitor.cc
Normal 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
115
src/cas/generic/casMsgIO.cc
Normal 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
168
src/cas/generic/casPV.cc
Normal 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
181
src/cas/generic/casPVI.cc
Normal 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
160
src/cas/generic/casPVIIL.h
Normal 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
|
||||
|
||||
|
||||
|
||||
62
src/cas/generic/casPVListChanIL.h
Normal file
62
src/cas/generic/casPVListChanIL.h
Normal 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
|
||||
|
||||
1725
src/cas/generic/casStrmClient.cc
Normal file
1725
src/cas/generic/casStrmClient.cc
Normal file
File diff suppressed because it is too large
Load Diff
557
src/cas/generic/casdef.h
Normal file
557
src/cas/generic/casdef.h
Normal 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) */
|
||||
|
||||
229
src/cas/generic/gddAppFuncTable.h
Normal file
229
src/cas/generic/gddAppFuncTable.h
Normal 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
135
src/cas/generic/inBuf.cc
Normal 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
171
src/cas/generic/osiTimer.cc
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
172
src/cas/generic/osiTimerQueue.cc
Normal file
172
src/cas/generic/osiTimerQueue.cc
Normal 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
234
src/cas/generic/outBuf.cc
Normal 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
995
src/cas/generic/server.h
Normal 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*/
|
||||
|
||||
|
||||
6
src/cas/io/bsdSocket/README
Normal file
6
src/cas/io/bsdSocket/README
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
this directory contains the bsd socket dependent source for
|
||||
the EPICS ca server
|
||||
|
||||
|
||||
217
src/cas/io/bsdSocket/caServerIO.cc
Normal file
217
src/cas/io/bsdSocket/caServerIO.cc
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
398
src/cas/io/bsdSocket/casDGIO.cc
Normal file
398
src/cas/io/bsdSocket/casDGIO.cc
Normal 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;
|
||||
}
|
||||
|
||||
155
src/cas/io/bsdSocket/casIOD.h
Normal file
155
src/cas/io/bsdSocket/casIOD.h
Normal 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
|
||||
|
||||
382
src/cas/io/bsdSocket/casStreamIO.cc
Normal file
382
src/cas/io/bsdSocket/casStreamIO.cc
Normal 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;
|
||||
}
|
||||
|
||||
51
src/cas/io/bsdSocket/sigPipeIgnore.c
Normal file
51
src/cas/io/bsdSocket/sigPipeIgnore.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
16
src/cas/io/bsdSocket/sigPipeIgnore.h
Normal file
16
src/cas/io/bsdSocket/sigPipeIgnore.h
Normal 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
6
src/cas/os/posix/README
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
this directory contains the posix os dependent source for
|
||||
the EPICS ca server
|
||||
|
||||
|
||||
113
src/cas/os/posix/caServerOS.cc
Normal file
113
src/cas/os/posix/caServerOS.cc
Normal 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();
|
||||
}
|
||||
|
||||
131
src/cas/os/posix/casClientOS.h
Normal file
131
src/cas/os/posix/casClientOS.h
Normal 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
235
src/cas/os/posix/casDGOS.cc
Normal 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
100
src/cas/os/posix/casOSD.h
Normal 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
|
||||
|
||||
46
src/cas/os/posix/casSpecificOS.h
Normal file
46
src/cas/os/posix/casSpecificOS.h
Normal 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) */
|
||||
|
||||
456
src/cas/os/posix/casStreamOS.cc
Normal file
456
src/cas/os/posix/casStreamOS.cc
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
13
src/cas/os/posix/osiMutex.h
Normal file
13
src/cas/os/posix/osiMutex.h
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
//
|
||||
// osiMutex - OS independent mutex
|
||||
// (NOOP on single threaded OS)
|
||||
//
|
||||
class osiMutex {
|
||||
public:
|
||||
void lock() {};
|
||||
void unlock() {};
|
||||
private:
|
||||
};
|
||||
|
||||
25
src/cas/os/posix/osiTimeOSD.cc
Normal file
25
src/cas/os/posix/osiTimeOSD.cc
Normal 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);
|
||||
}
|
||||
|
||||
7
src/cas/os/posixRT/README
Normal file
7
src/cas/os/posixRT/README
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
WORK IN PROGRESS
|
||||
|
||||
this directory contains the posix RT os dependent source for
|
||||
the EPICS ca server
|
||||
|
||||
|
||||
203
src/cas/os/vms/BUILD_VMS.COM
Normal file
203
src/cas/os/vms/BUILD_VMS.COM
Normal 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
7
src/cas/os/vms/README
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
WORK IN PROGRESS
|
||||
|
||||
this directory contains the vms os dependent source for
|
||||
the EPICS ca server
|
||||
|
||||
|
||||
48
src/cas/os/vms/casSpecificOS.h
Normal file
48
src/cas/os/vms/casSpecificOS.h
Normal 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
3
src/cas/os/vms/login.com
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
set display/create/node=xxxx.atdiv.lanl.gov/trans=tcpip
|
||||
|
||||
266
src/cas/os/vms/mitfp.c
Normal file
266
src/cas/os/vms/mitfp.c
Normal 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
275
src/cas/os/vms/mitfp.cc
Normal 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
8
src/cas/os/vms/mitfp.h
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
double htond(double mit);
|
||||
double ntohd(double ieee);
|
||||
float htonf(float mit);
|
||||
float ntohf(float ieee);
|
||||
|
||||
|
||||
41
src/cas/os/vms/vms_depen.h
Normal file
41
src/cas/os/vms/vms_depen.h
Normal 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*/
|
||||
|
||||
7
src/cas/os/vxWorks/README
Normal file
7
src/cas/os/vxWorks/README
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
WORK IN PROGRESS
|
||||
|
||||
this directory contains the vxWorks os dependent source for
|
||||
the EPICS ca server
|
||||
|
||||
|
||||
659
src/cas/os/vxWorks/vxWorks_depen.c
Normal file
659
src/cas/os/vxWorks/vxWorks_depen.c
Normal 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';
|
||||
}
|
||||
|
||||
659
src/cas/os/vxWorks/vxWorks_depen.cc
Normal file
659
src/cas/os/vxWorks/vxWorks_depen.cc
Normal 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';
|
||||
}
|
||||
|
||||
256
src/cas/os/vxWorks/vxWorks_depen.h
Normal file
256
src/cas/os/vxWorks/vxWorks_depen.h
Normal 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
74
src/cas/test/buckTest.c
Normal 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;
|
||||
}
|
||||
|
||||
65
src/cas/test/gddAppFuncTableTest.cc
Normal file
65
src/cas/test/gddAppFuncTableTest.cc
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
110
src/cas/test/resourceLibTest.cc
Normal file
110
src/cas/test/resourceLibTest.cc
Normal 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;
|
||||
}
|
||||
|
||||
65
src/cas/test/tsDLListBench.cc
Normal file
65
src/cas/test/tsDLListBench.cc
Normal 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);
|
||||
}
|
||||
|
||||
72
src/cas/test/tsDLListTest.cc
Normal file
72
src/cas/test/tsDLListTest.cc
Normal 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
773
src/cas/test/tsDLListTest.s
Normal 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
|
||||
62
src/cas/test/tsSLListBench.cc
Normal file
62
src/cas/test/tsSLListBench.cc
Normal 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);
|
||||
}
|
||||
|
||||
67
src/cas/test/tsSLListTest.cc
Normal file
67
src/cas/test/tsSLListTest.cc
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user