Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed37ace27e | ||
|
|
bc15875bfb | ||
|
|
69eaaa17ba | ||
|
|
30b789aa49 | ||
|
|
1a94ea1045 | ||
|
|
f1dec35c5c | ||
|
|
6e8a3fcd6d | ||
|
|
ec35ef7136 | ||
|
|
fce8377156 | ||
|
|
5c4def1632 | ||
|
|
bdc57ecb2b | ||
|
|
fd3bf215c5 | ||
|
|
ba922d2bfa | ||
|
|
cd8e08651b | ||
|
|
0627aa5712 | ||
|
|
adc6219c2a | ||
|
|
a99f1d238e | ||
|
|
09797ee7ca | ||
|
|
01c0275876 | ||
|
|
d7269f9d80 | ||
|
|
58cd1d0a71 | ||
|
|
e4954ba26a | ||
|
|
60a5c476b3 | ||
|
|
9e63a51707 | ||
|
|
93149071b7 | ||
|
|
9c2a62ea96 | ||
|
|
ae7b8c7aa3 | ||
|
|
ac2ff29abb | ||
|
|
f9d0fd351d | ||
|
|
66fbbbb19a | ||
|
|
89777707c4 | ||
|
|
4c66f7f2d9 | ||
|
|
924350b362 | ||
|
|
d35780888a | ||
|
|
f7cc0e2d09 | ||
|
|
5554dfd66d | ||
|
|
69daab81d5 | ||
|
|
3aa5d2adee | ||
|
|
574bac67b4 | ||
|
|
3d03822043 | ||
|
|
6f7fc7bf8e | ||
|
|
702edbf4af | ||
|
|
0d0ac88242 | ||
|
|
2ab2470317 | ||
|
|
53d9a07f64 | ||
|
|
eae4f60e57 | ||
|
|
a05856375a | ||
|
|
05d3bb63aa | ||
|
|
743e3bd387 | ||
|
|
79b70d651c | ||
|
|
9d5bffca94 | ||
|
|
64bf84169c | ||
|
|
647bd334ae | ||
|
|
09ff608ca9 | ||
|
|
6c14dc194c | ||
|
|
9f163ef8d9 | ||
|
|
f0156119be | ||
|
|
f808e4309d | ||
|
|
f59123bd3c | ||
|
|
49a9d64946 | ||
|
|
c5740c0dd0 | ||
|
|
3eb6a66f3c | ||
|
|
986f7abb08 |
@@ -14,8 +14,8 @@
|
||||
EPICS_BASE_HOST_BIN = $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH)
|
||||
EPICS_BASE_HOST_LIB = $(EPICS_BASE)/lib/$(EPICS_HOST_ARCH)
|
||||
ifdef T_A
|
||||
EPICS_BASE_LIB = $(EPICS_BASE)/lib/$(T_A)
|
||||
EPICS_BASE_BIN = $(EPICS_BASE)/bin/$(T_A)
|
||||
EPICS_BASE_LIB = $(EPICS_BASE)/lib/$(T_A)
|
||||
EPICS_BASE_BIN = $(EPICS_BASE)/bin/$(T_A)
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
@@ -33,8 +33,10 @@ EPICS_BASE_HOST_LIBS += ca Com
|
||||
# Version number for base shared libraries (and win32 products)
|
||||
|
||||
ifdef BASE_TOP
|
||||
SHRLIB_VERSION = $(EPICS_VERSION).$(EPICS_REVISION)
|
||||
PROD_VERSION = $(EPICS_VERSION).$(EPICS_REVISION)
|
||||
# Unix lib.so.<v.r.m> Darwin lib.<v.r.m>.dylib
|
||||
SHRLIB_VERSION = $(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)
|
||||
# Windows only allows 2 levels of version numbering
|
||||
PROD_VERSION = $(EPICS_VERSION).$(EPICS_REVISION)
|
||||
endif # BASE_TOP
|
||||
|
||||
#---------------------------------------------------------------
|
||||
@@ -84,12 +86,15 @@ ELEX = $(call PATH_FILTER, $(TOOLS)/e_flex$(HOSTEXE)) -S$(EPICS_BASE)/include/fl
|
||||
YACC = $(EYACC)
|
||||
LEX = $(ELEX)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# msi used to be an external tool
|
||||
|
||||
MSI ?= $(EPICS_BASE_HOST_BIN)/msi
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# External tools and tool flags - must be in path or defined in application
|
||||
|
||||
ifndef ADL2DL
|
||||
ADL2DL = adl2dl
|
||||
endif
|
||||
ADL2DL ?= adl2dl
|
||||
|
||||
# sch2edif compiler and flags
|
||||
SCH2EDIF = sch2edif
|
||||
@@ -99,18 +104,11 @@ SCH2EDIF_FLAGS =
|
||||
|
||||
# e2db and flags
|
||||
# - again there is an assumption where edb.def is installed.
|
||||
ifndef E2DB
|
||||
E2DB = e2db
|
||||
endif
|
||||
E2DB ?= e2db
|
||||
E2DB_SYSFLAGS = -ate -d $(CAPFAST_TEMPLATES)/edb.def
|
||||
E2DB_FLAGS =
|
||||
|
||||
ifndef DBST
|
||||
DBST = dbst
|
||||
endif
|
||||
|
||||
ifndef MSI
|
||||
MSI = $(EPICS_BASE_HOST_BIN)/msi
|
||||
endif
|
||||
DBST ?= dbst
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ EPICS_VERSION = 3
|
||||
EPICS_REVISION = 15
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 0
|
||||
EPICS_MODIFICATION = 1
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included if zero
|
||||
EPICS_PATCH_LEVEL = 2
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
|
||||
# This will end in -DEV between official releases
|
||||
#EPICS_DEV_SNAPSHOT=-DEV
|
||||
|
||||
@@ -177,7 +177,7 @@ LIBRARY_OBJS = $(addsuffix $(OBJ),$(basename $(SRCS) $(USR_SRCS) $(LIB_SRCS) $(L
|
||||
LIBRARY_LD_OBJS = $(USR_OBJLIBS) $(LIB_OBJLIBS) $(TARGET_OBJS) $(LIBRARY_OBJS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# WIN95/NT resource files
|
||||
# Windows resource files
|
||||
|
||||
TARGET_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $($*_RCS))),)
|
||||
|
||||
@@ -187,11 +187,6 @@ PROD_LD_RESS = $(TARGET_RESS) $(PROD_RESS)
|
||||
LIBRARY_RESS = $(if $(RES),$(addsuffix $(RES),$(basename $(RCS) $(LIB_RCS) $(LIBRARY_RCS))),)
|
||||
LIBRARY_LD_RESS = $(TARGET_RESS) $(LIBRARY_RESS)
|
||||
|
||||
#--------------------------------------------------
|
||||
# WIN95/NT source browser
|
||||
PROD_BAF = $(addsuffix $(BAF), $(basename $(PROD)))
|
||||
LIB_BAF=$(addsuffix $(BAF),$(basename $(LIBRARY)))
|
||||
|
||||
#--------------------------------------------------
|
||||
# C preprocessor, compiler, and linker flag defaults
|
||||
|
||||
|
||||
@@ -30,23 +30,23 @@
|
||||
# local timezone info for vxWorks and RTEMS IOCs. The format is
|
||||
# <name>::<minutesWest>:<start daylight>:<end daylight>
|
||||
# where the start and end are mmddhh - that is month,day,hour
|
||||
# e.g. for ANL in 2010: EPICS_TIMEZONE=CUS::360:031402:110702
|
||||
# e.g. for ANL in 2015: EPICS_TIMEZONE=CST/CDT::360:030802:110102
|
||||
#
|
||||
# DST for 2011 US: Mar 13 - Nov 06
|
||||
# EU: Mar 27 - Oct 30
|
||||
# DST for 2012 US: Mar 11 - Nov 04
|
||||
# EU: Mar 25 - Oct 28
|
||||
# DST for 2013 US: Mar 10 - Nov 03
|
||||
# EU: Mar 31 - Oct 27
|
||||
# DST for 2014 US: Mar 09 - Nov 02
|
||||
# EU: Mar 30 - Oct 26
|
||||
# DST for 2015 US: Mar 08 - Nov 01
|
||||
# EU: Mar 29 - Oct 25
|
||||
# (see: http://www.worldtimezone.org/daylight.html)
|
||||
# DST for 2016 US: Mar 13 - Nov 06
|
||||
# EU: Mar 27 - Oct 30
|
||||
# DST for 2017 US: Mar 12 - Nov 05
|
||||
# EU: Mar 26 - Oct 29
|
||||
# DST for 2018 US: Mar 11 - Nov 04
|
||||
# EU: Mar 25 - Oct 28
|
||||
# DST for 2019 US: Mar 10 - Nov 03
|
||||
# EU: Mar 31 - Oct 27
|
||||
# (see: http://www.timeanddate.com/time/map/)
|
||||
#
|
||||
# These values are for 2011:
|
||||
EPICS_TIMEZONE=CUS::360:031302:110602
|
||||
#EPICS_TIMEZONE=MET::-60:032702:103002
|
||||
# These values are for 2015:
|
||||
EPICS_TIMEZONE=CST/CDT::360:030802:110102
|
||||
#EPICS_TIMEZONE=CET/CEST::-60:032902:102502
|
||||
|
||||
# EPICS_TS_NTP_INET
|
||||
# NTP time server ip address. Uses boot host if not set.
|
||||
|
||||
@@ -151,7 +151,6 @@ ACTIONS = inc
|
||||
ACTIONS += build
|
||||
ACTIONS += install
|
||||
ACTIONS += buildInstall
|
||||
ACTIONS += browse
|
||||
ACTIONS += runtests tapfiles
|
||||
|
||||
actionArchTargets = $(foreach x, $(ACTIONS),\ $(foreach arch,$(BUILD_ARCHS), $(x)$(DIVIDER)$(arch)))
|
||||
@@ -233,6 +232,11 @@ menu%.h$(DEP): menu%.dbd
|
||||
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
menu%.h$(DEP): ../menu%.dbd
|
||||
@$(RM) $@
|
||||
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
%.dbd$(DEP): %.dbd.pod
|
||||
@$(RM) $@
|
||||
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
|
||||
@@ -18,16 +18,17 @@ ifeq ($(filter $(ARCH),$(BUILD_ARCHS)),$(ARCH))
|
||||
buildInstall$(DIVIDER)$(ARCH) buildInstall: $(TARGETS)
|
||||
|
||||
clean$(DIVIDER)$(ARCH) clean:
|
||||
$(RM) cdCommands envPaths dllPath.bat
|
||||
$(RM) cdCommands envPaths dllPath.bat relPaths.sh
|
||||
else
|
||||
buildInstall$(DIVIDER)$(ARCH) buildInstall:
|
||||
clean$(DIVIDER)$(ARCH) clean:
|
||||
endif
|
||||
|
||||
cdCommands envPaths dllPath.bat: $(wildcard $(TOP)/configure/RELEASE*) \
|
||||
cdCommands envPaths dllPath.bat relPaths.sh: \
|
||||
$(wildcard $(TOP)/configure/RELEASE*) \
|
||||
$(wildcard $(TOP)/configure/CONFIG_SITE*) $(INSTALL_BIN)
|
||||
$(CONVERTRELEASE) -a $(ARCH) -t $(IOCS_APPL_TOP) $@
|
||||
|
||||
realclean:
|
||||
$(RM) cdCommands envPaths dllPath.bat
|
||||
$(RM) cdCommands envPaths dllPath.bat relPaths.sh
|
||||
|
||||
|
||||
@@ -17,48 +17,39 @@ ACTIONS = inc
|
||||
ACTIONS += build
|
||||
ACTIONS += install
|
||||
ACTIONS += buildInstall
|
||||
ACTIONS += browse
|
||||
ACTIONS += runtests tapfiles
|
||||
#ACTIONS += rebuild
|
||||
|
||||
actionPart = $(word 1, $(subst $(DIVIDER), ,$@))
|
||||
archPart = $(word 2, $(subst $(DIVIDER), ,$@))
|
||||
|
||||
actionArchTargets = $(foreach x, $(ACTIONS),\
|
||||
$(foreach arch,$(BUILD_ARCHS), $(x)$(DIVIDER)$(arch)))
|
||||
actionArchTargets = $(foreach action, $(ACTIONS), \
|
||||
$(addprefix $(action)$(DIVIDER), $(BUILD_ARCHS)))
|
||||
|
||||
cleanArchTargets = $(foreach arch,$(BUILD_ARCHS), clean$(DIVIDER)$(arch))
|
||||
cleanArchTargets = $(addprefix clean$(DIVIDER), $(BUILD_ARCHS))
|
||||
|
||||
buildDirs = $(addprefix O.,$(BUILD_ARCHS))
|
||||
buildDirs = $(addprefix O., $(BUILD_ARCHS))
|
||||
|
||||
#*************************************************************************
|
||||
# Create epics_host_arch dependancies for GNU make -j option
|
||||
# Only works with GNU make 3.81 or later (uses eval function)
|
||||
# Needed in dirs where EPICS_HOST_ARCH build creates a tool used in
|
||||
# Create EPICS_HOST_ARCH dependancies for GNU make -j option
|
||||
# Needed in dirs where EPICS_HOST_ARCH builds a tool used by
|
||||
# cross arch builds
|
||||
|
||||
CROSS_ARCHS += $(CROSS1) $(CROSS2)
|
||||
|
||||
define DEP_template
|
||||
$(2): $$(EPICS_HOST_ARCH)
|
||||
$(1)$$(DIVIDER)$(2): $(1)$$(DIVIDER)$$(EPICS_HOST_ARCH) O.$(2)
|
||||
$(2) : $(EPICS_HOST_ARCH)
|
||||
$(1)$(DIVIDER)$(2) : $(1)$(DIVIDER)$(EPICS_HOST_ARCH) O.$(2)
|
||||
endef
|
||||
|
||||
ifeq ($(MAKE_VERSION),3.81)
|
||||
$(foreach action, $(ACTIONS), $(foreach arch,\
|
||||
$(CROSS_ARCHS),$(eval $(call DEP_template,$(action),$(arch)))))
|
||||
else
|
||||
ifeq ($(findstring j,$(MAKEFLAGS)),j)
|
||||
$(foreach action, $(ACTIONS), $(foreach arch,\
|
||||
$(CROSS_ARCHS),$(eval $(call DEP_template,$(action),$(arch)))))
|
||||
endif
|
||||
endif
|
||||
$(foreach action, $(ACTIONS), $(foreach arch, $(CROSS_ARCHS), \
|
||||
$(eval $(call DEP_template,$(action),$(arch)))))
|
||||
|
||||
#*************************************************************************
|
||||
|
||||
# Allows rebuild to work with parallel builds option, -j.
|
||||
ifeq (rebuild,$(filter rebuild,$(MAKECMDGOALS)))
|
||||
$(buildDirs) O.Common : clean
|
||||
rebuild: install
|
||||
$(buildDirs) O.Common : clean
|
||||
rebuild : install
|
||||
endif
|
||||
|
||||
$(actionArchTargets) : $(buildDirs) O.Common
|
||||
@@ -67,7 +58,7 @@ $(actionArchTargets) : $(buildDirs) O.Common
|
||||
$(BUILD_ARCHS) : % : O.% O.Common
|
||||
$(MAKE) -C O.$@ -f ../Makefile TOP=$(TOP)/.. T_A=$@
|
||||
|
||||
$(ACTIONS):%: $(foreach arch, $(BUILD_ARCHS), %$(DIVIDER)$(arch))
|
||||
$(ACTIONS) : % : $(foreach arch, $(BUILD_ARCHS), %$(DIVIDER)$(arch))
|
||||
|
||||
$(buildDirs):
|
||||
$(PERL) $(TOOLS)/makeMakefile.pl $@ $(TOP)/..
|
||||
@@ -78,21 +69,21 @@ O.Common:
|
||||
#
|
||||
# special clean rule
|
||||
#
|
||||
clean : archs_common_clean
|
||||
clean: archsCommonClean
|
||||
|
||||
archs_common_clean :
|
||||
$(RMDIR) $(addprefix O.,$(BUILD_ARCHS)) O.Common
|
||||
archsCommonClean:
|
||||
$(RMDIR) $(buildDirs) O.Common
|
||||
|
||||
archclean :
|
||||
$(RMDIR) $(addprefix O.,$(BUILD_ARCHS))
|
||||
archclean:
|
||||
$(RMDIR) $(buildDirs)
|
||||
|
||||
$(cleanArchTargets) :
|
||||
$(cleanArchTargets):
|
||||
$(RMDIR) O.$(archPart)
|
||||
|
||||
realclean :
|
||||
realclean:
|
||||
$(RMDIR) O.*
|
||||
|
||||
.PHONY : $(actionArchTargets)
|
||||
.PHONY : $(cleanArchTargets)
|
||||
.PHONY : $(BUILD_ARCHS) rebuild arch_common_clean
|
||||
.PHONY : $(BUILD_ARCHS) rebuild archsCommonClean
|
||||
.PHONY : $(ACTIONS) clean realclean archclean host all
|
||||
|
||||
@@ -166,17 +166,6 @@ build_clean:
|
||||
ifdef RES
|
||||
@$(RM) *$(RES)
|
||||
endif
|
||||
ifdef BAF
|
||||
@$(RM) $(PROD_BAF) $(LIB_BAF)
|
||||
endif
|
||||
ifdef BOF
|
||||
@$(RM) *$(BOF)
|
||||
endif
|
||||
|
||||
# WIN95/NT source browser
|
||||
#ifdef BAF
|
||||
browse: $(LIB_BAF) $(PROD_BAF)
|
||||
#endif
|
||||
|
||||
$(DIRECTORY_TARGETS) :
|
||||
$(MKDIR) -p $@
|
||||
@@ -238,17 +227,11 @@ $(TESTPRODNAME) $(PRODNAME): %$(EXE):
|
||||
@$(RM) $@
|
||||
$(COMPILE.cpp) -c $<
|
||||
|
||||
# WIN95/NT resource compiler
|
||||
# Windows resource compiler
|
||||
%$(RES): %.rc
|
||||
@$(RM) $@
|
||||
$(RCCMD)
|
||||
|
||||
# WIN95/NT source browser
|
||||
%.bsc: %.sbr
|
||||
$(ECHO) "building source browser archive $@"
|
||||
@$(RM) $@
|
||||
$(BAFCMD) $<
|
||||
|
||||
YACCOPT ?= $($*_YACCOPT)
|
||||
#
|
||||
# rename the y.tab.h file only if we
|
||||
@@ -271,16 +254,6 @@ YACCOPT ?= $($*_YACCOPT)
|
||||
@$(RM) $@
|
||||
$(MV) $*.yy.c $@
|
||||
|
||||
# WIN95/NT source browser
|
||||
ifdef BAF
|
||||
|
||||
$(LIB_BAF): $(addsuffix $(BOF),$(basename $(LIBRARY_LD_OBJS)))
|
||||
$(ECHO) "Building source browser archive $@"
|
||||
@$(RM) $@
|
||||
$(BAFCMD) $^
|
||||
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Libraries, shared/DLL and stubs
|
||||
|
||||
@@ -332,10 +305,6 @@ $(MUNCHNAME): %$(MUNCH_SUFFIX): $(MUNCH_DEPENDS) %$(EXE)
|
||||
@$(RM) $@
|
||||
$(MUNCH_CMD)
|
||||
|
||||
$(OBJLIB_MUNCHNAME): %.munch: %_ctdt$(OBJ) %$(OBJ)
|
||||
@$(RM) $@
|
||||
$(MUNCH_CMD)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Automated testing
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ CPPFLAGS += $(CROSS_CPPFLAGS) $(POSIX_CPPFLAGS)\
|
||||
$(BASE_CPPFLAGS) $(TARGET_CPPFLAGS) $(USR_CPPFLAGS) $(ARCH_DEP_CPPFLAGS)\
|
||||
$(OP_SYS_CPPFLAGS) $(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
|
||||
|
||||
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Although RTEMS uses gcc, it wants to use gcc its own way
|
||||
CROSS_CPPFLAGS =
|
||||
|
||||
@@ -25,7 +25,7 @@ OS_CLASS = iOS
|
||||
#--------------------------------------------------
|
||||
# GNU and SDK directories
|
||||
GNU_DIR = $(PLATFORM_DIR)/Developer/usr
|
||||
SDK_DIR = $(PLATFORM_DIR)/Developer/SDKs/$(IOS_PLATFORM)$(IOS_VERSION).sdk
|
||||
SDK_DIR = $(PLATFORM_DIR)/Developer/SDKs/$(IOS_PLATFORM).sdk
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Build architecture flags
|
||||
@@ -64,7 +64,7 @@ CC_CLANG = clang
|
||||
CCC_CLANG = clang++
|
||||
CMPLR_CLASS_CLANG = clang
|
||||
|
||||
CMPLR_CLASS = $(CMPLR_CLASS_$(COMPLER))
|
||||
CMPLR_CLASS = $(CMPLR_CLASS_$(COMPILER))
|
||||
|
||||
# Convert the iOS platform to lowercase for passing to xcrun's sdk parameter
|
||||
XCRUN_SDK_BASE = $(shell echo $(IOS_PLATFORM) | tr A-Z a-z)
|
||||
|
||||
@@ -68,13 +68,12 @@ GNU = NO
|
||||
#
|
||||
# Darwin shared libraries
|
||||
#
|
||||
SHRLIB_VERSION = $(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)
|
||||
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined suppress \
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
-compatibility_version $(EPICS_VERSION).$(EPICS_REVISION) \
|
||||
-current_version $(SHRLIB_VERSION)
|
||||
-install_name $(shell $(FULLPATHNAME) $(INSTALL_LIB))/$@ \
|
||||
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
|
||||
$(addprefix -current_version , $(SHRLIB_VERSION))
|
||||
SHRLIB_SUFFIX_BASE = .dylib
|
||||
SHRLIB_SUFFIX = .$(SHRLIB_VERSION)$(SHRLIB_SUFFIX_BASE)
|
||||
SHRLIB_SUFFIX = $(addprefix ., $(SHRLIB_VERSION))$(SHRLIB_SUFFIX_BASE)
|
||||
|
||||
LOADABLE_SHRLIB_LDFLAGS = -bundle -flat_namespace -undefined suppress
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ RCCMD = rc -l 0x409 $(INCLUDES) -fo $@ $<
|
||||
|
||||
ARCMD = lib -nologo -verbose -out:$@ $(LIB_OPT_LDFLAGS) $(LIBRARY_LD_OBJS)
|
||||
|
||||
BAFCMD = bscmake -nologo -o $@
|
||||
|
||||
#
|
||||
# Configure OS vendor C compiler
|
||||
CC = cl
|
||||
@@ -130,6 +128,7 @@ RANLIB=
|
||||
# -LTCG whole program optimization
|
||||
# -incremental:no full linking
|
||||
# -fixed:no generate relocatable code
|
||||
# -version:<major>.<minor> - only 2 components allowed, 0-65535 each
|
||||
# -debug generate debugging info
|
||||
LINK_OPT_FLAGS_YES = -LTCG -incremental:no -opt:ref \
|
||||
-release $(PROD_VERSION:%=-version:%)
|
||||
@@ -150,8 +149,6 @@ WIN32=1
|
||||
EXE=.exe
|
||||
OBJ=.obj
|
||||
RES=.res
|
||||
BAF=.bsc
|
||||
BOF=.sbr
|
||||
|
||||
# Problem: MS Visual C++ does not recognize *.cc as C++ source,
|
||||
# so we do C++ compiles using the global flag -TP
|
||||
|
||||
@@ -10,19 +10,9 @@
|
||||
-include $(CONFIG)/os/CONFIG.Common.win32-x86
|
||||
-include $(CONFIG)/os/CONFIG.win32-x86.win32-x86
|
||||
|
||||
ARCH_DEP_CPPFLAGS += /favor:blend
|
||||
#ARCH_DEP_CPPFLAGS += /Wp64
|
||||
|
||||
# /favor:blend both AMD64 and INTEL64
|
||||
# /favor:AMD64
|
||||
# /favor:INTEL64 (new value)
|
||||
# /favor:EN64T (old value)
|
||||
|
||||
OPT_LDFLAGS += /MACHINE:X64
|
||||
|
||||
# /MACHINE:X64
|
||||
# /MACHINE:IA64 (Itanium)
|
||||
# /MACHINE:X86
|
||||
|
||||
#The following option does not work
|
||||
#ARCH_DEP_CPPFLAGS += /env x64
|
||||
|
||||
@@ -9,14 +9,6 @@
|
||||
|
||||
-include $(CONFIG)/os/CONFIG.win32-x86.win32-x86
|
||||
|
||||
ARCH_DEP_CPPFLAGS += /favor:blend
|
||||
#ARCH_DEP_CPPFLAGS += /Wp64
|
||||
|
||||
# /favor:blend both AMD64 and INTEL64
|
||||
# /favor:AMD64
|
||||
# /favor:INTEL64 (new value)
|
||||
# /favor:EN64T (old value)
|
||||
|
||||
OPT_LDFLAGS += /MACHINE:X64
|
||||
|
||||
# /MACHINE:X64
|
||||
|
||||
12
configure/os/CONFIG.windows-x64.windows-x64-debug
Normal file
12
configure/os/CONFIG.windows-x64.windows-x64-debug
Normal file
@@ -0,0 +1,12 @@
|
||||
# CONFIG.windows-x64.windows-x64-debug
|
||||
#
|
||||
# $Revision-Id$
|
||||
# This file is maintained by the build community.
|
||||
#
|
||||
# Definitions for windows-x64 compiler host - windows-x64 debug compiler target builds
|
||||
# Sites may override these definitions in CONFIG_SITE.windows-x64.windows-x64-debug
|
||||
#-------------------------------------------------------
|
||||
|
||||
include $(CONFIG)/os/CONFIG.windows-x64.windows-x64
|
||||
|
||||
HOST_OPT=NO
|
||||
@@ -5,17 +5,6 @@
|
||||
# Site-specific settings for Apple iOS builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# iOS SDK Version number (not the XCode version).
|
||||
# We haven't tested our current build rules on the older
|
||||
# versions of either XCode or the iOS SDK, be warned!
|
||||
|
||||
#IOS_VERSION = 5.0
|
||||
#IOS_VERSION = 5.1
|
||||
#IOS_VERSION = 6.0
|
||||
#IOS_VERSION = 6.1
|
||||
#IOS_VERSION = 7.0
|
||||
IOS_VERSION = 8.0
|
||||
|
||||
# Minimum version of iOS the executables must run on.
|
||||
# Earlier versions may work, if XCode supports them.
|
||||
|
||||
|
||||
11
configure/os/CONFIG_SITE.Common.windows-x64-static
Normal file
11
configure/os/CONFIG_SITE.Common.windows-x64-static
Normal file
@@ -0,0 +1,11 @@
|
||||
# CONFIG_SITE.Common.windows-x64-static
|
||||
#
|
||||
# $Revision-Id$
|
||||
#
|
||||
# Site Specific definitions for windows-x64-static target
|
||||
# Only the local epics system manager should modify this file
|
||||
|
||||
# 64-bit Visual Studio 2010 builds fail when built optimized.
|
||||
# If you are using a newer version you can try removing this:
|
||||
HOST_OPT = NO
|
||||
|
||||
@@ -4,30 +4,27 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<title>Known Problems in R3.15.0.2</title>
|
||||
<title>Known Problems in R3.15.1</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="text-align: center">EPICS Base R3.15.0.2: Known Problems</h1>
|
||||
<h1 style="text-align: center">EPICS Base R3.15.1: Known Problems</h1>
|
||||
|
||||
<p>Any patch files linked below should be applied at the root of the
|
||||
base-3.15.0.2 tree. Download them, then use the GNU Patch program as
|
||||
base-3.15.1 tree. Download them, then use the GNU Patch program as
|
||||
follows:</p>
|
||||
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.0.2</b>
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.1</b>
|
||||
% <b>patch -p0 < <i>/path/to/</i>file.patch</b></pre></blockquote>
|
||||
|
||||
<p>The following significant problems have been reported with this
|
||||
version of EPICS Base:</p>
|
||||
|
||||
<ul>
|
||||
<li>64-bit Windows builds may not work with some tool-sets, the code in
|
||||
<tt>src/legacy/gdd</tt> is not comptible with the LLP64 model that Windows
|
||||
uses for its 64-bit ABI.</li>
|
||||
<li>The <tt>-x</tt> option to the softIoc program loads a standard database
|
||||
that is supposed to be able to exit the running IOC. In this release that
|
||||
causes an assertion failure which prints a stack trace and suspends the
|
||||
program wihout exiting.</li>
|
||||
|
||||
<li>64-bit Windows builds of the CAS library may not work with some compilers.
|
||||
The code in <tt>src/legacy/gdd</tt> is currently incompatible with the LLP64
|
||||
model that Windows uses for its 64-bit ABI.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
Installation Instructions
|
||||
|
||||
EPICS Base Release 3.15.0.2
|
||||
EPICS Base Release 3.15.1
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
* What is EPICS base?
|
||||
* What is new in this release?
|
||||
* Copyright
|
||||
* Supported platforms
|
||||
* Supported compilers
|
||||
* Software requirements
|
||||
* Host system storage requirements
|
||||
* Documentation
|
||||
* Directory Structure
|
||||
* Build related components
|
||||
* Building EPICS base (Unix and Win32)
|
||||
* Example application and extension
|
||||
* Multiple host platforms
|
||||
* What is EPICS base?
|
||||
* What is new in this release?
|
||||
* Copyright
|
||||
* Supported platforms
|
||||
* Supported compilers
|
||||
* Software requirements
|
||||
* Host system storage requirements
|
||||
* Documentation
|
||||
* Directory Structure
|
||||
* Build related components
|
||||
* Building EPICS base (Unix and Win32)
|
||||
* Example application and extension
|
||||
* Multiple host platforms
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<BODY>
|
||||
<CENTER>
|
||||
<H1>Installation Instructions</H1>
|
||||
<H2>EPICS Base Release 3.15.0.2</H2><BR>
|
||||
<H2>EPICS Base Release 3.15.1</H2><BR>
|
||||
</CENTER>
|
||||
<HR>
|
||||
<H3> Table of Contents</H3>
|
||||
|
||||
@@ -3,17 +3,77 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<title>EPICS Base R3.15.0.1 Release Notes</title>
|
||||
<title>EPICS Base R3.15.1 Release Notes</title>
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 align="center">EPICS Base Release 3.15.0.2</h1>
|
||||
<h1 align="center">EPICS Base Release 3.15.1</h1>
|
||||
|
||||
<h2 align="center">Changes between 3.15.0.2 and 3.15.1</h2>
|
||||
|
||||
<h3>epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()</h3>
|
||||
|
||||
<p>These routines have been rewritten; the previous implementations did not
|
||||
always behave exactly as specified.</p>
|
||||
|
||||
<h3>Shared Library Versions</h3>
|
||||
|
||||
<p>On architectures that can support it, the shared library version number for
|
||||
libraries provided with Base has had the third component of the EPICS version
|
||||
number added to it, thus libCom.so.3.15.1 instead of libCom.so.3.15. Windows
|
||||
can only support two components to its internal product version number, and the
|
||||
Darwin bug that external shared libraries were being built using the EPICS
|
||||
version number has been fixed.</p>
|
||||
|
||||
<h3>Hooking into dbLoadRecords</h3>
|
||||
|
||||
<p>A function pointer hook has been added to the dbLoadRecords() routine, to
|
||||
allow external modules such as autosave to be notified when new records have
|
||||
been loaded during IOC initialization. The hook is called dbLoadRecordsHook and
|
||||
follows the model of the recGblAlarmHook pointer in that modules that wish to
|
||||
use it must save the current value of the pointer before installing their own
|
||||
function pointer, and must call the original function from their own
|
||||
routine.</p>
|
||||
|
||||
<p>The hook is activiated from the dbLoadRecords() routine and gets called only
|
||||
after a database instance file has been read in without error. Note that the
|
||||
dbLoadTemplates() routine directly calls dbLoadRecords() so this hook also
|
||||
provides information about instantiated database templates. It is still possible
|
||||
to load record instances using dbLoadDatabase() though, and doing this will not
|
||||
result in the hook routines being called.</p>
|
||||
|
||||
<p>Code to use this hook should look something like this:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
#include "dbAccessDefs.h"
|
||||
|
||||
static DB_LOAD_RECORDS_HOOK_ROUTINE previousHook;
|
||||
|
||||
static void myRoutine(const char* file, const char* subs) {
|
||||
if (previousHook)
|
||||
previousHook(file, subs);
|
||||
|
||||
/* Do whatever ... */
|
||||
}
|
||||
|
||||
void myInit(void) {
|
||||
static int done = 0;
|
||||
|
||||
if (!done) {
|
||||
previousHook = dbLoadRecordsHook;
|
||||
dbLoadRecordsHook = myRoutine;
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
</pre></blockquote>
|
||||
|
||||
<p>As with many other parts of the static database access library there is no
|
||||
mutex to protect the function pointer. Initialization is expected to take place
|
||||
in the context of the IOC's main thread, from either a static C++ constructor or
|
||||
an EPICS registrar routine.</p>
|
||||
|
||||
<p>
|
||||
EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
|
||||
|
||||
<h2 align="center">Changes between 3.15.0.1 and 3.15.0.2</h2>
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>New iocshLoad command</h3>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $version = '0.5';
|
||||
my $version = '0.6';
|
||||
|
||||
|
||||
package CA;
|
||||
@@ -95,8 +95,8 @@ CA - Perl 5 interface to EPICS Channel Access
|
||||
} else {
|
||||
printf " Value: %g\n", $data->{value};
|
||||
printf " Severity: %s\n", $data->{severity};
|
||||
printf " Timestamp: %d.%09d\n",
|
||||
$data->{stamp}, $data->{stamp_fraction};
|
||||
printf " Timestamp: %.6f\n",
|
||||
$data->{stamp} + $data->{stamp_fraction};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ C<die> with an exception object in the callback and catch that using C<eval> in
|
||||
the main thread are not likely to succeed and will probably result in a crash.
|
||||
Callbacks should not perform any operations that would block for more than a
|
||||
fraction of a second as this will hold up network communications with the
|
||||
relevent server and could cause the Perl program and/or the Channel Access
|
||||
relevant server and could cause the Perl program and/or the Channel Access
|
||||
server to crash. Calling C<< CA->pend_event >> from within a callback is not
|
||||
permitted by the underlying Channel Access library.
|
||||
|
||||
@@ -291,7 +291,7 @@ apply to the callback subroutine as described in C<get_callback> above.
|
||||
|
||||
=item put_acks( I<SEVR>, I<SUB> )
|
||||
|
||||
Applications that need to ackowledge alarms by doing a C<ca_put()> with type
|
||||
Applications that need to acknowledge alarms by doing a C<ca_put()> with type
|
||||
C<DBR_PUT_ACKS> can do so using the C<put_acks> method. The severity argument
|
||||
may be provided as an integer from zero through three or as a string containing
|
||||
one of the corresponding EPICS severity names C<NO_ALARM>, C<MINOR>, C<MAJOR> or
|
||||
@@ -316,6 +316,19 @@ channel; see the C<new> constructor for details. If I<SUB> is C<undef> any
|
||||
existing handler is removed, otherwise the new subroutine will be used for all
|
||||
future connection events on this channel.
|
||||
|
||||
|
||||
=item change_access_rights_event( I<SUB> )
|
||||
|
||||
This method replaces, adds or cancels an access rights handler subroutine for
|
||||
the channel, which will be called if the client's right to read from or write
|
||||
to the channel changes. If I<SUB> is C<undef> any existing handler is removed,
|
||||
otherwise the new subroutine will be used for all future rights change events
|
||||
on this channel.
|
||||
|
||||
The arguments passed to I<SUB> are the channel object and a pair of scalar
|
||||
values for read and write permissions respectively, that are true when the
|
||||
access is permitted, false when it is not.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
@@ -325,11 +338,12 @@ The data provided to a callback function registered with either C<get_callback>
|
||||
or C<create_subscription> can be a scalar value or a reference to an array or a
|
||||
hash, depending on the data type that was used for the data transfer. If the
|
||||
request was for a single item of one of the basic data types, the data argument
|
||||
will be a perl scalar that holds the value directly. If the request was for
|
||||
will be a Perl scalar that holds the value directly. If the request was for
|
||||
multiple items of one of the basic types, the data argument will be a reference
|
||||
to an array holding the data. There is one exception though; if the data type
|
||||
requested was for an array of C<DBF_CHAR> values that array will be represented
|
||||
as a single Perl string contining all the characters before the first zero byte.
|
||||
as a single Perl string containing all the characters before the first zero
|
||||
byte.
|
||||
|
||||
If the request was for one of the compound data types, the data argument will be
|
||||
a reference to a hash with keys as described below. Keys that are not classed
|
||||
@@ -355,7 +369,7 @@ widened from the original type used to request or subscribe for the data.
|
||||
The number of elements in the data returned by the server. If the data type is
|
||||
C<DBF_CHAR> the value given for C<COUNT> is the number of bytes (including any
|
||||
trailing zeros) returned by the server, although the value field is given as a
|
||||
Perl string contining all the characters before the first zero byte.
|
||||
Perl string containing all the characters before the first zero byte.
|
||||
|
||||
=back
|
||||
|
||||
@@ -417,7 +431,7 @@ Present only when I<TYPE> is C<DBR_GR_ENUM> or C<DBR_CTRL_ENUM>.
|
||||
=item stamp
|
||||
|
||||
The process variable timestamp, converted to a local C<time_t>. This value is
|
||||
suitable for passing to the perl C<localtime> or C<gmtime> functions.
|
||||
suitable for passing to the Perl C<localtime> or C<gmtime> functions.
|
||||
|
||||
Present only when I<TYPE> is C<DBR_TIME_yyy>.
|
||||
|
||||
@@ -620,15 +634,15 @@ passing C<undef> as the subroutine reference.
|
||||
|
||||
Errors in using the library will be indicated by the module throwing an
|
||||
exception, i.e. calling C<croak()> with an appropriate error message. These
|
||||
exceptions can be caught using the standard Parl C<eval {}> statement and
|
||||
exceptions can be caught using the standard Perl C<eval {}> statement and
|
||||
testing the C<$@> variable afterwards; if not caught, they will cause the
|
||||
running program to C<die> with an appropriate error message pointing to the
|
||||
program line that called the C<CA> library.
|
||||
|
||||
Errors messages reported by the underlying CA client library all start with the
|
||||
Error messages reported by the underlying CA client library all start with the
|
||||
string C<ECA_> and the remainder of the symbol for the associated CA error
|
||||
number, and are followed after a space-hyphen-space by a human-readable message
|
||||
describing the error. Errors that are detected by the perl interface layer do
|
||||
describing the error. Errors that are detected by the Perl interface layer do
|
||||
not follow this pattern, but are still printable strings.
|
||||
|
||||
|
||||
@@ -636,9 +650,9 @@ not follow this pattern, but are still printable strings.
|
||||
|
||||
=over
|
||||
|
||||
=item [1] R3.14 Channel Access Reference Manual by Jeffrey O. Hill
|
||||
=item [1] R3.15 Channel Access Reference Manual by Jeffrey O. Hill
|
||||
|
||||
L<http://www.aps.anl.gov/epics/base/R3-14/12-docs/CAref.html>
|
||||
L<http://www.aps.anl.gov/epics/base/R3-15/0-docs/CAref.html>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
@@ -519,6 +519,46 @@ void CA_change_connection_event(SV *ca_ref, SV *sub) {
|
||||
}
|
||||
}
|
||||
|
||||
/* CA::replace_access_rights_event($ca_ref, \$sub) */
|
||||
|
||||
static
|
||||
void rights_handler(struct access_rights_handler_args arha) {
|
||||
CA_channel *pch = ca_puser(arha.chid);
|
||||
|
||||
PERL_SET_CONTEXT(p5_ctx);
|
||||
{
|
||||
dSP;
|
||||
|
||||
SvSetSV(ERRSV, &PL_sv_undef);
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(pch->chan_ref);
|
||||
XPUSHs(arha.ar.read_access ? &PL_sv_yes : &PL_sv_no);
|
||||
XPUSHs(arha.ar.write_access ? &PL_sv_yes : &PL_sv_no);
|
||||
PUTBACK;
|
||||
|
||||
call_sv(pch->rights_sub, G_EVAL | G_VOID | G_DISCARD | G_KEEPERR);
|
||||
|
||||
if (SvTRUE(ERRSV))
|
||||
croak(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void CA_replace_access_rights_event(SV *ca_ref, SV *sub) {
|
||||
CA_channel *pch = (CA_channel *)SvIV(SvRV(ca_ref));
|
||||
caArh *handler = &rights_handler;
|
||||
int status;
|
||||
|
||||
if (! replace_handler(sub, &pch->rights_sub, (long *)&handler))
|
||||
return;
|
||||
|
||||
status = ca_replace_access_rights_event(pch->chan, handler);
|
||||
|
||||
if (status != ECA_NORMAL) {
|
||||
croak("%s", get_error_msg(status));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* CA::put($ca_ref, @values) */
|
||||
|
||||
@@ -914,16 +954,18 @@ SV * CA_create_subscription(SV *ca_ref, const char *mask_str, SV *sub, ...) {
|
||||
|
||||
dbr_text_to_type(treq, type);
|
||||
if (type < 0) {
|
||||
croak_msg = "Unknown data type";
|
||||
croak_msg = "Unknown CA data type";
|
||||
goto exit_croak;
|
||||
}
|
||||
if (type == DBR_PUT_ACKT ||
|
||||
type == DBR_PUT_ACKS) {
|
||||
croak_msg = "DBR_PUT_ACK types are write-only";
|
||||
goto exit_croak;
|
||||
} else if (type == DBR_CLASS_NAME ||
|
||||
} else if (type == DBR_GR_ENUM ||
|
||||
type == DBR_CTRL_ENUM ||
|
||||
type == DBR_CLASS_NAME ||
|
||||
type == DBR_STSACK_STRING)
|
||||
/* These break the dbr_type_is macros */ ;
|
||||
/* These above types are supported */ ;
|
||||
else if (dbr_type_is_SHORT(type))
|
||||
type += (DBR_LONG - DBR_SHORT);
|
||||
else if (dbr_type_is_FLOAT(type))
|
||||
@@ -1265,6 +1307,11 @@ CA_change_connection_event (ca_ref, sub)
|
||||
SV * ca_ref
|
||||
SV * sub
|
||||
|
||||
void
|
||||
CA_replace_access_rights_event (ca_ref, sub)
|
||||
SV * ca_ref
|
||||
SV * sub
|
||||
|
||||
void
|
||||
CA_put (ca_ref, val, ...)
|
||||
SV * ca_ref
|
||||
|
||||
@@ -8,18 +8,16 @@
|
||||
TOP=../../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
|
||||
# Use hdepends command (not GNU compiler flags)
|
||||
# to generate header file dependancies for Darwin.
|
||||
# Darwin has multiple -arch compiler flags.
|
||||
# Special settings for Darwin:
|
||||
ifeq ($(OS_CLASS),Darwin)
|
||||
HDEPENDS_METHOD = MKMF
|
||||
endif
|
||||
# Use hdepends command (not GNU compiler flags)
|
||||
# to generate header file dependancies for Darwin.
|
||||
# Darwin has multiple -arch compiler flags.
|
||||
HDEPENDS_METHOD = MKMF
|
||||
|
||||
ifneq ($(findstring darwin,$(T_A)),)
|
||||
# Perl loadable libraries on Darwin have funny names
|
||||
LOADABLE_SHRLIB_PREFIX =
|
||||
LOADABLE_SHRLIB_SUFFIX = .bundle
|
||||
LOADABLE_SHRLIB_SUFFIX = .$(shell $(PERL) ../perlConfig.pl dlext)
|
||||
endif
|
||||
|
||||
PERL_VERSION = $(shell $(PERL) ../perlConfig.pl version)
|
||||
@@ -56,10 +54,11 @@ include $(TOP)/configure/RULES
|
||||
|
||||
ifdef T_A
|
||||
EXTUTILS = $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
|
||||
XSUBPP = $(firstword $(wildcard /usr/bin/xsubpp $(EXTUTILS)/xsubpp))
|
||||
|
||||
%.c: ../%.xs
|
||||
$(RM) $@ $@_new
|
||||
$(PERL) $(EXTUTILS)/xsubpp -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@
|
||||
$(PERL) $(XSUBPP) -typemap $(EXTUTILS)/typemap $< > $@_new && $(MV) $@_new $@
|
||||
|
||||
$(INSTALL_PERL_MODULES)/$(PERL_ARCHPATH)/%: %
|
||||
$(ECHO) "Installing loadable shared library $@"
|
||||
|
||||
@@ -160,11 +160,21 @@ char *val2str (const void *v, unsigned type, int index)
|
||||
case DBR_ENUM:
|
||||
{
|
||||
dbr_enum_t *val = (dbr_enum_t *)val_ptr;
|
||||
if (dbr_type_is_GR(type) && !enumAsNr)
|
||||
sprintf(str, "%s", ((struct dbr_gr_enum *)v)->strs[val[index]]);
|
||||
else if (dbr_type_is_CTRL(type) && !enumAsNr)
|
||||
sprintf(str, "%s", ((struct dbr_ctrl_enum *)v)->strs[val[index]]);
|
||||
else
|
||||
if (dbr_type_is_GR(type) && !enumAsNr) {
|
||||
if (val[index] >= MAX_ENUM_STATES)
|
||||
sprintf(str, "Illegal Value (%d)", val[index]);
|
||||
else if (val[index] >= ((struct dbr_gr_enum *)v)->no_str)
|
||||
sprintf(str, "Enum Index Overflow (%d)", val[index]);
|
||||
else
|
||||
sprintf(str, "%s", ((struct dbr_gr_enum *)v)->strs[val[index]]);
|
||||
} else if (dbr_type_is_CTRL(type) && !enumAsNr) {
|
||||
if (val[index] >= MAX_ENUM_STATES)
|
||||
sprintf(str, "Illegal Value (%d)", val[index]);
|
||||
else if (val[index] >= ((struct dbr_ctrl_enum *)v)->no_str)
|
||||
sprintf(str, "Enum Index Overflow (%d)", val[index]);
|
||||
else
|
||||
sprintf(str, "%s", ((struct dbr_ctrl_enum *)v)->strs[val[index]]);
|
||||
} else
|
||||
sprintf(str, "%d", val[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,10 +164,9 @@ struct sockaddr caNetAddr::getSock() const
|
||||
throw std::logic_error ( "caNetAddr::getSock (): address wasnt IP" );
|
||||
}
|
||||
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in *psain = reinterpret_cast <struct sockaddr_in*> ( & sa );
|
||||
*psain = this->addr.ip;
|
||||
return sa;
|
||||
osiSockAddr addr;
|
||||
addr.ia = this->addr.ip;
|
||||
return addr.sa;
|
||||
}
|
||||
|
||||
caNetAddr::operator sockaddr_in () const
|
||||
|
||||
@@ -40,25 +40,25 @@ INC += db_access_routines.h
|
||||
INC += db_convert.h
|
||||
INC += dbUnitTest.h
|
||||
|
||||
# Generate menuGlobal.dbd automatically
|
||||
DBD += menuGlobal.dbd
|
||||
# Generate menuGlobal.dbd, not really by concatenation, see RULES
|
||||
DBDCAT += menuGlobal.dbd
|
||||
menuGlobal_DBD += menuAlarmSevr.dbd
|
||||
menuGlobal_DBD += menuAlarmStat.dbd
|
||||
menuGlobal_DBD += menuCompress.dbd
|
||||
menuGlobal_DBD += menuFtype.dbd
|
||||
menuGlobal_DBD += menuIvoa.dbd
|
||||
menuGlobal_DBD += menuOmsl.dbd
|
||||
menuGlobal_DBD += menuPini.dbd
|
||||
menuGlobal_DBD += menuPost.dbd
|
||||
menuGlobal_DBD += menuPriority.dbd
|
||||
menuGlobal_DBD += menuScan.dbd
|
||||
menuGlobal_DBD += menuYesNo.dbd
|
||||
menuGlobal_DBD += menuSimm.dbd
|
||||
|
||||
DBDINC += $(basename $(menuGlobal_DBD))
|
||||
DBDINC += menuScan
|
||||
DBDINC += dbCommon
|
||||
|
||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(notdir $(wildcard ../db/menu*.dbd.pod)))
|
||||
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
|
||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(menusPod))
|
||||
|
||||
dbCore_SRCS += dbLock.c
|
||||
dbCore_SRCS += dbAccess.c
|
||||
|
||||
@@ -14,9 +14,14 @@
|
||||
dbCommon.h$(DEP): $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
|
||||
@$(RM) $@
|
||||
@$(DBTORECORDTYPEH) -D -I ../db -o $(COMMONDEP_TARGET) $< > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
$(COMMON_DIR)/dbCommon.h: $(IOCDIR)/db/dbCommonRecord.dbd
|
||||
$(COMMON_DIR)/dbCommon.h: $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
|
||||
@$(RM) $(notdir $@)
|
||||
$(DBTORECORDTYPEH) -I ../db -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/menuGlobal.dbd: $(IOCDIR)/db/Makefile $(IOCDIR)/db/RULES
|
||||
|
||||
# This is a target-specific variable
|
||||
$(COMMON_DIR)/menuGlobal.dbd: DBDCAT_COMMAND = \
|
||||
$(PERL) $(TOOLS)/makeIncludeDbd.pl $(menuGlobal_DBD) $(@F)
|
||||
|
||||
@@ -65,6 +65,10 @@
|
||||
epicsShareDef struct dbBase *pdbbase = 0;
|
||||
epicsShareDef volatile int interruptAccept=FALSE;
|
||||
|
||||
/* Hook Routines */
|
||||
|
||||
epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
|
||||
|
||||
static short mapDBFToDBR[DBF_NTYPES] = {
|
||||
/* DBF_STRING => */ DBR_STRING,
|
||||
/* DBF_CHAR => */ DBR_CHAR,
|
||||
@@ -711,7 +715,11 @@ int dbLoadDatabase(const char *file, const char *path, const char *subs)
|
||||
|
||||
int dbLoadRecords(const char* file, const char* subs)
|
||||
{
|
||||
return dbReadDatabase(&pdbbase, file, 0, subs);
|
||||
int status = dbReadDatabase(&pdbbase, file, 0, subs);
|
||||
|
||||
if (!status && dbLoadRecordsHook)
|
||||
dbLoadRecordsHook(file, subs);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -835,17 +843,15 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
|
||||
/* For array field, the rset function
|
||||
/* For SPC_DBADDR fields, the rset function
|
||||
* get_array_info() is allowed to modify
|
||||
* paddr->pfield. So we store the original
|
||||
* value and restore it later.
|
||||
*/
|
||||
pfieldsave = paddr->pfield;
|
||||
|
||||
/* check for array */
|
||||
if ((!pfl || pfl->type == dbfl_type_rec) &&
|
||||
paddr->pfldDes->special == SPC_DBADDR &&
|
||||
no_elements > 1 &&
|
||||
/* Update field info */
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
(prset = dbGetRset(paddr)) &&
|
||||
prset->get_array_info) {
|
||||
status = prset->get_array_info(paddr, &no_elements, &offset);
|
||||
@@ -1171,7 +1177,9 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
long no_elements = paddr->no_elements;
|
||||
long special = paddr->special;
|
||||
void *pfieldsave = paddr->pfield;
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
long status = 0;
|
||||
long offset;
|
||||
dbFldDes *pfldDes;
|
||||
int isValueField;
|
||||
|
||||
@@ -1195,31 +1203,32 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
if (status) return status;
|
||||
}
|
||||
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
} else
|
||||
offset = 0;
|
||||
|
||||
if (no_elements <= 1) {
|
||||
status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
|
||||
paddr->pfield, paddr);
|
||||
nRequest = 1;
|
||||
} else {
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
long offset = 0;
|
||||
if (no_elements < nRequest)
|
||||
nRequest = no_elements;
|
||||
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
|
||||
nRequest, no_elements, offset);
|
||||
}
|
||||
if (status) goto done;
|
||||
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
}
|
||||
if (no_elements < nRequest) nRequest = no_elements;
|
||||
if (!status)
|
||||
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
|
||||
nRequest, no_elements, offset);
|
||||
|
||||
/* update array info */
|
||||
if (!status &&
|
||||
paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
}
|
||||
/* update array info */
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
}
|
||||
if (status) goto done;
|
||||
|
||||
|
||||
@@ -233,9 +233,14 @@ epicsShareFunc long dbBufferSize(
|
||||
short dbrType,long options,long nRequest);
|
||||
epicsShareFunc long dbValueSize(short dbrType);
|
||||
|
||||
/* Hook Routine */
|
||||
|
||||
typedef void (*DB_LOAD_RECORDS_HOOK_ROUTINE)(const char* filename,
|
||||
const char* substitutions);
|
||||
epicsShareExtern DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook;
|
||||
|
||||
epicsShareFunc int dbLoadDatabase(
|
||||
const char *filename, const char *path, const char *substitutions);
|
||||
|
||||
epicsShareFunc int dbLoadRecords(
|
||||
const char* filename, const char* substitutions);
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
@@ -252,11 +251,6 @@ static long FIND_CONT_NODE(
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void dbBkptExit(void *junk) {
|
||||
epicsMutexDestroy(bkpt_stack_sem);
|
||||
bkpt_stack_sem = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the breakpoint stack
|
||||
*/
|
||||
@@ -265,7 +259,6 @@ void dbBkptInit(void)
|
||||
if (! bkpt_stack_sem) {
|
||||
bkpt_stack_sem = epicsMutexMustCreate();
|
||||
lset_stack_count = 0;
|
||||
epicsAtExit(dbBkptExit, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ void dbcaStats(int *pchans, int *pdiscon)
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
|
||||
ncalinks++;
|
||||
if (pca && ca_state(pca->chid) == cs_conn) {
|
||||
if (pca && pca->chid && ca_state(pca->chid) == cs_conn) {
|
||||
nconnected++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ static void *dbChannelFreeList;
|
||||
static void *chFilterFreeList;
|
||||
static void *dbchStringFreeList;
|
||||
|
||||
static void dbChannelExit(void* junk)
|
||||
void dbChannelExit(void)
|
||||
{
|
||||
freeListCleanup(dbChannelFreeList);
|
||||
freeListCleanup(chFilterFreeList);
|
||||
@@ -69,7 +69,6 @@ void dbChannelInit (void)
|
||||
freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
|
||||
freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
|
||||
freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
|
||||
epicsAtExit(dbChannelExit, NULL);
|
||||
}
|
||||
|
||||
static void chf_value(parseContext *parser, parse_result *presult)
|
||||
@@ -762,7 +761,7 @@ void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
|
||||
void *p;
|
||||
struct dbCommon *prec = dbChannelRecord(chan);
|
||||
|
||||
if (!pfl->type == dbfl_type_rec) return;
|
||||
if (pfl->type != dbfl_type_rec) return;
|
||||
|
||||
pfl->type = dbfl_type_ref;
|
||||
pfl->stat = prec->stat;
|
||||
|
||||
@@ -150,6 +150,7 @@ struct dbCommon;
|
||||
struct dbFldDes;
|
||||
|
||||
epicsShareFunc void dbChannelInit (void);
|
||||
epicsShareFunc void dbChannelExit(void);
|
||||
epicsShareFunc long dbChannelTest(const char *name);
|
||||
epicsShareFunc dbChannel * dbChannelCreate(const char *name);
|
||||
epicsShareFunc long dbChannelOpen(dbChannel *chan);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbLock.h"
|
||||
#include "link.h"
|
||||
#include "special.h"
|
||||
|
||||
#define EVENTSPERQUE 32
|
||||
#define EVENTENTRIES 4 /* the number of que entries for each event */
|
||||
@@ -452,7 +453,8 @@ dbEventSubscription db_add_event (
|
||||
* communication (for other types they get whatever happens to be
|
||||
* there upon wakeup)
|
||||
*/
|
||||
if( dbChannelElements(chan) == 1 &&
|
||||
if (dbChannelElements(chan) == 1 &&
|
||||
dbChannelSpecial(chan) != SPC_DBADDR &&
|
||||
dbChannelFieldSize(chan) <= sizeof(union native_value)) {
|
||||
pevent->useValque = TRUE;
|
||||
}
|
||||
@@ -824,7 +826,7 @@ unsigned int caEventMask
|
||||
|
||||
/*
|
||||
* Only send event msg if they are waiting on the field which
|
||||
* changed or pval==NULL and waiting on alarms and alarms changed
|
||||
* changed or pval==NULL, and are waiting on matching event
|
||||
*/
|
||||
if ( (dbChannelField(pevent->chan) == (void *)pField || pField==NULL) &&
|
||||
(caEventMask & pevent->select)) {
|
||||
|
||||
@@ -110,15 +110,6 @@ typedef struct lockRecord {
|
||||
dbCommon *precord;
|
||||
} lockRecord;
|
||||
|
||||
static void dbLockExit(void *junk)
|
||||
{
|
||||
epicsMutexDestroy(globalLock);
|
||||
epicsMutexDestroy(lockSetModifyLock);
|
||||
globalLock = NULL;
|
||||
lockSetModifyLock = NULL;
|
||||
dbLockIsInitialized = FALSE;
|
||||
}
|
||||
|
||||
/*private routines */
|
||||
static void dbLockInitialize(void)
|
||||
{
|
||||
@@ -129,7 +120,6 @@ static void dbLockInitialize(void)
|
||||
globalLock = epicsMutexMustCreate();
|
||||
lockSetModifyLock = epicsMutexMustCreate();
|
||||
dbLockIsInitialized = TRUE;
|
||||
epicsAtExit(dbLockExit,NULL);
|
||||
}
|
||||
|
||||
static lockSet * allocLockSet(
|
||||
|
||||
@@ -299,7 +299,7 @@ static void notifyCallback(CALLBACK *pcallback)
|
||||
callDone(precord, ppn);
|
||||
}
|
||||
|
||||
static void dbProcessNotifyExit(void* junk)
|
||||
void dbProcessNotifyExit(void)
|
||||
{
|
||||
assert(ellCount(&pnotifyGlobal->freeList)==0);
|
||||
epicsMutexDestroy(pnotifyGlobal->lock);
|
||||
@@ -314,7 +314,6 @@ void dbProcessNotifyInit(void)
|
||||
pnotifyGlobal = dbCalloc(1,sizeof(notifyGlobal));
|
||||
pnotifyGlobal->lock = epicsMutexMustCreate();
|
||||
ellInit(&pnotifyGlobal->freeList);
|
||||
epicsAtExit(dbProcessNotifyExit, NULL);
|
||||
}
|
||||
|
||||
void dbProcessNotify(processNotify *ppn)
|
||||
|
||||
@@ -76,6 +76,7 @@ epicsShareFunc void dbNotifyCancel(processNotify *pprocessNotify);
|
||||
|
||||
/* dbProcessNotifyInit called by iocInit */
|
||||
epicsShareFunc void dbProcessNotifyInit(void);
|
||||
epicsShareFunc void dbProcessNotifyExit(void);
|
||||
|
||||
/*dbNotifyAdd called by dbScanPassive and dbScanLink*/
|
||||
epicsShareFunc void dbNotifyAdd(
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE Versions 3.13.7
|
||||
# and higher are distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
menu(menuCompress) {
|
||||
choice(menuCompressN_to_1_First_Value,"N to 1 First Value")
|
||||
choice(menuCompressN_to_1_Low_Value,"N to 1 Low Value")
|
||||
choice(menuCompressN_to_1_High_Value,"N to 1 High Value")
|
||||
choice(menuCompressN_to_1_Average,"N to 1 Average")
|
||||
}
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
/* Hook Routines */
|
||||
|
||||
RECGBL_ALARM_HOOK_ROUTINE recGblAlarmHook = NULL;
|
||||
epicsShareDef RECGBL_ALARM_HOOK_ROUTINE recGblAlarmHook = NULL;
|
||||
|
||||
/* local routines */
|
||||
static void getMaxRangeValues(short field_type, double *pupper_limit,
|
||||
|
||||
@@ -36,7 +36,7 @@ struct dbCommon;
|
||||
|
||||
typedef void (*RECGBL_ALARM_HOOK_ROUTINE)(struct dbCommon *prec,
|
||||
epicsEnum16 prev_sevr, epicsEnum16 prev_stat);
|
||||
extern RECGBL_ALARM_HOOK_ROUTINE recGblAlarmHook;
|
||||
epicsShareExtern RECGBL_ALARM_HOOK_ROUTINE recGblAlarmHook;
|
||||
|
||||
/* Global Record Support Routines */
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ dbTestIoc_LIBS = dbCore
|
||||
TARGETS += $(COMMON_DIR)/dbTestIoc.dbd
|
||||
dbTestIoc_DBD += menuGlobal.dbd
|
||||
dbTestIoc_DBD += menuConvert.dbd
|
||||
dbTestIoc_DBD += menuScan.dbd
|
||||
dbTestIoc_DBD += xRecord.dbd
|
||||
dbTestIoc_DBD += dbLinkdset.dbd
|
||||
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
|
||||
@@ -67,9 +68,17 @@ dbStateTest_SRCS += dbStateTest.c
|
||||
testHarness_SRCS += dbStateTest.c
|
||||
TESTS += dbStateTest
|
||||
|
||||
TESTPROD_HOST += dbCaStatsTest
|
||||
dbCaStatsTest_SRCS += dbCaStatsTest.c
|
||||
dbCaStatsTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbCaStatsTest.c
|
||||
TESTS += dbCaStatsTest
|
||||
TESTFILES += ../dbCaStatsTest.db
|
||||
|
||||
TARGETS += $(COMMON_DIR)/scanIoTest.dbd
|
||||
scanIoTest_DBD += menuGlobal.dbd
|
||||
scanIoTest_DBD += menuConvert.dbd
|
||||
scanIoTest_DBD += menuScan.dbd
|
||||
scanIoTest_DBD += yRecord.dbd
|
||||
TESTPROD_HOST += scanIoTest
|
||||
scanIoTest_SRCS += scanIoTest.c
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "chfPlugin.h"
|
||||
#include "dbStaticLib.h"
|
||||
@@ -540,7 +541,7 @@ MAIN(chfPluginTest)
|
||||
dbChannel *pch;
|
||||
db_field_log *pfl;
|
||||
|
||||
#ifdef WIN32
|
||||
#if defined(WIN32) && (!defined(_MINGW) || __MSVCRT_VERSION__ >= 0x0800)
|
||||
_set_output_format(_TWO_DIGIT_EXPONENT);
|
||||
#endif
|
||||
|
||||
|
||||
4
src/ioc/db/test/dbCaStats.db
Normal file
4
src/ioc/db/test/dbCaStats.db
Normal file
@@ -0,0 +1,4 @@
|
||||
record(x, "e1") {
|
||||
}
|
||||
record(x, "e2") {
|
||||
}
|
||||
73
src/ioc/db/test/dbCaStatsTest.c
Normal file
73
src/ioc/db/test/dbCaStatsTest.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2014 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <ralph.lange@gmx.de>
|
||||
*/
|
||||
|
||||
#include "dbCaTest.h"
|
||||
#include "dbAccess.h"
|
||||
|
||||
#include "dbUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#include "dbAccess.h"
|
||||
#include "errlog.h"
|
||||
|
||||
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
static
|
||||
void testCaStats(void) {
|
||||
int channels;
|
||||
int disconnected;
|
||||
|
||||
testDiag("Check dbcaStats");
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
|
||||
dbTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
testdbReadDatabase("dbCaStats.db", NULL, NULL);
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
|
||||
testDiag("No CA links");
|
||||
|
||||
channels = disconnected = -1;
|
||||
dbcaStats(&channels, &disconnected);
|
||||
|
||||
testOk(channels==0, "channels==0 (got %d)", channels);
|
||||
testOk(disconnected==0, "disconnected==0 (got %d)", disconnected);
|
||||
|
||||
|
||||
testDiag("One CA link, disconnected");
|
||||
|
||||
testdbPutFieldOk("e2.INP", DBR_STRING, "e12 CA", 1);
|
||||
|
||||
channels = disconnected = -1;
|
||||
dbcaStats(&channels, &disconnected);
|
||||
|
||||
testOk(channels==1, "channels==1 (got %d)", channels);
|
||||
testOk(disconnected==1, "disconnected==1 (got %d)", disconnected);
|
||||
|
||||
/* Connected CA links can not be tested without fully starting the IOC
|
||||
which we will skip for the moment as it is not allowed inside the vxWorks/RTEMS test harness.
|
||||
The above is good enough to check for bug lp:1394212 */
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
MAIN(dbCaStatsTest)
|
||||
{
|
||||
testPlan(0);
|
||||
testCaStats();
|
||||
return testDone();
|
||||
}
|
||||
@@ -18,7 +18,9 @@
|
||||
|
||||
int testdbConvert(void);
|
||||
int callbackTest(void);
|
||||
int callbackParallelTest(void);
|
||||
int dbStateTest(void);
|
||||
int dbCaStatsTest(void);
|
||||
int dbShutdownTest(void);
|
||||
int scanIoTest(void);
|
||||
int dbLockTest(void);
|
||||
@@ -34,7 +36,9 @@ void epicsRunDbTests(void)
|
||||
|
||||
runTest(testdbConvert);
|
||||
runTest(callbackTest);
|
||||
runTest(callbackParallelTest);
|
||||
runTest(dbStateTest);
|
||||
runTest(dbCaStatsTest);
|
||||
runTest(dbShutdownTest);
|
||||
runTest(scanIoTest);
|
||||
runTest(dbLockTest);
|
||||
|
||||
@@ -315,7 +315,7 @@ MAIN(scanIoTest)
|
||||
}
|
||||
}
|
||||
|
||||
epicsThreadSleep(0.1);
|
||||
epicsThreadSleep(1.0);
|
||||
|
||||
testOk((orderFail==0), "No out-of-order processing");
|
||||
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
static enum {
|
||||
iocVirgin, iocBuilding, iocBuilt, iocRunning, iocPaused, iocStopped
|
||||
} iocState = iocVirgin;
|
||||
static enum {
|
||||
buildRSRV, buildIsolated
|
||||
} iocBuildMode;
|
||||
|
||||
/* define forward references*/
|
||||
static int checkDatabase(dbBase *pdbbase);
|
||||
@@ -183,6 +186,7 @@ int iocBuild(void)
|
||||
rsrv_init();
|
||||
|
||||
status = iocBuild_3();
|
||||
if (!status) iocBuildMode = buildRSRV;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -199,6 +203,7 @@ int iocBuildIsolated(void)
|
||||
if (status) return status;
|
||||
|
||||
status = iocBuild_3();
|
||||
if (!status) iocBuildMode = buildIsolated;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -672,13 +677,18 @@ int iocShutdown(void)
|
||||
{
|
||||
if (iocState == iocVirgin || iocState == iocStopped) return 0;
|
||||
iterateRecords(doCloseLinks, NULL);
|
||||
scanShutdown();
|
||||
callbackShutdown();
|
||||
iterateRecords(doFreeRecord, NULL);
|
||||
dbLockCleanupRecords(pdbbase);
|
||||
asShutdown();
|
||||
iocshFree();
|
||||
if (iocBuildMode==buildIsolated) {
|
||||
scanShutdown();
|
||||
callbackShutdown();
|
||||
iterateRecords(doFreeRecord, NULL);
|
||||
dbLockCleanupRecords(pdbbase);
|
||||
asShutdown();
|
||||
dbChannelExit();
|
||||
dbProcessNotifyExit();
|
||||
iocshFree();
|
||||
}
|
||||
iocState = iocStopped;
|
||||
iocBuildMode = buildRSRV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -453,15 +453,6 @@ static void errlogExitHandler(void *pvt)
|
||||
pvtData.atExit = 1;
|
||||
epicsEventSignal(pvtData.waitForWork);
|
||||
epicsEventMustWait(pvtData.waitForExit);
|
||||
|
||||
free(pvtData.pbuffer);
|
||||
epicsMutexDestroy(pvtData.flushLock);
|
||||
epicsEventDestroy(pvtData.flush);
|
||||
epicsEventDestroy(pvtData.waitForFlush);
|
||||
epicsMutexDestroy(pvtData.listenerLock);
|
||||
epicsMutexDestroy(pvtData.msgQueueLock);
|
||||
epicsEventDestroy(pvtData.waitForWork);
|
||||
epicsEventDestroy(pvtData.waitForExit);
|
||||
}
|
||||
|
||||
struct initArgs {
|
||||
|
||||
@@ -13,7 +13,7 @@ SRC_DIRS += $(LIBCOM)/flex
|
||||
|
||||
parse_YACCOPT = -l -d
|
||||
|
||||
SKELETON_FILE = include/flex.skel.static
|
||||
SKELETON_FILE = flex.skel.static
|
||||
|
||||
parse_CPPFLAGS = -DDEFAULT_SKELETON_FILE=$(SKELETON_FILE)
|
||||
|
||||
|
||||
@@ -59,7 +59,10 @@ static void echoCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
char *str = args[0].sval;
|
||||
|
||||
dbTranslateEscape(str, str); /* in-place is safe */
|
||||
if (str)
|
||||
dbTranslateEscape(str, str); /* in-place is safe */
|
||||
else
|
||||
str = "";
|
||||
printf("%s\n", str);
|
||||
}
|
||||
|
||||
@@ -69,9 +72,8 @@ static const iocshArg * const chdirArgs[1] = {&chdirArg0};
|
||||
static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs};
|
||||
static void chdirCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
int status;
|
||||
status = chdir(args[0].sval);
|
||||
if (status) {
|
||||
if (args[0].sval == NULL ||
|
||||
chdir(args[0].sval)) {
|
||||
fprintf(stderr, "Invalid directory path, ignored\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "logClient.h"
|
||||
#include "iocLog.h"
|
||||
|
||||
@@ -90,9 +89,6 @@ static logClientId iocLogClientInit (void)
|
||||
return NULL;
|
||||
}
|
||||
id = logClientCreate (addr, port);
|
||||
if (id != NULL) {
|
||||
errlogAddListener ( logClientSendMessage, id );
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -139,13 +135,3 @@ logClientId epicsShareAPI logClientInit (void)
|
||||
{
|
||||
return iocLogClientInit ();
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientSendMessage (); deprecated
|
||||
*/
|
||||
void logClientSendMessage ( logClientId id, const char * message )
|
||||
{
|
||||
if ( !iocLogDisable ) {
|
||||
logClientSend (id, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "iocLog.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
@@ -152,6 +154,8 @@ static void logClientDestroy (logClientId id)
|
||||
return;
|
||||
}
|
||||
|
||||
errlogRemoveListeners ( logClientSendMessage, (void *) pClient );
|
||||
|
||||
logClientClose ( pClient );
|
||||
|
||||
epicsMutexDestroy ( pClient->mutex );
|
||||
@@ -545,6 +549,8 @@ logClientId epicsShareAPI logClientCreate (
|
||||
pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
|
||||
}
|
||||
|
||||
errlogAddListener ( logClientSendMessage, (void *) pClient );
|
||||
|
||||
return (void *) pClient;
|
||||
}
|
||||
|
||||
@@ -573,6 +579,16 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientSendMessage (); deprecated
|
||||
*/
|
||||
void logClientSendMessage ( logClientId id, const char * message )
|
||||
{
|
||||
if ( !iocLogDisable ) {
|
||||
logClientSend (id, message);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* iocLogPrefix()
|
||||
*/
|
||||
|
||||
@@ -259,9 +259,10 @@ epicsShareAPI macPutValue(
|
||||
* a macro from all scopes will still be needed by iocshEnvClear
|
||||
*/
|
||||
while ( ( entry = lookup( handle, name, FALSE ) ) != NULL ) {
|
||||
int done = strcmp(entry->type, "environment variable") == 0;
|
||||
delete( handle, entry );
|
||||
|
||||
if (strcmp(entry->type, "environment variable") == 0)
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "ellLib.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "cantProceed.h"
|
||||
@@ -48,10 +49,13 @@ typedef struct exitPvt {
|
||||
int atExitDebug = 0;
|
||||
|
||||
static epicsThreadOnceId exitPvtOnce = EPICS_THREAD_ONCE_INIT;
|
||||
static epicsThreadOnceId exitLaterOnce = EPICS_THREAD_ONCE_INIT;
|
||||
static exitPvt * pExitPvtPerProcess = 0;
|
||||
static epicsMutexId exitPvtLock = 0;
|
||||
static epicsThreadPrivateId exitPvtPerThread = 0;
|
||||
|
||||
static int exitLaterStatus;
|
||||
|
||||
static void destroyExitPvt(exitPvt * pep)
|
||||
{
|
||||
ellFree ( &pep->list );
|
||||
@@ -179,6 +183,26 @@ epicsShareFunc void epicsExit(int status)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static void exitNow(void *junk)
|
||||
{
|
||||
epicsExit(exitLaterStatus);
|
||||
}
|
||||
|
||||
static void exitLaterOnceFunc(void *raw)
|
||||
{
|
||||
int *status = raw;
|
||||
exitLaterStatus = *status;
|
||||
epicsThreadMustCreate("exitLater",
|
||||
epicsThreadPriorityLow,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
&exitNow, NULL);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsExitLater(int status)
|
||||
{
|
||||
epicsThreadOnce(&exitLaterOnce, &exitLaterOnceFunc, &status);
|
||||
}
|
||||
|
||||
#include "epicsExport.h"
|
||||
|
||||
epicsExportAddress(int,atExitDebug);
|
||||
|
||||
@@ -18,6 +18,7 @@ extern "C" {
|
||||
typedef void (*epicsExitFunc)(void *arg);
|
||||
|
||||
epicsShareFunc void epicsExit(int status);
|
||||
epicsShareFunc void epicsExitLater(int status);
|
||||
epicsShareFunc void epicsExitCallAtExits(void);
|
||||
epicsShareFunc int epicsAtExit3(epicsExitFunc func, void *arg, const char* name);
|
||||
#define epicsAtExit(F,A) epicsAtExit3(F,A,#F)
|
||||
|
||||
@@ -367,8 +367,12 @@ epicsStrtod(const char *str, char **endp)
|
||||
else
|
||||
return strtoul(str, endp, 16);
|
||||
}
|
||||
if (!isalpha((int)*cp))
|
||||
return strtod(str, endp);
|
||||
if (!isalpha((int)*cp)) {
|
||||
res = strtod(str, endp);
|
||||
if (isinf(res))
|
||||
errno = ERANGE;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (epicsStrnCaseCmp("NAN", cp, 3) == 0) {
|
||||
res = epicsNAN;
|
||||
|
||||
@@ -29,143 +29,165 @@
|
||||
#include "epicsString.h"
|
||||
|
||||
/* Deprecated, use epicsStrnRawFromEscaped() instead */
|
||||
int dbTranslateEscape(char *to, const char *from)
|
||||
int dbTranslateEscape(char *dst, const char *src)
|
||||
{
|
||||
size_t big_enough = strlen(from)+1;
|
||||
return epicsStrnRawFromEscaped(to, big_enough, from, big_enough);
|
||||
size_t big_enough = strlen(src) + 1;
|
||||
|
||||
return epicsStrnRawFromEscaped(dst, big_enough, src, big_enough);
|
||||
}
|
||||
|
||||
int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from,
|
||||
size_t inlen)
|
||||
int epicsStrnRawFromEscaped(char *dst, size_t dstlen, const char *src,
|
||||
size_t srclen)
|
||||
{
|
||||
const char *pfrom = from;
|
||||
char *pto = to;
|
||||
char c;
|
||||
size_t nto = 0, nfrom = 0;
|
||||
int rem = dstlen;
|
||||
int ndst = 0;
|
||||
|
||||
while ((c = *pfrom++) && nto < outsize && nfrom < inlen) {
|
||||
nfrom++;
|
||||
if (c == '\\') {
|
||||
if (nfrom >= inlen || *pfrom == '\0') break;
|
||||
switch (*pfrom) {
|
||||
case 'a': pfrom++; nfrom++; *pto++ = '\a' ; nto++; break;
|
||||
case 'b': pfrom++; nfrom++; *pto++ = '\b' ; nto++; break;
|
||||
case 'f': pfrom++; nfrom++; *pto++ = '\f' ; nto++; break;
|
||||
case 'n': pfrom++; nfrom++; *pto++ = '\n' ; nto++; break;
|
||||
case 'r': pfrom++; nfrom++; *pto++ = '\r' ; nto++; break;
|
||||
case 't': pfrom++; nfrom++; *pto++ = '\t' ; nto++; break;
|
||||
case 'v': pfrom++; nfrom++; *pto++ = '\v' ; nto++; break;
|
||||
case '\\': pfrom++; nfrom++; *pto++ = '\\' ; nto++; break;
|
||||
case '\?': pfrom++; nfrom++; *pto++ = '\?' ; nto++; break;
|
||||
case '\'': pfrom++; nfrom++; *pto++ = '\'' ; nto++; break;
|
||||
case '\"': pfrom++; nfrom++; *pto++ = '\"' ; nto++; break;
|
||||
case '0' :case '1' :case '2' :case '3' :
|
||||
case '4' :case '5' :case '6' :case '7' :
|
||||
{
|
||||
int i;
|
||||
char strval[4] = {0,0,0,0};
|
||||
unsigned int ival;
|
||||
unsigned char *pchar;
|
||||
while (srclen--) {
|
||||
int c = *src++;
|
||||
#define OUT(chr) if (--rem > 0) ndst++, *dst++ = chr
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
if ((*pfrom < '0') || (*pfrom > '7')) break;
|
||||
strval[i] = *pfrom++; nfrom++;
|
||||
}
|
||||
sscanf(strval,"%o",&ival);
|
||||
pchar = (unsigned char *)(pto++); nto++;
|
||||
*pchar = (unsigned char)(ival);
|
||||
}
|
||||
break;
|
||||
case 'x' :
|
||||
{
|
||||
int i;
|
||||
char strval[3] = {0,0,0};
|
||||
unsigned int ival;
|
||||
unsigned char *pchar;
|
||||
if (!c) break;
|
||||
|
||||
pfrom++; /*skip the x*/
|
||||
for (i=0; i<2; i++) {
|
||||
if (!isxdigit((int)*pfrom)) break;
|
||||
strval[i] = *pfrom++; nfrom++;
|
||||
}
|
||||
sscanf(strval,"%x",&ival);
|
||||
pchar = (unsigned char *)(pto++); nto++;
|
||||
*pchar = (unsigned char)(ival);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*pto++ = *pfrom++; nfrom++; nto++;
|
||||
}
|
||||
} else {
|
||||
*pto++ = c; nto++;
|
||||
input:
|
||||
if (c != '\\') {
|
||||
OUT(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*pto = '\0'; /* NOTE that nto does not have to be incremented */
|
||||
return nto;
|
||||
}
|
||||
|
||||
int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf,
|
||||
size_t inlen)
|
||||
{
|
||||
int maxout = outsize;
|
||||
int nout = 0;
|
||||
int len;
|
||||
char *outpos = outbuf;
|
||||
if (!srclen-- || !(c = *src++)) break;
|
||||
|
||||
while (inlen--) {
|
||||
char c = *inbuf++;
|
||||
switch (c) {
|
||||
case '\a': len = epicsSnprintf(outpos, maxout, "\\a"); break;
|
||||
case '\b': len = epicsSnprintf(outpos, maxout, "\\b"); break;
|
||||
case '\f': len = epicsSnprintf(outpos, maxout, "\\f"); break;
|
||||
case '\n': len = epicsSnprintf(outpos, maxout, "\\n"); break;
|
||||
case '\r': len = epicsSnprintf(outpos, maxout, "\\r"); break;
|
||||
case '\t': len = epicsSnprintf(outpos, maxout, "\\t"); break;
|
||||
case '\v': len = epicsSnprintf(outpos, maxout, "\\v"); break;
|
||||
case '\\': len = epicsSnprintf(outpos, maxout, "\\\\"); ; break;
|
||||
case '\'': len = epicsSnprintf(outpos, maxout, "\\'"); break;
|
||||
case '\"': len = epicsSnprintf(outpos, maxout, "\\\""); break;
|
||||
default:
|
||||
if (isprint((int)c))
|
||||
len = epicsSnprintf(outpos, maxout, "%c", c);
|
||||
else
|
||||
len = epicsSnprintf(outpos, maxout, "\\%03o",
|
||||
(unsigned char)c);
|
||||
break;
|
||||
}
|
||||
if (len<0) return -1;
|
||||
nout += len;
|
||||
if (nout < outsize) {
|
||||
maxout -= len;
|
||||
outpos += len;
|
||||
} else {
|
||||
outpos = outpos + maxout -1;
|
||||
maxout = 1;
|
||||
case 'a': OUT('\a'); break;
|
||||
case 'b': OUT('\b'); break;
|
||||
case 'f': OUT('\f'); break;
|
||||
case 'n': OUT('\n'); break;
|
||||
case 'r': OUT('\r'); break;
|
||||
case 't': OUT('\t'); break;
|
||||
case 'v': OUT('\v'); break;
|
||||
case '\\': OUT('\\'); break;
|
||||
case '\'': OUT('\''); break;
|
||||
case '\"': OUT('\"'); break;
|
||||
|
||||
case '0' :case '1' :case '2' :case '3' :
|
||||
case '4' :case '5' :case '6' :case '7' :
|
||||
{ /* \ooo */
|
||||
unsigned int u = c - '0';
|
||||
|
||||
if (!srclen-- || !(c = *src++)) {
|
||||
OUT(u); goto done;
|
||||
}
|
||||
if (c < '0' || c > '7') {
|
||||
OUT(u); goto input;
|
||||
}
|
||||
u = u << 3 | (c - '0');
|
||||
|
||||
if (!srclen-- || !(c = *src++)) {
|
||||
OUT(u); goto done;
|
||||
}
|
||||
if (c < '0' || c > '7') {
|
||||
OUT(u); goto input;
|
||||
}
|
||||
u = u << 3 | (c - '0');
|
||||
|
||||
if (u > 0377) {
|
||||
/* Undefined behaviour! */
|
||||
}
|
||||
OUT(u);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'x' :
|
||||
{ /* \xXXX... */
|
||||
unsigned int u = 0;
|
||||
|
||||
if (!srclen-- || !(c = *src++))
|
||||
goto done;
|
||||
|
||||
while (isxdigit(c)) {
|
||||
u = u << 4 | ((c > '9') ? toupper(c) - 'A' + 10 : c - '0');
|
||||
if (u > 0xff) {
|
||||
/* Undefined behaviour! */
|
||||
}
|
||||
if (!srclen-- || !(c = *src++)) {
|
||||
OUT(u);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
OUT(u);
|
||||
goto input;
|
||||
}
|
||||
|
||||
default:
|
||||
OUT(c);
|
||||
}
|
||||
#undef OUT
|
||||
}
|
||||
*outpos = '\0';
|
||||
return nout;
|
||||
done:
|
||||
if (dstlen)
|
||||
*dst = '\0';
|
||||
return ndst;
|
||||
}
|
||||
|
||||
size_t epicsStrnEscapedFromRawSize(const char *inbuf, size_t inlen)
|
||||
int epicsStrnEscapedFromRaw(char *dst, size_t dstlen, const char *src,
|
||||
size_t srclen)
|
||||
{
|
||||
size_t nout = inlen;
|
||||
int rem = dstlen;
|
||||
int ndst = 0;
|
||||
|
||||
while (inlen--) {
|
||||
char c = *inbuf++;
|
||||
if (dst == src)
|
||||
return -1;
|
||||
|
||||
while (srclen--) {
|
||||
int c = *src++;
|
||||
#define OUT(chr) ndst++; if (--rem > 0) *dst++ = chr
|
||||
|
||||
switch (c) {
|
||||
case '\a': OUT('\\'); OUT('a'); break;
|
||||
case '\b': OUT('\\'); OUT('b'); break;
|
||||
case '\f': OUT('\\'); OUT('f'); break;
|
||||
case '\n': OUT('\\'); OUT('n'); break;
|
||||
case '\r': OUT('\\'); OUT('r'); break;
|
||||
case '\t': OUT('\\'); OUT('t'); break;
|
||||
case '\v': OUT('\\'); OUT('v'); break;
|
||||
case '\\': OUT('\\'); OUT('\\'); break;
|
||||
case '\'': OUT('\\'); OUT('\''); break;
|
||||
case '\"': OUT('\\'); OUT('\"'); break;
|
||||
default:
|
||||
if (isprint(c)) {
|
||||
OUT(c);
|
||||
break;
|
||||
}
|
||||
OUT('\\');
|
||||
OUT('0' + ((c & 0300) >> 6));
|
||||
OUT('0' + ((c & 0070) >> 3));
|
||||
OUT('0' + (c & 0007));
|
||||
}
|
||||
#undef OUT
|
||||
}
|
||||
if (dstlen)
|
||||
*dst = '\0';
|
||||
return ndst;
|
||||
}
|
||||
|
||||
size_t epicsStrnEscapedFromRawSize(const char *src, size_t srclen)
|
||||
{
|
||||
size_t ndst = srclen;
|
||||
|
||||
while (srclen--) {
|
||||
int c = *src++;
|
||||
|
||||
switch (c) {
|
||||
case '\a': case '\b': case '\f': case '\n':
|
||||
case '\r': case '\t': case '\v': case '\\':
|
||||
case '\'': case '\"':
|
||||
nout++;
|
||||
ndst++;
|
||||
break;
|
||||
default:
|
||||
if (!isprint((int)c))
|
||||
nout += 3;
|
||||
if (!isprint(c))
|
||||
ndst += 3;
|
||||
}
|
||||
}
|
||||
return nout;
|
||||
return ndst;
|
||||
}
|
||||
|
||||
int epicsStrCaseCmp(const char *s1, const char *s2)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define INC_epicsTypes_H
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifndef stringOf
|
||||
# if defined (__STDC__ ) || defined (__cplusplus)
|
||||
@@ -26,6 +27,11 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
epicsFalse = 0,
|
||||
epicsTrue = 1
|
||||
} epicsBoolean EPICS_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Architecture Independent Data Types
|
||||
* These are sufficient for all our current archs
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
@@ -57,8 +58,10 @@ static void thread_hook(epicsThreadId pthreadInfo)
|
||||
/* Set the name of the thread's process. Limited to 16 characters. */
|
||||
char comm[16];
|
||||
|
||||
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
|
||||
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
|
||||
if (strcmp(pthreadInfo->name, "_main_")) {
|
||||
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
|
||||
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
|
||||
}
|
||||
pthreadInfo->lwpId = syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
# define MS_InterlockedDecrement64 InterlockedDecrement64
|
||||
# define MS_InterlockedExchange64 InterlockedExchange64
|
||||
# define MS_InterlockedExchangeAdd64 InterlockedExchangeAdd64
|
||||
# define MS_InterlockedCompareExchange InterlockedCompareExchange64
|
||||
# define MS_InterlockedCompareExchange64 InterlockedCompareExchange64
|
||||
#endif
|
||||
|
||||
#include "epicsAtomicMS.h"
|
||||
|
||||
@@ -14,10 +14,15 @@
|
||||
|
||||
int epicsBackTrace(void **buf, int buf_sz)
|
||||
{
|
||||
/* Docs say that (for some windows versions) the sum of
|
||||
* skipped + captured frames must be less than 63
|
||||
*/
|
||||
if ( buf_sz >= 63 )
|
||||
buf_sz = 62;
|
||||
return CaptureStackBackTrace(0, buf_sz, buf, 0);
|
||||
#ifdef CaptureStackBackTrace
|
||||
/* Docs say that (for some windows versions) the sum of
|
||||
* skipped + captured frames must be less than 63
|
||||
*/
|
||||
if ( buf_sz >= 63 )
|
||||
buf_sz = 62;
|
||||
return CaptureStackBackTrace(0, buf_sz, buf, 0);
|
||||
#else
|
||||
/* Older versions of MinGW */
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ epicsShareFunc double epicsStrtod(const char *str, char **endp);
|
||||
* Older compilers have these equivalents though
|
||||
*/
|
||||
|
||||
#define strtoll _strtoi64
|
||||
#define strtoull _strtoui64
|
||||
#ifndef _MINGW
|
||||
# define strtoll _strtoi64
|
||||
# define strtoull _strtoui64
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsDynLink.h"
|
||||
#include "epicsFindSymbol.h"
|
||||
#include "epicsExit.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -21,15 +21,12 @@ typedef int (*sysAtReboot_t)(void(func)(void));
|
||||
|
||||
void atRebootRegister(void)
|
||||
{
|
||||
STATUS status;
|
||||
sysAtReboot_t sysAtReboot;
|
||||
SYM_TYPE type;
|
||||
sysAtReboot_t sysAtReboot = (sysAtReboot_t) epicsFindSymbol("_sysAtReboot");
|
||||
|
||||
status = symFindByNameEPICS(sysSymTbl, "_sysAtReboot",
|
||||
(char **)&sysAtReboot, &type);
|
||||
if (status == OK) {
|
||||
status = sysAtReboot(epicsExitCallAtExits);
|
||||
if (status != OK) {
|
||||
if (sysAtReboot) {
|
||||
STATUS status = sysAtReboot(epicsExitCallAtExits);
|
||||
|
||||
if (status) {
|
||||
printf("atReboot: sysAtReboot returned error %d\n", status);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,92 +1,95 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* $Id $
|
||||
*
|
||||
* Comments from original version:
|
||||
* On the MIPS processor, all symbols do not have the prepended underscore.
|
||||
* Here we redefine symFindByName to look at the second character of the
|
||||
* name string.
|
||||
*
|
||||
* On various RISC processors (at least MIPS and PPC), symbols do not have
|
||||
* the prepended underscore. Here we redefine symFindByName so that, if the
|
||||
* name lookup fails and if the first character of the name is "_", the
|
||||
* lookup is repeated starting at the second character of the name string.
|
||||
*
|
||||
* 01a,08apr97,bdg created.
|
||||
* 02a,03apr97,npr changed from mips.h into symFindByNameMips.c
|
||||
* 03a,03jun98,wfl changed Mips -> EPICS and avoid architecture knowledge
|
||||
* On 68K targets, all symbols have an underscore prepended to their name.
|
||||
* This code permits both standards to work, as long as you're not looking
|
||||
* for a symbol name that actually begins with an underscore.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "epicsDynLink.h"
|
||||
|
||||
STATUS symFindByNameEPICS(
|
||||
SYMTAB_ID symTblId,
|
||||
char *name,
|
||||
char **ppvalue,
|
||||
SYM_TYPE *pType )
|
||||
|
||||
#if _WRS_VXWORKS_MAJOR < 6 || _WRS_VXWORKS_MINOR < 9
|
||||
|
||||
static int symNoUnderscore(SYMTAB_ID symTblId)
|
||||
{
|
||||
static int leadingUnderscore = 1;
|
||||
static int init = 0;
|
||||
STATUS status = ERROR;
|
||||
static int init = 0;
|
||||
static int noUnderscore = 0;
|
||||
|
||||
if (!init) {
|
||||
char *pSymValue;
|
||||
SYM_TYPE type;
|
||||
status = symFindByName ( symTblId, "symFindByNameEPICS", &pSymValue, &type );
|
||||
if (status==OK) {
|
||||
leadingUnderscore = 0;
|
||||
}
|
||||
init = 1;
|
||||
}
|
||||
if (!init) {
|
||||
char name[] = "symFindByNameEPICS";
|
||||
char *pSymValue;
|
||||
SYM_TYPE type;
|
||||
|
||||
if (name[0] != '_' || leadingUnderscore) {
|
||||
status = symFindByName ( symTblId, name, ppvalue, pType );
|
||||
}
|
||||
else {
|
||||
status = symFindByName ( symTblId, (name+1), ppvalue, pType );
|
||||
}
|
||||
|
||||
return status;
|
||||
if (symFindByName(symTblId, name, &pSymValue, &type) == OK)
|
||||
noUnderscore = 1;
|
||||
init = 1;
|
||||
}
|
||||
return noUnderscore;
|
||||
}
|
||||
|
||||
STATUS symFindByNameAndTypeEPICS(
|
||||
SYMTAB_ID symTblId,
|
||||
char *name,
|
||||
char **ppvalue,
|
||||
SYM_TYPE *pType,
|
||||
SYM_TYPE sType,
|
||||
SYM_TYPE mask )
|
||||
STATUS symFindByNameEPICS(SYMTAB_ID symTblId, char *name, char **ppvalue,
|
||||
SYM_TYPE *pType)
|
||||
{
|
||||
static int leadingUnderscore = 1;
|
||||
static int init = 0;
|
||||
STATUS status = ERROR;
|
||||
if (name[0] == '_' && symNoUnderscore(symTblId))
|
||||
name++;
|
||||
|
||||
if (!init) {
|
||||
char *pSymValue;
|
||||
SYM_TYPE type;
|
||||
status = symFindByName (symTblId, "symFindByNameAndTypeEPICS", &pSymValue, &type );
|
||||
if (status==OK) {
|
||||
leadingUnderscore = 0;
|
||||
}
|
||||
init = 1;
|
||||
}
|
||||
|
||||
if (name[0] != '_' || leadingUnderscore) {
|
||||
status = symFindByNameAndType ( symTblId, name, ppvalue, pType, sType, mask );
|
||||
}
|
||||
else if (leadingUnderscore) {
|
||||
status = symFindByNameAndType ( symTblId, (name+1), ppvalue, pType, sType, mask );
|
||||
}
|
||||
|
||||
return status;
|
||||
return symFindByName(symTblId, name, ppvalue, pType);
|
||||
}
|
||||
|
||||
STATUS symFindByNameAndTypeEPICS(SYMTAB_ID symTblId, char *name,
|
||||
char **ppvalue, SYM_TYPE *pType, SYM_TYPE sType, SYM_TYPE mask)
|
||||
{
|
||||
if (name[0] == '_' && symNoUnderscore(symTblId))
|
||||
name++;
|
||||
|
||||
return symFindByNameAndType(symTblId, name, ppvalue, pType, sType, mask);
|
||||
}
|
||||
|
||||
#else /* VxWorks 6.9 deprecated the symFindBy routines */
|
||||
|
||||
STATUS symFindByNameEPICS(SYMTAB_ID symTblId, char *name, char **ppvalue,
|
||||
SYM_TYPE *pType)
|
||||
{
|
||||
SYMBOL_DESC symDesc;
|
||||
STATUS status;
|
||||
|
||||
memset(&symDesc, 0, sizeof(SYMBOL_DESC));
|
||||
symDesc.mask = SYM_FIND_BY_NAME;
|
||||
symDesc.name = name + (name[0] == '_');
|
||||
status = symFind(sysSymTbl, &symDesc);
|
||||
if (!status) {
|
||||
*ppvalue = symDesc.value;
|
||||
*pType = symDesc.type;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
STATUS symFindByNameAndTypeEPICS(SYMTAB_ID symTblId, char *name,
|
||||
char **ppvalue, SYM_TYPE *pType, SYM_TYPE sType, SYM_TYPE mask)
|
||||
{
|
||||
SYMBOL_DESC symDesc;
|
||||
STATUS status;
|
||||
|
||||
memset(&symDesc, 0, sizeof(SYMBOL_DESC));
|
||||
symDesc.mask = SYM_FIND_BY_NAME | SYM_FIND_BY_TYPE;
|
||||
symDesc.name = name + (name[0] == '_');
|
||||
symDesc.type = sType;
|
||||
symDesc.typeMask = mask;
|
||||
status = symFind(sysSymTbl, &symDesc);
|
||||
if (!status) {
|
||||
*ppvalue = symDesc.value;
|
||||
*pType = symDesc.type;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
@@ -16,32 +15,22 @@
|
||||
#ifndef epicsDynLinkh
|
||||
#define epicsDynLinkh
|
||||
|
||||
#ifdef symFindByName
|
||||
#undef symFindByName
|
||||
#endif
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "symLib.h"
|
||||
#include "sysSymTbl.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
STATUS symFindByNameEPICS(
|
||||
SYMTAB_ID symTblId,
|
||||
char *name,
|
||||
char **pvalue,
|
||||
SYM_TYPE *pType);
|
||||
/* Use epicsFindSymbol() instead of these */
|
||||
|
||||
STATUS symFindByNameAndTypeEPICS(
|
||||
SYMTAB_ID symTblId,
|
||||
char *name,
|
||||
char **pvalue,
|
||||
SYM_TYPE *pType,
|
||||
SYM_TYPE sType,
|
||||
SYM_TYPE mask);
|
||||
STATUS symFindByNameEPICS(SYMTAB_ID symTblId, char *name, char **pvalue,
|
||||
SYM_TYPE *pType) EPICS_DEPRECATED;
|
||||
|
||||
STATUS symFindByNameAndTypeEPICS(SYMTAB_ID symTblId, char *name, char **pvalue,
|
||||
SYM_TYPE *pType, SYM_TYPE sType, SYM_TYPE mask) EPICS_DEPRECATED;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -56,7 +56,9 @@ epicsShareFunc void * epicsLoadLibrary(const char *name)
|
||||
|
||||
epicsShareFunc const char *epicsLoadError(void)
|
||||
{
|
||||
if (oldmsg) free(oldmsg);
|
||||
if (oldmsg)
|
||||
free(oldmsg);
|
||||
|
||||
oldmsg = errmsg;
|
||||
errmsg = NULL;
|
||||
return oldmsg;
|
||||
@@ -65,22 +67,49 @@ epicsShareFunc const char *epicsLoadError(void)
|
||||
void *epicsFindSymbol(const char *name)
|
||||
{
|
||||
STATUS status;
|
||||
SYM_TYPE type;
|
||||
|
||||
#if _WRS_VXWORKS_MAJOR < 6 || _WRS_VXWORKS_MINOR < 9
|
||||
char *pvalue;
|
||||
|
||||
status = symFindByName( sysSymTbl, (char *)name, &pvalue, &type );
|
||||
if(status) {
|
||||
if(name[0] == '_' ) {
|
||||
status = symFindByName(sysSymTbl, (char *)(name+1), &pvalue, &type);
|
||||
} else {
|
||||
char *pname;
|
||||
pname = dbmfMalloc(strlen(name) + 2);
|
||||
strcpy(pname,"_");
|
||||
strcat(pname,name);
|
||||
status = symFindByName(sysSymTbl,pname, &pvalue, &type);
|
||||
dbmfFree(pname);
|
||||
}
|
||||
SYM_TYPE type;
|
||||
|
||||
status = symFindByName(sysSymTbl, (char *)name, &pvalue, &type);
|
||||
if (!status)
|
||||
return pvalue;
|
||||
|
||||
if (name[0] == '_' ) {
|
||||
status = symFindByName(sysSymTbl, (char *)(name+1), &pvalue, &type);
|
||||
}
|
||||
if(status) return(0);
|
||||
return((void *)pvalue);
|
||||
#if CPU_FAMILY == MC680X0
|
||||
else {
|
||||
char *pname = dbmfMalloc(strlen(name) + 2);
|
||||
|
||||
pname[0] = '_';
|
||||
strcpy(pname + 1, name);
|
||||
status = symFindByName(sysSymTbl, pname, &pvalue, &type);
|
||||
dbmfFree(pname);
|
||||
}
|
||||
#endif
|
||||
if (!status)
|
||||
return pvalue;
|
||||
|
||||
#else
|
||||
|
||||
SYMBOL_DESC symDesc;
|
||||
|
||||
memset(&symDesc, 0, sizeof(SYMBOL_DESC));
|
||||
symDesc.mask = SYM_FIND_BY_NAME;
|
||||
symDesc.name = (char *) name;
|
||||
status = symFind(sysSymTbl, &symDesc);
|
||||
if (!status)
|
||||
return symDesc.value;
|
||||
|
||||
if (name[0] == '_') {
|
||||
symDesc.name++;
|
||||
status = symFind(sysSymTbl, &symDesc);
|
||||
if (!status)
|
||||
return symDesc.value;
|
||||
}
|
||||
/* No need to prepend an '_'; 68K-only, no longer supported */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -255,9 +255,9 @@ MAIN(epicsStdlibTest)
|
||||
testOk(epicsScanULong("0xffffffff", &u, 0) && u == 0xffffffff,
|
||||
"ULong '0xffffffff'");
|
||||
testOk(epicsScanLLong("0x7fffffffffffffff", &ll, 0) &&
|
||||
ll == 0x7fffffffffffffff, "LLong '0x7fffffffffffffff'");
|
||||
ll == 0x7fffffffffffffffLL, "LLong '0x7fffffffffffffff'");
|
||||
testOk(epicsScanULLong("0xffffffffffffffff", &ull, 0) &&
|
||||
ull == 0xffffffffffffffff, "ULLong '0xffffffffffffffff'");
|
||||
ull == 0xffffffffffffffffULL, "ULLong '0xffffffffffffffff'");
|
||||
testOk(epicsScanFloat("0xffffff", &f) && f == 0xffffff,
|
||||
"Float '0xffffff'");
|
||||
testOk(epicsScanDouble("0xffffffff", &d) && d == 0xffffffff,
|
||||
@@ -268,9 +268,9 @@ MAIN(epicsStdlibTest)
|
||||
testOk(epicsScanULong("-0x7fffffff", &u, 0) && u == -0x7fffffff,
|
||||
"ULong '-0x7fffffff'");
|
||||
testOk(epicsScanLLong("-0x7fffffffffffffff", &ll, 0)
|
||||
&& ll == -0x7fffffffffffffff, "LLong '-0x7fffffffffffffff'");
|
||||
&& ll == -0x7fffffffffffffffLL, "LLong '-0x7fffffffffffffff'");
|
||||
testOk(epicsScanULLong("-0x7fffffffffffffff", &ull, 0) &&
|
||||
ull == -0x7fffffffffffffff, "ULLong '-0x7fffffffffffffff'");
|
||||
ull == -0x7fffffffffffffffULL, "ULLong '-0x7fffffffffffffff'");
|
||||
testOk(epicsScanFloat("-0xffffff", &f) && f == -0xffffff,
|
||||
"Float '-0xffffff'");
|
||||
testOk(epicsScanDouble("-0x7fffffff", &d) && d == -0x7fffffff,
|
||||
@@ -328,12 +328,12 @@ MAIN(epicsStdlibTest)
|
||||
"UInt32 '-0x100000000' => overflow");
|
||||
|
||||
testOk(!epicsParseInt64("0x7fffffffffffffff", &i64, 0, NULL) &&
|
||||
i64 == 0x7fffffffffffffff, "Int64 '0x7fffffffffffffff'");
|
||||
i64 == 0x7fffffffffffffffLL, "Int64 '0x7fffffffffffffff'");
|
||||
testOk(!epicsParseInt64("-0x8000000000000000", &i64, 0, NULL) &&
|
||||
i64 == -0x8000000000000000L, "Int64 '-0x8000000000000000'");
|
||||
i64 == -0x8000000000000000LL, "Int64 '-0x8000000000000000'");
|
||||
testOk(!epicsParseUInt64("0xffffffffffffffff", &u64, 0, NULL) &&
|
||||
u64 == 0xffffffffffffffff, "UInt64 '0xffffffffffffffff'");
|
||||
testOk(!epicsParseUInt64("-1", &u64, 0, NULL) && u64 == 0xffffffffffffffffU,
|
||||
u64 == 0xffffffffffffffffULL, "UInt64 '0xffffffffffffffff'");
|
||||
testOk(!epicsParseUInt64("-1", &u64, 0, NULL) && u64 == 0xffffffffffffffffULL,
|
||||
"UInt64 '-1'");
|
||||
testOk(epicsParseInt64("0x8000000000000000", &i64, 0, NULL) == S_stdlib_overflow,
|
||||
"Int64 '0x8000000000000000' => overflow");
|
||||
|
||||
@@ -84,9 +84,11 @@ MAIN(epicsStringTest)
|
||||
const char * const a = "a";
|
||||
const char * const abcd = "abcd";
|
||||
const char * const abcde = "abcde";
|
||||
char result[8];
|
||||
char *s;
|
||||
int status;
|
||||
|
||||
testPlan(305);
|
||||
testPlan(402);
|
||||
|
||||
testChars();
|
||||
|
||||
@@ -123,5 +125,199 @@ MAIN(epicsStringTest)
|
||||
|
||||
testGlob();
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnEscapedFromRaw(result, 0, ABCD, 4);
|
||||
testOk(status == 4, "epicsStrnEscapedFromRaw(out, 0) -> %d (exp. 4)", status);
|
||||
testOk(result[0] == 'x', " No output");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 0, ABCD, 4);
|
||||
testOk(status == 0, "epicsStrnRawFromEscaped(out, 0) -> %d (exp. 0)", status);
|
||||
testOk(result[0] == 'x', " No output");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnEscapedFromRaw(result, 1, ABCD, 4);
|
||||
testOk(status == 4, "epicsStrnEscapedFromRaw(out, 1) -> %d (exp. 4)", status);
|
||||
testOk(result[0] == 0, " 0-terminated");
|
||||
testOk(result[1] == 'x', " No overrun");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 1, ABCD, 4);
|
||||
testOk(status == 0, "epicsStrnRawFromEscaped(out, 1) -> %d (exp. 0)", status);
|
||||
testOk(result[0] == 0, " 0-terminated");
|
||||
testOk(result[1] == 'x', " No overrun");
|
||||
|
||||
testDiag("Testing size = epicsStrnEscapedFromRawSize");
|
||||
|
||||
status = epicsStrnEscapedFromRawSize(ABCD, 3);
|
||||
testOk(status == 3, "size(\"ABCD\", 3) -> %d (exp. 3)", status);
|
||||
status = epicsStrnEscapedFromRawSize(ABCD, 4);
|
||||
testOk(status == 4, "size(\"ABCD\", 4) -> %d (exp. 4)", status);
|
||||
status = epicsStrnEscapedFromRawSize(ABCD, 5);
|
||||
testOk(status == 8, "size(\"ABCD\", 5) -> %d (exp. 8)", status);
|
||||
|
||||
testDiag("Testing esc = epicsStrnEscapedFromRaw(out, 4, ...)");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnEscapedFromRaw(result, 4, ABCD, 3);
|
||||
testOk(status == 3, "esc(\"ABCD\", 3) -> %d (exp. 3)", status);
|
||||
testOk(result[3] == 0, " 0-terminated");
|
||||
testOk(result[4] == 'x', " No overrun");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnEscapedFromRaw(result, 4, ABCD, 4);
|
||||
testOk(status == 4, "esc(\"ABCD\", 4) -> %d (exp. 4)", status);
|
||||
testOk(result[3] == 0, " 0-terminated");
|
||||
testOk(result[4] == 'x', " No overrun");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnEscapedFromRaw(result, 4, ABCD, 5);
|
||||
testOk(status == 8, "esc(\"ABCD\", 5) -> %d (exp. 8)", status);
|
||||
testOk(result[3] == 0, " 0-terminated");
|
||||
testOk(result[4] == 'x', " No overrun");
|
||||
|
||||
testDiag("Testing raw = epicsStrnRawFromEscaped(out, 4, ...)");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, ABCD, 0);
|
||||
testOk(status == 0, "raw(\"ABCD\", 0) -> %d (exp. 0)", status);
|
||||
testOk(result[0] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, ABCD, 1);
|
||||
testOk(status == 1, "raw(\"ABCD\", 1) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
|
||||
testOk(result[1] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, ABCD, 2);
|
||||
testOk(status == 2, "raw(\"ABCD\", 2) -> %d (exp. 2)", status);
|
||||
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
|
||||
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
|
||||
testOk(result[2] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, ABCD, 3);
|
||||
testOk(status == 3, "raw(\"ABCD\", 3) -> %d (exp. 3)", status);
|
||||
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
|
||||
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
|
||||
testOk(result[2] == 'C', " Char '%c' (exp. 'C')", result[2]);
|
||||
testOk(result[3] == 0, " 0-terminated");
|
||||
testOk(result[4] == 'x', " No write outside buffer");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, ABCD, 4);
|
||||
testOk(status == 3, "raw(\"ABCD\", 4) -> %d (exp. 3)", status);
|
||||
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
|
||||
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
|
||||
testOk(result[2] == 'C', " Char '%c' (exp. 'C')", result[2]);
|
||||
testOk(result[3] == 0, " 0-terminated");
|
||||
testOk(result[4] == 'x', " No write outside buffer");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, ABCDE, 5);
|
||||
testOk(status == 3, "raw(\"ABCDE\", 5) -> %d (exp. 3)", status);
|
||||
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
|
||||
testOk(result[1] == 'B', " Char '%c' (exp. 'B')", result[1]);
|
||||
testOk(result[2] == 'C', " Char '%c' (exp. 'C')", result[2]);
|
||||
testOk(result[3] == 0, " 0-terminated");
|
||||
testOk(result[4] == 'x', " No write outside buffer");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "A", 2);
|
||||
testOk(status == 1, "raw(\"A\", 2) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 'A', " Char '%c' (exp. 'A')", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\123", 1);
|
||||
testOk(status == 0, "raw(\"\\123\", 1) -> %d (exp. 0)", status);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\123", 2);
|
||||
testOk(status == 1, "raw(\"\\123\", 2) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 1, " Octal escape (got \\%03o)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\123", 3);
|
||||
testOk(status == 1, "raw(\"\\123\", 3) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 012, " Octal escape (got \\%03o)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\123", 4);
|
||||
testOk(status == 1, "raw(\"\\123\", 4) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 0123, " Octal escape (got \\%03o)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\812", 2);
|
||||
testOk(status == 1, "raw(\"\\812\", 2) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == '8', " Escaped '%c')", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\182", 3);
|
||||
testOk(status == 2, "raw(\"\\182\", 3) -> %d (exp. 2)", status);
|
||||
testOk(result[0] == 1, " Octal escape (got \\%03o)", result[0]);
|
||||
testOk(result[1] == '8', " Terminated with '%c'", result[1]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\128", 4);
|
||||
testOk(status == 2, "raw(\"\\128\", 4) -> %d (exp. 2)", status);
|
||||
testOk(result[0] == 012, " Octal escape (got \\%03o)", result[0]);
|
||||
testOk(result[1] == '8', " Terminator char got '%c'", result[1]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 1);
|
||||
testOk(status == 0, "raw(\"\\x12\", 1) -> %d (exp. 0)", status);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 2);
|
||||
testOk(status == 0, "raw(\"\\x12\", 2) -> %d (exp. 0)", status);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 3);
|
||||
testOk(status == 1, "raw(\"\\x12\", 3) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 1, " Hex escape (got \\x%x)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x12", 4);
|
||||
testOk(status == 1, "raw(\"\\x12\", 4) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 0x12," Hex escape (got \\x%x)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\xaF", 4);
|
||||
testOk(status == 1, "raw(\"\\xaF\", 4) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == '\xaF'," Hex escape (got \\x%x)", result[0] & 0xFF);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x012", 5);
|
||||
testOk(status == 1, "raw(\"\\x012\", 5) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 0x12," Hex escape (got \\x%x)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x0012", 6);
|
||||
testOk(status == 1, "raw(\"\\x0012\", 6) -> %d (exp. 1)", status);
|
||||
testOk(result[0] == 0x12," Hex escape (got \\x%x)", result[0]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
memset(result, 'x', sizeof(result));
|
||||
status = epicsStrnRawFromEscaped(result, 4, "\\x1g", 4);
|
||||
testOk(status == 2, "raw(\"\\x1g\", 4) -> %d (exp. 2)", status);
|
||||
testOk(result[0] == 1, " Hex escape (got \\x%x)", result[0]);
|
||||
testOk(result[1] == 'g', " Terminator char got '%c'", result[1]);
|
||||
testOk(result[status] == 0, " 0-terminated");
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -26,179 +26,221 @@
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
#define ringSize 10
|
||||
#define consumerCount 4
|
||||
#define producerCount 4
|
||||
|
||||
static volatile int testExit = 0;
|
||||
int value[ringSize*2];
|
||||
|
||||
typedef struct info {
|
||||
epicsEventId consumerEvent;
|
||||
epicsRingPointerId ring;
|
||||
int checkOrder;
|
||||
int value[ringSize*2];
|
||||
}info;
|
||||
|
||||
static void consumer(void *arg)
|
||||
static
|
||||
void *int2ptr(size_t i)
|
||||
{
|
||||
info *pinfo = (info *)arg;
|
||||
static int expectedValue=0;
|
||||
int *newvalue;
|
||||
char myname[20];
|
||||
|
||||
epicsThreadGetName(epicsThreadGetIdSelf(), myname, sizeof(myname));
|
||||
testDiag("%s starting", myname);
|
||||
while(1) {
|
||||
epicsEventMustWait(pinfo->consumerEvent);
|
||||
if (testExit) return;
|
||||
while ((newvalue = (int *)epicsRingPointerPop(pinfo->ring))) {
|
||||
if (pinfo->checkOrder) {
|
||||
testOk(expectedValue == *newvalue,
|
||||
"%s: (got) %d == %d (expected)", myname, *newvalue, expectedValue);
|
||||
expectedValue = *newvalue + 1;
|
||||
} else {
|
||||
testOk(pinfo->value[*newvalue] <= producerCount, "%s: got a %d (%d times seen before)",
|
||||
myname, *newvalue, pinfo->value[*newvalue]);
|
||||
}
|
||||
/* This must be atomic... */
|
||||
pinfo->value[*newvalue]++;
|
||||
epicsThreadSleep(0.05);
|
||||
}
|
||||
}
|
||||
char *zero = 0;
|
||||
i = i|(i<<16);
|
||||
return zero+i;
|
||||
}
|
||||
|
||||
static void producer(void *arg)
|
||||
{
|
||||
info *pinfo = (info *)arg;
|
||||
char myname[20];
|
||||
int i;
|
||||
static int foundCorruption;
|
||||
|
||||
epicsThreadGetName(epicsThreadGetIdSelf(), myname, sizeof(myname));
|
||||
testDiag("%s starting", myname);
|
||||
for (i=0; i<ringSize*2; i++) {
|
||||
while (epicsRingPointerIsFull(pinfo->ring)) {
|
||||
epicsThreadSleep(0.2);
|
||||
if (testExit) return;
|
||||
}
|
||||
testOk(epicsRingPointerPush(pinfo->ring, (void *)&value[i]),
|
||||
"%s: Pushing %d, ring not full", myname, i);
|
||||
epicsEventSignal(pinfo->consumerEvent);
|
||||
if (testExit) return;
|
||||
static
|
||||
size_t ptr2int(void *p)
|
||||
{
|
||||
char *zero = 0, *p2 = p;
|
||||
size_t i = p2-zero;
|
||||
if((i&0xffff)!=((i>>16)&0xffff)) {
|
||||
testDiag("Pointer value corruption %p", p);
|
||||
foundCorruption = 1;
|
||||
}
|
||||
return i&0xffff;
|
||||
}
|
||||
|
||||
static void testSingle(void)
|
||||
{
|
||||
int i;
|
||||
const int rsize = 100;
|
||||
void *addr = 0;
|
||||
epicsRingPointerId ring = epicsRingPointerCreate(rsize);
|
||||
|
||||
foundCorruption = 0;
|
||||
|
||||
testDiag("Testing operations w/o threading");
|
||||
|
||||
testOk1(epicsRingPointerIsEmpty(ring));
|
||||
testOk1(!epicsRingPointerIsFull(ring));
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==0);
|
||||
|
||||
testOk1(epicsRingPointerPop(ring)==NULL);
|
||||
|
||||
addr = int2ptr(1);
|
||||
testOk1(epicsRingPointerPush(ring, addr)==1);
|
||||
|
||||
testOk1(!epicsRingPointerIsEmpty(ring));
|
||||
testOk1(!epicsRingPointerIsFull(ring));
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize-1);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==1);
|
||||
|
||||
testDiag("Fill it up");
|
||||
for(i=2; i<2*rsize; i++) {
|
||||
int ret;
|
||||
addr = int2ptr(i);
|
||||
ret = epicsRingPointerPush(ring, addr);
|
||||
if(!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Note: +1 because we started with 1 */
|
||||
testOk(i==rsize+1, "%d == %d", i, rsize+1);
|
||||
testOk1(!epicsRingPointerIsEmpty(ring));
|
||||
testOk1(epicsRingPointerIsFull(ring));
|
||||
testOk1(epicsRingPointerGetFree(ring)==0);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==rsize);
|
||||
|
||||
testDiag("Drain it out");
|
||||
for(i=1; i<2*rsize; i++) {
|
||||
addr = epicsRingPointerPop(ring);
|
||||
if(addr==NULL || ptr2int(addr)!=i)
|
||||
break;
|
||||
}
|
||||
|
||||
testOk1(!foundCorruption);
|
||||
|
||||
testOk(i==rsize+1, "%d == %d", i, rsize+1);
|
||||
testOk1(epicsRingPointerIsEmpty(ring));
|
||||
testOk1(!epicsRingPointerIsFull(ring));
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==0);
|
||||
|
||||
testDiag("Fill it up again");
|
||||
for(i=2; i<2*rsize; i++) {
|
||||
int ret;
|
||||
addr = int2ptr(i);
|
||||
ret = epicsRingPointerPush(ring, addr);
|
||||
if(!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
testDiag("flush");
|
||||
testOk1(epicsRingPointerIsFull(ring));
|
||||
epicsRingPointerFlush(ring);
|
||||
|
||||
testOk1(epicsRingPointerIsEmpty(ring));
|
||||
testOk1(!epicsRingPointerIsFull(ring));
|
||||
testOk1(epicsRingPointerGetFree(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetSize(ring)==rsize);
|
||||
testOk1(epicsRingPointerGetUsed(ring)==0);
|
||||
|
||||
epicsRingPointerDelete(ring);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
epicsRingPointerId ring;
|
||||
epicsEventId sync, wait;
|
||||
int stop;
|
||||
void *lastaddr;
|
||||
} pairPvt;
|
||||
|
||||
static void pairConsumer(void *raw)
|
||||
{
|
||||
pairPvt *pvt = raw;
|
||||
void *prev = pvt->lastaddr;
|
||||
|
||||
epicsEventMustTrigger(pvt->sync);
|
||||
|
||||
while(1) {
|
||||
size_t c,p;
|
||||
|
||||
epicsEventMustWait(pvt->wait);
|
||||
if(pvt->stop)
|
||||
break;
|
||||
|
||||
pvt->lastaddr = epicsRingPointerPop(pvt->ring);
|
||||
c = ptr2int(pvt->lastaddr);
|
||||
p = ptr2int(prev);
|
||||
if(p+1!=c) {
|
||||
testFail("consumer skip %p %p", prev, pvt->lastaddr);
|
||||
break;
|
||||
}
|
||||
prev = pvt->lastaddr;
|
||||
}
|
||||
|
||||
pvt->stop = 1;
|
||||
epicsEventMustTrigger(pvt->sync);
|
||||
}
|
||||
|
||||
static void testPair(int locked)
|
||||
{
|
||||
unsigned int myprio = epicsThreadGetPrioritySelf(), consumerprio;
|
||||
pairPvt pvt;
|
||||
const int rsize = 100;
|
||||
int i, expect;
|
||||
epicsRingPointerId ring;
|
||||
if(locked)
|
||||
ring = epicsRingPointerLockedCreate(rsize);
|
||||
else
|
||||
ring = epicsRingPointerCreate(rsize);
|
||||
|
||||
pvt.ring = ring;
|
||||
pvt.sync = epicsEventCreate(epicsEventEmpty);
|
||||
pvt.wait = epicsEventCreate(epicsEventEmpty);
|
||||
pvt.stop = 0;
|
||||
pvt.lastaddr = 0;
|
||||
|
||||
foundCorruption = 0;
|
||||
|
||||
testDiag("single producer, single consumer with%s locking", locked?"":"out");
|
||||
|
||||
/* give the consumer thread a slightly higher priority so that
|
||||
* it can preempt us on RTOS targets. On non-RTOS targets
|
||||
* we expect to be preempted at some random time
|
||||
*/
|
||||
if(!epicsThreadLowestPriorityLevelAbove(myprio, &consumerprio))
|
||||
testAbort("Can't run test from thread with highest priority");
|
||||
|
||||
epicsThreadMustCreate("pair", consumerprio,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
&pairConsumer, &pvt);
|
||||
/* wait for worker to start */
|
||||
epicsEventMustWait(pvt.sync);
|
||||
|
||||
i=1;
|
||||
while(i<rsize*10 && !pvt.stop) {
|
||||
int full = epicsRingPointerPush(ring, int2ptr(i));
|
||||
if(full || i%32==31)
|
||||
epicsEventMustTrigger(pvt.wait);
|
||||
if(full) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
testDiag("Everything enqueued, Stopping consumer");
|
||||
pvt.stop = 1;
|
||||
epicsEventMustTrigger(pvt.wait);
|
||||
epicsEventMustWait(pvt.sync);
|
||||
|
||||
i = epicsRingPointerGetUsed(ring);
|
||||
testDiag("Pushed %d, have %d remaining unconsumed", rsize*10, i);
|
||||
expect = rsize*10-i;
|
||||
testDiag("Expect %d consumed", expect);
|
||||
|
||||
testOk(pvt.lastaddr==int2ptr(expect-1), "%p == %p", pvt.lastaddr, int2ptr(expect-1));
|
||||
if(pvt.lastaddr==int2ptr(expect-1))
|
||||
testPass("Consumer consumed all");
|
||||
|
||||
testOk1(!foundCorruption);
|
||||
|
||||
epicsEventDestroy(pvt.sync);
|
||||
epicsEventDestroy(pvt.wait);
|
||||
epicsRingPointerDelete(ring);
|
||||
}
|
||||
|
||||
MAIN(ringPointerTest)
|
||||
{
|
||||
int i;
|
||||
info *pinfo;
|
||||
epicsEventId consumerEvent;
|
||||
int *pgetValue;
|
||||
epicsRingPointerId ring;
|
||||
epicsThreadId tid;
|
||||
char threadName[20];
|
||||
|
||||
testPlan(256);
|
||||
|
||||
for (i=0; i<ringSize*2; i++) value[i] = i;
|
||||
|
||||
pinfo = calloc(1,sizeof(info));
|
||||
if(!pinfo) testAbort("calloc failed");
|
||||
|
||||
pinfo->consumerEvent = consumerEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
if (!consumerEvent) {
|
||||
testAbort("epicsEventMustCreate failed");
|
||||
}
|
||||
|
||||
testDiag("******************************************************");
|
||||
testDiag("** Test 1: local ring pointer, check size and order **");
|
||||
testDiag("******************************************************");
|
||||
|
||||
pinfo->ring = ring = epicsRingPointerCreate(ringSize);
|
||||
if (!ring) {
|
||||
testAbort("epicsRingPointerCreate failed");
|
||||
}
|
||||
testOk(epicsRingPointerIsEmpty(ring), "Ring empty");
|
||||
|
||||
for (i=0; epicsRingPointerPush(ring,(void *)&value[i]); ++i) {}
|
||||
testOk(i==ringSize, "ring filled, %d values", i);
|
||||
|
||||
for (i=0; (pgetValue = (int *)epicsRingPointerPop(ring)); ++i) {
|
||||
testOk(i==*pgetValue, "Pop test: %d == %d", i, *pgetValue);
|
||||
}
|
||||
testOk(epicsRingPointerIsEmpty(ring), "Ring empty");
|
||||
|
||||
testDiag("**************************************************************");
|
||||
testDiag("** Test 2: unlocked ring pointer, one consumer, check order **");
|
||||
testDiag("**************************************************************");
|
||||
|
||||
pinfo->checkOrder = 1;
|
||||
tid=epicsThreadCreate("consumer", 50,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall), consumer, pinfo);
|
||||
if(!tid) testAbort("epicsThreadCreate failed");
|
||||
epicsThreadSleep(0.2);
|
||||
|
||||
for (i=0; i<ringSize*2; i++) {
|
||||
if (epicsRingPointerIsFull(ring)) {
|
||||
epicsThreadSleep(0.2);
|
||||
}
|
||||
testOk(epicsRingPointerPush(ring, (void *)&value[i]), "Pushing %d, ring not full", i);
|
||||
epicsEventSignal(consumerEvent);
|
||||
}
|
||||
epicsThreadSleep(1.0);
|
||||
testOk(epicsRingPointerIsEmpty(ring), "Ring empty");
|
||||
|
||||
for (i=0; i<ringSize*2; i++) {
|
||||
testOk(pinfo->value[i] == 1, "Value test: %d was processed", i);
|
||||
}
|
||||
|
||||
testExit = 1;
|
||||
epicsEventSignal(consumerEvent);
|
||||
epicsThreadSleep(1.0);
|
||||
|
||||
epicsRingPointerDelete(pinfo->ring);
|
||||
|
||||
testDiag("*************************************************************************************");
|
||||
testDiag("** Test 3: locked ring pointer, many consumers, many producers, check no of copies **");
|
||||
testDiag("*************************************************************************************");
|
||||
|
||||
pinfo->ring = ring = epicsRingPointerLockedCreate(ringSize);
|
||||
if (!ring) {
|
||||
testAbort("epicsRingPointerLockedCreate failed");
|
||||
}
|
||||
testOk(epicsRingPointerIsEmpty(ring), "Ring empty");
|
||||
|
||||
for (i=0; i<ringSize*2; i++) pinfo->value[i] = 0;
|
||||
testExit = 0;
|
||||
pinfo->checkOrder = 0;
|
||||
for (i=0; i<consumerCount; i++) {
|
||||
sprintf(threadName, "consumer%d", i);
|
||||
tid=epicsThreadCreate(threadName, 50,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall), consumer, pinfo);
|
||||
if(!tid) testAbort("epicsThreadCreate failed");
|
||||
}
|
||||
epicsThreadSleep(0.2);
|
||||
|
||||
for (i=0; i<producerCount; i++) {
|
||||
sprintf(threadName, "producer%d", i);
|
||||
tid=epicsThreadCreate(threadName, 50,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall), producer, pinfo);
|
||||
if(!tid) testAbort("epicsThreadCreate failed");
|
||||
}
|
||||
|
||||
epicsThreadSleep(0.5);
|
||||
epicsEventSignal(consumerEvent);
|
||||
epicsThreadSleep(1.0);
|
||||
|
||||
testOk(epicsRingPointerIsEmpty(ring), "Ring empty");
|
||||
|
||||
for (i=0; i<ringSize*2; i++) {
|
||||
testOk(pinfo->value[i] == producerCount, "Value test: %d was processed %d times", i, producerCount);
|
||||
}
|
||||
|
||||
testExit = 1;
|
||||
epicsEventSignal(consumerEvent);
|
||||
epicsThreadSleep(1.0);
|
||||
int prio = epicsThreadGetPrioritySelf();
|
||||
|
||||
testPlan(37);
|
||||
testSingle();
|
||||
epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityScanLow);
|
||||
testPair(0);
|
||||
testPair(1);
|
||||
epicsThreadSetPriority(epicsThreadGetIdSelf(), prio);
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
include "menuGlobal.dbd"
|
||||
include "menuConvert.dbd"
|
||||
include "menuScan.dbd"
|
||||
recordtype(arr) {
|
||||
include "dbCommon.dbd"
|
||||
field(VAL, DBF_NOACCESS) {
|
||||
|
||||
@@ -45,8 +45,9 @@ stdRecords += subArrayRecord
|
||||
stdRecords += waveformRecord
|
||||
|
||||
DBDINC += $(stdRecords)
|
||||
DBD += stdRecords.dbd
|
||||
|
||||
# Generate stdRecords.dbd, not really by concatenation, see RULES
|
||||
DBDCAT += stdRecords.dbd
|
||||
stdRecords_DBD = $(patsubst %,%.dbd,$(stdRecords))
|
||||
|
||||
dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
##########################################################################
|
||||
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
@@ -7,4 +7,12 @@
|
||||
|
||||
# This is a Makefile fragment, see src/ioc/Makefile.
|
||||
|
||||
$(COMMON_DIR)/stdRecords.dbd: $(STDDIR)/rec/Makefile
|
||||
stdRecords.dbd$(DEP): $(STDDIR)/rec/Makefile $(STDDIR)/rec/RULES
|
||||
@$(RM) $@
|
||||
@echo "$(COMMON_DIR)/stdRecords.dbd:" > $@
|
||||
|
||||
$(COMMON_DIR)/stdRecords.dbd: $(STDDIR)/rec/Makefile $(STDDIR)/rec/RULES
|
||||
|
||||
# This is a target-specific variable
|
||||
$(COMMON_DIR)/stdRecords.dbd: DBDCAT_COMMAND = \
|
||||
$(PERL) $(TOOLS)/makeIncludeDbd.pl $(stdRecords_DBD) $(@F)
|
||||
|
||||
@@ -26,8 +26,6 @@ static void testGetPutArray(void)
|
||||
epicsInt32 *pbtr;
|
||||
waveformRecord *prec;
|
||||
|
||||
testDiag("Test dbGet() and dbPut() of an array");
|
||||
|
||||
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
|
||||
|
||||
recTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
@@ -38,6 +36,8 @@ static void testGetPutArray(void)
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
testDiag("Test dbGet() and dbPut() from/to an array");
|
||||
|
||||
prec = (waveformRecord*)testdbRecordPtr("wfrec");
|
||||
if(!prec || dbNameToAddr("wfrec", &addr))
|
||||
testAbort("Failed to find record wfrec");
|
||||
@@ -52,7 +52,7 @@ static void testGetPutArray(void)
|
||||
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
|
||||
testFail("dbGet fails");
|
||||
else {
|
||||
testOk1(nreq==0);
|
||||
testOk(nreq==0, "nreq==0 (got %ld)", nreq);
|
||||
}
|
||||
dbScanUnlock(addr.precord);
|
||||
|
||||
@@ -69,7 +69,7 @@ static void testGetPutArray(void)
|
||||
dbScanLock(addr.precord);
|
||||
testOk1(dbPut(&addr, DBF_DOUBLE, &data, NELEMENTS(data))==0);
|
||||
pbtr = prec->bptr;
|
||||
testOk1(prec->nord==4);
|
||||
testOk(prec->nord==4, "prec->nord==4 (got %u)", prec->nord);
|
||||
testOk1(pbtr[0]==4 && pbtr[1]==5 && pbtr[2]==6 && pbtr[3]==7);
|
||||
dbScanUnlock(addr.precord);
|
||||
|
||||
@@ -78,7 +78,7 @@ static void testGetPutArray(void)
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
testDiag("reread the value");
|
||||
testDiag("Reread the value");
|
||||
|
||||
dbScanLock(addr.precord);
|
||||
nreq = NELEMENTS(data);
|
||||
@@ -92,6 +92,62 @@ static void testGetPutArray(void)
|
||||
|
||||
testOk1(memcmp(&addr, &save, sizeof(save))==0);
|
||||
|
||||
testDiag("Test dbGet() and dbPut() from/to an array of size 1");
|
||||
|
||||
prec = (waveformRecord*)testdbRecordPtr("wfrec1");
|
||||
if(!prec || dbNameToAddr("wfrec1", &addr))
|
||||
testAbort("Failed to find record wfrec1");
|
||||
memcpy(&save, &addr, sizeof(save));
|
||||
|
||||
testDiag("Fetch initial value");
|
||||
|
||||
dbScanLock(addr.precord);
|
||||
testOk1(prec->nord==0);
|
||||
|
||||
nreq = NELEMENTS(data);
|
||||
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
|
||||
testFail("dbGet fails");
|
||||
else {
|
||||
testOk(nreq==0, "nreq==0 (got %ld)", nreq);
|
||||
}
|
||||
dbScanUnlock(addr.precord);
|
||||
|
||||
testOk1(memcmp(&addr, &save, sizeof(save))==0);
|
||||
addr=save;
|
||||
|
||||
testDiag("Write a new value");
|
||||
|
||||
data[0] = 4.0;
|
||||
data[1] = 5.0;
|
||||
data[2] = 6.0;
|
||||
data[3] = 7.0;
|
||||
|
||||
dbScanLock(addr.precord);
|
||||
testOk1(dbPut(&addr, DBF_DOUBLE, &data, 1)==0);
|
||||
pbtr = prec->bptr;
|
||||
testOk(prec->nord==1, "prec->nord==1 (got %u)", prec->nord);
|
||||
testOk1(pbtr[0]==4);
|
||||
dbScanUnlock(addr.precord);
|
||||
|
||||
testOk1(memcmp(&addr, &save, sizeof(save))==0);
|
||||
addr=save;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
testDiag("Reread the value");
|
||||
|
||||
dbScanLock(addr.precord);
|
||||
nreq = NELEMENTS(data);
|
||||
if(dbGet(&addr, DBF_DOUBLE, &data, NULL, &nreq, NULL))
|
||||
testFail("dbGet fails");
|
||||
else {
|
||||
testOk1(nreq==1);
|
||||
testOk1(data[0]==4.0);
|
||||
}
|
||||
dbScanUnlock(addr.precord);
|
||||
|
||||
testOk1(memcmp(&addr, &save, sizeof(save))==0);
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
@@ -99,7 +155,7 @@ static void testGetPutArray(void)
|
||||
|
||||
MAIN(arrayOpTest)
|
||||
{
|
||||
testPlan(10);
|
||||
testPlan(20);
|
||||
testGetPutArray();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -2,3 +2,7 @@ record(waveform, "wfrec") {
|
||||
field(NELM, "10")
|
||||
field(FTVL, "LONG")
|
||||
}
|
||||
record(waveform, "wfrec1") {
|
||||
field(NELM, "1")
|
||||
field(FTVL, "LONG")
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# $Revision-Id$
|
||||
#
|
||||
# This file defines the standard record types and device support
|
||||
# This file includes the standard record types and device support
|
||||
# provided by Base and (usually) loaded into all IOCs.
|
||||
|
||||
# Menus
|
||||
# Fixed menus
|
||||
include "menuGlobal.dbd"
|
||||
|
||||
# Modifyable menus
|
||||
include "menuConvert.dbd"
|
||||
include "menuScan.dbd"
|
||||
|
||||
# Record types
|
||||
include "stdRecords.dbd"
|
||||
@@ -13,7 +16,7 @@ include "stdRecords.dbd"
|
||||
# Channel filters & plugins
|
||||
include "filters.dbd"
|
||||
|
||||
# "Soft Channel", "Raw Soft Channel", and "Async Soft Channel" device support
|
||||
# Standard device support
|
||||
include "devSoft.dbd"
|
||||
|
||||
# Access security subroutines
|
||||
|
||||
@@ -83,7 +83,7 @@ const char *exit_db = EXIT_FILE;
|
||||
|
||||
|
||||
static void exitSubroutine(subRecord *precord) {
|
||||
epicsExit((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void usage(int status) {
|
||||
|
||||
@@ -52,6 +52,8 @@ TEMPLATES += top/exampleBoot/nfsCommands@RTEMS
|
||||
TEMPLATES += top/exampleBoot/ioc/Makefile@Common
|
||||
TEMPLATES += top/exampleBoot/ioc/Makefile@vxWorks
|
||||
TEMPLATES += top/exampleBoot/ioc/Makefile@win32
|
||||
TEMPLATES += top/exampleBoot/ioc/Makefile@windows
|
||||
TEMPLATES += top/exampleBoot/ioc/Makefile@cygwin
|
||||
TEMPLATES += top/exampleBoot/ioc/st.cmd@Common
|
||||
TEMPLATES += top/exampleBoot/ioc/st.cmd@vxWorks
|
||||
TEMPLATES += top/exampleBoot/ioc/st.cmd@RTEMS
|
||||
@@ -81,6 +83,8 @@ TEMPLATES += top/iocBoot/nfsCommands@RTEMS
|
||||
TEMPLATES += top/iocBoot/ioc/Makefile@Common
|
||||
TEMPLATES += top/iocBoot/ioc/Makefile@vxWorks
|
||||
TEMPLATES += top/iocBoot/ioc/Makefile@win32
|
||||
TEMPLATES += top/iocBoot/ioc/Makefile@windows
|
||||
TEMPLATES += top/iocBoot/ioc/Makefile@cygwin
|
||||
TEMPLATES += top/iocBoot/ioc/st.cmd@Common
|
||||
TEMPLATES += top/iocBoot/ioc/st.cmd@Cross
|
||||
TEMPLATES += top/iocBoot/ioc/st.cmd@vxWorks
|
||||
|
||||
5
src/template/base/top/exampleBoot/ioc/Makefile@cygwin
Normal file
5
src/template/base/top/exampleBoot/ioc/Makefile@cygwin
Normal file
@@ -0,0 +1,5 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = _ARCH_
|
||||
TARGETS = envPaths relPaths.sh
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
5
src/template/base/top/exampleBoot/ioc/Makefile@windows
Normal file
5
src/template/base/top/exampleBoot/ioc/Makefile@windows
Normal file
@@ -0,0 +1,5 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = _ARCH_
|
||||
TARGETS = envPaths dllPath.bat
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
5
src/template/base/top/iocBoot/ioc/Makefile@cygwin
Normal file
5
src/template/base/top/iocBoot/ioc/Makefile@cygwin
Normal file
@@ -0,0 +1,5 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = _ARCH_
|
||||
TARGETS = envPaths relPaths.sh
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
5
src/template/base/top/iocBoot/ioc/Makefile@windows
Normal file
5
src/template/base/top/iocBoot/ioc/Makefile@windows
Normal file
@@ -0,0 +1,5 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = _ARCH_
|
||||
TARGETS = envPaths dllPath.bat
|
||||
include $(TOP)/configure/RULES.ioc
|
||||
@@ -38,6 +38,7 @@ PERL_SCRIPTS += dos2unix.pl
|
||||
PERL_SCRIPTS += expandVars.pl
|
||||
PERL_SCRIPTS += fullPathName.pl
|
||||
PERL_SCRIPTS += installEpics.pl
|
||||
PERL_SCRIPTS += makeIncludeDbd.pl
|
||||
PERL_SCRIPTS += makeMakefile.pl
|
||||
PERL_SCRIPTS += makeTestfile.pl
|
||||
PERL_SCRIPTS += mkmf.pl
|
||||
|
||||
@@ -82,6 +82,7 @@ expandRelease(\%macros, \@apps);
|
||||
for ($outfile) {
|
||||
m/releaseTops/ and do { &releaseTops; last; };
|
||||
m/dllPath\.bat/ and do { &dllPath; last; };
|
||||
m/relPaths\.sh/ and do { &relPaths; last; };
|
||||
m/cdCommands/ and do { &cdCommands; last; };
|
||||
m/envPaths/ and do { &envPaths; last; };
|
||||
m/checkRelease/ and do { &checkRelease; last; };
|
||||
@@ -96,7 +97,8 @@ sub HELP_MESSAGE {
|
||||
Usage: convertRelease.pl [-a arch] [-T top] [-t ioctop] outfile
|
||||
where outfile is one of:
|
||||
releaseTops - lists the module names defined in RELEASE*s
|
||||
dllPath.bat - path changes for cmd.exe to find WIN32 DLLs
|
||||
dllPath.bat - path changes for cmd.exe to find Windows DLLs
|
||||
relPaths.sh - path changes for bash to add RELEASE bin dir's
|
||||
cdCommands - generate cd path strings for vxWorks IOCs
|
||||
envPaths - generate epicsEnvSet commands for other IOCs
|
||||
checkRelease - checks consistency with support modules
|
||||
@@ -113,13 +115,21 @@ sub releaseTops {
|
||||
}
|
||||
|
||||
#
|
||||
# Generate Path files so Windows can find our DLLs
|
||||
# Generate Path files so Windows/Cygwin can find our DLLs
|
||||
#
|
||||
sub dllPath {
|
||||
unlink $outfile;
|
||||
open(OUT, ">$outfile") or die "$! creating $outfile";
|
||||
print OUT "\@ECHO OFF\n";
|
||||
print OUT "PATH %PATH%;", join(';', binDirs()), "\n";
|
||||
print OUT "PATH \%PATH\%;", join(';', binDirs()), "\n";
|
||||
close OUT;
|
||||
}
|
||||
|
||||
sub relPaths {
|
||||
unlink $outfile;
|
||||
open(OUT, ">$outfile") or die "$! creating $outfile";
|
||||
print OUT "export PATH=\$PATH:",
|
||||
join(':', map {m/\s/ ? "\"$_\"" : $_ } binDirs()), "\n";
|
||||
close OUT;
|
||||
}
|
||||
|
||||
|
||||
34
src/tools/makeIncludeDbd.pl
Normal file
34
src/tools/makeIncludeDbd.pl
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env perl
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# $Revision-Id$
|
||||
|
||||
use strict;
|
||||
use File::Basename;
|
||||
|
||||
sub Usage {
|
||||
my $txt = shift;
|
||||
|
||||
print "Usage: makeIncludeDbd.pl input file list ... outfile\n";
|
||||
print "Error: $txt\n" if $txt;
|
||||
exit 2;
|
||||
}
|
||||
|
||||
Usage("No input files specified")
|
||||
unless $#ARGV > 1;
|
||||
|
||||
my $target = pop @ARGV;
|
||||
my @inputs = map { basename($_); } @ARGV;
|
||||
|
||||
open(my $OUT, '>', $target)
|
||||
or die "$0: Can't create $target, $!\n";
|
||||
|
||||
print $OUT "# Generated file $target\n\n";
|
||||
print $OUT map { "include \"$_\"\n"; } @inputs;
|
||||
|
||||
close $OUT;
|
||||
Reference in New Issue
Block a user