From 4697f951b96458e2182f9069618df7e4de4355a1 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 20 Jun 1996 00:28:19 +0000 Subject: [PATCH] ca server installation --- src/cas/.ftp | 26 + src/cas/.ftp2 | 11 + src/cas/Makefile | 21 + src/cas/Makefile.Unix | 62 + src/cas/README | 29 + src/cas/build/Makefile | 21 + src/cas/build/multiThread/Makefile.Unix | 78 + src/cas/build/singleThread/Makefile | 19 + src/cas/build/singleThread/Makefile.Unix | 86 ++ src/cas/example/Makefile | 18 + src/cas/example/Makefile.Unix | 92 ++ src/cas/example/exAsyncPV.cc | 93 ++ src/cas/example/exChannel.cc | 7 + src/cas/example/exPV.cc | 353 +++++ src/cas/example/exServer.cc | 182 +++ src/cas/example/exServer.h | 385 +++++ src/cas/example/exSyncPV.cc | 38 + src/cas/example/test.adl | 846 +++++++++++ src/cas/generic/README | 6 + src/cas/generic/caCommonDef.h | 76 + src/cas/generic/caProto.h | 226 +++ src/cas/generic/caServer.cc | 141 ++ src/cas/generic/caServerI.cc | 368 +++++ src/cas/generic/caServerIIL.h | 137 ++ src/cas/generic/casAsyncIO.cc | 45 + src/cas/generic/casAsyncIOI.cc | 252 ++++ src/cas/generic/casAsyncIOIIL.h | 56 + src/cas/generic/casChanDelEv.cc | 50 + src/cas/generic/casChannel.cc | 149 ++ src/cas/generic/casChannelI.cc | 174 +++ src/cas/generic/casChannelIIL.h | 171 +++ src/cas/generic/casClient.cc | 558 +++++++ src/cas/generic/casClientIL.h | 65 + src/cas/generic/casClientMon.cc | 83 ++ src/cas/generic/casCoreClient.cc | 228 +++ src/cas/generic/casDGClient.cc | 289 ++++ src/cas/generic/casEventMask.cc | 157 ++ src/cas/generic/casEventMask.h | 166 +++ src/cas/generic/casEventSys.cc | 170 +++ src/cas/generic/casEventSysIL.h | 68 + src/cas/generic/casInternal.h | 587 ++++++++ src/cas/generic/casMonEvent.cc | 120 ++ src/cas/generic/casMonEventIL.h | 47 + src/cas/generic/casMonitor.cc | 284 ++++ src/cas/generic/casMsgIO.cc | 115 ++ src/cas/generic/casPV.cc | 168 +++ src/cas/generic/casPVI.cc | 181 +++ src/cas/generic/casPVIIL.h | 160 ++ src/cas/generic/casPVListChanIL.h | 62 + src/cas/generic/casStrmClient.cc | 1725 ++++++++++++++++++++++ src/cas/generic/casdef.h | 557 +++++++ src/cas/generic/gddAppFuncTable.h | 229 +++ src/cas/generic/inBuf.cc | 135 ++ src/cas/generic/osiTimer.cc | 171 +++ src/cas/generic/osiTimerQueue.cc | 172 +++ src/cas/generic/outBuf.cc | 234 +++ src/cas/generic/server.h | 995 +++++++++++++ src/cas/io/bsdSocket/README | 6 + src/cas/io/bsdSocket/caServerIO.cc | 217 +++ src/cas/io/bsdSocket/casDGIO.cc | 398 +++++ src/cas/io/bsdSocket/casIOD.h | 155 ++ src/cas/io/bsdSocket/casStreamIO.cc | 382 +++++ src/cas/io/bsdSocket/sigPipeIgnore.c | 51 + src/cas/io/bsdSocket/sigPipeIgnore.h | 16 + src/cas/os/posix/README | 6 + src/cas/os/posix/caServerOS.cc | 113 ++ src/cas/os/posix/casClientOS.h | 131 ++ src/cas/os/posix/casDGOS.cc | 235 +++ src/cas/os/posix/casOSD.h | 100 ++ src/cas/os/posix/casSpecificOS.h | 46 + src/cas/os/posix/casStreamOS.cc | 456 ++++++ src/cas/os/posix/osiMutex.h | 13 + src/cas/os/posix/osiTimeOSD.cc | 25 + src/cas/os/posixRT/README | 7 + src/cas/os/vms/BUILD_VMS.COM | 203 +++ src/cas/os/vms/README | 7 + src/cas/os/vms/casSpecificOS.h | 48 + src/cas/os/vms/login.com | 3 + src/cas/os/vms/mitfp.c | 266 ++++ src/cas/os/vms/mitfp.cc | 275 ++++ src/cas/os/vms/mitfp.h | 8 + src/cas/os/vms/vms_depen.h | 41 + src/cas/os/vxWorks/README | 7 + src/cas/os/vxWorks/vxWorks_depen.c | 659 +++++++++ src/cas/os/vxWorks/vxWorks_depen.cc | 659 +++++++++ src/cas/os/vxWorks/vxWorks_depen.h | 256 ++++ src/cas/test/buckTest.c | 74 + src/cas/test/gddAppFuncTableTest.cc | 65 + src/cas/test/resourceLibTest.cc | 110 ++ src/cas/test/tsDLListBench.cc | 65 + src/cas/test/tsDLListTest.cc | 72 + src/cas/test/tsDLListTest.s | 773 ++++++++++ src/cas/test/tsSLListBench.cc | 62 + src/cas/test/tsSLListTest.cc | 67 + 94 files changed, 18021 insertions(+) create mode 100644 src/cas/.ftp create mode 100644 src/cas/.ftp2 create mode 100644 src/cas/Makefile create mode 100644 src/cas/Makefile.Unix create mode 100644 src/cas/README create mode 100644 src/cas/build/Makefile create mode 100644 src/cas/build/multiThread/Makefile.Unix create mode 100644 src/cas/build/singleThread/Makefile create mode 100644 src/cas/build/singleThread/Makefile.Unix create mode 100644 src/cas/example/Makefile create mode 100644 src/cas/example/Makefile.Unix create mode 100644 src/cas/example/exAsyncPV.cc create mode 100644 src/cas/example/exChannel.cc create mode 100644 src/cas/example/exPV.cc create mode 100644 src/cas/example/exServer.cc create mode 100644 src/cas/example/exServer.h create mode 100644 src/cas/example/exSyncPV.cc create mode 100644 src/cas/example/test.adl create mode 100644 src/cas/generic/README create mode 100644 src/cas/generic/caCommonDef.h create mode 100644 src/cas/generic/caProto.h create mode 100644 src/cas/generic/caServer.cc create mode 100644 src/cas/generic/caServerI.cc create mode 100644 src/cas/generic/caServerIIL.h create mode 100644 src/cas/generic/casAsyncIO.cc create mode 100644 src/cas/generic/casAsyncIOI.cc create mode 100644 src/cas/generic/casAsyncIOIIL.h create mode 100644 src/cas/generic/casChanDelEv.cc create mode 100644 src/cas/generic/casChannel.cc create mode 100644 src/cas/generic/casChannelI.cc create mode 100644 src/cas/generic/casChannelIIL.h create mode 100644 src/cas/generic/casClient.cc create mode 100644 src/cas/generic/casClientIL.h create mode 100644 src/cas/generic/casClientMon.cc create mode 100644 src/cas/generic/casCoreClient.cc create mode 100644 src/cas/generic/casDGClient.cc create mode 100644 src/cas/generic/casEventMask.cc create mode 100644 src/cas/generic/casEventMask.h create mode 100644 src/cas/generic/casEventSys.cc create mode 100644 src/cas/generic/casEventSysIL.h create mode 100644 src/cas/generic/casInternal.h create mode 100644 src/cas/generic/casMonEvent.cc create mode 100644 src/cas/generic/casMonEventIL.h create mode 100644 src/cas/generic/casMonitor.cc create mode 100644 src/cas/generic/casMsgIO.cc create mode 100644 src/cas/generic/casPV.cc create mode 100644 src/cas/generic/casPVI.cc create mode 100644 src/cas/generic/casPVIIL.h create mode 100644 src/cas/generic/casPVListChanIL.h create mode 100644 src/cas/generic/casStrmClient.cc create mode 100644 src/cas/generic/casdef.h create mode 100644 src/cas/generic/gddAppFuncTable.h create mode 100644 src/cas/generic/inBuf.cc create mode 100644 src/cas/generic/osiTimer.cc create mode 100644 src/cas/generic/osiTimerQueue.cc create mode 100644 src/cas/generic/outBuf.cc create mode 100644 src/cas/generic/server.h create mode 100644 src/cas/io/bsdSocket/README create mode 100644 src/cas/io/bsdSocket/caServerIO.cc create mode 100644 src/cas/io/bsdSocket/casDGIO.cc create mode 100644 src/cas/io/bsdSocket/casIOD.h create mode 100644 src/cas/io/bsdSocket/casStreamIO.cc create mode 100644 src/cas/io/bsdSocket/sigPipeIgnore.c create mode 100644 src/cas/io/bsdSocket/sigPipeIgnore.h create mode 100644 src/cas/os/posix/README create mode 100644 src/cas/os/posix/caServerOS.cc create mode 100644 src/cas/os/posix/casClientOS.h create mode 100644 src/cas/os/posix/casDGOS.cc create mode 100644 src/cas/os/posix/casOSD.h create mode 100644 src/cas/os/posix/casSpecificOS.h create mode 100644 src/cas/os/posix/casStreamOS.cc create mode 100644 src/cas/os/posix/osiMutex.h create mode 100644 src/cas/os/posix/osiTimeOSD.cc create mode 100644 src/cas/os/posixRT/README create mode 100644 src/cas/os/vms/BUILD_VMS.COM create mode 100644 src/cas/os/vms/README create mode 100644 src/cas/os/vms/casSpecificOS.h create mode 100644 src/cas/os/vms/login.com create mode 100644 src/cas/os/vms/mitfp.c create mode 100644 src/cas/os/vms/mitfp.cc create mode 100644 src/cas/os/vms/mitfp.h create mode 100644 src/cas/os/vms/vms_depen.h create mode 100644 src/cas/os/vxWorks/README create mode 100644 src/cas/os/vxWorks/vxWorks_depen.c create mode 100644 src/cas/os/vxWorks/vxWorks_depen.cc create mode 100644 src/cas/os/vxWorks/vxWorks_depen.h create mode 100644 src/cas/test/buckTest.c create mode 100644 src/cas/test/gddAppFuncTableTest.cc create mode 100644 src/cas/test/resourceLibTest.cc create mode 100644 src/cas/test/tsDLListBench.cc create mode 100644 src/cas/test/tsDLListTest.cc create mode 100644 src/cas/test/tsDLListTest.s create mode 100644 src/cas/test/tsSLListBench.cc create mode 100644 src/cas/test/tsSLListTest.cc diff --git a/src/cas/.ftp b/src/cas/.ftp new file mode 100644 index 000000000..e10d30168 --- /dev/null +++ b/src/cas/.ftp @@ -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 + diff --git a/src/cas/.ftp2 b/src/cas/.ftp2 new file mode 100644 index 000000000..b800dbb26 --- /dev/null +++ b/src/cas/.ftp2 @@ -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 diff --git a/src/cas/Makefile b/src/cas/Makefile new file mode 100644 index 000000000..492d374d7 --- /dev/null +++ b/src/cas/Makefile @@ -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 + + diff --git a/src/cas/Makefile.Unix b/src/cas/Makefile.Unix new file mode 100644 index 000000000..e7e0e96f1 --- /dev/null +++ b/src/cas/Makefile.Unix @@ -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 + diff --git a/src/cas/README b/src/cas/README new file mode 100644 index 000000000..f3451b422 --- /dev/null +++ b/src/cas/README @@ -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 + + diff --git a/src/cas/build/Makefile b/src/cas/build/Makefile new file mode 100644 index 000000000..019f0d2b5 --- /dev/null +++ b/src/cas/build/Makefile @@ -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 + + diff --git a/src/cas/build/multiThread/Makefile.Unix b/src/cas/build/multiThread/Makefile.Unix new file mode 100644 index 000000000..2ebc06003 --- /dev/null +++ b/src/cas/build/multiThread/Makefile.Unix @@ -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 + diff --git a/src/cas/build/singleThread/Makefile b/src/cas/build/singleThread/Makefile new file mode 100644 index 000000000..b0ba1d1f8 --- /dev/null +++ b/src/cas/build/singleThread/Makefile @@ -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 + + diff --git a/src/cas/build/singleThread/Makefile.Unix b/src/cas/build/singleThread/Makefile.Unix new file mode 100644 index 000000000..63c5e90f3 --- /dev/null +++ b/src/cas/build/singleThread/Makefile.Unix @@ -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 + diff --git a/src/cas/example/Makefile b/src/cas/example/Makefile new file mode 100644 index 000000000..eb1b12fe7 --- /dev/null +++ b/src/cas/example/Makefile @@ -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 + diff --git a/src/cas/example/Makefile.Unix b/src/cas/example/Makefile.Unix new file mode 100644 index 000000000..09337344e --- /dev/null +++ b/src/cas/example/Makefile.Unix @@ -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 + diff --git a/src/cas/example/exAsyncPV.cc b/src/cas/example/exAsyncPV.cc new file mode 100644 index 000000000..ce675d95d --- /dev/null +++ b/src/cas/example/exAsyncPV.cc @@ -0,0 +1,93 @@ + +// +// Example EPICS CA server +// + +#include + +// +// 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); +} + diff --git a/src/cas/example/exChannel.cc b/src/cas/example/exChannel.cc new file mode 100644 index 000000000..18802d574 --- /dev/null +++ b/src/cas/example/exChannel.cc @@ -0,0 +1,7 @@ + +// +// Example EPICS CA server +// + +#include + diff --git a/src/cas/example/exPV.cc b/src/cas/example/exPV.cc new file mode 100644 index 000000000..32ac2237d --- /dev/null +++ b/src/cas/example/exPV.cc @@ -0,0 +1,353 @@ +// +// Example EPICS CA server +// + +#include + +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; +} + diff --git a/src/cas/example/exServer.cc b/src/cas/example/exServer.cc new file mode 100644 index 000000000..fde8562c9 --- /dev/null +++ b/src/cas/example/exServer.cc @@ -0,0 +1,182 @@ +// +// fileDescriptorManager.process(delay); +// (the name of the global symbol has leaked in here) +// + +// +// Example EPICS CA server +// + + +#include +#include + +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 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() +{ +} + diff --git a/src/cas/example/exServer.h b/src/cas/example/exServer.h new file mode 100644 index 000000000..4d6c928ea --- /dev/null +++ b/src/cas/example/exServer.h @@ -0,0 +1,385 @@ +// +// Example EPICS CA server +// + +// +// ANSI C +// +#include +#include +#include +#include +#include + +// +// 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 +#include +#include +#include + +#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 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: +}; + + diff --git a/src/cas/example/exSyncPV.cc b/src/cas/example/exSyncPV.cc new file mode 100644 index 000000000..b974aa724 --- /dev/null +++ b/src/cas/example/exSyncPV.cc @@ -0,0 +1,38 @@ + +// +// Example EPICS CA server +// + +#include + +// +// 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); +} + diff --git a/src/cas/example/test.adl b/src/cas/example/test.adl new file mode 100644 index 000000000..709635897 --- /dev/null +++ b/src/cas/example/test.adl @@ -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="" +} +"<>" { + 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" + } +} +"<>" { + 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" + } +} +"<>" { + 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" +} diff --git a/src/cas/generic/README b/src/cas/generic/README new file mode 100644 index 000000000..2c21c9650 --- /dev/null +++ b/src/cas/generic/README @@ -0,0 +1,6 @@ + + +this directory contains the generic source for +the EPICS ca server + + diff --git a/src/cas/generic/caCommonDef.h b/src/cas/generic/caCommonDef.h new file mode 100644 index 000000000..c6ae3c7b5 --- /dev/null +++ b/src/cas/generic/caCommonDef.h @@ -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) */ + diff --git a/src/cas/generic/caProto.h b/src/cas/generic/caProto.h new file mode 100644 index 000000000..592f061fd --- /dev/null +++ b/src/cas/generic/caProto.h @@ -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__ */ + diff --git a/src/cas/generic/caServer.cc b/src/cas/generic/caServer.cc new file mode 100644 index 000000000..f4b06e8e0 --- /dev/null +++ b/src/cas/generic/caServer.cc @@ -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 + +// +// 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; + } +} + diff --git a/src/cas/generic/caServerI.cc b/src/cas/generic/caServerI.cc new file mode 100644 index 000000000..fd5192044 --- /dev/null +++ b/src/cas/generic/caServerI.cc @@ -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 + +VERSIONID(casAccessc,"%W% %G%") + + +// +// caServerI::show() +// +void caServerI::show (unsigned level) +{ + casStrmClient *pClient; + tsDLIter 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::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::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); +} + diff --git a/src/cas/generic/caServerIIL.h b/src/cas/generic/caServerIIL.h new file mode 100644 index 000000000..2d1357890 --- /dev/null +++ b/src/cas/generic/caServerIIL.h @@ -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::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 + diff --git a/src/cas/generic/casAsyncIO.cc b/src/cas/generic/casAsyncIO.cc new file mode 100644 index 000000000..616f1117a --- /dev/null +++ b/src/cas/generic/casAsyncIO.cc @@ -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 + +// +// casAsyncIO::destroy() +// +void casAsyncIO::destroy() +{ + delete this; +} + diff --git a/src/cas/generic/casAsyncIOI.cc b/src/cas/generic/casAsyncIOI.cc new file mode 100644 index 000000000..ae74d9d41 --- /dev/null +++ b/src/cas/generic/casAsyncIOI.cc @@ -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 +#include // casAsyncIOI inline func +#include // casChannelI inline func +#include // 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(); +} + diff --git a/src/cas/generic/casAsyncIOIIL.h b/src/cas/generic/casAsyncIOIIL.h new file mode 100644 index 000000000..cd6ca1bb3 --- /dev/null +++ b/src/cas/generic/casAsyncIOIIL.h @@ -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 + diff --git a/src/cas/generic/casChanDelEv.cc b/src/cas/generic/casChanDelEv.cc new file mode 100644 index 000000000..a129c1c9c --- /dev/null +++ b/src/cas/generic/casChanDelEv.cc @@ -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 + +// +// casChanDelEv() +// +caStatus casChanDelEv::cbFunc(casEventSys &eSys) +{ + caStatus status; + status = eSys.getCoreClient().disconnectChan(this->id); + if (status == S_cas_success) { + delete this; + } + return status; +} + diff --git a/src/cas/generic/casChannel.cc b/src/cas/generic/casChannel.cc new file mode 100644 index 000000000..f9aa5e990 --- /dev/null +++ b/src/cas/generic/casChannel.cc @@ -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 +#include // casChannelI inline func +#include // 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; +} + + diff --git a/src/cas/generic/casChannelI.cc b/src/cas/generic/casChannelI.cc new file mode 100644 index 000000000..e804d6c95 --- /dev/null +++ b/src/cas/generic/casChannelI.cc @@ -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 +#include // casEventSys inline func +#include // 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 iterIO(this->ioInProgList); + casMonitor *pMonitor; + tsDLIter 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 iter(this->monitorList); + + this->lock(); + while ( (pMon=iter()) ) { + pMon->postIfModified(); + } + this->unlock(); +} + + +// +// casChannelI::show() +// +void casChannelI::show(unsigned level) +{ + casMonitor *pMon; + tsDLIter 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(); +} + diff --git a/src/cas/generic/casChannelIIL.h b/src/cas/generic/casChannelIIL.h new file mode 100644 index 000000000..fd17e1618 --- /dev/null +++ b/src/cas/generic/casChannelIIL.h @@ -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 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 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 // 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 + diff --git a/src/cas/generic/casClient.cc b/src/cas/generic/casClient.cc new file mode 100644 index 000000000..ad492aa1a --- /dev/null +++ b/src/cas/generic/casClient.cc @@ -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 +#include // 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 "?"; +} + diff --git a/src/cas/generic/casClientIL.h b/src/cas/generic/casClientIL.h new file mode 100644 index 000000000..1a0fc2330 --- /dev/null +++ b/src/cas/generic/casClientIL.h @@ -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 // 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 + diff --git a/src/cas/generic/casClientMon.cc b/src/cas/generic/casClientMon.cc new file mode 100644 index 000000000..a3d5f1c22 --- /dev/null +++ b/src/cas/generic/casClientMon.cc @@ -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 + +#include + + +// +// 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; +} + diff --git a/src/cas/generic/casCoreClient.cc b/src/cas/generic/casCoreClient.cc new file mode 100644 index 000000000..e3c8f5716 --- /dev/null +++ b/src/cas/generic/casCoreClient.cc @@ -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 +#include + +// +// 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 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); +} + diff --git a/src/cas/generic/casDGClient.cc b/src/cas/generic/casDGClient.cc new file mode 100644 index 000000000..201545719 --- /dev/null +++ b/src/cas/generic/casDGClient.cc @@ -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 +#include // caServerI inline func +#include // casClient inline func +#include + +// +// 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) + // +} + diff --git a/src/cas/generic/casEventMask.cc b/src/cas/generic/casEventMask.cc new file mode 100644 index 000000000..24dbbb8e5 --- /dev/null +++ b/src/cas/generic/casEventMask.cc @@ -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 +#include +#include + +#include +#include + +#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 ::show(level); +} + diff --git a/src/cas/generic/casEventMask.h b/src/cas/generic/casEventMask.h new file mode 100644 index 000000000..d832e1e0b --- /dev/null +++ b/src/cas/generic/casEventMask.h @@ -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 + + +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, + 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 { +public: + casEventRegistry() : allocator(0) + { + int status; + status = this->resTable ::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 + diff --git a/src/cas/generic/casEventSys.cc b/src/cas/generic/casEventSys.cc new file mode 100644 index 000000000..10b70f462 --- /dev/null +++ b/src/cas/generic/casEventSys.cc @@ -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 + +/* + * EPICS + */ +#include +#include // casMonitor inline func + +#if 0 +VERSIONID(caEventQueuec,"%W% %G%") +#endif + +#if 0 +#include +#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; +} + diff --git a/src/cas/generic/casEventSysIL.h b/src/cas/generic/casEventSysIL.h new file mode 100644 index 000000000..43631edc9 --- /dev/null +++ b/src/cas/generic/casEventSysIL.h @@ -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 + diff --git a/src/cas/generic/casInternal.h b/src/cas/generic/casInternal.h new file mode 100644 index 000000000..aafc29c0e --- /dev/null +++ b/src/cas/generic/casInternal.h @@ -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 +#include +#include + +typedef aitUint32 caResId; + +class casEventSys; +class casChannelI; + +// +// casEvent +// +class casEvent : public tsDLNode { +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 +{ +public: + virtual ~casRes() {} + virtual casResType resourceType() const = 0; + virtual void show (unsigned level) = 0; +private: +}; + +// +// ioBlocked +// +class ioBlocked : public tsDLNode { +friend class ioBlockedList; +public: + ioBlocked (); + virtual ~ioBlocked (); + void setBlocked (ioBlockedList &list); +private: + ioBlockedList *pList; + virtual void ioBlockedSignal () = 0; +}; + +// +// ioBlockedList +// +class ioBlockedList : public tsDLList { +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 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, 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 { +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, 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 monitorList; + tsDLList 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 +{ +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, // 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 chanList; + caServerI &cas; + unsigned nMonAttached; + unsigned nIOAttached; +}; + diff --git a/src/cas/generic/casMonEvent.cc b/src/cas/generic/casMonEvent.cc new file mode 100644 index 000000000..b25b6dc3f --- /dev/null +++ b/src/cas/generic/casMonEvent.cc @@ -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 +#include + +// +// 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(); +} + + diff --git a/src/cas/generic/casMonEventIL.h b/src/cas/generic/casMonEventIL.h new file mode 100644 index 000000000..f8988ecce --- /dev/null +++ b/src/cas/generic/casMonEventIL.h @@ -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 + diff --git a/src/cas/generic/casMonitor.cc b/src/cas/generic/casMonitor.cc new file mode 100644 index 000000000..95ffbf167 --- /dev/null +++ b/src/cas/generic/casMonitor.cc @@ -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 +#include // casChannelI inline func +#include // casEventSys inline func +#include // 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(); +} + diff --git a/src/cas/generic/casMsgIO.cc b/src/cas/generic/casMsgIO.cc new file mode 100644 index 000000000..b2e31ad22 --- /dev/null +++ b/src/cas/generic/casMsgIO.cc @@ -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 + +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; +} + diff --git a/src/cas/generic/casPV.cc b/src/cas/generic/casPV.cc new file mode 100644 index 000000000..1cb968e2a --- /dev/null +++ b/src/cas/generic/casPV.cc @@ -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 +#include // 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(); +} + diff --git a/src/cas/generic/casPVI.cc b/src/cas/generic/casPVI.cc new file mode 100644 index 000000000..675eaf687 --- /dev/null +++ b/src/cas/generic/casPVI.cc @@ -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 +#include // casPVI inline func +#include // 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 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(); +} + diff --git a/src/cas/generic/casPVIIL.h b/src/cas/generic/casPVIIL.h new file mode 100644 index 000000000..5f07d55b2 --- /dev/null +++ b/src/cas/generic/casPVIIL.h @@ -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 // 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 iter(this->chanList); + while ( (pChan = iter()) ) { + pChan->postEvent(select, event); + } +} + +#endif // casPVIIL_h + + + diff --git a/src/cas/generic/casPVListChanIL.h b/src/cas/generic/casPVListChanIL.h new file mode 100644 index 000000000..16ab38ae7 --- /dev/null +++ b/src/cas/generic/casPVListChanIL.h @@ -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 + diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc new file mode 100644 index 000000000..5b2c9120e --- /dev/null +++ b/src/cas/generic/casStrmClient.cc @@ -0,0 +1,1725 @@ +/* + * $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 +#include // caServerI inline functions +#include // casClient inline functions +#include // casChannelI inline functions +#include // casPVI inline functions +#include + +VERSIONID(casStrmClientcc,"%W% %G%") + +static const caHdr nill_msg = {0u,0u,0u,0u,0u,0u}; + +// +// casStrmClient::verifyRequest() +// +inline caStatus casStrmClient::verifyRequest (casChannelI *&pChan) +{ + const caHdr *mp = this->ctx.getMsg(); + + // + // channel exists for this resource id ? + // + pChan = this->resIdToChannel(mp->m_cid); + if (!pChan) { + return this->sendErr(mp, ECA_BADCHID, NULL); + } + + // + // data type out of range ? + // + if (mp->m_type>((unsigned)LAST_BUFFER_TYPE)) { + return this->sendErr(mp, ECA_BADTYPE, NULL); + } + + // + // element count out of range ? + // + if (mp->m_count> pChan->getPVI().nativeCount()) { + return this->sendErr(mp, ECA_BADCOUNT, NULL); + } + + // + // If too many IO operations are in progress against this pv + // then we will need to wait until later to initiate this + // request. + // + if (pChan->getIOOPSInProgress() >= + pChan->getPVI()->maxSimultAsyncOps()) { + this->ioBlocked::setBlocked (pChan->getPVI()); + return S_cas_ioBlocked; + } + + return S_cas_validRequest; +} + + +// +// casStrmClient::createChannel() +// +inline caStatus casStrmClient::createChannel (const char *pName) +{ + caStatus status; + int gddStatus; + gdd *pCanonicalName; + +// set correct appl type here !!!! + pCanonicalName = new gddAtomic(0u, aitEnumString, 1u); + if (!pCanonicalName) { + return S_cas_noMemory; + } + + /* + * Verify that the server still has this channel + * and that we have its correct official name. + * I assume that we may have found this server by + * contacting a name resolution service so we need to + * verify that the specified channel still exists here. + */ + status = this->ctx.getServer()->pvExistTest( + this->ctx, pName, *pCanonicalName); + if (status == S_casApp_asyncCompletion) { + status = S_cas_success; + } + else if (status == S_cas_ioBlocked) { + this->ioBlocked::setBlocked (this->getCAS()); + } + else { + status = createChanResponse (NULL, *this->ctx.getMsg(), + pCanonicalName, status); + } + gddStatus = pCanonicalName->Unreference (); + assert (!gddStatus); + return status; +} + + + +// +// casStrmClient::casStrmClient() +// +casStrmClient::casStrmClient(caServerI &serverInternal, casMsgIO &ioIn) : + casClient(serverInternal, ioIn) +{ + assert(&ioIn); + this->ctx.getServer()->installClient(this); + + this->pUserName = NULL; + this->pHostName = NULL; + this->ioBlockCache = NULL; +} + +// +// casStrmClient::init() +// +caStatus casStrmClient::init() +{ + caStatus status; + + status = casClient::init(); + if (status) { + return status; + } + + this->pHostName = new char [1u]; + if (!this->pHostName) { + return S_cas_noMemory; + } + *this->pHostName = '\0'; + + this->pUserName = new char [1u]; + if (!this->pUserName) { + return S_cas_noMemory; + } + *this->pUserName= '\0'; + + return this->start(); +} + + +// +// casStrmClient::~casStrmClient() +// +casStrmClient::~casStrmClient() +{ + casChannelI *pChan; + casChannelI *pNextChan; + tsDLIter iter(this->chanList); + + // + // remove this from the list of connected clients + // + this->ctx.getServer()->removeClient(this); + + if (this->pUserName) { + delete [] this->pUserName; + } + + if (this->pHostName) { + delete [] this->pHostName; + } + + this->lock(); + + // + // delete all channel attached + // + pChan = iter(); + while (pChan) { + // + // destroying the channel removes it from the list + // + pNextChan = iter(); + pChan->clientDestroy(); + pChan = pNextChan; + } +} + +// +// find the monitor associated with a resource id +// +inline casClientMon *caServerI::resIdToClientMon(const caResId &idIn) +{ + casRes *pRes; + + pRes = this->lookupRes(idIn, casClientMonT); + // + // cast is ok since the type code was verified + // (and we know casClientMon derived from resource) + // + return (casClientMon *) pRes; +} + + +// +// casStrmClient::show (unsigned level) +// +void casStrmClient::show (unsigned level) +{ + this->casClient::show (level); + printf ("casStrmClient at %x\n", (unsigned) this); + if (level > 1u) { + printf ("\tuser %s at %s\n", this->pUserName, this->pHostName); + } +} + + +/* + * casStrmClient::readAction() + */ +caStatus casStrmClient::readAction () +{ + const caHdr *mp = this->ctx.getMsg(); + caStatus status; + casChannelI *pChan; + gdd *pDesc; + + status = this->verifyRequest (pChan); + if (status != S_cas_validRequest) { + return status; + } + + /* + * verify read access + */ + if ((*pChan)->readAccess()!=aitTrue) { + int v41; + + v41 = CA_V41(CA_PROTOCOL_VERSION,this->minor_version_number); + if(v41){ + status = ECA_NORDACCESS; + } + else{ + status = ECA_GETFAIL; + } + + return this->sendErr(mp, status, "read access denied"); + } + + pDesc = NULL; + status = this->read(pDesc); + if (status==S_casApp_success && pDesc) { + status = this->readResponse(pChan, *mp, pDesc, S_cas_success); + } + else if (status == S_casApp_asyncCompletion) { + status = S_cas_success; + } + else { + status = this->sendErrWithEpicsStatus(mp, status, ECA_GETFAIL); + } + + if (pDesc) { + int gddStatus; + + gddStatus = pDesc->Unreference(); + assert(gddStatus==0); + } + + return status; +} + + + +// +// casStrmClient::readResponse() +// +caStatus casStrmClient::readResponse (casChannelI *pChan, const caHdr &msg, + gdd *pDesc, const caStatus status) +{ + caHdr *reply; + unsigned size; + int localStatus; + int strcnt; + + if (status!=S_casApp_success) { + return this->sendErrWithEpicsStatus(&msg, status, ECA_GETFAIL); + } + + // + // must have a descriptor if status is S_casApp_success + // + else if (!pDesc) { + return this->sendErrWithEpicsStatus(&msg, + S_cas_badParameter, ECA_GETFAIL); + } + + size = dbr_size_n (msg.m_type, msg.m_count); + localStatus = this->allocMsg(size, &reply); + if (localStatus) { + if (localStatus==S_cas_hugeRequest) { + localStatus = sendErr(&msg, ECA_TOLARGE, NULL); + } + return localStatus; + } + + // + // setup response message + // + *reply = msg; + reply->m_postsize = size; + reply->m_cid = pChan->getCID(); + + // + // convert gdd to db_access type + // (places the data in network format) + // + gddMapDbr[msg.m_type].conv_dbr((reply+1), pDesc); + + // + // force string message size to be the true size rounded to even + // boundary + // + if (msg.m_type == DBR_STRING && msg.m_count == 1u) { + /* add 1 so that the string terminator will be shipped */ + strcnt = strlen((char *)(reply + 1u)) + 1u; + reply->m_postsize = strcnt; + } + + this->commitMsg (); + + return localStatus; +} + + +// +// casStrmClient::readNotifyAction() +// +caStatus casStrmClient::readNotifyAction () +{ + const caHdr *mp = this->ctx.getMsg(); + int status; + casChannelI *pChan; + gdd *pDesc; + + status = this->verifyRequest (pChan); + if (status != S_cas_validRequest) { + return status; + } + + // + // verify read access + // + if ((*pChan)->readAccess()!=aitTrue) { + return this->readNotifyResponse(pChan, *mp, NULL, S_cas_noRead); + } + + pDesc = NULL; + status = this->read(pDesc); + if (status == S_casApp_asyncCompletion) { + status = S_cas_success; + } + else { + status = this->readNotifyResponse(pChan, *mp, pDesc, status); + } + + if (pDesc) { + int gddStatus; + gddStatus = pDesc->Unreference(); + assert(gddStatus==0); + } + + return status; +} + + + +// +// casStrmClient::readNotifyResponse() +// +caStatus casStrmClient::readNotifyResponse (casChannelI *, + const caHdr &msg, gdd *pDesc, const caStatus completionStatus) +{ + caHdr *reply; + unsigned size; + caStatus status; + int strcnt; + + size = dbr_size_n (msg.m_type, msg.m_count); + status = this->allocMsg(size, &reply); + if (status) { + if (status==S_cas_hugeRequest) { + // + // All read notify responses must include a buffer of + // the size they specify - otherwise an exception + // is generated + // + status = sendErr(&msg, ECA_TOLARGE, NULL); + } + return status; + } + + // + // setup response message + // + *reply = msg; + reply->m_postsize = size; + + // + // cid field abused to store the status here + // + if (completionStatus == S_cas_success) { + if (pDesc) { + // + // convert gdd to db_access type + // (places the data in network format) + // + gddMapDbr[msg.m_type].conv_dbr((reply+1), pDesc); + reply->m_cid = ECA_NORMAL; + } + else { + errMessage(S_cas_badParameter, + "because no data in server tool asynch read resp"); + reply->m_cid = ECA_GETFAIL; + } + } + else if (completionStatus==S_cas_noRead && + CA_V41(CA_PROTOCOL_VERSION,this->minor_version_number)) { + reply->m_cid = ECA_NORDACCESS; + } + else { + errMessage(completionStatus, + "for call back asynch completion"); + reply->m_cid = ECA_GETFAIL; + } + + // + // If they return non-zero status or a nill gdd ptr + // + if (reply->m_cid != ECA_NORMAL) { + // + // If the operation failed clear the response data + // area + // + memset ((char *)(reply+1), '\0', size); + } + + // + // force string message size to be the true size rounded to even + // boundary + // + if (msg.m_type == DBR_STRING && msg.m_count == 1u) { + /* add 1 so that the string terminator will be shipped */ + strcnt = strlen((char *)(reply + 1u)) + 1u; + reply->m_postsize = strcnt; + } + + this->commitMsg (); + + return S_cas_success; +} + + +// +// casStrmClient::monitorResponse() +// +caStatus casStrmClient::monitorResponse (casChannelI *pChan, + const caHdr &msg, gdd *pDesc, const caStatus completionStatus) +{ + caStatus completionStatusCopy = completionStatus; + caHdr *pReply; + unsigned size; + caStatus status; + int strcnt; + gdd *pDBRDD; + gddStatus gdds; + + // + // verify read access + // + if (!(*pChan)->readAccess()) { + completionStatusCopy = S_cas_noRead; + } + + size = dbr_size_n (msg.m_type, msg.m_count); + status = this->allocMsg(size, &pReply); + if (status) { + if (status==S_cas_hugeRequest) { + // + // If we cant includ the data it is a proto + // violation - so we generate an exception + // instead + // + status = sendErr(&msg, ECA_TOLARGE, + "unable to xmit enevt info"); + } + return status; + } + + // + // setup response message + // + *pReply = msg; + pReply->m_postsize = size; + + // + // cid field abused to store the status here + // + if (completionStatusCopy == S_cas_success) { + if (pDesc) { + + status = createDBRDD(msg.m_type, msg.m_count, pDBRDD); + if (status != S_cas_success) { + pDBRDD = NULL; + completionStatusCopy = status; + } + else { + gdds = gddApplicationTypeTable:: + app_table.SmartCopy(pDBRDD, pDesc); + if (gdds) { + errPrintf (status, __FILE__, __LINE__, +"no conversion between event app type=%d and DBR type=%d Element count=%d", + pDesc->ApplicationType(), + msg.m_type, + msg.m_count); + completionStatusCopy = S_cas_noConvert; + } + } + } + else { + completionStatusCopy = S_cas_badParameter; + } + } + + // + // see no DD and no convert case above + // + if (completionStatusCopy == S_cas_success) { + pReply->m_cid = ECA_NORMAL; + + // + // there appears to be no success/fail + // status from this routine + // + gddMapDbr[msg.m_type].conv_dbr ((pReply+1), pDBRDD); + + // + // force string message size to be the true size + // + if (msg.m_type == DBR_STRING && msg.m_count == 1u) { + // add 1 so that the string terminator + // will be shipped + strcnt = strlen((char *)(pReply + 1u)) + 1u; + pReply->m_postsize = strcnt; + } + } + else { + errMessage(completionStatusCopy, "monitor response"); + if (completionStatusCopy== S_cas_noRead) { + pReply->m_cid = ECA_NORDACCESS; + } + else { + pReply->m_cid = ECA_GETFAIL; + } + + // + // If the operation failed clear the response data + // area + // + memset ((char *)(pReply+1u), '\0', size); + } + + this->commitMsg (); + + if (pDBRDD) { + pDBRDD->Unreference(); + } + + return S_cas_success; +} + + + +/* + * casStrmClient::writeAction() + */ +caStatus casStrmClient::writeAction() +{ + const caHdr *mp = this->ctx.getMsg(); + caStatus status; + casChannelI *pChan; + + status = this->verifyRequest (pChan); + if (status != S_cas_validRequest) { + return status; + } + + // + // verify write access + // + if ((*pChan)->writeAccess()!=aitTrue) { + int v41; + + v41 = CA_V41(CA_PROTOCOL_VERSION,this->minor_version_number); + if (v41) { + status = ECA_NOWTACCESS; + } + else{ + status = ECA_PUTFAIL; + } + + return this->sendErr(mp, status, "write access denied"); + } + + // + // initiate the write operation + // + status = this->write(); + if (status==S_casApp_success) { + status = S_cas_success; + } + else if (status == S_casApp_asyncCompletion) { + status = S_cas_success; + } + else { + status = this->sendErrWithEpicsStatus(mp, status, ECA_PUTFAIL); + // + // I have assumed that the server tool has deleted the gdd here + // + } + + // + // The gdd created above is deleted by the server tool + // + + return status; + +} + + +// +// casStrmClient::writeResponse() +// +caStatus casStrmClient::writeResponse (casChannelI *, + const caHdr &msg, gdd *pDesc, const caStatus completionStatus) +{ + caStatus status; + + if (pDesc) { + errMessage(S_cas_badParameter, + "didnt expect a data descriptor from asynch write"); + } + + if (completionStatus) { + errMessage(completionStatus, NULL); + status = this->sendErrWithEpicsStatus(&msg, + completionStatus, ECA_PUTFAIL); + } + else { + status = S_cas_success; + } + + return status; +} + + +/* + * casStrmClient::writeNotifyAction() + */ +caStatus casStrmClient::writeNotifyAction() +{ + const caHdr *mp = this->ctx.getMsg(); + int status; + casChannelI *pChan; + + status = this->verifyRequest (pChan); + if (status != S_cas_validRequest) { + return status; + } + + // + // verify write access + // + if ((*pChan)->writeAccess()!=aitTrue) { + return casStrmClient::writeNotifyResponse(pChan, *mp, + NULL, S_cas_noWrite); + } + + // + // initiate the write operation + // + status = this->write(); + if (status == S_casApp_asyncCompletion) { + status = S_cas_success; + } + else { + status = casStrmClient::writeNotifyResponse(pChan, *mp, + NULL, status); + } + + return status; +} + + +/* + * casStrmClient::writeNotifyResponse() + */ +caStatus casStrmClient::writeNotifyResponse(casChannelI *, + const caHdr &msg, gdd *pDesc, const caStatus completionStatus) +{ + caHdr *preply; + caStatus opStatus; + + if (pDesc) { + errMessage(S_cas_badParameter, + "didnt expect a data descriptor from asynch write"); + } + + opStatus = this->allocMsg(0u, &preply); + if (opStatus) { + return opStatus; + } + + *preply = msg; + preply->m_postsize = 0u; + if (completionStatus==S_cas_success) { + preply->m_cid = ECA_NORMAL; + } + else if (completionStatus==S_cas_noWrite && + CA_V41(CA_PROTOCOL_VERSION,this->minor_version_number)) { + preply->m_cid = ECA_NOWTACCESS; + } + else { + errMessage(completionStatus, NULL); + preply->m_cid = ECA_PUTFAIL; + } + + /* commit the message */ + this->commitMsg(); + + return S_cas_success; +} + + +/* + * casStrmClient::hostNameAction() + */ +caStatus casStrmClient::hostNameAction() +{ + const caHdr *mp = this->ctx.getMsg(); + char *pName = (char *) this->ctx.getData(); + casChannelI *pciu; + tsDLIter iter(this->chanList); + unsigned size; + char *pMalloc; + + size = strlen(pName)+1u; + /* + * user name will not change if there isnt enough memory + */ + pMalloc = new char [size]; + if(!pMalloc){ + this->sendErr(mp, ECA_ALLOCMEM, pName); + return S_cas_internal; + } + strncpy( + pMalloc, + pName, + size-1); + pMalloc[size-1]='\0'; + + this->lock(); + + if (this->pHostName) { + delete [] this->pHostName; + } + this->pHostName = pMalloc; + + while ( (pciu = iter()) ) { + (*pciu)->setOwner(this->pUserName, this->pHostName); + } + + this->unlock(); + + return S_cas_success; +} + + +/* + * casStrmClient::clientNameAction() + */ +caStatus casStrmClient::clientNameAction() +{ + const caHdr *mp = this->ctx.getMsg(); + char *pName = (char *) this->ctx.getData(); + casChannelI *pciu; + tsDLIter iter(this->chanList); + unsigned size; + char *pMalloc; + + size = strlen(pName)+1; + + /* + * user name will not change if there isnt enough memory + */ + pMalloc = new char [size]; + if(!pMalloc){ + this->sendErr(mp, ECA_ALLOCMEM, pName); + return S_cas_internal; + } + strncpy( + pMalloc, + pName, + size-1); + pMalloc[size-1]='\0'; + + this->lock(); + if (this->pUserName) { + delete [] this->pUserName; + } + this->pUserName = pMalloc; + + while ( (pciu = iter()) ) { + (*pciu)->setOwner(this->pUserName, this->pHostName); + } + this->unlock(); + + return S_cas_success; +} + + + +/* + * casStrmClientMon::claimChannelAction() + */ +caStatus casStrmClient::claimChannelAction() +{ + const caHdr *mp = this->ctx.getMsg(); + char *pName = (char *) this->ctx.getData(); + int status; + unsigned nameLength; + + /* + * The available field is used (abused) + * here to communicate the miner version number + * starting with CA 4.1. The field was set to zero + * prior to 4.1 + */ + this->minor_version_number = mp->m_available; + + // + // We shouldnt be receiving a connect message from + // an R3.11 client because we will not respond to their + // search requests (if so we disconnect) + // + if (!CA_V44(CA_PROTOCOL_VERSION,this->minor_version_number)) { + // + // 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(mp, ECA_DEFUNCT, + "R3.11 connect sequence from old client was ignored"); + return S_cas_badProtocol; // disconnect client + } + + + if (mp->m_postsize == 0u) { + return S_cas_badProtocol; // disconnect client + } + + nameLength = strlen(pName); + if (nameLength>mp->m_postsize) { + return S_cas_badProtocol; // disconnect client + } + + if (nameLength>unreasonablePVNameSize) { + return S_cas_badProtocol; // disconnect client + } + + status = this->createChannel (pName); + if (status == S_casApp_asyncCompletion) { + // + // asynchronous completion + // + status = S_cas_success; + } + return status; +} + + +/* + * casStrmClient::channelCreateFailed() + * + * If we are talking to an CA_V46 client then tell them when a channel + * cant be created (instead of just disconnecting) + */ +caStatus casStrmClient::channelCreateFailed( +const caHdr *mp, +caStatus createStatus) +{ + caStatus status; + caHdr *reply; + + errMessage (createStatus, "- Server unable to create a new PV"); + if (CA_V46(CA_PROTOCOL_VERSION,this->minor_version_number)) { + + status = allocMsg (0u, &reply); + if (status) { + return status; + } + *reply = nill_msg; + reply->m_cmmd = CA_PROTO_CLAIM_CIU_FAILED; + reply->m_cid = mp->m_cid; + this->commitMsg(); + createStatus = S_cas_success; + } + else { + this->sendErrWithEpicsStatus(mp, createStatus, ECA_ALLOCMEM); + } + + return createStatus; +} + + +/* + * casStrmClient::disconnectChan() + * + * If we are talking to an CA_V47 client then tell them when a channel + * was deleted by the server tool + */ +caStatus casStrmClient::disconnectChan(caResId id) +{ + caStatus status; + caStatus createStatus; + caHdr *reply; + + if (CA_V47(CA_PROTOCOL_VERSION,this->minor_version_number)) { + + status = allocMsg (0u, &reply); + if (status) { + return status; + } + *reply = nill_msg; + reply->m_cmmd = CA_PROTO_SERVER_DISCONN; + reply->m_cid = id; + this->commitMsg(); + createStatus = S_cas_success; + } + else { + ca_printf( +"Disconnecting old client when server tool deleted its channel or PV\n"); + createStatus = S_cas_disconnect; + } + + return createStatus; +} + + + +// +// casStrmClient::eventsOnAction() +// +caStatus casStrmClient::eventsOnAction () +{ + casChannelI *pciu; + tsDLIter iter(this->chanList); + + this->setEventsOff(); + + // + // perhaps this is to slow - perhaps there + // should be a queue of modified events + // + this->lock(); + while ( (pciu = iter()) ) { + pciu->postAllModifiedEvents(); + } + this->unlock(); + + return S_cas_success; +} + +// +// casStrmClient::eventsOffAction() +// +caStatus casStrmClient::eventsOffAction() +{ + this->setEventsOn(); + return S_cas_success; +} + + + +// +// eventAddAction() +// +caStatus casStrmClient::eventAddAction () +{ + const caHdr *mp = this->ctx.getMsg(); + struct mon_info *pMonInfo = (struct mon_info *) + this->ctx.getData(); + casClientMon *pMonitor; + casChannelI *pciu; + gdd *pDD; + caStatus status; + casEventMask mask; + + pciu = this->resIdToChannel(mp->m_cid); + if (!pciu) { + logBadId(mp, (void *) pMonInfo); + return S_cas_internal; + } + + if (mp->m_count==0u) { + this->sendErr(mp, ECA_BADCOUNT, "event add request"); + return S_cas_success; + } + + if (pMonInfo->m_mask&DBE_VALUE) { + mask |= this->getCAS().getAdapter()->valueEventMask; + } + + if (pMonInfo->m_mask&DBE_LOG) { + mask |= this->getCAS().getAdapter()->logEventMask; + } + + if (pMonInfo->m_mask&DBE_ALARM) { + mask |= this->getCAS().getAdapter()->alarmEventMask; + } + + if (mask.noEventsSelected()) { + this->sendErr(mp, ECA_BADMASK, "event add request"); + return S_cas_success; + } + + pMonitor = new casClientMon(*pciu, mp->m_available, + mp->m_count, mp->m_type, mask, *this); + if (!pMonitor) { + this->sendErr(mp, ECA_ALLOCMEM, NULL); + return S_cas_internal; + } + + // + // always send immediate monitor response at event add + // + pDD = NULL; + status = this->read(pDD); + if (status == S_casApp_asyncCompletion) { + status = S_cas_success; + } + else { + status = this->monitorResponse (pciu, *mp, pDD, status); + } + + if (pDD) { + int gddStatus; + gddStatus = pDD->Unreference(); + assert(gddStatus==0); + } + + return status; +} + + + +// +// casStrmClient::clearChannelAction() +// +caStatus casStrmClient::clearChannelAction () +{ + const caHdr *mp = this->ctx.getMsg(); + void *dp = this->ctx.getData(); + caHdr *reply; + casChannelI *pciu; + int status; + + /* + * Verify the channel + */ + pciu = this->resIdToChannel (mp->m_cid); + if (!pciu) { + logBadId (mp, dp); + return S_cas_internal; + } + if (&pciu->getClient()!=this) { + logBadId (mp, dp); + return S_cas_internal; + } + + /* + * send delete confirmed message + */ + status = this->allocMsg (0u, &reply); + if (status) { + return status; + } + *reply = *mp; + this->commitMsg (); + + pciu->clientDestroy (); + + return S_cas_success; +} + + + + +// +// casStrmClient::eventCancelAction() +// +caStatus casStrmClient::eventCancelAction() +{ + const caHdr *mp = this->ctx.getMsg(); + void *dp = this->ctx.getData(); + casChannelI *pciu; + caHdr *reply; + casMonitor *pMon; + int status; + + /* + * Verify the channel + */ + pciu = this->resIdToChannel(mp->m_cid); + if (!pciu) { + logBadId(mp, dp); + return S_cas_internal; + } + if (&pciu->getClient()!=this) { + logBadId(mp, dp); + return S_cas_internal; + } + pMon = pciu->findMonitor(mp->m_available); + if (!pMon) { + logBadId(mp, dp); + return S_cas_internal; + } + + /* + * allocate delete confirmed message + */ + status = allocMsg(0u, &reply); + if (status) { + return status; + } + + reply->m_cmmd = CA_PROTO_EVENT_ADD; + reply->m_postsize = 0u; + reply->m_type = pMon->getType(); + reply->m_count = pMon->getCount(); + reply->m_cid = pciu->getCID(); + reply->m_available = pMon->getClientId(); + + this->commitMsg(); + + delete pMon; + + return S_cas_success; +} + + +#if 0 +/* + * casStrmClient::noReadAccessEvent() + * + * substantial complication introduced here by the need for backwards + * compatibility + */ +caStatus casStrmClient::noReadAccessEvent(casClientMon *pMon) +{ + caHdr falseReply; + unsigned size; + caHdr *reply; + int status; + + size = dbr_size_n (pMon->getType(), pMon->getCount()); + + falseReply.m_cmmd = CA_PROTO_EVENT_ADD; + falseReply.m_postsize = size; + falseReply.m_type = pMon->getType(); + falseReply.m_count = pMon->getCount(); + falseReply.m_cid = pMon->getChannel().getCID(); + falseReply.m_available = pMon->getClientId(); + + status = this->allocMsg(size, &reply); + if (status) { + if(status == S_cas_hugeRequest){ + status = this->sendErr(&falseReply, ECA_TOLARGE, NULL); + return status; + } + return status; + } + else{ + /* + * New clients recv the status of the + * operation directly to the + * event/put/get callback. + * + * Fetched value is zerod in case they + * use it even when the status indicates + * failure. + * + * The m_cid field in the protocol + * header is abused to carry the status + */ + *reply = falseReply; + reply->m_postsize = size; + reply->m_cid = ECA_NORDACCESS; + memset((char *)(reply+1), 0, size); + this->commitMsg(); + } + + return S_cas_success; +} +#endif + + +/* + * casStrmClient::readSyncAction() + */ +caStatus casStrmClient::readSyncAction() +{ + const caHdr *mp = this->ctx.getMsg(); + int status; + caHdr *reply; + + status = this->allocMsg(0u, &reply); + if(status){ + return status; + } + + *reply = *mp; + + this->commitMsg(); + + return S_cas_success; +} + + + +/* + * caStatus casStrmClient::accessRightsResponse() + */ +caStatus casStrmClient::accessRightsResponse(casChannelI *pciu) +{ + caHdr *reply; + unsigned ar; + int v41; + int status; + + /* + * noop if this is an old client + */ + v41 = CA_V41(CA_PROTOCOL_VERSION, this->minor_version_number); + if(!v41){ + return S_cas_success; + } + + ar = 0; /* none */ + if ((*pciu)->readAccess()) { + ar |= CA_PROTO_ACCESS_RIGHT_READ; + } + if ((*pciu)->writeAccess()) { + ar |= CA_PROTO_ACCESS_RIGHT_WRITE; + } + + status = this->allocMsg(0u, &reply); + if(status){ + return status; + } + + *reply = nill_msg; + reply->m_cmmd = CA_PROTO_ACCESS_RIGHTS; + reply->m_cid = pciu->getCID(); + reply->m_available = ar; + this->commitMsg(); + + return S_cas_success; +} + + +// +// casStrmClient::write() +// +caStatus casStrmClient::write() +{ + const caHdr *pHdr = this->ctx.getMsg(); + casPVI *pPV = this->ctx.getPV(); + caStatus status; + + // + // no puts via compound types (for now) + // + if (dbr_value_offset[pHdr->m_type]) { + return S_cas_badType; + } + + // + // the PV state must not be modified during a transaction + // + status = (*pPV)->beginTransaction(); + if (status) { + return status; + } + + // + // DBR_STRING is stored outside the DD so it + // lumped in with arrays + // + if (pHdr->m_count > 1u || pHdr->m_type==DBR_STRING) { + status = this->writeArrayData(); + } + else { + status = this->writeScalerData(); + } + + (*pPV)->endTransaction(); + + return status; +} + + +// +// casStrmClient::writeScalerData() +// +caStatus casStrmClient::writeScalerData() +{ + gdd *pDD; + const caHdr *pHdr = this->ctx.getMsg(); + gddStatus gddStat; + caStatus status; + aitEnum type; + + type = gddDbrToAit[pHdr->m_type].type; + if (type == aitEnumInvalid) { + return S_cas_badType; + } + + pDD = new gddScaler (gddAppType_value, type); + if (!pDD) { + return S_cas_noMemory; + } + + gddStat = pDD->GCopy(type, this->ctx.getData()); + if (gddStat) { + pDD->Unreference(); + return S_cas_badType; + } + + // + // No suprises when multiple codes are looking + // at the same data + // + pDD->MarkConstant (); + + // + // call the server tool's virtual function + // + status = (*this->ctx.getPV())->write(this->ctx, *pDD); + + // + // tell the DD that this code is finished with it + // + gddStat = pDD->Unreference(); + assert(gddStat==0); + + return status; +} + + +// +// casStrmClient::writeArrayData() +// +caStatus casStrmClient::writeArrayData() +{ + gdd *pDD; + const caHdr *pHdr = this->ctx.getMsg(); + gddDestructor *pDestructor; + gddStatus gddStat; + caStatus status; + aitEnum type; + char *pData; + size_t size; + + type = gddDbrToAit[pHdr->m_type].type; + if (type == aitEnumInvalid) { + return S_cas_badType; + } + + pDD = new gddAtomic(gddAppType_value, type, 1, pHdr->m_count); + if (!pDD) { + return S_cas_noMemory; + } + + size = dbr_size_n (pHdr->m_type, pHdr->m_count); + pData = new char [size]; + if (!pData) { + pDD->Unreference(); + return S_cas_noMemory; + } + + pDestructor = new gddDestructor; + if (!pDestructor) { + delete [] pData; + pDD->Unreference(); + return S_cas_noMemory; + } + + // + // move the data from the protocol buffer + // to the allocated area so that they + // will be allowed to ref the DD + // + memcpy (pData, this->ctx.getData(), size); + + // + // install allocated area into the DD + // + pDD->PutRef (pData, type, pDestructor); + + // + // No suprises when multiple codes are looking + // at the same data + // + pDD->MarkConstant (); + + // + // call the server tool's virtual function + // + status = (*this->ctx.getPV())->write(this->ctx, *pDD); + + // + // tell the DD that this code is finished with it + // + gddStat = pDD->Unreference(); + assert(gddStat==0); + + return status; +} + + +// +// casStrmClient::read() +// +caStatus casStrmClient::read(gdd *&pDescRet) +{ + const caHdr *pHdr = this->ctx.getMsg(); + caStatus status; + + pDescRet = NULL; + status = createDBRDD (pHdr->m_type, pHdr->m_count, pDescRet); + if (status) { + return status; + } + + assert(pDescRet); + + // + // the PV state must not be modified during a transaction + // + status = (*this->ctx.getPV())->beginTransaction(); + if (status) { + return status; + } + + // + // call the server tool's virtual function + // + status = (*this->ctx.getPV())->read(this->ctx, *pDescRet); + if (status) { + pDescRet->Unreference(); + pDescRet = NULL; + if (status!=S_casApp_asyncCompletion) { + errMessage(status, + " - response from server tool\n"); + } + } + + (*this->ctx.getPV())->endTransaction(); + + return status; +} + +// +// createDBRDD () +// +caStatus createDBRDD (unsigned dbrType, aitIndex dbrCount, gdd *&pDescRet) +{ + aitUint32 valIndex; + aitUint32 gddStatus; + aitUint16 appType; + + appType = gddDbrToAit[dbrType].app; + + // + // create the descriptor + // + pDescRet = gddApplicationTypeTable::app_table.GetDD (appType); + if (!pDescRet) { + return S_cas_noMemory; + } + + // + // set bounds for the value member + // + if (dbrCount != 1u) { + if (pDescRet->IsContainer()) { + gddContainer *pCont = (gddContainer *) pDescRet; + gdd *pVal; + + gddStatus = + gddApplicationTypeTable::app_table.MapAppToIndex + (appType, gddAppType_value, valIndex); + if (gddStatus) { + pDescRet->Unreference(); + pDescRet = NULL; + return S_cas_badType; + } + pVal = pCont->GetDD(valIndex); + assert (pVal); + gddStatus = pVal->SetBound (0, 0u, dbrCount); + assert (gddStatus==0) + } + else if (pDescRet->IsAtomic()) { + gddAtomic *pAtomic = (gddAtomic *) pDescRet; + gddStatus = pAtomic->SetBound(0, 0u, dbrCount); + assert (gddStatus==0) + } + else { + assert(dbrCount==1u); + } + } + + return S_cas_success; +} + + +// +// casStrmClient::userName() +// +const char *casStrmClient::userName() const +{ + return this->pUserName?this->pUserName:"?"; +} + +// +// casStrmClient::hostName() +// +const char *casStrmClient::hostName() const +{ + return this->pHostName?this->pHostName:"?"; +} + + +// +// casStrmClient::createChanResponse() +// +caStatus casStrmClient::createChanResponse(casChannelI *, + const caHdr &msg, gdd *pCanonicalName, + const caStatus completionStatus) +{ + casChannel *pChan; + casChannelI *pChanI; + casPVI *pPV; + caHdr *claim_reply; + unsigned dbrType; + caStatus status; + + this->ctx.getServer()->pvExistTestCompletion(); + + if (completionStatus) { + return this->channelCreateFailed(&msg, completionStatus); + } + + if (!pCanonicalName) { + return this->channelCreateFailed(&msg, S_cas_badParameter); + } + + status = allocMsg (0u, &claim_reply); + if (status) { + return status; + } + + // + // prevent problems such as the PV being deleted before the + // channel references it + // + this->lock(); + + pCanonicalName->MarkConstant(); + + pPV = this->ctx.getServer()->createPV(*pCanonicalName); + if (!pPV) { + this->unlock(); + return this->channelCreateFailed(&msg, S_cas_noMemory); + } + + // + // create server tool XXX derived from casChannel + // + this->ctx.setPV(pPV); + pChan = (*pPV)->createChannel(this->ctx, + this->pUserName, this->pHostName); + if (!pChan) { + this->unlock(); + pPV->deleteSignal(); + return this->channelCreateFailed(&msg, S_cas_noMemory); + } + + this->unlock(); + + pChanI = (casChannelI *) pChan; + + status = pPV->bestDBRType(dbrType); + if (status) { + errMessage(status, "best external dbr type fetch failed"); + pChanI->clientDestroy(); + return this->channelCreateFailed(&msg, status); + } + + *claim_reply = nill_msg; + claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU; + claim_reply->m_type = dbrType; + claim_reply->m_count = pPV->nativeCount(); + claim_reply->m_cid = msg.m_cid; + claim_reply->m_available = pChanI->getSID(); + this->commitMsg(); + + return status; +} + +// +// caServerI::createPV () +// +casPVI *caServerI::createPV (gdd &name) +{ + aitString *pAITStr; + casPVI *pPVI; + caStatus status; + + // + // dont proceed unless its a valid PV name + // + status = casPVI::verifyPVName (name); + if (status) { + return NULL; + } + + name.GetRef (pAITStr); + stringId id (pAITStr->String()); + + this->lock (); + + pPVI = this->stringResTbl.lookup (id); + if (!pPVI) { + casPV *pPV; + pPV = (*this)->createPV (this->ctx, pAITStr->String()); + if (pPV) { + pPVI = (casPVI *) pPV; + } + } + + // + // lock shouldnt be released until we finish creating and + // installing the PV + // + this->unlock (); + + return pPVI; +} + +// +// caServerI::roomForNewChannel() +// +inline aitBool caServerI::roomForNewChannel() const +{ + return aitTrue; +} + +// +// casStrmClient::installChannel() +// +void casStrmClient::installChannel(casChannelI &chan) +{ + this->lock(); + this->getCAS().installItem(chan); + this->chanList.add(chan); + this->unlock(); +} + +// +// casStrmClient::removeChannel() +// +void casStrmClient::removeChannel(casChannelI &chan) +{ + casRes *pRes; + + this->lock(); + pRes = this->getCAS().removeItem(chan); + assert (&chan == (casChannelI *)pRes); + this->chanList.remove(chan); + this->unlock(); +} + diff --git a/src/cas/generic/casdef.h b/src/cas/generic/casdef.h new file mode 100644 index 000000000..13f66ec22 --- /dev/null +++ b/src/cas/generic/casdef.h @@ -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 // EPICS alarm severity/condition +#include // EPICS error codes +#include // EPICS data descriptors +#if 0 +#include // EPICS data descriptors appl data types +#include // EPICS application type table +#endif + +typedef aitUint32 caStatus; + +#include +#include + +/* + * =========================================================== + * 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) */ + diff --git a/src/cas/generic/gddAppFuncTable.h b/src/cas/generic/gddAppFuncTable.h new file mode 100644 index 000000000..e26bf2d10 --- /dev/null +++ b/src/cas/generic/gddAppFuncTable.h @@ -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 + +// +// GDD +// +#include +#include + +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 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::gddAppFuncTable() +// +// The total number of application tags to manage should be +// hidden from the application +// +template +inline gddAppFuncTable::gddAppFuncTable() : + pMFuncRead(NULL), + maxAppType(0u) +{ +} + +// +// gddAppFuncTable::newTbl() +// +// The total number of application tags to manage should be +// hidden from the application +// +template +inline void gddAppFuncTable::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::installReadFunc() +// + + +// +// gddAppFuncTable::read() +// +// (g++ generates "multiply defined symbols" message unless I set this +// to be inline) +// +template +inline gddAppFuncTableStatus gddAppFuncTable::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; +} + diff --git a/src/cas/generic/inBuf.cc b/src/cas/generic/inBuf.cc new file mode 100644 index 000000000..ef0214768 --- /dev/null +++ b/src/cas/generic/inBuf.cc @@ -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 + +// +// 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; + } +} + diff --git a/src/cas/generic/osiTimer.cc b/src/cas/generic/osiTimer.cc new file mode 100644 index 000000000..19db508f3 --- /dev/null +++ b/src/cas/generic/osiTimer.cc @@ -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 +#include + +#include + +// +// osiTimer::arm() +// +void osiTimer::arm (const osiTime * const pInitialDelay) +{ + tsDLIter 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); + } +} + diff --git a/src/cas/generic/osiTimerQueue.cc b/src/cas/generic/osiTimerQueue.cc new file mode 100644 index 000000000..6857aedf1 --- /dev/null +++ b/src/cas/generic/osiTimerQueue.cc @@ -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 + +#include + +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 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 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(); + } +} + + diff --git a/src/cas/generic/outBuf.cc b/src/cas/generic/outBuf.cc new file mode 100644 index 000000000..9641ec547 --- /dev/null +++ b/src/cas/generic/outBuf.cc @@ -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 + +// +// 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()); + } +} + diff --git a/src/cas/generic/server.h b/src/cas/generic/server.h new file mode 100644 index 000000000..82470b81c --- /dev/null +++ b/src/cas/generic/server.h @@ -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 +#include +#include +#include +#include +#include +#include +#include + +// +// EPICS +// +#include +#define epicsAssertAuthor "Jeff Hill johill@lanl.gov" +#include + +// +// CA +// +#include +#include +#include +#include + +// +// gdd +// +#include +#include + +// +// 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 // IO dependent +#include // 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 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 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 { +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 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 // OS dependent + +class casClientMon; + +// +// caServerI +// +class caServerI : public caServerOS, public caServerIO, + public osiMutex, public ioBlockedList, + private uintResTable, + 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 &getResTable() {return *this;} + + void installItem(casRes &res) + { + this->uintResTable::installItem(res); + } + + casRes *removeItem(casRes &res) + { + return this->uintResTable::remove(res); + } + + // + // call virtual function in the interface class + // + caServer * operator -> () + { + return this->getAdapter(); + } + + void connectCB(); + +private: + void advanceBeaconPeriod(); + + casDGOS dgClient; + casCtx ctx; + tsDLList clientList; + resTable 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*/ + + diff --git a/src/cas/io/bsdSocket/README b/src/cas/io/bsdSocket/README new file mode 100644 index 000000000..2c2147c18 --- /dev/null +++ b/src/cas/io/bsdSocket/README @@ -0,0 +1,6 @@ + + +this directory contains the bsd socket dependent source for +the EPICS ca server + + diff --git a/src/cas/io/bsdSocket/caServerIO.cc b/src/cas/io/bsdSocket/caServerIO.cc new file mode 100644 index 000000000..eb786f6af --- /dev/null +++ b/src/cas/io/bsdSocket/caServerIO.cc @@ -0,0 +1,217 @@ +// +// $Id$ +// +// verify connection state prior to doing anything in this file +// +// +// $Log$ +// + +#include +#include + +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; +} + + diff --git a/src/cas/io/bsdSocket/casDGIO.cc b/src/cas/io/bsdSocket/casDGIO.cc new file mode 100644 index 000000000..e5362af22 --- /dev/null +++ b/src/cas/io/bsdSocket/casDGIO.cc @@ -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 + +// +// 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; +} + diff --git a/src/cas/io/bsdSocket/casIOD.h b/src/cas/io/bsdSocket/casIOD.h new file mode 100644 index 000000000..d84693941 --- /dev/null +++ b/src/cas/io/bsdSocket/casIOD.h @@ -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 +#include +#include +#include +#if 0 // func proto do not have args for C++ +#include +#include +#endif + +#ifdef __cplusplus +} +#endif + +#include + +typedef int SOCKET; +#define SOCKERRNO errno +#define socket_close(S) close(S) +#define socket_ioctl(A,B,C) ioctl(A,B,C) + +// ca +#include + +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 + diff --git a/src/cas/io/bsdSocket/casStreamIO.cc b/src/cas/io/bsdSocket/casStreamIO.cc new file mode 100644 index 000000000..fafa77a11 --- /dev/null +++ b/src/cas/io/bsdSocket/casStreamIO.cc @@ -0,0 +1,382 @@ +// +// $Id$ +// +// verify connection state prior to doing anything in this file +// +// +// $Log$ +// + +#include + + +// +// 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; +} + diff --git a/src/cas/io/bsdSocket/sigPipeIgnore.c b/src/cas/io/bsdSocket/sigPipeIgnore.c new file mode 100644 index 000000000..9af6dbd70 --- /dev/null +++ b/src/cas/io/bsdSocket/sigPipeIgnore.c @@ -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 +#include +#include +#include + +#include + +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; +} + + + diff --git a/src/cas/io/bsdSocket/sigPipeIgnore.h b/src/cas/io/bsdSocket/sigPipeIgnore.h new file mode 100644 index 000000000..264db8ea9 --- /dev/null +++ b/src/cas/io/bsdSocket/sigPipeIgnore.h @@ -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 + diff --git a/src/cas/os/posix/README b/src/cas/os/posix/README new file mode 100644 index 000000000..fc9445f12 --- /dev/null +++ b/src/cas/os/posix/README @@ -0,0 +1,6 @@ + + +this directory contains the posix os dependent source for +the EPICS ca server + + diff --git a/src/cas/os/posix/caServerOS.cc b/src/cas/os/posix/caServerOS.cc new file mode 100644 index 000000000..f502325b4 --- /dev/null +++ b/src/cas/os/posix/caServerOS.cc @@ -0,0 +1,113 @@ + +/* + * + * caServerOS.c + * $Id$ + * + * + * $Log$ + * + */ + + +// +// CA server +// +#include + +#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(); +} + diff --git a/src/cas/os/posix/casClientOS.h b/src/cas/os/posix/casClientOS.h new file mode 100644 index 000000000..3e5db6a0b --- /dev/null +++ b/src/cas/os/posix/casClientOS.h @@ -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 (); +}; + diff --git a/src/cas/os/posix/casDGOS.cc b/src/cas/os/posix/casDGOS.cc new file mode 100644 index 000000000..431613814 --- /dev/null +++ b/src/cas/os/posix/casDGOS.cc @@ -0,0 +1,235 @@ + +/* + * + * casDGOS.c + * $Id$ + * + * + * $Log$ + * + */ + +// +// CA server +// +#include +#include // 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); +} + diff --git a/src/cas/os/posix/casOSD.h b/src/cas/os/posix/casOSD.h new file mode 100644 index 000000000..942ae27ef --- /dev/null +++ b/src/cas/os/posix/casOSD.h @@ -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 +#include + +extern "C" { +// +// for htons() etc +// +# include + +} // extern "C" + +#include +#include +#include + +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 + diff --git a/src/cas/os/posix/casSpecificOS.h b/src/cas/os/posix/casSpecificOS.h new file mode 100644 index 000000000..248e5ac0e --- /dev/null +++ b/src/cas/os/posix/casSpecificOS.h @@ -0,0 +1,46 @@ +/* + * $Id$ + * Some of this isnt posix - its BSD + * + * $Log$ + */ + +#ifndef includeCasSpecificOSH +#define includeCasSpecificOSH + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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) */ + diff --git a/src/cas/os/posix/casStreamOS.cc b/src/cas/os/posix/casStreamOS.cc new file mode 100644 index 000000000..24f733130 --- /dev/null +++ b/src/cas/os/posix/casStreamOS.cc @@ -0,0 +1,456 @@ +// +// casStreamOS.cc +// $Id$ +// +// +// $Log$ +// +// + +// +// CA server +// +#include +#include // 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; + } +} + diff --git a/src/cas/os/posix/osiMutex.h b/src/cas/os/posix/osiMutex.h new file mode 100644 index 000000000..0ce658885 --- /dev/null +++ b/src/cas/os/posix/osiMutex.h @@ -0,0 +1,13 @@ + + +// +// osiMutex - OS independent mutex +// (NOOP on single threaded OS) +// +class osiMutex { +public: + void lock() {}; + void unlock() {}; +private: +}; + diff --git a/src/cas/os/posix/osiTimeOSD.cc b/src/cas/os/posix/osiTimeOSD.cc new file mode 100644 index 000000000..28016a0d9 --- /dev/null +++ b/src/cas/os/posix/osiTimeOSD.cc @@ -0,0 +1,25 @@ + +#include + +#include +#include + +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); +} + diff --git a/src/cas/os/posixRT/README b/src/cas/os/posixRT/README new file mode 100644 index 000000000..42e5e7848 --- /dev/null +++ b/src/cas/os/posixRT/README @@ -0,0 +1,7 @@ + +WORK IN PROGRESS + +this directory contains the posix RT os dependent source for +the EPICS ca server + + diff --git a/src/cas/os/vms/BUILD_VMS.COM b/src/cas/os/vms/BUILD_VMS.COM new file mode 100644 index 000000000..5a56baedc --- /dev/null +++ b/src/cas/os/vms/BUILD_VMS.COM @@ -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 +$! user +$! 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 +$! ************************************************************ + diff --git a/src/cas/os/vms/README b/src/cas/os/vms/README new file mode 100644 index 000000000..6602707af --- /dev/null +++ b/src/cas/os/vms/README @@ -0,0 +1,7 @@ + +WORK IN PROGRESS + +this directory contains the vms os dependent source for +the EPICS ca server + + diff --git a/src/cas/os/vms/casSpecificOS.h b/src/cas/os/vms/casSpecificOS.h new file mode 100644 index 000000000..8e5038a8a --- /dev/null +++ b/src/cas/os/vms/casSpecificOS.h @@ -0,0 +1,48 @@ + +#include + +#include + +#if defined (MULTINET) +# include "multinet_root:[multinet.include]errno.h" +#elif defined (WINTCP) +# include +#else +# include +#endif + +#include +#include +#include +#include + +#if defined(UCX) && 0 +# include +# include +#else +# include +#endif + +#include + +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 + diff --git a/src/cas/os/vms/login.com b/src/cas/os/vms/login.com new file mode 100644 index 000000000..8c0e2c6d6 --- /dev/null +++ b/src/cas/os/vms/login.com @@ -0,0 +1,3 @@ + +set display/create/node=xxxx.atdiv.lanl.gov/trans=tcpip + diff --git a/src/cas/os/vms/mitfp.c b/src/cas/os/vms/mitfp.c new file mode 100644 index 000000000..df1e3435d --- /dev/null +++ b/src/cas/os/vms/mitfp.c @@ -0,0 +1,266 @@ + +/* + * mitfp.c - routines to convert between VAX float and big endian + * IEEE float + * + * Author: Jeffrey O. Hill + * + * + */ + +#include + + + +/************************************************************************/ +/* 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 */ +/* -126sign; + 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 */ +/* -1022exp) < (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; +} + diff --git a/src/cas/os/vms/mitfp.cc b/src/cas/os/vms/mitfp.cc new file mode 100644 index 000000000..e6fb71a66 --- /dev/null +++ b/src/cas/os/vms/mitfp.cc @@ -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 +#include + +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 */ +/* -126sign; + 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 */ +/* -1022exp) < (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; +} + diff --git a/src/cas/os/vms/mitfp.h b/src/cas/os/vms/mitfp.h new file mode 100644 index 000000000..b916f9c5b --- /dev/null +++ b/src/cas/os/vms/mitfp.h @@ -0,0 +1,8 @@ + + +double htond(double mit); +double ntohd(double ieee); +float htonf(float mit); +float ntohf(float ieee); + + diff --git a/src/cas/os/vms/vms_depen.h b/src/cas/os/vms/vms_depen.h new file mode 100644 index 000000000..394f77942 --- /dev/null +++ b/src/cas/os/vms/vms_depen.h @@ -0,0 +1,41 @@ + + +#include +#include +#include +#include + + +#if defined(WINTCP) /* Wallangong */ +# define socket_close(S) netclose(S) +# define socket_ioctl(A,B,C) ioctl(A,B,C) +# include +# include +# include +# include +# define SOCKERRNO uerrno +#elif defined(UCX) /* GeG 09-DEC-1992 */ +# include +# include +# define socket_close(S) close(S) +# define socket_ioctl(A,B,C) ioctl(A,B,C) +# include +# define SOCKERRNO errno +#else /* MULTINET */ +# include +# include +# include +# include +# 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*/ + diff --git a/src/cas/os/vxWorks/README b/src/cas/os/vxWorks/README new file mode 100644 index 000000000..47ee432df --- /dev/null +++ b/src/cas/os/vxWorks/README @@ -0,0 +1,7 @@ + +WORK IN PROGRESS + +this directory contains the vxWorks os dependent source for +the EPICS ca server + + diff --git a/src/cas/os/vxWorks/vxWorks_depen.c b/src/cas/os/vxWorks/vxWorks_depen.c new file mode 100644 index 000000000..1b9adfb74 --- /dev/null +++ b/src/cas/os/vxWorks/vxWorks_depen.c @@ -0,0 +1,659 @@ + +/* + * + * vxWorks_depen.c + * %W% %G% + * + * vxWorks dependent routines for the CA server + * + * + */ + +#include +#include + +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 (caMaxFreeBlockclient; + 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'; +} + diff --git a/src/cas/os/vxWorks/vxWorks_depen.cc b/src/cas/os/vxWorks/vxWorks_depen.cc new file mode 100644 index 000000000..61355d49c --- /dev/null +++ b/src/cas/os/vxWorks/vxWorks_depen.cc @@ -0,0 +1,659 @@ + +/* + * + * vxWorks_depen.c + * %W% %G% + * + * vxWorks dependent routines for the CA server + * + * + */ + +#include +#include + +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 (caMaxFreeBlockclient; + 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'; +} + diff --git a/src/cas/os/vxWorks/vxWorks_depen.h b/src/cas/os/vxWorks/vxWorks_depen.h new file mode 100644 index 000000000..e1d187630 --- /dev/null +++ b/src/cas/os/vxWorks/vxWorks_depen.h @@ -0,0 +1,256 @@ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include /* for sendto() setsockopt() etc */ +#include +#include + +/* + * EPICS on vxWorks + */ +#include +#include +#include + +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) + + + + diff --git a/src/cas/test/buckTest.c b/src/cas/test/buckTest.c new file mode 100644 index 000000000..deb7a6ded --- /dev/null +++ b/src/cas/test/buckTest.c @@ -0,0 +1,74 @@ + +#include +#include +#include + +#include + +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 +#include + +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 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; +} + + diff --git a/src/cas/test/resourceLibTest.cc b/src/cas/test/resourceLibTest.cc new file mode 100644 index 000000000..e5f4d4b98 --- /dev/null +++ b/src/cas/test/resourceLibTest.cc @@ -0,0 +1,110 @@ + + +#include +#include +#include +#include + +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 { +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 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 +#include +#include +#include + +class fred : public tsDLNode { +public: + fred() : count(0) {} + void inc () {count++;} +private: + unsigned count; +}; + +class jane : public fred, public tsDLNode { +public: + jane() {} +private: +}; + +#define LOOPCOUNT 100000 + +main () +{ + tsDLList list; + tsDLIter iter(list); + fred *pFred; + unsigned i; + clock_t clk; + clock_t diff; + double delay; + + for (i=0; iinc(); + } + 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; iinc(); + } + diff = clock() - clk; + delay = diff; + delay = delay/CLOCKS_PER_SEC; + delay = delay/LOOPCOUNT; + printf("delay = %15.10lf\n", delay); +} + diff --git a/src/cas/test/tsDLListTest.cc b/src/cas/test/tsDLListTest.cc new file mode 100644 index 000000000..98815c3c2 --- /dev/null +++ b/src/cas/test/tsDLListTest.cc @@ -0,0 +1,72 @@ + + + +#include +#include +#include + +class fred : public tsDLNode { +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 { +public: + jane(const char * const pNameIn) : fred(pNameIn){} +private: +}; + +main () +{ + tsDLList list; + tsDLIter iter(list); + fred *pFred; + fred *pFredII; + fred *pFredBack; + tsDLList janeList; + tsDLIter 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(); + } +} + diff --git a/src/cas/test/tsDLListTest.s b/src/cas/test/tsDLListTest.s new file mode 100644 index 000000000..77e6df1b0 --- /dev/null +++ b/src/cas/test/tsDLListTest.s @@ -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 +! 5 !#include +! 7 !class fred : public tsDLNode { +! 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 { +! 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 list; +! 24 ! tsDLIter iter(list); +! 25 ! fred *pFred; +! 26 ! fred *pFredII; +! 27 ! fred *pFredBack; +! 28 ! tsDLList janeList; +! 29 ! tsDLIter 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=<>",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 diff --git a/src/cas/test/tsSLListBench.cc b/src/cas/test/tsSLListBench.cc new file mode 100644 index 000000000..df12cf361 --- /dev/null +++ b/src/cas/test/tsSLListBench.cc @@ -0,0 +1,62 @@ + + + +#include +#include +#include + +class fred : public tsSLNode { +public: + fred() : count(0) {} + void inc () {count++;} +private: + unsigned count; +}; + +class jane : public fred, public tsSLNode { +public: + jane() {} +private: +}; + +#define LOOPCOUNT 100000 + +main () +{ + tsSLList list; + tsSLIter iter(list); + fred *pFred; + unsigned i; + clock_t clk; + clock_t diff; + double delay; + + for (i=0; iinc(); + } + 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; iinc(); + } + diff = clock() - clk; + delay = diff; + delay = delay/CLOCKS_PER_SEC; + delay = delay/LOOPCOUNT; + printf("delay = %15.10lf\n", delay); +} + diff --git a/src/cas/test/tsSLListTest.cc b/src/cas/test/tsSLListTest.cc new file mode 100644 index 000000000..3cd21e708 --- /dev/null +++ b/src/cas/test/tsSLListTest.cc @@ -0,0 +1,67 @@ + + + +#include +#include + +class fred : public tsSLNode { +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 { +public: + jane(const char * const pNameIn) : fred(pNameIn){} +private: +}; + +main () +{ + tsSLList list; + tsSLIter iter(list); + fred *pFred; + fred *pFredII; + fred *pFredBack; + tsSLList janeList; + tsSLIter 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(); + } +} +