Compare commits
277 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee91b29fe0 | ||
|
|
0c9254f768 | ||
|
|
073f3f33a6 | ||
|
|
77c00faabe | ||
|
|
117e294ec6 | ||
|
|
afdb6af0c7 | ||
|
|
b97f04464c | ||
|
|
b2473f939f | ||
|
|
c05fa4ddb7 | ||
|
|
c8fcfbea9f | ||
|
|
07aa712b07 | ||
|
|
1865e84321 | ||
|
|
7efba21d1f | ||
|
|
c22c94a3aa | ||
|
|
542353aedb | ||
|
|
c670ef0199 | ||
|
|
43ea188385 | ||
|
|
ffa7399c71 | ||
|
|
78b910574d | ||
|
|
020f09e83a | ||
|
|
ac590e671e | ||
|
|
e0dea7ab23 | ||
|
|
7aefee6737 | ||
|
|
f9564a3b82 | ||
|
|
17da4bfc1f | ||
|
|
2fe8d82872 | ||
|
|
2ff9f249a0 | ||
|
|
5ec1340902 | ||
|
|
269f828733 | ||
|
|
4ce60c9797 | ||
|
|
d5fc8c9b76 | ||
|
|
93c0dcd3e5 | ||
|
|
fd583ac594 | ||
|
|
9621ff1552 | ||
|
|
3f49787be1 | ||
|
|
bbd9ba0b6d | ||
|
|
fcd443a026 | ||
|
|
02809de380 | ||
|
|
987943be4e | ||
|
|
16a3657613 | ||
|
|
8ae7930375 | ||
|
|
05d3e640cd | ||
|
|
efe8d69f82 | ||
|
|
2c65739286 | ||
|
|
93fe387e87 | ||
|
|
ad0695b119 | ||
|
|
8f880a614c | ||
|
|
7805fbe295 | ||
|
|
2a81e0b338 | ||
|
|
5e0dc5d1c9 | ||
|
|
1b16c7130b | ||
|
|
925d03bcec | ||
|
|
1151d78cb5 | ||
|
|
b4c625d8d1 | ||
|
|
096fb5e0a2 | ||
|
|
8640e1c9fb | ||
|
|
d154d8eab7 | ||
|
|
3fbdcdb032 | ||
|
|
eedf296cd2 | ||
|
|
f0d7d42ab4 | ||
|
|
5761028d6f | ||
|
|
fbc1ed26f0 | ||
|
|
93b47f103e | ||
|
|
1917d0563a | ||
|
|
da4bf2d5ee | ||
|
|
ec3a89e43c | ||
|
|
62475a383e | ||
|
|
6ba949cdb4 | ||
|
|
5d37bc2996 | ||
|
|
2eaede9925 | ||
|
|
12d68e6021 | ||
|
|
78a7ad168e | ||
|
|
f716b1b26a | ||
|
|
0bbb381efd | ||
|
|
f2a1834dc9 | ||
|
|
6572816a6a | ||
|
|
c304e29da6 | ||
|
|
9fd8eec2e2 | ||
|
|
a873c4f3dc | ||
|
|
26650d6cbf | ||
|
|
d1a0b74c83 | ||
|
|
83428d2b2c | ||
|
|
1235ad76e7 | ||
|
|
1cad1c5ba6 | ||
|
|
12fc7ed07c | ||
|
|
564ef01951 | ||
|
|
f65b2119ad | ||
|
|
4a9fe82575 | ||
|
|
2a1f790909 | ||
|
|
d752b962d5 | ||
|
|
b4db176e48 | ||
|
|
d397f0fd92 | ||
|
|
b096dc3e01 | ||
|
|
be8de34130 | ||
|
|
579a0791ea | ||
|
|
e51cc39b0c | ||
|
|
e296e99667 | ||
|
|
8677c84528 | ||
|
|
052573f4ca | ||
|
|
7a727bbd41 | ||
|
|
0748adfb9a | ||
|
|
4813b37538 | ||
|
|
bbd94928bb | ||
|
|
c13a4f24ce | ||
|
|
d1af663705 | ||
|
|
4eafb6fd8e | ||
|
|
33f3145fcc | ||
|
|
c71afb631c | ||
|
|
da94b7a2e4 | ||
|
|
311ad57e93 | ||
|
|
30e634b97b | ||
|
|
421a2c8eb9 | ||
|
|
cfe9a51c5d | ||
|
|
066984e11d | ||
|
|
6c062981fb | ||
|
|
54e94a1e12 | ||
|
|
414e5b82b8 | ||
|
|
b99a7b9252 | ||
|
|
43f6a06bcd | ||
|
|
7121b016d5 | ||
|
|
8b24383e9e | ||
|
|
e99fe61e07 | ||
|
|
23cef0339e | ||
|
|
611cb3f52e | ||
|
|
7e60faae10 | ||
|
|
4f1b244589 | ||
|
|
dcb1f75b4d | ||
|
|
89f13aa51b | ||
|
|
d2db634ed2 | ||
|
|
6bf66d1c93 | ||
|
|
865a870912 | ||
|
|
9bfc8d8fad | ||
|
|
23a856ae9b | ||
|
|
6884e0ce61 | ||
|
|
9e778511ee | ||
|
|
bad1b0ead3 | ||
|
|
ecf5ab4a4c | ||
|
|
2f510af603 | ||
|
|
0f2e26bc4c | ||
|
|
26a4e1489f | ||
|
|
19be96ec3a | ||
|
|
6397204354 | ||
|
|
89a858f655 | ||
|
|
0b410c1b03 | ||
|
|
4f8134c63c | ||
|
|
ef2da59c24 | ||
|
|
40c9e4799b | ||
|
|
675c2aff14 | ||
|
|
1636f3d9fe | ||
|
|
1e7c80c909 | ||
|
|
2096c60652 | ||
|
|
3009f88f64 | ||
|
|
b783427bf7 | ||
|
|
85b6b5c507 | ||
|
|
20627c0465 | ||
|
|
17bd1ae6d0 | ||
|
|
f71fe62bc3 | ||
|
|
825c075df7 | ||
|
|
ff91ede462 | ||
|
|
1d749ac7e7 | ||
|
|
6377c2e1e4 | ||
|
|
8069d9d80b | ||
|
|
46993a5e38 | ||
|
|
2bb02e732a | ||
|
|
428dfe7a5c | ||
|
|
5dcd3483ba | ||
|
|
1c3ffa1c76 | ||
|
|
cc946b760c | ||
|
|
00549c832a | ||
|
|
c52088205e | ||
|
|
e95fcb2e06 | ||
|
|
a7f0525ac7 | ||
|
|
051c059938 | ||
|
|
fab5ce675f | ||
|
|
0a4981093a | ||
|
|
99500b9be4 | ||
|
|
0821c8c4ff | ||
|
|
da5455ed22 | ||
|
|
58c78af4f9 | ||
|
|
813166128e | ||
|
|
b2012fdfb5 | ||
|
|
c12a35e388 | ||
|
|
8a9707e74f | ||
|
|
2d4301f0bb | ||
|
|
268e59b052 | ||
|
|
5b74799605 | ||
|
|
cd49e245c2 | ||
|
|
19447dc7ff | ||
|
|
dd311be319 | ||
|
|
4448317d73 | ||
|
|
ec6d86c91c | ||
|
|
4302da3628 | ||
|
|
25315882ec | ||
|
|
f8d6cd98a0 | ||
|
|
5fe3e8bfb5 | ||
|
|
8d1c416551 | ||
|
|
07b09eed1f | ||
|
|
1e1c52cb69 | ||
|
|
6e88d48615 | ||
|
|
23c71e9965 | ||
|
|
3992d4b92a | ||
|
|
40a3a66745 | ||
|
|
d0dcd61b23 | ||
|
|
5ec0633282 | ||
|
|
33e565b67d | ||
|
|
7edc0c67ca | ||
|
|
056edc0d8a | ||
|
|
fc66793ee2 | ||
|
|
37b6cbb50c | ||
|
|
cca6a5d05a | ||
|
|
82385c9f1b | ||
|
|
cbc7af0ef8 | ||
|
|
bed1c618a8 | ||
|
|
7df97f074e | ||
|
|
fe71fc98b8 | ||
|
|
d3a9ba7701 | ||
|
|
bb58598eba | ||
|
|
899feb24b2 | ||
|
|
fb785e45c7 | ||
|
|
519208833f | ||
|
|
ae2180f5b5 | ||
|
|
dafe2a83a3 | ||
|
|
ebfaca8228 | ||
|
|
da78e01e89 | ||
|
|
caf70216d3 | ||
|
|
95fd255dd6 | ||
|
|
2dd16f4362 | ||
|
|
4c2b8819cd | ||
|
|
8992d5a593 | ||
|
|
802f29df47 | ||
|
|
16c419350b | ||
|
|
935ab02bc1 | ||
|
|
63d8651474 | ||
|
|
c01967d64f | ||
|
|
d1986edd9e | ||
|
|
7627454f63 | ||
|
|
667f74759d | ||
|
|
1f726c8760 | ||
|
|
08b7802009 | ||
|
|
f6c4099634 | ||
|
|
c76041b14c | ||
|
|
7ea544673a | ||
|
|
6e6ae4354b | ||
|
|
61e82ee1ae | ||
|
|
28b3b1678c | ||
|
|
efb5ba27ae | ||
|
|
574db56740 | ||
|
|
998c3c1648 | ||
|
|
6a592dc2c0 | ||
|
|
ac5c7b0314 | ||
|
|
d674866219 | ||
|
|
a1bd644502 | ||
|
|
a38dccfb1a | ||
|
|
17edfd0652 | ||
|
|
afd48be98c | ||
|
|
d92af8c44d | ||
|
|
2af37d076d | ||
|
|
64c1a28f69 | ||
|
|
954874dbd6 | ||
|
|
673cb24fc2 | ||
|
|
05c347434b | ||
|
|
13294f80cc | ||
|
|
778aa18c00 | ||
|
|
0348c2295b | ||
|
|
8a5d1a08ad | ||
|
|
1e028d68d8 | ||
|
|
d33c402b00 | ||
|
|
bc2a47b849 | ||
|
|
0a0b9a93a2 | ||
|
|
d949e34c13 | ||
|
|
db4f208659 | ||
|
|
e82449171f | ||
|
|
e7bba39737 | ||
|
|
f97c1a345e | ||
|
|
4a5a675ef8 | ||
|
|
2d4243981f | ||
|
|
2fb0b0763d |
10
README
10
README
@@ -2,14 +2,14 @@
|
||||
EPICS Base - the central core of a control system toolkit
|
||||
---------------------------------------------------------
|
||||
|
||||
Copyright (c) 1991-2003 The University of Chicago, as Operator
|
||||
of Argonne National Laboratory.
|
||||
Copyright UChicago Argonne LLC, as Operator of Argonne
|
||||
National Laboratory.
|
||||
Copyright (c) 1991-2003 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 the
|
||||
file LICENSE that is included with this distribution.
|
||||
EPICS Base is distributed subject to a Software License
|
||||
Agreement found in the file LICENSE that is included with
|
||||
this distribution.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
# 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
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Epics base directories
|
||||
# EPICS Base directories
|
||||
|
||||
EPICS_BASE_HOST_BIN = $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH)
|
||||
EPICS_BASE_HOST_LIB = $(EPICS_BASE)/lib/$(EPICS_HOST_ARCH)
|
||||
@@ -19,12 +18,12 @@ ifdef T_A
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Epics base Ioc libraries
|
||||
# EPICS Base Ioc libraries
|
||||
|
||||
EPICS_BASE_IOC_LIBS += dbRecStd dbCore ca Com
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Epics base Host libraries
|
||||
# EPICS Base Host libraries
|
||||
|
||||
EPICS_BASE_HOST_LIBS += cas gdd
|
||||
EPICS_BASE_HOST_LIBS += ca Com
|
||||
@@ -37,17 +36,16 @@ ifdef BASE_TOP
|
||||
SHRLIB_VERSION = $(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)
|
||||
# Windows only allows 2 levels of version numbering
|
||||
PROD_VERSION = $(EPICS_VERSION).$(EPICS_REVISION)
|
||||
BASE_CPPFLAGS += -DUSE_TYPED_RSET
|
||||
endif # BASE_TOP
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Base c preprocessor flags
|
||||
|
||||
BASE_CPPFLAGS =
|
||||
|
||||
# osithread default stack
|
||||
OSITHREAD_USE_DEFAULT_STACK = NO
|
||||
OSITHREAD_DEFAULT_STACK_FLAGS_YES = -DOSITHREAD_USE_DEFAULT_STACK
|
||||
OSITHREAD_DEFAULT_STACK_FLAGS_NO =
|
||||
|
||||
BASE_CPPFLAGS += $(OSITHREAD_DEFAULT_STACK_FLAGS_$(OSITHREAD_USE_DEFAULT_STACK))
|
||||
|
||||
#---------------------------------------------------------------
|
||||
@@ -59,7 +57,7 @@ TOOLS = $(abspath $(EPICS_BASE_HOST_BIN))
|
||||
FIND_TOOL = $(firstword $(wildcard $(TOOLS)/$(1) $(TOP)/src/tools/$(1)))
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Epics base build tools and tool flags
|
||||
# EPICS Base build tools and tool flags
|
||||
|
||||
MAKEBPT = $(TOOLS)/makeBpt$(HOSTEXE)
|
||||
DBEXPAND = $(PERL) $(TOOLS)/dbdExpand.pl
|
||||
@@ -69,11 +67,11 @@ REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl
|
||||
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
|
||||
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
|
||||
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
||||
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG)
|
||||
|
||||
#-------------------------------------------------------
|
||||
#---------------------------------------------------------------
|
||||
# tools for installing libraries and products
|
||||
INSTALL_QUIETLY := $(if $(findstring s,$(MAKEFLAGS)),-q,)
|
||||
INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(INSTALL_QUIETLY)
|
||||
INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(QUIET_FLAG)
|
||||
INSTALL_PRODUCT = $(INSTALL)
|
||||
INSTALL_LIBRARY = $(INSTALL)
|
||||
|
||||
@@ -83,7 +81,7 @@ MKMF = $(PERL) $(TOOLS)/mkmf.pl
|
||||
REPLACEVAR = $(PERL) $(TOOLS)/replaceVAR.pl
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# private versions of lex/yacc from EPICS
|
||||
# Our versions of lex (flex) and yacc (antelope)
|
||||
EYACC = $(TOOLS)/antelope$(HOSTEXE)
|
||||
ELEX = $(TOOLS)/e_flex$(HOSTEXE) -S$(EPICS_BASE)/include/flex.skel.static
|
||||
|
||||
@@ -91,28 +89,6 @@ YACC = $(EYACC)
|
||||
LEX = $(ELEX)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Our use of msi is incompatible with older versions
|
||||
# The 3.15 version of msi supports new options
|
||||
|
||||
MSI3_15 = $(EPICS_BASE_HOST_BIN)/msi
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# External tools and tool flags - must be in path or defined in application
|
||||
|
||||
ADL2DL ?= adl2dl
|
||||
|
||||
# sch2edif compiler and flags
|
||||
SCH2EDIF = sch2edif
|
||||
SCH2EDIF_PATH =
|
||||
SCH2EDIF_SYSFLAGS = -n -ap -p.+..+$(SCH2EDIF_PATH)+$(CAPFAST_TEMPLATES)/sym+
|
||||
SCH2EDIF_FLAGS =
|
||||
|
||||
# e2db and flags
|
||||
# - again there is an assumption where edb.def is installed.
|
||||
E2DB ?= e2db
|
||||
E2DB_SYSFLAGS = -ate -d $(CAPFAST_TEMPLATES)/edb.def
|
||||
E2DB_FLAGS =
|
||||
|
||||
DBST ?= dbst
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
# in the file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# EPICS Version information
|
||||
@@ -15,26 +15,37 @@
|
||||
# EPICS_SITE_VERSION is defined in CONFIG_SITE for sites that want a local
|
||||
# version number to be included in the reported version string.
|
||||
|
||||
# In 3.15 we still define BASE_3_14 so "ifdef BASE_3_14" means
|
||||
# 3.14 or later, but "ifeq ($(BASE_3_14),YES)" means 3.14 only.
|
||||
# We define BASE_3_14 and BASE_3_15 as NO and BASE_3_16 as YES, so
|
||||
# ifdef BASE_3_14
|
||||
# true for 3.14 or later
|
||||
# ifdef BASE_3_15
|
||||
# true for 3.15 or later
|
||||
# ifeq ($(BASE_3_14),YES)
|
||||
# true for 3.14.x only
|
||||
# ifeq ($(BASE_3_15),YES)
|
||||
# true for 3.15 only
|
||||
# ifeq ($(BASE_3_16),YES)
|
||||
# true for 3.16 only.
|
||||
|
||||
BASE_3_14 = NO
|
||||
BASE_3_15 = YES
|
||||
BASE_3_15 = NO
|
||||
BASE_3_16 = YES
|
||||
|
||||
# EPICS_VERSION must be a number >0 and <256
|
||||
EPICS_VERSION = 3
|
||||
|
||||
# EPICS_REVISION must be a number >=0 and <256
|
||||
EPICS_REVISION = 15
|
||||
EPICS_REVISION = 16
|
||||
|
||||
# EPICS_MODIFICATION must be a number >=0 and <256
|
||||
EPICS_MODIFICATION = 5
|
||||
EPICS_MODIFICATION = 1
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included if zero
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
|
||||
# This will end in -DEV between official releases
|
||||
EPICS_DEV_SNAPSHOT=-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-pre1
|
||||
#EPICS_DEV_SNAPSHOT=-pre1-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-pre2
|
||||
@@ -43,7 +54,7 @@ EPICS_DEV_SNAPSHOT=-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-rc1-DEV
|
||||
#EPICS_DEV_SNAPSHOT=-rc2
|
||||
#EPICS_DEV_SNAPSHOT=-rc2-DEV
|
||||
#EPICS_DEV_SNAPSHOT=
|
||||
EPICS_DEV_SNAPSHOT=
|
||||
|
||||
# No changes should be needed below here
|
||||
|
||||
|
||||
@@ -38,10 +38,6 @@ BUILD_ARCHS = $(EPICS_HOST_ARCH) $(CROSS1) $(CROSS2)
|
||||
# otherwise override this in os/CONFIG_SITE.<host_arch>.Common
|
||||
PERL = perl -CSD
|
||||
|
||||
#-------------------------------------------------------
|
||||
# dbst based database optimization default
|
||||
DB_OPT = NO
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Check configure/RELEASE file for consistency
|
||||
CHECK_RELEASE_YES = checkRelease
|
||||
@@ -83,6 +79,7 @@ IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
|
||||
# Make echo output - suppress echoing if make's '-s' flag is set
|
||||
NOP = :
|
||||
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
|
||||
QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,)
|
||||
|
||||
#-------------------------------------------------------
|
||||
ifdef T_A
|
||||
@@ -332,6 +329,14 @@ COMPILE.cpp = $(CCC) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES)
|
||||
# C preprocessor command
|
||||
PREPROCESS.cpp = $(CPP) $(CPPFLAGS) $(INCLUDES) $< > $@
|
||||
|
||||
#--------------------------------------------------
|
||||
# genVersion header defaults
|
||||
|
||||
# C macro name
|
||||
GENVERSIONMACRO = VCSVERSION
|
||||
# C macro default value (empty to use date+time)
|
||||
GENVERSIONDEFAULT =
|
||||
|
||||
#--------------------------------------------------
|
||||
# Header dependency file generation
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@ EPICS_CA_CONN_TMO=30.0
|
||||
EPICS_CA_REPEATER_PORT=5065
|
||||
EPICS_CA_SERVER_PORT=5064
|
||||
EPICS_CA_MAX_ARRAY_BYTES=16384
|
||||
EPICS_CA_AUTO_ARRAY_BYTES=YES
|
||||
EPICS_CA_BEACON_PERIOD=15.0
|
||||
EPICS_CA_MAX_SEARCH_PERIOD=300.0
|
||||
EPICS_CA_MCAST_TTL=1
|
||||
EPICS_CAS_BEACON_PERIOD=
|
||||
EPICS_CAS_BEACON_PORT=
|
||||
EPICS_CAS_AUTO_BEACON_ADDR_LIST=""
|
||||
|
||||
@@ -58,8 +58,11 @@ EPICS_TS_NTP_INET=
|
||||
# Prompt string
|
||||
# IOCSH_HISTSIZE
|
||||
# Number of lines of command history to keep.
|
||||
# IOCSH_HISTEDIT_DISABLE
|
||||
# Prevents use of readline or equivalent if defined.
|
||||
IOCSH_PS1="epics> "
|
||||
IOCSH_HISTSIZE=50
|
||||
IOCSH_HISTEDIT_DISABLE=
|
||||
|
||||
# Log Server:
|
||||
# EPICS_IOC_LOG_INET
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
#*************************************************************************
|
||||
#RULES.Db
|
||||
|
||||
# Set db substitutions file suffix
|
||||
# Set db substitutions and template file suffixes
|
||||
SUBST_SUFFIX ?= .substitutions
|
||||
TEMPL_SUFFIX ?= .template
|
||||
|
||||
##################################################### vpath
|
||||
#---------------------------------------------------------------
|
||||
# vpath
|
||||
|
||||
vpath %.pm $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
|
||||
vpath %.pod $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
|
||||
@@ -19,12 +21,13 @@ vpath %.dbd $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
|
||||
vpath %.db $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
|
||||
vpath %.vdb $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
|
||||
vpath %$(SUBST_SUFFIX) $(USR_VPATH) $(SRC_DIRS) $(COMMON_DIR)
|
||||
vpath %.template $(USR_VPATH) $(SRC_DIRS) $(COMMON_DIR)
|
||||
vpath %$(TEMPL_SUFFIX) $(USR_VPATH) $(SRC_DIRS) $(COMMON_DIR)
|
||||
vpath bpt%.data $(USR_VPATH) $(SRC_DIRS) $(COMMON_DIR)
|
||||
vpath %.acf $(USR_VPATH) $(SRC_DIRS) $(COMMON_DIR)
|
||||
vpath %.acs $(USR_VPATH) $(SRC_DIRS) $(COMMON_DIR)
|
||||
|
||||
##################################################### dbflags dbdflags
|
||||
#---------------------------------------------------------------
|
||||
# dbflags dbdflags
|
||||
|
||||
DBD_SEARCH_DIRS = . .. $(COMMON_DIR) $(SRC_DIRS) $(INSTALL_DBD) $(RELEASE_DBD_DIRS)
|
||||
DB_SEARCH_DIRS = . .. $(COMMON_DIR) $(SRC_DIRS) $(INSTALL_DB) $(RELEASE_DB_DIRS)
|
||||
@@ -33,13 +36,15 @@ DBDFLAGS = $(USR_DBDFLAGS) $(CMD_DBDFLAGS) $(addprefix -I,$(DBD_SEARCH_DIRS))
|
||||
DBFLAGS = $($*_DBFLAGS) $(USR_DBFLAGS) $(CMD_DBFLAGS) $(addprefix -I,$(DB_SEARCH_DIRS))
|
||||
REGRDDFLAGS = $(DBDFLAGS) $($*_REGRDDFLAGS) $(USR_REGRDDFLAGS) $(CMD_REGRDDFLAGS)
|
||||
|
||||
##################################################### Targets
|
||||
#---------------------------------------------------------------
|
||||
# Targets
|
||||
|
||||
# ---------------------------------------------------
|
||||
# To allow os specific dbd files AND have the -j option work properly,
|
||||
|
||||
CROSS_TARGET_OS_TYPES = $(sort $(foreach target, \
|
||||
$(EPICS_HOST_ARCH) $(CROSS_COMPILER_TARGET_ARCHS),$(firstword $(subst -, ,$(target)))))
|
||||
CROSS_TARGET_OS_TYPES = $(sort $(foreach target, \
|
||||
$(EPICS_HOST_ARCH) $(CROSS_COMPILER_TARGET_ARCHS), \
|
||||
$(firstword $(subst -, ,$(target)))))
|
||||
DBD += $(foreach type, $(CROSS_TARGET_OS_TYPES), $(DBD_$(type)))
|
||||
|
||||
# Users add os specific dbd files to a Makefile as follows
|
||||
@@ -86,31 +91,28 @@ SOURCE_DB_bbb = $(foreach dir, $(GENERIC_SRC_DIRS), $(SOURCE_DB_aaa) )
|
||||
SOURCE_DB_aaa = $(addsuffix /$(file), $(dir) )
|
||||
|
||||
COMMONS = $(COMMON_DIR)/*.dbd $(COMMON_DIR)/*.db $(COMMON_DIR)/*.h \
|
||||
$(COMMON_DIR)/*$(SUBST_SUFFIX) $(COMMON_DIR)/*.template
|
||||
$(COMMON_DIR)/*$(SUBST_SUFFIX) $(COMMON_DIR)/*$(TEMPL_SUFFIX)
|
||||
|
||||
# Remove trailing numbers (to 99) on stem
|
||||
TEMPLATE1=$(patsubst %0,%,$(patsubst %1,%,$(patsubst %2,%,$(patsubst %3,%,$(patsubst %4,%, \
|
||||
$(patsubst %5,%,$(patsubst %6,%,$(patsubst %7,%,$(patsubst %8,%,$(patsubst %9,%, \
|
||||
$*))))))))))
|
||||
TEMPLATE2=$(patsubst %0,%,$(patsubst %1,%,$(patsubst %2,%,$(patsubst %3,%,$(patsubst %4,%, \
|
||||
$(patsubst %5,%,$(patsubst %6,%,$(patsubst %7,%,$(patsubst %8,%,$(patsubst %9,%, \
|
||||
$(TEMPLATE1)))))))))))
|
||||
TEMPLATE3=$(addsuffix .template,$(addprefix ../,$(TEMPLATE2)))
|
||||
TEMPLATE_FILENAME=$(firstword $(wildcard $($*_TEMPLATE) $(addprefix ../,$($*_TEMPLATE)) ../$*.template $(TEMPLATE3) ../template))
|
||||
|
||||
# dbst based database optimization
|
||||
ifeq '$(DB_OPT)' 'YES'
|
||||
RAW=.raw
|
||||
DBS = $(filter %.db,$(DB)) $(addsuffix $(RAW),$(filter %.db,$(DB)))
|
||||
COMMON_DBS = $(addprefix $(COMMON_DIR)/,$(DBS))
|
||||
endif
|
||||
TEMPLATE1 = $(patsubst %0,%,$(patsubst %1,%,$(patsubst %2,%,$(patsubst %3,%, \
|
||||
$(patsubst %4,%,$(patsubst %5,%,$(patsubst %6,%,$(patsubst %7,%, \
|
||||
$(patsubst %8,%,$(patsubst %9,%,$*))))))))))
|
||||
TEMPLATE2 = $(patsubst %0,%,$(patsubst %1,%,$(patsubst %2,%,$(patsubst %3,%, \
|
||||
$(patsubst %4,%,$(patsubst %5,%,$(patsubst %6,%,$(patsubst %7,%, \
|
||||
$(patsubst %8,%,$(patsubst %9,%,$(TEMPLATE1)))))))))))
|
||||
TEMPLATE3 = $(addsuffix $(TEMPL_SUFFIX),$(addprefix ../,$(TEMPLATE2)))
|
||||
TEMPLATE_FILENAME = $(firstword $(wildcard $($*_TEMPLATE) \
|
||||
$(addprefix ../,$($*_TEMPLATE)) ../$*$(TEMPL_SUFFIX) $(TEMPLATE3) \
|
||||
../template))
|
||||
|
||||
INSTALL_DB_INSTALLS = $(addprefix $(INSTALL_DB)/,$(notdir $(DB_INSTALLS)))
|
||||
INSTALL_DBD_INSTALLS = $(addprefix $(INSTALL_DBD)/,$(notdir $(DBD_INSTALLS)))
|
||||
|
||||
COMMONDEP_TARGET = $(COMMON_DIR)/$(basename $@)
|
||||
|
||||
##################################################### acf files
|
||||
#---------------------------------------------------------------
|
||||
# acf files
|
||||
|
||||
# An access security configuration file, *.acf, can be created from
|
||||
# an *.acs file (has format of acf file plus #include "filename" lines)
|
||||
|
||||
@@ -123,7 +125,8 @@ ACF_INCLUDES = -I. $(TARGET_INCLUDES) $(USR_INCLUDES)\
|
||||
ACFDEPENDS_CMD = $(MKMF) -m $@ $(ACF_INCLUDES) $(COMMONDEP_TARGET) $<
|
||||
ACF_CMD = $(CPP) $(ACF_CPPFLAGS) $(ACF_INCLUDES) $< > $@
|
||||
|
||||
##################################################### dependancies
|
||||
#---------------------------------------------------------------
|
||||
# dependencies
|
||||
|
||||
HINC += $(addsuffix .h,$(DBDINC_NAME))
|
||||
COMMON_DBDINC += $(addprefix $(COMMON_DIR)/,$(HINC))
|
||||
@@ -133,12 +136,12 @@ DBDDEPENDS_FILES += $(addsuffix $(DEP),$(HINC) \
|
||||
$(patsubst $(COMMON_DIR)/%,%, \
|
||||
$(filter-out $(COMMON_DIR)/bpt%.dbd,$(COMMON_DBDS))))
|
||||
|
||||
#####################################################
|
||||
#---------------------------------------------------------------
|
||||
|
||||
ifndef T_A
|
||||
|
||||
DEP = .d
|
||||
TEMPLATE3+=$(addsuffix .template, $(TEMPLATE2))
|
||||
TEMPLATE3 += $(addsuffix $(TEMPL_SUFFIX), $(TEMPLATE2))
|
||||
|
||||
COMMON_DIR = .
|
||||
INSTALL_DBDS =
|
||||
@@ -153,18 +156,13 @@ ACTIONS += install
|
||||
ACTIONS += buildInstall
|
||||
ACTIONS += runtests tapfiles clean-tests test-results junitfiles
|
||||
|
||||
actionArchTargets = $(foreach x, $(ACTIONS),\ $(foreach arch,$(BUILD_ARCHS), $(x)$(DIVIDER)$(arch)))
|
||||
actionArchTargets = $(foreach action, $(ACTIONS), \
|
||||
$(foreach arch, $(BUILD_ARCHS), $(action)$(DIVIDER)$(arch)))
|
||||
cleanArchTargets = $(foreach arch, $(BUILD_ARCHS), clean$(DIVIDER)$(arch))
|
||||
|
||||
cleanArchTargets = $(foreach arch,$(BUILD_ARCHS), clean$(DIVIDER)$(arch))
|
||||
-include $(TOP)/configure/CONFIG_APP_INCLUDE
|
||||
|
||||
all: install
|
||||
ifeq ($(EPICS_HOST_ARCH),$T_A)
|
||||
host: install
|
||||
else
|
||||
# Do nothing
|
||||
host:
|
||||
endif
|
||||
|
||||
install: buildInstall
|
||||
|
||||
@@ -172,20 +170,30 @@ buildInstall : build
|
||||
|
||||
rebuild: clean install
|
||||
|
||||
.PHONY: all host $(ACTIONS)
|
||||
.PHONY: all $(ACTIONS)
|
||||
|
||||
$(actionArchTargets) $(BUILD_ARCHS): install
|
||||
$(cleanArchTargets): clean
|
||||
|
||||
.PHONY: $(BUILD_ARCHS) $(actionArchTargets) $(cleanArchTargets)
|
||||
|
||||
endif # T_A defined
|
||||
else
|
||||
# T_A is defined
|
||||
ifeq ($(EPICS_HOST_ARCH),$(T_A))
|
||||
host: install
|
||||
else
|
||||
host:
|
||||
endif
|
||||
|
||||
.PHONY: host
|
||||
endif # T_A
|
||||
|
||||
ifneq (,$(strip $(DBDDEPENDS_FILES)))
|
||||
-include $(DBDDEPENDS_FILES)
|
||||
endif
|
||||
|
||||
##################################################### build dependancies, clean rule
|
||||
#---------------------------------------------------------------
|
||||
# build dependancies, clean rule
|
||||
|
||||
inc : $(COMMON_INC) $(INSTALL_INC)
|
||||
|
||||
@@ -205,7 +213,8 @@ db_clean :
|
||||
|
||||
realclean: clean
|
||||
|
||||
##################################################### Dependency files
|
||||
#---------------------------------------------------------------
|
||||
# Dependency files
|
||||
|
||||
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd
|
||||
@$(RM) $@
|
||||
@@ -256,19 +265,19 @@ menu%.h$(DEP): ../menu%.dbd
|
||||
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $($*_DBD) > $@
|
||||
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
|
||||
|
||||
%.db$(RAW)$(DEP): %$(SUBST_SUFFIX)
|
||||
%.db$(DEP): %$(SUBST_SUFFIX)
|
||||
@$(RM) $@
|
||||
$(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) -S$< $(TEMPLATE_FILENAME) > $@
|
||||
|
||||
%.db$(RAW)$(DEP): ../%$(SUBST_SUFFIX)
|
||||
%.db$(DEP): ../%$(SUBST_SUFFIX)
|
||||
@$(RM) $@
|
||||
$(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) -S$< $(TEMPLATE_FILENAME) > $@
|
||||
|
||||
%.db$(RAW)$(DEP): %.template
|
||||
%.db$(DEP): %$(TEMPL_SUFFIX)
|
||||
@$(RM) $@
|
||||
$(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
|
||||
%.db$(RAW)$(DEP): ../%.template
|
||||
%.db$(DEP): ../%$(TEMPL_SUFFIX)
|
||||
@$(RM) $@
|
||||
$(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) $< > $@
|
||||
|
||||
@@ -282,14 +291,8 @@ menu%.h$(DEP): ../menu%.dbd
|
||||
|
||||
.PRECIOUS: %$(DEP)
|
||||
|
||||
##################################################### CapFast filter
|
||||
|
||||
$(COMMON_DIR)/%.edf: ../%.sch $(DEPSCHS)
|
||||
@$(RM) $@
|
||||
@if [ ! -f cad.rc -a -r ../cad.rc ] ; then ln -s ../cad.rc ; fi
|
||||
$(SCH2EDIF) $(SCH2EDIF_SYSFLAGS) $(SCH2EDIF_FLAGS) -o $@ $<
|
||||
|
||||
##################################################### Substitution files
|
||||
#---------------------------------------------------------------
|
||||
# Substitution files
|
||||
|
||||
# WARNING: CREATESUBSTITUTIONS script needs output dir on command line
|
||||
|
||||
@@ -310,25 +313,21 @@ $(INSTALL_DB)/%$(SUBST_SUFFIX): ../%$(SUBST_SUFFIX)
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%$(SUBST_SUFFIX)
|
||||
|
||||
##################################################### Template files
|
||||
#---------------------------------------------------------------
|
||||
# Template files
|
||||
|
||||
$(COMMON_DIR)/%.template: $(COMMON_DIR)/%.edf
|
||||
@$(RM) $@
|
||||
$(E2DB) $(E2DB_SYSFLAGS) $(E2DB_FLAGS) -n $@.VAR $<
|
||||
@$(REPLACEVAR) < $@.VAR > $@
|
||||
@$(RM) $@.VAR
|
||||
|
||||
$(INSTALL_DB)/%.template: %.template
|
||||
$(INSTALL_DB)/%$(TEMPL_SUFFIX): %$(TEMPL_SUFFIX)
|
||||
$(ECHO) "Installing template file $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
$(INSTALL_DB)/%.template: ../%.template
|
||||
$(INSTALL_DB)/%$(TEMPL_SUFFIX): ../%$(TEMPL_SUFFIX)
|
||||
$(ECHO) "Installing template file $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.template
|
||||
.PRECIOUS: $(COMMON_DIR)/%$(TEMPL_SUFFIX)
|
||||
|
||||
##################################################### INC files
|
||||
#---------------------------------------------------------------
|
||||
# INC files
|
||||
|
||||
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd
|
||||
@$(RM) $(notdir $@)
|
||||
@@ -362,7 +361,8 @@ $(COMMON_DIR)/menu%.h: ../menu%.dbd
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.h
|
||||
|
||||
##################################################### DBD files
|
||||
#---------------------------------------------------------------
|
||||
# DBD files
|
||||
|
||||
$(COMMON_DIR)/bpt%.dbd: bpt%.data
|
||||
@$(RM) $(notdir $@)
|
||||
@@ -425,7 +425,8 @@ $(foreach file, $(DBD_INSTALLS), $(eval $(call DBD_INSTALLS_template, $(file))))
|
||||
|
||||
.PRECIOUS: $(COMMON_DBDS) $(COMMON_DIR)/%.dbd
|
||||
|
||||
##################################################### HTML files
|
||||
#---------------------------------------------------------------
|
||||
# HTML files
|
||||
|
||||
$(COMMON_DIR)/%.html: %.dbd.pod $(TOOLS)/dbdToHtml.pl
|
||||
@$(RM) $(notdir $@)
|
||||
@@ -444,37 +445,44 @@ $(COMMON_DIR)/%.html: %.pm $(TOOLS)/podToHtml.pl
|
||||
|
||||
$(COMMON_DIR)/%.html: ../%.pm $(TOOLS)/podToHtml.pl
|
||||
@$(RM) $(notdir $@)
|
||||
$(PERL) $(TOOLS)/podToHtml.pl -o $(notdir $@) $<
|
||||
$(PERL) $(TOOLS)/podToHtml.pl -s -o $(notdir $@) $<
|
||||
@$(MKDIR) $(dir $@)
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.html: ../%.pl $(TOOLS)/podToHtml.pl
|
||||
@$(RM) $(notdir $@)
|
||||
$(PERL) $(TOOLS)/podToHtml.pl -s -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.html %.html
|
||||
|
||||
##################################################### DB files
|
||||
#---------------------------------------------------------------
|
||||
# DB files
|
||||
|
||||
$(COMMON_DIR)/%.db$(RAW): $(COMMON_DIR)/%.edf
|
||||
$(COMMON_DIR)/%.db: $(COMMON_DIR)/%.edf
|
||||
$(E2DB) $(E2DB_SYSFLAGS) $(E2DB_FLAGS) -n $*.VAR $<
|
||||
@$(REPLACEVAR) < $*.VAR > $@
|
||||
@$(RM) $*.VAR
|
||||
|
||||
$(COMMON_DIR)/%.db$(RAW): %$(SUBST_SUFFIX)
|
||||
$(COMMON_DIR)/%.db: %$(SUBST_SUFFIX)
|
||||
$(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"
|
||||
@$(RM) $(notdir $@)
|
||||
$(MSI3_15) $(DBFLAGS) -o $(notdir $@) -S$< $(TEMPLATE_FILENAME)
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.db$(RAW): ../%$(SUBST_SUFFIX)
|
||||
$(COMMON_DIR)/%.db: ../%$(SUBST_SUFFIX)
|
||||
$(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"
|
||||
@$(RM) $(notdir $@)
|
||||
$(MSI3_15) $(DBFLAGS) -o $(notdir $@) -S$< $(TEMPLATE_FILENAME)
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.db$(RAW): %.template
|
||||
$(COMMON_DIR)/%.db: %$(TEMPL_SUFFIX)
|
||||
$(ECHO) "Inflating database from $<"
|
||||
@$(RM) $(notdir $@)
|
||||
$(MSI3_15) $(DBFLAGS) -o $(notdir $@) $<
|
||||
@$(MV) $(notdir $@) $@
|
||||
|
||||
$(COMMON_DIR)/%.db$(RAW): ../%.template
|
||||
$(COMMON_DIR)/%.db: ../%$(TEMPL_SUFFIX)
|
||||
$(ECHO) "Inflating database from $<"
|
||||
@$(RM) $(notdir $@)
|
||||
$(MSI3_15) $(DBFLAGS) -o $(notdir $@) $<
|
||||
@@ -492,22 +500,6 @@ $(COMMON_DIR)/%.acf: ../%.acs
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.acf
|
||||
|
||||
# dbst based database optimization
|
||||
ifeq '$(DB_OPT)' 'YES'
|
||||
|
||||
$(COMMON_DIR)/%.db$(RAW): ../%.db
|
||||
@$(RM) $@
|
||||
$(CP) $< $@
|
||||
|
||||
$(COMMON_DIR)/%.db: $(COMMON_DIR)/%.db$(RAW)
|
||||
$(ECHO) "Optimizing database $@"
|
||||
@$(RM) $@
|
||||
$(DBST) . $< -d > $@
|
||||
|
||||
.PRECIOUS: $(COMMON_DIR)/%.db
|
||||
.PRECIOUS: $(DB:%=$(COMMON_DIR)/%$(RAW))
|
||||
else
|
||||
|
||||
$(INSTALL_DB)/%: %
|
||||
$(ECHO) "Installing $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@@ -515,7 +507,6 @@ $(INSTALL_DB)/%: %
|
||||
$(INSTALL_DB)/%: ../%
|
||||
$(ECHO) "Installing $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
endif
|
||||
|
||||
$(INSTALL_DB)/%.db: $(COMMON_DIR)/%.db
|
||||
$(ECHO) "Installing created db file $@"
|
||||
@@ -531,8 +522,8 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
|
||||
.PRECIOUS: $(COMMON_DIR)/%.edf
|
||||
.PRECIOUS: $(COMMON_DBS)
|
||||
|
||||
##################################################### register record,device,driver support
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# register record,device,driver support
|
||||
|
||||
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
|
||||
@$(RM) $@
|
||||
@@ -548,4 +539,3 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
|
||||
|
||||
.PRECIOUS: %_registerRecordDeviceDriver.cpp
|
||||
|
||||
##################################################### END OF FILE
|
||||
|
||||
@@ -172,7 +172,7 @@ ifdef RES
|
||||
endif
|
||||
|
||||
$(DIRECTORY_TARGETS) :
|
||||
$(MKDIR) -p $@
|
||||
$(MKDIR) $@
|
||||
|
||||
# Install LIB_INSTALLS libraries before linking executables
|
||||
$(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS)
|
||||
@@ -383,6 +383,14 @@ endif
|
||||
@$(RM) $@
|
||||
$(PERL) $(TOOLS)/makeTestfile.pl $@ $<
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Generate header with version number from VCS
|
||||
|
||||
ifneq ($(GENVERSION),)
|
||||
$(COMMON_DIR)/$(GENVERSION): FORCE
|
||||
$(GENVERSIONHEADER) -t $(TOP) -N $(GENVERSIONMACRO) -V "$(GENVERSIONDEFAULT)" $@
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Install rules for BIN_INSTALLS and LIB_INSTALLS
|
||||
|
||||
@@ -517,7 +525,7 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
|
||||
|
||||
.PHONY: all host inc build install clean rebuild buildInstall build_clean
|
||||
.PHONY: runtests tapfiles clean-tests test-results junitfiles
|
||||
.PHONY: checkRelease warnRelease noCheckRelease
|
||||
.PHONY: checkRelease warnRelease noCheckRelease FORCE
|
||||
|
||||
endif # BASE_RULES_BUILD
|
||||
# EOF RULES_BUILD
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# CONFIG.Common.vxWorksCommon
|
||||
#
|
||||
# Definitions for vxWorks target archs
|
||||
# Sites may override these definitions in CONFIG_SITE.Common.vxWorksCommon
|
||||
# Override these definitions in CONFIG_SITE.Common.vxWorksCommon
|
||||
# or CONFIG_SITE.<host>.vxWorksCommon
|
||||
#-------------------------------------------------------
|
||||
|
||||
@@ -63,8 +63,6 @@ VXWORKS_MAJOR_VERSION = $(basename $(basename $(VXWORKS_VERSION)))
|
||||
|
||||
# These are needed for vxWorks 6.x; the GNU toolset version number
|
||||
# is in the path to the compiler tools:
|
||||
VX_GNU_VERSION_5.4 = 2.95
|
||||
VX_GNU_VERSION_5.5 = 2.96
|
||||
VX_GNU_VERSION_6.0 = 3.3.2
|
||||
VX_GNU_VERSION_6.1 = 3.3.2
|
||||
VX_GNU_VERSION_6.2 = 3.3.2
|
||||
@@ -80,30 +78,21 @@ VX_GNU_VERSION = $(VX_GNU_VERSION_$(VXWORKS_VERSION))
|
||||
VX_GNU_MAJOR_VERSION = $(basename $(basename $(VX_GNU_VERSION)))
|
||||
|
||||
#--------------------------------------------------
|
||||
# Fix WIND_BASE for vxWorks 6.x on linux
|
||||
# NB: We know the value of WIND_HOST_TYPE here, but not VXWORKS_VERSION
|
||||
# Fix old Linux WIND_HOST_TYPE
|
||||
ifeq ($(WIND_HOST_TYPE),x86-linux)
|
||||
WIND_HOST_TYPE_5 = x86-linux
|
||||
WIND_HOST_TYPE_6 = x86-linux2
|
||||
WIND_HOST_TYPE = $(WIND_HOST_TYPE_$(VXWORKS_MAJOR_VERSION))
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
endif
|
||||
|
||||
#--------------------------------------------------
|
||||
# vxWorks directory definitions
|
||||
VX_DIR_5 = $(WIND_BASE)
|
||||
VX_DIR_6 = $(WIND_BASE)/vxworks-$(VXWORKS_VERSION)
|
||||
VX_DIR = $(VX_DIR_$(VXWORKS_MAJOR_VERSION))
|
||||
VX_DIR = $(WIND_BASE)/vxworks-$(VXWORKS_VERSION)
|
||||
|
||||
VX_INCLUDE_DIRS_5 = $(VX_DIR)/target/h
|
||||
VX_INCLUDE_DIRS_6 = $(VX_DIR)/target/h $(VX_DIR)/target/h/wrn/coreip
|
||||
GNU_TARGET_INCLUDE_DIR = $(VX_INCLUDE_DIRS_$(VXWORKS_MAJOR_VERSION))
|
||||
GNU_TARGET_INCLUDE_DIR = $(VX_DIR)/target/h $(VX_DIR)/target/h/wrn/coreip
|
||||
|
||||
#--------------------------------------------------
|
||||
# vxWorks GNU directories
|
||||
|
||||
GNU_DIR_5 = $(WIND_BASE)/host/$(WIND_HOST_TYPE)
|
||||
GNU_DIR_6 = $(WIND_BASE)/gnu/$(VX_GNU_VERSION)-vxworks-$(VXWORKS_VERSION)/$(WIND_HOST_TYPE)
|
||||
GNU_DIR = $(GNU_DIR_$(VXWORKS_MAJOR_VERSION))
|
||||
GNU_DIR = $(WIND_BASE)/gnu/$(VX_GNU_VERSION)-vxworks-$(VXWORKS_VERSION)/$(WIND_HOST_TYPE)
|
||||
|
||||
#--------------------------------------------------
|
||||
# Wind River moved nm out of GNU_BIN in some versions
|
||||
@@ -123,9 +112,7 @@ NM = $(NM_DIR)/$(CMPLR_PREFIX)nm$(CMPLR_SUFFIX)$(HOSTEXE)
|
||||
|
||||
#--------------------------------------------------
|
||||
# A linker script is essential for munching from vxWorks 6.6 onwards
|
||||
# (i.e. with versions that use gcc 4.1.2 or later). It can be used
|
||||
# with any vxWorks 5 or 6 version, but apparently should not be used
|
||||
# when compiling for 68K (which isn't supported in vxWorks 6 anyway)
|
||||
# (i.e. with versions that use gcc 4.1.2 or later).
|
||||
MUNCH_LDFLAGS_6 = -T $(VX_DIR)/target/h/tool/gnu/ldscripts/link.OUT
|
||||
MUNCH_LDFLAGS = $(MUNCH_LDFLAGS_$(VXWORKS_MAJOR_VERSION))
|
||||
|
||||
@@ -140,11 +127,10 @@ export TOOL_FAMILY = GNU
|
||||
OP_SYS_CPPFLAGS += -DvxWorks=vxWorks
|
||||
OP_SYS_CFLAGS += -fno-builtin
|
||||
|
||||
# Fix for vxWorks 5 headers that use macros defined in vxWorks.h but
|
||||
# Fix for vxWorks headers that use macros defined in vxWorks.h but
|
||||
# which don't actually include vxWorks.h themselves, for example the
|
||||
# target/h/sys/stat.h file which uses ULONG. This also stops dbDefs.h
|
||||
# from defining the OFFSET macro, which generates lots of warnings in
|
||||
# both vxWorks 5 and 6.
|
||||
# from defining the OFFSET macro, which generates lots of warnings.
|
||||
OP_SYS_INCLUDE_CPPFLAGS += -include $(VX_DIR)/target/h/vxWorks.h
|
||||
|
||||
#--------------------------------------------------
|
||||
@@ -157,7 +143,6 @@ OPT_CXXFLAGS_YES = -O2
|
||||
CODE_CFLAGS =
|
||||
#
|
||||
# For vxWorks versions before 6.3 we need this g++ compiler flag
|
||||
CODE_CXXFLAGS_5 = -fno-implicit-templates
|
||||
CODE_CXXFLAGS_6.0 = -fno-implicit-templates
|
||||
CODE_CXXFLAGS_6.1 = -fno-implicit-templates
|
||||
CODE_CXXFLAGS_6.2 = -fno-implicit-templates
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
CP = cp
|
||||
MV = mv
|
||||
RM = rm -f
|
||||
MKDIR = mkdir
|
||||
MKDIR = mkdir -p
|
||||
RMDIR = rm -rf
|
||||
CAT = cat
|
||||
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
|
||||
WIND_HOST_TYPE = x86-linux
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
|
||||
WIND_HOST_TYPE = x86-linux
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
|
||||
WIND_HOST_TYPE = x86-linux
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
|
||||
WIND_HOST_TYPE = x86-linux
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
|
||||
WIND_HOST_TYPE = x86-linux
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#Include definitions common to unix hosts
|
||||
include $(CONFIG)/os/CONFIG.UnixCommon.Common
|
||||
|
||||
WIND_HOST_TYPE = x86-linux
|
||||
WIND_HOST_TYPE = x86-linux2
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
# CONFIG_SITE.Common.vxWorksCommon
|
||||
#
|
||||
# Site specific definitions for vxWorks target builds.
|
||||
# Only the local epics system manager should modify this file
|
||||
|
||||
# Compiler options can vary with the vxWorks version number, so we
|
||||
# need to know that. However don't include any third-level digits
|
||||
# (e.g. the .2 in 5.5.2) because we don't need them.
|
||||
# need to know that. Do not include any third-level digits.
|
||||
|
||||
# Note: vxWorks 5.4.x (Tornado 2.0.x) is not supported
|
||||
# Note: vxWorks 5.4.x and 5.5.x (Tornado 2.x) are not supported.
|
||||
# VxWorks 6.0 through 6.5 use older, untested versions of GCC.
|
||||
|
||||
VXWORKS_VERSION = 5.5
|
||||
#VXWORKS_VERSION = 6.0
|
||||
#VXWORKS_VERSION = 6.1
|
||||
#VXWORKS_VERSION = 6.2
|
||||
#VXWORKS_VERSION = 6.3
|
||||
#VXWORKS_VERSION = 6.4
|
||||
#VXWORKS_VERSION = 6.5
|
||||
#VXWORKS_VERSION = 6.6
|
||||
#VXWORKS_VERSION = 6.7
|
||||
#VXWORKS_VERSION = 6.8
|
||||
#VXWORKS_VERSION = 6.9
|
||||
VXWORKS_VERSION = 6.9
|
||||
|
||||
|
||||
# Sites may override the following path for a particular host
|
||||
@@ -27,10 +19,8 @@ VXWORKS_VERSION = 5.5
|
||||
# CONFIG_SITE.$(EPICS_HOST_ARCH).vxWorksCommon file.
|
||||
|
||||
# WIND_BASE is where you installed the Wind River software.
|
||||
# Under vxWorks 6.x this is *not* the same as the old VX_DIR setting
|
||||
|
||||
WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
|
||||
#WIND_BASE = /usr/local/vw/vxWorks-$(VXWORKS_VERSION)
|
||||
WIND_BASE = /usr/local/vw/vxWorks-$(VXWORKS_VERSION)
|
||||
#WIND_BASE = /ade/vxWorks/$(VXWORKS_VERSION)
|
||||
|
||||
|
||||
@@ -39,9 +29,9 @@ WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
|
||||
#WORKBENCH_VERSION = 2.6
|
||||
#WORKBENCH_VERSION = 3.0
|
||||
#WORKBENCH_VERSION = 3.2
|
||||
#WORKBENCH_VERSION = 3.3
|
||||
WORKBENCH_VERSION = 3.3
|
||||
|
||||
|
||||
# Utilities Version number, required from vxWorks 6.8 and later
|
||||
|
||||
#UTILITIES_VERSION = 1.0
|
||||
UTILITIES_VERSION = 1.0
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
#GNU_DIR = /usr/local
|
||||
|
||||
# Different distribution cross-build packages use different prefixes:
|
||||
# Ubuntu:
|
||||
#CMPLR_PREFIX = i686-w64-mingw32-
|
||||
# RHEL:
|
||||
CMPLR_PREFIX = i686-pc-mingw32-
|
||||
# Ubuntu, RHEL7:
|
||||
CMPLR_PREFIX = i686-w64-mingw32-
|
||||
# RHEL6:
|
||||
#CMPLR_PREFIX = i686-pc-mingw32-
|
||||
# Debian?
|
||||
#CMPLR_PREFIX = i586-mingw32msvc-
|
||||
|
||||
|
||||
@@ -4,25 +4,37 @@
|
||||
<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.6</title>
|
||||
<title>Known Problems in Base-3.16.1</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="text-align: center">EPICS Base R3.15.6: Known Problems</h1>
|
||||
<h1 style="text-align: center">EPICS Base R3.16.1: Known Problems</h1>
|
||||
|
||||
<p>Any patch files linked below should be applied at the root of the
|
||||
base-3.15.6 tree. Download them, then use the GNU Patch program as
|
||||
base-3.16.1 tree. Download them, then use the GNU Patch program as
|
||||
follows:</p>
|
||||
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.15.6</b>
|
||||
% <b>patch -p0 < <i>/path/to/</i>file.patch</b></pre></blockquote>
|
||||
<blockquote><pre>% <b>cd <i>/path/to/</i>base-3.16.1</b>
|
||||
% <b>patch -p1 < <i>/path/to/</i>file.patch</b></pre></blockquote>
|
||||
|
||||
<p>The following significant problems have been reported with this
|
||||
version of EPICS Base:</p>
|
||||
<p>The following problems were known by the developers at the time of this
|
||||
release:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>None known as yet.</li>
|
||||
<!-- Items added after release should be formatted thusly:
|
||||
<li>YYYY-MM-DD: Description of problem.
|
||||
<a href="fix.patch">This patch</a> fixes the problem.
|
||||
...</li>
|
||||
-->
|
||||
|
||||
<li>IOCs running on some versions of Cygwin may display warnings at iocInit
|
||||
about duplicate EPICS CA Address list entries. These warnings might be due
|
||||
to a bug in Cygwin; they are benign and can be ignored.</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 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.6
|
||||
EPICS Base Release 3.16.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
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
@@ -85,17 +85,17 @@
|
||||
as processes on the host platform.
|
||||
|
||||
vxWorks
|
||||
You must have vxWorks 5.5.x or 6.x installed if any of your target
|
||||
systems are vxWorks systems; the C++ compiler for vxWorks 5.4 is now too
|
||||
old to support. The vxWorks installation provides the cross-compiler and
|
||||
header files needed to build for these targets. The absolute path to and
|
||||
the version number of the vxWorks installation must be set in the
|
||||
You must have vxWorks 6 installed if any of your target systems are
|
||||
vxWorks systems; the C++ compilers for vxWorks 5.x are now too old to
|
||||
support. The vxWorks installation provides the cross-compiler and header
|
||||
files needed to build for these targets. The absolute path to and the
|
||||
version number of the vxWorks installation must be set in the
|
||||
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
|
||||
target-specific overrides.
|
||||
|
||||
Consult the vxWorks 5.x or vxWorks 6.x EPICS web pages about and the
|
||||
vxWorks documentation for information about configuring your vxWorks
|
||||
operating system for use with EPICS.
|
||||
Consult the vxWorks 6.x EPICS web pages and the vxWorks documentation
|
||||
for information about configuring your vxWorks operating system for use
|
||||
with EPICS.
|
||||
|
||||
RTEMS
|
||||
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<BODY>
|
||||
<CENTER>
|
||||
<H1>Installation Instructions</H1>
|
||||
<H2>EPICS Base Release 3.15.6</H2><BR>
|
||||
<H2>EPICS Base Release 3.16.1</H2><BR>
|
||||
</CENTER>
|
||||
<HR>
|
||||
<H3> Table of Contents</H3>
|
||||
@@ -90,17 +90,16 @@
|
||||
as processes on the host platform.</P>
|
||||
|
||||
<P><B>vxWorks</B><BR>
|
||||
You must have vxWorks 5.5.x or 6.x installed if any of your target systems are
|
||||
vxWorks systems; the C++ compiler for vxWorks 5.4 is now too old to support.
|
||||
The vxWorks installation provides the cross-compiler and header files needed to
|
||||
You must have vxWorks 6 installed if any of your target systems are vxWorks
|
||||
systems; the C++ compilers for vxWorks 5.x are now too old to support. The
|
||||
vxWorks installation provides the cross-compiler and header files needed to
|
||||
build for these targets. The absolute path to and the version number of the
|
||||
vxWorks installation must be set in the
|
||||
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
|
||||
target-specific overrides.</P>
|
||||
|
||||
<P>Consult the <a href="http://www.aps.anl.gov/epics/base/tornado.php">vxWorks
|
||||
5.x</a> or <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
|
||||
6.x</a> EPICS web pages about and the vxWorks documentation for information
|
||||
<P>Consult the <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
|
||||
6.x</a> EPICS web pages and the vxWorks documentation for information
|
||||
about configuring your vxWorks operating system for use with EPICS.</P>
|
||||
|
||||
<P><B>RTEMS</B><BR>
|
||||
@@ -191,12 +190,12 @@
|
||||
CONFIG.CrossCommon Cross build definitions
|
||||
CONFIG.gnuCommon Gnu compiler build definitions for all archs
|
||||
CONFIG_ADDONS Definitions for <osclass> and DEFAULT options
|
||||
CONFIG_APP_INCLUDE
|
||||
CONFIG_APP_INCLUDE
|
||||
CONFIG_BASE EPICS base tool and location definitions
|
||||
CONFIG_BASE_VERSION Definitions for EPICS base version number
|
||||
CONFIG_COMMON Definitions common to all builds
|
||||
CONFIG_ENV Definitions of EPICS environment variables
|
||||
CONFIG_FILE_TYPE
|
||||
CONFIG_FILE_TYPE
|
||||
CONFIG_SITE Site specific make definitions
|
||||
CONFIG_SITE_ENV Site defaults for EPICS environment variables
|
||||
MAKEFILE Installs CONFIG* RULES* creates
|
||||
@@ -207,9 +206,9 @@
|
||||
RULES_ARCHS Definitions and rules for building architectures
|
||||
RULES_BUILD Build and install rules and definitions
|
||||
RULES_DIRS Definitions and rules for building subdirectories
|
||||
RULES_EXPAND
|
||||
RULES_FILE_TYPE
|
||||
RULES_TARGET
|
||||
RULES_EXPAND
|
||||
RULES_FILE_TYPE
|
||||
RULES_TARGET
|
||||
RULES_TOP Rules specific to a <top> dir (uninstall and tar)
|
||||
Sample.Makefile Sample makefile with comments
|
||||
</PRE>
|
||||
@@ -341,7 +340,7 @@ Files in the base/startup directory have been provided to
|
||||
<H3><A NAME="0_0_13"> Example application and extension</A></H3>
|
||||
<BLOCKQUOTE>A perl tool, makeBaseApp.pl is included in the distribution
|
||||
file. This script will create a sample application that can be built
|
||||
and then executed to try out this release of base.
|
||||
and then executed to try out this release of base.
|
||||
|
||||
<P>
|
||||
Instructions for building and executing the 3.15 example application
|
||||
@@ -351,8 +350,8 @@ Files in the base/startup directory have been provided to
|
||||
create and build an example application in a user created <top>
|
||||
directory. It also explains how to run the example application on a
|
||||
vxWorks ioc or as a process on the host system.
|
||||
By running the example application as a host-based IOC, you will be
|
||||
able to quickly implement a complete EPICS system and be able to run channel
|
||||
By running the example application as a host-based IOC, you will be
|
||||
able to quickly implement a complete EPICS system and be able to run channel
|
||||
access clients on the host system.
|
||||
|
||||
<P>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,29 +33,27 @@
|
||||
<h1>EPICS Base Release Procedures & Checklist</h1>
|
||||
|
||||
<p>This document describes the procedures and provides a checklist of tasks
|
||||
that should be performed when creating new releases of EPICS Base.</p>
|
||||
that should be performed when creating production releases of EPICS Base.</p>
|
||||
|
||||
<h3>The Release Process</h3>
|
||||
|
||||
<p>The version released on the Feature Freeze date is designated the first
|
||||
pre-release, <tt>-pre1</tt>. The first Release Candidate <tt>-rc1</tt> is the
|
||||
pre-release, <tt>-pre1</tt>. The first release candidate <tt>-rc1</tt> is the
|
||||
first version that has undergone widespread testing and which has no known
|
||||
problems in it that are slated to be fixed in this release. New versions should
|
||||
be made at 2-weekly intervals during the testing and debugging period, and will
|
||||
be designated as either pre-release versions or Release Candidates by the
|
||||
Release Manager. After a Release Candidate has been available to the whole
|
||||
be made at about weekly intervals during the testing and debugging period, and
|
||||
will be designated as either pre-release or release candidate versions by the
|
||||
Release Manager. After a release candidate has been available to the whole
|
||||
community for testing for at least a week without any additional problems being
|
||||
reported or significant changes being committed, the branch can be designated as
|
||||
the final release version.</p>
|
||||
|
||||
<h3>Roles</h3>
|
||||
|
||||
<p>The following roles are required. The individuals named here have have been
|
||||
responsible for these tasks in the past and are expected to continue in the
|
||||
relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<p>The following roles are used below:</p>
|
||||
|
||||
<dl>
|
||||
<dt><strong>Release Manager</strong> (Ralph Lange)</dt>
|
||||
<dt><strong>Release Manager</strong> ()</dt>
|
||||
<dd>Responsible for managing and tagging the release</dd>
|
||||
<dt><strong>Platform Developers</strong> (optional)</dt>
|
||||
<dd>Responsible for individual operating system platforms</dd>
|
||||
@@ -91,7 +89,7 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Set the Feature Freeze date, by which time all Bazaar commits for
|
||||
<td>Set the Feature Freeze date, by which time all Git commits for
|
||||
enhancements and new functionality should have been completed. After
|
||||
this date, commits should only be made to fix problems that show up
|
||||
during testing.</td>
|
||||
@@ -133,39 +131,40 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Tag the module in Bazaar, using these tag conventions:
|
||||
<td>Tag the module in Git using these tag conventions:
|
||||
<ul>
|
||||
<li>
|
||||
<tt>R3.15.6-pre1</tt>
|
||||
<tt>R3.16.1-pre<i>n</i></tt>
|
||||
— pre-release tag
|
||||
</li>
|
||||
<li>
|
||||
<tt>R3.15.6-rc1</tt>
|
||||
<tt>R3.16.1-rc<i>n</i></tt>
|
||||
— release candidate tag
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote><tt>
|
||||
cd ~/base/mirror-3.15<br />
|
||||
bzr tag R3.15.6-rc1
|
||||
cd base-3.16<br />
|
||||
git tag -m 'ANJ: Tagged for 3.16.1-rc1' R3.16.1-rc1
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Export the tagged version into a tarfile. Note that this command
|
||||
generates a gzipped tarfile directly from the repository:
|
||||
<td>Export the tagged version into a tarfile. This command generates a
|
||||
gzipped tarfile directly from the repository, excluding those files and
|
||||
directories needed only for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd ~/base<br />
|
||||
bzr export
|
||||
--root=base-3.15.6-rc1
|
||||
-r tag:R3.15.6-rc1
|
||||
base-3.15.6-rc1.tar.gz
|
||||
mirror-3.15
|
||||
cd base-3.16<br />
|
||||
git archive
|
||||
--prefix=base-3.16.1-rc1/
|
||||
--output=../base-3.16.1-rc1.tar.gz
|
||||
R3.16.1-rc1
|
||||
configure documentation LICENSE Makefile README src startup
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-3.15.6-rc1.tar.gz
|
||||
gpg --armor --sign --detach-sig base-3.16.1-rc1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -259,7 +258,7 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Obtain a positive <q>Ok to release</q> from all platform developers
|
||||
once a Release Candidate version has gone a whole week without any
|
||||
once a release candidate version has gone a whole week without any
|
||||
issues being reported.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -274,29 +273,30 @@ relevent roles unless the Release Manager designates otherwise:</p>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Tag the module in Bazaar:
|
||||
<td>Tag the module in Git:
|
||||
<blockquote><tt>
|
||||
cd ~/base/mirror-3.15<br />
|
||||
bzr tag R3.15.6</i>
|
||||
cd base-3.16<br />
|
||||
git tag -m 'ANJ: Tagged for 3.16.1' R3.16.1</i>
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>Release Manager</td>
|
||||
<td>Export the tagged version into a tarfile. Note that this command
|
||||
generates a gzipped tarfile directly from the repository:
|
||||
<td>Export the tagged version into a tarfile. This command generates a
|
||||
gzipped tarfile directly from the repository, excluding those files and
|
||||
directories needed only for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd ~/base<br />
|
||||
bzr export
|
||||
--root=base-3.15.6
|
||||
-r tag:R3.15.6
|
||||
base-3.15.6.tar.gz
|
||||
mirror-3.15
|
||||
cd base-3.16<br />
|
||||
git archive
|
||||
--prefix=base-3.16.1/
|
||||
--output=../base-3.16.1.tar.gz
|
||||
R3.16.1
|
||||
configure documentation LICENSE Makefile README src startup
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
gpg --armor --sign --detach-sig base-3.15.6.tar.gz
|
||||
gpg --armor --sign --detach-sig base-3.16.1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -314,11 +314,21 @@ is used.</p>
|
||||
<td>i >= 16384</td>
|
||||
<td>16384</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EPICS_CA_AUTO_ARRAY_BYTES</td>
|
||||
<td>{YES, NO}</td>
|
||||
<td>YES</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EPICS_CA_MAX_SEARCH_PERIOD</td>
|
||||
<td>r > 60 seconds</td>
|
||||
<td>300</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EPICS_CA_MCAST_TTL</td>
|
||||
<td>r > 1</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EPICS_TS_MIN_WEST</td>
|
||||
<td>-720 < i <720 minutes</td>
|
||||
@@ -746,6 +756,12 @@ in the variable EPICS_TS_MIN_WEST.</p>
|
||||
|
||||
<h3><a name="Configurin1">Configuring the Maximum Array Size</a></h3>
|
||||
|
||||
<p>From version R3.16.1, the default setting of EPICS_CA_AUTO_ARRAY_BYTES=YES
|
||||
will cause the software to ignore EPICS_CA_MAX_ARRAY_BYTES and attempt to
|
||||
allocate network buffer space as needed by the particular client connection
|
||||
using malloc. Setting EPICS_CA_AUTO_ARRAY_BYTES=NO will configure the software
|
||||
to respect the EPICS_CA_MAX_ARRAY_BYTES setting as described below instead.</p>
|
||||
|
||||
<p>Starting with version R3.14 the environment variable
|
||||
EPICS_CA_MAX_ARRAY_BYTES determines the size of the largest array that may pass
|
||||
through CA. Prior to this version only arrays smaller than 16k bytes could be
|
||||
@@ -768,11 +784,7 @@ array larger than EPICS_CA_MAX_ARRAY_BYTES it will return ECA_TOLARGE.</p>
|
||||
by multiplying the number of elements by the size of a single element, but
|
||||
neglect to add additional bytes for the compound data types (for example
|
||||
DBR_GR_DOUBLE) commonly used by the more sophisticated client side
|
||||
applications. <em>Based on this confusion, one could arrive at the conclusion
|
||||
that EPICS_CA_MAX_ARRAY_BYTES might have been better named
|
||||
EPICS_CA_MAX_DATUM_BYTES, or that the software should be changed internally to
|
||||
round the users request up by the size of the maximum scalar datum (nothing has
|
||||
been done to address this issue so far).</em></p>
|
||||
applications.</p>
|
||||
|
||||
<h3><a name="Configurin2">Configuring a CA Server</a></h3>
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ LIBSRCS += comQueSend.cpp
|
||||
LIBSRCS += comBuf.cpp
|
||||
LIBSRCS += hostNameCache.cpp
|
||||
LIBSRCS += msgForMultiplyDefinedPV.cpp
|
||||
LIBSRCS_vxWorks += templateInstances.cpp
|
||||
|
||||
LIBRARY=ca
|
||||
|
||||
|
||||
@@ -1,94 +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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef autoPtrDestroyh
|
||||
#define autoPtrDestroyh
|
||||
|
||||
template < class T >
|
||||
class autoPtrDestroy {
|
||||
public:
|
||||
autoPtrDestroy ( T * );
|
||||
~autoPtrDestroy ();
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
autoPtrDestroy<T> & operator = ( T * );
|
||||
T * get () const;
|
||||
T * release ();
|
||||
private:
|
||||
T * p;
|
||||
// not implemented
|
||||
autoPtrDestroy<T> & operator = ( const autoPtrDestroy<T> & );
|
||||
autoPtrDestroy ( const autoPtrDestroy<T> & );
|
||||
};
|
||||
|
||||
template < class T >
|
||||
inline autoPtrDestroy<T>::autoPtrDestroy ( T *pIn ) :
|
||||
p ( pIn ) {}
|
||||
|
||||
template < class T >
|
||||
inline autoPtrDestroy<T>::~autoPtrDestroy ()
|
||||
{
|
||||
if ( this->p ) {
|
||||
this->p->destroy ();
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T & autoPtrDestroy<T>::operator * () const
|
||||
{
|
||||
return * this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrDestroy<T>::operator -> () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline autoPtrDestroy<T> & autoPtrDestroy<T>::operator = ( T * pIn )
|
||||
{
|
||||
if ( this->p ) {
|
||||
this->p->destroy ();
|
||||
}
|
||||
this->p = pIn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrDestroy<T>::get () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrDestroy<T>::release ()
|
||||
{
|
||||
T *pTmp = this->p;
|
||||
this->p = 0;
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
#endif // #ifdef autoPtrDestroyh
|
||||
@@ -28,7 +28,8 @@
|
||||
#define CA_VERSION_STRING( MINOR_REVISION ) \
|
||||
( capStrOfX ( CA_MAJOR_PROTOCOL_REVISION ) "." capStrOfX ( MINOR_REVISION ) )
|
||||
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
|
||||
#if CA_MAJOR_PROTOCOL_REVISION == 4u
|
||||
#define CA_MINIMUM_SUPPORTED_VERSION 4u
|
||||
# define CA_VSUPPORTED(MINOR) ((MINOR)>=CA_MINIMUM_SUPPORTED_VERSION)
|
||||
# define CA_V41(MINOR) ((MINOR)>=1u)
|
||||
# define CA_V42(MINOR) ((MINOR)>=2u)
|
||||
# define CA_V43(MINOR) ((MINOR)>=3u)
|
||||
@@ -42,35 +43,6 @@
|
||||
# define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
|
||||
# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
|
||||
# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
|
||||
#elif CA_MAJOR_PROTOCOL_REVISION > 4u
|
||||
# define CA_V41(MINOR) ( 1u )
|
||||
# define CA_V42(MINOR) ( 1u )
|
||||
# define CA_V43(MINOR) ( 1u )
|
||||
# define CA_V44(MINOR) ( 1u )
|
||||
# define CA_V45(MINOR) ( 1u )
|
||||
# define CA_V46(MINOR) ( 1u )
|
||||
# define CA_V47(MINOR) ( 1u )
|
||||
# define CA_V48(MINOR) ( 1u )
|
||||
# define CA_V49(MINOR) ( 1u )
|
||||
# define CA_V410(MINOR) ( 1u )
|
||||
# define CA_V411(MINOR) ( 1u )
|
||||
# define CA_V412(MINOR) ( 1u )
|
||||
# define CA_V413(MINOR) ( 1u )
|
||||
#else
|
||||
# define CA_V41(MINOR) ( 0u )
|
||||
# define CA_V42(MINOR) ( 0u )
|
||||
# define CA_V43(MINOR) ( 0u )
|
||||
# define CA_V44(MINOR) ( 0u )
|
||||
# define CA_V45(MINOR) ( 0u )
|
||||
# define CA_V46(MINOR) ( 0u )
|
||||
# define CA_V47(MINOR) ( 0u )
|
||||
# define CA_V48(MINOR) ( 0u )
|
||||
# define CA_V49(MINOR) ( 0u )
|
||||
# define CA_V410(MINOR) ( 0u )
|
||||
# define CA_V411(MINOR) ( 0u )
|
||||
# define CA_V412(MINOR) ( 0u )
|
||||
# define CA_V413(MINOR) ( 0u )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These port numbers are only used if the CA repeater and
|
||||
|
||||
@@ -159,7 +159,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
|
||||
this->localPort = htons ( tmpAddr.ia.sin_port );
|
||||
}
|
||||
|
||||
epics_auto_ptr < CallbackGuard > pCBGuard;
|
||||
std::auto_ptr < CallbackGuard > pCBGuard;
|
||||
if ( ! enablePreemptiveCallback ) {
|
||||
pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) );
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "envDefs.h"
|
||||
#include "locationException.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "addrList.h"
|
||||
@@ -218,9 +219,15 @@ cac::cac (
|
||||
throw std::bad_alloc ();
|
||||
}
|
||||
|
||||
freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 );
|
||||
if ( ! this->tcpLargeRecvBufFreeList ) {
|
||||
throw std::bad_alloc ();
|
||||
int autoMaxBytes;
|
||||
if(envGetBoolConfigParam(&EPICS_CA_AUTO_ARRAY_BYTES, &autoMaxBytes))
|
||||
autoMaxBytes = 1;
|
||||
|
||||
if(!autoMaxBytes) {
|
||||
freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 );
|
||||
if ( ! this->tcpLargeRecvBufFreeList ) {
|
||||
throw std::bad_alloc ();
|
||||
}
|
||||
}
|
||||
unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes ();
|
||||
if ( bufsPerArray > 1u ) {
|
||||
@@ -231,9 +238,7 @@ cac::cac (
|
||||
catch ( ... ) {
|
||||
osiSockRelease ();
|
||||
delete [] this->pUserName;
|
||||
if ( this->tcpSmallRecvBufFreeList ) {
|
||||
freeListCleanup ( this->tcpSmallRecvBufFreeList );
|
||||
}
|
||||
freeListCleanup ( this->tcpSmallRecvBufFreeList );
|
||||
if ( this->tcpLargeRecvBufFreeList ) {
|
||||
freeListCleanup ( this->tcpLargeRecvBufFreeList );
|
||||
}
|
||||
@@ -260,9 +265,14 @@ cac::cac (
|
||||
tcpiiu * piiu = NULL;
|
||||
SearchDestTCP * pdst = new SearchDestTCP ( *this, pNode->addr );
|
||||
this->registerSearchDest ( guard, * pdst );
|
||||
/* Initially assume that servers listed in EPICS_CA_NAME_SERVERS support at least minor
|
||||
* version 11. This causes tcpiiu to send the user and host name authentication
|
||||
* messages. When the actual Version message is received from the server it will
|
||||
* be overwrite this assumption.
|
||||
*/
|
||||
bool newIIU = findOrCreateVirtCircuit (
|
||||
guard, pNode->addr, cacChannel::priorityDefault,
|
||||
piiu, CA_UKN_MINOR_VERSION, pdst );
|
||||
piiu, 11, pdst );
|
||||
free ( pNode );
|
||||
if ( newIIU ) {
|
||||
piiu->start ( guard );
|
||||
@@ -318,7 +328,9 @@ cac::~cac ()
|
||||
}
|
||||
|
||||
freeListCleanup ( this->tcpSmallRecvBufFreeList );
|
||||
freeListCleanup ( this->tcpLargeRecvBufFreeList );
|
||||
if ( this->tcpLargeRecvBufFreeList ) {
|
||||
freeListCleanup ( this->tcpLargeRecvBufFreeList );
|
||||
}
|
||||
|
||||
delete [] this->pUserName;
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
class netWriteNotifyIO;
|
||||
class netReadNotifyIO;
|
||||
class netSubscription;
|
||||
class tcpiiu;
|
||||
|
||||
// used to control access to cac's recycle routines which
|
||||
// should only be indirectly invoked by CAC when its lock
|
||||
@@ -193,12 +194,6 @@ public:
|
||||
const char *pformat, va_list args ) const;
|
||||
double connectionTimeout ( epicsGuard < epicsMutex > & );
|
||||
|
||||
// buffer management
|
||||
char * allocateSmallBufferTCP ();
|
||||
void releaseSmallBufferTCP ( char * );
|
||||
unsigned largeBufferSizeTCP () const;
|
||||
char * allocateLargeBufferTCP ();
|
||||
void releaseLargeBufferTCP ( char * );
|
||||
unsigned maxContiguousFrames ( epicsGuard < epicsMutex > & ) const;
|
||||
|
||||
// misc
|
||||
@@ -355,6 +350,8 @@ private:
|
||||
|
||||
cac ( const cac & );
|
||||
cac & operator = ( const cac & );
|
||||
|
||||
friend class tcpiiu;
|
||||
};
|
||||
|
||||
inline const char * cac::userNamePointer () const
|
||||
@@ -385,35 +382,6 @@ inline void cac::attachToClientCtx ()
|
||||
this->notify.attachToClientCtx ();
|
||||
}
|
||||
|
||||
inline char * cac::allocateSmallBufferTCP ()
|
||||
{
|
||||
// this locks internally
|
||||
return ( char * ) freeListMalloc ( this->tcpSmallRecvBufFreeList );
|
||||
}
|
||||
|
||||
inline void cac::releaseSmallBufferTCP ( char *pBuf )
|
||||
{
|
||||
// this locks internally
|
||||
freeListFree ( this->tcpSmallRecvBufFreeList, pBuf );
|
||||
}
|
||||
|
||||
inline unsigned cac::largeBufferSizeTCP () const
|
||||
{
|
||||
return this->maxRecvBytesTCP;
|
||||
}
|
||||
|
||||
inline char * cac::allocateLargeBufferTCP ()
|
||||
{
|
||||
// this locks internally
|
||||
return ( char * ) freeListMalloc ( this->tcpLargeRecvBufFreeList );
|
||||
}
|
||||
|
||||
inline void cac::releaseLargeBufferTCP ( char *pBuf )
|
||||
{
|
||||
// this locks internally
|
||||
freeListFree ( this->tcpLargeRecvBufFreeList, pBuf );
|
||||
}
|
||||
|
||||
inline unsigned cac::beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@ protected:
|
||||
channelNode ();
|
||||
bool isInstalledInServer ( epicsGuard < epicsMutex > & ) const;
|
||||
bool isConnected ( epicsGuard < epicsMutex > & ) const;
|
||||
public:
|
||||
static unsigned getMaxSearchTimerCount ();
|
||||
private:
|
||||
enum channelState {
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
#ifndef oldAccessh
|
||||
#define oldAccessh
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define oldAccessh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsFreeList.h"
|
||||
#include "epicsMemory.h"
|
||||
#include "compilerDependencies.h"
|
||||
#include "osiSock.h"
|
||||
|
||||
@@ -402,8 +403,8 @@ private:
|
||||
epicsEvent ioDone;
|
||||
epicsEvent callbackThreadActivityComplete;
|
||||
epicsThreadId createdByThread;
|
||||
epics_auto_ptr < CallbackGuard > pCallbackGuard;
|
||||
epics_auto_ptr < cacContext > pServiceContext;
|
||||
std::auto_ptr < CallbackGuard > pCallbackGuard;
|
||||
std::auto_ptr < cacContext > pServiceContext;
|
||||
caExceptionHandler * ca_exception_func;
|
||||
void * ca_exception_arg;
|
||||
caPrintfFunc * pVPrintfFunc;
|
||||
|
||||
@@ -66,6 +66,8 @@ void repeaterSubscribeTimer::shutdown (
|
||||
epicsTimerNotify::expireStatus repeaterSubscribeTimer::
|
||||
expire ( const epicsTime & /* currentTime */ )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->stateMutex );
|
||||
|
||||
static const unsigned nTriesToMsg = 50;
|
||||
if ( this->attempts > nTriesToMsg && ! this->once ) {
|
||||
callbackManager mgr ( this->ctxNotify, this->cbMutex );
|
||||
@@ -92,12 +94,15 @@ epicsTimerNotify::expireStatus repeaterSubscribeTimer::
|
||||
|
||||
void repeaterSubscribeTimer::show ( unsigned /* level */ ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->stateMutex );
|
||||
|
||||
::printf ( "repeater subscribe timer: attempts=%u registered=%u once=%u\n",
|
||||
this->attempts, this->registered, this->once );
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::confirmNotify ()
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->stateMutex );
|
||||
this->registered = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ private:
|
||||
repeaterTimerNotify & iiu;
|
||||
epicsMutex & cbMutex;
|
||||
cacContextNotify & ctxNotify;
|
||||
mutable epicsMutex stateMutex;
|
||||
unsigned attempts;
|
||||
bool registered;
|
||||
bool once;
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "tsMinMax.h"
|
||||
#include "envDefs.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -687,7 +690,7 @@ tcpiiu::tcpiiu (
|
||||
curDataBytes ( 0ul ),
|
||||
comBufMemMgr ( comBufMemMgrIn ),
|
||||
cacRef ( cac ),
|
||||
pCurData ( cac.allocateSmallBufferTCP () ),
|
||||
pCurData ( (char*) freeListMalloc(this->cacRef.tcpSmallRecvBufFreeList) ),
|
||||
pSearchDest ( pSearchDestIn ),
|
||||
mutex ( mutexIn ),
|
||||
cbMutex ( cbMutexIn ),
|
||||
@@ -711,9 +714,12 @@ tcpiiu::tcpiiu (
|
||||
socketHasBeenClosed ( false ),
|
||||
unresponsiveCircuit ( false )
|
||||
{
|
||||
if(!pCurData)
|
||||
throw std::bad_alloc();
|
||||
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if ( this->sock == INVALID_SOCKET ) {
|
||||
cac.releaseSmallBufferTCP ( this->pCurData );
|
||||
freeListFree(this->cacRef.tcpSmallRecvBufFreeList, this->pCurData);
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
@@ -1023,11 +1029,14 @@ tcpiiu :: ~tcpiiu ()
|
||||
|
||||
// free message body cache
|
||||
if ( this->pCurData ) {
|
||||
if ( this->curDataMax == MAX_TCP ) {
|
||||
this->cacRef.releaseSmallBufferTCP ( this->pCurData );
|
||||
if ( this->curDataMax <= MAX_TCP ) {
|
||||
freeListFree(this->cacRef.tcpSmallRecvBufFreeList, this->pCurData);
|
||||
}
|
||||
else if ( this->cacRef.tcpLargeRecvBufFreeList ) {
|
||||
freeListFree(this->cacRef.tcpLargeRecvBufFreeList, this->pCurData);
|
||||
}
|
||||
else {
|
||||
this->cacRef.releaseLargeBufferTCP ( this->pCurData );
|
||||
free ( this->pCurData );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1197,18 +1206,46 @@ bool tcpiiu::processIncoming (
|
||||
// make sure we have a large enough message body cache
|
||||
//
|
||||
if ( this->curMsg.m_postsize > this->curDataMax ) {
|
||||
if ( this->curDataMax == MAX_TCP &&
|
||||
this->cacRef.largeBufferSizeTCP() >= this->curMsg.m_postsize ) {
|
||||
char * pBuf = this->cacRef.allocateLargeBufferTCP ();
|
||||
if ( pBuf ) {
|
||||
this->cacRef.releaseSmallBufferTCP ( this->pCurData );
|
||||
this->pCurData = pBuf;
|
||||
this->curDataMax = this->cacRef.largeBufferSizeTCP ();
|
||||
assert (this->curMsg.m_postsize > MAX_TCP);
|
||||
|
||||
char * newbuf = NULL;
|
||||
arrayElementCount newsize;
|
||||
|
||||
if ( !this->cacRef.tcpLargeRecvBufFreeList ) {
|
||||
// round size up to multiple of 4K
|
||||
newsize = ((this->curMsg.m_postsize-1)|0xfff)+1;
|
||||
|
||||
if ( this->curDataMax <= MAX_TCP ) {
|
||||
// small -> large
|
||||
newbuf = (char*)malloc(newsize);
|
||||
|
||||
} else {
|
||||
// expand large to larger
|
||||
newbuf = (char*)realloc(this->pCurData, newsize);
|
||||
}
|
||||
else {
|
||||
this->printFormated ( mgr.cbGuard,
|
||||
"CAC: not enough memory for message body cache (ignoring response message)\n");
|
||||
|
||||
} else if ( this->curMsg.m_postsize <= this->cacRef.maxRecvBytesTCP ) {
|
||||
newbuf = (char*) freeListMalloc(this->cacRef.tcpLargeRecvBufFreeList);
|
||||
newsize = this->cacRef.maxRecvBytesTCP;
|
||||
|
||||
}
|
||||
|
||||
if ( newbuf) {
|
||||
if (this->curDataMax <= MAX_TCP) {
|
||||
freeListFree(this->cacRef.tcpSmallRecvBufFreeList, this->pCurData );
|
||||
|
||||
} else if (this->cacRef.tcpLargeRecvBufFreeList) {
|
||||
freeListFree(this->cacRef.tcpLargeRecvBufFreeList, this->pCurData );
|
||||
|
||||
} else {
|
||||
// called realloc()
|
||||
}
|
||||
this->pCurData = newbuf;
|
||||
this->curDataMax = newsize;
|
||||
|
||||
} else {
|
||||
this->printFormated ( mgr.cbGuard,
|
||||
"CAC: not enough memory for message body cache (ignoring response message)\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1426,7 +1463,7 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard,
|
||||
}
|
||||
arrayElementCount maxBytes;
|
||||
if ( CA_V49 ( this->minorProtocolVersion ) ) {
|
||||
maxBytes = this->cacRef.largeBufferSizeTCP ();
|
||||
maxBytes = 0xfffffff0;
|
||||
}
|
||||
else {
|
||||
maxBytes = MAX_TCP;
|
||||
@@ -1537,7 +1574,7 @@ void tcpiiu::subscriptionRequest (
|
||||
guard, CA_V413(this->minorProtocolVersion) );
|
||||
arrayElementCount maxBytes;
|
||||
if ( CA_V49 ( this->minorProtocolVersion ) ) {
|
||||
maxBytes = this->cacRef.largeBufferSizeTCP ();
|
||||
maxBytes = 0xfffffff0;
|
||||
}
|
||||
else {
|
||||
maxBytes = MAX_TCP;
|
||||
@@ -1584,7 +1621,7 @@ void tcpiiu::subscriptionUpdateRequest (
|
||||
guard, CA_V413(this->minorProtocolVersion) );
|
||||
arrayElementCount maxBytes;
|
||||
if ( CA_V49 ( this->minorProtocolVersion ) ) {
|
||||
maxBytes = this->cacRef.largeBufferSizeTCP ();
|
||||
maxBytes = 0xfffffff0;
|
||||
}
|
||||
else {
|
||||
maxBytes = MAX_TCP;
|
||||
|
||||
@@ -1,89 +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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "virtualCircuit.h"
|
||||
#include "bhe.h"
|
||||
#include "cac.h"
|
||||
#include "syncGroup.h"
|
||||
#include "nciu.h"
|
||||
#include "udpiiu.h"
|
||||
#include "oldAccess.h"
|
||||
#include "msgForMultiplyDefinedPV.h"
|
||||
#include "repeaterClient.h"
|
||||
#include "hostNameCache.h"
|
||||
#include "comBuf.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class resTable < nciu, chronIntId >;
|
||||
template class chronIntIdResTable < nciu >;
|
||||
template class resTable < baseNMIU, chronIntId >;
|
||||
template class chronIntIdResTable < baseNMIU >;
|
||||
template class resTable < CASG, chronIntId >;
|
||||
template class chronIntIdResTable < CASG >;
|
||||
template class resTable < bhe, inetAddrID >;
|
||||
template class resTable < tcpiiu, caServerID >;
|
||||
template class tsFreeList < bhe, 0x100 >;
|
||||
template class tsFreeList < tcpiiu, 32, epicsMutexNOOP >;
|
||||
template class tsFreeList < netReadNotifyIO, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < netWriteNotifyIO, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < netSubscription, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < CASG, 128, epicsMutexNOOP >;
|
||||
template class tsFreeList < syncGroupReadNotify, 128, epicsMutexNOOP >;
|
||||
template class tsFreeList < syncGroupWriteNotify, 128, epicsMutexNOOP >;
|
||||
template class tsFreeList < comBuf, 0x20 >;
|
||||
template class tsFreeList < getCallback, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < getCopy, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < msgForMultiplyDefinedPV, 16 >;
|
||||
template class tsFreeList < nciu, 1024, epicsMutexNOOP>;
|
||||
template class tsFreeList < oldChannelNotify, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < oldSubscription, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < putCallback, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < repeaterClient, 0x20 >;
|
||||
template class epicsSingleton < localHostName >;
|
||||
template class epics_auto_ptr < epics_auto_ptr < class searchTimer >, eapt_array >;
|
||||
template unsigned comBuf :: push ( const double * pValue, unsigned nElem );
|
||||
template unsigned comBuf :: push ( const float * pValue, unsigned nElem );
|
||||
template unsigned comBuf :: push ( const int * pValue, unsigned nElem );
|
||||
template unsigned comBuf :: push ( const short * pValue, unsigned nElem );
|
||||
template comBuf :: popStatus comBuf :: pop ( unsigned int & returnVal );
|
||||
template comBuf :: popStatus comBuf :: pop ( unsigned short & returnVal );
|
||||
template comBuf :: popStatus comBuf :: pop ( unsigned char & returnVal );
|
||||
template void WireSet ( float const &, unsigned char * );
|
||||
template void WireSet ( int const &, unsigned char * );
|
||||
template void WireSet ( short const &, unsigned char * );
|
||||
template void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO
|
||||
(epicsGuard < epicsMutex > &, syncGroupWriteNotify & );
|
||||
template void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO
|
||||
( epicsGuard < epicsMutex > &, syncGroupReadNotify & );
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
@@ -64,6 +64,52 @@ const udpiiu::pProtoStubUDP udpiiu::udpJumpTableCAC [] =
|
||||
&udpiiu::repeaterAckAction,
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
double getMaxPeriod()
|
||||
{
|
||||
double maxPeriod = maxSearchPeriodDefault;
|
||||
|
||||
if ( envGetConfigParamPtr ( & EPICS_CA_MAX_SEARCH_PERIOD ) ) {
|
||||
long longStatus = envGetDoubleConfigParam (
|
||||
& EPICS_CA_MAX_SEARCH_PERIOD, & maxPeriod );
|
||||
if ( ! longStatus ) {
|
||||
if ( maxPeriod < maxSearchPeriodLowerLimit ) {
|
||||
epicsPrintf ( "\"%s\" out of range (low)\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name );
|
||||
maxPeriod = maxSearchPeriodLowerLimit;
|
||||
epicsPrintf ( "Setting \"%s\" = %f seconds\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name, maxPeriod );
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsPrintf ( "EPICS \"%s\" wasnt a real number\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name );
|
||||
epicsPrintf ( "Setting \"%s\" = %f seconds\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name, maxPeriod );
|
||||
}
|
||||
}
|
||||
|
||||
return maxPeriod;
|
||||
}
|
||||
|
||||
static
|
||||
unsigned getNTimers(double maxPeriod)
|
||||
{
|
||||
unsigned nTimers = static_cast < unsigned > ( 1.0 + log ( maxPeriod / minRoundTripEstimate ) / log ( 2.0 ) );
|
||||
|
||||
if ( nTimers > channelNode::getMaxSearchTimerCount () ) {
|
||||
nTimers = channelNode::getMaxSearchTimerCount ();
|
||||
epicsPrintf ( "\"%s\" out of range (high)\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name );
|
||||
epicsPrintf ( "Setting \"%s\" = %f seconds\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name,
|
||||
(1<<(nTimers-1)) * minRoundTripEstimate );
|
||||
}
|
||||
|
||||
return nTimers;
|
||||
}
|
||||
|
||||
//
|
||||
// udpiiu::udpiiu ()
|
||||
//
|
||||
@@ -85,14 +131,15 @@ udpiiu::udpiiu (
|
||||
repeaterSubscribeTmr (
|
||||
m_repeaterTimerNotify, timerQueue, cbMutexIn, ctxNotifyIn ),
|
||||
govTmr ( *this, timerQueue, cacMutexIn ),
|
||||
maxPeriod ( maxSearchPeriodDefault ),
|
||||
maxPeriod ( getMaxPeriod() ),
|
||||
rtteMean ( minRoundTripEstimate ),
|
||||
rtteMeanDev ( 0 ),
|
||||
cacRef ( cac ),
|
||||
cbMutex ( cbMutexIn ),
|
||||
cacMutex ( cacMutexIn ),
|
||||
nTimers ( getNTimers(maxPeriod) ),
|
||||
ppSearchTmr ( nTimers ),
|
||||
nBytesInXmitBuf ( 0 ),
|
||||
nTimers ( 0 ),
|
||||
beaconAnomalyTimerIndex ( 0 ),
|
||||
sequenceNumber ( 0 ),
|
||||
lastReceivedSeqNo ( 0 ),
|
||||
@@ -104,45 +151,13 @@ udpiiu::udpiiu (
|
||||
lastReceivedSeqNoIsValid ( false )
|
||||
{
|
||||
cacGuard.assertIdenticalMutex ( cacMutex );
|
||||
|
||||
if ( envGetConfigParamPtr ( & EPICS_CA_MAX_SEARCH_PERIOD ) ) {
|
||||
long longStatus = envGetDoubleConfigParam (
|
||||
& EPICS_CA_MAX_SEARCH_PERIOD, & this->maxPeriod );
|
||||
if ( ! longStatus ) {
|
||||
if ( this->maxPeriod < maxSearchPeriodLowerLimit ) {
|
||||
epicsPrintf ( "\"%s\" out of range (low)\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name );
|
||||
this->maxPeriod = maxSearchPeriodLowerLimit;
|
||||
epicsPrintf ( "Setting \"%s\" = %f seconds\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name, this->maxPeriod );
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsPrintf ( "EPICS \"%s\" wasnt a real number\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name );
|
||||
epicsPrintf ( "Setting \"%s\" = %f seconds\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name, this->maxPeriod );
|
||||
}
|
||||
}
|
||||
|
||||
double powerOfTwo = log ( this->maxPeriod / minRoundTripEstimate ) / log ( 2.0 );
|
||||
this->nTimers = static_cast < unsigned > ( powerOfTwo + 1.0 );
|
||||
if ( this->nTimers > channelNode::getMaxSearchTimerCount () ) {
|
||||
this->nTimers = channelNode::getMaxSearchTimerCount ();
|
||||
epicsPrintf ( "\"%s\" out of range (high)\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name );
|
||||
epicsPrintf ( "Setting \"%s\" = %f seconds\n",
|
||||
EPICS_CA_MAX_SEARCH_PERIOD.name,
|
||||
(1<<(this->nTimers-1)) * minRoundTripEstimate );
|
||||
}
|
||||
|
||||
powerOfTwo = log ( beaconAnomalySearchPeriod / minRoundTripEstimate ) / log ( 2.0 );
|
||||
double powerOfTwo = log ( beaconAnomalySearchPeriod / minRoundTripEstimate ) / log ( 2.0 );
|
||||
this->beaconAnomalyTimerIndex = static_cast < unsigned > ( powerOfTwo + 1.0 );
|
||||
if ( this->beaconAnomalyTimerIndex >= this->nTimers ) {
|
||||
this->beaconAnomalyTimerIndex = this->nTimers - 1;
|
||||
}
|
||||
|
||||
this->ppSearchTmr.reset ( new epics_auto_ptr < class searchTimer > [ this->nTimers ] );
|
||||
for ( unsigned i = 0; i < this->nTimers; i++ ) {
|
||||
this->ppSearchTmr[i].reset (
|
||||
new searchTimer ( *this, timerQueue, i, cacMutexIn,
|
||||
@@ -176,6 +191,22 @@ udpiiu::udpiiu (
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IP_MULTICAST_TTL
|
||||
{
|
||||
int ttl;
|
||||
long val;
|
||||
if(envGetLongConfigParam(&EPICS_CA_MCAST_TTL, &val))
|
||||
val =1;
|
||||
ttl = val;
|
||||
if ( setsockopt(this->sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl))) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf("CAC: failed to set mcast ttl %d\n", ttl);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int boolValue = true;
|
||||
int status = setsockopt ( this->sock, SOL_SOCKET, SO_BROADCAST,
|
||||
(char *) &boolValue, sizeof ( boolValue ) );
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef udpiiuh
|
||||
#define udpiiuh
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define udpiiuh_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
@@ -32,9 +34,7 @@
|
||||
|
||||
#include "osiSock.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsMemory.h"
|
||||
#include "epicsTime.h"
|
||||
#include "tsMinMax.h"
|
||||
#include "tsDLList.h"
|
||||
|
||||
#ifdef udpiiuh_accessh_epicsExportSharedSymbols
|
||||
@@ -160,15 +160,24 @@ private:
|
||||
repeaterSubscribeTimer repeaterSubscribeTmr;
|
||||
disconnectGovernorTimer govTmr;
|
||||
tsDLList < SearchDest > _searchDestList;
|
||||
double maxPeriod;
|
||||
const double maxPeriod;
|
||||
double rtteMean;
|
||||
double rtteMeanDev;
|
||||
cac & cacRef;
|
||||
epicsMutex & cbMutex;
|
||||
epicsMutex & cacMutex;
|
||||
epics_auto_ptr < epics_auto_ptr < class searchTimer >, eapt_array > ppSearchTmr;
|
||||
const unsigned nTimers;
|
||||
struct SearchArray {
|
||||
typedef std::auto_ptr <searchTimer> value_type;
|
||||
value_type *arr;
|
||||
SearchArray(size_t n) : arr(new value_type[n]) {}
|
||||
~SearchArray() { delete[] arr; }
|
||||
value_type& operator[](size_t i) const { return arr[i]; }
|
||||
private:
|
||||
SearchArray(const SearchArray&);
|
||||
SearchArray& operator=(const SearchArray&);
|
||||
} ppSearchTmr;
|
||||
unsigned nBytesInXmitBuf;
|
||||
unsigned nTimers;
|
||||
unsigned beaconAnomalyTimerIndex;
|
||||
ca_uint32_t sequenceNumber;
|
||||
ca_uint32_t lastReceivedSeqNo;
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
#ifndef virtualCircuith
|
||||
#define virtualCircuith
|
||||
|
||||
#include "epicsMemory.h"
|
||||
#include "tsDLList.h"
|
||||
#include "tsMinMax.h"
|
||||
|
||||
#include "comBuf.h"
|
||||
#include "caServerID.h"
|
||||
|
||||
@@ -53,7 +53,6 @@ LIBSRCS += outBuf.cc
|
||||
LIBSRCS += casCtx.cc
|
||||
LIBSRCS += casEventMask.cc
|
||||
LIBSRCS += ioBlocked.cc
|
||||
LIBSRCS += casBufferFactory.cc
|
||||
LIBSRCS += pvExistReturn.cc
|
||||
LIBSRCS += pvAttachReturn.cc
|
||||
LIBSRCS += caNetAddr.cc
|
||||
@@ -80,8 +79,6 @@ ifeq ($(VX_GNU_VERSION), 4.1.2)
|
||||
casStreamOS_CXXFLAGS_vxWorks-ppc604 = -O0
|
||||
endif
|
||||
|
||||
LIBSRCS_vxWorks += templateInstances.cpp
|
||||
|
||||
LIBRARY = cas
|
||||
cas_LIBS = ca gdd Com
|
||||
cas_SYS_LIBS_WIN32 = ws2_32
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
|
||||
#include "directoryServer.h"
|
||||
#include "tsMinMax.h"
|
||||
#include "epicsAlgorithm.h"
|
||||
|
||||
const pvInfo *pvInfo::pFirst;
|
||||
|
||||
@@ -128,7 +128,7 @@ pvExistReturn directoryServer::pvExistTest
|
||||
}
|
||||
else {
|
||||
size_t diff = pLastStr-pPVName;
|
||||
diff = tsMin (diff, sizeof(pvNameBuf)-1);
|
||||
diff = epicsMin (diff, sizeof(pvNameBuf)-1);
|
||||
memcpy (pvNameBuf, pPVName, diff);
|
||||
pvNameBuf[diff] = '\0';
|
||||
pLastStr = pvNameBuf;
|
||||
|
||||
@@ -1,104 +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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "freeList.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "clientBufMemoryManager.h"
|
||||
#include "caProto.h"
|
||||
|
||||
casBufferFactory::casBufferFactory () :
|
||||
smallBufFreeList ( 0 ), largeBufFreeList ( 0 ), largeBufferSizePriv ( 0u )
|
||||
{
|
||||
long maxBytesAsALong;
|
||||
long status = envGetLongConfigParam ( & EPICS_CA_MAX_ARRAY_BYTES, & maxBytesAsALong );
|
||||
if ( status || maxBytesAsALong < 0 ) {
|
||||
errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" );
|
||||
this->largeBufferSizePriv = MAX_TCP;
|
||||
}
|
||||
else {
|
||||
/* allow room for the protocol header so that they get the array size they requested */
|
||||
static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
|
||||
ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong;
|
||||
if ( maxBytes < 0xffffffff - headerSize ) {
|
||||
maxBytes += headerSize;
|
||||
}
|
||||
else {
|
||||
maxBytes = 0xffffffff;
|
||||
}
|
||||
if ( maxBytes < MAX_TCP ) {
|
||||
errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP );
|
||||
this->largeBufferSizePriv = MAX_TCP;
|
||||
}
|
||||
else {
|
||||
this->largeBufferSizePriv = maxBytes;
|
||||
}
|
||||
}
|
||||
|
||||
freeListInitPvt ( & this->smallBufFreeList, MAX_MSG_SIZE, 8 );
|
||||
freeListInitPvt ( & this->largeBufFreeList, this->largeBufferSizePriv, 1 );
|
||||
}
|
||||
|
||||
casBufferFactory::~casBufferFactory ()
|
||||
{
|
||||
freeListCleanup ( this->smallBufFreeList );
|
||||
freeListCleanup ( this->largeBufFreeList );
|
||||
}
|
||||
|
||||
unsigned casBufferFactory::smallBufferSize () const
|
||||
{
|
||||
return MAX_MSG_SIZE;
|
||||
}
|
||||
|
||||
char * casBufferFactory::newSmallBuffer ()
|
||||
{
|
||||
void * pBuf = freeListCalloc ( this->smallBufFreeList );
|
||||
if ( ! pBuf ) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return static_cast < char * > ( pBuf );
|
||||
}
|
||||
|
||||
void casBufferFactory::destroySmallBuffer ( char * pBuf )
|
||||
{
|
||||
if ( pBuf ) {
|
||||
freeListFree ( this->smallBufFreeList, pBuf );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned casBufferFactory::largeBufferSize () const
|
||||
{
|
||||
return this->largeBufferSizePriv;
|
||||
}
|
||||
|
||||
char * casBufferFactory::newLargeBuffer ()
|
||||
{
|
||||
void * pBuf = freeListCalloc ( this->largeBufFreeList );
|
||||
if ( ! pBuf ) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return static_cast < char * > ( pBuf );
|
||||
}
|
||||
|
||||
void casBufferFactory::destroyLargeBuffer ( char * pBuf )
|
||||
{
|
||||
if ( pBuf ) {
|
||||
freeListFree ( this->largeBufFreeList, pBuf );
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* 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.
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
@@ -30,9 +30,9 @@ casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::searchAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::searchAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
@@ -51,7 +51,7 @@ casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::echoAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
@@ -64,9 +64,9 @@ casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
|
||||
//
|
||||
casDGClient::casDGClient ( caServerI & serverIn, clientBufMemoryManager & mgrIn ) :
|
||||
casCoreClient ( serverIn ),
|
||||
in ( *this, mgrIn, MAX_UDP_RECV + sizeof ( cadg ) ),
|
||||
in ( *this, mgrIn, MAX_UDP_RECV + sizeof ( cadg ) ),
|
||||
out ( *this, mgrIn ),
|
||||
seqNoOfReq ( 0 ),
|
||||
seqNoOfReq ( 0 ),
|
||||
minor_version_number ( 0 )
|
||||
{
|
||||
}
|
||||
@@ -92,12 +92,12 @@ void casDGClient::destroy()
|
||||
//
|
||||
void casDGClient::show (unsigned level) const
|
||||
{
|
||||
printf ( "casDGClient at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
printf ( "casDGClient at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
if (level>=1u) {
|
||||
char buf[64];
|
||||
this->hostName (buf, sizeof(buf));
|
||||
printf ("Client Host=%s\n", buf);
|
||||
printf ("Client Host=%s\n", buf);
|
||||
this->casCoreClient::show ( level - 1u );
|
||||
this->in.show ( level - 1u );
|
||||
this->out.show ( level - 1u );
|
||||
@@ -111,11 +111,13 @@ caStatus casDGClient::uknownMessageAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"bad request code=%u in DG\n", mp->m_cmmd );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"bad request code=%u in DG\n", mp->m_cmmd );
|
||||
}
|
||||
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
@@ -129,13 +131,23 @@ caStatus casDGClient::searchAction()
|
||||
const char *pChanName = static_cast <char * > ( this->ctx.getData() );
|
||||
caStatus status;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\" but is too old\n",
|
||||
pHostName, pChanName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
//
|
||||
// check the sanity of the message
|
||||
//
|
||||
if ( mp->m_postsize <= 1 ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"empty PV name extension in UDP search request?\n" );
|
||||
return S_cas_success;
|
||||
}
|
||||
@@ -143,19 +155,19 @@ caStatus casDGClient::searchAction()
|
||||
if ( pChanName[0] == '\0' ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"zero length PV name in UDP search request?\n" );
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
// check for an unterminated string before calling server tool
|
||||
// by searching backwards through the string (some early versions
|
||||
// by searching backwards through the string (some early versions
|
||||
// of the client library might not be setting the pad bytes to nill)
|
||||
for ( unsigned i = mp->m_postsize-1; pChanName[i] != '\0'; i-- ) {
|
||||
if ( i <= 1 ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"unterminated PV name in UDP search request?\n" );
|
||||
return S_cas_success;
|
||||
}
|
||||
@@ -164,7 +176,7 @@ caStatus casDGClient::searchAction()
|
||||
if ( this->getCAS().getDebugLevel() > 6u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\"\n",
|
||||
printf ( "\"%s\" is searching for \"%s\"\n",
|
||||
pHostName, pChanName );
|
||||
}
|
||||
|
||||
@@ -183,7 +195,7 @@ caStatus casDGClient::searchAction()
|
||||
// ask the server tool if this PV exists
|
||||
//
|
||||
this->userStartedAsyncIO = false;
|
||||
pvExistReturn pver =
|
||||
pvExistReturn pver =
|
||||
this->getCAS()->pvExistTest ( this->ctx, this->lastRecvAddr, pChanName );
|
||||
|
||||
//
|
||||
@@ -193,7 +205,7 @@ caStatus casDGClient::searchAction()
|
||||
//
|
||||
if ( this->userStartedAsyncIO ) {
|
||||
if ( pver.getStatus() != pverAsyncCompletion ) {
|
||||
errMessage (S_cas_badParameter,
|
||||
errMessage (S_cas_badParameter,
|
||||
"- assuming asynch IO status from caServer::pvExistTest()");
|
||||
}
|
||||
status = S_cas_success;
|
||||
@@ -212,13 +224,13 @@ caStatus casDGClient::searchAction()
|
||||
break;
|
||||
|
||||
case pverAsyncCompletion:
|
||||
errMessage (S_cas_badParameter,
|
||||
errMessage (S_cas_badParameter,
|
||||
"- unexpected asynch IO status from caServer::pvExistTest() ignored");
|
||||
status = S_cas_success;
|
||||
break;
|
||||
|
||||
default:
|
||||
errMessage (S_cas_badParameter,
|
||||
errMessage (S_cas_badParameter,
|
||||
"- invalid return from caServer::pvExistTest() ignored");
|
||||
status = S_cas_success;
|
||||
break;
|
||||
@@ -230,18 +242,18 @@ caStatus casDGClient::searchAction()
|
||||
//
|
||||
// caStatus casDGClient::searchResponse()
|
||||
//
|
||||
caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
const pvExistReturn & retVal )
|
||||
{
|
||||
caStatus status;
|
||||
|
||||
|
||||
if ( retVal.getStatus() != pverExistsHere ) {
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// starting with V4.1 the count field is used (abused)
|
||||
// by the client to store the minor version number of
|
||||
// by the client to store the minor version number of
|
||||
// the client.
|
||||
//
|
||||
// Old versions expect alloc of channel in response
|
||||
@@ -250,8 +262,8 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
if ( !CA_V44(msg.m_count) ) {
|
||||
char pName[64u];
|
||||
this->hostName (pName, sizeof (pName));
|
||||
errlogPrintf (
|
||||
"client \"%s\" using EPICS R3.11 CA connect protocol was ignored\n",
|
||||
errlogPrintf (
|
||||
"client \"%s\" using EPICS R3.11 CA connect protocol was ignored\n",
|
||||
pName);
|
||||
//
|
||||
// old connect protocol was dropped when the
|
||||
@@ -264,19 +276,19 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
}
|
||||
|
||||
//
|
||||
// cid field is abused to carry the IP
|
||||
// cid field is abused to carry the IP
|
||||
// address in CA_V48 or higher
|
||||
// (this allows a CA servers to serve
|
||||
// as a directory service)
|
||||
//
|
||||
// data type field is abused to carry the IP
|
||||
// data type field is abused to carry the IP
|
||||
// port number here CA_V44 or higher
|
||||
// (this allows multiple CA servers on one
|
||||
// host)
|
||||
//
|
||||
ca_uint32_t serverAddr;
|
||||
ca_uint16_t serverPort;
|
||||
if ( CA_V48( msg.m_count ) ) {
|
||||
if ( CA_V48( msg.m_count ) ) {
|
||||
struct sockaddr_in ina;
|
||||
if ( retVal.addrIsValid() ) {
|
||||
caNetAddr addr = retVal.getAddr();
|
||||
@@ -296,7 +308,7 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
ina = addr.getSockIP();
|
||||
//
|
||||
// We dont fill in the servers address here
|
||||
// because the server was not bound to a particular
|
||||
// because the server was not bound to a particular
|
||||
// interface, and we would need to waste CPU performing
|
||||
// the following steps to determine the interface that
|
||||
// will be used:
|
||||
@@ -318,24 +330,24 @@ caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
|
||||
serverAddr = ~0U;
|
||||
serverPort = ntohs ( inetAddr.sin_port );
|
||||
}
|
||||
|
||||
|
||||
ca_uint16_t * pMinorVersion;
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
status = this->out.copyInHeader ( CA_PROTO_SEARCH,
|
||||
sizeof ( *pMinorVersion ), serverPort, 0,
|
||||
serverAddr, msg.m_available,
|
||||
status = this->out.copyInHeader ( CA_PROTO_SEARCH,
|
||||
sizeof ( *pMinorVersion ), serverPort, 0,
|
||||
serverAddr, msg.m_available,
|
||||
reinterpret_cast <void **> ( &pMinorVersion ) );
|
||||
//
|
||||
// Starting with CA V4.1 the minor version number
|
||||
// is appended to the end of each search reply.
|
||||
// This value is ignored by earlier clients.
|
||||
// This value is ignored by earlier clients.
|
||||
//
|
||||
if ( status == S_cas_success ) {
|
||||
AlignedWireRef < epicsUInt16 > tmp ( *pMinorVersion );
|
||||
tmp = CA_MINOR_PROTOCOL_REVISION;
|
||||
this->out.commitMsg ();
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -362,6 +374,15 @@ caStatus casDGClient::versionAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is too old\n",
|
||||
pHostName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
if ( mp->m_count != 0 ) {
|
||||
this->minor_version_number = static_cast <ca_uint16_t> ( mp->m_count );
|
||||
if ( CA_V411 ( mp->m_count ) ) {
|
||||
@@ -404,8 +425,8 @@ void casDGClient::sendBeacon ( ca_uint32_t beaconNumber )
|
||||
//
|
||||
// casDGClient::xSend()
|
||||
//
|
||||
outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
|
||||
bufSizeT nBytesToSend, bufSizeT & nBytesSent )
|
||||
outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
|
||||
bufSizeT nBytesToSend, bufSizeT & nBytesSent )
|
||||
{
|
||||
bufSizeT totalBytes = 0;
|
||||
while ( totalBytes < nBytesToSend ) {
|
||||
@@ -418,7 +439,7 @@ outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
|
||||
unsigned sizeDG = pHdr->cadg_nBytes - sizeof ( *pHdr );
|
||||
|
||||
if ( pHdr->cadg_addr.isValid() ) {
|
||||
outBufClient::flushCondition stat =
|
||||
outBufClient::flushCondition stat =
|
||||
this->osdSend ( pDG, sizeDG, pHdr->cadg_addr );
|
||||
if ( stat != outBufClient::flushProgress ) {
|
||||
break;
|
||||
@@ -455,7 +476,7 @@ inBufClient::fillCondition casDGClient::xRecv (char *pBufIn, bufSizeT nBytesToRe
|
||||
|
||||
while (pAfter-pCurBuf >= static_cast<int>(MAX_UDP_RECV+sizeof(cadg))) {
|
||||
pHdr = reinterpret_cast < cadg * > ( pCurBuf );
|
||||
stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
|
||||
stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
|
||||
MAX_UDP_RECV, parm, nDGBytesRecv, pHdr->cadg_addr);
|
||||
if (stat==casFillProgress) {
|
||||
pHdr->cadg_nBytes = nDGBytesRecv + sizeof(*pHdr);
|
||||
@@ -487,9 +508,9 @@ inBufClient::fillCondition casDGClient::xRecv (char *pBufIn, bufSizeT nBytesToRe
|
||||
// this results in many small UDP frames which unfortunately
|
||||
// isnt particularly efficient
|
||||
//
|
||||
caStatus casDGClient::asyncSearchResponse (
|
||||
caStatus casDGClient::asyncSearchResponse (
|
||||
epicsGuard < casClientMutex > &, const caNetAddr & outAddr,
|
||||
const caHdrLargeArray & msg, const pvExistReturn & retVal,
|
||||
const caHdrLargeArray & msg, const pvExistReturn & retVal,
|
||||
ca_uint16_t protocolRevision, ca_uint32_t sequenceNumber )
|
||||
{
|
||||
if ( retVal.getStatus() != pverExistsHere ) {
|
||||
@@ -497,7 +518,7 @@ caStatus casDGClient::asyncSearchResponse (
|
||||
}
|
||||
|
||||
void * pRaw;
|
||||
const outBufCtx outctx = this->out.pushCtx
|
||||
const outBufCtx outctx = this->out.pushCtx
|
||||
( sizeof(cadg), MAX_UDP_SEND, pRaw );
|
||||
if ( outctx.pushResult() != outBufCtx::pushCtxSuccess ) {
|
||||
return S_cas_sendBlocked;
|
||||
@@ -533,8 +554,8 @@ caStatus casDGClient::processDG ()
|
||||
{
|
||||
bufSizeT bytesLeft;
|
||||
caStatus status;
|
||||
|
||||
status = S_cas_success;
|
||||
|
||||
status = S_cas_success;
|
||||
while ( ( bytesLeft = this->in.bytesPresent() ) ) {
|
||||
bufSizeT dgInBytesConsumed;
|
||||
const cadg * pReqHdr = reinterpret_cast < cadg * > ( this->in.msgPtr () );
|
||||
@@ -561,9 +582,9 @@ caStatus casDGClient::processDG ()
|
||||
|
||||
// insert version header at the start of the reply message
|
||||
this->sendVersion ();
|
||||
|
||||
|
||||
cadg * pRespHdr = static_cast < cadg * > ( pRaw );
|
||||
|
||||
|
||||
//
|
||||
// select the next DG in the input stream and start processing it
|
||||
//
|
||||
@@ -593,7 +614,7 @@ caStatus casDGClient::processDG ()
|
||||
// a) it used all of the incoming DG or
|
||||
// b) it used all of the outgoing DG
|
||||
//
|
||||
// In either case commit the DG to the protocol stream and
|
||||
// In either case commit the DG to the protocol stream and
|
||||
// release the send lock
|
||||
//
|
||||
// if there are not additional messages passed the version header
|
||||
@@ -684,7 +705,7 @@ void casDGClient::hostName ( char *pBufIn, unsigned bufSizeIn ) const
|
||||
void casDGClient::sendVersion ()
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
caStatus status = this->out.copyInHeader ( CA_PROTO_VERSION, 0,
|
||||
caStatus status = this->out.copyInHeader ( CA_PROTO_VERSION, 0,
|
||||
0, CA_MINOR_PROTOCOL_REVISION, 0, 0, 0 );
|
||||
if ( ! status ) {
|
||||
this->out.commitMsg ();
|
||||
@@ -779,8 +800,8 @@ caStatus casDGClient::processMsg ()
|
||||
msgTmp.m_available = AlignedWireRef < epicsUInt32 > ( smallHdr.m_available );
|
||||
|
||||
if ( payloadSize & 0x7 ) {
|
||||
status = this->sendErr (
|
||||
& msgTmp, invalidResID, ECA_INTERNAL,
|
||||
status = this->sendErr (
|
||||
& msgTmp, invalidResID, ECA_INTERNAL,
|
||||
"CAS: Datagram request wasn't 8 byte aligned" );
|
||||
this->in.removeMsg ( bytesLeft );
|
||||
break;
|
||||
@@ -789,7 +810,7 @@ caStatus casDGClient::processMsg ()
|
||||
msgSize = hdrSize + payloadSize;
|
||||
if ( bytesLeft < msgSize ) {
|
||||
if ( msgSize > this->in.bufferSize() ) {
|
||||
status = this->sendErr ( & msgTmp, invalidResID, ECA_TOLARGE,
|
||||
status = this->sendErr ( & msgTmp, invalidResID, ECA_TOLARGE,
|
||||
"client's request didnt fit within the CA server's message buffer" );
|
||||
this->in.removeMsg ( bytesLeft );
|
||||
}
|
||||
@@ -801,7 +822,7 @@ caStatus casDGClient::processMsg ()
|
||||
if ( this->getCAS().getDebugLevel() > 5u ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
caServerI::dumpMsg ( pHostName, "?",
|
||||
caServerI::dumpMsg ( pHostName, "?",
|
||||
& msgTmp, rawMP + hdrSize, 0 );
|
||||
}
|
||||
|
||||
@@ -809,7 +830,7 @@ caStatus casDGClient::processMsg ()
|
||||
|
||||
//
|
||||
// Reset the context to the default
|
||||
// (guarantees that previous message does not get mixed
|
||||
// (guarantees that previous message does not get mixed
|
||||
// up with the current message)
|
||||
//
|
||||
this->ctx.setChannel ( NULL );
|
||||
@@ -836,16 +857,16 @@ caStatus casDGClient::processMsg ()
|
||||
}
|
||||
catch ( std::exception & except ) {
|
||||
this->in.removeMsg ( this->in.bytesPresent() );
|
||||
this->sendErr (
|
||||
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
|
||||
this->sendErr (
|
||||
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
|
||||
"C++ exception \"%s\" in CA circuit server",
|
||||
except.what () );
|
||||
status = S_cas_internal;
|
||||
}
|
||||
catch (...) {
|
||||
this->in.removeMsg ( this->in.bytesPresent() );
|
||||
this->sendErr (
|
||||
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
|
||||
this->sendErr (
|
||||
this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
|
||||
"unexpected C++ exception in CA datagram server" );
|
||||
status = S_cas_internal;
|
||||
}
|
||||
@@ -854,9 +875,9 @@ caStatus casDGClient::processMsg ()
|
||||
}
|
||||
|
||||
//
|
||||
// casDGClient::sendErr()
|
||||
// casDGClient::sendErr()
|
||||
//
|
||||
caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
ca_uint32_t cid, const int reportedStatus, const char *pformat, ... )
|
||||
{
|
||||
unsigned stringSize;
|
||||
@@ -880,14 +901,14 @@ caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
}
|
||||
|
||||
unsigned hdrSize = sizeof ( caHdr );
|
||||
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
|
||||
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
|
||||
CA_V49( this->minor_version_number ) ) {
|
||||
hdrSize += 2 * sizeof ( ca_uint32_t );
|
||||
}
|
||||
|
||||
caHdr * pReqOut;
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
caStatus status = this->out.copyInHeader ( CA_PROTO_ERROR,
|
||||
caStatus status = this->out.copyInHeader ( CA_PROTO_ERROR,
|
||||
hdrSize + stringSize, 0, 0, cid, reportedStatus,
|
||||
reinterpret_cast <void **> ( & pReqOut ) );
|
||||
if ( ! status ) {
|
||||
@@ -897,7 +918,7 @@ caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
|
||||
* copy back the request protocol
|
||||
* (in network byte order)
|
||||
*/
|
||||
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
|
||||
if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
|
||||
CA_V49( this->minor_version_number ) ) {
|
||||
ca_uint32_t *pLW = ( ca_uint32_t * ) ( pReqOut + 1 );
|
||||
pReqOut->m_cmmd = htons ( curp->m_cmmd );
|
||||
@@ -942,7 +963,7 @@ caStatus casDGClient::echoAction ()
|
||||
void * pPayloadOut;
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
caStatus status = this->out.copyInHeader ( mp->m_cmmd, mp->m_postsize,
|
||||
caStatus status = this->out.copyInHeader ( mp->m_cmmd, mp->m_postsize,
|
||||
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
|
||||
& pPayloadOut );
|
||||
if ( ! status ) {
|
||||
|
||||
@@ -205,7 +205,7 @@ caStatus casStrmClient :: processMsg ()
|
||||
if ( bytesLeft < msgSize ) {
|
||||
status = S_cas_success;
|
||||
if ( msgSize > this->in.bufferSize() ) {
|
||||
this->in.expandBuffer ();
|
||||
this->in.expandBuffer (msgSize);
|
||||
// msg to large - set up message drain
|
||||
if ( msgSize > this->in.bufferSize() ) {
|
||||
caServerI::dumpMsg ( this->pHostName, this->pUserName, & msgTmp, 0,
|
||||
@@ -338,6 +338,16 @@ caStatus casStrmClient::versionAction ( epicsGuard < casClientMutex > & )
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is too old\n",
|
||||
pHostName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
double tmp = mp->m_dataType - CA_PROTO_PRIORITY_MIN;
|
||||
tmp *= epicsThreadPriorityCAServerHigh - epicsThreadPriorityCAServerLow;
|
||||
tmp /= CA_PROTO_PRIORITY_MAX - CA_PROTO_PRIORITY_MIN;
|
||||
@@ -1267,6 +1277,14 @@ caStatus casStrmClient :: searchResponse (
|
||||
const pvExistReturn & retVal )
|
||||
{
|
||||
if ( retVal.getStatus() != pverExistsHere ) {
|
||||
if (msg.m_dataType == DOREPLY ) {
|
||||
long status = this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
|
||||
msg.m_dataType, msg.m_count, msg.m_cid, msg.m_available, 0 );
|
||||
|
||||
if ( status == S_cas_success ) {
|
||||
this->out.commitMsg ();
|
||||
}
|
||||
}
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
@@ -1362,6 +1380,16 @@ caStatus casStrmClient :: searchAction ( epicsGuard < casClientMutex > & guard )
|
||||
const char *pChanName = static_cast <char * > ( this->ctx.getData() );
|
||||
caStatus status;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\" but is too old\n",
|
||||
pHostName, pChanName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
//
|
||||
// check the sanity of the message
|
||||
//
|
||||
@@ -1431,11 +1459,8 @@ caStatus casStrmClient :: searchAction ( epicsGuard < casClientMutex > & guard )
|
||||
//
|
||||
switch ( pver.getStatus() ) {
|
||||
case pverExistsHere:
|
||||
status = this->searchResponse ( guard, *mp, pver );
|
||||
break;
|
||||
|
||||
case pverDoesNotExistHere:
|
||||
status = S_cas_success;
|
||||
status = this->searchResponse ( guard, *mp, pver );
|
||||
break;
|
||||
|
||||
case pverAsyncCompletion:
|
||||
|
||||
@@ -13,42 +13,54 @@
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "freeList.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "clientBufMemoryManager.h"
|
||||
#include "caProto.h"
|
||||
|
||||
bufSizeT clientBufMemoryManager::maxSize () const
|
||||
clientBufMemoryManager::clientBufMemoryManager()
|
||||
:smallBufFreeList ( 0 )
|
||||
{
|
||||
return bufferFactory.largeBufferSize ();
|
||||
freeListInitPvt ( & this->smallBufFreeList, MAX_MSG_SIZE, 8 );
|
||||
}
|
||||
|
||||
clientBufMemoryManager::~clientBufMemoryManager()
|
||||
{
|
||||
freeListCleanup ( this->smallBufFreeList );
|
||||
}
|
||||
|
||||
casBufferParm clientBufMemoryManager::allocate ( bufSizeT newMinSize )
|
||||
{
|
||||
casBufferParm parm;
|
||||
if ( newMinSize <= bufferFactory.smallBufferSize () ) {
|
||||
parm.pBuf = bufferFactory.newSmallBuffer ();
|
||||
parm.bufSize = bufferFactory.smallBufferSize ();
|
||||
}
|
||||
else if ( newMinSize <= bufferFactory.largeBufferSize () ) {
|
||||
parm.pBuf = bufferFactory.newLargeBuffer ();
|
||||
parm.bufSize = bufferFactory.largeBufferSize ();
|
||||
if ( newMinSize <= MAX_MSG_SIZE ) {
|
||||
parm.pBuf = (char*)freeListMalloc(this->smallBufFreeList);
|
||||
parm.bufSize = MAX_MSG_SIZE;
|
||||
}
|
||||
else {
|
||||
parm.pBuf = static_cast < char * > ( ::operator new ( newMinSize ) );
|
||||
// round size up to multiple of 4K
|
||||
newMinSize = ((newMinSize-1)|0xfff)+1;
|
||||
parm.pBuf = (char*)malloc(newMinSize);
|
||||
parm.bufSize = newMinSize;
|
||||
}
|
||||
if(!parm.pBuf)
|
||||
throw std::bad_alloc();
|
||||
return parm;
|
||||
}
|
||||
|
||||
void clientBufMemoryManager::release ( char * pBuf, bufSizeT bufSize )
|
||||
{
|
||||
if ( bufSize == bufferFactory.smallBufferSize () ) {
|
||||
bufferFactory.destroySmallBuffer ( pBuf );
|
||||
}
|
||||
else if ( bufSize == bufferFactory.largeBufferSize () ) {
|
||||
bufferFactory.destroyLargeBuffer ( pBuf );
|
||||
assert(pBuf);
|
||||
if (bufSize <= MAX_MSG_SIZE) {
|
||||
freeListFree(this->smallBufFreeList, pBuf);
|
||||
}
|
||||
else {
|
||||
::operator delete ( pBuf );
|
||||
free(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,22 +16,6 @@
|
||||
typedef unsigned bufSizeT;
|
||||
static const unsigned bufSizeT_MAX = UINT_MAX;
|
||||
|
||||
class casBufferFactory {
|
||||
public:
|
||||
casBufferFactory ();
|
||||
~casBufferFactory ();
|
||||
unsigned smallBufferSize () const;
|
||||
char * newSmallBuffer ();
|
||||
void destroySmallBuffer ( char * pBuf );
|
||||
unsigned largeBufferSize () const;
|
||||
char * newLargeBuffer ();
|
||||
void destroyLargeBuffer ( char * pBuf );
|
||||
private:
|
||||
void * smallBufFreeList;
|
||||
void * largeBufFreeList;
|
||||
unsigned largeBufferSizePriv;
|
||||
};
|
||||
|
||||
struct casBufferParm {
|
||||
char * pBuf;
|
||||
bufSizeT bufSize;
|
||||
@@ -39,11 +23,15 @@ struct casBufferParm {
|
||||
|
||||
class clientBufMemoryManager {
|
||||
public:
|
||||
clientBufMemoryManager();
|
||||
~clientBufMemoryManager();
|
||||
|
||||
//! @throws std::bad_alloc on failure
|
||||
casBufferParm allocate ( bufSizeT newMinSize );
|
||||
void release ( char * pBuf, bufSizeT bufSize );
|
||||
bufSizeT maxSize () const;
|
||||
private:
|
||||
casBufferFactory bufferFactory;
|
||||
|
||||
void * smallBufFreeList;
|
||||
};
|
||||
|
||||
#endif // clientBufMemoryManagerh
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <new>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -155,11 +158,17 @@ bufSizeT inBuf::popCtx ( const inBufCtx &ctx )
|
||||
}
|
||||
}
|
||||
|
||||
void inBuf::expandBuffer ()
|
||||
void inBuf::expandBuffer (bufSizeT needed)
|
||||
{
|
||||
bufSizeT max = this->memMgr.maxSize();
|
||||
if ( this->bufSize < max ) {
|
||||
casBufferParm bufParm = this->memMgr.allocate ( max );
|
||||
if (needed > bufSize) {
|
||||
casBufferParm bufParm;
|
||||
try {
|
||||
bufParm = this->memMgr.allocate ( needed );
|
||||
} catch (std::bad_alloc& e) {
|
||||
// caller must check that buffer size has expended
|
||||
return;
|
||||
}
|
||||
|
||||
bufSizeT unprocessedBytes = this->bytesPresent ();
|
||||
memcpy ( bufParm.pBuf, &this->pBuf[this->nextReadIndex], unprocessedBytes );
|
||||
this->bytesInBuffer = unprocessedBytes;
|
||||
@@ -170,7 +179,7 @@ void inBuf::expandBuffer ()
|
||||
}
|
||||
}
|
||||
|
||||
unsigned inBuf::bufferSize () const
|
||||
bufSizeT inBuf::bufferSize() const
|
||||
{
|
||||
return this->bufSize;
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ public:
|
||||
//
|
||||
const inBufCtx pushCtx ( bufSizeT headerSize, bufSizeT bodySize );
|
||||
bufSizeT popCtx ( const inBufCtx & ); // returns actual size
|
||||
unsigned bufferSize () const;
|
||||
void expandBuffer ();
|
||||
bufSizeT bufferSize () const;
|
||||
void expandBuffer (bufSizeT needed);
|
||||
private:
|
||||
class inBufClient & client;
|
||||
class clientBufMemoryManager & memMgr;
|
||||
|
||||
@@ -59,7 +59,7 @@ caStatus outBuf::allocRawMsg ( bufSizeT msgsize, void **ppMsg )
|
||||
msgsize = CA_MESSAGE_ALIGN ( msgsize );
|
||||
|
||||
if ( msgsize > this->bufSize ) {
|
||||
this->expandBuffer ();
|
||||
this->expandBuffer (msgsize);
|
||||
if ( msgsize > this->bufSize ) {
|
||||
return S_cas_hugeRequest;
|
||||
}
|
||||
@@ -316,11 +316,17 @@ void outBuf::show (unsigned level) const
|
||||
}
|
||||
}
|
||||
|
||||
void outBuf::expandBuffer ()
|
||||
void outBuf::expandBuffer (bufSizeT needed)
|
||||
{
|
||||
bufSizeT max = this->memMgr.maxSize();
|
||||
if ( this->bufSize < max ) {
|
||||
casBufferParm bufParm = this->memMgr.allocate ( max );
|
||||
if (needed > bufSize) {
|
||||
casBufferParm bufParm;
|
||||
try {
|
||||
bufParm = this->memMgr.allocate ( needed );
|
||||
} catch (std::bad_alloc& e) {
|
||||
// caller must check that buffer size has expended
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy ( bufParm.pBuf, this->pBuf, this->stack );
|
||||
this->memMgr.release ( this->pBuf, this->bufSize );
|
||||
this->pBuf = bufParm.pBuf;
|
||||
|
||||
@@ -122,7 +122,7 @@ private:
|
||||
bufSizeT stack;
|
||||
unsigned ctxRecursCount;
|
||||
|
||||
void expandBuffer ();
|
||||
void expandBuffer (bufSizeT needed);
|
||||
|
||||
outBuf ( const outBuf & );
|
||||
outBuf & operator = ( const outBuf & );
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2008 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 is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "ipIgnoreEntry.h"
|
||||
#include "casChannelI.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class resTable < ipIgnoreEntry, ipIgnoreEntry >;
|
||||
template class resTable < casChannelI, chronIntId >;
|
||||
template class resTable < casEventMaskEntry, stringId >;
|
||||
template class chronIntIdResTable < casChannelI >;
|
||||
template class tsFreeList < casMonEvent, 1024, epicsMutexNOOP >;
|
||||
template class tsFreeList < casMonitor, 1024, epicsMutex >;
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
@@ -23,5 +23,4 @@ dbCore_SRCS += asIocRegister.c
|
||||
|
||||
PROD_HOST += ascheck
|
||||
ascheck_SRCS = ascheck.c
|
||||
ascheck_LIBS = dbCore
|
||||
|
||||
ascheck_LIBS = dbCore ca
|
||||
|
||||
@@ -14,14 +14,18 @@ SRC_DIRS += $(IOCDIR)/db
|
||||
INC += callback.h
|
||||
INC += dbAccess.h
|
||||
INC += dbAccessDefs.h
|
||||
INC += dbCa.h
|
||||
INC += dbAddr.h
|
||||
INC += dbBkpt.h
|
||||
INC += dbCa.h
|
||||
INC += dbChannel.h
|
||||
INC += dbConstLink.h
|
||||
INC += dbConvert.h
|
||||
INC += dbConvertFast.h
|
||||
INC += dbConvertJSON.h
|
||||
INC += dbDbLink.h
|
||||
INC += dbExtractArray.h
|
||||
INC += dbEvent.h
|
||||
INC += dbJLink.h
|
||||
INC += dbLink.h
|
||||
INC += dbLock.h
|
||||
INC += dbNotify.h
|
||||
@@ -64,9 +68,13 @@ dbCore_SRCS += dbLock.c
|
||||
dbCore_SRCS += dbAccess.c
|
||||
dbCore_SRCS += dbBkpt.c
|
||||
dbCore_SRCS += dbChannel.c
|
||||
dbCore_SRCS += dbConstLink.c
|
||||
dbCore_SRCS += dbConvert.c
|
||||
dbCore_SRCS += dbConvertJSON.c
|
||||
dbCore_SRCS += dbDbLink.c
|
||||
dbCore_SRCS += dbFastLinkConv.c
|
||||
dbCore_SRCS += dbExtractArray.c
|
||||
dbCore_SRCS += dbJLink.c
|
||||
dbCore_SRCS += dbLink.c
|
||||
dbCore_SRCS += dbNotify.c
|
||||
dbCore_SRCS += dbScan.c
|
||||
@@ -85,7 +93,6 @@ dbCore_SRCS += dbChannelIO.cpp
|
||||
dbCore_SRCS += dbSubscriptionIO.cpp
|
||||
dbCore_SRCS += dbPutNotifyBlocker.cpp
|
||||
dbCore_SRCS += dbContextReadNotifyCache.cpp
|
||||
dbCore_SRCS += templateInstances.cpp
|
||||
dbCore_SRCS += dbIocRegister.c
|
||||
dbCore_SRCS += chfPlugin.c
|
||||
dbCore_SRCS += dbState.c
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "dbDefs.h"
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsInterrupt.h"
|
||||
#include "epicsRingPointer.h"
|
||||
#include "epicsString.h"
|
||||
@@ -92,7 +91,7 @@ static int priorityValue[NUM_CALLBACK_PRIORITIES] = {0, 1, 2};
|
||||
int callbackSetQueueSize(int size)
|
||||
{
|
||||
if (callbackIsInit) {
|
||||
errlogPrintf("Callback system already initialized\n");
|
||||
fprintf(stderr, "Callback system already initialized\n");
|
||||
return -1;
|
||||
}
|
||||
callbackQueueSize = size;
|
||||
@@ -102,7 +101,7 @@ int callbackSetQueueSize(int size)
|
||||
int callbackParallelThreads(int count, const char *prio)
|
||||
{
|
||||
if (callbackIsInit) {
|
||||
errlogPrintf("Callback system already initialized\n");
|
||||
fprintf(stderr, "Callback system already initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -112,7 +111,7 @@ int callbackParallelThreads(int count, const char *prio)
|
||||
count = callbackParallelThreadsDefault;
|
||||
if (count < 1) count = 1;
|
||||
|
||||
if (!prio || strcmp(prio, "") == 0 || strcmp(prio, "*") == 0) {
|
||||
if (!prio || *prio == 0 || strcmp(prio, "*") == 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
|
||||
@@ -121,30 +120,30 @@ int callbackParallelThreads(int count, const char *prio)
|
||||
}
|
||||
else {
|
||||
dbMenu *pdbMenu;
|
||||
int i;
|
||||
|
||||
if (!pdbbase) {
|
||||
errlogPrintf("callbackParallelThreads: pdbbase not set\n");
|
||||
fprintf(stderr, "callbackParallelThreads: pdbbase not set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find prio in menuPriority */
|
||||
pdbMenu = dbFindMenu(pdbbase, "menuPriority");
|
||||
if (pdbMenu) {
|
||||
int i, gotMatch = 0;
|
||||
|
||||
for (i = 0; i < pdbMenu->nChoice; i++) {
|
||||
gotMatch = (epicsStrCaseCmp(prio, pdbMenu->papChoiceValue[i])==0) ? TRUE : FALSE;
|
||||
if (gotMatch)
|
||||
break;
|
||||
}
|
||||
if (gotMatch) {
|
||||
callbackQueue[i].threadsConfigured = count;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
errlogPrintf("Unknown priority \"%s\"\n", prio);
|
||||
return -1;
|
||||
}
|
||||
if (!pdbMenu) {
|
||||
fprintf(stderr, "callbackParallelThreads: No Priority menu\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < pdbMenu->nChoice; i++) {
|
||||
if (epicsStrCaseCmp(prio, pdbMenu->papChoiceValue[i]) == 0)
|
||||
goto found;
|
||||
}
|
||||
fprintf(stderr, "callbackParallelThreads: "
|
||||
"Unknown priority \"%s\"\n", prio);
|
||||
return -1;
|
||||
|
||||
found:
|
||||
callbackQueue[i].threadsConfigured = count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,14 +46,16 @@ typedef struct callbackPvt {
|
||||
|
||||
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
|
||||
|
||||
#define callbackSetCallback(PFUN,PCALLBACK)\
|
||||
( (PCALLBACK)->callback = (PFUN) )
|
||||
#define callbackSetPriority(PRIORITY,PCALLBACK)\
|
||||
( (PCALLBACK)->priority = (PRIORITY) )
|
||||
#define callbackSetUser(USER,PCALLBACK)\
|
||||
( (PCALLBACK)->user = (void *)(USER) )
|
||||
#define callbackGetUser(USER,PCALLBACK)\
|
||||
( (USER) = (void *)((CALLBACK *)(PCALLBACK))->user )
|
||||
#define callbackSetCallback(PFUN, PCALLBACK) \
|
||||
( (PCALLBACK)->callback = (PFUN) )
|
||||
#define callbackSetPriority(PRIORITY, PCALLBACK) \
|
||||
( (PCALLBACK)->priority = (PRIORITY) )
|
||||
#define callbackGetPriority(PRIORITY, PCALLBACK) \
|
||||
( (PRIORITY) = (PCALLBACK)->priority )
|
||||
#define callbackSetUser(USER, PCALLBACK) \
|
||||
( (PCALLBACK)->user = (void *) (USER) )
|
||||
#define callbackGetUser(USER, PCALLBACK) \
|
||||
( (USER) = (PCALLBACK)->user )
|
||||
|
||||
epicsShareFunc void callbackInit(void);
|
||||
epicsShareFunc void callbackStop(void);
|
||||
|
||||
@@ -41,8 +41,7 @@
|
||||
#include "dbAddr.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "dbCa.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbCommonPvt.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbEvent.h"
|
||||
@@ -50,11 +49,12 @@
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbLockPvt.h"
|
||||
#include "dbNotify.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbServer.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
#include "devSup.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "link.h"
|
||||
@@ -77,6 +77,8 @@ static short mapDBFToDBR[DBF_NTYPES] = {
|
||||
/* DBF_USHORT => */ DBR_USHORT,
|
||||
/* DBF_LONG => */ DBR_LONG,
|
||||
/* DBF_ULONG => */ DBR_ULONG,
|
||||
/* DBF_INT64 => */ DBR_INT64,
|
||||
/* DBF_UINT64 => */ DBR_UINT64,
|
||||
/* DBF_FLOAT => */ DBR_FLOAT,
|
||||
/* DBF_DOUBLE => */ DBR_DOUBLE,
|
||||
/* DBF_ENUM, => */ DBR_ENUM,
|
||||
@@ -107,7 +109,7 @@ void dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
|
||||
long dbPutSpecial(DBADDR *paddr,int pass)
|
||||
{
|
||||
long int (*pspecial)()=NULL;
|
||||
struct rset *prset;
|
||||
rset *prset;
|
||||
dbCommon *precord = paddr->precord;
|
||||
long status=0;
|
||||
long special=paddr->special;
|
||||
@@ -139,7 +141,7 @@ long dbPutSpecial(DBADDR *paddr,int pass)
|
||||
}
|
||||
|
||||
static void get_enum_strs(DBADDR *paddr, char **ppbuffer,
|
||||
struct rset *prset,long *options)
|
||||
rset *prset,long *options)
|
||||
{
|
||||
short field_type=paddr->field_type;
|
||||
dbFldDes *pdbFldDes = paddr->pfldDes;
|
||||
@@ -199,7 +201,7 @@ choice_common:
|
||||
}
|
||||
|
||||
static void get_graphics(DBADDR *paddr, char **ppbuffer,
|
||||
struct rset *prset,long *options)
|
||||
rset *prset,long *options)
|
||||
{
|
||||
struct dbr_grDouble grd;
|
||||
int got_data=FALSE;
|
||||
@@ -239,7 +241,7 @@ static void get_graphics(DBADDR *paddr, char **ppbuffer,
|
||||
}
|
||||
|
||||
static void get_control(DBADDR *paddr, char **ppbuffer,
|
||||
struct rset *prset,long *options)
|
||||
rset *prset,long *options)
|
||||
{
|
||||
struct dbr_ctrlDouble ctrld;
|
||||
int got_data=FALSE;
|
||||
@@ -279,7 +281,7 @@ static void get_control(DBADDR *paddr, char **ppbuffer,
|
||||
}
|
||||
|
||||
static void get_alarm(DBADDR *paddr, char **ppbuffer,
|
||||
struct rset *prset, long *options)
|
||||
rset *prset, long *options)
|
||||
{
|
||||
char *pbuffer = *ppbuffer;
|
||||
struct dbr_alDouble ald = {epicsNAN, epicsNAN, epicsNAN, epicsNAN};
|
||||
@@ -324,7 +326,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
|
||||
void *pflin)
|
||||
{
|
||||
db_field_log *pfl= (db_field_log *)pflin;
|
||||
struct rset *prset;
|
||||
rset *prset;
|
||||
short field_type;
|
||||
dbCommon *pcommon;
|
||||
char *pbuffer = *poriginal;
|
||||
@@ -364,7 +366,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
|
||||
memset(pbuffer, '\0', dbr_precision_size);
|
||||
if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE)
|
||||
&& prset && prset->get_precision ){
|
||||
(*prset->get_precision)(paddr,pbuffer);
|
||||
(*prset->get_precision)(paddr,(long *)pbuffer);
|
||||
} else {
|
||||
*options ^= DBR_PRECISION; /*Turn off DBR_PRECISION*/
|
||||
}
|
||||
@@ -393,7 +395,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
|
||||
*poriginal = pbuffer;
|
||||
}
|
||||
|
||||
struct rset * dbGetRset(const struct dbAddr *paddr)
|
||||
rset * dbGetRset(const struct dbAddr *paddr)
|
||||
{
|
||||
struct dbFldDes *pfldDes = paddr->pfldDes;
|
||||
|
||||
@@ -467,7 +469,7 @@ long dbScanPassive(dbCommon *pfrom, dbCommon *pto)
|
||||
*/
|
||||
long dbProcess(dbCommon *precord)
|
||||
{
|
||||
struct rset *prset = precord->rset;
|
||||
rset *prset = precord->rset;
|
||||
dbRecordType *pdbRecordType = precord->rdes;
|
||||
unsigned char tpro = precord->tpro;
|
||||
char context[40] = "";
|
||||
@@ -646,7 +648,7 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
|
||||
paddr->dbr_field_type = mapDBFToDBR[dbfType];
|
||||
|
||||
if (paddr->special == SPC_DBADDR) {
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
rset *prset = dbGetRset(paddr);
|
||||
|
||||
/* Let record type modify paddr */
|
||||
if (prset && prset->cvt_dbaddr) {
|
||||
@@ -667,7 +669,7 @@ long dbNameToAddr(const char *pname, DBADDR *paddr)
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
|
||||
/* Clients see a char array, but keep original dbfType */
|
||||
paddr->no_elements = PVNAME_STRINGSZ + 12;
|
||||
paddr->no_elements = PVLINK_STRINGSZ;
|
||||
paddr->field_size = 1;
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else {
|
||||
@@ -681,6 +683,32 @@ finish:
|
||||
return status;
|
||||
}
|
||||
|
||||
void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry)
|
||||
{
|
||||
struct dbCommon *prec = paddr->precord;
|
||||
dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common);
|
||||
|
||||
memset((char *)pdbentry,'\0',sizeof(DBENTRY));
|
||||
|
||||
pdbentry->pdbbase = pdbbase;
|
||||
pdbentry->precordType = prec->rdes;
|
||||
pdbentry->precnode = ppvt->recnode;
|
||||
pdbentry->pflddes = paddr->pfldDes;
|
||||
pdbentry->pfield = paddr->pfield;
|
||||
pdbentry->indfield = paddr->pfldDes->indRecordType;
|
||||
}
|
||||
|
||||
void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry)
|
||||
{
|
||||
dbCommonPvt *ppvt = CONTAINER(prec, dbCommonPvt, common);
|
||||
|
||||
memset((char *)pdbentry,'\0',sizeof(DBENTRY));
|
||||
|
||||
pdbentry->pdbbase = pdbbase;
|
||||
pdbentry->precordType = prec->rdes;
|
||||
pdbentry->precnode = ppvt->recnode;
|
||||
}
|
||||
|
||||
long dbValueSize(short dbr_type)
|
||||
{
|
||||
/* sizes for value associated with each DBR request type */
|
||||
@@ -692,6 +720,8 @@ long dbValueSize(short dbr_type)
|
||||
sizeof(epicsUInt16), /* USHORT */
|
||||
sizeof(epicsInt32), /* LONG */
|
||||
sizeof(epicsUInt32), /* ULONG */
|
||||
sizeof(epicsInt64), /* INT64 */
|
||||
sizeof(epicsUInt64), /* UINT64 */
|
||||
sizeof(epicsFloat32), /* FLOAT */
|
||||
sizeof(epicsFloat64), /* DOUBLE */
|
||||
sizeof(epicsEnum16)}; /* ENUM */
|
||||
@@ -838,7 +868,7 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
db_field_log *pfl = (db_field_log *)pflin;
|
||||
short field_type;
|
||||
long capacity, no_elements, offset;
|
||||
struct rset *prset;
|
||||
rset *prset;
|
||||
long status = 0;
|
||||
|
||||
if (options && *options)
|
||||
@@ -973,19 +1003,25 @@ devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) {
|
||||
static long dbPutFieldLink(DBADDR *paddr,
|
||||
short dbrType, const void *pbuffer, long nRequest)
|
||||
{
|
||||
dbLinkInfo link_info;
|
||||
DBADDR *pdbaddr = NULL;
|
||||
dbCommon *precord = paddr->precord;
|
||||
dbCommon *lockrecs[2];
|
||||
dbLocker locker;
|
||||
dbFldDes *pfldDes = paddr->pfldDes;
|
||||
long special = paddr->special;
|
||||
struct link *plink = (struct link *)paddr->pfield;
|
||||
const char *pstring = (const char *)pbuffer;
|
||||
DBENTRY dbEntry;
|
||||
struct dsxt *old_dsxt = NULL;
|
||||
struct dset *new_dset = NULL;
|
||||
struct dsxt *new_dsxt = NULL;
|
||||
devSup *new_devsup = NULL;
|
||||
long status;
|
||||
int isDevLink;
|
||||
short scan;
|
||||
|
||||
STATIC_ASSERT(DBLOCKER_NALLOC>=2);
|
||||
|
||||
switch (dbrType) {
|
||||
case DBR_CHAR:
|
||||
case DBR_UCHAR:
|
||||
@@ -1000,31 +1036,57 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
return S_db_badDbrtype;
|
||||
}
|
||||
|
||||
dbInitEntry(pdbbase, &dbEntry);
|
||||
status = dbFindRecord(&dbEntry, precord->name);
|
||||
if (!status) status = dbFindField(&dbEntry, pfldDes->name);
|
||||
if (status) goto finish;
|
||||
status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (link_info.ltype == PV_LINK &&
|
||||
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
|
||||
DBADDR tempaddr;
|
||||
|
||||
if (dbNameToAddr(link_info.target, &tempaddr)==0) {
|
||||
/* This will become a DB link. */
|
||||
pdbaddr = malloc(sizeof(*pdbaddr));
|
||||
if (!pdbaddr) {
|
||||
status = S_db_noMemory;
|
||||
goto cleanup;
|
||||
}
|
||||
*pdbaddr = tempaddr; /* struct copy */
|
||||
}
|
||||
}
|
||||
|
||||
isDevLink = ellCount(&precord->rdes->devList) > 0 &&
|
||||
(strcmp(pfldDes->name, "INP") == 0 ||
|
||||
strcmp(pfldDes->name, "OUT") == 0);
|
||||
pfldDes->isDevLink;
|
||||
|
||||
dbLockSetGblLock();
|
||||
dbLockSetRecordLock(precord);
|
||||
memset(&locker, 0, sizeof(locker));
|
||||
lockrecs[0] = precord;
|
||||
lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL;
|
||||
dbLockerPrepare(&locker, lockrecs, 2);
|
||||
|
||||
dbScanLockMany(&locker);
|
||||
|
||||
scan = precord->scan;
|
||||
|
||||
if (isDevLink) {
|
||||
devSup *pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
|
||||
if (pdevSup) {
|
||||
new_dset = pdevSup->pdset;
|
||||
new_dsxt = pdevSup->pdsxt;
|
||||
new_devsup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
|
||||
if (new_devsup) {
|
||||
new_dset = new_devsup->pdset;
|
||||
new_dsxt = new_devsup->pdsxt;
|
||||
}
|
||||
}
|
||||
|
||||
if (dbCanSetLink(plink, &link_info, new_devsup)) {
|
||||
/* link type mis-match prevents assignment */
|
||||
status = S_dbLib_badField;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (isDevLink) {
|
||||
if (precord->dset) {
|
||||
pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset);
|
||||
if (pdevSup)
|
||||
old_dsxt = pdevSup->pdsxt;
|
||||
devSup *old_devsup = dbDSETtoDevSup(precord->rdes, precord->dset);
|
||||
|
||||
if (old_devsup)
|
||||
old_dsxt = old_devsup->pdsxt;
|
||||
}
|
||||
|
||||
if (new_dsxt == NULL ||
|
||||
@@ -1047,30 +1109,17 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
}
|
||||
}
|
||||
|
||||
switch (plink->type) { /* Old link type */
|
||||
case DB_LINK:
|
||||
case CA_LINK:
|
||||
dbRemoveLink(plink);
|
||||
break;
|
||||
|
||||
case PV_LINK:
|
||||
case CONSTANT:
|
||||
break; /* do nothing */
|
||||
|
||||
case MACRO_LINK:
|
||||
break; /* should never get here */
|
||||
|
||||
default: /* Hardware address */
|
||||
if (!isDevLink) {
|
||||
status = S_db_badHWaddr;
|
||||
goto restoreScan;
|
||||
}
|
||||
break;
|
||||
if (dbLinkIsDefined(plink)) {
|
||||
dbRemoveLink(&locker, plink); /* Clear out old link */
|
||||
}
|
||||
else if (!isDevLink) {
|
||||
status = S_db_badHWaddr;
|
||||
goto restoreScan;
|
||||
}
|
||||
|
||||
if (special) status = dbPutSpecial(paddr, 0);
|
||||
|
||||
if (!status) status = dbPutString(&dbEntry, pstring);
|
||||
if (!status) status = dbSetLink(plink, &link_info, new_devsup);
|
||||
|
||||
if (!status && special) status = dbPutSpecial(paddr, 1);
|
||||
|
||||
@@ -1097,11 +1146,10 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
|
||||
switch (plink->type) { /* New link type */
|
||||
case PV_LINK:
|
||||
dbAddLink(precord, plink, pfldDes->field_type);
|
||||
break;
|
||||
|
||||
case CONSTANT:
|
||||
break; /* do nothing */
|
||||
case JSON_LINK:
|
||||
dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);
|
||||
break;
|
||||
|
||||
case DB_LINK:
|
||||
case CA_LINK:
|
||||
@@ -1127,9 +1175,10 @@ postScanEvent:
|
||||
if (scan != precord->scan)
|
||||
db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
|
||||
unlock:
|
||||
dbLockSetGblUnlock();
|
||||
finish:
|
||||
dbFinishEntry(&dbEntry);
|
||||
dbScanUnlockMany(&locker);
|
||||
dbLockerFinalize(&locker);
|
||||
cleanup:
|
||||
free(link_info.target);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1215,7 +1264,7 @@ 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);
|
||||
rset *prset = dbGetRset(paddr);
|
||||
long status = 0;
|
||||
long offset;
|
||||
dbFldDes *pfldDes;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "epicsTime.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAddr.h"
|
||||
#include "recSup.h"
|
||||
|
||||
#ifdef INCLdb_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
@@ -181,6 +182,7 @@ struct dbr_alDouble {DBRalDouble};
|
||||
#define S_db_badChoice (M_dbAccess|13) /*Illegal choice*/
|
||||
#define S_db_badField (M_dbAccess|15) /*Illegal field value*/
|
||||
#define S_db_lsetLogic (M_dbAccess|17) /*Logic error generating lock sets*/
|
||||
#define S_db_noLSET (M_dbAccess|21) /*No link support table or entry*/
|
||||
#define S_db_noRSET (M_dbAccess|31) /*missing record support entry table*/
|
||||
#define S_db_noSupport (M_dbAccess|33) /*RSET or DSXT routine not defined*/
|
||||
#define S_db_BadSub (M_dbAccess|35) /*Subroutine not found*/
|
||||
@@ -202,7 +204,7 @@ struct dbr_alDouble {DBRalDouble};
|
||||
#define S_db_bufFull (M_dbAccess|68) /*Buffer full*/
|
||||
|
||||
epicsShareFunc long dbPutSpecial(struct dbAddr *paddr,int pass);
|
||||
epicsShareFunc struct rset * dbGetRset(const struct dbAddr *paddr);
|
||||
epicsShareFunc rset * dbGetRset(const struct dbAddr *paddr);
|
||||
epicsShareFunc long dbPutAttribute(
|
||||
const char *recordTypename,const char *name,const char*value);
|
||||
epicsShareFunc int dbIsValueField(const struct dbFldDes *pdbFldDes);
|
||||
|
||||
@@ -26,12 +26,13 @@
|
||||
|
||||
#include "stdlib.h"
|
||||
|
||||
#include <memory> // std::auto_ptr
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "resourceLib.h"
|
||||
#include "cacIO.h"
|
||||
#include "compilerDependencies.h"
|
||||
#include "epicsMemory.h"
|
||||
|
||||
#ifdef dbCACh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
@@ -193,8 +194,9 @@ private:
|
||||
epicsMutex & mutex;
|
||||
epicsMutex & cbMutex;
|
||||
cacContextNotify & notify;
|
||||
epics_auto_ptr < cacContext > pNetContext;
|
||||
std::auto_ptr < cacContext > pNetContext;
|
||||
char * pStateNotifyCache;
|
||||
bool isolated;
|
||||
|
||||
cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > &,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Original Authors: Bob Dalesio and Marty Kraimer
|
||||
* Date: 26MAR96
|
||||
*/
|
||||
|
||||
#define EPICS_DBCA_PRIVATE_API
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "epicsPrint.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsAtomic.h"
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
#include "errMdef.h"
|
||||
@@ -44,13 +45,18 @@
|
||||
#include "dbCaPvt.h"
|
||||
#include "dbCommon.h"
|
||||
#include "db_convert.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbScan.h"
|
||||
#include "link.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
|
||||
/* defined in dbContext.cpp
|
||||
* Setup local CA access
|
||||
*/
|
||||
extern void dbServiceIOInit();
|
||||
|
||||
extern int dbServiceIsolate;
|
||||
|
||||
static ELLLIST workList = ELLLIST_INIT; /* Work list for dbCaTask */
|
||||
static epicsMutexId workListLock; /*Mutual exclusions semaphores for workList*/
|
||||
@@ -58,7 +64,7 @@ static epicsEventId workListEvent; /*wakeup event for dbCaTask*/
|
||||
static int removesOutstanding = 0;
|
||||
#define removesOutstandingWarning 10000
|
||||
|
||||
static volatile enum {
|
||||
static volatile enum dbCaCtl_t {
|
||||
ctlInit, ctlRun, ctlPause, ctlExit
|
||||
} dbCaCtl;
|
||||
static epicsEventId startStopEvent;
|
||||
@@ -68,57 +74,47 @@ struct ca_client_context * dbCaClientContext;
|
||||
/* Forward declarations */
|
||||
static void dbCaTask(void *);
|
||||
|
||||
static lset dbCa_lset;
|
||||
|
||||
#define printLinks(pcaLink) \
|
||||
errlogPrintf("%s has DB CA link to %s\n",\
|
||||
pcaLink->plink->value.pv_link.precord->name, pcaLink->pvname)
|
||||
pcaLink->plink->precord->name, pcaLink->pvname)
|
||||
|
||||
static int dbca_chan_count;
|
||||
|
||||
/* caLink locking
|
||||
*
|
||||
* workListLock
|
||||
* This is only used to put request into and take them out of workList.
|
||||
* While this is locked no other locks are taken
|
||||
* Lock ordering:
|
||||
* dbScanLock -> caLink.lock -> workListLock
|
||||
*
|
||||
* dbScanLock
|
||||
* dbCaAddLink and dbCaRemoveLink are only called by dbAccess or iocInit
|
||||
* They are only called by dbAccess when it has a global lock on lock set.
|
||||
* It is assumed that ALL other dbCaxxx calls are made only if dbScanLock
|
||||
* is already active. These routines are intended for use by record/device
|
||||
* support.
|
||||
* workListLock:
|
||||
* Guards access to workList.
|
||||
*
|
||||
* caLink.lock
|
||||
* Any code that use a caLink takes this lock and releases it when done
|
||||
* dbScanLock:
|
||||
* All dbCa* functions operating on a single link may only be called when
|
||||
* the record containing the DBLINK is locked. Including:
|
||||
* dbCaGet*()
|
||||
* isConnected()
|
||||
* dbCaPutLink()
|
||||
* scanForward()
|
||||
* dbCaAddLinkCallback()
|
||||
* dbCaRemoveLink()
|
||||
*
|
||||
* dbCaTask and the channel access callbacks NEVER access anything in the
|
||||
* records except after locking caLink.lock and checking that caLink.plink
|
||||
* is not null. They NEVER call dbScanLock.
|
||||
* Guard the pointer plink.value.pv_link.pvt, but not the struct caLink
|
||||
* which is pointed to.
|
||||
*
|
||||
* The above is necessary to prevent deadlocks and attempts to use a caLink
|
||||
* that has been deleted.
|
||||
* caLink.lock:
|
||||
* Guards the caLink structure (but not the struct DBLINK)
|
||||
*
|
||||
* Just a few words about handling dbCaRemoveLink because this is when
|
||||
* it is essential that nothing tries to use a caLink that has been freed.
|
||||
* The dbCaTask only locks caLink, and must not lock the record (a violation of lock order).
|
||||
*
|
||||
* dbCaRemoveLink is called when links are being modified. This is only
|
||||
* done with the dbScan mechanism guranteeing that nothing from
|
||||
* database access trys to access the record containing the caLink.
|
||||
* During link modification or IOC shutdown the pca->plink pointer (guarded by caLink.lock)
|
||||
* is used as a flag to indicate that a link is no longer active.
|
||||
*
|
||||
* Thus the problem is to make sure that nothing from channel access
|
||||
* accesses a caLink that is deleted. This is done as follows.
|
||||
* References to the struct caLink are owned by the dbCaTask, and any scanOnceCallback()
|
||||
* which is in progress.
|
||||
*
|
||||
* dbCaRemoveLink does the following:
|
||||
* epicsMutexMustLock(pca->lock);
|
||||
* pca->plink = 0;
|
||||
* plink->value.pv_link.pvt = 0;
|
||||
* epicsMutexUnlock(pca->lock);
|
||||
* addAction(pca,CA_CLEAR_CHANNEL);
|
||||
*
|
||||
* dbCaTask issues a ca_clear_channel and then frees the caLink.
|
||||
*
|
||||
* If any channel access callback gets called before the ca_clear_channel
|
||||
* it finds pca->plink==0 and does nothing. Once ca_clear_channel
|
||||
* is called no other callback for this caLink will be called.
|
||||
* The libca and scanOnceCallback callbacks take no action if pca->plink==NULL.
|
||||
*
|
||||
* dbCaPutLinkCallback causes an additional complication because
|
||||
* when dbCaRemoveLink is called the callback may not have occured.
|
||||
@@ -159,11 +155,23 @@ static void addAction(caLink *pca, short link_action)
|
||||
epicsEventSignal(workListEvent);
|
||||
}
|
||||
|
||||
static void dbCaLinkFree(caLink *pca)
|
||||
static void caLinkInc(caLink *pca)
|
||||
{
|
||||
assert(epicsAtomicGetIntT(&pca->refcount)>0);
|
||||
epicsAtomicIncrIntT(&pca->refcount);
|
||||
}
|
||||
|
||||
static void caLinkDec(caLink *pca)
|
||||
{
|
||||
int cnt;
|
||||
dbCaCallback callback;
|
||||
void *userPvt = 0;
|
||||
|
||||
cnt = epicsAtomicDecrIntT(&pca->refcount);
|
||||
assert(cnt>=0);
|
||||
if(cnt>0)
|
||||
return;
|
||||
|
||||
if (pca->chid) {
|
||||
ca_clear_channel(pca->chid);
|
||||
--dbca_chan_count;
|
||||
@@ -184,52 +192,86 @@ static void dbCaLinkFree(caLink *pca)
|
||||
if (callback) callback(userPvt);
|
||||
}
|
||||
|
||||
/* Block until worker thread has processed all previously queued actions.
|
||||
* Does not prevent additional actions from being queued.
|
||||
*/
|
||||
void dbCaSync(void)
|
||||
{
|
||||
epicsEventId wake;
|
||||
caLink templink;
|
||||
|
||||
/* we only partially initialize templink.
|
||||
* It has no link field and no subscription
|
||||
* so the worker must handle it early
|
||||
*/
|
||||
memset(&templink, 0, sizeof(templink));
|
||||
templink.refcount = 1;
|
||||
|
||||
wake = epicsEventMustCreate(epicsEventEmpty);
|
||||
templink.lock = epicsMutexMustCreate();
|
||||
|
||||
templink.userPvt = wake;
|
||||
|
||||
addAction(&templink, CA_SYNC);
|
||||
|
||||
epicsEventMustWait(wake);
|
||||
/* Worker holds workListLock when calling epicsEventMustTrigger()
|
||||
* we cycle through workListLock to ensure worker call to
|
||||
* epicsEventMustTrigger() returns before we destroy the event.
|
||||
*/
|
||||
epicsMutexMustLock(workListLock);
|
||||
epicsMutexUnlock(workListLock);
|
||||
|
||||
assert(templink.refcount==1);
|
||||
|
||||
epicsMutexDestroy(templink.lock);
|
||||
epicsEventDestroy(wake);
|
||||
}
|
||||
|
||||
epicsShareFunc unsigned long dbCaGetUpdateCount(struct link *plink)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
unsigned long ret;
|
||||
|
||||
if (!pca) return (unsigned long)-1;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
ret = pca->nUpdate;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dbCaCallbackProcess(void *userPvt)
|
||||
{
|
||||
struct link *plink = (struct link *)userPvt;
|
||||
dbCommon *pdbCommon = plink->value.pv_link.precord;
|
||||
|
||||
dbScanLock(pdbCommon);
|
||||
pdbCommon->rset->process(pdbCommon);
|
||||
dbScanUnlock(pdbCommon);
|
||||
dbLinkAsyncComplete(plink);
|
||||
}
|
||||
|
||||
void dbCaShutdown(void)
|
||||
{
|
||||
if (dbCaCtl == ctlRun || dbCaCtl == ctlPause) {
|
||||
dbCaCtl = ctlExit;
|
||||
epicsEventSignal(workListEvent);
|
||||
epicsEventMustWait(startStopEvent);
|
||||
epicsEventDestroy(startStopEvent);
|
||||
} else {
|
||||
/* manually cleanup queue since dbCa thread isn't running
|
||||
* which only happens in unit tests
|
||||
*/
|
||||
caLink *pca;
|
||||
epicsMutexMustLock(workListLock);
|
||||
while((pca=(caLink*)ellGet(&workList))!=NULL) {
|
||||
if(pca->link_action&CA_CLEAR_CHANNEL) {
|
||||
dbCaLinkFree(pca);
|
||||
}
|
||||
}
|
||||
epicsMutexUnlock(workListLock);
|
||||
}
|
||||
enum dbCaCtl_t cur = dbCaCtl;
|
||||
assert(cur == ctlRun || cur == ctlPause);
|
||||
dbCaCtl = ctlExit;
|
||||
epicsEventSignal(workListEvent);
|
||||
epicsEventMustWait(startStopEvent);
|
||||
}
|
||||
|
||||
void dbCaLinkInitIsolated(void)
|
||||
static void dbCaLinkInitImpl(int isolate)
|
||||
{
|
||||
dbServiceIsolate = isolate;
|
||||
dbServiceIOInit();
|
||||
|
||||
if (!workListLock)
|
||||
workListLock = epicsMutexMustCreate();
|
||||
if (!workListEvent)
|
||||
workListEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
dbCaCtl = ctlExit;
|
||||
}
|
||||
|
||||
void dbCaLinkInit(void)
|
||||
{
|
||||
dbServiceIOInit();
|
||||
dbCaLinkInitIsolated();
|
||||
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
if(!startStopEvent)
|
||||
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
dbCaCtl = ctlPause;
|
||||
|
||||
epicsThreadCreate("dbCaLink", epicsThreadPriorityMedium,
|
||||
@@ -238,6 +280,16 @@ void dbCaLinkInit(void)
|
||||
epicsEventMustWait(startStopEvent);
|
||||
}
|
||||
|
||||
void dbCaLinkInitIsolated(void)
|
||||
{
|
||||
dbCaLinkInitImpl(1);
|
||||
}
|
||||
|
||||
void dbCaLinkInit(void)
|
||||
{
|
||||
dbCaLinkInitImpl(0);
|
||||
}
|
||||
|
||||
void dbCaRun(void)
|
||||
{
|
||||
if (dbCaCtl == ctlPause) {
|
||||
@@ -262,6 +314,7 @@ void dbCaAddLinkCallback(struct link *plink,
|
||||
assert(!plink->value.pv_link.pvt);
|
||||
|
||||
pca = (caLink *)dbCalloc(1, sizeof(caLink));
|
||||
pca->refcount = 1;
|
||||
pca->lock = epicsMutexMustCreate();
|
||||
pca->plink = plink;
|
||||
pca->pvname = epicsStrDup(plink->value.pv_link.pvname);
|
||||
@@ -270,13 +323,20 @@ void dbCaAddLinkCallback(struct link *plink,
|
||||
pca->userPvt = userPvt;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
plink->lset = &dbCa_lset;
|
||||
plink->type = CA_LINK;
|
||||
plink->value.pv_link.pvt = pca;
|
||||
addAction(pca, CA_CONNECT);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
}
|
||||
|
||||
void dbCaRemoveLink(struct link *plink)
|
||||
long dbCaAddLink(struct dbLocker *locker, struct link *plink, short dbfType)
|
||||
{
|
||||
dbCaAddLinkCallback(plink, 0, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbCaRemoveLink(struct dbLocker *locker, struct link *plink)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
|
||||
@@ -284,13 +344,16 @@ void dbCaRemoveLink(struct link *plink)
|
||||
epicsMutexMustLock(pca->lock);
|
||||
pca->plink = 0;
|
||||
plink->value.pv_link.pvt = 0;
|
||||
plink->value.pv_link.pvlMask = 0;
|
||||
plink->type = PV_LINK;
|
||||
plink->lset = NULL;
|
||||
/* Unlock before addAction or dbCaTask might free first */
|
||||
epicsMutexUnlock(pca->lock);
|
||||
addAction(pca, CA_CLEAR_CHANNEL);
|
||||
}
|
||||
|
||||
long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *nelements)
|
||||
long dbCaGetLink(struct link *plink, short dbrType, void *pdest,
|
||||
long *nelements)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
long status = 0;
|
||||
@@ -343,15 +406,15 @@ long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
|
||||
assert(pca->pgetNative);
|
||||
status = fConvert(pca->pgetNative, pdest, 0);
|
||||
} else {
|
||||
long ntoget = *nelements;
|
||||
unsigned long ntoget = *nelements;
|
||||
struct dbAddr dbAddr;
|
||||
long (*aConvert)(struct dbAddr *paddr, void *to, long nreq, long nto, long off);
|
||||
|
||||
aConvert = dbGetConvertRoutine[newType][dbrType];
|
||||
assert(pca->pgetNative);
|
||||
|
||||
if (ntoget > pca->nelements)
|
||||
ntoget = pca->nelements;
|
||||
if (ntoget > pca->usedelements)
|
||||
ntoget = pca->usedelements;
|
||||
*nelements = ntoget;
|
||||
|
||||
memset((void *)&dbAddr, 0, sizeof(dbAddr));
|
||||
@@ -362,13 +425,23 @@ long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
|
||||
aConvert(&dbAddr, pdest, ntoget, ntoget, 0);
|
||||
}
|
||||
done:
|
||||
if (pstat) *pstat = pca->stat;
|
||||
if (psevr) *psevr = pca->sevr;
|
||||
if (link_action) addAction(pca, link_action);
|
||||
if (link_action)
|
||||
addAction(pca, link_action);
|
||||
if (!status)
|
||||
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
|
||||
plink->precord, pca->stat, pca->sevr);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static long dbCaPutAsync(struct link *plink,short dbrType,
|
||||
const void *pbuffer,long nRequest)
|
||||
{
|
||||
return dbCaPutLinkCallback(plink, dbrType, pbuffer, nRequest,
|
||||
dbCaCallbackProcess, plink);
|
||||
}
|
||||
|
||||
long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
const void *pbuffer,long nRequest,dbCaCallback callback,void *userPvt)
|
||||
{
|
||||
@@ -406,6 +479,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
if (!pca->pputNative) {
|
||||
pca->pputNative = dbCalloc(pca->nelements,
|
||||
dbr_value_size[ca_field_type(pca->chid)]);
|
||||
pca->putnelements = 0;
|
||||
/* Fixed and disabled by ANJ, see comment above.
|
||||
plink->value.pv_link.pvlMask |= pvlOptOutNative;
|
||||
*/
|
||||
@@ -415,6 +489,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
|
||||
fConvert = dbFastPutConvertRoutine[dbrType][newType];
|
||||
status = fConvert(pbuffer, pca->pputNative, 0);
|
||||
pca->putnelements = 1;
|
||||
} else {
|
||||
struct dbAddr dbAddr;
|
||||
long (*aConvert)(struct dbAddr *paddr, const void *from, long nreq, long nfrom, long off);
|
||||
@@ -427,10 +502,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
if(nRequest>pca->nelements)
|
||||
nRequest = pca->nelements;
|
||||
status = aConvert(&dbAddr, pbuffer, nRequest, pca->nelements, 0);
|
||||
if(nRequest<pca->nelements) {
|
||||
long elemsize = dbr_value_size[ca_field_type(pca->chid)];
|
||||
memset(nRequest*elemsize+(char*)pca->pputNative, 0, (pca->nelements-nRequest)*elemsize);
|
||||
}
|
||||
pca->putnelements = nRequest;
|
||||
}
|
||||
link_action |= CA_WRITE_NATIVE;
|
||||
pca->gotOutNative = TRUE;
|
||||
@@ -450,7 +522,13 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
return status;
|
||||
}
|
||||
|
||||
int dbCaIsLinkConnected(const struct link *plink)
|
||||
long dbCaPutLink(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest)
|
||||
{
|
||||
return dbCaPutLinkCallback(plink, dbrType, pbuffer, nRequest, 0, NULL);
|
||||
}
|
||||
|
||||
static int isConnected(const struct link *plink)
|
||||
{
|
||||
caLink *pca;
|
||||
|
||||
@@ -460,7 +538,7 @@ int dbCaIsLinkConnected(const struct link *plink)
|
||||
return pca->isConnected;
|
||||
}
|
||||
|
||||
void dbCaScanFwdLink(struct link *plink) {
|
||||
static void scanForward(struct link *plink) {
|
||||
short fwdLinkValue = 1;
|
||||
|
||||
if (plink->value.pv_link.pvlMask & pvlOptFWD)
|
||||
@@ -479,7 +557,7 @@ void dbCaScanFwdLink(struct link *plink) {
|
||||
return -1; \
|
||||
}
|
||||
|
||||
long dbCaGetNelements(const struct link *plink, long *nelements)
|
||||
static long getElements(const struct link *plink, long *nelements)
|
||||
{
|
||||
caLink *pca;
|
||||
|
||||
@@ -489,7 +567,7 @@ long dbCaGetNelements(const struct link *plink, long *nelements)
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dbCaGetAlarm(const struct link *plink,
|
||||
static long getAlarm(const struct link *plink,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -501,7 +579,7 @@ long dbCaGetAlarm(const struct link *plink,
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dbCaGetTimeStamp(const struct link *plink,
|
||||
static long getTimeStamp(const struct link *plink,
|
||||
epicsTimeStamp *pstamp)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -512,7 +590,7 @@ long dbCaGetTimeStamp(const struct link *plink,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbCaGetLinkDBFtype(const struct link *plink)
|
||||
static int getDBFtype(const struct link *plink)
|
||||
{
|
||||
caLink *pca;
|
||||
int type;
|
||||
@@ -543,7 +621,7 @@ long dbCaGetAttributes(const struct link *plink,
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dbCaGetControlLimits(const struct link *plink,
|
||||
static long getControlLimits(const struct link *plink,
|
||||
double *low, double *high)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -559,7 +637,7 @@ long dbCaGetControlLimits(const struct link *plink,
|
||||
return gotAttributes ? 0 : -1;
|
||||
}
|
||||
|
||||
long dbCaGetGraphicLimits(const struct link *plink,
|
||||
static long getGraphicLimits(const struct link *plink,
|
||||
double *low, double *high)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -575,7 +653,7 @@ long dbCaGetGraphicLimits(const struct link *plink,
|
||||
return gotAttributes ? 0 : -1;
|
||||
}
|
||||
|
||||
long dbCaGetAlarmLimits(const struct link *plink,
|
||||
static long getAlarmLimits(const struct link *plink,
|
||||
double *lolo, double *low, double *high, double *hihi)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -593,7 +671,7 @@ long dbCaGetAlarmLimits(const struct link *plink,
|
||||
return gotAttributes ? 0 : -1;
|
||||
}
|
||||
|
||||
long dbCaGetPrecision(const struct link *plink, short *precision)
|
||||
static long getPrecision(const struct link *plink, short *precision)
|
||||
{
|
||||
caLink *pca;
|
||||
int gotAttributes;
|
||||
@@ -605,7 +683,7 @@ long dbCaGetPrecision(const struct link *plink, short *precision)
|
||||
return gotAttributes ? 0 : -1;
|
||||
}
|
||||
|
||||
long dbCaGetUnits(const struct link *plink,
|
||||
static long getUnits(const struct link *plink,
|
||||
char *units, int unitsSize)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -620,6 +698,63 @@ long dbCaGetUnits(const struct link *plink,
|
||||
return gotAttributes ? 0 : -1;
|
||||
}
|
||||
|
||||
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
|
||||
{
|
||||
caLink *pca;
|
||||
long status;
|
||||
|
||||
pcaGetCheck
|
||||
status = rtn(plink, priv);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void scanComplete(void *raw, dbCommon *prec)
|
||||
{
|
||||
caLink *pca = raw;
|
||||
epicsMutexMustLock(pca->lock);
|
||||
if(!pca->plink) {
|
||||
/* IOC shutdown or link re-targeted. Do nothing. */
|
||||
} else if(pca->scanningOnce==0) {
|
||||
errlogPrintf("dbCa.c complete callback w/ scanningOnce==0\n");
|
||||
} else if(--pca->scanningOnce){
|
||||
/* another scan is queued */
|
||||
if(scanOnceCallback(prec, scanComplete, raw)) {
|
||||
errlogPrintf("dbCa.c failed to re-queue scanOnce\n");
|
||||
} else
|
||||
caLinkInc(pca);
|
||||
}
|
||||
epicsMutexUnlock(pca->lock);
|
||||
caLinkDec(pca);
|
||||
}
|
||||
|
||||
/* must be called with pca->lock held */
|
||||
static void scanLinkOnce(dbCommon *prec, caLink *pca) {
|
||||
if(pca->scanningOnce==0) {
|
||||
if(scanOnceCallback(prec, scanComplete, pca)) {
|
||||
errlogPrintf("dbCa.c failed to queue scanOnce\n");
|
||||
} else
|
||||
caLinkInc(pca);
|
||||
}
|
||||
if(pca->scanningOnce<5)
|
||||
pca->scanningOnce++;
|
||||
/* else too many scans queued */
|
||||
}
|
||||
|
||||
static lset dbCa_lset = {
|
||||
0, 1, /* not Constant, Volatile */
|
||||
NULL, dbCaRemoveLink,
|
||||
NULL, NULL, NULL,
|
||||
isConnected,
|
||||
getDBFtype, getElements,
|
||||
dbCaGetLink,
|
||||
getControlLimits, getGraphicLimits, getAlarmLimits,
|
||||
getPrecision, getUnits,
|
||||
getAlarm, getTimeStamp,
|
||||
dbCaPutLink, dbCaPutAsync,
|
||||
scanForward, doLocked
|
||||
};
|
||||
|
||||
static void connectionCallback(struct connection_handler_args arg)
|
||||
{
|
||||
caLink *pca;
|
||||
@@ -634,13 +769,13 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
pca->isConnected = (ca_state(arg.chid) == cs_conn);
|
||||
if (!pca->isConnected) {
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
dbCommon *precord = ppv_link->precord;
|
||||
dbCommon *precord = plink->precord;
|
||||
|
||||
pca->nDisconnect++;
|
||||
if (precord &&
|
||||
((ppv_link->pvlMask & pvlOptCP) ||
|
||||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
|
||||
scanOnce(precord);
|
||||
scanLinkOnce(precord, pca);
|
||||
goto done;
|
||||
}
|
||||
pca->hasReadAccess = ca_read_access(arg.chid);
|
||||
@@ -670,6 +805,7 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
}
|
||||
pca->gotFirstConnection = TRUE;
|
||||
pca->nelements = ca_element_count(arg.chid);
|
||||
pca->usedelements = 0;
|
||||
pca->dbrType = ca_field_type(arg.chid);
|
||||
if ((plink->value.pv_link.pvlMask & pvlOptInpNative) && !pca->pgetNative) {
|
||||
link_action |= CA_MONITOR_NATIVE;
|
||||
@@ -706,9 +842,10 @@ static void eventCallback(struct event_handler_args arg)
|
||||
epicsMutexMustLock(pca->lock);
|
||||
plink = pca->plink;
|
||||
if (!plink) goto done;
|
||||
pca->nUpdate++;
|
||||
monitor = pca->monitor;
|
||||
userPvt = pca->userPvt;
|
||||
precord = plink->value.pv_link.precord;
|
||||
precord = plink->precord;
|
||||
if (arg.status != ECA_NORMAL) {
|
||||
if (precord) {
|
||||
if (arg.status != ECA_NORDACCESS &&
|
||||
@@ -722,6 +859,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
goto done;
|
||||
}
|
||||
assert(arg.dbr);
|
||||
assert(arg.count<=pca->nelements);
|
||||
size = arg.count * dbr_value_size[arg.type];
|
||||
if (arg.type == DBR_TIME_STRING &&
|
||||
ca_field_type(pca->chid) == DBR_ENUM) {
|
||||
@@ -738,10 +876,12 @@ static void eventCallback(struct event_handler_args arg)
|
||||
case DBR_TIME_DOUBLE:
|
||||
assert(pca->pgetNative);
|
||||
memcpy(pca->pgetNative, dbr_value_ptr(arg.dbr, arg.type), size);
|
||||
pca->usedelements = arg.count;
|
||||
pca->gotInNative = TRUE;
|
||||
break;
|
||||
default:
|
||||
errMessage(-1, "dbCa: eventCallback Logic Error\n");
|
||||
errlogPrintf("dbCa: eventCallback Logic Error. dbr=%ld dbf=%d\n",
|
||||
arg.type, ca_field_type(pca->chid));
|
||||
break;
|
||||
}
|
||||
pdbr_time_double = (struct dbr_time_double *)arg.dbr;
|
||||
@@ -753,7 +893,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
|
||||
if ((ppv_link->pvlMask & pvlOptCP) ||
|
||||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0))
|
||||
scanOnce(precord);
|
||||
scanLinkOnce(precord, pca);
|
||||
}
|
||||
done:
|
||||
epicsMutexUnlock(pca->lock);
|
||||
@@ -822,11 +962,11 @@ static void accessRightsCallback(struct access_rights_handler_args arg)
|
||||
pca->hasWriteAccess = ca_write_access(arg.chid);
|
||||
if (pca->hasReadAccess && pca->hasWriteAccess) goto done;
|
||||
ppv_link = &plink->value.pv_link;
|
||||
precord = ppv_link->precord;
|
||||
precord = plink->precord;
|
||||
if (precord &&
|
||||
((ppv_link->pvlMask & pvlOptCP) ||
|
||||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
|
||||
scanOnce(precord);
|
||||
scanLinkOnce(precord, pca);
|
||||
done:
|
||||
epicsMutexUnlock(pca->lock);
|
||||
}
|
||||
@@ -853,7 +993,7 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
getAttributes = pca->getAttributes;
|
||||
getAttributesPvt = pca->getAttributesPvt;
|
||||
if (arg.status != ECA_NORMAL) {
|
||||
dbCommon *precord = plink->value.pv_link.precord;
|
||||
dbCommon *precord = plink->precord;
|
||||
if (precord) {
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s error %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
@@ -909,11 +1049,15 @@ static void dbCaTask(void *arg)
|
||||
break; /* workList is empty */
|
||||
}
|
||||
link_action = pca->link_action;
|
||||
if (link_action&CA_SYNC)
|
||||
epicsEventMustTrigger((epicsEventId)pca->userPvt); /* dbCaSync() requires workListLock to be held here */
|
||||
pca->link_action = 0;
|
||||
if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
|
||||
epicsMutexUnlock(workListLock); /* Give back immediately */
|
||||
if (link_action&CA_SYNC)
|
||||
continue;
|
||||
if (link_action & CA_CLEAR_CHANNEL) { /* This must be first */
|
||||
dbCaLinkFree(pca);
|
||||
caLinkDec(pca);
|
||||
/* No alarm is raised. Since link is changing so what? */
|
||||
continue; /* No other link_action makes sense */
|
||||
}
|
||||
@@ -942,11 +1086,11 @@ static void dbCaTask(void *arg)
|
||||
assert(pca->pputNative);
|
||||
if (pca->putType == CA_PUT) {
|
||||
status = ca_array_put(
|
||||
pca->dbrType, pca->nelements,
|
||||
pca->dbrType, pca->putnelements,
|
||||
pca->chid, pca->pputNative);
|
||||
} else if (pca->putType==CA_PUT_CALLBACK) {
|
||||
status = ca_array_put_callback(
|
||||
pca->dbrType, pca->nelements,
|
||||
pca->dbrType, pca->putnelements,
|
||||
pca->chid, pca->pputNative,
|
||||
putComplete, pca);
|
||||
} else {
|
||||
@@ -996,15 +1140,15 @@ static void dbCaTask(void *arg)
|
||||
}
|
||||
}
|
||||
if (link_action & CA_MONITOR_NATIVE) {
|
||||
size_t element_size;
|
||||
|
||||
element_size = dbr_value_size[ca_field_type(pca->chid)];
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
pca->pgetNative = dbCalloc(pca->nelements, element_size);
|
||||
pca->elementSize = dbr_value_size[ca_field_type(pca->chid)];
|
||||
pca->pgetNative = dbCalloc(pca->nelements, pca->elementSize);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
status = ca_add_array_event(
|
||||
ca_field_type(pca->chid)+DBR_TIME_STRING,
|
||||
ca_element_count(pca->chid),
|
||||
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
|
||||
0, /* dynamic size */
|
||||
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
|
||||
if (status != ECA_NORMAL) {
|
||||
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2015 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.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbCa.h */
|
||||
/* dbCa.h */
|
||||
|
||||
#ifndef INCdbCah
|
||||
#define INCdbCah
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "epicsTime.h"
|
||||
#include "link.h"
|
||||
#include "dbLink.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -29,48 +26,60 @@ epicsShareFunc void dbCaRun(void);
|
||||
epicsShareFunc void dbCaPause(void);
|
||||
epicsShareFunc void dbCaShutdown(void);
|
||||
|
||||
struct dbLocker;
|
||||
epicsShareFunc void dbCaAddLinkCallback(struct link *plink,
|
||||
dbCaCallback connect, dbCaCallback monitor, void *userPvt);
|
||||
#define dbCaAddLink(plink) dbCaAddLinkCallback((plink), 0, 0, 0)
|
||||
epicsShareFunc void dbCaRemoveLink(struct link *plink);
|
||||
epicsShareFunc long dbCaAddLink(struct dbLocker *locker, struct link *plink, short dbfType);
|
||||
epicsShareFunc void dbCaRemoveLink(struct dbLocker *locker, struct link *plink);
|
||||
|
||||
epicsShareFunc long dbCaGetLink(struct link *plink,
|
||||
short dbrType, void *pbuffer, epicsEnum16 *pstat, epicsEnum16 *psevr,
|
||||
long *nRequest);
|
||||
short dbrType, void *pbuffer, long *nRequest);
|
||||
|
||||
epicsShareFunc long dbCaGetAttributes(const struct link *plink,
|
||||
dbCaCallback callback, void *userPvt);
|
||||
|
||||
epicsShareFunc long dbCaPutLinkCallback(struct link *plink,
|
||||
short dbrType, const void *pbuffer,long nRequest,
|
||||
dbCaCallback callback, void *userPvt);
|
||||
#define dbCaPutLink(plink, dbrType, pbuffer, nRequest) \
|
||||
dbCaPutLinkCallback((plink), (dbrType), (pbuffer), (nRequest), 0, 0)
|
||||
epicsShareFunc int dbCaIsLinkConnected(const struct link *plink);
|
||||
epicsShareFunc void dbCaScanFwdLink(struct link *plink);
|
||||
|
||||
/* The following are available after the link is connected*/
|
||||
epicsShareFunc long dbCaGetNelements(const struct link *plink,
|
||||
long *nelements);
|
||||
#define dbCaGetSevr(plink, severity) \
|
||||
dbCaGetAlarm((plink), NULL, (severity))
|
||||
epicsShareFunc long dbCaGetAlarm(const struct link *plink,
|
||||
epicsEnum16 *status, epicsEnum16 *severity);
|
||||
epicsShareFunc long dbCaGetTimeStamp(const struct link *plink,
|
||||
epicsTimeStamp *pstamp);
|
||||
epicsShareFunc int dbCaGetLinkDBFtype(const struct link *plink);
|
||||
|
||||
/*The following are available after attribute request is complete*/
|
||||
epicsShareFunc long dbCaGetAttributes(const struct link *plink,
|
||||
dbCaCallback callback, void *userPvt);
|
||||
epicsShareFunc long dbCaGetControlLimits(const struct link *plink,
|
||||
double *low, double *high);
|
||||
epicsShareFunc long dbCaGetGraphicLimits(const struct link *plink,
|
||||
double *low, double *high);
|
||||
epicsShareFunc long dbCaGetAlarmLimits(const struct link *plink,
|
||||
double *lolo, double *low, double *high, double *hihi);
|
||||
epicsShareFunc long dbCaGetPrecision(const struct link *plink,
|
||||
short *precision);
|
||||
epicsShareFunc long dbCaGetUnits(const struct link *plink,
|
||||
char *units, int unitsSize);
|
||||
epicsShareFunc long dbCaPutLink(struct link *plink,short dbrType,
|
||||
const void *pbuffer,long nRequest);
|
||||
|
||||
extern struct ca_client_context * dbCaClientContext;
|
||||
|
||||
#ifdef EPICS_DBCA_PRIVATE_API
|
||||
epicsShareFunc void dbCaSync(void);
|
||||
epicsShareFunc unsigned long dbCaGetUpdateCount(struct link *plink);
|
||||
#endif
|
||||
|
||||
/* These macros are for backwards compatibility */
|
||||
|
||||
#define dbCaIsLinkConnected(link) \
|
||||
dbIsLinkConnected(link)
|
||||
|
||||
#define dbCaGetLinkDBFtype(link) \
|
||||
dbGetLinkDBFtype(link)
|
||||
#define dbCaGetNelements(link, nelements) \
|
||||
dbGetNelements(link, nelements)
|
||||
#define dbCaGetSevr(link, sevr) \
|
||||
dbGetAlarm(link, NULL, sevr)
|
||||
#define dbCaGetAlarm(link, stat, sevr) \
|
||||
dbGetAlarm(link, stat, sevr)
|
||||
#define dbCaGetTimeStamp(link, pstamp) \
|
||||
dbGetTimeStamp(link, pstamp)
|
||||
#define dbCaGetControlLimits(link, low, high) \
|
||||
dbGetControlLimits(link, low, high)
|
||||
#define dbCaGetGraphicLimits(link, low, high) \
|
||||
dbGetGraphicLimits(link, low, high)
|
||||
#define dbCaGetAlarmLimits(link, lolo, low, high, hihi) \
|
||||
dbGetAlarmLimits(link, lolo, low, high, hihi)
|
||||
#define dbCaGetPrecision(link, prec) \
|
||||
dbGetPrecision(link, prec)
|
||||
#define dbCaGetUnits(link, units, unitSize) \
|
||||
dbGetUnits(link, units, unitSize)
|
||||
|
||||
#define dbCaScanFwdLink(link) \
|
||||
dbScanFwdLink(link)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,14 +6,11 @@
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbCaPvt.h */
|
||||
/****************************************************************
|
||||
*
|
||||
* Current Author: Bob Dalesio
|
||||
* Contributing Author: Marty Kraimer
|
||||
* Date: 08APR96
|
||||
*
|
||||
****************************************************************/
|
||||
/* dbCaPvt.h
|
||||
*
|
||||
* Original Authors: Bob Dalesio, Marty Kraimer
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INC_dbCaPvt_H
|
||||
#define INC_dbCaPvt_H
|
||||
@@ -32,61 +29,68 @@
|
||||
#define CA_MONITOR_NATIVE 0x10
|
||||
#define CA_MONITOR_STRING 0x20
|
||||
#define CA_GET_ATTRIBUTES 0x40
|
||||
#define CA_SYNC 0x1000
|
||||
/* write type */
|
||||
#define CA_PUT 0x1
|
||||
#define CA_PUT_CALLBACK 0x2
|
||||
|
||||
|
||||
typedef struct caLink
|
||||
{
|
||||
ELLNODE node;
|
||||
epicsMutexId lock;
|
||||
struct link *plink;
|
||||
char *pvname;
|
||||
chid chid;
|
||||
short link_action;
|
||||
/* The following have new values after each data event*/
|
||||
epicsEnum16 sevr;
|
||||
epicsEnum16 stat;
|
||||
epicsTimeStamp timeStamp;
|
||||
/* The following have values after connection*/
|
||||
short dbrType;
|
||||
long nelements;
|
||||
char hasReadAccess;
|
||||
char hasWriteAccess;
|
||||
char isConnected;
|
||||
char gotFirstConnection;
|
||||
/* The following are for dbCaAddLinkCallback */
|
||||
dbCaCallback connect;
|
||||
dbCaCallback monitor;
|
||||
void *userPvt;
|
||||
/* The following are for write request */
|
||||
short putType;
|
||||
dbCaCallback putCallback;
|
||||
void *putUserPvt;
|
||||
/* The following are for access to additional attributes*/
|
||||
char gotAttributes;
|
||||
dbCaCallback getAttributes;
|
||||
void *getAttributesPvt;
|
||||
/* The following have values after getAttribEventCallback*/
|
||||
double controlLimits[2];
|
||||
double displayLimits[2];
|
||||
double alarmLimits[4];
|
||||
short precision;
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
/* The following are for handling data*/
|
||||
void *pgetNative;
|
||||
char *pgetString;
|
||||
void *pputNative;
|
||||
char *pputString;
|
||||
char gotInNative;
|
||||
char gotInString;
|
||||
char gotOutNative;
|
||||
char gotOutString;
|
||||
char newOutNative;
|
||||
char newOutString;
|
||||
/* The following are for dbcar*/
|
||||
unsigned long nDisconnect;
|
||||
unsigned long nNoWrite; /*only modified by dbCaPutLink*/
|
||||
ELLNODE node;
|
||||
int refcount;
|
||||
epicsMutexId lock;
|
||||
struct link *plink;
|
||||
char *pvname;
|
||||
chid chid;
|
||||
short link_action;
|
||||
/* The following have new values after each data event*/
|
||||
epicsEnum16 sevr;
|
||||
epicsEnum16 stat;
|
||||
epicsTimeStamp timeStamp;
|
||||
/* The following have values after connection*/
|
||||
short dbrType;
|
||||
size_t elementSize; /* size of one element in pgetNative */
|
||||
unsigned long nelements; /* PVs max array size */
|
||||
unsigned long usedelements; /* currently used in pgetNative */
|
||||
unsigned long putnelements; /* currently used in pputNative */
|
||||
char hasReadAccess;
|
||||
char hasWriteAccess;
|
||||
char isConnected;
|
||||
char gotFirstConnection;
|
||||
/* The following are for dbCaAddLinkCallback */
|
||||
dbCaCallback connect;
|
||||
dbCaCallback monitor;
|
||||
void *userPvt;
|
||||
/* The following are for write request */
|
||||
short putType;
|
||||
dbCaCallback putCallback;
|
||||
void *putUserPvt;
|
||||
/* The following are for access to additional attributes*/
|
||||
char gotAttributes;
|
||||
dbCaCallback getAttributes;
|
||||
void *getAttributesPvt;
|
||||
/* The following have values after getAttribEventCallback*/
|
||||
double controlLimits[2];
|
||||
double displayLimits[2];
|
||||
double alarmLimits[4];
|
||||
short precision;
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
/* The following are for handling data*/
|
||||
void *pgetNative;
|
||||
char *pgetString;
|
||||
void *pputNative;
|
||||
char *pputString;
|
||||
char gotInNative;
|
||||
char gotInString;
|
||||
char gotOutNative;
|
||||
char gotOutString;
|
||||
char newOutNative;
|
||||
char newOutString;
|
||||
unsigned char scanningOnce;
|
||||
/* The following are for dbcar*/
|
||||
unsigned long nDisconnect;
|
||||
unsigned long nNoWrite; /*only modified by dbCaPutLink*/
|
||||
unsigned long nUpdate;
|
||||
}caLink;
|
||||
|
||||
#endif /* INC_dbCaPvt_H */
|
||||
|
||||
@@ -87,10 +87,10 @@ long dbcar(char *precordname, int level)
|
||||
!dbIsAlias(pdbentry)) {
|
||||
pdbRecordType = pdbentry->precordType;
|
||||
precord = (dbCommon *)pdbentry->precnode->precord;
|
||||
dbScanLock(precord);
|
||||
for (j=0; j<pdbRecordType->no_links; j++) {
|
||||
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
|
||||
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
|
||||
dbLockSetGblLock();
|
||||
if (plink->type == CA_LINK) {
|
||||
ncalinks++;
|
||||
pca = (caLink *)plink->value.pv_link.pvt;
|
||||
@@ -135,8 +135,8 @@ long dbcar(char *precordname, int level)
|
||||
}
|
||||
}
|
||||
}
|
||||
dbLockSetGblUnlock();
|
||||
}
|
||||
dbScanUnlock(precord);
|
||||
if (precordname) goto done;
|
||||
}
|
||||
status = dbNextRecord(pdbentry);
|
||||
@@ -189,10 +189,8 @@ void dbcaStats(int *pchans, int *pdiscon)
|
||||
dbFldDes *pdbFldDes = pdbRecordType->papFldDes[i];
|
||||
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
|
||||
if (plink->type == CA_LINK) {
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
|
||||
ncalinks++;
|
||||
if (pca && pca->chid && ca_state(pca->chid) == cs_conn) {
|
||||
if (dbCaIsLinkConnected(plink)) {
|
||||
nconnected++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "cantProceed.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsString.h"
|
||||
#include "errlog.h"
|
||||
#include "freeList.h"
|
||||
@@ -455,6 +454,8 @@ static short mapDBFToDBR[DBF_NTYPES] =
|
||||
/* DBF_USHORT => */DBR_USHORT,
|
||||
/* DBF_LONG => */DBR_LONG,
|
||||
/* DBF_ULONG => */DBR_ULONG,
|
||||
/* DBF_INT64 => */DBR_INT64,
|
||||
/* DBF_UINT64 => */DBR_UINT64,
|
||||
/* DBF_FLOAT => */DBR_FLOAT,
|
||||
/* DBF_DOUBLE => */DBR_DOUBLE,
|
||||
/* DBF_ENUM, => */DBR_ENUM,
|
||||
@@ -510,7 +511,7 @@ dbChannel * dbChannelCreate(const char *name)
|
||||
paddr->dbr_field_type = mapDBFToDBR[dbfType];
|
||||
|
||||
if (paddr->special == SPC_DBADDR) {
|
||||
struct rset *prset = dbGetRset(paddr);
|
||||
rset *prset = dbGetRset(paddr);
|
||||
|
||||
/* Let record type modify paddr */
|
||||
if (prset && prset->cvt_dbaddr) {
|
||||
@@ -532,7 +533,7 @@ dbChannel * dbChannelCreate(const char *name)
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
|
||||
/* Clients see a char array, but keep original dbfType */
|
||||
paddr->no_elements = PVNAME_STRINGSZ + 12;
|
||||
paddr->no_elements = PVLINK_STRINGSZ;
|
||||
paddr->field_size = 1;
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#endif
|
||||
|
||||
#include "compilerDependencies.h"
|
||||
#include "epicsMemory.h"
|
||||
|
||||
#ifdef dbChannelIOh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
|
||||
118
src/ioc/db/dbChannelNOOP.h
Normal file
118
src/ioc/db/dbChannelNOOP.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef DBCHANNELNOOP_H
|
||||
#define DBCHANNELNOOP_H
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "cacIO.h"
|
||||
#include "caerr.h"
|
||||
|
||||
/** @brief A channel which never connects
|
||||
*
|
||||
* Used when dbCa is placed in isolated mode for unittests
|
||||
*/
|
||||
class dbChannelNOOP : public cacChannel
|
||||
{
|
||||
std::string myname;
|
||||
public:
|
||||
dbChannelNOOP(const char *name, cacChannelNotify ¬ify)
|
||||
:cacChannel(notify)
|
||||
,myname(name)
|
||||
{}
|
||||
|
||||
virtual void destroy (
|
||||
CallbackGuard & /*callbackGuard*/,
|
||||
epicsGuard < epicsMutex > & /*mutualExclusionGuard*/ )
|
||||
{
|
||||
delete this; // goodbye cruel world
|
||||
}
|
||||
|
||||
virtual unsigned getName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw ()
|
||||
{
|
||||
const char* name = myname.c_str();
|
||||
if(bufLen>myname.size()+1) {
|
||||
bufLen=myname.size()+1;
|
||||
}
|
||||
memcpy(pBuf, name, bufLen);
|
||||
pBuf[--bufLen] = '\0';
|
||||
return bufLen;
|
||||
}
|
||||
|
||||
// !! deprecated, avoid use !!
|
||||
virtual const char * pName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw ()
|
||||
{return myname.c_str();}
|
||||
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const
|
||||
{}
|
||||
|
||||
virtual void initiateConnect (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{}
|
||||
|
||||
virtual unsigned requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & /*mutualExclusionGuard*/ )
|
||||
{return 0;}
|
||||
|
||||
virtual void flush (
|
||||
epicsGuard < epicsMutex > & /*mutualExclusionGuard*/ )
|
||||
{}
|
||||
|
||||
virtual ioStatus read (
|
||||
epicsGuard < epicsMutex > &mut,
|
||||
unsigned type, arrayElementCount count,
|
||||
cacReadNotify ¬ify, ioid * = 0 )
|
||||
{
|
||||
notify.exception(mut, ECA_NORDACCESS, "dbChannelNOOP", type, count);
|
||||
return iosSynch;
|
||||
}
|
||||
|
||||
virtual void write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue )
|
||||
{}
|
||||
|
||||
virtual ioStatus write (
|
||||
epicsGuard < epicsMutex > &mut,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void */*pValue*/, cacWriteNotify & notify, ioid * = 0 )
|
||||
{
|
||||
notify.exception(mut, ECA_NOWTACCESS, "dbChannelNOOP", type, count);
|
||||
return iosSynch;
|
||||
}
|
||||
|
||||
virtual void subscribe (
|
||||
epicsGuard < epicsMutex > &mut, unsigned type,
|
||||
arrayElementCount count, unsigned /*mask*/, cacStateNotify & notify,
|
||||
ioid * = 0 )
|
||||
{
|
||||
// should never subscribe
|
||||
notify.exception(mut, ECA_BADMASK, "dbChannelNOOP", type, count);
|
||||
}
|
||||
|
||||
virtual void ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const ioid & )
|
||||
{}
|
||||
|
||||
virtual void ioShow (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const ioid &, unsigned level ) const
|
||||
{}
|
||||
|
||||
virtual short nativeType (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{return 0;} // DBR_STRING
|
||||
|
||||
virtual arrayElementCount nativeElementCount (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{return 1;}
|
||||
};
|
||||
|
||||
#endif // DBCHANNELNOOP_H
|
||||
@@ -92,6 +92,12 @@
|
||||
interest(4)
|
||||
extra("ELLLIST mlis")
|
||||
}
|
||||
field(BKLNK,DBF_NOACCESS) {
|
||||
prompt("Backwards link tracking")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("ELLLIST bklnk")
|
||||
}
|
||||
field(DISP,DBF_UCHAR) {
|
||||
prompt("Disable putField")
|
||||
}
|
||||
@@ -191,7 +197,7 @@
|
||||
prompt("Address of RSET")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("struct rset *rset")
|
||||
extra("struct typed_rset *rset")
|
||||
}
|
||||
field(DSET,DBF_NOACCESS) {
|
||||
prompt("DSET address")
|
||||
|
||||
14
src/ioc/db/dbCommonPvt.h
Normal file
14
src/ioc/db/dbCommonPvt.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef DBCOMMONPVT_H
|
||||
#define DBCOMMONPVT_H
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
/** Base internal additional information for every record
|
||||
*/
|
||||
typedef struct dbCommonPvt {
|
||||
struct dbRecordNode *recnode;
|
||||
|
||||
struct dbCommon common;
|
||||
} dbCommonPvt;
|
||||
|
||||
#endif // DBCOMMONPVT_H
|
||||
126
src/ioc/db/dbConstLink.c
Normal file
126
src/ioc/db/dbConstLink.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 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 is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbConstLink.c
|
||||
*
|
||||
* Original Authors: Bob Dalesio, Marty Kraimer
|
||||
* Current Author: Andrew Johnson
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbConstLink.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbConvertJSON.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbLink.h"
|
||||
#include "link.h"
|
||||
|
||||
/***************************** Constant Links *****************************/
|
||||
|
||||
/* Forward definition */
|
||||
static lset dbConst_lset;
|
||||
|
||||
void dbConstInitLink(struct link *plink)
|
||||
{
|
||||
plink->lset = &dbConst_lset;
|
||||
}
|
||||
|
||||
void dbConstAddLink(struct link *plink)
|
||||
{
|
||||
plink->lset = &dbConst_lset;
|
||||
}
|
||||
|
||||
/**************************** Member functions ****************************/
|
||||
|
||||
static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
|
||||
{
|
||||
const char *pstr = plink->value.constantStr;
|
||||
size_t len;
|
||||
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
len = strlen(pstr);
|
||||
|
||||
/* Choice values must be numeric */
|
||||
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
if (*pstr == '[' && pstr[len-1] == ']') {
|
||||
/* Convert from JSON array */
|
||||
long nReq = 1;
|
||||
|
||||
return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq);
|
||||
}
|
||||
|
||||
return dbFastPutConvertRoutine[DBR_STRING][dbrType]
|
||||
(pstr, pbuffer, NULL);
|
||||
}
|
||||
|
||||
static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
const char *pstr = plink->value.constantStr;
|
||||
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
|
||||
return dbLSConvertJSON(pstr, pbuffer, size, plen);
|
||||
}
|
||||
|
||||
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnReq)
|
||||
{
|
||||
const char *pstr = plink->value.constantStr;
|
||||
|
||||
if (!pstr)
|
||||
return S_db_badField;
|
||||
|
||||
/* Choice values must be numeric */
|
||||
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
|
||||
}
|
||||
|
||||
static long dbConstGetNelements(const struct link *plink, long *nelements)
|
||||
{
|
||||
*nelements = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest)
|
||||
{
|
||||
if (pnRequest)
|
||||
*pnRequest = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lset dbConst_lset = {
|
||||
1, 0, /* Constant, not Volatile */
|
||||
NULL, NULL,
|
||||
dbConstLoadScalar,
|
||||
dbConstLoadLS,
|
||||
dbConstLoadArray,
|
||||
NULL,
|
||||
NULL, dbConstGetNelements,
|
||||
dbConstGetValue,
|
||||
NULL, NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL
|
||||
};
|
||||
34
src/ioc/db/dbConstLink.h
Normal file
34
src/ioc/db/dbConstLink.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 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 is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbConstLink.h
|
||||
*
|
||||
* Created on: April 3rd, 2016
|
||||
* Author: Andrew Johnson
|
||||
*/
|
||||
|
||||
#ifndef INC_dbConstLink_H
|
||||
#define INC_dbConstLink_H
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct link;
|
||||
|
||||
epicsShareFunc void dbConstInitLink(struct link *plink);
|
||||
epicsShareFunc void dbConstAddLink(struct link *plink);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_dbConstLink_H */
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "dbCAC.h"
|
||||
#include "dbChannel.h"
|
||||
#include "dbChannelIO.h"
|
||||
#include "dbChannelNOOP.h"
|
||||
#include "dbPutNotifyBlocker.h"
|
||||
|
||||
class dbService : public cacService {
|
||||
@@ -51,9 +52,16 @@ cacContext & dbService::contextCreate (
|
||||
mutualExclusion, notify );
|
||||
}
|
||||
|
||||
extern "C" int dbServiceIsolate;
|
||||
int dbServiceIsolate = 0;
|
||||
|
||||
extern "C" void dbServiceIOInit ()
|
||||
{
|
||||
caInstallDefaultService ( dbs );
|
||||
static int init=0;
|
||||
if(!init) {
|
||||
caInstallDefaultService ( dbs );
|
||||
init=1;
|
||||
}
|
||||
}
|
||||
|
||||
dbBaseIO::dbBaseIO () {}
|
||||
@@ -62,7 +70,8 @@ dbContext::dbContext ( epicsMutex & cbMutexIn,
|
||||
epicsMutex & mutexIn, cacContextNotify & notifyIn ) :
|
||||
readNotifyCache ( mutexIn ), ctx ( 0 ),
|
||||
stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), cbMutex ( cbMutexIn ),
|
||||
notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 )
|
||||
notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 ),
|
||||
isolated(dbServiceIsolate)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -82,7 +91,10 @@ cacChannel & dbContext::createChannel (
|
||||
|
||||
dbChannel *dbch = dbChannel_create ( pName );
|
||||
if ( ! dbch ) {
|
||||
if ( ! this->pNetContext.get() ) {
|
||||
if ( isolated ) {
|
||||
return *new dbChannelNOOP(pName, notifyIn);
|
||||
|
||||
} else if ( ! this->pNetContext.get() ) {
|
||||
this->pNetContext.reset (
|
||||
& this->notify.createNetworkContext (
|
||||
this->mutex, this->cbMutex ) );
|
||||
@@ -132,7 +144,8 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
|
||||
const struct db_field_log * pfl,
|
||||
cacStateNotify & notifyIn )
|
||||
{
|
||||
unsigned long size = dbr_size_n ( type, count );
|
||||
long realcount = (count==0)?dbChannelElements(dbch):count;
|
||||
unsigned long size = dbr_size_n ( type, realcount );
|
||||
|
||||
if ( type > INT_MAX ) {
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -159,8 +172,13 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
|
||||
this->stateNotifyCacheSize = size;
|
||||
}
|
||||
void *pvfl = (void *) pfl;
|
||||
int status = dbChannel_get ( dbch, static_cast <int> ( type ),
|
||||
this->pStateNotifyCache, static_cast <int> ( count ), pvfl );
|
||||
int status;
|
||||
if(count==0) /* fetch actual number of elements (dynamic array) */
|
||||
status = dbChannel_get_count( dbch, static_cast <int> ( type ),
|
||||
this->pStateNotifyCache, &realcount, pvfl );
|
||||
else /* fetch requested number of elements, truncated or zero padded */
|
||||
status = dbChannel_get( dbch, static_cast <int> ( type ),
|
||||
this->pStateNotifyCache, realcount, pvfl );
|
||||
if ( status ) {
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
notifyIn.exception ( guard, ECA_GETFAIL,
|
||||
@@ -168,7 +186,7 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
|
||||
}
|
||||
else {
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
notifyIn.current ( guard, type, count, this->pStateNotifyCache );
|
||||
notifyIn.current ( guard, type, realcount, this->pStateNotifyCache );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,27 +60,32 @@ void dbContextReadNotifyCache::callReadNotify (
|
||||
return;
|
||||
}
|
||||
|
||||
if ( dbChannelElements(dbch) < 0 ) {
|
||||
const long maxcount = dbChannelElements(dbch);
|
||||
|
||||
if ( maxcount < 0 ) {
|
||||
notify.exception ( guard, ECA_BADCOUNT,
|
||||
"database has negetive element count",
|
||||
type, count);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( count > static_cast < unsigned long > ( dbChannelElements(dbch) ) ) {
|
||||
} else if ( count > (unsigned long)maxcount ) {
|
||||
notify.exception ( guard, ECA_BADCOUNT,
|
||||
"element count out of range (high side)",
|
||||
type, count);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long size = dbr_size_n ( type, count );
|
||||
long realcount = (count==0)?maxcount:count;
|
||||
unsigned long size = dbr_size_n ( type, realcount );
|
||||
|
||||
privateAutoDestroyPtr ptr ( _allocator, size );
|
||||
int status;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
status = dbChannel_get ( dbch, static_cast <int> ( type ),
|
||||
ptr.get (), static_cast <long> ( count ), 0 );
|
||||
if ( count==0 )
|
||||
status = dbChannel_get_count ( dbch, (int)type, ptr.get(), &realcount, 0);
|
||||
else
|
||||
status = dbChannel_get ( dbch, (int)type, ptr.get (), realcount, 0 );
|
||||
}
|
||||
if ( status ) {
|
||||
notify.exception ( guard, ECA_GETFAIL,
|
||||
@@ -89,7 +94,7 @@ void dbContextReadNotifyCache::callReadNotify (
|
||||
}
|
||||
else {
|
||||
notify.completion (
|
||||
guard, type, count, ptr.get () );
|
||||
guard, type, realcount, ptr.get () );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
257
src/ioc/db/dbConvertJSON.c
Normal file
257
src/ioc/db/dbConvertJSON.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 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.
|
||||
\*************************************************************************/
|
||||
/* dbConvertJSON.c */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "yajl_alloc.h"
|
||||
#include "yajl_parse.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbConvertJSON.h"
|
||||
|
||||
typedef long (*FASTCONVERT)();
|
||||
|
||||
typedef struct parseContext {
|
||||
int depth;
|
||||
short dbrType;
|
||||
short dbrSize;
|
||||
char *pdest;
|
||||
int elems;
|
||||
} parseContext;
|
||||
|
||||
static int dbcj_null(void *ctx) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_boolean(void *ctx, int val) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_integer(void *ctx, long num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
epicsInt32 val32 = num;
|
||||
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_LONG][parser->dbrType];
|
||||
|
||||
if (parser->elems > 0) {
|
||||
conv(&val32, parser->pdest, NULL);
|
||||
parser->pdest += parser->dbrSize;
|
||||
parser->elems--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dblsj_integer(void *ctx, long num) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_double(void *ctx, double num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
|
||||
|
||||
if (parser->elems > 0) {
|
||||
conv(&num, parser->pdest, NULL);
|
||||
parser->pdest += parser->dbrSize;
|
||||
parser->elems--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dblsj_double(void *ctx, double num) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
char *pdest = parser->pdest;
|
||||
|
||||
/* Not attempting to handle char-array fields here, they need more
|
||||
* metadata about the field than we have available at the moment.
|
||||
*/
|
||||
if (parser->dbrType != DBF_STRING) {
|
||||
errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
if (parser->elems > 0) {
|
||||
if (len > parser->dbrSize - 1)
|
||||
len = parser->dbrSize - 1;
|
||||
strncpy(pdest, (const char *) val, len);
|
||||
pdest[len] = 0;
|
||||
parser->pdest += parser->dbrSize;
|
||||
parser->elems--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dblsj_string(void *ctx, const unsigned char *val, unsigned int len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
char *pdest = parser->pdest;
|
||||
|
||||
if (parser->dbrType != DBF_STRING) {
|
||||
errlogPrintf("dbConvertJSON: dblsj_string dbrType error\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
if (parser->elems > 0) {
|
||||
if (len > parser->dbrSize - 1)
|
||||
len = parser->dbrSize - 1;
|
||||
strncpy(pdest, (const char *) val, len);
|
||||
pdest[len] = 0;
|
||||
parser->pdest = pdest + len;
|
||||
parser->elems = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dbcj_start_map(void *ctx) {
|
||||
errlogPrintf("dbConvertJSON: Map type not supported\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_map_key(void *ctx, const unsigned char *key, unsigned int len) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_end_map(void *ctx) {
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
static int dbcj_start_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
|
||||
if (++parser->depth > 1)
|
||||
errlogPrintf("dbConvertJSON: Embedded arrays not supported\n");
|
||||
|
||||
return (parser->depth == 1);
|
||||
}
|
||||
|
||||
static int dbcj_end_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
|
||||
parser->depth--;
|
||||
return (parser->depth == 0);
|
||||
}
|
||||
|
||||
|
||||
static yajl_callbacks dbcj_callbacks = {
|
||||
dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string,
|
||||
dbcj_start_map, dbcj_map_key, dbcj_end_map,
|
||||
dbcj_start_array, dbcj_end_array
|
||||
};
|
||||
|
||||
static const yajl_parser_config dbcj_config =
|
||||
{ 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
|
||||
|
||||
long dbPutConvertJSON(const char *json, short dbrType,
|
||||
void *pdest, long *pnRequest)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbcj_alloc;
|
||||
yajl_handle yh;
|
||||
yajl_status ys;
|
||||
size_t jlen = strlen(json);
|
||||
long status;
|
||||
|
||||
parser->depth = 0;
|
||||
parser->dbrType = dbrType;
|
||||
parser->dbrSize = dbValueSize(dbrType);
|
||||
parser->pdest = pdest;
|
||||
parser->elems = *pnRequest;
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbcj_alloc);
|
||||
yh = yajl_alloc(&dbcj_callbacks, &dbcj_config, &dbcj_alloc, parser);
|
||||
if (!yh)
|
||||
return S_db_noMemory;
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen);
|
||||
if (ys == yajl_status_insufficient_data)
|
||||
ys = yajl_parse_complete(yh);
|
||||
|
||||
switch (ys) {
|
||||
case yajl_status_ok:
|
||||
*pnRequest -= parser->elems;
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case yajl_status_error: {
|
||||
unsigned char *err = yajl_get_error(yh, 1,
|
||||
(const unsigned char *) json, (unsigned int) jlen);
|
||||
fprintf(stderr, "dbConvertJSON: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static yajl_callbacks dblsj_callbacks = {
|
||||
dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
|
||||
dbcj_start_map, dbcj_map_key, dbcj_end_map,
|
||||
dbcj_start_array, dbcj_end_array
|
||||
};
|
||||
|
||||
long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbcj_alloc;
|
||||
yajl_handle yh;
|
||||
yajl_status ys;
|
||||
size_t jlen = strlen(json);
|
||||
long status;
|
||||
|
||||
if (!size) {
|
||||
*plen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser->depth = 0;
|
||||
parser->dbrType = DBF_STRING;
|
||||
parser->dbrSize = size;
|
||||
parser->pdest = pdest;
|
||||
parser->elems = 1;
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbcj_alloc);
|
||||
yh = yajl_alloc(&dblsj_callbacks, &dbcj_config, &dbcj_alloc, parser);
|
||||
if (!yh)
|
||||
return S_db_noMemory;
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen);
|
||||
if (ys == yajl_status_insufficient_data)
|
||||
ys = yajl_parse_complete(yh);
|
||||
|
||||
switch (ys) {
|
||||
case yajl_status_ok:
|
||||
*plen = (char *) parser->pdest - pdest + 1;
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case yajl_status_error: {
|
||||
unsigned char *err = yajl_get_error(yh, 1,
|
||||
(const unsigned char *) json, (unsigned int) jlen);
|
||||
fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
return status;
|
||||
}
|
||||
28
src/ioc/db/dbConvertJSON.h
Normal file
28
src/ioc/db/dbConvertJSON.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 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.
|
||||
\*************************************************************************/
|
||||
/* dbConvertJSON.h */
|
||||
|
||||
#ifndef INC_dbConvertJSON_H
|
||||
#define INC_dbConvertJSON_H
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This name should probably be changed to inclue "array" */
|
||||
epicsShareFunc long dbPutConvertJSON(const char *json, short dbrType,
|
||||
void *pdest, long *psize);
|
||||
epicsShareFunc long dbLSConvertJSON(const char *json, char *pdest,
|
||||
epicsUInt32 size, epicsUInt32 *plen);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_dbConvertJSON_H */
|
||||
|
||||
358
src/ioc/db/dbDbLink.c
Normal file
358
src/ioc/db/dbDbLink.c
Normal file
@@ -0,0 +1,358 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 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 is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbDbLink.c
|
||||
*
|
||||
* Original Authors: Bob Dalesio, Marty Kraimer
|
||||
* Current Author: Andrew Johnson
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alarm.h"
|
||||
#include "cantProceed.h"
|
||||
#include "cvtFast.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#include "caeventmask.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbConvert.h"
|
||||
#include "db_field_log.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbLockPvt.h"
|
||||
#include "dbNotify.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "special.h"
|
||||
|
||||
/***************************** Database Links *****************************/
|
||||
|
||||
/* Forward definition */
|
||||
static lset dbDb_lset;
|
||||
|
||||
long dbDbInitLink(struct link *plink, short dbfType)
|
||||
{
|
||||
DBADDR dbaddr;
|
||||
long status;
|
||||
DBADDR *pdbAddr;
|
||||
|
||||
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
plink->lset = &dbDb_lset;
|
||||
plink->type = DB_LINK;
|
||||
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
|
||||
*pdbAddr = dbaddr; /* structure copy */
|
||||
plink->value.pv_link.pvt = pdbAddr;
|
||||
ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
/* merging into the same lockset is deferred to the caller.
|
||||
* cf. initPVLinks()
|
||||
*/
|
||||
dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
|
||||
assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
DBADDR *ptarget)
|
||||
{
|
||||
plink->lset = &dbDb_lset;
|
||||
plink->type = DB_LINK;
|
||||
plink->value.pv_link.pvt = ptarget;
|
||||
ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
|
||||
/* target record is already locked in dbPutFieldLink() */
|
||||
dbLockSetMerge(locker, plink->precord, ptarget->precord);
|
||||
}
|
||||
|
||||
static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
|
||||
{
|
||||
DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
plink->type = PV_LINK;
|
||||
|
||||
/* locker is NULL when an isolated IOC is closing its links */
|
||||
if (locker) {
|
||||
plink->value.pv_link.pvt = 0;
|
||||
plink->value.pv_link.getCvt = 0;
|
||||
plink->value.pv_link.pvlMask = 0;
|
||||
plink->value.pv_link.lastGetdbrType = 0;
|
||||
ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
|
||||
dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
|
||||
}
|
||||
free(pdbAddr);
|
||||
}
|
||||
|
||||
static int dbDbIsConnected(const struct link *plink)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int dbDbGetDBFtype(const struct link *plink)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
return paddr->field_type;
|
||||
}
|
||||
|
||||
static long dbDbGetElements(const struct link *plink, long *nelements)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
*nelements = paddr->no_elements;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
DBADDR *paddr = ppv_link->pvt;
|
||||
dbCommon *precord = plink->precord;
|
||||
long status;
|
||||
|
||||
/* scan passive records if link is process passive */
|
||||
if (ppv_link->pvlMask & pvlOptPP) {
|
||||
unsigned char pact = precord->pact;
|
||||
|
||||
precord->pact = TRUE;
|
||||
status = dbScanPassive(precord, paddr->precord);
|
||||
precord->pact = pact;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
} else {
|
||||
unsigned short dbfType = paddr->field_type;
|
||||
|
||||
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
|
||||
return S_db_badDbrtype;
|
||||
|
||||
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
|
||||
&& paddr->special != SPC_DBADDR
|
||||
&& paddr->special != SPC_ATTRIBUTE) {
|
||||
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
} else {
|
||||
ppv_link->getCvt = NULL;
|
||||
status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
|
||||
}
|
||||
ppv_link->lastGetdbrType = dbrType;
|
||||
}
|
||||
|
||||
if (!status)
|
||||
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
|
||||
plink->precord, paddr->precord->stat, paddr->precord->sevr);
|
||||
return status;
|
||||
}
|
||||
|
||||
static long dbDbGetControlLimits(const struct link *plink, double *low,
|
||||
double *high)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRctrlDouble
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_CTRL_DOUBLE;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
NULL);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*low = buffer.lower_ctrl_limit;
|
||||
*high = buffer.upper_ctrl_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
|
||||
double *high)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRgrDouble
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_GR_DOUBLE;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
NULL);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*low = buffer.lower_disp_limit;
|
||||
*high = buffer.upper_disp_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
|
||||
double *low, double *high, double *hihi)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRalDouble
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_AL_DOUBLE;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
0);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*lolo = buffer.lower_alarm_limit;
|
||||
*low = buffer.lower_warning_limit;
|
||||
*high = buffer.upper_warning_limit;
|
||||
*hihi = buffer.upper_alarm_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetPrecision(const struct link *plink, short *precision)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRprecision
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_PRECISION;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
0);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*precision = (short) buffer.precision.dp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRunits
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_UNITS;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
0);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
strncpy(units, buffer.units, unitsSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
if (status)
|
||||
*status = paddr->precord->stat;
|
||||
if (severity)
|
||||
*severity = paddr->precord->sevr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
*pstamp = paddr->precord->time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbPutValue(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
struct dbCommon *psrce = plink->precord;
|
||||
DBADDR *paddr = (DBADDR *) ppv_link->pvt;
|
||||
dbCommon *pdest = paddr->precord;
|
||||
long status = dbPut(paddr, dbrType, pbuffer, nRequest);
|
||||
|
||||
recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
|
||||
psrce->nsev);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (paddr->pfield == (void *) &pdest->proc ||
|
||||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
||||
/* if dbPutField caused asyn record to process */
|
||||
/* ask for reprocessing*/
|
||||
if (pdest->putf) {
|
||||
pdest->rpro = TRUE;
|
||||
} else { /* process dest record with source's PACT true */
|
||||
unsigned char pact;
|
||||
|
||||
if (psrce && psrce->ppn)
|
||||
dbNotifyAdd(psrce, pdest);
|
||||
pact = psrce->pact;
|
||||
psrce->pact = TRUE;
|
||||
status = dbProcess(pdest);
|
||||
psrce->pact = pact;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dbDbScanFwdLink(struct link *plink)
|
||||
{
|
||||
dbCommon *precord = plink->precord;
|
||||
dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
|
||||
|
||||
dbScanPassive(precord, paddr->precord);
|
||||
}
|
||||
|
||||
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
|
||||
{
|
||||
return rtn(plink, priv);
|
||||
}
|
||||
|
||||
static lset dbDb_lset = {
|
||||
0, 0, /* not Constant, not Volatile */
|
||||
NULL, dbDbRemoveLink,
|
||||
NULL, NULL, NULL,
|
||||
dbDbIsConnected,
|
||||
dbDbGetDBFtype, dbDbGetElements,
|
||||
dbDbGetValue,
|
||||
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
|
||||
dbDbGetPrecision, dbDbGetUnits,
|
||||
dbDbGetAlarm, dbDbGetTimeStamp,
|
||||
dbDbPutValue, NULL,
|
||||
dbDbScanFwdLink, doLocked
|
||||
};
|
||||
35
src/ioc/db/dbDbLink.h
Normal file
35
src/ioc/db/dbDbLink.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 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 is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbDbLink.h
|
||||
*
|
||||
* Created on: April 3rd, 2016
|
||||
* Author: Andrew Johnson
|
||||
*/
|
||||
|
||||
#ifndef INC_dbDbLink_H
|
||||
#define INC_dbDbLink_H
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct link;
|
||||
struct dbLocker;
|
||||
|
||||
epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
|
||||
epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
|
||||
short dbfType, DBADDR *ptarget);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_dbDbLink_H */
|
||||
@@ -321,6 +321,22 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc void db_cleanup_events(void)
|
||||
{
|
||||
freeListCleanup(dbevEventUserFreeList);
|
||||
dbevEventUserFreeList = NULL;
|
||||
|
||||
freeListCleanup(dbevEventQueueFreeList);
|
||||
dbevEventQueueFreeList = NULL;
|
||||
|
||||
freeListCleanup(dbevEventSubscriptionFreeList);
|
||||
dbevEventSubscriptionFreeList = NULL;
|
||||
|
||||
freeListCleanup(dbevFieldLogFreeList);
|
||||
dbevFieldLogFreeList = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* DB_CLOSE_EVENTS()
|
||||
*
|
||||
|
||||
@@ -63,6 +63,10 @@ epicsShareFunc void db_flush_extra_labor_event (dbEventCtx);
|
||||
epicsShareFunc int db_post_extra_labor (dbEventCtx ctx);
|
||||
epicsShareFunc void db_event_change_priority ( dbEventCtx ctx, unsigned epicsPriority );
|
||||
|
||||
#ifdef EPICS_PRIVATE_API
|
||||
epicsShareFunc void db_cleanup_events(void);
|
||||
#endif
|
||||
|
||||
typedef void EVENTFUNC (void *user_arg, struct dbChannel *chan,
|
||||
int eventsRemaining, struct db_field_log *pfl);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@
|
||||
#include "dbCaTest.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbIocRegister.h"
|
||||
#include "dbJLink.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbNotify.h"
|
||||
#include "dbScan.h"
|
||||
@@ -109,6 +110,16 @@ static void dbcarCallFunc(const iocshArgBuf *args)
|
||||
dbcar(args[0].sval,args[1].ival);
|
||||
}
|
||||
|
||||
/* dbjlr */
|
||||
static const iocshArg dbjlrArg0 = { "record name",iocshArgString};
|
||||
static const iocshArg dbjlrArg1 = { "level",iocshArgInt};
|
||||
static const iocshArg * const dbjlrArgs[2] = {&dbjlrArg0,&dbjlrArg1};
|
||||
static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs};
|
||||
static void dbjlrCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
dbjlr(args[0].sval,args[1].ival);
|
||||
}
|
||||
|
||||
/* dbel */
|
||||
static const iocshArg dbelArg0 = { "record name",iocshArgString};
|
||||
static const iocshArg dbelArg1 = { "level",iocshArgInt};
|
||||
@@ -395,6 +406,7 @@ void dbIocRegister(void)
|
||||
iocshRegister(&dbsrFuncDef,dbsrCallFunc);
|
||||
iocshRegister(&dbcarFuncDef,dbcarCallFunc);
|
||||
iocshRegister(&dbelFuncDef,dbelCallFunc);
|
||||
iocshRegister(&dbjlrFuncDef,dbjlrCallFunc);
|
||||
|
||||
iocshRegister(&dbLoadDatabaseFuncDef,dbLoadDatabaseCallFunc);
|
||||
iocshRegister(&dbLoadRecordsFuncDef,dbLoadRecordsCallFunc);
|
||||
|
||||
540
src/ioc/db/dbJLink.c
Normal file
540
src/ioc/db/dbJLink.c
Normal file
@@ -0,0 +1,540 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 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.
|
||||
\*************************************************************************/
|
||||
/* dbJLink.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "dbmf.h"
|
||||
#include "errlog.h"
|
||||
#include "yajl_alloc.h"
|
||||
#include "yajl_parse.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbJLink.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "link.h"
|
||||
|
||||
#define IFDEBUG(n) if(parser->parse_debug)
|
||||
|
||||
typedef struct parseContext {
|
||||
jlink *pjlink;
|
||||
jlink *product;
|
||||
short dbfType;
|
||||
short jsonDepth;
|
||||
unsigned key_is_link:1;
|
||||
unsigned parse_debug:1;
|
||||
unsigned lset_debug:1;
|
||||
} parseContext;
|
||||
|
||||
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
|
||||
|
||||
static int dbjl_return(parseContext *parser, jlif_result result) {
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
}
|
||||
|
||||
if (result == jlif_stop && pjlink) {
|
||||
jlink *parent;
|
||||
|
||||
while ((parent = pjlink->parent)) {
|
||||
pjlink->pif->free_jlink(pjlink);
|
||||
pjlink = parent;
|
||||
}
|
||||
pjlink->pif->free_jlink(pjlink);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dbjl_value(parseContext *parser, jlif_result result) {
|
||||
jlink *pjlink = parser->pjlink;
|
||||
jlink *parent;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
}
|
||||
|
||||
if (result == jlif_stop || pjlink->parseDepth > 0)
|
||||
return dbjl_return(parser, result);
|
||||
|
||||
parent = pjlink->parent;
|
||||
if (!parent) {
|
||||
parser->product = pjlink;
|
||||
} else if (parent->pif->end_child) {
|
||||
parent->pif->end_child(parent, pjlink);
|
||||
}
|
||||
pjlink->debug = 0;
|
||||
|
||||
parser->pjlink = parent;
|
||||
|
||||
IFDEBUG(8)
|
||||
printf("dbjl_value: product = %p\n", pjlink);
|
||||
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
static int dbjl_null(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_null(%s@%p)\n", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_null)(pjlink));
|
||||
}
|
||||
|
||||
static int dbjl_boolean(void *ctx, int val) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_boolean)(pjlink, val));
|
||||
}
|
||||
|
||||
static int dbjl_integer(void *ctx, long num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_integer(%s@%p, %ld)\n",
|
||||
pjlink->pif->name, pjlink, num);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_integer)(pjlink, num));
|
||||
}
|
||||
|
||||
static int dbjl_double(void *ctx, double num) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_double(%s@%p, %g)\n",
|
||||
pjlink->pif->name, pjlink, num);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_double)(pjlink, num));
|
||||
}
|
||||
|
||||
static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_string(%s@%p, \"%.*s\")\n",
|
||||
pjlink->pif->name, pjlink, len, val);
|
||||
|
||||
assert(pjlink);
|
||||
return dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_string)(pjlink, (const char *) val, len));
|
||||
}
|
||||
|
||||
static int dbjl_start_map(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
int result;
|
||||
|
||||
if (!pjlink) {
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_map(NULL)\t");
|
||||
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(parser->jsonDepth == 0);
|
||||
parser->jsonDepth++;
|
||||
parser->key_is_link = 1;
|
||||
return jlif_continue; /* Opening '{' */
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
}
|
||||
|
||||
pjlink->parseDepth++;
|
||||
parser->jsonDepth++;
|
||||
|
||||
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
|
||||
if (result == jlif_key_child_link) {
|
||||
parser->key_is_link = 1;
|
||||
result = jlif_continue;
|
||||
}
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbjl_start_map -> %d\n", result);
|
||||
|
||||
return dbjl_return(parser, result);
|
||||
}
|
||||
|
||||
static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
char *link_name;
|
||||
linkSup *linkSup;
|
||||
jlif *pjlif;
|
||||
|
||||
if (!parser->key_is_link) {
|
||||
if (!pjlink) {
|
||||
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
|
||||
len, key);
|
||||
return dbjl_return(parser, jlif_stop);
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
|
||||
pjlink->pif->name, pjlink, len, key);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(pjlink->parseDepth > 0);
|
||||
return dbjl_return(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_map_key)(pjlink,
|
||||
(const char *) key, len));
|
||||
}
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_map_key(NULL, \"%.*s\")\t", len, key);
|
||||
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->key_is_link);
|
||||
}
|
||||
|
||||
link_name = dbmfStrndup((const char *) key, len);
|
||||
|
||||
linkSup = dbFindLinkSup(pdbbase, link_name);
|
||||
if (!linkSup) {
|
||||
errlogPrintf("dbJLinkInit: Link type '%s' not found\n",
|
||||
link_name);
|
||||
dbmfFree(link_name);
|
||||
return dbjl_return(parser, jlif_stop);
|
||||
}
|
||||
|
||||
pjlif = linkSup->pjlif;
|
||||
if (!pjlif) {
|
||||
errlogPrintf("dbJLinkInit: Support for Link type '%s' not loaded\n",
|
||||
link_name);
|
||||
dbmfFree(link_name);
|
||||
return dbjl_return(parser, jlif_stop);
|
||||
}
|
||||
|
||||
dbmfFree(link_name);
|
||||
|
||||
pjlink = pjlif->alloc_jlink(parser->dbfType);
|
||||
if (!pjlink) {
|
||||
errlogPrintf("dbJLinkInit: Out of memory\n");
|
||||
return dbjl_return(parser, jlif_stop);
|
||||
}
|
||||
pjlink->pif = pjlif;
|
||||
pjlink->parent = NULL;
|
||||
pjlink->parseDepth = 0;
|
||||
pjlink->debug = !!parser->lset_debug;
|
||||
|
||||
if (parser->pjlink) {
|
||||
/* We're starting a child link, save its parent */
|
||||
pjlink->parent = parser->pjlink;
|
||||
}
|
||||
parser->pjlink = pjlink;
|
||||
parser->key_is_link = 0;
|
||||
|
||||
IFDEBUG(8)
|
||||
printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
|
||||
return jlif_continue;
|
||||
}
|
||||
|
||||
static int dbjl_end_map(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
jlif_result result;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_end_map(%s@%p)\t",
|
||||
pjlink ? pjlink->pif->name : "NULL", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
|
||||
parser->key_is_link);
|
||||
}
|
||||
|
||||
parser->jsonDepth--;
|
||||
if (pjlink) {
|
||||
pjlink->parseDepth--;
|
||||
|
||||
result = dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_end_map)(pjlink));
|
||||
}
|
||||
else {
|
||||
result = jlif_continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dbjl_start_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(pjlink);
|
||||
pjlink->parseDepth++;
|
||||
parser->jsonDepth++;
|
||||
|
||||
return dbjl_return(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_start_array)(pjlink));
|
||||
}
|
||||
|
||||
static int dbjl_end_array(void *ctx) {
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
jlink *pjlink = parser->pjlink;
|
||||
|
||||
IFDEBUG(10) {
|
||||
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
|
||||
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
|
||||
}
|
||||
|
||||
assert(pjlink);
|
||||
pjlink->parseDepth--;
|
||||
parser->jsonDepth--;
|
||||
|
||||
return dbjl_value(parser,
|
||||
CALL_OR_STOP(pjlink->pif->parse_end_array)(pjlink));
|
||||
}
|
||||
|
||||
|
||||
static yajl_callbacks dbjl_callbacks = {
|
||||
dbjl_null, dbjl_boolean, dbjl_integer, dbjl_double, NULL, dbjl_string,
|
||||
dbjl_start_map, dbjl_map_key, dbjl_end_map, dbjl_start_array, dbjl_end_array
|
||||
};
|
||||
|
||||
static const yajl_parser_config dbjl_config =
|
||||
{ 0, 0 }; /* allowComments = NO, checkUTF8 = NO */
|
||||
|
||||
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
|
||||
jlink **ppjlink, unsigned opts)
|
||||
{
|
||||
parseContext context, *parser = &context;
|
||||
yajl_alloc_funcs dbjl_allocs;
|
||||
yajl_handle yh;
|
||||
yajl_status ys;
|
||||
long status;
|
||||
|
||||
parser->pjlink = NULL;
|
||||
parser->product = NULL;
|
||||
parser->dbfType = dbfType;
|
||||
parser->jsonDepth = 0;
|
||||
parser->key_is_link = 0;
|
||||
parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
|
||||
parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
|
||||
(int) jlen, json, dbfType, ppjlink);
|
||||
|
||||
IFDEBUG(10)
|
||||
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
|
||||
parser->jsonDepth, parser->key_is_link);
|
||||
|
||||
yajl_set_default_alloc_funcs(&dbjl_allocs);
|
||||
yh = yajl_alloc(&dbjl_callbacks, &dbjl_config, &dbjl_allocs, parser);
|
||||
if (!yh)
|
||||
return S_db_noMemory;
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, (unsigned) jlen);
|
||||
if (ys == yajl_status_insufficient_data)
|
||||
ys = yajl_parse_complete(yh);
|
||||
|
||||
switch (ys) {
|
||||
unsigned char *err;
|
||||
|
||||
case yajl_status_ok:
|
||||
assert(parser->jsonDepth == 0);
|
||||
*ppjlink = parser->product;
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case yajl_status_error:
|
||||
err = yajl_get_error(yh, 1, (const unsigned char *) json, (unsigned) jlen);
|
||||
errlogPrintf("dbJLinkInit: %s\n", err);
|
||||
yajl_free_error(yh, err);
|
||||
dbJLinkFree(parser->pjlink);
|
||||
/* fall through */
|
||||
default:
|
||||
status = S_db_badField;
|
||||
}
|
||||
|
||||
yajl_free(yh);
|
||||
return status;
|
||||
}
|
||||
|
||||
long dbJLinkInit(struct link *plink)
|
||||
{
|
||||
jlink *pjlink;
|
||||
|
||||
assert(plink);
|
||||
pjlink = plink->value.json.jlink;
|
||||
|
||||
if (pjlink)
|
||||
plink->lset = pjlink->pif->get_lset(pjlink);
|
||||
|
||||
dbLinkOpen(plink);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbJLinkFree(jlink *pjlink)
|
||||
{
|
||||
if (pjlink)
|
||||
pjlink->pif->free_jlink(pjlink);
|
||||
}
|
||||
|
||||
void dbJLinkReport(jlink *pjlink, int level, int indent) {
|
||||
if (pjlink && pjlink->pif->report)
|
||||
pjlink->pif->report(pjlink, level, indent);
|
||||
}
|
||||
|
||||
long dbJLinkMapChildren(struct link *plink, jlink_map_fn rtn, void *ctx)
|
||||
{
|
||||
jlink *pjlink;
|
||||
long status;
|
||||
|
||||
if (!plink || plink->type != JSON_LINK)
|
||||
return 0;
|
||||
|
||||
pjlink = plink->value.json.jlink;
|
||||
if (!pjlink)
|
||||
return 0;
|
||||
|
||||
status = rtn(pjlink, ctx);
|
||||
if (!status && pjlink->pif->map_children)
|
||||
status = pjlink->pif->map_children(pjlink, rtn, ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
long dbjlr(const char *recname, int level)
|
||||
{
|
||||
DBENTRY dbentry;
|
||||
DBENTRY * const pdbentry = &dbentry;
|
||||
long status;
|
||||
|
||||
if (!recname || recname[0] == '\0' || !strcmp(recname, "*")) {
|
||||
recname = NULL;
|
||||
printf("JSON links in all records\n\n");
|
||||
}
|
||||
else
|
||||
printf("JSON links in record '%s'\n\n", recname);
|
||||
|
||||
dbInitEntry(pdbbase, pdbentry);
|
||||
for (status = dbFirstRecordType(pdbentry);
|
||||
status == 0;
|
||||
status = dbNextRecordType(pdbentry)) {
|
||||
for (status = dbFirstRecord(pdbentry);
|
||||
status == 0;
|
||||
status = dbNextRecord(pdbentry)) {
|
||||
dbRecordType *pdbRecordType = pdbentry->precordType;
|
||||
dbCommon *precord = pdbentry->precnode->precord;
|
||||
char *prec = (char *) precord;
|
||||
int i;
|
||||
|
||||
if (recname && strcmp(recname, dbGetRecordName(pdbentry)))
|
||||
continue;
|
||||
if (dbIsAlias(pdbentry))
|
||||
continue;
|
||||
|
||||
printf(" %s record '%s':\n", pdbRecordType->name, precord->name);
|
||||
|
||||
dbScanLock(precord);
|
||||
for (i = 0; i < pdbRecordType->no_links; i++) {
|
||||
int idx = pdbRecordType->link_ind[i];
|
||||
dbFldDes *pdbFldDes = pdbRecordType->papFldDes[idx];
|
||||
DBLINK *plink = (DBLINK *) (prec + pdbFldDes->offset);
|
||||
|
||||
if (plink->type != JSON_LINK)
|
||||
continue;
|
||||
if (!dbLinkIsDefined(plink))
|
||||
continue;
|
||||
|
||||
printf(" Link field '%s':\n", pdbFldDes->name);
|
||||
dbJLinkReport(plink->value.json.jlink, level, 6);
|
||||
}
|
||||
dbScanUnlock(precord);
|
||||
if (recname)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx)
|
||||
{
|
||||
DBENTRY dbentry;
|
||||
DBENTRY * const pdbentry = &dbentry;
|
||||
long status;
|
||||
|
||||
if (recname && (recname[0] = '\0' || !strcmp(recname, "*")))
|
||||
recname = NULL;
|
||||
|
||||
dbInitEntry(pdbbase, pdbentry);
|
||||
for (status = dbFirstRecordType(pdbentry);
|
||||
status == 0;
|
||||
status = dbNextRecordType(pdbentry)) {
|
||||
for (status = dbFirstRecord(pdbentry);
|
||||
status == 0;
|
||||
status = dbNextRecord(pdbentry)) {
|
||||
dbRecordType *pdbRecordType = pdbentry->precordType;
|
||||
dbCommon *precord = pdbentry->precnode->precord;
|
||||
char *prec = (char *) precord;
|
||||
int i;
|
||||
|
||||
if (recname && strcmp(recname, dbGetRecordName(pdbentry)))
|
||||
continue;
|
||||
if (dbIsAlias(pdbentry))
|
||||
continue;
|
||||
|
||||
dbScanLock(precord);
|
||||
for (i = 0; i < pdbRecordType->no_links; i++) {
|
||||
int idx = pdbRecordType->link_ind[i];
|
||||
dbFldDes *pdbFldDes = pdbRecordType->papFldDes[idx];
|
||||
DBLINK *plink = (DBLINK *) (prec + pdbFldDes->offset);
|
||||
|
||||
status = dbJLinkMapChildren(plink, rtn, ctx);
|
||||
if (status)
|
||||
goto unlock;
|
||||
}
|
||||
unlock:
|
||||
dbScanUnlock(precord);
|
||||
if (status || recname)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
133
src/ioc/db/dbJLink.h
Normal file
133
src/ioc/db/dbJLink.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2016 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.
|
||||
\*************************************************************************/
|
||||
/* dbJLink.h */
|
||||
|
||||
#ifndef INC_dbJLink_H
|
||||
#define INC_dbJLink_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
jlif_stop = 0,
|
||||
jlif_continue = 1
|
||||
} jlif_result;
|
||||
|
||||
typedef enum {
|
||||
jlif_key_stop = jlif_stop,
|
||||
jlif_key_continue = jlif_continue,
|
||||
jlif_key_child_link
|
||||
} jlif_key_result;
|
||||
|
||||
struct link;
|
||||
struct lset;
|
||||
struct jlif;
|
||||
|
||||
typedef struct jlink {
|
||||
struct jlif *pif; /* Link methods */
|
||||
struct jlink *parent; /* NULL for top-level links */
|
||||
int parseDepth; /* Used by parser, unused afterwards */
|
||||
unsigned debug:1; /* set by caller of jlif operations to request debug output to console */
|
||||
/* Link types extend or embed this structure for private storage */
|
||||
} jlink;
|
||||
|
||||
typedef long (*jlink_map_fn)(jlink *, void *ctx);
|
||||
|
||||
typedef struct jlif {
|
||||
/* Optional parser methods below given as NULL are equivalent to
|
||||
* providing a routine that always returns jlif_stop, meaning that
|
||||
* this JSON construct is not allowed at this point in the parse.
|
||||
*/
|
||||
|
||||
const char *name;
|
||||
/* Name for the link type, used in link value */
|
||||
|
||||
jlink* (*alloc_jlink)(short dbfType);
|
||||
/* Required, allocate new link structure */
|
||||
|
||||
void (*free_jlink)(jlink *);
|
||||
/* Required, release all resources allocated for link */
|
||||
|
||||
jlif_result (*parse_null)(jlink *);
|
||||
/* Optional, parser saw a null value */
|
||||
|
||||
jlif_result (*parse_boolean)(jlink *, int val);
|
||||
/* Optional, parser saw a boolean value */
|
||||
|
||||
jlif_result (*parse_integer)(jlink *, long long num);
|
||||
/* Optional, parser saw an integer value */
|
||||
|
||||
jlif_result (*parse_double)(jlink *, double num);
|
||||
/* Optional, parser saw a double value */
|
||||
|
||||
jlif_result (*parse_string)(jlink *, const char *val, size_t len);
|
||||
/* Optional, parser saw a string value */
|
||||
|
||||
jlif_key_result (*parse_start_map)(jlink *);
|
||||
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_link
|
||||
* to expect a child link next (extra key/value pairs may follow).
|
||||
*/
|
||||
|
||||
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
|
||||
/* Optional, parser saw a map key */
|
||||
|
||||
jlif_result (*parse_end_map)(jlink *);
|
||||
/* Optional, parser saw a close-brace '}' */
|
||||
|
||||
jlif_result (*parse_start_array)(jlink *);
|
||||
/* Optional, parser saw an open-bracket */
|
||||
|
||||
jlif_result (*parse_end_array)(jlink *);
|
||||
/* Optional, parser saw a close-bracket */
|
||||
|
||||
void (*end_child)(jlink *parent, jlink *child);
|
||||
/* Optional, called with pointer to the new child link after
|
||||
* parse_start_map() returned jlif_key_child_link */
|
||||
|
||||
struct lset* (*get_lset)(const jlink *);
|
||||
/* Required, return lset for this link instance */
|
||||
|
||||
void (*report)(const jlink *, int level, int indent);
|
||||
/* Optional, print status information about this link instance, then
|
||||
* if (level > 0) print a link identifier (at indent+2) and call
|
||||
* dbJLinkReport(child, level-1, indent+4)
|
||||
* for each child.
|
||||
*/
|
||||
|
||||
long (*map_children)(jlink *, jlink_map_fn rtn, void *ctx);
|
||||
/* Optional, call dbJLinkMapChildren() on all embedded links.
|
||||
* Stop immediately and return status if non-zero.
|
||||
*/
|
||||
|
||||
/* Link types must NOT extend this table with their own routines,
|
||||
* this space is reserved for extensions to the jlink interface.
|
||||
*/
|
||||
} jlif;
|
||||
|
||||
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
|
||||
jlink **ppjlink, unsigned opts);
|
||||
epicsShareFunc long dbJLinkInit(struct link *plink);
|
||||
|
||||
epicsShareFunc void dbJLinkFree(jlink *);
|
||||
epicsShareFunc void dbJLinkReport(jlink *, int level, int indent);
|
||||
|
||||
epicsShareFunc long dbJLinkMapChildren(struct link *,
|
||||
jlink_map_fn rtn, void *ctx);
|
||||
|
||||
epicsShareFunc long dbjlr(const char *recname, int level);
|
||||
epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_dbJLink_H */
|
||||
|
||||
@@ -19,66 +19,39 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "alarm.h"
|
||||
#include "cantProceed.h"
|
||||
#include "cvtFast.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#include "caeventmask.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "callback.h"
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "dbCa.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbConvertFast.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbConstLink.h"
|
||||
#include "dbDbLink.h"
|
||||
#include "db_field_log.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbJLink.h"
|
||||
#include "dbLink.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbNotify.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "devSup.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "errMdef.h"
|
||||
#include "link.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "special.h"
|
||||
|
||||
static void inherit_severity(const struct pv_link *ppv_link, dbCommon *pdest,
|
||||
epicsEnum16 stat, epicsEnum16 sevr)
|
||||
{
|
||||
switch (ppv_link->pvlMask & pvlOptMsMode) {
|
||||
case pvlOptNMS:
|
||||
break;
|
||||
case pvlOptMSI:
|
||||
if (sevr < INVALID_ALARM)
|
||||
break;
|
||||
/* Fall through */
|
||||
case pvlOptMS:
|
||||
recGblSetSevr(pdest, LINK_ALARM, sevr);
|
||||
break;
|
||||
case pvlOptMSS:
|
||||
recGblSetSevr(pdest, stat, sevr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* How to identify links in error messages */
|
||||
static const char * link_field_name(const struct link *plink)
|
||||
{
|
||||
const struct dbCommon *precord = plink->value.pv_link.precord;
|
||||
const struct dbCommon *precord = plink->precord;
|
||||
const dbRecordType *pdbRecordType = precord->rdes;
|
||||
dbFldDes * const *papFldDes = pdbRecordType->papFldDes;
|
||||
const short *link_ind = pdbRecordType->link_ind;
|
||||
@@ -94,323 +67,30 @@ static const char * link_field_name(const struct link *plink)
|
||||
}
|
||||
|
||||
|
||||
/***************************** Constant Links *****************************/
|
||||
|
||||
static long dbConstLoadLink(struct link *plink, short dbrType, void *pbuffer)
|
||||
{
|
||||
if (!plink->value.constantStr)
|
||||
return S_db_badField;
|
||||
|
||||
/* Constant strings are always numeric */
|
||||
if (dbrType== DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
|
||||
dbrType = DBF_USHORT;
|
||||
|
||||
return dbFastPutConvertRoutine[DBR_STRING][dbrType]
|
||||
(plink->value.constantStr, pbuffer, NULL);
|
||||
}
|
||||
|
||||
static long dbConstGetNelements(const struct link *plink, long *nelements)
|
||||
{
|
||||
*nelements = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbConstGetLink(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
|
||||
{
|
||||
if (pnRequest)
|
||||
*pnRequest = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************** Database Links *****************************/
|
||||
|
||||
static long dbDbInitLink(struct link *plink, short dbfType)
|
||||
{
|
||||
DBADDR dbaddr;
|
||||
long status;
|
||||
DBADDR *pdbAddr;
|
||||
|
||||
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
plink->type = DB_LINK;
|
||||
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
|
||||
*pdbAddr = dbaddr; /* structure copy */
|
||||
plink->value.pv_link.pvt = pdbAddr;
|
||||
dbLockSetMerge(plink->value.pv_link.precord, pdbAddr->precord);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbAddLink(struct link *plink, short dbfType)
|
||||
{
|
||||
DBADDR dbaddr;
|
||||
long status;
|
||||
DBADDR *pdbAddr;
|
||||
|
||||
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
plink->type = DB_LINK;
|
||||
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
|
||||
*pdbAddr = dbaddr; /* structure copy */
|
||||
plink->value.pv_link.pvt = pdbAddr;
|
||||
|
||||
dbLockSetRecordLock(pdbAddr->precord);
|
||||
dbLockSetMerge(plink->value.pv_link.precord, pdbAddr->precord);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dbDbRemoveLink(struct link *plink)
|
||||
{
|
||||
free(plink->value.pv_link.pvt);
|
||||
plink->value.pv_link.pvt = 0;
|
||||
plink->value.pv_link.getCvt = 0;
|
||||
plink->value.pv_link.lastGetdbrType = 0;
|
||||
plink->type = PV_LINK;
|
||||
dbLockSetSplit(plink->value.pv_link.precord);
|
||||
}
|
||||
|
||||
static int dbDbIsLinkConnected(const struct link *plink)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int dbDbGetDBFtype(const struct link *plink)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
return paddr->field_type;
|
||||
}
|
||||
|
||||
static long dbDbGetElements(const struct link *plink, long *nelements)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
*nelements = paddr->no_elements;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
DBADDR *paddr = ppv_link->pvt;
|
||||
dbCommon *precord = plink->value.pv_link.precord;
|
||||
long status;
|
||||
|
||||
/* scan passive records if link is process passive */
|
||||
if (ppv_link->pvlMask & pvlOptPP) {
|
||||
unsigned char pact = precord->pact;
|
||||
|
||||
precord->pact = TRUE;
|
||||
status = dbScanPassive(precord, paddr->precord);
|
||||
precord->pact = pact;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
*pstat = paddr->precord->stat;
|
||||
*psevr = paddr->precord->sevr;
|
||||
|
||||
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
} else {
|
||||
unsigned short dbfType = paddr->field_type;
|
||||
|
||||
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
|
||||
return S_db_badDbrtype;
|
||||
|
||||
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
|
||||
&& paddr->special != SPC_DBADDR
|
||||
&& paddr->special != SPC_ATTRIBUTE) {
|
||||
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
|
||||
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
|
||||
} else {
|
||||
ppv_link->getCvt = NULL;
|
||||
status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
|
||||
}
|
||||
ppv_link->lastGetdbrType = dbrType;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static long dbDbGetControlLimits(const struct link *plink, double *low,
|
||||
double *high)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRctrlDouble
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_CTRL_DOUBLE;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
NULL);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*low = buffer.lower_ctrl_limit;
|
||||
*high = buffer.upper_ctrl_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
|
||||
double *high)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRgrDouble
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_GR_DOUBLE;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
NULL);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*low = buffer.lower_disp_limit;
|
||||
*high = buffer.upper_disp_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
|
||||
double *low, double *high, double *hihi)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRalDouble
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_AL_DOUBLE;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
0);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*lolo = buffer.lower_alarm_limit;
|
||||
*low = buffer.lower_warning_limit;
|
||||
*high = buffer.upper_warning_limit;
|
||||
*hihi = buffer.upper_alarm_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetPrecision(const struct link *plink, short *precision)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRprecision
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_PRECISION;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
0);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*precision = (short) buffer.precision.dp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
struct buffer {
|
||||
DBRunits
|
||||
double value;
|
||||
} buffer;
|
||||
long options = DBR_UNITS;
|
||||
long number_elements = 0;
|
||||
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
|
||||
0);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
strncpy(units, buffer.units, unitsSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
if (status)
|
||||
*status = paddr->precord->stat;
|
||||
if (severity)
|
||||
*severity = paddr->precord->sevr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
|
||||
{
|
||||
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
|
||||
|
||||
*pstamp = paddr->precord->time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dbDbPutValue(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest)
|
||||
{
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
struct dbCommon *psrce = ppv_link->precord;
|
||||
DBADDR *paddr = (DBADDR *) ppv_link->pvt;
|
||||
dbCommon *pdest = paddr->precord;
|
||||
long status = dbPut(paddr, dbrType, pbuffer, nRequest);
|
||||
|
||||
inherit_severity(ppv_link, pdest, psrce->nsta, psrce->nsev);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (paddr->pfield == (void *) &pdest->proc ||
|
||||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
|
||||
/* if dbPutField caused asyn record to process */
|
||||
/* ask for reprocessing*/
|
||||
if (pdest->putf) {
|
||||
pdest->rpro = TRUE;
|
||||
} else { /* process dest record with source's PACT true */
|
||||
unsigned char pact;
|
||||
|
||||
if (psrce && psrce->ppn)
|
||||
dbNotifyAdd(psrce, pdest);
|
||||
pact = psrce->pact;
|
||||
psrce->pact = TRUE;
|
||||
status = dbProcess(pdest);
|
||||
psrce->pact = pact;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dbDbScanFwdLink(struct link *plink)
|
||||
{
|
||||
dbCommon *precord = plink->value.pv_link.precord;
|
||||
dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
|
||||
|
||||
dbScanPassive(precord, paddr->precord);
|
||||
}
|
||||
|
||||
lset dbDb_lset = { dbDbInitLink, dbDbAddLink, NULL, dbDbRemoveLink,
|
||||
dbDbIsLinkConnected, dbDbGetDBFtype, dbDbGetElements, dbDbGetValue,
|
||||
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
|
||||
dbDbGetPrecision, dbDbGetUnits, dbDbGetAlarm, dbDbGetTimeStamp,
|
||||
dbDbPutValue, dbDbScanFwdLink };
|
||||
|
||||
/***************************** Generic Link API *****************************/
|
||||
|
||||
void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
void dbInitLink(struct link *plink, short dbfType)
|
||||
{
|
||||
plink->value.pv_link.precord = precord;
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
/* Only initialize link once */
|
||||
if (plink->flags & DBLINK_FLAG_INITIALIZED)
|
||||
return;
|
||||
else
|
||||
plink->flags |= DBLINK_FLAG_INITIALIZED;
|
||||
|
||||
if (plink->type == CONSTANT) {
|
||||
dbConstInitLink(plink);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type == JSON_LINK) {
|
||||
dbJLinkInit(plink);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type != PV_LINK)
|
||||
return;
|
||||
|
||||
if (plink == &precord->tsel)
|
||||
recGblTSELwasModified(plink);
|
||||
@@ -425,7 +105,7 @@ void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
if (dbfType == DBF_INLINK)
|
||||
plink->value.pv_link.pvlMask |= pvlOptInpNative;
|
||||
|
||||
dbCaAddLink(plink);
|
||||
dbCaAddLink(NULL, plink, dbfType);
|
||||
if (dbfType == DBF_FWDLINK) {
|
||||
char *pperiod = strrchr(plink->value.pv_link.pvname, '.');
|
||||
|
||||
@@ -442,24 +122,42 @@ void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
}
|
||||
}
|
||||
|
||||
void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
|
||||
DBADDR *ptarget)
|
||||
{
|
||||
plink->value.pv_link.precord = precord;
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
if (plink->type == CONSTANT) {
|
||||
dbConstAddLink(plink);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type == JSON_LINK) {
|
||||
/*
|
||||
* FIXME: Can't create DB links as dbJLink types yet,
|
||||
* dbLock.c doesn't have any way to find/track them.
|
||||
*/
|
||||
dbJLinkInit(plink);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plink->type != PV_LINK)
|
||||
return;
|
||||
|
||||
if (plink == &precord->tsel)
|
||||
recGblTSELwasModified(plink);
|
||||
|
||||
if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
|
||||
/* Can we make it a DB link? */
|
||||
if (!dbDbAddLink(plink, dbfType))
|
||||
return;
|
||||
if (ptarget) {
|
||||
/* It's a DB link */
|
||||
dbDbAddLink(locker, plink, dbfType, ptarget);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make it a CA link */
|
||||
if (dbfType == DBF_INLINK)
|
||||
plink->value.pv_link.pvlMask |= pvlOptInpNative;
|
||||
|
||||
dbCaAddLink(plink);
|
||||
dbCaAddLink(locker, plink, dbfType);
|
||||
if (dbfType == DBF_FWDLINK) {
|
||||
char *pperiod = strrchr(plink->value.pv_link.pvname, '.');
|
||||
|
||||
@@ -468,201 +166,240 @@ void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType)
|
||||
}
|
||||
}
|
||||
|
||||
long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
|
||||
void dbLinkOpen(struct link *plink)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
return dbConstLoadLink(plink, dbrType, pbuffer);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (plset && plset->openLink)
|
||||
plset->openLink(plink);
|
||||
}
|
||||
|
||||
void dbRemoveLink(struct link *plink)
|
||||
void dbRemoveLink(struct dbLocker *locker, struct link *plink)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
dbDbRemoveLink(plink);
|
||||
break;
|
||||
case CA_LINK:
|
||||
dbCaRemoveLink(plink);
|
||||
break;
|
||||
default:
|
||||
cantProceed("dbRemoveLink: Unexpected link type %d\n", plink->type);
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (plset) {
|
||||
if (plset->removeLink)
|
||||
plset->removeLink(locker, plink);
|
||||
plink->lset = NULL;
|
||||
}
|
||||
plink->type = PV_LINK;
|
||||
plink->value.pv_link.pvlMask = 0;
|
||||
if (plink->type == JSON_LINK)
|
||||
plink->value.json.jlink = NULL;
|
||||
}
|
||||
|
||||
int dbLinkIsDefined(const struct link *plink)
|
||||
{
|
||||
return (plink->lset != 0);
|
||||
}
|
||||
|
||||
int dbLinkIsConstant(const struct link *plink)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
return !plset || plset->isConstant;
|
||||
}
|
||||
|
||||
int dbLinkIsVolatile(const struct link *plink)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
return plset && plset->isVolatile;
|
||||
}
|
||||
|
||||
long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (plset && plset->loadScalar)
|
||||
return plset->loadScalar(plink, dbrType, pbuffer);
|
||||
|
||||
return S_db_noLSET;
|
||||
}
|
||||
|
||||
long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (plset && plset->loadLS)
|
||||
return plset->loadLS(plink, pbuffer, size, plen);
|
||||
|
||||
return S_db_noLSET;
|
||||
}
|
||||
|
||||
long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (plset && plset->loadArray)
|
||||
return plset->loadArray(plink, dbrType, pbuffer, pnRequest);
|
||||
|
||||
return S_db_noLSET;
|
||||
}
|
||||
|
||||
int dbIsLinkConnected(const struct link *plink)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbIsLinkConnected(plink);
|
||||
case CA_LINK:
|
||||
return dbCaIsLinkConnected(plink);
|
||||
}
|
||||
return FALSE;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->isConnected)
|
||||
return FALSE;
|
||||
|
||||
return plset->isConnected(plink);
|
||||
}
|
||||
|
||||
int dbGetLinkDBFtype(const struct link *plink)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetDBFtype(plink);
|
||||
case CA_LINK:
|
||||
return dbCaGetLinkDBFtype(plink);
|
||||
}
|
||||
return -1;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getDBFtype)
|
||||
return -1;
|
||||
|
||||
return plset->getDBFtype(plink);
|
||||
}
|
||||
|
||||
long dbGetNelements(const struct link *plink, long *nelements)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
return dbConstGetNelements(plink, nelements);
|
||||
case DB_LINK:
|
||||
return dbDbGetElements(plink, nelements);
|
||||
case CA_LINK:
|
||||
return dbCaGetNelements(plink, nelements);
|
||||
}
|
||||
return S_db_badField;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getElements)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getElements(plink, nelements);
|
||||
}
|
||||
|
||||
long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *poptions, long *pnRequest)
|
||||
{
|
||||
struct dbCommon *precord = plink->value.pv_link.precord;
|
||||
epicsEnum16 sevr = 0, stat = 0;
|
||||
struct dbCommon *precord = plink->precord;
|
||||
lset *plset = plink->lset;
|
||||
long status;
|
||||
|
||||
if (poptions && *poptions) {
|
||||
printf("dbGetLinkValue: Use of poptions no longer supported\n");
|
||||
printf("dbGetLink: Use of poptions no longer supported\n");
|
||||
*poptions = 0;
|
||||
}
|
||||
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
status = dbConstGetLink(plink, dbrType, pbuffer, &stat, &sevr,
|
||||
pnRequest);
|
||||
break;
|
||||
case DB_LINK:
|
||||
status = dbDbGetValue(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
|
||||
break;
|
||||
case CA_LINK:
|
||||
status = dbCaGetLink(plink, dbrType, pbuffer, &stat, &sevr, pnRequest);
|
||||
break;
|
||||
default:
|
||||
cantProceed("dbGetLinkValue: Illegal link type %d\n", plink->type);
|
||||
status = -1;
|
||||
}
|
||||
if (status) {
|
||||
if (!plset || !plset->getValue)
|
||||
return -1;
|
||||
|
||||
status = plset->getValue(plink, dbrType, pbuffer, pnRequest);
|
||||
if (status)
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
} else {
|
||||
inherit_severity(&plink->value.pv_link, precord, stat, sevr);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
long dbGetControlLimits(const struct link *plink, double *low, double *high)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetControlLimits(plink, low, high);
|
||||
case CA_LINK:
|
||||
return dbCaGetControlLimits(plink, low, high);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getControlLimits)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getControlLimits(plink, low, high);
|
||||
}
|
||||
|
||||
long dbGetGraphicLimits(const struct link *plink, double *low, double *high)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetGraphicLimits(plink, low, high);
|
||||
case CA_LINK:
|
||||
return dbCaGetGraphicLimits(plink, low, high);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getGraphicLimits)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getGraphicLimits(plink, low, high);
|
||||
}
|
||||
|
||||
long dbGetAlarmLimits(const struct link *plink, double *lolo, double *low,
|
||||
double *high, double *hihi)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetAlarmLimits(plink, lolo, low, high, hihi);
|
||||
case CA_LINK:
|
||||
return dbCaGetAlarmLimits(plink, lolo, low, high, hihi);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getAlarmLimits)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getAlarmLimits(plink, lolo, low, high, hihi);
|
||||
}
|
||||
|
||||
long dbGetPrecision(const struct link *plink, short *precision)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetPrecision(plink, precision);
|
||||
case CA_LINK:
|
||||
return dbCaGetPrecision(plink, precision);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getPrecision)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getPrecision(plink, precision);
|
||||
}
|
||||
|
||||
long dbGetUnits(const struct link *plink, char *units, int unitsSize)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetUnits(plink, units, unitsSize);
|
||||
case CA_LINK:
|
||||
return dbCaGetUnits(plink, units, unitsSize);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getUnits)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getUnits(plink, units, unitsSize);
|
||||
}
|
||||
|
||||
long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetAlarm(plink, status, severity);
|
||||
case CA_LINK:
|
||||
return dbCaGetAlarm(plink, status, severity);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getAlarm)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getAlarm(plink, status, severity);
|
||||
}
|
||||
|
||||
long dbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
return dbDbGetTimeStamp(plink, pstamp);
|
||||
case CA_LINK:
|
||||
return dbCaGetTimeStamp(plink, pstamp);
|
||||
}
|
||||
return S_db_notFound;
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!plset || !plset->getTimeStamp)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->getTimeStamp(plink, pstamp);
|
||||
}
|
||||
|
||||
long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
|
||||
long nRequest)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
long status;
|
||||
|
||||
switch (plink->type) {
|
||||
case CONSTANT:
|
||||
status = 0;
|
||||
break;
|
||||
case DB_LINK:
|
||||
status = dbDbPutValue(plink, dbrType, pbuffer, nRequest);
|
||||
break;
|
||||
case CA_LINK:
|
||||
status = dbCaPutLink(plink, dbrType, pbuffer, nRequest);
|
||||
break;
|
||||
default:
|
||||
cantProceed("dbPutLinkValue: Illegal link type %d\n", plink->type);
|
||||
status = -1;
|
||||
}
|
||||
if (!plset || !plset->putValue)
|
||||
return S_db_noLSET;
|
||||
|
||||
status = plset->putValue(plink, dbrType, pbuffer, nRequest);
|
||||
if (status) {
|
||||
struct dbCommon *precord = plink->value.pv_link.precord;
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void dbLinkAsyncComplete(struct link *plink)
|
||||
{
|
||||
dbCommon *pdbCommon = plink->precord;
|
||||
|
||||
dbScanLock(pdbCommon);
|
||||
pdbCommon->rset->process(pdbCommon);
|
||||
dbScanUnlock(pdbCommon);
|
||||
}
|
||||
|
||||
long dbPutLinkAsync(struct link *plink, short dbrType, const void *pbuffer,
|
||||
long nRequest)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
long status;
|
||||
|
||||
if (!plset || !plset->putAsync)
|
||||
return S_db_noLSET;
|
||||
|
||||
status = plset->putAsync(plink, dbrType, pbuffer, nRequest);
|
||||
if (status) {
|
||||
struct dbCommon *precord = plink->precord;
|
||||
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
}
|
||||
@@ -671,32 +408,26 @@ long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
|
||||
|
||||
void dbScanFwdLink(struct link *plink)
|
||||
{
|
||||
switch (plink->type) {
|
||||
case DB_LINK:
|
||||
dbDbScanFwdLink(plink);
|
||||
break;
|
||||
case CA_LINK:
|
||||
dbCaScanFwdLink(plink);
|
||||
break;
|
||||
}
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (plset && plset->scanForward)
|
||||
plset->scanForward(plink);
|
||||
}
|
||||
|
||||
long dbLinkDoLocked(struct link *plink, dbLinkUserCallback rtn,
|
||||
void *priv)
|
||||
{
|
||||
lset *plset = plink->lset;
|
||||
|
||||
if (!rtn || !plset || !plset->doLocked)
|
||||
return S_db_noLSET;
|
||||
|
||||
return plset->doLocked(plink, rtn, priv);
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions for long string support */
|
||||
|
||||
long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
if (plink->type == CONSTANT &&
|
||||
plink->value.constantStr) {
|
||||
strncpy(pbuffer, plink->value.constantStr, --size);
|
||||
pbuffer[size] = 0;
|
||||
*plen = (epicsUInt32) strlen(pbuffer) + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return S_db_notFound;
|
||||
}
|
||||
|
||||
long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen)
|
||||
{
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* dbLink.h
|
||||
/* dbLink.h
|
||||
*
|
||||
* Created on: Mar 21, 2010
|
||||
* Author: Andrew Johnson
|
||||
@@ -20,21 +19,42 @@
|
||||
#include "shareLib.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsTime.h"
|
||||
#include "dbAddr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dbLocker;
|
||||
|
||||
typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
|
||||
|
||||
typedef struct lset {
|
||||
long (*initLink)(struct link *plink, short dbfType);
|
||||
long (*addLink)(struct link *plink, short dbfType);
|
||||
long (*loadLink)(struct link *plink, short dbrType, void *pbuffer);
|
||||
void (*removeLink)(struct link *plink);
|
||||
int (*isLinkConnected)(const struct link *plink);
|
||||
/* Characteristics of the link type */
|
||||
const unsigned isConstant:1;
|
||||
const unsigned isVolatile:1;
|
||||
|
||||
/* Activation */
|
||||
void (*openLink)(struct link *plink);
|
||||
|
||||
/* Destructor */
|
||||
void (*removeLink)(struct dbLocker *locker, struct link *plink);
|
||||
|
||||
/* Const init, data type hinting */
|
||||
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
|
||||
long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
|
||||
epicsUInt32 *plen);
|
||||
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
|
||||
long *pnRequest);
|
||||
|
||||
/* Metadata */
|
||||
int (*isConnected)(const struct link *plink);
|
||||
int (*getDBFtype)(const struct link *plink);
|
||||
long (*getElements)(const struct link *plink, long *nelements);
|
||||
|
||||
/* Get data */
|
||||
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
|
||||
epicsEnum16 *pstat, epicsEnum16 *psevr, long *pnRequest);
|
||||
long *pnRequest);
|
||||
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
|
||||
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
|
||||
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
|
||||
@@ -44,23 +64,41 @@ typedef struct lset {
|
||||
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity);
|
||||
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
|
||||
|
||||
/* Put data */
|
||||
long (*putValue)(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
void (*scanFwdLink)(struct link *plink);
|
||||
long (*putAsync)(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
|
||||
/* Process */
|
||||
void (*scanForward)(struct link *plink);
|
||||
|
||||
/* Atomicity */
|
||||
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
|
||||
} lset;
|
||||
|
||||
#define dbGetSevr(PLINK, PSEVERITY) \
|
||||
dbGetAlarm((PLINK), NULL, (PSEVERITY))
|
||||
#define dbGetSevr(link, sevr) \
|
||||
dbGetAlarm(link, NULL, sevr)
|
||||
|
||||
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
|
||||
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
|
||||
short dbfType, DBADDR *ptarget);
|
||||
|
||||
epicsShareFunc void dbLinkOpen(struct link *plink);
|
||||
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
|
||||
|
||||
epicsShareFunc int dbLinkIsDefined(const struct link *plink); /* 0 or 1 */
|
||||
epicsShareFunc int dbLinkIsConstant(const struct link *plink); /* 0 or 1 */
|
||||
epicsShareFunc int dbLinkIsVolatile(const struct link *plink); /* 0 or 1 */
|
||||
|
||||
epicsShareFunc void dbInitLink(struct dbCommon *precord, struct link *plink,
|
||||
short dbfType);
|
||||
epicsShareFunc void dbAddLink(struct dbCommon *precord, struct link *plink,
|
||||
short dbfType);
|
||||
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
|
||||
void *pbuffer);
|
||||
epicsShareFunc void dbRemoveLink(struct link *plink);
|
||||
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
|
||||
long *pnRequest);
|
||||
|
||||
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
|
||||
epicsShareFunc int dbIsLinkConnected(const struct link *plink);
|
||||
epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
|
||||
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
|
||||
epicsShareFunc long dbGetLink(struct link *, short dbrType, void *pbuffer,
|
||||
long *options, long *nRequest);
|
||||
@@ -77,10 +115,16 @@ epicsShareFunc long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity);
|
||||
epicsShareFunc long dbGetTimeStamp(const struct link *plink,
|
||||
epicsTimeStamp *pstamp);
|
||||
epicsShareFunc long dbPutLink(struct link *, short dbrType,
|
||||
epicsShareFunc long dbPutLink(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
epicsShareFunc void dbLinkAsyncComplete(struct link *plink);
|
||||
epicsShareFunc long dbPutLinkAsync(struct link *plink, short dbrType,
|
||||
const void *pbuffer, long nRequest);
|
||||
epicsShareFunc void dbScanFwdLink(struct link *plink);
|
||||
|
||||
epicsShareFunc long dbLinkDoLocked(struct link *plink, dbLinkUserCallback rtn,
|
||||
void *priv);
|
||||
|
||||
epicsShareFunc long dbLoadLinkLS(struct link *plink, char *pbuffer,
|
||||
epicsUInt32 size, epicsUInt32 *plen);
|
||||
epicsShareFunc long dbGetLinkLS(struct link *plink, char *pbuffer,
|
||||
|
||||
1286
src/ioc/db/dbLock.c
1286
src/ioc/db/dbLock.c
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@
|
||||
#ifndef INCdbLockh
|
||||
#define INCdbLockh
|
||||
|
||||
#include "ellLib.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -21,21 +22,26 @@ extern "C" {
|
||||
|
||||
struct dbCommon;
|
||||
struct dbBase;
|
||||
typedef struct dbLocker dbLocker;
|
||||
|
||||
epicsShareFunc void dbScanLock(struct dbCommon *precord);
|
||||
epicsShareFunc void dbScanUnlock(struct dbCommon *precord);
|
||||
|
||||
epicsShareFunc dbLocker *dbLockerAlloc(struct dbCommon * const *precs,
|
||||
size_t nrecs,
|
||||
unsigned int flags);
|
||||
|
||||
epicsShareFunc void dbLockerFree(dbLocker *);
|
||||
|
||||
epicsShareFunc void dbScanLockMany(dbLocker*);
|
||||
epicsShareFunc void dbScanUnlockMany(dbLocker*);
|
||||
|
||||
epicsShareFunc unsigned long dbLockGetLockId(
|
||||
struct dbCommon *precord);
|
||||
|
||||
epicsShareFunc void dbLockInitRecords(struct dbBase *pdbbase);
|
||||
epicsShareFunc void dbLockCleanupRecords(struct dbBase *pdbbase);
|
||||
epicsShareFunc void dbLockSetMerge(
|
||||
struct dbCommon *pfirst,struct dbCommon *psecond);
|
||||
epicsShareFunc void dbLockSetSplit(struct dbCommon *psource);
|
||||
/*The following are for code that modifies lock sets*/
|
||||
epicsShareFunc void dbLockSetGblLock(void);
|
||||
epicsShareFunc void dbLockSetGblUnlock(void);
|
||||
epicsShareFunc void dbLockSetRecordLock(struct dbCommon *precord);
|
||||
|
||||
|
||||
/* Lock Set Report */
|
||||
epicsShareFunc long dblsr(char *recordname,int level);
|
||||
@@ -47,6 +53,10 @@ epicsShareFunc long dbLockShowLocked(int level);
|
||||
/*KLUDGE to support field TPRO*/
|
||||
epicsShareFunc int * dbLockSetAddrTrace(struct dbCommon *precord);
|
||||
|
||||
/* debugging */
|
||||
epicsShareFunc unsigned long dbLockGetRefs(struct dbCommon*);
|
||||
epicsShareFunc unsigned long dbLockCountSets(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
110
src/ioc/db/dbLockPvt.h
Normal file
110
src/ioc/db/dbLockPvt.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2014 Brookhaven Science Assoc., as Operator of Brookhaven
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef DBLOCKPVT_H
|
||||
#define DBLOCKPVT_H
|
||||
|
||||
#include "dbLock.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
/* Define to enable additional error checking */
|
||||
#undef LOCKSET_DEBUG
|
||||
|
||||
/* Define to disable the free list for lockSets */
|
||||
#undef LOCKSET_NOFREE
|
||||
|
||||
/* Define to disable use of recomputeCnt optimization */
|
||||
#undef LOCKSET_NOCNT
|
||||
|
||||
/* except for refcount (and lock), all members of dbLockSet
|
||||
* are guarded by its lock.
|
||||
*/
|
||||
typedef struct dbLockSet {
|
||||
ELLNODE node;
|
||||
ELLLIST lockRecordList; /* holds lockRecord::node */
|
||||
epicsMutexId lock;
|
||||
unsigned long id;
|
||||
|
||||
int refcount;
|
||||
#ifdef LOCKSET_DEBUG
|
||||
int ownercount;
|
||||
epicsThreadId owner;
|
||||
#endif
|
||||
dbLocker *ownerlocker;
|
||||
ELLNODE lockernode;
|
||||
|
||||
int trace; /*For field TPRO*/
|
||||
} lockSet;
|
||||
|
||||
struct lockRecord;
|
||||
|
||||
/* dbCommon.LSET is a plockRecord.
|
||||
* Except for spin and plockSet, all members of lockRecord are guarded
|
||||
* by the present lockset lock.
|
||||
* plockSet is guarded by spin.
|
||||
*/
|
||||
typedef struct lockRecord {
|
||||
ELLNODE node; /* in lockSet::lockRecordList */
|
||||
/* The association between lockRecord and lockSet
|
||||
* can only be changed while the lockSet is held,
|
||||
* and the lockRecord's spinlock is held.
|
||||
* It may be read which either lock is held.
|
||||
*/
|
||||
lockSet *plockSet;
|
||||
/* the association between lockRecord and dbCommon never changes */
|
||||
dbCommon *precord;
|
||||
epicsSpinId spin;
|
||||
|
||||
/* temp used during lockset split.
|
||||
* lockSet must be locked for access
|
||||
*/
|
||||
ELLNODE compnode;
|
||||
unsigned int compflag;
|
||||
} lockRecord;
|
||||
|
||||
typedef struct {
|
||||
lockRecord *plr;
|
||||
/* the last lock found associated with the ref.
|
||||
* not stable unless lock is locked, or ref spin
|
||||
* is locked.
|
||||
*/
|
||||
lockSet *plockSet;
|
||||
} lockRecordRef;
|
||||
|
||||
#define DBLOCKER_NALLOC 2
|
||||
/* a dbLocker can only be used by a single thread. */
|
||||
struct dbLocker {
|
||||
ELLLIST locked;
|
||||
#ifndef LOCKSET_NOCNT
|
||||
size_t recomp; /* snapshot of recomputeCnt when refs[] cache updated */
|
||||
#endif
|
||||
size_t maxrefs;
|
||||
lockRecordRef refs[DBLOCKER_NALLOC]; /* actual length is maxrefs */
|
||||
};
|
||||
|
||||
/* These are exported for testing only */
|
||||
epicsShareFunc lockSet* dbLockGetRef(lockRecord *lr); /* lookup lockset and increment ref count */
|
||||
epicsShareFunc void dbLockIncRef(lockSet* ls);
|
||||
epicsShareFunc void dbLockDecRef(lockSet *ls);
|
||||
|
||||
/* Calling dbLockerPrepare directly is an internal
|
||||
* optimization used when dbLocker on the stack.
|
||||
* nrecs must be <=DBLOCKER_NALLOC.
|
||||
*/
|
||||
void dbLockerPrepare(struct dbLocker *locker,
|
||||
struct dbCommon * const *precs,
|
||||
size_t nrecs);
|
||||
void dbLockerFinalize(dbLocker *);
|
||||
|
||||
void dbLockSetMerge(struct dbLocker *locker,
|
||||
struct dbCommon *pfirst,
|
||||
struct dbCommon *psecond);
|
||||
void dbLockSetSplit(struct dbLocker *locker,
|
||||
struct dbCommon *psource,
|
||||
struct dbCommon *psecond);
|
||||
|
||||
#endif /* DBLOCKPVT_H */
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "ellLib.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsThread.h"
|
||||
@@ -109,6 +108,15 @@ static void notifyCallback(CALLBACK *pcallback);
|
||||
(listnode)->isOnList=0; \
|
||||
}
|
||||
|
||||
static void notifyFree(void *raw)
|
||||
{
|
||||
notifyPvt *pnotifyPvt = raw;
|
||||
assert(pnotifyPvt->magic==MAGIC);
|
||||
epicsEventDestroy(pnotifyPvt->cancelEvent);
|
||||
epicsEventDestroy(pnotifyPvt->userCallbackEvent);
|
||||
free(pnotifyPvt);
|
||||
}
|
||||
|
||||
static void notifyInit(processNotify *ppn)
|
||||
{
|
||||
notifyPvt *pnotifyPvt;
|
||||
@@ -301,7 +309,7 @@ static void notifyCallback(CALLBACK *pcallback)
|
||||
|
||||
void dbProcessNotifyExit(void)
|
||||
{
|
||||
assert(ellCount(&pnotifyGlobal->freeList)==0);
|
||||
ellFree2(&pnotifyGlobal->freeList, ¬ifyFree);
|
||||
epicsMutexDestroy(pnotifyGlobal->lock);
|
||||
free(pnotifyGlobal);
|
||||
pnotifyGlobal = NULL;
|
||||
|
||||
@@ -25,11 +25,9 @@
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsInterrupt.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "epicsRingPointer.h"
|
||||
#include "epicsRingBytes.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsString.h"
|
||||
@@ -64,7 +62,7 @@ static volatile enum ctl scanCtl;
|
||||
|
||||
static int onceQueueSize = 1000;
|
||||
static epicsEventId onceSem;
|
||||
static epicsRingPointerId onceQ;
|
||||
static epicsRingBytesId onceQ;
|
||||
static epicsThreadId onceTaskId;
|
||||
static void *exitOnce;
|
||||
|
||||
@@ -179,7 +177,7 @@ void scanCleanup(void)
|
||||
deletePeriodic();
|
||||
ioscanDestroy();
|
||||
|
||||
epicsRingPointerDelete(onceQ);
|
||||
epicsRingBytesDelete(onceQ);
|
||||
|
||||
free(periodicTaskId);
|
||||
papPeriodic = NULL;
|
||||
@@ -490,7 +488,9 @@ event_list *eventNameToHandle(const char *eventname)
|
||||
if (strcmp(pel->event_name, eventname) == 0) break;
|
||||
}
|
||||
if (pel == NULL) {
|
||||
pel = dbCalloc(1, sizeof(event_list));
|
||||
pel = calloc(1, sizeof(event_list));
|
||||
if (!pel)
|
||||
goto done;
|
||||
strcpy(pel->event_name, eventname);
|
||||
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
|
||||
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
|
||||
@@ -508,6 +508,7 @@ event_list *eventNameToHandle(const char *eventname)
|
||||
pevent_list[e] = pel;
|
||||
}
|
||||
}
|
||||
done:
|
||||
epicsMutexUnlock(event_lock);
|
||||
return pel;
|
||||
}
|
||||
@@ -614,6 +615,28 @@ unsigned int scanIoRequest(IOSCANPVT piosh)
|
||||
return queued;
|
||||
}
|
||||
|
||||
unsigned int scanIoImmediate(IOSCANPVT piosh, int prio)
|
||||
{
|
||||
io_scan_list *piosl;
|
||||
|
||||
if (prio<0 || prio>=NUM_CALLBACK_PRIORITIES)
|
||||
return S_db_errArg;
|
||||
else if (scanCtl != ctlRun)
|
||||
return 0;
|
||||
|
||||
piosl = &piosh->iosl[prio];
|
||||
|
||||
if (ellCount(&piosl->scan_list.list) == 0)
|
||||
return 0;
|
||||
|
||||
scanList(&piosl->scan_list);
|
||||
|
||||
if (piosh->cb)
|
||||
piosh->cb(piosh->arg, piosh, prio);
|
||||
|
||||
return 1 << prio;
|
||||
}
|
||||
|
||||
/* May not be called while a scan request is queued or running */
|
||||
void scanIoSetComplete(IOSCANPVT piosh, io_scan_complete cb, void *arg)
|
||||
{
|
||||
@@ -621,15 +644,27 @@ void scanIoSetComplete(IOSCANPVT piosh, io_scan_complete cb, void *arg)
|
||||
piosh->arg = arg;
|
||||
}
|
||||
|
||||
void scanOnce(struct dbCommon *precord)
|
||||
int scanOnce(struct dbCommon *precord) {
|
||||
return scanOnceCallback(precord, NULL, NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct dbCommon *prec;
|
||||
once_complete cb;
|
||||
void *usr;
|
||||
} onceEntry;
|
||||
|
||||
int scanOnceCallback(struct dbCommon *precord, once_complete cb, void *usr)
|
||||
{
|
||||
static int newOverflow = TRUE;
|
||||
int lockKey;
|
||||
onceEntry ent;
|
||||
int pushOK;
|
||||
|
||||
lockKey = epicsInterruptLock();
|
||||
pushOK = epicsRingPointerPush(onceQ, precord);
|
||||
epicsInterruptUnlock(lockKey);
|
||||
ent.prec = precord;
|
||||
ent.cb = cb;
|
||||
ent.usr = usr;
|
||||
|
||||
pushOK = epicsRingBytesPut(onceQ, (void*)&ent, sizeof(ent));
|
||||
|
||||
if (!pushOK) {
|
||||
if (newOverflow) errlogPrintf("scanOnce: Ring buffer overflow\n");
|
||||
@@ -638,6 +673,8 @@ void scanOnce(struct dbCommon *precord)
|
||||
newOverflow = TRUE;
|
||||
}
|
||||
epicsEventSignal(onceSem);
|
||||
|
||||
return !pushOK;
|
||||
}
|
||||
|
||||
static void onceTask(void *arg)
|
||||
@@ -646,14 +683,24 @@ static void onceTask(void *arg)
|
||||
epicsEventSignal(startStopEvent);
|
||||
|
||||
while (TRUE) {
|
||||
void *precord;
|
||||
|
||||
epicsEventMustWait(onceSem);
|
||||
while ((precord = epicsRingPointerPop(onceQ))) {
|
||||
if (precord == &exitOnce) goto shutdown;
|
||||
dbScanLock(precord);
|
||||
dbProcess(precord);
|
||||
dbScanUnlock(precord);
|
||||
while(1) {
|
||||
onceEntry ent;
|
||||
int bytes = epicsRingBytesGet(onceQ, (void*)&ent, sizeof(ent));
|
||||
if(bytes==0)
|
||||
break;
|
||||
if(bytes!=sizeof(ent)) {
|
||||
errlogPrintf("onceTask: received incomplete %d of %u\n",
|
||||
bytes, (unsigned)sizeof(ent));
|
||||
continue; /* what to do? */
|
||||
} else if (ent.prec == (void*)&exitOnce) goto shutdown;
|
||||
|
||||
dbScanLock(ent.prec);
|
||||
dbProcess(ent.prec);
|
||||
dbScanUnlock(ent.prec);
|
||||
if(ent.cb)
|
||||
ent.cb(ent.usr, ent.prec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,7 +717,7 @@ int scanOnceSetQueueSize(int size)
|
||||
|
||||
static void initOnce(void)
|
||||
{
|
||||
if ((onceQ = epicsRingPointerCreate(onceQueueSize)) == NULL) {
|
||||
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
|
||||
cantProceed("initOnce: Ring buffer create failed\n");
|
||||
}
|
||||
if(!onceSem)
|
||||
@@ -855,9 +902,11 @@ static void spawnPeriodic(int ind)
|
||||
|
||||
static void ioscanCallback(CALLBACK *pcallback)
|
||||
{
|
||||
ioscan_head *piosh = (ioscan_head *) pcallback->user;
|
||||
int prio = pcallback->priority;
|
||||
ioscan_head *piosh;
|
||||
int prio;
|
||||
|
||||
callbackGetUser(piosh, pcallback);
|
||||
callbackGetPriority(prio, pcallback);
|
||||
scanList(&piosh->iosl[prio].scan_list);
|
||||
if (piosh->cb)
|
||||
piosh->cb(piosh->arg, piosh, prio);
|
||||
|
||||
@@ -38,10 +38,11 @@ struct ioscan_head;
|
||||
typedef struct ioscan_head *IOSCANPVT;
|
||||
typedef struct event_list *EVENTPVT;
|
||||
|
||||
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
|
||||
|
||||
struct dbCommon;
|
||||
|
||||
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
|
||||
typedef void (*once_complete)(void *usr, struct dbCommon*);
|
||||
|
||||
epicsShareFunc long scanInit(void);
|
||||
epicsShareFunc void scanRun(void);
|
||||
epicsShareFunc void scanPause(void);
|
||||
@@ -54,7 +55,8 @@ epicsShareFunc void post_event(int event) EPICS_DEPRECATED;
|
||||
epicsShareFunc void scanAdd(struct dbCommon *);
|
||||
epicsShareFunc void scanDelete(struct dbCommon *);
|
||||
epicsShareFunc double scanPeriod(int scan);
|
||||
epicsShareFunc void scanOnce(struct dbCommon *);
|
||||
epicsShareFunc int scanOnce(struct dbCommon *);
|
||||
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
|
||||
epicsShareFunc int scanOnceSetQueueSize(int size);
|
||||
|
||||
/*print periodic lists*/
|
||||
@@ -68,6 +70,7 @@ epicsShareFunc int scanpiol(void);
|
||||
|
||||
epicsShareFunc void scanIoInit(IOSCANPVT *ppios);
|
||||
epicsShareFunc unsigned int scanIoRequest(IOSCANPVT pios);
|
||||
epicsShareFunc unsigned int scanIoImmediate(IOSCANPVT pios, int prio);
|
||||
epicsShareFunc void scanIoSetComplete(IOSCANPVT, io_scan_complete, void *usr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cvtFast.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsMutex.h"
|
||||
@@ -72,13 +73,13 @@ static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size);
|
||||
|
||||
static char *dbf[DBF_NTYPES] = {
|
||||
"STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG",
|
||||
"FLOAT","DOUBLE","ENUM","MENU","DEVICE",
|
||||
"INT64","UINT64","FLOAT","DOUBLE","ENUM","MENU","DEVICE",
|
||||
"INLINK","OUTLINK","FWDLINK","NOACCESS"
|
||||
};
|
||||
|
||||
static char *dbr[DBR_ENUM+2] = {
|
||||
"STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG",
|
||||
"FLOAT","DOUBLE","ENUM","NOACCESS"
|
||||
"INT64","UINT64","FLOAT","DOUBLE","ENUM","NOACCESS"
|
||||
};
|
||||
|
||||
long dba(const char*pname)
|
||||
@@ -484,6 +485,16 @@ long dbtgf(const char *pname)
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_INT64;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_UINT64;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
|
||||
|
||||
dbr_type = DBR_FLOAT;
|
||||
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
|
||||
status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
|
||||
@@ -510,17 +521,7 @@ long dbtpf(const char *pname, const char *pvalue)
|
||||
long buffer[100];
|
||||
long *pbuffer = buffer;
|
||||
DBADDR addr;
|
||||
long status = 0;
|
||||
long options, no_elements;
|
||||
char *pend;
|
||||
long val_long;
|
||||
int validLong;
|
||||
unsigned long val_ulong;
|
||||
int validULong;
|
||||
int valid = 1;
|
||||
int put_type;
|
||||
epicsFloat32 fvalue;
|
||||
epicsFloat64 dvalue;
|
||||
static TAB_BUFFER msg_Buff;
|
||||
TAB_BUFFER *pMsgBuff = &msg_Buff;
|
||||
char *pmsg = pMsgBuff->message;
|
||||
@@ -530,91 +531,90 @@ long dbtpf(const char *pname, const char *pvalue)
|
||||
printf("Usage: dbtpf \"pv name\", \"value\"\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nameToAddr(pname, &addr))
|
||||
return -1;
|
||||
|
||||
val_long = strtol(pvalue, &pend, 10);
|
||||
validLong = (*pend == 0);
|
||||
|
||||
val_ulong = strtoul(pvalue, &pend, 10);
|
||||
validULong = (*pend == 0);
|
||||
|
||||
for (put_type = DBR_STRING; put_type <= DBF_ENUM; put_type++) {
|
||||
union {
|
||||
epicsInt8 i8;
|
||||
epicsUInt8 u8;
|
||||
epicsInt16 i16;
|
||||
epicsUInt16 u16;
|
||||
epicsInt32 i32;
|
||||
epicsUInt32 u32;
|
||||
epicsInt64 i64;
|
||||
epicsUInt64 u64;
|
||||
epicsFloat32 f32;
|
||||
epicsFloat64 f64;
|
||||
epicsEnum16 e16;
|
||||
} val;
|
||||
const void *pval = &val;
|
||||
int valid = 1;
|
||||
|
||||
switch (put_type) {
|
||||
case DBR_STRING:
|
||||
status = dbPutField(&addr, put_type, pvalue, 1L);
|
||||
pval = pvalue;
|
||||
break;
|
||||
case DBR_CHAR:
|
||||
if ((valid = validLong)) {
|
||||
epicsInt8 val_i8 = (epicsInt8)val_long;
|
||||
status = dbPutField(&addr, put_type, &val_i8, 1L);
|
||||
}
|
||||
valid = !epicsParseInt8(pvalue, &val.i8, 10, NULL);
|
||||
break;
|
||||
case DBR_UCHAR:
|
||||
if ((valid = validULong)) {
|
||||
epicsUInt8 val_u8 = (epicsUInt8)val_ulong;
|
||||
status = dbPutField(&addr, put_type, &val_u8, 1L);
|
||||
}
|
||||
valid = !epicsParseUInt8(pvalue, &val.u8, 10, NULL);
|
||||
break;
|
||||
case DBR_SHORT:
|
||||
if ((valid = validLong)) {
|
||||
epicsInt16 val_i16 = (epicsInt16) val_long;
|
||||
status = dbPutField(&addr, put_type, &val_i16,1L);
|
||||
}
|
||||
valid = !epicsParseInt16(pvalue, &val.i16, 10, NULL);
|
||||
break;
|
||||
case DBR_USHORT:
|
||||
if ((valid = validULong)) {
|
||||
epicsUInt16 val_u16 = (epicsUInt16) val_ulong;
|
||||
status = dbPutField(&addr, put_type, &val_u16, 1L);
|
||||
}
|
||||
valid = !epicsParseUInt16(pvalue, &val.u16, 10, NULL);
|
||||
break;
|
||||
case DBR_LONG:
|
||||
if ((valid = validLong)) {
|
||||
epicsInt32 val_i32 = val_long;
|
||||
status = dbPutField(&addr, put_type,&val_i32,1L);
|
||||
}
|
||||
valid = !epicsParseInt32(pvalue, &val.i32, 10, NULL);
|
||||
break;
|
||||
case DBR_ULONG:
|
||||
if ((valid = validULong)) {
|
||||
epicsUInt32 val_u32 = val_ulong;
|
||||
status = dbPutField(&addr, put_type, &val_u32, 1L);
|
||||
}
|
||||
valid = !epicsParseUInt32(pvalue, &val.u32, 10, NULL);
|
||||
break;
|
||||
case DBR_INT64:
|
||||
valid = !epicsParseInt64(pvalue, &val.i64, 10, NULL);
|
||||
break;
|
||||
case DBR_UINT64:
|
||||
valid = !epicsParseUInt64(pvalue, &val.u64, 10, NULL);
|
||||
break;
|
||||
case DBR_FLOAT:
|
||||
if ((valid = epicsScanFloat(pvalue, &fvalue) == 1))
|
||||
status = dbPutField(&addr, put_type, &fvalue, 1L);
|
||||
valid = !epicsParseFloat32(pvalue, &val.f32, NULL);
|
||||
break;
|
||||
case DBR_DOUBLE:
|
||||
if ((valid = epicsScanDouble(pvalue, &dvalue) == 1))
|
||||
status = dbPutField(&addr, put_type, &dvalue, 1L);
|
||||
valid = !epicsParseFloat64(pvalue, &val.f64, NULL);
|
||||
break;
|
||||
case DBR_ENUM:
|
||||
if ((valid = validULong)) {
|
||||
epicsEnum16 val_e16 = (epicsEnum16) val_ulong;
|
||||
status = dbPutField(&addr, put_type, &val_e16, 1L);
|
||||
}
|
||||
valid = !epicsParseUInt16(pvalue, &val.e16, 10, NULL);
|
||||
break;
|
||||
}
|
||||
if (valid) {
|
||||
long status = dbPutField(&addr, put_type, pval, 1);
|
||||
|
||||
if (status) {
|
||||
printf("Put as DBR_%s Failed.\n", dbr[put_type]);
|
||||
} else {
|
||||
printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);
|
||||
no_elements = MIN(addr.no_elements,
|
||||
printf("Put as DBR_%-6s Failed.\n", dbr[put_type]);
|
||||
}
|
||||
else {
|
||||
long options = 0;
|
||||
long no_elements = MIN(addr.no_elements,
|
||||
((sizeof(buffer))/addr.field_size));
|
||||
options = 0;
|
||||
|
||||
printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);
|
||||
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
|
||||
&options, &no_elements, NULL);
|
||||
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
|
||||
no_elements, pMsgBuff, tab_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Cvt to DBR_%s failed.\n", dbr[put_type]);
|
||||
}
|
||||
}
|
||||
|
||||
pmsg[0] = '\0';
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dbior(const char *pdrvName,int interest_level)
|
||||
@@ -732,10 +732,8 @@ static void printBuffer(
|
||||
long status, short dbr_type, void *pbuffer, long reqOptions,
|
||||
long retOptions, long no_elements, TAB_BUFFER *pMsgBuff, int tab_size)
|
||||
{
|
||||
epicsInt32 val_i32;
|
||||
epicsUInt32 val_u32;
|
||||
char *pmsg = pMsgBuff->message;
|
||||
size_t i, len;
|
||||
int i;
|
||||
|
||||
if (reqOptions & DBR_STATUS) {
|
||||
if (retOptions & DBR_STATUS) {
|
||||
@@ -898,221 +896,166 @@ static void printBuffer(
|
||||
if (no_elements == 0)
|
||||
return;
|
||||
|
||||
switch (dbr_type) {
|
||||
case (DBR_STRING):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_STRING: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_STRING[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, "DBR_STRING: failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBF_%s: ", dbr[dbr_type]);
|
||||
else
|
||||
sprintf(pmsg, "DBF_%s[%ld]: ", dbr[dbr_type], no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
|
||||
for(i=0; i<no_elements; i++) {
|
||||
len = strlen(pbuffer);
|
||||
if (len > 0) {
|
||||
sprintf(pmsg, " \"%s\"", (char *)pbuffer);
|
||||
if (status != 0) {
|
||||
strcpy(pmsg, "failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
}
|
||||
else {
|
||||
switch (dbr_type) {
|
||||
case DBR_STRING:
|
||||
for(i=0; i<no_elements; i++) {
|
||||
size_t len = strlen(pbuffer);
|
||||
|
||||
strcpy(pmsg, "\"");
|
||||
epicsStrnEscapedFromRaw(pmsg+1, MAXLINE - 3,
|
||||
(char *)pbuffer, len);
|
||||
strcat(pmsg, "\"");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + MAX_STRING_SIZE;
|
||||
}
|
||||
pbuffer = (char *)pbuffer + MAX_STRING_SIZE;
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_CHAR):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_CHAR: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_CHAR[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (no_elements == 1) {
|
||||
val_i32 = *(epicsInt8 *) pbuffer;
|
||||
sprintf(pmsg, "%-9d 0x%-9x", val_i32, val_i32);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < no_elements; i+= MAXLINE - 5) {
|
||||
int width = no_elements - i;
|
||||
if (width > MAXLINE - 5) width = MAXLINE - 5;
|
||||
sprintf(pmsg, " \"%.*s\"", width, (char *)pbuffer + i);
|
||||
if (i + MAXLINE - 5 < no_elements) strcat(pmsg, " +");
|
||||
case DBR_CHAR:
|
||||
if (no_elements == 1) {
|
||||
epicsInt32 val = *(epicsInt8 *) pbuffer;
|
||||
|
||||
if (isprint(val))
|
||||
sprintf(pmsg, "%d = 0x%x = '%c'", val, val & 0xff, val);
|
||||
else
|
||||
sprintf(pmsg, "%d = 0x%x", val, val & 0xff);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
} else {
|
||||
size_t len = epicsStrnLen(pbuffer, no_elements);
|
||||
|
||||
i = 0;
|
||||
while (len > 0) {
|
||||
int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len;
|
||||
|
||||
sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i);
|
||||
len -= chunk;
|
||||
if (len > 0)
|
||||
strcat(pmsg, " +");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case (DBR_UCHAR):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_UCHAR: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_UCHAR[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
case DBR_UCHAR:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsUInt32 val = *(epicsUInt8 *) pbuffer;
|
||||
|
||||
sprintf(pmsg, "%u = 0x%x", val, val);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt8);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_SHORT:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsInt16 val = *(epicsInt16 *) pbuffer;
|
||||
|
||||
sprintf(pmsg, "%hd = 0x%hx", val, val);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsInt16);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_USHORT:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsUInt16 val = *(epicsUInt16 *) pbuffer;
|
||||
|
||||
sprintf(pmsg, "%hu = 0x%hx", val, val);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt16);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_LONG:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsInt32 val = *(epicsInt32 *) pbuffer;
|
||||
|
||||
sprintf(pmsg, "%d = 0x%x", val, val);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsInt32);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_ULONG:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsUInt32 val = *(epicsUInt32 *) pbuffer;
|
||||
|
||||
sprintf(pmsg, "%u = 0x%x", val, val);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt32);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_INT64:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsInt64 val = *(epicsInt64 *) pbuffer;
|
||||
|
||||
pmsg += cvtInt64ToString(val, pmsg);
|
||||
strcpy(pmsg, " = ");
|
||||
pmsg += 3;
|
||||
cvtInt64ToHexString(val, pmsg);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pmsg = pMsgBuff->message;
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsInt64);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_UINT64:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
epicsUInt64 val = *(epicsUInt64 *) pbuffer;
|
||||
|
||||
pmsg += cvtUInt64ToString(val, pmsg);
|
||||
strcpy(pmsg, " = ");
|
||||
pmsg += 3;
|
||||
cvtUInt64ToHexString(val, pmsg);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pmsg = pMsgBuff->message;
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt64);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_FLOAT:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
sprintf(pmsg, "%.6g", *((epicsFloat32 *) pbuffer));
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsFloat32);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_DOUBLE:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
sprintf(pmsg, "%.12g", *((epicsFloat64 *) pbuffer));
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsFloat64);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_ENUM:
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
sprintf(pmsg, "%u", *((epicsEnum16 *) pbuffer));
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsEnum16);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(pmsg, "Bad DBR type %d", dbr_type);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
val_u32 = *(epicsUInt8 *) pbuffer;
|
||||
sprintf(pmsg, "%-9u 0x%-9x", val_u32, val_u32);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt8);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_SHORT):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_SHORT: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_SHORT[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
val_i32 = *(epicsInt16 *) pbuffer;
|
||||
sprintf(pmsg, "%-9d 0x%-9x", val_i32, val_i32);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsInt16);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_USHORT):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_USHORT: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_USHORT[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
val_u32 = *(epicsUInt16 *) pbuffer;
|
||||
sprintf(pmsg, "%-9u 0x%-9x", val_u32, val_u32);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt16);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_LONG):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_LONG: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_LONG[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
val_i32 = *(epicsInt32 *) pbuffer;
|
||||
sprintf(pmsg, "%-9d 0x%-9x", val_i32, val_i32);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsInt32);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_ULONG):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_ULONG: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_ULONG[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
val_u32 = *(epicsUInt32 *) pbuffer;
|
||||
sprintf(pmsg, "%-9u 0x%-9x", val_u32, val_u32);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsUInt32);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_FLOAT):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_FLOAT: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_FLOAT[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
sprintf(pmsg, "%-13.6g", *((epicsFloat32 *) pbuffer));
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsFloat32);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_DOUBLE):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_DOUBLE: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_DOUBLE[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
sprintf(pmsg, "%-13.6g", *((epicsFloat64 *) pbuffer));
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsFloat64);
|
||||
}
|
||||
break;
|
||||
|
||||
case (DBR_ENUM):
|
||||
if (no_elements == 1)
|
||||
sprintf(pmsg, "DBR_ENUM: ");
|
||||
else
|
||||
sprintf(pmsg, "DBR_ENUM[%ld]: ", no_elements);
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
if (status != 0) {
|
||||
sprintf(pmsg, " failed.");
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < no_elements; i++) {
|
||||
sprintf(pmsg, "%-9u", *((epicsEnum16 *) pbuffer));
|
||||
dbpr_msgOut(pMsgBuff, tab_size);
|
||||
pbuffer = (char *)pbuffer + sizeof(epicsEnum16);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf(" illegal request type.");
|
||||
break;
|
||||
}
|
||||
|
||||
dbpr_msg_flush(pMsgBuff, tab_size);
|
||||
return;
|
||||
}
|
||||
|
||||
static int dbpr_report(
|
||||
@@ -1144,7 +1087,6 @@ static int dbpr_report(
|
||||
pfield = ((char *)paddr->precord) + pdbFldDes->offset;
|
||||
if (pdbFldDes->interest > interest_level )
|
||||
continue;
|
||||
|
||||
switch (pdbFldDes->field_type) {
|
||||
case DBF_STRING:
|
||||
case DBF_USHORT:
|
||||
@@ -1155,6 +1097,8 @@ static int dbpr_report(
|
||||
case DBF_SHORT:
|
||||
case DBF_LONG:
|
||||
case DBF_ULONG:
|
||||
case DBF_INT64:
|
||||
case DBF_UINT64:
|
||||
case DBF_DOUBLE:
|
||||
case DBF_MENU:
|
||||
case DBF_DEVICE:
|
||||
|
||||
@@ -12,22 +12,41 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define EPICS_PRIVATE_API
|
||||
|
||||
#include "dbmf.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "osiFileName.h"
|
||||
#include "osiUnistd.h"
|
||||
#include "registry.h"
|
||||
#include "epicsEvent.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbAccess.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbChannel.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbUnitTest.h"
|
||||
#include "initHooks.h"
|
||||
#include "iocInit.h"
|
||||
|
||||
static dbEventCtx testEvtCtx;
|
||||
static epicsMutexId testEvtLock;
|
||||
static ELLLIST testEvtList; /* holds testMonitor::node */
|
||||
|
||||
struct testMonitor {
|
||||
ELLNODE node;
|
||||
dbEventSubscription sub;
|
||||
dbChannel *chan;
|
||||
epicsEventId event;
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
void testdbPrepare(void)
|
||||
{
|
||||
/* No-op at the moment */
|
||||
if(!testEvtLock)
|
||||
testEvtLock = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
void testdbReadDatabase(const char* file,
|
||||
@@ -37,19 +56,35 @@ void testdbReadDatabase(const char* file,
|
||||
if(!path)
|
||||
path = "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
|
||||
"../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common";
|
||||
if(dbReadDatabase(&pdbbase, file, path, substitutions))
|
||||
testAbort("Failed to load test database\ndbReadDatabase(%s,%s,%s)",
|
||||
file, path, substitutions);
|
||||
if(dbReadDatabase(&pdbbase, file, path, substitutions)) {
|
||||
char buf[100];
|
||||
const char *cwd = getcwd(buf, sizeof(buf));
|
||||
if(!cwd)
|
||||
cwd = "<directory too long>";
|
||||
testAbort("Failed to load test database\ndbReadDatabase(%s,%s,%s)\n from: \"%s\"",
|
||||
file, path, substitutions, cwd);
|
||||
}
|
||||
}
|
||||
|
||||
void testIocInitOk(void)
|
||||
{
|
||||
if(iocBuildIsolated() || iocRun())
|
||||
testAbort("Failed to start up test database");
|
||||
if(!(testEvtCtx=db_init_events()))
|
||||
testAbort("Failed to initialize test dbEvent context");
|
||||
if(DB_EVENT_OK!=db_start_events(testEvtCtx, "CAS-test", NULL, NULL, epicsThreadPriorityCAServerLow))
|
||||
testAbort("Failed to start test dbEvent context");
|
||||
}
|
||||
|
||||
void testIocShutdownOk(void)
|
||||
{
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
if(ellCount(&testEvtList))
|
||||
testDiag("Warning, testing monitors still active at testIocShutdownOk()");
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
|
||||
db_close_events(testEvtCtx);
|
||||
testEvtCtx = NULL;
|
||||
if(iocShutdown())
|
||||
testAbort("Failed to shutdown test database");
|
||||
}
|
||||
@@ -57,6 +92,7 @@ void testIocShutdownOk(void)
|
||||
void testdbCleanup(void)
|
||||
{
|
||||
dbFreeBase(pdbbase);
|
||||
db_cleanup_events();
|
||||
initHookFree();
|
||||
registryFree();
|
||||
pdbbase = NULL;
|
||||
@@ -74,8 +110,8 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap)
|
||||
DBADDR addr;
|
||||
union anybuf pod;
|
||||
|
||||
if(dbNameToAddr(pv, &addr)) {
|
||||
testFail("Missing PV %s", pv);
|
||||
if (dbNameToAddr(pv, &addr)) {
|
||||
testFail("Missing PV \"%s\"", pv);
|
||||
return S_dbLib_recNotFound;
|
||||
}
|
||||
|
||||
@@ -98,6 +134,8 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap)
|
||||
OP(DBR_USHORT, int, uInt16);
|
||||
OP(DBR_LONG, int, int32);
|
||||
OP(DBR_ULONG, unsigned int, uInt32);
|
||||
OP(DBR_INT64, long long, int64);
|
||||
OP(DBR_UINT64, unsigned long long, uInt64);
|
||||
OP(DBR_FLOAT, double, float32);
|
||||
OP(DBR_DOUBLE, double, float64);
|
||||
OP(DBR_ENUM, int, enum16);
|
||||
@@ -120,7 +158,7 @@ void testdbPutFieldOk(const char* pv, short dbrType, ...)
|
||||
ret = testdbVPutField(pv, dbrType, ap);
|
||||
va_end(ap);
|
||||
|
||||
testOk(ret==0, "dbPutField(%s, %d, ...) == %ld", pv, dbrType, ret);
|
||||
testOk(ret==0, "dbPutField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, ret, errSymMsg(ret));
|
||||
}
|
||||
|
||||
void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
|
||||
@@ -132,10 +170,8 @@ void testdbPutFieldFail(long status, const char* pv, short dbrType, ...)
|
||||
ret = testdbVPutField(pv, dbrType, ap);
|
||||
va_end(ap);
|
||||
|
||||
if(ret==status)
|
||||
testPass("dbPutField(\"%s\", %d, ...) == %ld", pv, dbrType, status);
|
||||
else
|
||||
testFail("dbPutField(\"%s\", %d, ...) != %ld (%ld)", pv, dbrType, status, ret);
|
||||
testOk(ret==status, "dbPutField(\"%s\", %d, ...) -> %#lx (%s) == %#lx (%s)",
|
||||
pv, dbrType, status, errSymMsg(status), ret, errSymMsg(ret));
|
||||
}
|
||||
|
||||
void testdbGetFieldEqual(const char* pv, short dbrType, ...)
|
||||
@@ -155,13 +191,13 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
|
||||
long status;
|
||||
|
||||
if(dbNameToAddr(pv, &addr)) {
|
||||
testFail("Missing PV %s", pv);
|
||||
testFail("Missing PV \"%s\"", pv);
|
||||
return;
|
||||
}
|
||||
|
||||
status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL);
|
||||
if(status) {
|
||||
testFail("dbGetField(\"%s\",%d,...) returns %ld", pv, dbrType, status);
|
||||
if (status) {
|
||||
testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
|
||||
return;
|
||||
} else if(nReq==0) {
|
||||
testFail("dbGetField(\"%s\", %d, ...) -> zero length", pv, dbrType);
|
||||
@@ -186,13 +222,32 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
|
||||
OP(DBR_USHORT, int, uInt16, "%d");
|
||||
OP(DBR_LONG, int, int32, "%d");
|
||||
OP(DBR_ULONG, unsigned int, uInt32, "%u");
|
||||
OP(DBR_INT64, long long, int64, "%lld");
|
||||
OP(DBR_UINT64, unsigned long long, uInt64, "%llu");
|
||||
OP(DBR_FLOAT, double, float32, "%e");
|
||||
OP(DBR_DOUBLE, double, float64, "%e");
|
||||
OP(DBR_ENUM, int, enum16, "%d");
|
||||
#undef OP
|
||||
default:
|
||||
testFail("dbGetField(\"%s\", %d) -> unsupported dbf", pv, dbrType);
|
||||
}
|
||||
}
|
||||
|
||||
void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf)
|
||||
{
|
||||
DBADDR addr;
|
||||
long status;
|
||||
|
||||
if (dbNameToAddr(pv, &addr)) {
|
||||
testFail("Missing PV \"%s\"", pv);
|
||||
return;
|
||||
}
|
||||
|
||||
status = dbPutField(&addr, dbrType, pbuf, count);
|
||||
|
||||
testOk(status==0, "dbPutField(\"%s\", dbr=%d, count=%lu, ...) -> %ld", pv, dbrType, count, status);
|
||||
}
|
||||
|
||||
void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbufraw)
|
||||
{
|
||||
DBADDR addr;
|
||||
@@ -246,6 +301,8 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
|
||||
OP(DBR_USHORT, unsigned short, "%u");
|
||||
OP(DBR_LONG, int, "%d");
|
||||
OP(DBR_ULONG, unsigned int, "%u");
|
||||
OP(DBR_INT64, long long, "%lld");
|
||||
OP(DBR_UINT64, unsigned long long, "%llu");
|
||||
OP(DBR_FLOAT, float, "%e");
|
||||
OP(DBR_DOUBLE, double, "%e");
|
||||
OP(DBR_ENUM, int, "%d");
|
||||
@@ -263,8 +320,97 @@ dbCommon* testdbRecordPtr(const char* pv)
|
||||
{
|
||||
DBADDR addr;
|
||||
|
||||
if(dbNameToAddr(pv, &addr))
|
||||
testAbort("Missing record %s", pv);
|
||||
if (dbNameToAddr(pv, &addr))
|
||||
testAbort("Missing record \"%s\"", pv);
|
||||
|
||||
return addr.precord;
|
||||
}
|
||||
|
||||
static
|
||||
void testmonupdate(void *user_arg, struct dbChannel *chan,
|
||||
int eventsRemaining, struct db_field_log *pfl)
|
||||
{
|
||||
testMonitor *mon = user_arg;
|
||||
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
mon->count++;
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
epicsEventMustTrigger(mon->event);
|
||||
}
|
||||
|
||||
testMonitor* testMonitorCreate(const char* pvname, unsigned mask, unsigned opt)
|
||||
{
|
||||
long status;
|
||||
testMonitor *mon;
|
||||
dbChannel *chan;
|
||||
assert(testEvtCtx);
|
||||
|
||||
mon = callocMustSucceed(1, sizeof(*mon), "testMonitorCreate");
|
||||
|
||||
mon->event = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
chan = mon->chan = dbChannelCreate(pvname);
|
||||
if(!chan)
|
||||
testAbort("testMonitorCreate - dbChannelCreate(\"%s\") fails", pvname);
|
||||
if(!!(status=dbChannelOpen(chan)))
|
||||
testAbort("testMonitorCreate - dbChannelOpen(\"%s\") fails w/ %ld", pvname, status);
|
||||
|
||||
mon->sub = db_add_event(testEvtCtx, chan, &testmonupdate, mon, mask);
|
||||
if(!mon->sub)
|
||||
testAbort("testMonitorCreate - db_add_event(\"%s\") fails", pvname);
|
||||
|
||||
db_event_enable(mon->sub);
|
||||
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
ellAdd(&testEvtList, &mon->node);
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
|
||||
return mon;
|
||||
}
|
||||
|
||||
void testMonitorDestroy(testMonitor *mon)
|
||||
{
|
||||
if(!mon) return;
|
||||
|
||||
db_event_disable(mon->sub);
|
||||
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
ellDelete(&testEvtList, &mon->node);
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
|
||||
db_cancel_event(mon->sub);
|
||||
|
||||
dbChannelDelete(mon->chan);
|
||||
|
||||
epicsEventDestroy(mon->event);
|
||||
|
||||
free(mon);
|
||||
}
|
||||
|
||||
void testMonitorWait(testMonitor *mon)
|
||||
{
|
||||
static const double delay = 60.0;
|
||||
|
||||
switch(epicsEventWaitWithTimeout(mon->event, delay))
|
||||
{
|
||||
case epicsEventOK:
|
||||
return;
|
||||
case epicsEventWaitTimeout:
|
||||
default:
|
||||
testAbort("testMonitorWait() exceeded %g second timeout", delay);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned testMonitorCount(testMonitor *mon, unsigned reset)
|
||||
{
|
||||
unsigned count;
|
||||
epicsMutexMustLock(testEvtLock);
|
||||
count = mon->count;
|
||||
if(reset) {
|
||||
mon->count = 0;
|
||||
epicsEventWaitWithTimeout(mon->event, 0); /* clear the event */
|
||||
}
|
||||
epicsMutexUnlock(testEvtLock);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ epicsShareFunc void testdbCleanup(void);
|
||||
*
|
||||
* int for DBR_UCHAR, DBR_CHAR, DBR_USHORT, DBR_SHORT, DBR_LONG
|
||||
* unsigned int for DBR_ULONG
|
||||
* long long for DBF_INT64
|
||||
* unsigned long long for DBF_UINT64
|
||||
* double for DBR_FLOAT and DBR_DOUBLE
|
||||
* const char* for DBR_STRING
|
||||
*
|
||||
@@ -55,6 +57,8 @@ epicsShareFunc long testdbVPutField(const char* pv, short dbrType, va_list ap);
|
||||
epicsShareFunc void testdbGetFieldEqual(const char* pv, short dbrType, ...);
|
||||
epicsShareFunc void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap);
|
||||
|
||||
epicsShareFunc void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf);
|
||||
|
||||
/**
|
||||
* @param pv PV name string
|
||||
* @param dbfType One of the DBF_* macros from dbAccess.h
|
||||
@@ -74,6 +78,26 @@ epicsShareFunc void testdbGetArrFieldEqual(const char* pv, short dbfType, long n
|
||||
|
||||
epicsShareFunc dbCommon* testdbRecordPtr(const char* pv);
|
||||
|
||||
typedef struct testMonitor testMonitor;
|
||||
|
||||
/* Begin monitoring the named PV for changes */
|
||||
epicsShareFunc testMonitor* testMonitorCreate(const char* pvname, unsigned dbe_mask, unsigned opt);
|
||||
/* End monitoring */
|
||||
epicsShareFunc void testMonitorDestroy(testMonitor*);
|
||||
/* Return immediately if it has been updated since create, last wait,
|
||||
* or reset (count w/ reset=1).
|
||||
* Otherwise, block until the value of the target PV is updated.
|
||||
*/
|
||||
epicsShareFunc void testMonitorWait(testMonitor*);
|
||||
/* Return the number of monitor events which have occured since create,
|
||||
* or a pervious reset (called reset=1).
|
||||
* Calling w/ reset=0 only returns the count.
|
||||
* Calling w/ reset=1 resets the count to zero and ensures that the next
|
||||
* wait will block unless subsequent events occur. Returns the previous
|
||||
* count.
|
||||
*/
|
||||
epicsShareFunc unsigned testMonitorCount(testMonitor*, unsigned reset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -23,8 +23,8 @@ epicsShareExtern struct dbBase *pdbbase;
|
||||
epicsShareExtern volatile int interruptAccept;
|
||||
|
||||
/*Definitions that allow old database access to use new conversion routines*/
|
||||
#define newDBF_DEVICE 11
|
||||
#define newDBR_ENUM 9
|
||||
#define newDBF_DEVICE 13
|
||||
#define newDBR_ENUM 11
|
||||
epicsShareExtern long (*dbGetConvertRoutine[newDBF_DEVICE+1][newDBR_ENUM+1])
|
||||
(struct dbAddr *paddr, void *pbuffer,long nRequest,
|
||||
long no_elements, long offset);
|
||||
@@ -43,11 +43,11 @@ epicsShareExtern unsigned short dbDBRnewToDBRold[newDBR_ENUM+1];
|
||||
epicsShareDef unsigned short dbDBRoldToDBFnew[DBR_DOUBLE+1] = {
|
||||
0, /*DBR_STRING to DBF_STRING*/
|
||||
3, /*DBR_INT to DBF_SHORT*/
|
||||
7, /*DBR_FLOAT to DBF_FLOAT*/
|
||||
9, /*DBR_ENUM to DBF_ENUM*/
|
||||
9, /*DBR_FLOAT to DBF_FLOAT*/
|
||||
11, /*DBR_ENUM to DBF_ENUM*/
|
||||
1, /*DBR_CHAR to DBF_CHAR*/
|
||||
5, /*DBR_LONG to DBF_LONG*/
|
||||
8 /*DBR_DOUBLE to DBF_DOUBLE*/
|
||||
10 /*DBR_DOUBLE to DBF_DOUBLE*/
|
||||
};
|
||||
epicsShareDef unsigned short dbDBRnewToDBRold[newDBR_ENUM+1] = {
|
||||
0, /*DBR_STRING to DBR_STRING*/
|
||||
@@ -57,6 +57,8 @@ epicsShareDef unsigned short dbDBRnewToDBRold[newDBR_ENUM+1] = {
|
||||
5, /*DBR_USHORT to DBR_LONG*/
|
||||
5, /*DBR_LONG to DBR_LONG*/
|
||||
6, /*DBR_ULONG to DBR_DOUBLE*/
|
||||
6, /*DBR_INT64 to DBR_DOUBLE*/
|
||||
6, /*DBR_UINT64 to DBR_DOUBLE*/
|
||||
2, /*DBR_FLOAT to DBR_FLOAT*/
|
||||
6, /*DBR_DOUBLE to DBR_DOUBLE*/
|
||||
3, /*DBR_ENUM to DBR_ENUM*/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# Copyright (c) 2013 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
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
menu(menuFtype) {
|
||||
@@ -15,6 +14,8 @@ menu(menuFtype) {
|
||||
choice(menuFtypeUSHORT,"USHORT")
|
||||
choice(menuFtypeLONG,"LONG")
|
||||
choice(menuFtypeULONG,"ULONG")
|
||||
choice(menuFtypeINT64,"INT64")
|
||||
choice(menuFtypeUINT64,"UINT64")
|
||||
choice(menuFtypeFLOAT,"FLOAT")
|
||||
choice(menuFtypeDOUBLE,"DOUBLE")
|
||||
choice(menuFtypeENUM,"ENUM")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "alarm.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsPrint.h"
|
||||
@@ -30,7 +31,6 @@
|
||||
#include "dbAccessDefs.h"
|
||||
#include "dbAddr.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbCa.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbEvent.h"
|
||||
#include "db_field_log.h"
|
||||
@@ -120,6 +120,8 @@ void recGblGetPrec(const struct dbAddr *paddr, long *precision)
|
||||
case DBF_USHORT:
|
||||
case DBF_LONG:
|
||||
case DBF_ULONG:
|
||||
case DBF_INT64:
|
||||
case DBF_UINT64:
|
||||
*precision = 0;
|
||||
break;
|
||||
|
||||
@@ -161,14 +163,9 @@ void recGblGetControlDouble(const struct dbAddr *paddr,
|
||||
&pcd->upper_ctrl_limit, &pcd->lower_ctrl_limit);
|
||||
}
|
||||
|
||||
int recGblInitConstantLink(
|
||||
struct link *plink,short dbftype,void *pdest)
|
||||
int recGblInitConstantLink(struct link *plink, short dbftype, void *pdest)
|
||||
{
|
||||
long status = dbLoadLink(plink, dbftype, pdest);
|
||||
|
||||
if (status)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
return !dbLoadLink(plink, dbftype, pdest);
|
||||
}
|
||||
|
||||
unsigned short recGblResetAlarms(void *precord)
|
||||
@@ -219,7 +216,27 @@ int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr)
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
|
||||
epicsEnum16 sevr)
|
||||
{
|
||||
switch (msMode) {
|
||||
case pvlOptNMS:
|
||||
break;
|
||||
case pvlOptMSI:
|
||||
if (sevr < INVALID_ALARM)
|
||||
break;
|
||||
/* Fall through */
|
||||
case pvlOptMS:
|
||||
recGblSetSevr(precord, LINK_ALARM, sevr);
|
||||
break;
|
||||
case pvlOptMSS:
|
||||
recGblSetSevr(precord, stat, sevr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void recGblFwdLink(void *precord)
|
||||
{
|
||||
dbCommon *pdbc = precord;
|
||||
@@ -241,7 +258,7 @@ void recGblGetTimeStamp(void *pvoid)
|
||||
dbCommon* prec = (dbCommon*)pvoid;
|
||||
struct link *plink = &prec->tsel;
|
||||
|
||||
if (plink->type != CONSTANT) {
|
||||
if (!dbLinkIsConstant(plink)) {
|
||||
struct pv_link *ppv_link = &plink->value.pv_link;
|
||||
|
||||
if (ppv_link->pvlMask & pvlOptTSELisTime) {
|
||||
@@ -330,7 +347,15 @@ static void getMaxRangeValues(short field_type, double *pupper_limit,
|
||||
*plower_limit = -2147483648.0;
|
||||
break;
|
||||
case DBF_ULONG:
|
||||
*pupper_limit = (double) 0xffffffffU;
|
||||
*pupper_limit = 4294967295.0;
|
||||
*plower_limit = 0.0;
|
||||
break;
|
||||
case DBF_INT64:
|
||||
*pupper_limit = 9223372036854775808.0;
|
||||
*plower_limit = -9223372036854775808.0;
|
||||
break;
|
||||
case DBF_UINT64:
|
||||
*pupper_limit = 18446744073709551615.0;
|
||||
*plower_limit = 0.0;
|
||||
break;
|
||||
case DBF_FLOAT:
|
||||
|
||||
@@ -59,6 +59,8 @@ epicsShareFunc int recGblInitConstantLink(struct link *plink,
|
||||
epicsShareFunc unsigned short recGblResetAlarms(void *precord);
|
||||
epicsShareFunc int recGblSetSevr(void *precord, epicsEnum16 new_stat,
|
||||
epicsEnum16 new_sevr);
|
||||
epicsShareFunc void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
|
||||
epicsEnum16 sevr);
|
||||
epicsShareFunc void recGblFwdLink(void *precord);
|
||||
epicsShareFunc void recGblGetTimeStamp(void *precord);
|
||||
epicsShareFunc void recGblTSELwasModified(struct link *plink);
|
||||
|
||||
@@ -1,36 +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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include "dbCAC.h"
|
||||
#include "dbChannelIO.h"
|
||||
#include "dbPutNotifyBlocker.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class tsFreeList < dbChannelIO, 256, epicsMutexNOOP >;
|
||||
template class tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP >;
|
||||
template class tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP >;
|
||||
template class resTable < dbBaseIO, chronIntId >;
|
||||
template class chronIntIdResTable < dbBaseIO >;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
@@ -10,11 +10,17 @@ TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
# Allow access to private headers in db/
|
||||
USR_CPPFLAGS = -I ../..
|
||||
|
||||
TESTLIBRARY = dbTestIoc
|
||||
|
||||
dbTestIoc_SRCS += arrRecord.c
|
||||
dbTestIoc_SRCS += xRecord.c
|
||||
dbTestIoc_SRCS += dbLinkdset.c
|
||||
dbTestIoc_SRCS += xLink.c
|
||||
dbTestIoc_SRCS += devx.c
|
||||
dbTestIoc_SRCS += jlinkz.c
|
||||
dbTestIoc_LIBS = dbCore ca Com
|
||||
|
||||
TARGETS += $(COMMON_DIR)/dbTestIoc.dbd
|
||||
@@ -22,8 +28,11 @@ DBDDEPENDS_FILES += dbTestIoc.dbd$(DEP)
|
||||
dbTestIoc_DBD += menuGlobal.dbd
|
||||
dbTestIoc_DBD += menuConvert.dbd
|
||||
dbTestIoc_DBD += menuScan.dbd
|
||||
#dbTestIoc_DBD += arrRecord.dbd
|
||||
dbTestIoc_DBD += xRecord.dbd
|
||||
dbTestIoc_DBD += arrRecord.dbd
|
||||
dbTestIoc_DBD += xLink.dbd
|
||||
dbTestIoc_DBD += devx.dbd
|
||||
dbTestIoc_DBD += jlinkz.dbd
|
||||
dbTestIoc_DBD += dbLinkdset.dbd
|
||||
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
|
||||
|
||||
@@ -31,6 +40,12 @@ testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
|
||||
PROD_LIBS = dbTestIoc dbCore ca Com
|
||||
|
||||
TESTPROD_HOST += dbScanTest
|
||||
dbScanTest_SRCS += dbScanTest.c
|
||||
dbScanTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbScanTest.c
|
||||
TESTS += dbScanTest
|
||||
|
||||
TESTPROD_HOST += dbShutdownTest
|
||||
dbShutdownTest_SRCS += dbShutdownTest.c
|
||||
dbShutdownTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
@@ -42,7 +57,7 @@ dbPutLinkTest_SRCS += dbPutLinkTest.c
|
||||
dbPutLinkTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbPutLinkTest.c
|
||||
TESTS += dbPutLinkTest
|
||||
TESTFILES += ../dbPutLinkTest.db
|
||||
TESTFILES += ../dbPutLinkTest.db ../dbPutLinkTestJ.db ../dbBadLink.db
|
||||
|
||||
TESTPROD_HOST += dbLockTest
|
||||
dbLockTest_SRCS += dbLockTest.c
|
||||
@@ -51,6 +66,14 @@ testHarness_SRCS += dbLockTest.c
|
||||
TESTS += dbLockTest
|
||||
TESTFILES += ../dbLockTest.db
|
||||
|
||||
TESTPROD_HOST += dbStressTest
|
||||
dbStressTest_SRCS += dbStressLock.c
|
||||
dbStressTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
dbStressTest_SYS_LIBS_solaris += rt
|
||||
dbStressTest_SYS_LIBS_Linux += rt
|
||||
TESTS += dbStressTest
|
||||
TESTFILES += ../dbStressLock.db
|
||||
|
||||
TESTPROD_HOST += testdbConvert
|
||||
testdbConvert_SRCS += testdbConvert.c
|
||||
testHarness_SRCS += testdbConvert.c
|
||||
@@ -76,21 +99,22 @@ dbCaStatsTest_SRCS += dbCaStatsTest.c
|
||||
dbCaStatsTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbCaStatsTest.c
|
||||
TESTS += dbCaStatsTest
|
||||
TESTFILES += ../dbCaStatsTest.db
|
||||
TESTFILES += ../dbCaStats.db
|
||||
|
||||
TESTPROD_HOST += dbCaLinkTest
|
||||
dbCaLinkTest_SRCS += dbCaLinkTest.c
|
||||
dbCaLinkTest_SRCS += dbCACTest.cpp
|
||||
dbCaLinkTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbCaLinkTest.c
|
||||
testHarness_SRCS += dbCACTest.cpp
|
||||
TESTS += dbCaLinkTest
|
||||
TESTFILES += ../dbCaLinkTest1.db ../dbCaLinkTest2.db ../dbCaLinkTest3.db
|
||||
|
||||
TARGETS += $(COMMON_DIR)/scanIoTest.dbd
|
||||
DBDDEPENDS_FILES += scanIoTest.dbd$(DEP)
|
||||
scanIoTest_DBD += menuGlobal.dbd
|
||||
scanIoTest_DBD += menuConvert.dbd
|
||||
scanIoTest_DBD += menuScan.dbd
|
||||
scanIoTest_DBD += yRecord.dbd
|
||||
TESTPROD_HOST += scanIoTest
|
||||
scanIoTest_SRCS += scanIoTest.c
|
||||
scanIoTest_REGRDDFLAGS = -l
|
||||
scanIoTest_SRCS += scanIoTest_registerRecordDeviceDriver.cpp
|
||||
scanIoTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += scanIoTest.c
|
||||
testHarness_SRCS += scanIoTest_registerRecordDeviceDriver.cpp
|
||||
TESTFILES += $(COMMON_DIR)/scanIoTest.dbd ../scanIoTest.db
|
||||
TESTFILES += ../scanIoTest.db
|
||||
TESTS += scanIoTest
|
||||
|
||||
TESTPROD_HOST += dbChannelTest
|
||||
@@ -134,10 +158,17 @@ TESTS += recGblCheckDeadbandTest
|
||||
TESTPROD_HOST += testPutGetTest
|
||||
testPutGetTest_SRCS += dbPutGetTest.c
|
||||
testPutGetTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbPutGetTest.db
|
||||
testHarness_SRCS += dbPutGetTest.c
|
||||
TESTFILES += ../dbPutGetTest.db
|
||||
TESTS += testPutGetTest
|
||||
|
||||
TESTPROD_HOST += dbStaticTest
|
||||
dbStaticTest_SRCS += dbStaticTest.c
|
||||
dbStaticTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
|
||||
testHarness_SRCS += dbStaticTest.c
|
||||
TESTFILES += ../dbStaticTest.db
|
||||
TESTS += dbStaticTest
|
||||
|
||||
# This runs all the test programs in a known working order:
|
||||
testHarness_SRCS += epicsRunDbTests.c
|
||||
|
||||
@@ -155,6 +186,10 @@ TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h
|
||||
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
dbCaLinkTest$(DEP): $(COMMON_DIR)/xRecord.h $(COMMON_DIR)/arrRecord.h
|
||||
dbPutLinkTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
scanIoTest$(DEP): $(COMMON_DIR)/yRecord.h
|
||||
dbStressLock$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
devx$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
xRecord$(DEP): $(COMMON_DIR)/xRecord.h
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user