From a4edc46a5f21d51278f83bda548290b68f2bb0ad Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 20 Mar 2013 16:53:10 -0500
Subject: [PATCH 01/16] dbStatic: Allow empty DB & DBD files
They used to cause a Syntax error with a bad context string.
---
documentation/RELEASE_NOTES.html | 7 +++++++
src/dbStatic/dbYacc.y | 8 +++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 98c9415b1..f62a502c7 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,13 @@
+Allow empty database files
+
+The IOC used to report an error if dbLoadRecords or dbLoadDatabase was asked
+to load an empty file or one containing just whitespace and/or comments. Such
+files are now permitted, simplifying the task of automated database generation
+programs which might discover they have nothing to output.
+
High-Resolution Time Provider on MacOS
MacOS does not provide the clock_gettime() API with CLOCK_REALTIME that other
diff --git a/src/dbStatic/dbYacc.y b/src/dbStatic/dbYacc.y
index b61ab26ea..b8cc9b4cf 100644
--- a/src/dbStatic/dbYacc.y
+++ b/src/dbStatic/dbYacc.y
@@ -31,7 +31,13 @@ static int yyAbort = 0;
%%
-database: database database_item | database_item;
+database: /* empty */
+ | database_item_list
+ ;
+
+database_item_list: database_item_list database_item
+ | database_item
+ ;
database_item: include
| path
From f9a0c82a63e1aace9f2da7d7878ac7ee29cbc2f5 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 28 Mar 2013 17:17:41 -0500
Subject: [PATCH 02/16] libCom/osi: Resolve bcopyLongs() conflict on vxWorks
6.9
---
documentation/RELEASE_NOTES.html | 8 ++++++++
src/libCom/osi/devLibVME.h | 5 -----
src/libCom/osi/os/RTEMS/osdVME.h | 2 ++
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index f62a502c7..7632b4c81 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,14 @@
+devLibVME.h
+
+Moved the declaration of bcopyLongs() from this header into RTEMS/osdVME.h.
+Its original location broke the build for vxWorks 6.9 (the int nlongs argument
+becomes size_t in 6.9, thus conflicting with this declaration). The only local
+implementation of this routine is found in RTEMS/devLibVMEOSD.c, but it is not
+used anywhere in Base.
+
Allow empty database files
The IOC used to report an error if dbLoadRecords or dbLoadDatabase was asked
diff --git a/src/libCom/osi/devLibVME.h b/src/libCom/osi/devLibVME.h
index 6d7476098..8e526a139 100644
--- a/src/libCom/osi/devLibVME.h
+++ b/src/libCom/osi/devLibVME.h
@@ -300,11 +300,6 @@ epicsShareFunc long locationProbe (epicsAddressType addrType, char *pLocation);
#endif /* NO_DEVLIB_OLD_INTERFACE */
-/*
- * Some vxWorks convenience routines
- */
-void bcopyLongs(char *source, char *destination, int nlongs);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/libCom/osi/os/RTEMS/osdVME.h b/src/libCom/osi/os/RTEMS/osdVME.h
index 470f64866..5e8c5f984 100644
--- a/src/libCom/osi/os/RTEMS/osdVME.h
+++ b/src/libCom/osi/os/RTEMS/osdVME.h
@@ -19,3 +19,5 @@
#endif
#endif
#endif
+
+void bcopyLongs(char *source, char *destination, int nlongs);
From f824246baa84da7b4e7e42fccd5c5a293084b21f Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 29 Mar 2013 11:17:09 -0500
Subject: [PATCH 03/16] Add configuration for vxWorks 6.9 builds.
---
configure/os/CONFIG.Common.vxWorksCommon | 2 ++
configure/os/CONFIG_SITE.Common.vxWorksCommon | 2 ++
2 files changed, 4 insertions(+)
diff --git a/configure/os/CONFIG.Common.vxWorksCommon b/configure/os/CONFIG.Common.vxWorksCommon
index 2203d276d..ee6efa934 100644
--- a/configure/os/CONFIG.Common.vxWorksCommon
+++ b/configure/os/CONFIG.Common.vxWorksCommon
@@ -93,6 +93,7 @@ VX_GNU_VERSION_6.5 = 3.4.4
VX_GNU_VERSION_6.6 = 4.1.2
VX_GNU_VERSION_6.7 = 4.1.2
VX_GNU_VERSION_6.8 = 4.1.2
+VX_GNU_VERSION_6.9 = 4.3.3
VX_GNU_VERSION = $(VX_GNU_VERSION_$(VXWORKS_VERSION))
VX_GNU_MAJOR_VERSION = $(basename $(basename $(VX_GNU_VERSION)))
@@ -134,6 +135,7 @@ NM_DIR_6.5 = $(WORKBENCH_BIN)
NM_DIR_6.6 = $(WORKBENCH_BIN)
NM_DIR_6.7 = $(GNU_BIN)
NM_DIR_6.8 = $(UTILITIES_BIN)
+NM_DIR_6.9 = $(UTILITIES_BIN)
NM_DIR = $(firstword $(NM_DIR_$(VXWORKS_VERSION)) $(GNU_BIN))
NM = $(NM_DIR)/$(CMPLR_PREFIX)nm$(CMPLR_SUFFIX)$(HOSTEXE)
diff --git a/configure/os/CONFIG_SITE.Common.vxWorksCommon b/configure/os/CONFIG_SITE.Common.vxWorksCommon
index 3fdc22ef9..17696fd36 100644
--- a/configure/os/CONFIG_SITE.Common.vxWorksCommon
+++ b/configure/os/CONFIG_SITE.Common.vxWorksCommon
@@ -20,6 +20,7 @@ VXWORKS_VERSION = 5.5
#VXWORKS_VERSION = 6.6
#VXWORKS_VERSION = 6.7
#VXWORKS_VERSION = 6.8
+#VXWORKS_VERSION = 6.9
# Sites may override the following path for a particular host
@@ -40,6 +41,7 @@ WIND_BASE = /usr/local/vw/tornado22-$(ARCH_CLASS)
#WORKBENCH_VERSION = 2.6
#WORKBENCH_VERSION = 3.0
#WORKBENCH_VERSION = 3.2
+#WORKBENCH_VERSION = 3.3
# Utilities Version number, required from vxWorks 6.8 and later
From 58c031238b988b6ebe2fe6a17dd1cfc8ec5c364d Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 1 Apr 2013 10:03:38 -0500
Subject: [PATCH 04/16] configure: Modify help rule to use $(DIVIDER)
... in case someone changes it.
---
configure/RULES_TOP | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/configure/RULES_TOP b/configure/RULES_TOP
index 7bcfc74a6..8f100621a 100644
--- a/configure/RULES_TOP
+++ b/configure/RULES_TOP
@@ -64,11 +64,11 @@ help:
@echo " rebuild - Same as clean install"
@echo " archclean - Removes O. dirs but not O.Common dir"
@echo "\"Partial\" build targets supported by Makefiles:"
- @echo " inc. - Installs only header files."
- @echo " build. - Builds and installs only."
- @echo " install. - Builds and installs only."
- @echo " clean. - Cleans binaries in O. dirs only."
- @echo " uninstall. - Remove bin & lib directories for only."
+ @echo " inc$(DIVIDER) - Installs only header files."
+ @echo " build$(DIVIDER) - Builds and installs only."
+ @echo " install$(DIVIDER) - Builds and installs only."
+ @echo " clean$(DIVIDER) - Cleans binaries in O. dirs only."
+ @echo " uninstall$(DIVIDER) - Remove bin & lib directories for only."
@echo "Targets supported by top level Makefile:"
@echo " archuninstall - Remove bin & lib directories created by this hostarch."
@echo " uninstall - Remove install directories created by this hostarch."
From 880db9d4af0af0c81fe93f38ff4058ec1113ca0a Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 9 Apr 2013 12:39:26 -0500
Subject: [PATCH 05/16] configure: Set IOCS_APPL_TOP from INSTALL_LOCATION
Fixes lp:1165257
---
configure/CONFIG_COMMON | 5 ++++-
configure/RULES.Db | 3 +--
configure/RULES.ioc | 25 ++++++++++---------------
documentation/RELEASE_NOTES.html | 10 ++++++++++
4 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON
index 5878c2cbe..653c52bee 100644
--- a/configure/CONFIG_COMMON
+++ b/configure/CONFIG_COMMON
@@ -76,9 +76,12 @@ INSTALL_DB = $(INSTALL_LOCATION)/db
INSTALL_CONFIG = $(INSTALL_LOCATION)/configure
INSTALL_JAVA = $(INSTALL_LOCATION)/javalib
-#Directory for OS independant build created files
+# Directory for OS independant build created files
COMMON_DIR = ../O.Common
+# The IOC's path to $(TOP), may be overridden inside the application
+IOCS_APPL_TOP = $(INSTALL_LOCATION)
+
#-------------------------------------------------------
# Make echo output - suppress echoing if make's '-s' flag is set
NOP = :
diff --git a/configure/RULES.Db b/configure/RULES.Db
index c66aef272..c697f675c 100644
--- a/configure/RULES.Db
+++ b/configure/RULES.Db
@@ -368,8 +368,7 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
##################################################### register record,device,driver support
-IOC_INST_TOP := $(firstword $(IOCS_APPL_TOP) \
- $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION) ) )
+IOC_INST_TOP := $(shell $(PERL) $(TOOLS)/fullPathName.pl $(IOCS_APPL_TOP) )
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
@$(RM) $@ $*.tmp
diff --git a/configure/RULES.ioc b/configure/RULES.ioc
index c661d54d5..cf74343b2 100644
--- a/configure/RULES.ioc
+++ b/configure/RULES.ioc
@@ -1,13 +1,13 @@
#*************************************************************************
-# 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
-# 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.
#*************************************************************************
#RULES.ioc
+
include $(CONFIG)/RULES_DIRS
build$(DIVIDER)$(ARCH) build: buildInstall
@@ -15,23 +15,18 @@ install$(DIVIDER)$(ARCH) install: buildInstall
$(ARCH): buildInstall
ifeq ($(filter $(ARCH),$(BUILD_ARCHS)),$(ARCH))
-buildInstall$(DIVIDER)$(ARCH) buildInstall: $(TARGETS)
+ buildInstall$(DIVIDER)$(ARCH) buildInstall: $(TARGETS)
-clean$(DIVIDER)$(ARCH) clean:
+ clean$(DIVIDER)$(ARCH) clean:
$(RM) cdCommands envPaths dllPath.bat
-
-else
-buildInstall$(DIVIDER)$(ARCH) buildInstall:
-clean$(DIVIDER)$(ARCH) clean:
+else
+ buildInstall$(DIVIDER)$(ARCH) buildInstall:
+ clean$(DIVIDER)$(ARCH) clean:
endif
cdCommands envPaths dllPath.bat: $(wildcard $(TOP)/configure/RELEASE*) \
- $(TOP)/configure/CONFIG $(INSTALL_BIN)
-ifeq ($(IOCS_APPL_TOP),)
- $(PERL) $(TOOLS)/convertRelease.pl -a $(ARCH) $@
-else
+ $(wildcard $(TOP)/configure/CONFIG_SITE*) $(INSTALL_BIN)
$(PERL) $(TOOLS)/convertRelease.pl -a $(ARCH) -t $(IOCS_APPL_TOP) $@
-endif
realclean:
$(RM) cdCommands envPaths dllPath.bat
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 7632b4c81..366ef973a 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,16 @@
+IOCS_APPL_TOP and INSTALL_LOCATION
+
+An IOC application that sets INSTALL_LOCATION in its configure/CONFIG_SITE
+file no longer has to set IOCS_APPL_TOP there as well, unless the IOC uses a
+different path than the build host to reach the application's top directory in
+its filesystem. The IOCS_APPL_TOP variable now defaults to the value of
+INSTALL_LOCATION, so setting the latter automatically sets the former. This
+change fixes Launchpad bug
+1165257.
+
devLibVME.h
Moved the declaration of bcopyLongs() from this header into RTEMS/osdVME.h.
From 5bc15b72a17a80fccd6fe19348b68f5b7dfad16b Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 11 Apr 2013 12:56:56 -0500
Subject: [PATCH 06/16] libCom: Add some missing #include guards.
There are still quite a few missing in libCom/osi/os/*
---
src/libCom/misc/epicsConvert.h | 9 ++++++---
src/libCom/misc/epicsStdlib.h | 9 ++++++---
src/libCom/osi/epicsSignal.h | 9 ++++++---
src/libCom/osi/osiPoolStatus.h | 9 ++++++---
src/libCom/osi/osiProcess.h | 9 ++++++---
5 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/src/libCom/misc/epicsConvert.h b/src/libCom/misc/epicsConvert.h
index 9674db0ef..1c38bc30a 100644
--- a/src/libCom/misc/epicsConvert.h
+++ b/src/libCom/misc/epicsConvert.h
@@ -3,12 +3,14 @@
* 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.
\*************************************************************************/
/*epicsConvert.h*/
+#ifndef INC_epicsConvert_H
+#define INC_epicsConvert_H
+
#include
#ifdef __cplusplus
@@ -21,3 +23,4 @@ epicsShareFunc float epicsConvertDoubleToFloat(double value);
}
#endif
+#endif /* INC_epicsConvert_H */
diff --git a/src/libCom/misc/epicsStdlib.h b/src/libCom/misc/epicsStdlib.h
index 84d4af062..78f822e4a 100644
--- a/src/libCom/misc/epicsStdlib.h
+++ b/src/libCom/misc/epicsStdlib.h
@@ -3,13 +3,15 @@
* 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.
\*************************************************************************/
/*epicsStdlib.h*/
/*Author: Eric Norum */
+#ifndef INC_epicsStdlib_H
+#define INC_epicsStdlib_H
+
#include
#ifdef __cplusplus
@@ -26,3 +28,4 @@ epicsShareFunc int epicsScanFloat(const char *str, float *dest);
}
#endif
+#endif /* INC_epicsStdlib_H */
diff --git a/src/libCom/osi/epicsSignal.h b/src/libCom/osi/epicsSignal.h
index 2fd0e5839..79adf71d1 100644
--- a/src/libCom/osi/epicsSignal.h
+++ b/src/libCom/osi/epicsSignal.h
@@ -3,11 +3,13 @@
* 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.
\*************************************************************************/
+#ifndef INC_epicsSignal_H
+#define INC_epicsSignal_H
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -44,3 +46,4 @@ epicsShareFunc void epicsShareAPI epicsSignalRaiseSigAlarm ( struct epicsThreadO
}
#endif
+#endif /* INC_epicsSignal_H */
diff --git a/src/libCom/osi/osiPoolStatus.h b/src/libCom/osi/osiPoolStatus.h
index c80612a37..20f1b7339 100644
--- a/src/libCom/osi/osiPoolStatus.h
+++ b/src/libCom/osi/osiPoolStatus.h
@@ -3,11 +3,13 @@
* 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.
\*************************************************************************/
+#ifndef INC_osiPoolStatus_H
+#define INC_osiPoolStatus_H
+
/*
* $Revision-Id$
*
@@ -39,3 +41,4 @@ epicsShareFunc int epicsShareAPI osiSufficentSpaceInPool ( size_t contiguousBloc
#include "osdPoolStatus.h"
+#endif /* INC_osiPoolStatus_H */
diff --git a/src/libCom/osi/osiProcess.h b/src/libCom/osi/osiProcess.h
index bd3cb5b31..b954c4019 100644
--- a/src/libCom/osi/osiProcess.h
+++ b/src/libCom/osi/osiProcess.h
@@ -3,11 +3,13 @@
* 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.
\*************************************************************************/
+#ifndef INC_osiProcess_H
+#define INC_osiProcess_H
+
/*
* $Revision-Id$
*
@@ -44,3 +46,4 @@ epicsShareFunc osiSpawnDetachedProcessReturn epicsShareAPI osiSpawnDetachedProce
}
#endif
+#endif /* INC_osiProcess_H */
From 7e347b2de92e7d4f7ac89bfa9dd7128dd8df8ef8 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Wed, 24 Apr 2013 12:52:05 -0500
Subject: [PATCH 07/16] libCom: Fix sysAtReboot registration on vxWorks 6.8+
Removed C++ static constructor, do it from epicsThreadInit()
---
documentation/RELEASE_NOTES.html | 7 +++++++
src/libCom/osi/os/vxWorks/atReboot.cpp | 25 +++++++++----------------
src/libCom/osi/os/vxWorks/osdThread.c | 9 +++------
3 files changed, 19 insertions(+), 22 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 366ef973a..8f15fb77c 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,13 @@
+VxWorks sysAtReboot Registration
+
+The increasing intelligence of the GNU compiler and linker broke the method
+that was being used by the VxWorks code to register a reboot hook that can close
+down TCP connections nicely before the network stack gets disabled. This has
+been fixed and no longer uses a C++ static contructor to execute that code.
+
IOCS_APPL_TOP and INSTALL_LOCATION
An IOC application that sets INSTALL_LOCATION in its configure/CONFIG_SITE
diff --git a/src/libCom/osi/os/vxWorks/atReboot.cpp b/src/libCom/osi/os/vxWorks/atReboot.cpp
index cb4bff5cc..9a35286ef 100644
--- a/src/libCom/osi/os/vxWorks/atReboot.cpp
+++ b/src/libCom/osi/os/vxWorks/atReboot.cpp
@@ -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.
\*************************************************************************/
/* atReboot.cpp */
@@ -16,34 +15,28 @@
#include "epicsDynLink.h"
#include "epicsExit.h"
-/* osdThread references atRebootExtern just to make this module load*/
-int atRebootExtern;
+extern "C" {
typedef int (*sysAtReboot_t)(void(func)(void));
-class atRebootRegister {
-public:
- atRebootRegister();
-};
-
-atRebootRegister::atRebootRegister()
+void atRebootRegister(void)
{
STATUS status;
sysAtReboot_t sysAtReboot;
SYM_TYPE type;
status = symFindByNameEPICS(sysSymTbl, "_sysAtReboot",
- (char **)&sysAtReboot, &type);
+ (char **)&sysAtReboot, &type);
if (status == OK) {
status = sysAtReboot(epicsExitCallAtExits);
if (status != OK) {
printf("atReboot: sysAtReboot returned error %d\n", status);
}
} else {
- printf("BSP routine sysAtReboot() not found, epicsExit() will not be\n"
- "called by reboot. For reduced functionality, call\n"
- " rebootHookAdd(epicsExitCallAtExits)\n");
+ printf("BSP routine sysAtReboot() not found, epicsExit() will not be\n"
+ "called by reboot. For reduced functionality, call\n"
+ " rebootHookAdd(epicsExitCallAtExits)\n");
}
}
-static atRebootRegister atRebootRegisterObj;
+}
diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c
index 69034b794..237347117 100644
--- a/src/libCom/osi/os/vxWorks/osdThread.c
+++ b/src/libCom/osi/os/vxWorks/osdThread.c
@@ -43,12 +43,8 @@
static const unsigned stackSizeTable[epicsThreadStackBig+1] =
{4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR};
-/*The following forces atReboot to be loaded*/
-extern int atRebootExtern;
-static struct pext {
- int *pExtern;
- struct pext *pext;
-} pext = {&atRebootExtern, &pext};
+/* This routine is found in atReboot.cpp */
+extern void atRebootRegister(void);
/* definitions for implementation of epicsThreadPrivate */
static void **papTSD = 0;
@@ -93,6 +89,7 @@ static void epicsThreadInit(void)
epicsThreadOnceMutex = semMCreate(
SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
assert(epicsThreadOnceMutex);
+ atRebootRegister();
}
lock = 0;
}
From 5ac686fafda3219db04937f6ad04871af81089f5 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 25 Apr 2013 17:00:36 -0500
Subject: [PATCH 08/16] tools: Munch support for module destructors
Added in VxWorks 6.9
---
src/tools/munch.pl | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/src/tools/munch.pl b/src/tools/munch.pl
index 2ed6567fb..f6c0d6e08 100644
--- a/src/tools/munch.pl
+++ b/src/tools/munch.pl
@@ -1,6 +1,6 @@
#!/usr/bin/env perl
#*************************************************************************
-# Copyright (c) 2010 UChicago Argonne LLC, 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.
@@ -24,6 +24,9 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1;
# Is exception handler frame info required?
my $need_eh_frame = 0;
+# Is module destructor needed?
+my $need_mod_dtor = 0;
+
# Constructor and destructor names:
# Array contains names from input file.
# Hash is used to skip duplicate names.
@@ -34,6 +37,7 @@ while (<>)
{
chomp;
$need_eh_frame++ if m/__? gxx_personality_v [0-9]/x;
+ $need_mod_dtor++ if m/__? cxa_atexit $/x;
next if m/__? GLOBAL_. (F | I._GLOBAL_.D) .+/x;
if (m/__? GLOBAL_ . D .+/x) {
my ($addr, $type, $name) = split ' ', $_, 3;
@@ -55,8 +59,11 @@ push my @out,
'',
'/* Declarations */',
(map {cDecl($_)} @ctors, @dtors),
+ '',
+ 'char __dso_handle = 0;',
'';
+moduleDestructor() if $need_mod_dtor;
exceptionHandlerFrame() if $need_eh_frame;
push @out,
@@ -81,6 +88,19 @@ if ($opt_o) {
print join "\n", @out;
}
+# Outputs the C code for registering a module destructor
+sub moduleDestructor {
+ my $mod_dtor = 'mod_dtor';
+ push @dtors, $mod_dtor;
+ push @out,
+ '/* Module destructor */',
+ "static void $mod_dtor(void) {",
+ ' extern void __cxa_finalize(void *);',
+ '',
+ ' __cxa_finalize(&__dso_handle);',
+ '}',
+ '';
+}
# Outputs the C code for registering exception handler frame info
sub exceptionHandlerFrame {
@@ -97,7 +117,11 @@ sub exceptionHandlerFrame {
'',
"static void $eh_ctor(void) {",
' extern void __register_frame_info (const void *, void *);',
- ' static struct { unsigned pad[8]; } object;',
+ ' static struct {',
+ ' void *a, *b, *c, *d;',
+ ' unsigned long e;',
+ ' void *f, *g;',
+ ' } object;',
'',
' __register_frame_info(__EH_FRAME_BEGIN__, &object);',
'}',
@@ -108,7 +132,6 @@ sub exceptionHandlerFrame {
' __deregister_frame_info(__EH_FRAME_BEGIN__);',
'}',
'';
- return;
}
sub cName {
From 34744264e1b6cbfb437e26f970df326dc4367b21 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Mon, 6 May 2013 17:29:10 -0500
Subject: [PATCH 09/16] libCom: Fix win32 handle leak
Closing an epicsThread would leak one Win32 handle.
Reported by Giles Knap, Diamond.
---
src/libCom/osi/os/WIN32/osdThread.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c
index 46c1009c8..a3125e1f5 100644
--- a/src/libCom/osi/os/WIN32/osdThread.c
+++ b/src/libCom/osi/os/WIN32/osdThread.c
@@ -3,9 +3,8 @@
* 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.
\*************************************************************************/
/*
@@ -246,10 +245,7 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
ellDelete ( & pGbl->threadList, & pParm->node );
LeaveCriticalSection ( & pGbl->mutex );
- /* close the handle if its an implicit thread id */
- if ( ! pParm->funptr ) {
- CloseHandle ( pParm->handle );
- }
+ CloseHandle ( pParm->handle );
free ( pParm );
TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, 0 );
}
From 593e313fab47db62e59aa042297d2ca3b3f0845f Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Thu, 9 May 2013 15:48:49 -0500
Subject: [PATCH 10/16] dbStatic: More commands accept "" or "*" to mean 'all'
dbDumpRecordType, dbDumpMenu and dbDumpRecord commands improved.
---
documentation/RELEASE_NOTES.html | 8 ++++++++
src/dbStatic/dbStaticLib.c | 19 +++++++++++++++++--
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 8f15fb77c..d2464baaa 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,14 @@
+More dbStatic commands accept "" or "*" to mean 'all'
+
+The IOC commands dbDumpRecordType, dbDumpMenu and dbDumpRecord will now
+accept either an empty string or any string beginning with an asterisk '*' to
+mean all record types or menus. Previously the 'all' option for these commands
+required passing in a NULL value, which could be done from the vxWorks shell but
+was not possible from iocsh.
+
VxWorks sysAtReboot Registration
The increasing intelligence of the GNU compiler and linker broke the method
diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c
index 247240f25..56d54928c 100644
--- a/src/dbStatic/dbStaticLib.c
+++ b/src/dbStatic/dbStaticLib.c
@@ -901,6 +901,11 @@ long epicsShareAPI dbWriteRecordFP(
dctonly = ((level>1) ? FALSE : TRUE);
dbInitEntry(pdbbase,pdbentry);
+ if (precordTypename) {
+ if (*precordTypename == 0 || *precordTypename == '*')
+ precordTypename = 0;
+ }
+
if(!precordTypename) {
status = dbFirstRecordType(pdbentry);
if(status) {
@@ -997,6 +1002,10 @@ long epicsShareAPI dbWriteMenuFP(DBBASE *pdbbase,FILE *fp,const char *menuName)
fprintf(stderr,"pdbbase not specified\n");
return(-1);
}
+ if (menuName) {
+ if (*menuName == 0 || *menuName == '*')
+ menuName = 0;
+ }
pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
while(pdbMenu) {
if(menuName) {
@@ -1042,6 +1051,11 @@ long epicsShareAPI dbWriteRecordTypeFP(
fprintf(stderr,"pdbbase not specified\n");
return(-1);
}
+ if (recordTypeName) {
+ if (*recordTypeName == 0 || *recordTypeName == '*')
+ recordTypeName = 0;
+ }
+
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
if(recordTypeName) {
@@ -3962,8 +3976,9 @@ void epicsShareAPI dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName)
devSup *pdevSup;
int gotMatch;
- if(recordTypeName) {
- if(recordTypeName[0]==0 || recordTypeName[0] == '*') recordTypeName = 0;
+ if (recordTypeName) {
+ if (*recordTypeName == 0 || *recordTypeName == '*')
+ recordTypeName = 0;
}
if(!pdbbase) {
fprintf(stderr,"pdbbase not specified\n");
From e0bc071de3d4585ae2bc3b51751c4c89439abce4 Mon Sep 17 00:00:00 2001
From: "Jeff Hill johill@lanl.gov"
Date: Thu, 16 May 2013 12:33:31 -0600
Subject: [PATCH 11/16] merged in fix for
https://bugs.launchpad.net/epics-base/+bug/1179642 also merged in removal of
c++ support for old HPUX compiler
---
src/ca/CASG.cpp | 56 +++++-----
src/ca/access.cpp | 40 ++++++--
src/ca/acctst.c | 158 +++++++++++++++++++++++++++++
src/ca/bhe.cpp | 7 --
src/ca/bhe.h | 1 -
src/ca/ca_client_context.cpp | 32 ++++--
src/ca/cac.cpp | 13 +--
src/ca/cac.h | 10 +-
src/ca/cacIO.h | 33 ++++--
src/ca/casw.cpp | 4 +-
src/ca/comBuf.h | 5 +-
src/ca/comQueRecv.cpp | 2 +-
src/ca/comQueSend.cpp | 2 +-
src/ca/disconnectGovernorTimer.cpp | 2 +-
src/ca/disconnectGovernorTimer.h | 2 +-
src/ca/getCallback.cpp | 7 --
src/ca/getCopy.cpp | 7 --
src/ca/iocinf.cpp | 20 ++--
src/ca/msgForMultiplyDefinedPV.cpp | 7 --
src/ca/msgForMultiplyDefinedPV.h | 3 +-
src/ca/nciu.cpp | 30 +++---
src/ca/nciu.h | 12 ++-
src/ca/netIO.h | 13 +--
src/ca/netReadNotifyIO.cpp | 7 --
src/ca/netSubscription.cpp | 7 --
src/ca/netWriteNotifyIO.cpp | 8 --
src/ca/netiiu.h | 2 +-
src/ca/oldAccess.h | 71 ++++++++++---
src/ca/oldChannelNotify.cpp | 18 ++--
src/ca/putCallback.cpp | 7 --
src/ca/repeater.cpp | 13 +--
src/ca/repeaterClient.h | 1 -
src/ca/repeaterSubscribeTimer.cpp | 2 +-
src/ca/repeaterSubscribeTimer.h | 2 +-
src/ca/searchTimer.cpp | 2 +-
src/ca/searchTimer.h | 2 +-
src/ca/sgAutoPtr.h | 21 ++--
src/ca/syncGroup.h | 70 ++++++-------
src/ca/syncGroupReadNotify.cpp | 30 +++---
src/ca/syncGroupWriteNotify.cpp | 28 +++--
src/ca/syncgrp.cpp | 123 +++++++++++++++++-----
src/ca/tcpRecvWatchdog.cpp | 2 +-
src/ca/tcpiiu.cpp | 35 +++----
src/ca/test_event.cpp | 4 +-
src/ca/udpiiu.cpp | 4 +-
src/ca/virtualCircuit.h | 3 +-
src/db/dbCAC.h | 15 ++-
src/db/dbChannelIO.cpp | 20 ++--
src/db/dbChannelIO.h | 6 +-
src/db/dbContext.cpp | 34 ++++---
src/db/dbPutNotifyBlocker.cpp | 13 +--
src/db/dbPutNotifyBlocker.h | 5 +-
src/db/dbSubscriptionIO.cpp | 13 +--
53 files changed, 635 insertions(+), 399 deletions(-)
diff --git a/src/ca/CASG.cpp b/src/ca/CASG.cpp
index 16573d1bc..f5cb64e0e 100644
--- a/src/ca/CASG.cpp
+++ b/src/ca/CASG.cpp
@@ -25,8 +25,6 @@
#include "cac.h"
#include "sgAutoPtr.h"
-casgRecycle::~casgRecycle () {}
-
CASG::CASG ( epicsGuard < epicsMutex > & guard, ca_client_context & cacIn ) :
client ( cacIn ), magic ( CASG_MAGIC )
{
@@ -38,12 +36,13 @@ CASG::~CASG ()
}
void CASG::destructor (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
if ( this->verify ( guard ) ) {
- this->reset ( guard );
+ this->reset ( cbGuard, guard );
this->client.uninstallCASG ( guard, *this );
this->magic = 0;
}
@@ -127,36 +126,37 @@ int CASG::block (
delay = cur_time - beg_time;
}
- this->reset ( guard );
-
return status;
}
void CASG::reset (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
- this->destroyCompletedIO ( guard );
- this->destroyPendingIO ( guard );
+ this->destroyCompletedIO ( cbGuard, guard );
+ this->destroyPendingIO ( cbGuard, guard );
}
// lock must be applied
void CASG::destroyCompletedIO (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
syncGroupNotify * pNotify;
while ( ( pNotify = this->ioCompletedList.get () ) ) {
- pNotify->destroy ( guard, * this );
+ pNotify->destroy ( cbGuard, guard );
}
}
void CASG::destroyPendingIO (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) {
- pNotify->cancel ( guard );
+ pNotify->cancel ( cbGuard, guard );
// cancel must release the guard while
// canceling put callbacks so we
// must double check list membership
@@ -166,7 +166,7 @@ void CASG::destroyPendingIO (
else {
this->ioCompletedList.remove ( *pNotify );
}
- pNotify->destroy ( guard, *this );
+ pNotify->destroy ( cbGuard, guard );
}
}
@@ -201,10 +201,11 @@ void CASG::show (
}
bool CASG::ioComplete (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
- this->destroyCompletedIO ( guard );
+ this->destroyCompletedIO ( cbGuard, guard );
return this->ioPendingList.count () == 0u;
}
@@ -212,9 +213,9 @@ void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan,
unsigned type, arrayElementCount count, const void * pValue )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
- sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this, this->ioPendingList );
+ sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this );
pNotify = syncGroupWriteNotify::factory (
- this->freeListWriteOP, *this, pChan );
+ this->freeListWriteOP, *this, & CASG :: recycleWriteNotifyIO, pChan );
pNotify->begin ( guard, type, count, pValue );
pNotify.release ();
}
@@ -223,9 +224,9 @@ void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan,
unsigned type, arrayElementCount count, void *pValue )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
- sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this, this->ioPendingList );
+ sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this );
pNotify = syncGroupReadNotify::factory (
- this->freeListReadOP, *this, pChan, pValue );
+ this->freeListReadOP, *this, & CASG :: recycleReadNotifyIO, pChan, pValue );
pNotify->begin ( guard, type, count );
pNotify.release ();
}
@@ -241,20 +242,20 @@ void CASG::completionNotify (
}
}
-void CASG::recycleSyncGroupWriteNotify (
- epicsGuard < epicsMutex > & guard, syncGroupWriteNotify & io )
-{
- guard.assertIdenticalMutex ( this->client.mutexRef() );
- this->freeListWriteOP.release ( & io );
-}
-
-void CASG::recycleSyncGroupReadNotify (
- epicsGuard < epicsMutex > & guard, syncGroupReadNotify & io )
+void CASG :: recycleReadNotifyIO ( epicsGuard < epicsMutex > & guard,
+ syncGroupReadNotify & io )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
this->freeListReadOP.release ( & io );
}
+void CASG :: recycleWriteNotifyIO ( epicsGuard < epicsMutex > & guard,
+ syncGroupWriteNotify & io )
+{
+ guard.assertIdenticalMutex ( this->client.mutexRef() );
+ this->freeListWriteOP.release ( & io );
+}
+
int CASG :: printFormated ( const char *pformat, ... )
{
va_list theArgs;
@@ -295,13 +296,6 @@ void CASG::exception (
}
}
-void * CASG::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void CASG::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/access.cpp b/src/ca/access.cpp
index 85fe2b205..74f74325a 100644
--- a/src/ca/access.cpp
+++ b/src/ca/access.cpp
@@ -376,15 +376,35 @@ int epicsShareAPI ca_create_channel (
int epicsShareAPI ca_clear_channel ( chid pChan )
{
ca_client_context & cac = pChan->getClientCtx ();
- epicsGuard < epicsMutex > guard ( cac.mutex );
- try {
- pChan->eliminateExcessiveSendBacklog ( guard );
+ {
+ epicsGuard < epicsMutex > guard ( cac.mutex );
+ try {
+ pChan->eliminateExcessiveSendBacklog ( guard );
+ }
+ catch ( cacChannel::notConnected & ) {
+ // intentionally ignored
+ }
}
- catch ( cacChannel::notConnected & ) {
- // intentionally ignored
- }
- pChan->destructor ( guard );
+ if ( cac.pCallbackGuard.get() &&
+ cac.createdByThread == epicsThreadGetIdSelf () ) {
+ epicsGuard < epicsMutex > guard ( cac.mutex );
+ pChan->destructor ( *cac.pCallbackGuard.get(), guard );
cac.oldChannelNotifyFreeList.release ( pChan );
+ }
+ else {
+ //
+ // we will definately stall out here if all of the
+ // following are true
+ //
+ // o user creates non-preemtive mode client library context
+ // o user doesnt periodically call a ca function
+ // o user calls this function from an auxiillary thread
+ //
+ CallbackGuard cbGuard ( cac.cbMutex );
+ epicsGuard < epicsMutex > guard ( cac.mutex );
+ pChan->destructor ( *cac.pCallbackGuard.get(), guard );
+ cac.oldChannelNotifyFreeList.release ( pChan );
+ }
return ECA_NORMAL;
}
@@ -433,7 +453,7 @@ chid epicsShareAPI ca_evid_to_chid ( evid pMon )
}
// extern "C"
-int epicsShareAPI ca_pend ( ca_real timeout, int early ) // X aCC 361
+int epicsShareAPI ca_pend ( ca_real timeout, int early )
{
if ( early ) {
return ca_pend_io ( timeout );
@@ -516,7 +536,7 @@ int epicsShareAPI ca_flush_io ()
/*
* CA_TEST_IO ()
*/
-int epicsShareAPI ca_test_io () // X aCC 361
+int epicsShareAPI ca_test_io ()
{
ca_client_context *pcac;
int caStatus = fetchClientContext ( &pcac );
@@ -551,7 +571,7 @@ void epicsShareAPI ca_signal ( long ca_status, const char *message )
* (if they call this routine again).
*/
// extern "C"
-const char * epicsShareAPI ca_message ( long ca_status ) // X aCC 361
+const char * epicsShareAPI ca_message ( long ca_status )
{
unsigned msgNo = CA_EXTRACT_MSG_NO ( ca_status );
diff --git a/src/ca/acctst.c b/src/ca/acctst.c
index f2d102868..a01ee131d 100644
--- a/src/ca/acctst.c
+++ b/src/ca/acctst.c
@@ -13,6 +13,7 @@
* Authors:
* Jeff Hill
* Murali Shankar - initial versions of verifyMultithreadSubscr
+ * Michael Abbott - initial versions of multiSubscrDestroyNoLateCallbackTest
*
*/
@@ -1328,6 +1329,158 @@ void test_sync_groups ( chid chan, unsigned interestLevel )
showProgressEnd ( interestLevel );
}
+#define multiSubscrDestroyNoLateCallbackEventCount 500
+
+struct MultiSubscrDestroyNoLateCallbackEventData {
+ evid m_id;
+ size_t m_nCallback;
+ int m_callbackIsOk;
+ struct MultiSubscrDestroyNoLateCallbackTestData * m_pTestData;
+};
+
+struct MultiSubscrDestroyNoLateCallbackTestData {
+ const char * m_pChanName;
+ chid m_chan;
+ epicsMutexId m_mutex;
+ epicsEventId m_testDoneEvent;
+ unsigned m_interestLevel;
+ struct MultiSubscrDestroyNoLateCallbackEventData
+ m_eventData [multiSubscrDestroyNoLateCallbackEventCount];
+};
+
+static void noLateCallbackDetect ( struct event_handler_args args )
+{
+ int callbackIsOk;
+ struct MultiSubscrDestroyNoLateCallbackEventData * const pEventData = args.usr;
+ epicsMutexLockStatus lockStatus = epicsMutexLock ( pEventData->m_pTestData->m_mutex );
+ callbackIsOk = pEventData->m_callbackIsOk;
+ pEventData->m_nCallback++;
+ epicsMutexUnlock ( pEventData->m_pTestData->m_mutex );
+ verify ( lockStatus == epicsMutexLockOK );
+ verify ( callbackIsOk );
+}
+
+static void multiSubscrDestroyNoLateCallbackThread ( void * pParm )
+{
+ struct MultiSubscrDestroyNoLateCallbackTestData * const pTestData =
+ ( struct MultiSubscrDestroyNoLateCallbackTestData * ) pParm;
+ unsigned i, j;
+ int status;
+
+ status = ca_context_create ( ca_enable_preemptive_callback );
+ verify ( status == ECA_NORMAL );
+
+ status = ca_create_channel ( pTestData->m_pChanName, 0, 0,
+ CA_PRIORITY_DEFAULT, &pTestData->m_chan );
+ status = ca_pend_io ( timeoutToPendIO );
+ SEVCHK ( status, "multiSubscrDestroyLateNoCallbackTest: channel connect failed" );
+ verify ( status == ECA_NORMAL );
+
+ /*
+ * create a set of subscriptions
+ */
+ for ( i=0; i < 10000; i++ ) {
+ unsigned int priorityOfTestThread;
+ for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) {
+ epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex );
+ verify ( lockStatus == epicsMutexLockOK );
+ pTestData->m_eventData[j].m_nCallback = 0;
+ pTestData->m_eventData[j].m_callbackIsOk = TRUE;
+ pTestData->m_eventData[j].m_pTestData = pTestData;
+ epicsMutexUnlock ( pTestData->m_mutex );
+ SEVCHK ( ca_add_event ( DBR_GR_FLOAT, pTestData->m_chan, noLateCallbackDetect,
+ &pTestData->m_eventData[j], &pTestData->m_eventData[j].m_id ) , NULL );
+ }
+ SEVCHK ( ca_flush_io(), NULL );
+
+ /*
+ * raise the priority of the current thread hoping to improve our
+ * likelyhood of detecting a bug
+ */
+ priorityOfTestThread = epicsThreadGetPrioritySelf ();
+ epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsThreadPriorityHigh );
+
+
+ /*
+ * wait for the first subscription update to arrive
+ */
+ {
+ epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex );
+ verify ( lockStatus == epicsMutexLockOK );
+ while ( pTestData->m_eventData[0].m_nCallback == 0 ) {
+ epicsMutexUnlock ( pTestData->m_mutex );
+ epicsThreadSleep ( 50e-6 );
+ lockStatus = epicsMutexLock ( pTestData->m_mutex );
+ verify ( lockStatus == epicsMutexLockOK );
+ }
+ epicsMutexUnlock ( pTestData->m_mutex );
+ }
+ /*
+ * try to destroy all of the subscriptions at precisely the same time that
+ * their first callbacks are running
+ */
+ for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) {
+ SEVCHK ( ca_clear_event ( pTestData->m_eventData[j].m_id ) , NULL );
+ epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex );
+ verify ( lockStatus == epicsMutexLockOK );
+ pTestData->m_eventData[j].m_callbackIsOk = FALSE;
+ epicsMutexUnlock ( pTestData->m_mutex );
+ }
+ /*
+ * return to the original priority
+ */
+ epicsThreadSetPriority ( epicsThreadGetIdSelf(), priorityOfTestThread );
+
+ if ( i % 1000 == 0 ) {
+ showProgress ( pTestData->m_interestLevel );
+ }
+ }
+
+ SEVCHK ( ca_clear_channel ( pTestData->m_chan ), NULL );
+
+ ca_context_destroy ();
+
+ epicsEventSignal ( pTestData->m_testDoneEvent );
+}
+
+/*
+ * verify that, in a preemtive callback mode client, a subscription callback never
+ * comes after the subscription is destroyed
+ */
+static void multiSubscrDestroyNoLateCallbackTest ( const char *pName, unsigned interestLevel )
+{
+ struct MultiSubscrDestroyNoLateCallbackTestData * pTestData;
+
+ showProgressBegin ( "multiSubscrDestroyNoLateCallbackTest", interestLevel );
+
+ pTestData = calloc ( 1u, sizeof ( struct MultiSubscrDestroyNoLateCallbackTestData ) );
+ verify ( pTestData );
+ pTestData->m_mutex = epicsMutexMustCreate ();
+ pTestData->m_testDoneEvent = epicsEventMustCreate ( epicsEventEmpty );
+ pTestData->m_pChanName = pName;
+ pTestData->m_interestLevel = interestLevel;
+ epicsThreadMustCreate (
+ "multiSubscrDestroyNoLateCallbackTest",
+ epicsThreadPriorityLow,
+ epicsThreadGetStackSize ( epicsThreadStackMedium ),
+ multiSubscrDestroyNoLateCallbackThread,
+ pTestData );
+
+ /*
+ * wait for test to complete
+ */
+ epicsEventMustWait ( pTestData->m_testDoneEvent );
+
+ /*
+ * cleanup
+ */
+ epicsMutexDestroy ( pTestData->m_mutex );
+ epicsEventDestroy ( pTestData->m_testDoneEvent );
+ free ( pTestData );
+
+ showProgressEnd ( interestLevel );
+}
+
/*
* multiSubscriptionDeleteTest
*
@@ -3263,6 +3416,11 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
epicsEnvSet ( "EPICS_CA_MAX_ARRAY_BYTES", tmpString );
}
+ /*
+ * this test creates, and then destroys, a private CA context
+ */
+ multiSubscrDestroyNoLateCallbackTest ( pName, interestLevel );
+
status = ca_context_create ( select );
SEVCHK ( status, NULL );
diff --git a/src/ca/bhe.cpp b/src/ca/bhe.cpp
index 8ede482b4..d6f1796be 100644
--- a/src/ca/bhe.cpp
+++ b/src/ca/bhe.cpp
@@ -332,13 +332,6 @@ void bhe::unregisterIIU (
}
}
-void * bhe::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void bhe::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/bhe.h b/src/ca/bhe.h
index 1660e485b..4da95202a 100644
--- a/src/ca/bhe.h
+++ b/src/ca/bhe.h
@@ -87,7 +87,6 @@ private:
const epicsTime & currentTime );
bhe ( const bhe & );
bhe & operator = ( const bhe & );
- void * operator new ( size_t size );
epicsShareFunc void operator delete ( void * );
};
diff --git a/src/ca/ca_client_context.cpp b/src/ca/ca_client_context.cpp
index f0d71f5b3..b8f6d9d0b 100644
--- a/src/ca/ca_client_context.cpp
+++ b/src/ca/ca_client_context.cpp
@@ -106,7 +106,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
{
osiSockIoctl_t yes = true;
- int status = socket_ioctl ( this->sock, // X aCC 392
+ int status = socket_ioctl ( this->sock,
FIONBIO, & yes);
if ( status < 0 ) {
char sockErrBuf[64];
@@ -126,7 +126,7 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
memset ( (char *)&addr, 0 , sizeof ( addr ) );
addr.ia.sin_family = AF_INET;
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
- addr.ia.sin_port = htons ( PORT_ANY ); // X aCC 818
+ addr.ia.sin_port = htons ( PORT_ANY );
int status = bind (this->sock, &addr.sa, sizeof (addr) );
if ( status < 0 ) {
char sockErrBuf[64];
@@ -159,9 +159,9 @@ ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
this->localPort = htons ( tmpAddr.ia.sin_port );
}
- epics_auto_ptr < epicsGuard < epicsMutex > > pCBGuard;
+ epics_auto_ptr < CallbackGuard > pCBGuard;
if ( ! enablePreemptiveCallback ) {
- pCBGuard.reset ( new epicsGuard < epicsMutex > ( this->cbMutex ) );
+ pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) );
}
// multiple steps ensure exception safety
@@ -277,7 +277,7 @@ int ca_client_context :: printFormated (
}
int ca_client_context :: varArgsPrintFormated (
- const char *pformat, va_list args ) const // X aCC 361
+ const char *pformat, va_list args ) const
{
caPrintfFunc * pFunc;
{
@@ -751,6 +751,8 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
{
oldChannelNotify & chan = pMon->channel ();
ca_client_context & cac = chan.getClientCtx ();
+ // !!!! the order in which we take the mutex here prevents deadlocks
+ {
epicsGuard < epicsMutex > guard ( cac.mutex );
try {
// if this stalls out on a live circuit then an exception
@@ -761,7 +763,25 @@ epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
catch ( cacChannel::notConnected & ) {
// intentionally ignored
}
- pMon->cancel ( guard );
+ }
+ if ( cac.pCallbackGuard.get() &&
+ cac.createdByThread == epicsThreadGetIdSelf () ) {
+ epicsGuard < epicsMutex > guard ( cac.mutex );
+ pMon->cancel ( *cac.pCallbackGuard.get(), guard );
+ }
+ else {
+ //
+ // we will definately stall out here if all of the
+ // following are true
+ //
+ // o user creates non-preemtive mode client library context
+ // o user doesnt periodically call a ca function
+ // o user calls this function from an auxiillary thread
+ //
+ CallbackGuard cbGuard ( cac.cbMutex );
+ epicsGuard < epicsMutex > guard ( cac.mutex );
+ pMon->cancel ( cbGuard, guard );
+ }
return ECA_NORMAL;
}
diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp
index 42a491fec..0317f2145 100644
--- a/src/ca/cac.cpp
+++ b/src/ca/cac.cpp
@@ -568,7 +568,7 @@ bool cac::findOrCreateVirtCircuit (
}
void cac::transferChanToVirtCircuit (
- unsigned cid, unsigned sid, // X aCC 431
+ unsigned cid, unsigned sid,
ca_uint16_t typeCode, arrayElementCount count,
unsigned minorVersionNumber, const osiSockAddr & addr,
const epicsTime & currentTime )
@@ -711,6 +711,7 @@ netReadNotifyIO & cac::readNotifyRequest (
}
bool cac::destroyIO (
+ CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & guard,
const cacChannel::ioid & idIn, nciu & chan )
{
@@ -787,7 +788,7 @@ void cac::recycleSubscription (
netSubscription & cac::subscriptionRequest (
epicsGuard < epicsMutex > & guard,
nciu & chan, privateInterfaceForIO & privChan,
- unsigned type, // X aCC 361
+ unsigned type,
arrayElementCount nElem, unsigned mask,
cacStateNotify & notifyIn,
bool chanIsInstalled )
@@ -1021,7 +1022,7 @@ bool cac::readExcep ( callbackManager &, tcpiiu &,
}
bool cac::writeExcep (
- callbackManager & mgr, // X aCC 431
+ callbackManager & mgr,
tcpiiu &, const caHdrLargeArray & hdr,
const char * pCtx, unsigned status )
{
@@ -1093,7 +1094,7 @@ bool cac::exceptionRespAction ( callbackManager & cbMutexIn, tcpiiu & iiu,
}
bool cac::accessRightsRespAction (
- callbackManager & mgr, tcpiiu &, // X aCC 431
+ callbackManager & mgr, tcpiiu &,
const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ )
{
epicsGuard < epicsMutex > guard ( this->mutex );
@@ -1110,7 +1111,7 @@ bool cac::accessRightsRespAction (
}
bool cac::createChannelRespAction (
- callbackManager & mgr, tcpiiu & iiu, // X aCC 431
+ callbackManager & mgr, tcpiiu & iiu,
const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ )
{
epicsGuard < epicsMutex > guard ( this->mutex );
@@ -1157,7 +1158,7 @@ bool cac::verifyAndDisconnectChan (
}
void cac::disconnectChannel (
- epicsGuard < epicsMutex > & cbGuard, // X aCC 431
+ epicsGuard < epicsMutex > & cbGuard,
epicsGuard < epicsMutex > & guard, nciu & chan )
{
guard.assertIdenticalMutex ( this->mutex );
diff --git a/src/ca/cac.h b/src/ca/cac.h
index ae20eef27..63acccb6f 100644
--- a/src/ca/cac.h
+++ b/src/ca/cac.h
@@ -55,7 +55,7 @@ class netSubscription;
// used to control access to cac's recycle routines which
// should only be indirectly invoked by CAC when its lock
// is applied
-class cacRecycle { // X aCC 655
+class cacRecycle {
public:
virtual void recycleReadNotifyIO (
epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0;
@@ -155,7 +155,8 @@ public:
unsigned type, arrayElementCount nElem, unsigned mask,
cacStateNotify &, bool channelIsInstalled );
bool destroyIO (
- epicsGuard < epicsMutex > & guard,
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExclusionGuard,
const cacChannel::ioid & idIn,
nciu & chan );
void disconnectAllIO (
@@ -167,11 +168,6 @@ public:
epicsGuard < epicsMutex > & guard,
const cacChannel::ioid &id, unsigned level ) const;
- // sync group routines
- CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id );
- void installCASG ( epicsGuard < epicsMutex > &, CASG & );
- void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & );
-
// exception generation
void exception (
epicsGuard < epicsMutex > & cbGuard,
diff --git a/src/ca/cacIO.h b/src/ca/cacIO.h
index 8086f1239..dd3955737 100644
--- a/src/ca/cacIO.h
+++ b/src/ca/cacIO.h
@@ -69,7 +69,7 @@ typedef unsigned long arrayElementCount;
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
-class epicsShareClass cacWriteNotify { // X aCC 655
+class epicsShareClass cacWriteNotify {
public:
virtual ~cacWriteNotify () = 0;
virtual void completion ( epicsGuard < epicsMutex > & ) = 0;
@@ -82,7 +82,7 @@ public:
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
-class epicsShareClass cacReadNotify { // X aCC 655
+class epicsShareClass cacReadNotify {
public:
virtual ~cacReadNotify () = 0;
virtual void completion (
@@ -97,7 +97,7 @@ public:
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
-class epicsShareClass cacStateNotify { // X aCC 655
+class epicsShareClass cacStateNotify {
public:
virtual ~cacStateNotify () = 0;
virtual void current (
@@ -131,7 +131,7 @@ private:
bool f_operatorConfirmationRequest:1;
};
-class epicsShareClass cacChannelNotify { // X aCC 655
+class epicsShareClass cacChannelNotify {
public:
virtual ~cacChannelNotify () = 0;
virtual void connectNotify ( epicsGuard < epicsMutex > & ) = 0;
@@ -152,6 +152,16 @@ public:
unsigned type, arrayElementCount count ) = 0;
};
+class CallbackGuard :
+ public epicsGuard < epicsMutex > {
+public:
+ CallbackGuard ( epicsMutex & mutex ) :
+ epicsGuard < epicsMutex > ( mutex ) {}
+private:
+ CallbackGuard ( const CallbackGuard & );
+ CallbackGuard & operator = ( const CallbackGuard & );
+};
+
//
// Notes
// 1) This interface assumes that when a channel is deleted then all
@@ -174,6 +184,7 @@ public:
cacChannel ( cacChannelNotify & );
virtual void destroy (
+ CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
cacChannelNotify & notify () const; // required ?????
virtual unsigned getName (
@@ -207,7 +218,15 @@ public:
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, unsigned mask, cacStateNotify &,
ioid * = 0 ) = 0;
+ // The primary mutex must be released when calling the user's
+ // callback, and therefore a finite interval exists when we are
+ // moving forward with the intent to call the users callback
+ // but the users IO could be deleted during this interval.
+ // To prevent the user's callback from being called after
+ // destroying his IO we must past a guard for the callback
+ // mutex here.
virtual void ioCancel (
+ CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & ) = 0;
virtual void ioShow (
@@ -258,7 +277,7 @@ private:
cacChannel & operator = ( const cacChannel & );
};
-class epicsShareClass cacContext { // X aCC 655
+class epicsShareClass cacContext {
public:
virtual ~cacContext ();
virtual cacChannel & createChannel (
@@ -277,7 +296,7 @@ public:
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
};
-class epicsShareClass cacContextNotify { // X aCC 655
+class epicsShareClass cacContextNotify {
public:
virtual ~cacContextNotify () = 0;
virtual cacContext & createNetworkContext (
@@ -297,7 +316,7 @@ public:
// **** Lock Hierarchy ****
// callbackControl must be taken before mutualExclusion if both are held at
// the same time
-class epicsShareClass cacService { // X aCC 655
+class epicsShareClass cacService {
public:
virtual ~cacService () = 0;
virtual cacContext & contextCreate (
diff --git a/src/ca/casw.cpp b/src/ca/casw.cpp
index d8334b8ca..f69632c13 100644
--- a/src/ca/casw.cpp
+++ b/src/ca/casw.cpp
@@ -131,7 +131,7 @@ int main ( int argc, char ** argv )
}
osiSockIoctl_t yes = true;
- status = socket_ioctl ( sock, FIONBIO, &yes ); // X aCC 392
+ status = socket_ioctl ( sock, FIONBIO, &yes );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
@@ -166,7 +166,7 @@ int main ( int argc, char ** argv )
}
osiSockIoctl_t no = false;
- status = socket_ioctl ( sock, FIONBIO, &no ); // X aCC 392
+ status = socket_ioctl ( sock, FIONBIO, &no );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
diff --git a/src/ca/comBuf.h b/src/ca/comBuf.h
index 2f6c6faa1..59e38780b 100644
--- a/src/ca/comBuf.h
+++ b/src/ca/comBuf.h
@@ -44,7 +44,7 @@ public:
virtual void release ( void * ) = 0;
};
-class wireSendAdapter { // X aCC 655
+class wireSendAdapter {
public:
virtual unsigned sendBytes ( const void * pBuf,
unsigned nBytesInBuf,
@@ -65,7 +65,7 @@ struct statusWireIO {
swioCircuitState circuitState;
};
-class wireRecvAdapter { // X aCC 655
+class wireRecvAdapter {
public:
virtual void recvBytes ( void * pBuf,
unsigned nBytesInBuf, statusWireIO & ) = 0;
@@ -114,7 +114,6 @@ private:
unsigned nextWriteIndex;
unsigned nextReadIndex;
epicsUInt8 buf [ comBufSize ];
- void * operator new ( size_t size );
void operator delete ( void * );
template < class T >
bool push ( const T * ); // disabled
diff --git a/src/ca/comQueRecv.cpp b/src/ca/comQueRecv.cpp
index db797fd65..88263544d 100644
--- a/src/ca/comQueRecv.cpp
+++ b/src/ca/comQueRecv.cpp
@@ -155,7 +155,7 @@ epicsUInt32 comQueRecv::multiBufferPopUInt32 ()
unsigned byte3 = this->popUInt8();
unsigned byte4 = this->popUInt8();
tmp = static_cast
- ( ( byte1 << 24u ) | ( byte2 << 16u ) | //X aCC 392
+ ( ( byte1 << 24u ) | ( byte2 << 16u ) |
( byte3 << 8u ) | byte4 );
}
else {
diff --git a/src/ca/comQueSend.cpp b/src/ca/comQueSend.cpp
index 5ae150be2..6ed516bb3 100644
--- a/src/ca/comQueSend.cpp
+++ b/src/ca/comQueSend.cpp
@@ -368,7 +368,7 @@ void comQueSend::insertRequestWithPayLoad (
// the above checks verify that the total size
// is lest that 0xffffffff
size = static_cast < ca_uint32_t >
- ( dbr_size_n ( dataType, nElem ) ); // X aCC 392
+ ( dbr_size_n ( dataType, nElem ) );
payloadSize = CA_MESSAGE_ALIGN ( size );
this->insertRequestHeader ( request, payloadSize,
static_cast ( dataType ),
diff --git a/src/ca/disconnectGovernorTimer.cpp b/src/ca/disconnectGovernorTimer.cpp
index 755b29cb3..f1d517f07 100644
--- a/src/ca/disconnectGovernorTimer.cpp
+++ b/src/ca/disconnectGovernorTimer.cpp
@@ -65,7 +65,7 @@ void disconnectGovernorTimer::shutdown (
}
epicsTimerNotify::expireStatus disconnectGovernorTimer::expire (
- const epicsTime & /* currentTime */ ) // X aCC 361
+ const epicsTime & /* currentTime */ )
{
epicsGuard < epicsMutex > guard ( this->mutex );
while ( nciu * pChan = chanList.get () ) {
diff --git a/src/ca/disconnectGovernorTimer.h b/src/ca/disconnectGovernorTimer.h
index 06b8a36a8..f636d6260 100644
--- a/src/ca/disconnectGovernorTimer.h
+++ b/src/ca/disconnectGovernorTimer.h
@@ -43,7 +43,7 @@
#include "caProto.h"
#include "netiiu.h"
-class disconnectGovernorNotify { // X aCC 655
+class disconnectGovernorNotify {
public:
virtual ~disconnectGovernorNotify () = 0;
virtual void govExpireNotify (
diff --git a/src/ca/getCallback.cpp b/src/ca/getCallback.cpp
index e95433dd5..05e654e30 100644
--- a/src/ca/getCallback.cpp
+++ b/src/ca/getCallback.cpp
@@ -90,13 +90,6 @@ void getCallback::exception (
}
}
-void * getCallback::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void getCallback::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/getCopy.cpp b/src/ca/getCopy.cpp
index 978676ef0..23a508d9a 100644
--- a/src/ca/getCopy.cpp
+++ b/src/ca/getCopy.cpp
@@ -105,13 +105,6 @@ void getCopy::show ( unsigned level ) const
}
}
-void * getCopy::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void getCopy::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/iocinf.cpp b/src/ca/iocinf.cpp
index d6fac8178..487067c00 100644
--- a/src/ca/iocinf.cpp
+++ b/src/ca/iocinf.cpp
@@ -133,7 +133,7 @@ extern "C" void epicsShareAPI removeDuplicateAddresses
if ( pNode->addr.sa.sa_family == AF_INET ) {
- pTmpNode = (osiSockAddrNode *) ellFirst (pDestList); // X aCC 749
+ pTmpNode = (osiSockAddrNode *) ellFirst (pDestList);
while ( pTmpNode ) {
if (pTmpNode->addr.sa.sa_family == AF_INET) {
if ( pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr &&
@@ -149,7 +149,7 @@ extern "C" void epicsShareAPI removeDuplicateAddresses
break;
}
}
- pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node); // X aCC 749
+ pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node);
}
if (pNode) {
ellAdd (pDestList, &pNode->node);
@@ -168,12 +168,12 @@ static void forcePort ( ELLLIST *pList, unsigned short port )
{
osiSockAddrNode *pNode;
- pNode = ( osiSockAddrNode * ) ellFirst ( pList ); // X aCC 749
+ pNode = ( osiSockAddrNode * ) ellFirst ( pList );
while ( pNode ) {
if ( pNode->addr.sa.sa_family == AF_INET ) {
pNode->addr.ia.sin_port = htons ( port );
}
- pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node ); // X aCC 749
+ pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node );
}
}
@@ -192,9 +192,9 @@ extern "C" void epicsShareAPI configureChannelAccessAddressList
/*
* dont load the list twice
*/
- assert ( ellCount (pList) == 0 ); // X aCC 392
+ assert ( ellCount (pList) == 0 );
- ellInit ( &tmpList ); // X aCC 392
+ ellInit ( &tmpList );
/*
* Check to see if the user has disabled
@@ -217,12 +217,12 @@ extern "C" void epicsShareAPI configureChannelAccessAddressList
if (yes) {
ELLLIST bcastList;
osiSockAddr addr;
- ellInit ( &bcastList ); // X aCC 392
+ ellInit ( &bcastList );
addr.ia.sin_family = AF_UNSPEC;
osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr );
forcePort ( &bcastList, port );
removeDuplicateAddresses ( &tmpList, &bcastList, 1 );
- if ( ellCount ( &tmpList ) == 0 ) { // X aCC 392
+ if ( ellCount ( &tmpList ) == 0 ) {
osiSockAddrNode *pNewNode;
pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) );
if ( pNewNode ) {
@@ -254,11 +254,11 @@ extern "C" void epicsShareAPI printChannelAccessAddressList ( const ELLLIST *pLi
osiSockAddrNode *pNode;
::printf ( "Channel Access Address List\n" );
- pNode = (osiSockAddrNode *) ellFirst ( pList ); // X aCC 749
+ pNode = (osiSockAddrNode *) ellFirst ( pList );
while (pNode) {
char buf[64];
ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) );
::printf ( "%s\n", buf );
- pNode = (osiSockAddrNode *) ellNext ( &pNode->node ); // X aCC 749
+ pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
}
}
diff --git a/src/ca/msgForMultiplyDefinedPV.cpp b/src/ca/msgForMultiplyDefinedPV.cpp
index 516bb63bb..2f1a45cde 100644
--- a/src/ca/msgForMultiplyDefinedPV.cpp
+++ b/src/ca/msgForMultiplyDefinedPV.cpp
@@ -73,13 +73,6 @@ void msgForMultiplyDefinedPV::operator delete ( void *pCadaver,
}
#endif
-void * msgForMultiplyDefinedPV::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void msgForMultiplyDefinedPV::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/msgForMultiplyDefinedPV.h b/src/ca/msgForMultiplyDefinedPV.h
index 545adc815..45d3453ac 100644
--- a/src/ca/msgForMultiplyDefinedPV.h
+++ b/src/ca/msgForMultiplyDefinedPV.h
@@ -39,7 +39,7 @@
# define epicsExportSharedSymbols
#endif
-class callbackForMultiplyDefinedPV { // X aCC 655
+class callbackForMultiplyDefinedPV {
public:
virtual ~callbackForMultiplyDefinedPV () = 0;
virtual void pvMultiplyDefinedNotify (
@@ -64,7 +64,6 @@ private:
void transactionComplete ( const char * pHostName );
msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & );
msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
diff --git a/src/ca/nciu.cpp b/src/ca/nciu.cpp
index c5ae941b2..66bbf02a0 100644
--- a/src/ca/nciu.cpp
+++ b/src/ca/nciu.cpp
@@ -76,29 +76,24 @@ nciu::~nciu ()
// channels are created by the user, and only destroyed by the user
// using this routine
void nciu::destroy (
- epicsGuard < epicsMutex > & guard )
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExcusionGuard )
{
while ( baseNMIU * pNetIO = this->eventq.first () ) {
- bool success = this->cacCtx.destroyIO ( guard, pNetIO->getId (), *this );
+ bool success = this->cacCtx.destroyIO ( callbackGuard, mutualExcusionGuard,
+ pNetIO->getId (), *this );
assert ( success );
}
// if the claim reply has not returned yet then we will issue
// the clear channel request to the server when the claim reply
// arrives and there is no matching nciu in the client
- if ( this->channelNode::isInstalledInServer ( guard ) ) {
- this->getPIIU(guard)->clearChannelRequest (
- guard, this->sid, this->id );
+ if ( this->channelNode::isInstalledInServer ( mutualExcusionGuard ) ) {
+ this->getPIIU(mutualExcusionGuard)->clearChannelRequest (
+ mutualExcusionGuard, this->sid, this->id );
}
- this->piiu->uninstallChan ( guard, *this );
- this->cacCtx.destroyChannel ( guard, *this );
-}
-
-void * nciu::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
+ this->piiu->uninstallChan ( mutualExcusionGuard, *this );
+ this->cacCtx.destroyChannel ( mutualExcusionGuard, *this );
}
void nciu::operator delete ( void * )
@@ -387,9 +382,12 @@ void nciu::subscribe (
}
void nciu::ioCancel (
- epicsGuard < epicsMutex > & guard, const ioid & idIn )
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExclusionGuard,
+ const ioid & idIn )
{
- this->cacCtx.destroyIO ( guard, idIn, *this );
+ this->cacCtx.destroyIO ( callbackGuard,
+ mutualExclusionGuard, idIn, *this );
}
void nciu::ioShow (
diff --git a/src/ca/nciu.h b/src/ca/nciu.h
index de070dcea..417e7fd5c 100644
--- a/src/ca/nciu.h
+++ b/src/ca/nciu.h
@@ -121,7 +121,7 @@ private:
friend class disconnectGovernorTimer;
};
-class privateInterfaceForIO { // X aCC 655
+class privateInterfaceForIO {
public:
virtual void ioCompletionNotify (
epicsGuard < epicsMutex > &, class baseNMIU & ) = 0;
@@ -220,6 +220,7 @@ private:
ca_uint16_t typeCode;
ca_uint8_t priority;
virtual void destroy (
+ CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard );
void initiateConnect (
epicsGuard < epicsMutex > & );
@@ -243,7 +244,15 @@ private:
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount nElem,
unsigned mask, cacStateNotify ¬ify, ioid * );
+ // The primary mutex must be released when calling the user's
+ // callback, and therefore a finite interval exists when we are
+ // moving forward with the intent to call the users callback
+ // but the users IO could be deleted during this interval.
+ // To prevent the user's callback from being called after
+ // destroying his IO we must past a guard for the callback
+ // mutex here.
virtual void ioCancel (
+ CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & );
void ioShow (
@@ -270,7 +279,6 @@ private:
epicsGuard < epicsMutex > & guard ) const throw ();
nciu ( const nciu & );
nciu & operator = ( const nciu & );
- void * operator new ( size_t );
void operator delete ( void * );
};
diff --git a/src/ca/netIO.h b/src/ca/netIO.h
index 57273427a..e728d2a1a 100644
--- a/src/ca/netIO.h
+++ b/src/ca/netIO.h
@@ -42,7 +42,7 @@
class privateInterfaceForIO;
-class baseNMIU : public tsDLNode < baseNMIU >, // X aCC 655
+class baseNMIU : public tsDLNode < baseNMIU >,
public chronIntIdRes < baseNMIU > {
public:
virtual void destroy (
@@ -106,7 +106,6 @@ private:
const unsigned mask;
bool subscribed;
class netSubscription * isSubscription ();
- void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & );
@@ -147,7 +146,6 @@ protected:
private:
cacReadNotify & notify;
class privateInterfaceForIO & privateChanForIO;
- void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & );
@@ -190,7 +188,6 @@ protected:
private:
cacWriteNotify & notify;
privateInterfaceForIO & privateChanForIO;
- void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & );
@@ -237,12 +234,12 @@ inline netSubscription * netSubscription::factory (
class privateInterfaceForIO & chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify ¬ify )
{
- return new ( freeList ) netSubscription ( chan, type, // X aCC 930
+ return new ( freeList ) netSubscription ( chan, type,
count, mask, notify );
}
inline arrayElementCount netSubscription::getCount (
- epicsGuard < epicsMutex > & guard, bool allow_zero ) const // X aCC 361
+ epicsGuard < epicsMutex > & guard, bool allow_zero ) const
{
//guard.assertIdenticalMutex ( this->mutex );
arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard );
@@ -268,7 +265,7 @@ inline netReadNotifyIO * netReadNotifyIO::factory (
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList,
privateInterfaceForIO & ioComplNotifIntf, cacReadNotify & notify )
{
- return new ( freeList ) netReadNotifyIO ( ioComplNotifIntf, notify ); // X aCC 930
+ return new ( freeList ) netReadNotifyIO ( ioComplNotifIntf, notify );
}
inline void * netReadNotifyIO::operator new ( size_t size,
@@ -289,7 +286,7 @@ inline netWriteNotifyIO * netWriteNotifyIO::factory (
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList,
privateInterfaceForIO & ioComplNotifyIntf, cacWriteNotify & notify )
{
- return new ( freeList ) netWriteNotifyIO ( ioComplNotifyIntf, notify ); // X aCC 930
+ return new ( freeList ) netWriteNotifyIO ( ioComplNotifyIntf, notify );
}
inline void * netWriteNotifyIO::operator new ( size_t size,
diff --git a/src/ca/netReadNotifyIO.cpp b/src/ca/netReadNotifyIO.cpp
index 446b7175d..2e4b8ead6 100644
--- a/src/ca/netReadNotifyIO.cpp
+++ b/src/ca/netReadNotifyIO.cpp
@@ -119,13 +119,6 @@ void netReadNotifyIO::forceSubscriptionUpdate (
{
}
-void * netReadNotifyIO::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void netReadNotifyIO::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/netSubscription.cpp b/src/ca/netSubscription.cpp
index 9a29ac2b6..fe2426a89 100644
--- a/src/ca/netSubscription.cpp
+++ b/src/ca/netSubscription.cpp
@@ -170,13 +170,6 @@ void netSubscription::forceSubscriptionUpdate (
guard, chan, *this );
}
-void * netSubscription::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void netSubscription::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/netWriteNotifyIO.cpp b/src/ca/netWriteNotifyIO.cpp
index 68d4992e7..afa9996d5 100644
--- a/src/ca/netWriteNotifyIO.cpp
+++ b/src/ca/netWriteNotifyIO.cpp
@@ -117,14 +117,6 @@ void netWriteNotifyIO::forceSubscriptionUpdate (
{
}
-void * netWriteNotifyIO::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error (
- "why is the compiler calling private operator new" );
-}
-
void netWriteNotifyIO::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/netiiu.h b/src/ca/netiiu.h
index 99ea128f1..2caa3d0fa 100644
--- a/src/ca/netiiu.h
+++ b/src/ca/netiiu.h
@@ -35,7 +35,7 @@ union osiSockAddr;
class cac;
class nciu;
-class netiiu { // X aCC 655
+class netiiu {
public:
virtual ~netiiu () = 0;
virtual unsigned getHostName (
diff --git a/src/ca/oldAccess.h b/src/ca/oldAccess.h
index d18a4fe1b..5684b83c3 100644
--- a/src/ca/oldAccess.h
+++ b/src/ca/oldAccess.h
@@ -53,7 +53,8 @@ public:
const char * pName, caCh * pConnCallBackIn,
void * pPrivateIn, capri priority );
void destructor (
- epicsGuard < epicsMutex > & guard );
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & mutexGuard );
// legacy C API
friend unsigned epicsShareAPI ca_get_host_name (
@@ -122,6 +123,7 @@ public:
unsigned type, arrayElementCount count, const void *pValue,
cacWriteNotify &, cacChannel::ioid *pId = 0 );
void ioCancel (
+ CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const cacChannel::ioid & );
void ioShow (
@@ -162,7 +164,6 @@ private:
unsigned type, arrayElementCount count );
oldChannelNotify ( const oldChannelNotify & );
oldChannelNotify & operator = ( const oldChannelNotify & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -195,7 +196,6 @@ private:
const char *pContext, unsigned type, arrayElementCount count );
getCopy ( const getCopy & );
getCopy & operator = ( const getCopy & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -221,7 +221,6 @@ private:
const char * pContext, unsigned type, arrayElementCount count );
getCallback ( const getCallback & );
getCallback & operator = ( const getCallback & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -245,7 +244,6 @@ private:
unsigned type, arrayElementCount count );
putCallback ( const putCallback & );
putCallback & operator = ( const putCallback & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -259,8 +257,16 @@ public:
evid * );
~oldSubscription ();
oldChannelNotify & channel () const;
+ // The primary mutex must be released when calling the user's
+ // callback, and therefore a finite interval exists when we are
+ // moving forward with the intent to call the users callback
+ // but the users IO could be deleted during this interval.
+ // To prevent the user's callback from being called after
+ // destroying his IO we must past a guard for the callback
+ // mutex here.
void cancel (
- epicsGuard < epicsMutex > & guard );
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExclusionGuard );
void * operator new ( size_t size,
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
@@ -278,7 +284,6 @@ private:
const char *pContext, unsigned type, arrayElementCount count );
oldSubscription ( const oldSubscription & );
oldSubscription & operator = ( const oldSubscription & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -341,6 +346,8 @@ public:
void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & );
epicsMutex & mutexRef () const;
+ template < class T >
+ void whenThereIsAnExceptionDestroySyncGroupIO ( epicsGuard < epicsMutex > &, T & );
// legacy C API
friend int epicsShareAPI ca_create_channel (
@@ -368,6 +375,17 @@ public:
friend int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeout );
friend int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid );
friend int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid );
+ friend int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid,
+ chtype type, arrayElementCount count,
+ chid pChan, void *pValue );
+ friend int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid,
+ chtype type, arrayElementCount count,
+ chid pChan, const void *pValue );
+ friend int ca_sync_group_destroy ( CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard,
+ ca_client_context & cac, const CA_SYNC_GID gid );
+ friend void sync_group_reset ( ca_client_context & client,
+ CASG & sg );
// exceptions
class noSocket {};
@@ -384,7 +402,7 @@ private:
epicsEvent ioDone;
epicsEvent callbackThreadActivityComplete;
epicsThreadId createdByThread;
- epics_auto_ptr < epicsGuard < epicsMutex > > pCallbackGuard;
+ epics_auto_ptr < CallbackGuard > pCallbackGuard;
epics_auto_ptr < cacContext > pServiceContext;
caExceptionHandler * ca_exception_func;
void * ca_exception_arg;
@@ -444,10 +462,11 @@ inline void oldChannelNotify::initiateConnect (
}
inline void oldChannelNotify::ioCancel (
- epicsGuard < epicsMutex > & guard,
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExclusionGuard,
const cacChannel::ioid & id )
{
- this->io.ioCancel ( guard, id );
+ this->io.ioCancel ( callbackGuard, mutualExclusionGuard, id );
}
inline void oldChannelNotify::ioShow (
@@ -492,9 +511,10 @@ inline void oldSubscription::operator delete ( void *pCadaver,
#endif
inline void oldSubscription::cancel (
- epicsGuard < epicsMutex > & guard )
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExclusionGuard )
{
- this->chan.ioCancel ( guard, this->id );
+ this->chan.ioCancel ( callbackGuard, mutualExclusionGuard, this->id );
}
inline oldChannelNotify & oldSubscription::channel () const
@@ -560,5 +580,32 @@ inline unsigned ca_client_context::sequenceNumberOfOutstandingIO (
// perhaps on SMP systems THERE should be lock/unlock around this
return this->ioSeqNo;
}
+
+template < class T >
+void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO (
+ epicsGuard < epicsMutex > & guard, T & io )
+{
+ if ( this->pCallbackGuard.get() &&
+ this->createdByThread == epicsThreadGetIdSelf () ) {
+ io.destroy ( *this->pCallbackGuard.get(), guard );
+ }
+ else {
+ // dont reverse the lock hierarchy
+ epicsGuardRelease < epicsMutex > guardRelease ();
+ {
+ //
+ // we will definately stall out here if all of the
+ // following are true
+ //
+ // o user creates non-preemtive mode client library context
+ // o user doesnt periodically call a ca function
+ // o user calls this function from an auxiillary thread
+ //
+ CallbackGuard cbGuard ( this->cbMutex );
+ epicsGuard < epicsMutex > guard ( this->mutex );
+ io.destroy ( cbGuard, guard );
+ }
+ }
+}
#endif // ifndef oldAccessh
diff --git a/src/ca/oldChannelNotify.cpp b/src/ca/oldChannelNotify.cpp
index 8865f8d63..289c4e8b4 100644
--- a/src/ca/oldChannelNotify.cpp
+++ b/src/ca/oldChannelNotify.cpp
@@ -65,14 +65,15 @@ oldChannelNotify::~oldChannelNotify ()
}
void oldChannelNotify::destructor (
- epicsGuard < epicsMutex > & guard )
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & mutexGuard )
{
- guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
- this->io.destroy ( guard );
+ mutexGuard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
+ this->io.destroy ( cbGuard, mutexGuard );
// no need to worry about a connect preempting here because
// the io (the nciu) has been destroyed above
if ( this->pConnCallBack == 0 && ! this->currentlyConnected ) {
- this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
+ this->cacCtx.decrementOutstandingIO ( mutexGuard, this->ioSeqNo );
}
this->~oldChannelNotify ();
}
@@ -159,13 +160,6 @@ void oldChannelNotify::writeException (
__FILE__, __LINE__, *this, type, count, CA_OP_PUT );
}
-void * oldChannelNotify::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void oldChannelNotify::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
@@ -638,7 +632,7 @@ arrayElementCount epicsShareAPI ca_element_count ( chid pChan )
/*
* ca_state ()
*/
-enum channel_state epicsShareAPI ca_state ( chid pChan ) // X aCC 361
+enum channel_state epicsShareAPI ca_state ( chid pChan )
{
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
if ( pChan->io.connected ( guard ) ) {
diff --git a/src/ca/putCallback.cpp b/src/ca/putCallback.cpp
index bff1dd8a4..ba17a654c 100644
--- a/src/ca/putCallback.cpp
+++ b/src/ca/putCallback.cpp
@@ -90,13 +90,6 @@ void putCallback::exception (
}
}
-void * putCallback::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void putCallback::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/repeater.cpp b/src/ca/repeater.cpp
index 64016aed6..ef271e461 100644
--- a/src/ca/repeater.cpp
+++ b/src/ca/repeater.cpp
@@ -178,7 +178,7 @@ bool repeaterClient::connect ()
return true;
}
-bool repeaterClient::sendConfirm () // X aCC 361
+bool repeaterClient::sendConfirm ()
{
int status;
@@ -204,7 +204,7 @@ bool repeaterClient::sendConfirm () // X aCC 361
}
}
-bool repeaterClient::sendMessage ( const void *pBuf, unsigned bufSize ) // X aCC 361
+bool repeaterClient::sendMessage ( const void *pBuf, unsigned bufSize )
{
int status;
@@ -245,13 +245,6 @@ repeaterClient::~repeaterClient ()
#endif
}
-void * repeaterClient::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void repeaterClient::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
@@ -304,7 +297,7 @@ inline bool repeaterClient::identicalPort ( const osiSockAddr &fromIn )
return false;
}
-bool repeaterClient::verify () // X aCC 361
+bool repeaterClient::verify ()
{
SOCKET tmpSock;
bool success = makeSocket ( this->port (), false, & tmpSock );
diff --git a/src/ca/repeaterClient.h b/src/ca/repeaterClient.h
index c57aeaefe..faaf0809f 100644
--- a/src/ca/repeaterClient.h
+++ b/src/ca/repeaterClient.h
@@ -64,7 +64,6 @@ private:
osiSockAddr from;
SOCKET sock;
unsigned short port () const;
- void * operator new ( size_t size );
void operator delete ( void * );
};
diff --git a/src/ca/repeaterSubscribeTimer.cpp b/src/ca/repeaterSubscribeTimer.cpp
index 337ff00ba..69362da5f 100644
--- a/src/ca/repeaterSubscribeTimer.cpp
+++ b/src/ca/repeaterSubscribeTimer.cpp
@@ -64,7 +64,7 @@ void repeaterSubscribeTimer::shutdown (
}
epicsTimerNotify::expireStatus repeaterSubscribeTimer::
- expire ( const epicsTime & /* currentTime */ ) // X aCC 361
+ expire ( const epicsTime & /* currentTime */ )
{
static const unsigned nTriesToMsg = 50;
if ( this->attempts > nTriesToMsg && ! this->once ) {
diff --git a/src/ca/repeaterSubscribeTimer.h b/src/ca/repeaterSubscribeTimer.h
index 0a23d16d3..52f146d6e 100644
--- a/src/ca/repeaterSubscribeTimer.h
+++ b/src/ca/repeaterSubscribeTimer.h
@@ -43,7 +43,7 @@
class epicsMutex;
class cacContextNotify;
-class repeaterTimerNotify { // X aCC 655
+class repeaterTimerNotify {
public:
virtual ~repeaterTimerNotify () = 0;
virtual void repeaterRegistrationMessage (
diff --git a/src/ca/searchTimer.cpp b/src/ca/searchTimer.cpp
index c7aa980ae..e5a8d1c54 100644
--- a/src/ca/searchTimer.cpp
+++ b/src/ca/searchTimer.cpp
@@ -124,7 +124,7 @@ void searchTimer::moveChannels (
// searchTimer::expire ()
//
epicsTimerNotify::expireStatus searchTimer::expire (
- const epicsTime & currentTime ) // X aCC 361
+ const epicsTime & currentTime )
{
epicsGuard < epicsMutex > guard ( this->mutex );
diff --git a/src/ca/searchTimer.h b/src/ca/searchTimer.h
index 2df980ded..7b9fe1717 100644
--- a/src/ca/searchTimer.h
+++ b/src/ca/searchTimer.h
@@ -43,7 +43,7 @@
#include "caProto.h"
#include "netiiu.h"
-class searchTimerNotify { // X aCC 655
+class searchTimerNotify {
public:
virtual ~searchTimerNotify () = 0;
virtual void boostChannel (
diff --git a/src/ca/sgAutoPtr.h b/src/ca/sgAutoPtr.h
index b3753bb44..a6383d69b 100644
--- a/src/ca/sgAutoPtr.h
+++ b/src/ca/sgAutoPtr.h
@@ -29,8 +29,7 @@
template < class T >
class sgAutoPtr {
public:
- sgAutoPtr ( epicsGuard < epicsMutex > &,
- struct CASG &, tsDLList < syncGroupNotify > & );
+ sgAutoPtr ( epicsGuard < epicsMutex > &, struct CASG & );
~sgAutoPtr ();
sgAutoPtr < T > & operator = ( T * );
T * operator -> ();
@@ -38,7 +37,6 @@ public:
T * get ();
T * release ();
private:
- tsDLList < syncGroupNotify > & list;
T * pNotify;
struct CASG & sg;
epicsGuard < epicsMutex > & guard;
@@ -47,9 +45,8 @@ private:
template < class T >
inline sgAutoPtr < T > :: sgAutoPtr (
- epicsGuard < epicsMutex > & guardIn,
- struct CASG & sgIn, tsDLList < syncGroupNotify > & listIn ) :
- list ( listIn ), pNotify ( 0 ), sg ( sgIn ), guard ( guardIn )
+ epicsGuard < epicsMutex > & guardIn, struct CASG & sgIn ) :
+ pNotify ( 0 ), sg ( sgIn ), guard ( guardIn )
{
}
@@ -57,8 +54,9 @@ template < class T >
inline sgAutoPtr < T > :: ~sgAutoPtr ()
{
if ( this->pNotify ) {
- list.remove ( *this->pNotify );
- pNotify->destroy ( this->guard, this->sg );
+ this->sg.ioPendingList.remove ( *this->pNotify );
+ this->sg.client.
+ whenThereIsAnExceptionDestroySyncGroupIO ( this->guard, *this->pNotify );
}
}
@@ -66,11 +64,12 @@ template < class T >
inline sgAutoPtr < T > & sgAutoPtr < T > :: operator = ( T * pNotifyIn )
{
if ( this->pNotify ) {
- list.remove ( *this->pNotify );
- pNotify->destroy ( this->guard, this->sg );
+ this->sg.ioPendingList.remove ( *this->pNotify );
+ this->sg.client.
+ whenThereIsAnExceptionDestroySyncGroupIO ( this->guard, *this->pNotify );
}
this->pNotify = pNotifyIn;
- list.add ( *this->pNotify );
+ this->sg.ioPendingList.add ( *this->pNotify );
return *this;
}
diff --git a/src/ca/syncGroup.h b/src/ca/syncGroup.h
index c41c9b5b8..f805b6bbd 100644
--- a/src/ca/syncGroup.h
+++ b/src/ca/syncGroup.h
@@ -46,29 +46,17 @@
static const unsigned CASG_MAGIC = 0xFAB4CAFE;
-// used to control access to CASG's recycle routines which
-// should only be indirectly invoked by CASG when its lock
-// is applied
-class casgRecycle { // X aCC 655
-public:
- virtual void recycleSyncGroupWriteNotify (
- epicsGuard < epicsMutex > &, class syncGroupWriteNotify & io ) = 0;
- virtual void recycleSyncGroupReadNotify (
- epicsGuard < epicsMutex > &, class syncGroupReadNotify & io ) = 0;
-protected:
- virtual ~casgRecycle ();
-};
-
class syncGroupNotify : public tsDLNode < syncGroupNotify > {
public:
syncGroupNotify ();
virtual void destroy (
- epicsGuard < epicsMutex > & guard,
- casgRecycle & ) = 0;
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard ) = 0;
virtual bool ioPending (
epicsGuard < epicsMutex > & guard ) = 0;
virtual void cancel (
- epicsGuard < epicsMutex > & guard ) = 0;
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
virtual void show (
epicsGuard < epicsMutex > &,
unsigned level ) const = 0;
@@ -78,33 +66,38 @@ protected:
syncGroupNotify & operator = ( const syncGroupNotify & );
};
+struct CASG;
+
class syncGroupReadNotify : public syncGroupNotify, public cacReadNotify {
public:
+ typedef void ( CASG :: * PRecycleFunc )
+ ( epicsGuard < epicsMutex > &, syncGroupReadNotify & );
static syncGroupReadNotify * factory (
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > &,
- struct CASG &, chid, void *pValueIn );
+ CASG &, PRecycleFunc, chid, void *pValueIn );
void destroy (
- epicsGuard < epicsMutex > & guard,
- casgRecycle & );
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard );
bool ioPending (
epicsGuard < epicsMutex > & guard );
void begin ( epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count );
void cancel (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
protected:
- syncGroupReadNotify ( struct CASG & sgIn, chid, void * pValueIn );
+ syncGroupReadNotify ( CASG & sgIn, PRecycleFunc, chid, void * pValueIn );
virtual ~syncGroupReadNotify ();
private:
chid chan;
- struct CASG & sg;
+ PRecycleFunc pRecycleFunc;
+ CASG & sg;
void * pValue;
const unsigned magic;
cacChannel::ioid id;
bool idIsValid;
bool ioComplete;
- void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & );
@@ -122,30 +115,33 @@ private:
class syncGroupWriteNotify : public syncGroupNotify, public cacWriteNotify {
public:
+ typedef void ( CASG :: * PRecycleFunc )
+ ( epicsGuard < epicsMutex > &, syncGroupWriteNotify & );
static syncGroupWriteNotify * factory (
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &,
- struct CASG &, chid );
+ CASG &, PRecycleFunc, chid );
void destroy (
- epicsGuard < epicsMutex > & guard,
- casgRecycle & );
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard );
bool ioPending (
epicsGuard < epicsMutex > & guard );
void begin ( epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void * pValueIn );
void cancel (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
protected:
- syncGroupWriteNotify ( struct CASG &, chid );
+ syncGroupWriteNotify ( struct CASG &, PRecycleFunc, chid );
virtual ~syncGroupWriteNotify (); // allocate only from pool
private:
chid chan;
- struct CASG & sg;
+ PRecycleFunc pRecycleFunc;
+ CASG & sg;
const unsigned magic;
cacChannel::ioid id;
bool idIsValid;
bool ioComplete;
- void * operator new ( size_t );
void operator delete ( void * );
void * operator new ( size_t,
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > & );
@@ -163,17 +159,19 @@ struct ca_client_context;
template < class T > class sgAutoPtr;
-struct CASG : public chronIntIdRes < CASG >, private casgRecycle {
+struct CASG : public chronIntIdRes < CASG > {
public:
CASG ( epicsGuard < epicsMutex > &, ca_client_context & cacIn );
void destructor (
+ CallbackGuard &,
epicsGuard < epicsMutex > & guard );
bool ioComplete (
+ CallbackGuard &,
epicsGuard < epicsMutex > & guard );
bool verify ( epicsGuard < epicsMutex > & ) const;
int block ( epicsGuard < epicsMutex > * pcbGuard,
epicsGuard < epicsMutex > & guard, double timeout );
- void reset ( epicsGuard < epicsMutex > & guard );
+ void reset ( CallbackGuard &, epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void get ( epicsGuard < epicsMutex > &, chid pChan,
@@ -194,6 +192,7 @@ public:
tsFreeList < struct CASG, 128, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < struct CASG, 128, epicsMutexNOOP > & ))
+
private:
tsDLList < syncGroupNotify > ioPendingList;
tsDLList < syncGroupNotify > ioCompletedList;
@@ -202,20 +201,21 @@ private:
unsigned magic;
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > freeListReadOP;
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > freeListWriteOP;
- void recycleSyncGroupWriteNotify (
- epicsGuard < epicsMutex > &, syncGroupWriteNotify & io );
- void recycleSyncGroupReadNotify (
- epicsGuard < epicsMutex > &, syncGroupReadNotify & io );
void destroyPendingIO (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard );
void destroyCompletedIO (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard );
+ void recycleReadNotifyIO ( epicsGuard < epicsMutex > &,
+ syncGroupReadNotify & );
+ void recycleWriteNotifyIO ( epicsGuard < epicsMutex > &,
+ syncGroupWriteNotify & );
CASG ( const CASG & );
CASG & operator = ( const CASG & );
- void * operator new ( size_t size );
void operator delete ( void * );
~CASG ();
diff --git a/src/ca/syncGroupReadNotify.cpp b/src/ca/syncGroupReadNotify.cpp
index 11f90fe57..33ba5fb32 100644
--- a/src/ca/syncGroupReadNotify.cpp
+++ b/src/ca/syncGroupReadNotify.cpp
@@ -27,8 +27,10 @@
#include "oldAccess.h"
syncGroupReadNotify::syncGroupReadNotify (
- CASG & sgIn, chid pChan, void * pValueIn ) :
- chan ( pChan ), sg ( sgIn ), pValue ( pValueIn ),
+ CASG & sgIn, PRecycleFunc pRecycleFuncIn,
+ chid pChan, void * pValueIn ) :
+ chan ( pChan ), pRecycleFunc ( pRecycleFuncIn ),
+ sg ( sgIn ), pValue ( pValueIn ),
magic ( CASG_MAGIC ), id ( 0u ),
idIsValid ( false ), ioComplete ( false )
{
@@ -46,27 +48,30 @@ void syncGroupReadNotify::begin (
}
void syncGroupReadNotify::cancel (
- epicsGuard < epicsMutex > & guard )
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExcusionGuard )
{
if ( this->idIsValid ) {
- this->chan->ioCancel ( guard, this->id );
+ this->chan->ioCancel ( callbackGuard, mutualExcusionGuard, this->id );
this->idIsValid = false;
}
}
syncGroupReadNotify * syncGroupReadNotify::factory (
tsFreeList < class syncGroupReadNotify, 128, epicsMutexNOOP > & freeList,
- struct CASG & sg, chid chan, void * pValueIn )
+ struct CASG & sg, PRecycleFunc pRecycleFunc, chid chan, void * pValueIn )
{
- return new ( freeList ) // X aCC 930
- syncGroupReadNotify ( sg, chan, pValueIn );
+ return new ( freeList )
+ syncGroupReadNotify ( sg, pRecycleFunc, chan, pValueIn );
}
void syncGroupReadNotify::destroy (
- epicsGuard < epicsMutex > & guard, casgRecycle & recycle )
+ CallbackGuard &,
+ epicsGuard < epicsMutex > & guard )
{
+ CASG & sgRef ( this->sg );
this->~syncGroupReadNotify ();
- recycle.recycleSyncGroupReadNotify ( guard, *this );
+ ( sgRef.*pRecycleFunc ) ( guard, *this );
}
syncGroupReadNotify::~syncGroupReadNotify ()
@@ -122,13 +127,6 @@ void syncGroupReadNotify::show (
}
}
-void * syncGroupReadNotify::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void syncGroupReadNotify::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/syncGroupWriteNotify.cpp b/src/ca/syncGroupWriteNotify.cpp
index 244d9d3bd..fed76ed81 100644
--- a/src/ca/syncGroupWriteNotify.cpp
+++ b/src/ca/syncGroupWriteNotify.cpp
@@ -26,8 +26,10 @@
#include "syncGroup.h"
#include "oldAccess.h"
-syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn, chid pChan ) :
- chan ( pChan ), sg ( sgIn ), magic ( CASG_MAGIC ),
+syncGroupWriteNotify::syncGroupWriteNotify ( CASG & sgIn,
+ PRecycleFunc pRecycleFuncIn, chid pChan ) :
+ chan ( pChan ), pRecycleFunc ( pRecycleFuncIn ),
+ sg ( sgIn ), magic ( CASG_MAGIC ),
id ( 0u ), idIsValid ( false ), ioComplete ( false )
{
}
@@ -45,26 +47,29 @@ void syncGroupWriteNotify::begin (
}
void syncGroupWriteNotify::cancel (
- epicsGuard < epicsMutex > & guard )
+ CallbackGuard & callbackGuard,
+ epicsGuard < epicsMutex > & mutualExcusionGuard )
{
if ( this->idIsValid ) {
- this->chan->ioCancel ( guard, this->id );
+ this->chan->ioCancel ( callbackGuard, mutualExcusionGuard, this->id );
this->idIsValid = false;
}
}
syncGroupWriteNotify * syncGroupWriteNotify::factory (
tsFreeList < class syncGroupWriteNotify, 128, epicsMutexNOOP > &freeList,
- struct CASG & sg, chid chan )
+ struct CASG & sg, PRecycleFunc pRecycleFunc, chid chan )
{
- return new ( freeList ) syncGroupWriteNotify ( sg, chan );
+ return new ( freeList ) syncGroupWriteNotify ( sg, pRecycleFunc, chan );
}
void syncGroupWriteNotify::destroy (
- epicsGuard < epicsMutex > & guard, casgRecycle & recycle )
+ CallbackGuard &,
+ epicsGuard < epicsMutex > & guard )
{
+ CASG & sgRef ( this->sg );
this->~syncGroupWriteNotify ();
- recycle.recycleSyncGroupWriteNotify ( guard, *this );
+ ( sgRef.*pRecycleFunc ) ( guard, *this );
}
syncGroupWriteNotify::~syncGroupWriteNotify ()
@@ -112,13 +117,6 @@ void syncGroupWriteNotify::show (
}
}
-void * syncGroupWriteNotify::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void syncGroupWriteNotify::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
diff --git a/src/ca/syncgrp.cpp b/src/ca/syncgrp.cpp
index c76f6a194..cb7a7cffa 100644
--- a/src/ca/syncgrp.cpp
+++ b/src/ca/syncgrp.cpp
@@ -23,7 +23,7 @@
/*
* ca_sg_create()
*/
-extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) // X aCC 361
+extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid )
{
ca_client_context * pcac;
int caStatus;
@@ -48,6 +48,22 @@ extern "C" int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid ) // X aCC 361
}
}
+int ca_sync_group_destroy ( CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard,
+ ca_client_context & cac, const CA_SYNC_GID gid )
+{
+ int caStatus;
+ CASG * pcasg = cac.lookupCASG ( guard, gid );
+ if ( pcasg ) {
+ pcasg->destructor ( cbGuard, guard );
+ cac.casgFreeList.release ( pcasg );
+ caStatus = ECA_NORMAL;
+ }
+ else {
+ caStatus = ECA_BADSYNCGRP;
+ }
+ return caStatus;
+}
+
/*
* ca_sg_delete()
*/
@@ -56,19 +72,51 @@ extern "C" int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid )
ca_client_context * pcac;
int caStatus = fetchClientContext ( & pcac );
if ( caStatus == ECA_NORMAL ) {
- epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
- CASG * pcasg = pcac->lookupCASG ( guard, gid );
- if ( pcasg ) {
- pcasg->destructor ( guard );
- pcac->casgFreeList.release ( pcasg );
+ if ( pcac->pCallbackGuard.get() &&
+ pcac->createdByThread == epicsThreadGetIdSelf () ) {
+ epicsGuard < epicsMutex > guard ( pcac->mutex );
+ caStatus = ca_sync_group_destroy ( *pcac->pCallbackGuard.get(),
+ guard, *pcac, gid );
}
else {
- caStatus = ECA_BADSYNCGRP;
+ //
+ // we will definately stall out here if all of the
+ // following are true
+ //
+ // o user creates non-preemtive mode client library context
+ // o user doesnt periodically call a ca function
+ // o user calls this function from an auxiillary thread
+ //
+ CallbackGuard cbGuard ( pcac->cbMutex );
+ epicsGuard < epicsMutex > guard ( pcac->mutex );
+ caStatus = ca_sync_group_destroy ( cbGuard, guard, *pcac, gid );
}
}
return caStatus;
}
+void sync_group_reset ( ca_client_context & client, CASG & sg )
+{
+ if ( client.pCallbackGuard.get() &&
+ client.createdByThread == epicsThreadGetIdSelf () ) {
+ epicsGuard < epicsMutex > guard ( client.mutex );
+ sg.reset ( *client.pCallbackGuard.get(), guard );
+ }
+ else {
+ //
+ // we will definately stall out here if all of the
+ // following are true
+ //
+ // o user creates non-preemtive mode client library context
+ // o user doesnt periodically call a ca function
+ // o user calls this function from an auxiillary thread
+ //
+ CallbackGuard cbGuard ( client.cbMutex );
+ epicsGuard < epicsMutex > guard ( client.mutex );
+ sg.reset ( cbGuard, guard );
+ }
+}
+
//
// ca_sg_block ()
//
@@ -84,14 +132,20 @@ extern "C" int epicsShareAPI ca_sg_block (
ca_client_context *pcac;
int status = fetchClientContext ( &pcac );
if ( status == ECA_NORMAL ) {
+ CASG * pcasg;
+ {
epicsGuard < epicsMutex > guard ( pcac->mutex );
- CASG * pcasg = pcac->lookupCASG ( guard, gid );
- if ( ! pcasg ) {
- status = ECA_BADSYNCGRP;
- }
- else {
+ pcasg = pcac->lookupCASG ( guard, gid );
+ if ( pcasg ) {
status = pcasg->block (
pcac->pCallbackGuard.get (), guard, timeout );
+ }
+ else {
+ status = ECA_BADSYNCGRP;
+ }
+ }
+ if ( pcasg ) {
+ sync_group_reset ( *pcac, *pcasg );
}
}
return status;
@@ -105,10 +159,14 @@ extern "C" int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid )
ca_client_context *pcac;
int caStatus = fetchClientContext (&pcac);
if ( caStatus == ECA_NORMAL ) {
+ CASG * pcasg;
+ {
epicsGuard < epicsMutex > guard ( pcac->mutex );
- CASG * pcasg = pcac->lookupCASG ( guard, gid );
+ pcasg = pcac->lookupCASG ( guard, gid );
+ }
if ( pcasg ) {
- pcasg->reset ( guard );
+ sync_group_reset ( *pcac, *pcasg );
+ caStatus = ECA_NORMAL;
}
else {
caStatus = ECA_BADSYNCGRP;
@@ -143,7 +201,7 @@ extern "C" int epicsShareAPI ca_sg_stat ( const CA_SYNC_GID gid )
/*
* ca_sg_test
*/
-extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) // X aCC 361
+extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid )
{
ca_client_context * pcac;
int caStatus = fetchClientContext ( &pcac );
@@ -151,7 +209,26 @@ extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid ) // X aCC 361
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
CASG * pcasg = pcac->lookupCASG ( guard, gid );
if ( pcasg ) {
- if ( pcasg->ioComplete ( guard ) ) {
+ bool isComplete;
+ if ( pcac->pCallbackGuard.get() &&
+ pcac->createdByThread == epicsThreadGetIdSelf () ) {
+ epicsGuard < epicsMutex > guard ( pcac->mutex );
+ isComplete = pcasg->ioComplete ( *pcac->pCallbackGuard.get(), guard );
+ }
+ else {
+ //
+ // we will definately stall out here if all of the
+ // following are true
+ //
+ // o user creates non-preemtive mode client library context
+ // o user doesnt periodically call a ca function
+ // o user calls this function from an auxiillary thread
+ //
+ CallbackGuard cbGuard ( pcac->cbMutex );
+ epicsGuard < epicsMutex > guard ( pcac->mutex );
+ isComplete = pcasg->ioComplete ( cbGuard, guard );
+ }
+ if ( isComplete ) {
caStatus = ECA_IODONE;
}
else{
@@ -172,17 +249,14 @@ extern "C" int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid, chtype typ
arrayElementCount count, chid pChan, const void *pValue )
{
ca_client_context *pcac;
- CASG *pcasg;
- int caStatus;
- caStatus = fetchClientContext ( &pcac );
+ int caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
-
- pcasg = pcac->lookupCASG ( guard, gid );
+ CASG * const pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
@@ -237,17 +311,14 @@ extern "C" int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid, chtype typ
arrayElementCount count, chid pChan, void *pValue )
{
ca_client_context *pcac;
- CASG *pcasg;
- int caStatus;
- caStatus = fetchClientContext ( &pcac );
+ int caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
epicsGuard < epicsMutex > guard ( pcac->mutexRef() );
-
- pcasg = pcac->lookupCASG ( guard, gid );
+ CASG * const pcasg = pcac->lookupCASG ( guard, gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
diff --git a/src/ca/tcpRecvWatchdog.cpp b/src/ca/tcpRecvWatchdog.cpp
index 35e509a7c..72c92968b 100644
--- a/src/ca/tcpRecvWatchdog.cpp
+++ b/src/ca/tcpRecvWatchdog.cpp
@@ -45,7 +45,7 @@ tcpRecvWatchdog::~tcpRecvWatchdog ()
}
epicsTimerNotify::expireStatus
-tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ ) // X aCC 361
+tcpRecvWatchdog::expire ( const epicsTime & /* currentTime */ )
{
epicsGuard < epicsMutex > guard ( this->mutex );
if ( this->shuttingDown ) {
diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp
index 9cf9f6f4d..377e3ac3c 100644
--- a/src/ca/tcpiiu.cpp
+++ b/src/ca/tcpiiu.cpp
@@ -1135,7 +1135,7 @@ void tcpiiu::show ( unsigned level ) const
}
}
-bool tcpiiu::setEchoRequestPending ( epicsGuard < epicsMutex > & guard ) // X aCC 361
+bool tcpiiu::setEchoRequestPending ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1275,12 +1275,9 @@ bool tcpiiu::processIncoming (
this->msgHeaderAvailable = false;
this->curDataBytes = 0u;
}
-# if defined ( __HP_aCC ) && _HP_aCC <= 033300
- return false; // to make hpux compiler happy...
-# endif
}
-void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431
+void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1310,7 +1307,7 @@ void tcpiiu::hostNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 4
/*
* tcpiiu::userNameSetRequest ()
*/
-void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431
+void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1338,7 +1335,7 @@ void tcpiiu::userNameSetRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 4
}
void tcpiiu::disableFlowControlRequest (
- epicsGuard < epicsMutex > & guard ) // X aCC 431
+ epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1354,7 +1351,7 @@ void tcpiiu::disableFlowControlRequest (
}
void tcpiiu::enableFlowControlRequest (
- epicsGuard < epicsMutex > & guard ) // X aCC 431
+ epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1369,7 +1366,7 @@ void tcpiiu::enableFlowControlRequest (
minder.commit ();
}
-void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, // X aCC 431
+void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard,
const cacChannel::priLev & priority )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1389,7 +1386,7 @@ void tcpiiu::versionMessage ( epicsGuard < epicsMutex > & guard, // X aCC 431
minder.commit ();
}
-void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431
+void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1410,7 +1407,7 @@ void tcpiiu::echoRequest ( epicsGuard < epicsMutex > & guard ) // X aCC 431
minder.commit ();
}
-void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
+void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard,
nciu &chan, unsigned type, arrayElementCount nElem, const void *pValue )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1425,7 +1422,7 @@ void tcpiiu::writeRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
}
-void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
+void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard,
nciu &chan, netWriteNotifyIO &io, unsigned type,
arrayElementCount nElem, const void *pValue )
{
@@ -1444,7 +1441,7 @@ void tcpiiu::writeNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 43
minder.commit ();
}
-void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
+void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard,
nciu & chan, netReadNotifyIO & io,
unsigned dataType, arrayElementCount nElem )
{
@@ -1477,7 +1474,7 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
}
void tcpiiu::createChannelRequest (
- nciu & chan, epicsGuard < epicsMutex > & guard ) // X aCC 431
+ nciu & chan, epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1525,7 +1522,7 @@ void tcpiiu::createChannelRequest (
minder.commit ();
}
-void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
+void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard,
ca_uint32_t sid, ca_uint32_t cid )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1547,7 +1544,7 @@ void tcpiiu::clearChannelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 4
// is to try again the next time that we reconnect
//
void tcpiiu::subscriptionRequest (
- epicsGuard < epicsMutex > & guard, // X aCC 431
+ epicsGuard < epicsMutex > & guard,
nciu & chan, netSubscription & subscr )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1599,7 +1596,7 @@ void tcpiiu::subscriptionRequest (
// is to try again the next time that we reconnect
//
void tcpiiu::subscriptionUpdateRequest (
- epicsGuard < epicsMutex > & guard, // X aCC 431
+ epicsGuard < epicsMutex > & guard,
nciu & chan, netSubscription & subscr )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -1634,7 +1631,7 @@ void tcpiiu::subscriptionUpdateRequest (
minder.commit ();
}
-void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard, // X aCC 431
+void tcpiiu::subscriptionCancelRequest ( epicsGuard < epicsMutex > & guard,
nciu & chan, netSubscription & subscr )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -2052,7 +2049,7 @@ bool tcpiiu::bytesArePendingInOS () const
return false;
#else
osiSockIoctl_t bytesPending = 0; /* shut up purifys yapping */
- int status = socket_ioctl ( this->sock, // X aCC 392
+ int status = socket_ioctl ( this->sock,
FIONREAD, & bytesPending );
if ( status >= 0 ) {
if ( bytesPending > 0 ) {
diff --git a/src/ca/test_event.cpp b/src/ca/test_event.cpp
index c39375aef..17cfe2f47 100644
--- a/src/ca/test_event.cpp
+++ b/src/ca/test_event.cpp
@@ -78,7 +78,7 @@ extern "C" void epicsShareAPI ca_dump_dbr (
dbr_short_t *pvalue = (dbr_short_t *)pbuffer;
for (i = 0; i < count; i++,pvalue++){
if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%d ",* (short *)pvalue); // X aCC 392
+ printf("%d ",* (short *)pvalue);
}
break;
}
@@ -96,7 +96,7 @@ extern "C" void epicsShareAPI ca_dump_dbr (
dbr_float_t *pvalue = (dbr_float_t *)pbuffer;
for (i = 0; i < count; i++,pvalue++){
if(count!=1 && (i%10 == 0)) printf("\n");
- printf("%6.4f ",*(float *)pvalue); // X aCC 392
+ printf("%6.4f ",*(float *)pvalue);
}
break;
}
diff --git a/src/ca/udpiiu.cpp b/src/ca/udpiiu.cpp
index 4760583e9..e4e8bd31f 100644
--- a/src/ca/udpiiu.cpp
+++ b/src/ca/udpiiu.cpp
@@ -201,7 +201,7 @@ udpiiu::udpiiu (
memset ( (char *)&addr, 0 , sizeof (addr) );
addr.ia.sin_family = AF_INET;
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
- addr.ia.sin_port = htons ( PORT_ANY ); // X aCC 818
+ addr.ia.sin_port = htons ( PORT_ANY );
status = bind (this->sock, &addr.sa, sizeof (addr) );
if ( status < 0 ) {
char sockErrBuf[64];
@@ -471,7 +471,7 @@ void epicsShareAPI caRepeaterRegistrationMessage (
}
memset ( (char *) &msg, 0, sizeof (msg) );
- AlignedWireRef < epicsUInt16 > ( msg.m_cmmd ) = REPEATER_REGISTER; // X aCC 818
+ AlignedWireRef < epicsUInt16 > ( msg.m_cmmd ) = REPEATER_REGISTER;
msg.m_available = saddr.ia.sin_addr.s_addr;
/*
diff --git a/src/ca/virtualCircuit.h b/src/ca/virtualCircuit.h
index 3d3031f31..017b99d0e 100644
--- a/src/ca/virtualCircuit.h
+++ b/src/ca/virtualCircuit.h
@@ -335,7 +335,6 @@ private:
tcpiiu ( const tcpiiu & );
tcpiiu & operator = ( const tcpiiu & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -372,7 +371,7 @@ inline bool tcpiiu::ca_v49_ok (
}
inline bool tcpiiu::alive (
- epicsGuard < epicsMutex > & ) const // X aCC 361
+ epicsGuard < epicsMutex > & ) const
{
return ( this->state == iiucs_connecting ||
this->state == iiucs_connected );
diff --git a/src/db/dbCAC.h b/src/db/dbCAC.h
index 3032023dc..a45bc60aa 100644
--- a/src/db/dbCAC.h
+++ b/src/db/dbCAC.h
@@ -62,7 +62,7 @@ class dbChannelIO;
class dbPutNotifyBlocker;
class dbSubscriptionIO;
-class dbBaseIO // X aCC 655
+class dbBaseIO
: public chronIntIdRes < dbBaseIO > {
public:
virtual dbSubscriptionIO * isSubscription () = 0;
@@ -86,9 +86,9 @@ public:
epicsGuard < epicsMutex > &, epicsMutex &,
dbContext &, dbChannelIO &, struct dbAddr &, cacStateNotify &,
unsigned type, unsigned long count, unsigned mask, dbEventCtx );
- void destructor ( epicsGuard < epicsMutex > & );
- void unsubscribe ( epicsGuard < epicsMutex > & );
- void channelDeleteException ( epicsGuard < epicsMutex > & );
+ void destructor ( CallbackGuard &, epicsGuard < epicsMutex > & );
+ void unsubscribe ( CallbackGuard &, epicsGuard < epicsMutex > & );
+ void channelDeleteException ( CallbackGuard &, epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void * operator new ( size_t size,
@@ -110,7 +110,6 @@ private:
dbSubscriptionIO ( const dbSubscriptionIO & );
dbSubscriptionIO & operator = ( const dbSubscriptionIO & );
virtual ~dbSubscriptionIO ();
- void * operator new ( size_t size );
void operator delete ( void * );
};
@@ -165,7 +164,7 @@ public:
dbContext ( epicsMutex & cbMutex, epicsMutex & mutex,
cacContextNotify & notify );
virtual ~dbContext ();
- void destroyChannel ( epicsGuard < epicsMutex > &, dbChannelIO & );
+ void destroyChannel ( CallbackGuard &,epicsGuard < epicsMutex > &, dbChannelIO & );
void callReadNotify ( epicsGuard < epicsMutex > &,
struct dbAddr & addr, unsigned type, unsigned long count,
cacReadNotify & notify );
@@ -182,9 +181,9 @@ public:
cacWriteNotify & notify, cacChannel::ioid * pId );
void show ( unsigned level ) const;
void showAllIO ( const dbChannelIO & chan, unsigned level ) const;
- void destroyAllIO (
+ void destroyAllIO ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > &, dbChannelIO & chan );
- void ioCancel ( epicsGuard < epicsMutex > &,
+ void ioCancel ( CallbackGuard &, epicsGuard < epicsMutex > &,
dbChannelIO & chan, const cacChannel::ioid &id );
void ioShow ( epicsGuard < epicsMutex > &,
const cacChannel::ioid & id, unsigned level ) const;
diff --git a/src/db/dbChannelIO.cpp b/src/db/dbChannelIO.cpp
index c95778abe..294c13d71 100644
--- a/src/db/dbChannelIO.cpp
+++ b/src/db/dbChannelIO.cpp
@@ -61,19 +61,21 @@ dbChannelIO::~dbChannelIO ()
{
}
-void dbChannelIO::destructor ( epicsGuard < epicsMutex > & guard )
+void dbChannelIO::destructor ( CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
- this->serviceIO.destroyAllIO ( guard, *this );
+ this->serviceIO.destroyAllIO ( cbGuard, guard, *this );
this->~dbChannelIO ();
}
void dbChannelIO::destroy (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
- this->serviceIO.destroyChannel ( guard, *this );
- // dont access this pointer after above call because
+ this->serviceIO.destroyChannel ( cbGuard, guard, *this );
+ // don't access this pointer after above call because
// object nolonger exists
}
@@ -132,11 +134,12 @@ void dbChannelIO::subscribe (
}
void dbChannelIO::ioCancel (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & id )
{
mutualExclusionGuard.assertIdenticalMutex ( this->mutex );
- this->serviceIO.ioCancel ( mutualExclusionGuard, *this, id );
+ this->serviceIO.ioCancel ( cbGuard, mutualExclusionGuard, *this, id );
}
void dbChannelIO::ioShow (
@@ -204,13 +207,6 @@ void * dbChannelIO::operator new ( size_t size,
return freeList.allocate ( size );
}
-void * dbChannelIO::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
#ifdef CXX_PLACEMENT_DELETE
void dbChannelIO::operator delete ( void *pCadaver,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
diff --git a/src/db/dbChannelIO.h b/src/db/dbChannelIO.h
index 0473962ba..54b2e2a3c 100644
--- a/src/db/dbChannelIO.h
+++ b/src/db/dbChannelIO.h
@@ -48,8 +48,10 @@ public:
epicsMutex &, cacChannelNotify &,
const dbAddr &, dbContext & );
void destructor (
+ CallbackGuard &,
epicsGuard < epicsMutex > & );
void destroy (
+ CallbackGuard &,
epicsGuard < epicsMutex > & mutualExclusionGuard );
void callReadNotify (
epicsGuard < epicsMutex > &,
@@ -100,7 +102,8 @@ private:
unsigned type, unsigned long count,
unsigned mask, cacStateNotify ¬ify, ioid * );
void ioCancel (
- epicsGuard < epicsMutex > & mutualExclusionGuard,
+ CallbackGuard &,
+ epicsGuard < epicsMutex > &,
const ioid & );
void ioShow (
epicsGuard < epicsMutex > &,
@@ -111,7 +114,6 @@ private:
epicsGuard < epicsMutex > & ) const;
dbChannelIO ( const dbChannelIO & );
dbChannelIO & operator = ( const dbChannelIO & );
- void * operator new ( size_t size );
void operator delete ( void * );
};
diff --git a/src/db/dbContext.cpp b/src/db/dbContext.cpp
index 86ebf1997..3ac05dfbc 100644
--- a/src/db/dbContext.cpp
+++ b/src/db/dbContext.cpp
@@ -83,7 +83,7 @@ dbContext::~dbContext ()
}
}
-cacChannel & dbContext::createChannel ( // X aCC 361
+cacChannel & dbContext::createChannel (
epicsGuard < epicsMutex > & guard, const char * pName,
cacChannelNotify & notifyIn, cacChannel::priLev priority )
{
@@ -119,18 +119,20 @@ cacChannel & dbContext::createChannel ( // X aCC 361
}
void dbContext::destroyChannel (
- epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard,
+ dbChannelIO & chan )
{
guard.assertIdenticalMutex ( this->mutex );
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
this->ioTable.remove ( *chan.dbContextPrivateListOfIO::pBlocker );
- chan.dbContextPrivateListOfIO::pBlocker->destructor ( guard );
+ chan.dbContextPrivateListOfIO::pBlocker->destructor ( cbGuard, guard );
this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker );
chan.dbContextPrivateListOfIO::pBlocker = 0;
}
- chan.destructor ( guard );
+ chan.destructor ( cbGuard, guard );
this->dbChannelIOFreeList.release ( & chan );
}
@@ -269,7 +271,9 @@ void dbContext::initiatePutNotify (
}
void dbContext::destroyAllIO (
- epicsGuard < epicsMutex > & guard, dbChannelIO & chan )
+ CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard,
+ dbChannelIO & chan )
{
guard.assertIdenticalMutex ( this->mutex );
dbSubscriptionIO * pIO;
@@ -286,24 +290,24 @@ void dbContext::destroyAllIO (
while ( ( pIO = tmp.get() ) ) {
// This prevents a db event callback from coming
// through after the notify IO is deleted
- pIO->unsubscribe ( guard );
+ pIO->unsubscribe ( cbGuard, guard );
// If they call ioCancel() here it will be ignored
// because the IO has been unregistered above.
- pIO->channelDeleteException ( guard );
- pIO->destructor ( guard );
+ pIO->channelDeleteException ( cbGuard, guard );
+ pIO->destructor ( cbGuard, guard );
this->dbSubscriptionIOFreeList.release ( pIO );
}
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
- chan.dbContextPrivateListOfIO::pBlocker->destructor ( guard );
+ chan.dbContextPrivateListOfIO::pBlocker->destructor ( cbGuard, guard );
this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker );
chan.dbContextPrivateListOfIO::pBlocker = 0;
}
}
void dbContext::ioCancel (
- epicsGuard < epicsMutex > & guard, dbChannelIO & chan,
- const cacChannel::ioid &id )
+ CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard,
+ dbChannelIO & chan, const cacChannel::ioid &id )
{
guard.assertIdenticalMutex ( this->mutex );
dbBaseIO * pIO = this->ioTable.remove ( id );
@@ -311,13 +315,13 @@ void dbContext::ioCancel (
dbSubscriptionIO *pSIO = pIO->isSubscription ();
if ( pSIO ) {
chan.dbContextPrivateListOfIO::eventq.remove ( *pSIO );
- pSIO->unsubscribe ( guard );
- pSIO->channelDeleteException ( guard );
- pSIO->destructor ( guard );
+ pSIO->unsubscribe ( cbGuard, guard );
+ pSIO->channelDeleteException ( cbGuard, guard );
+ pSIO->destructor ( cbGuard, guard );
this->dbSubscriptionIOFreeList.release ( pSIO );
}
else if ( pIO == chan.dbContextPrivateListOfIO::pBlocker ) {
- chan.dbContextPrivateListOfIO::pBlocker->cancel ( guard );
+ chan.dbContextPrivateListOfIO::pBlocker->cancel ( cbGuard, guard );
}
else {
errlogPrintf ( "dbContext::ioCancel() unrecognized IO was probably leaked or not canceled\n" );
diff --git a/src/db/dbPutNotifyBlocker.cpp b/src/db/dbPutNotifyBlocker.cpp
index e91234b67..6c82e4153 100644
--- a/src/db/dbPutNotifyBlocker.cpp
+++ b/src/db/dbPutNotifyBlocker.cpp
@@ -59,10 +59,11 @@ dbPutNotifyBlocker::~dbPutNotifyBlocker ()
{
}
-void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard )
+void dbPutNotifyBlocker::destructor ( CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
- this->cancel ( guard );
+ this->cancel ( cbGuard, guard );
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
char * pBuf = static_cast < char * > ( this->pn.pbuffer );
delete [] pBuf;
@@ -71,6 +72,7 @@ void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard )
}
void dbPutNotifyBlocker::cancel (
+ CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -212,13 +214,6 @@ void * dbPutNotifyBlocker::operator new ( size_t size,
return freeList.allocate ( size );
}
-void * dbPutNotifyBlocker::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
#ifdef CXX_PLACEMENT_DELETE
void dbPutNotifyBlocker::operator delete ( void *pCadaver,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
diff --git a/src/db/dbPutNotifyBlocker.h b/src/db/dbPutNotifyBlocker.h
index da2cc9fcb..56d3a37da 100644
--- a/src/db/dbPutNotifyBlocker.h
+++ b/src/db/dbPutNotifyBlocker.h
@@ -42,11 +42,11 @@
class dbPutNotifyBlocker : public dbBaseIO {
public:
dbPutNotifyBlocker ( epicsMutex & );
- void destructor ( epicsGuard < epicsMutex > & );
+ void destructor ( CallbackGuard &, epicsGuard < epicsMutex > & );
void initiatePutNotify ( epicsGuard < epicsMutex > &,
cacWriteNotify &, struct dbAddr &,
unsigned type, unsigned long count, const void * pValue );
- void cancel ( epicsGuard < epicsMutex > & );
+ void cancel ( CallbackGuard &, epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void * operator new ( size_t size,
@@ -82,7 +82,6 @@ private:
dbPutNotifyBlocker ( const dbPutNotifyBlocker & );
dbPutNotifyBlocker & operator = ( const dbPutNotifyBlocker & );
virtual ~dbPutNotifyBlocker ();
- void * operator new ( size_t size );
void operator delete ( void * );
};
diff --git a/src/db/dbSubscriptionIO.cpp b/src/db/dbSubscriptionIO.cpp
index 4fd190d3f..260d26e89 100644
--- a/src/db/dbSubscriptionIO.cpp
+++ b/src/db/dbSubscriptionIO.cpp
@@ -66,13 +66,14 @@ dbSubscriptionIO::~dbSubscriptionIO ()
{
}
-void dbSubscriptionIO::destructor ( epicsGuard < epicsMutex > & guard )
+void dbSubscriptionIO::destructor ( CallbackGuard & cbGuard,
+ epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->~dbSubscriptionIO ();
}
-void dbSubscriptionIO::unsubscribe (
+void dbSubscriptionIO::unsubscribe ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -87,6 +88,7 @@ void dbSubscriptionIO::unsubscribe (
}
void dbSubscriptionIO::channelDeleteException (
+ CallbackGuard &,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
@@ -94,13 +96,6 @@ void dbSubscriptionIO::channelDeleteException (
this->chan.pName(guard), this->type, this->count );
}
-void * dbSubscriptionIO::operator new ( size_t ) // X aCC 361
-{
- // The HPUX compiler seems to require this even though no code
- // calls it directly
- throw std::logic_error ( "why is the compiler calling private operator new" );
-}
-
void dbSubscriptionIO::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
From 7f82c2f32e1b1aca84f57da637d707683851842e Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 28 May 2013 14:16:22 -0500
Subject: [PATCH 12/16] libCom: Added osi/os/WIN32/osdFindSymbol.c
Implemented by Dirk Zimoch.
---
documentation/RELEASE_NOTES.html | 5 +++
src/libCom/osi/os/WIN32/osdFindSymbol.c | 46 +++++++++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 src/libCom/osi/os/WIN32/osdFindSymbol.c
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index d2464baaa..a9698ec90 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,11 @@
+Added osdFindSymbol for Windows
+
+Dirk Zimoch implemented the epicsLoadLibrary(), epicsLoadError() and
+epicsFindSymbol() routines for Windows OS targets.
+
More dbStatic commands accept "" or "*" to mean 'all'
The IOC commands dbDumpRecordType, dbDumpMenu and dbDumpRecord will now
diff --git a/src/libCom/osi/os/WIN32/osdFindSymbol.c b/src/libCom/osi/os/WIN32/osdFindSymbol.c
new file mode 100644
index 000000000..ed2b79c95
--- /dev/null
+++ b/src/libCom/osi/os/WIN32/osdFindSymbol.c
@@ -0,0 +1,46 @@
+/*************************************************************************\
+* Copyright (c) 2013 Dirk Zimoch, PSI
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+/* osi/os/WIN32/epicsFindSymbol.c */
+
+
+#include
+
+#define epicsExportSharedSymbols
+#include "epicsFindSymbol.h"
+
+static int epicsLoadErrorCode = 0;
+
+epicsShareFunc void * epicsLoadLibrary(const char *name)
+{
+ HMODULE lib;
+
+ epicsLoadErrorCode = 0;
+ lib = LoadLibrary(name);
+ if (lib == NULL)
+ {
+ epicsLoadErrorCode = GetLastError();
+ }
+ return lib;
+}
+
+epicsShareFunc const char *epicsLoadError(void)
+{
+ static char buffer[100];
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ epicsLoadErrorCode,
+ 0,
+ buffer,
+ sizeof(buffer)-1, NULL );
+ return buffer;
+}
+
+epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name)
+{
+ return GetProcAddress(0, name);
+}
From ee9c0ba40905ce9da771548b952a659b9e144f68 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Tue, 28 May 2013 15:07:33 -0500
Subject: [PATCH 13/16] ca: Minor reference manual tweaks.
---
src/ca/CAref.html | 72 ++++++++++++++++++++++-------------------------
1 file changed, 34 insertions(+), 38 deletions(-)
diff --git a/src/ca/CAref.html b/src/ca/CAref.html
index 30e8127d4..94f43aed8 100644
--- a/src/ca/CAref.html
+++ b/src/ca/CAref.html
@@ -1938,8 +1938,8 @@ Termination Appear to be Ignored
Short lived CA client applications that issue a CA put request and then
immediately exit the process (return from main or call
exit) may find that there request isn't executed. To guarantee
-that the request is sent call ca_flush followed by
-ca_context_destroy prior to terminating the process.
+that the request is sent call ca_flush_io() followed by
+ca_context_destroy() prior to terminating the process.
@@ -2648,7 +2648,7 @@ get called in the correct order.
resources used by the client library such as sockets and allocated memory are
automatically released by the system when the process exits and
ca_context_destroy() hasn't been called, but on light weight systems such as
-vxWorks or RTEMS no cleanup occurs unless the application call
+vxWorks or RTEMS no cleanup occurs unless the application calls
ca_context_destroy().
Returns
@@ -2661,16 +2661,10 @@ ca_context_destroy().
#include <cadef.h>
-typedef void ( *pCallBack ) (
- struct connection_handler_args );
-int ca_create_channel
-(
- const char *PROCESS_VARIABLE_NAME,
- caCh *USERFUNC,
- void *PUSER,
- capri priority,
- chid *PCHID
-);
+typedef void ( caCh ) (struct connection_handler_args);
+int ca_create_channel (const char *PVNAME,
+ caCh *USERFUNC, void *PUSER,
+ capri PRIORITY, chid *PCHID );
Description
@@ -2719,7 +2713,7 @@ time.
Arguments
- PROCESS_VARIABLE_NAME
+ PVNAME
- A nil terminated process variable name string. EPICS process control
function block database variable names are of the form "<record
name>.<field name>". If the field name and the period separator
@@ -2818,17 +2812,15 @@ subscriptions (monitors) registered with the channel.
#include <cadef.h>
int ca_put ( chtype TYPE,
chid CHID, void *PVALUE );
-int ca_array_put ( chtype TYPE,
- unsigned long COUNT,
+int ca_array_put ( chtype TYPE, unsigned long COUNT,
chid CHID, const void *PVALUE);
-typedef void ( *pCallBack ) (struct event_handler_args );
+typedef void ( caEventCallBackFunc ) (struct event_handler_args);
int ca_put_callback ( chtype TYPE,
chid CHID, const void *PVALUE,
- pCallBack PFUNC, void *USERARG );
-int ca_array_put_callback ( chtype TYPE,
- unsigned long COUNT,
+ caEventCallBackFunc PFUNC, void *USERARG );
+int ca_array_put_callback ( chtype TYPE, unsigned long COUNT,
chid CHID, const void *PVALUE,
- pCallBack PFUNC, void *USERARG );
+ caEventCallBackFunc PFUNC, void *USERARG );
Description
@@ -2948,12 +2940,13 @@ int ca_get ( chtype TYPE,
chid CHID, void *PVALUE );
int ca_array_get ( chtype TYPE, unsigned long COUNT,
chid CHID, void *PVALUE );
-typedef void ( *pCallBack ) (struct event_handler_args );
+typedef void ( caEventCallBackFunc ) (struct event_handler_args);
int ca_get_callback ( chtype TYPE,
- chid CHID, pCallBack USERFUNC, void *USERARG);
+ chid CHID,
+ caEventCallBackFunc USERFUNC, void *USERARG);
int ca_array_get_callback ( chtype TYPE, unsigned long COUNT,
chid CHID,
- pCallBack USERFUNC, void *USERARG );
+ caEventCallBackFunc USERFUNC, void *USERARG);
Description
@@ -3051,11 +3044,10 @@ when a CA get request is initiated.
#include <cadef.h>
-typedef void ( *pCallBack ) (
- struct event_handler_args );
-int ca_create_subscription ( chtype TYPE,
- unsigned long COUNT, chid CHID,
- unsigned long MASK, pCallBack USERFUNC, void *USERARG,
+typedef void ( caEventCallBackFunc ) (struct event_handler_args);
+int ca_create_subscription ( chtype TYPE, unsigned long COUNT,
+ chid CHID, unsigned long MASK,
+ caEventCallBackFunc USERFUNC, void *USERARG,
evid *PEVID );
Description
@@ -3540,7 +3532,7 @@ get the lowest latency response to the arrival of CA messages.
#include <cadef.h>
-typedef int caPrintfFunc ( const char *pFromat, va_list args );
+typedef int caPrintfFunc ( const char *pFormat, va_list args );
int ca_replace_printf_handler ( caPrintfFunc *PFUNC );
Description
@@ -3571,8 +3563,9 @@ SEVCHK ( status, "failed to install my printf handler" );
#include <cadef.h>
-typedef void ( *pCallBack )( struct access_rights_handler_args );
-int ca_replace_access_rights_event ( chid CHAN, pCallBack PFUNC );
+typedef void ( caEventCallBackFunc )(struct access_rights_handler_args);
+int ca_replace_access_rights_event ( chid CHAN,
+ caEventCallBackFunc PFUNC );
Description
@@ -4029,7 +4022,7 @@ SEVCHK ( status, Sync group delete failed );
#include <cadef.h>
-int ca_sg_block ( CA_SYNC_GID GID, double timeout );
+int ca_sg_block ( CA_SYNC_GID GID, double TIMEOUT );
Description
@@ -4050,13 +4043,16 @@ access background activity while it is waiting.
Arguments
- - GID
+ GID
- Identifier of the synchronous group.
+ TIMEOUT
+ - The duration to block in this routine in seconds. A timeout of zero
+ seconds blocks forever.
Examples
CA_SYNC_GID gid;
-status = ca_sg_block(gid);
+status = ca_sg_block(gid, 0.0);
SEVCHK(status, Sync group block failed);
Returns
@@ -4267,8 +4263,8 @@ reissued.
int ca_client_status ( unsigned level );
-int ca_context_status ( struct ca_client_context *,
- unsigned level );
+int ca_context_status ( struct ca_client_context *CONTEXT,
+ unsigned LEVEL );
Description
@@ -4279,7 +4275,7 @@ ca_client_status() prints information about the calling threads CA context.
Arguments
CONTEXT
- - A pointer to the CA context to join with.
+ - A pointer to the CA context to examine.
LEVEL
- The interest level. Increasing level produces increasing detail.
From 863e8fdd3bc199e81512c8113a50848ee01418c5 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 7 Jun 2013 14:35:45 -0500
Subject: [PATCH 14/16] libCom: Fix VxWorks localtime_r() and gmtime_r()
wrappers
Wind River changed the return value between VxWorks 6.8 and 6.9.
---
src/libCom/osi/os/vxWorks/osdTime.cpp | 12 ++++++++----
src/libCom/test/epicsTimeTest.cpp | 20 +++++++++++++-------
2 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/src/libCom/osi/os/vxWorks/osdTime.cpp b/src/libCom/osi/os/vxWorks/osdTime.cpp
index a0e2422e9..eed1ad078 100644
--- a/src/libCom/osi/os/vxWorks/osdTime.cpp
+++ b/src/libCom/osi/os/vxWorks/osdTime.cpp
@@ -67,14 +67,18 @@ void osdNTPReport(void)
}
-// vxWorks localtime_r interface does not match POSIX standards
+// vxWorks localtime_r returns different things in different versions.
+// It can't fail though, so we just ignore the return value.
int epicsTime_localtime(const time_t *clock, struct tm *result)
{
- return localtime_r(clock, result) == OK ? epicsTimeOK : epicsTimeERROR;
+ localtime_r(clock, result);
+ return epicsTimeOK;
}
-// vxWorks gmtime_r interface does not match POSIX standards
+// vxWorks gmtime_r returns different things in different versions.
+// It can't fail though, so we just ignore the return value.
int epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
{
- return gmtime_r(pAnsiTime, pTM) == OK ? epicsTimeOK : epicsTimeERROR;
+ gmtime_r(pAnsiTime, pTM);
+ return epicsTimeOK;
}
diff --git a/src/libCom/test/epicsTimeTest.cpp b/src/libCom/test/epicsTimeTest.cpp
index c89d13a5c..c108eca7f 100644
--- a/src/libCom/test/epicsTimeTest.cpp
+++ b/src/libCom/test/epicsTimeTest.cpp
@@ -48,17 +48,23 @@ MAIN(epicsTimeTest)
const int wasteTime = 100000;
const int nTimes = 10;
- testPlan(16 + nTimes * 18);
+ testPlan(12 + nTimes * 18);
- {
+ try {
const epicsTimeStamp epochTS = {0, 0};
epicsTime epochET = epochTS;
struct gm_tm_nano_sec epicsEpoch = epochET;
- testOk1(epicsEpoch.ansi_tm.tm_sec == 0);
- testOk1(epicsEpoch.ansi_tm.tm_min == 0);
- testOk1(epicsEpoch.ansi_tm.tm_hour == 0);
- testOk1(epicsEpoch.ansi_tm.tm_yday == 0);
- testOk1(epicsEpoch.ansi_tm.tm_year == 90);
+
+ testOk(epicsEpoch.ansi_tm.tm_sec == 0 &&
+ epicsEpoch.ansi_tm.tm_min == 0 &&
+ epicsEpoch.ansi_tm.tm_hour == 0 &&
+ epicsEpoch.ansi_tm.tm_yday == 0 &&
+ epicsEpoch.ansi_tm.tm_year == 90,
+ "epicsTime_gmtime() for EPICS epoch");
+ }
+ catch ( ... ) {
+ testFail("epicsTime_gmtime() failed");
+ testAbort("Can't continue, check your OS!");
}
{ // badNanosecTest
From 93449dccb8a4c0527973e8d684e8762854fe77e3 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 7 Jun 2013 16:08:57 -0500
Subject: [PATCH 15/16] ca: Fix acctst.c for older C compilers
All declarations must still precede other statements within a block...
---
src/ca/acctst.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ca/acctst.c b/src/ca/acctst.c
index a01ee131d..1256c29b6 100644
--- a/src/ca/acctst.c
+++ b/src/ca/acctst.c
@@ -1420,8 +1420,9 @@ static void multiSubscrDestroyNoLateCallbackThread ( void * pParm )
* their first callbacks are running
*/
for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) {
+ epicsMutexLockStatus lockStatus;
SEVCHK ( ca_clear_event ( pTestData->m_eventData[j].m_id ) , NULL );
- epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex );
+ lockStatus = epicsMutexLock ( pTestData->m_mutex );
verify ( lockStatus == epicsMutexLockOK );
pTestData->m_eventData[j].m_callbackIsOk = FALSE;
epicsMutexUnlock ( pTestData->m_mutex );
From ef5d88d3e561f6d1d36e6e3281ef32863e3b8288 Mon Sep 17 00:00:00 2001
From: Andrew Johnson
Date: Fri, 7 Jun 2013 17:03:55 -0500
Subject: [PATCH 16/16] libCom: Back-ported aToIPAddr fix from 3.15 branch.
Cherry-picked 3.15 revno 12398 with some changes.
---
documentation/RELEASE_NOTES.html | 7 ++
src/libCom/misc/aToIPAddr.c | 145 +++++++++----------------
src/libCom/osi/os/vxWorks/osdSock.c | 36 +++---
src/libCom/test/Makefile | 5 +
src/libCom/test/epicsRunLibComTests.c | 3 +
src/libCom/test/epicsSockResolveTest.c | 92 ++++++++++++++++
6 files changed, 173 insertions(+), 115 deletions(-)
create mode 100644 src/libCom/test/epicsSockResolveTest.c
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index a9698ec90..80c2a76e5 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -13,6 +13,13 @@
+Improvements to aToIPAddr()
+
+The libCom routine aToIPAddr() and the vxWorks implementation of the
+associated hostToIPAddr() function have been modified to be able to look up
+hostnames that begin with one or more digits. The epicsSockResolveTest program
+was added to check this functionality.
+
Added osdFindSymbol for Windows
Dirk Zimoch implemented the epicsLoadLibrary(), epicsLoadError() and
diff --git a/src/libCom/misc/aToIPAddr.c b/src/libCom/misc/aToIPAddr.c
index c5d53bc30..04809bffe 100644
--- a/src/libCom/misc/aToIPAddr.c
+++ b/src/libCom/misc/aToIPAddr.c
@@ -1,11 +1,10 @@
/*************************************************************************\
-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* rational replacement for inet_addr()
@@ -13,49 +12,25 @@
* author: Jeff Hill
*/
#include
-#include
-#include
#include
#define epicsExportSharedSymbols
#include "osiSock.h"
-
-#ifndef NELEMENTS
-#define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
-#endif /*NELEMENTS*/
-
-/*
- * addrArrayToUL ()
- */
-static int addrArrayToUL (const unsigned short *pAddr, unsigned nElements, struct in_addr *pIpAddr)
-{
- unsigned i;
- unsigned long addr = 0ul;
-
- for ( i=0u; i < nElements; i++ ) {
- if ( pAddr[i] > 0xff ) {
- return -1;
- }
- addr <<= 8;
- addr |= pAddr[i];
- }
- pIpAddr->s_addr = htonl ( addr );
-
- return 0;
-}
+#include "epicsStdlib.h"
/*
* initIPAddr()
* !! ipAddr should be passed in in network byte order !!
* !! port is passed in in host byte order !!
*/
-static int initIPAddr (struct in_addr ipAddr, unsigned short port, struct sockaddr_in *pIP)
+static int initIPAddr (struct in_addr ipAddr, unsigned short port,
+ struct sockaddr_in *pIP)
{
- memset (pIP, '\0', sizeof(*pIP));
- pIP->sin_family = AF_INET;
- pIP->sin_port = htons(port);
- pIP->sin_addr = ipAddr;
- return 0;
+ memset(pIP, '\0', sizeof(*pIP));
+ pIP->sin_family = AF_INET;
+ pIP->sin_port = htons(port);
+ pIP->sin_addr = ipAddr;
+ return 0;
}
/*
@@ -69,68 +44,46 @@ static int initIPAddr (struct in_addr ipAddr, unsigned short port, struct sockad
* "pAddrString" does not contain an address of the form
* "n.n.n.n:p"
*/
-epicsShareFunc int epicsShareAPI
- aToIPAddr(const char *pAddrString, unsigned short defaultPort, struct sockaddr_in *pIP)
+epicsShareFunc int epicsShareAPI
+aToIPAddr(const char *pAddrString, unsigned short defaultPort,
+ struct sockaddr_in *pIP)
{
- int status;
- unsigned short addr[4];
- unsigned long rawAddr;
- char hostName[512]; /* !! change n elements here requires change in format below !! */
- unsigned short port;
- struct in_addr ina;
+ int status;
+ char hostName[512]; /* !! change n elements here requires change in format below !! */
+ char *endp;
+ unsigned int port;
+ unsigned long numaddr;
+ struct in_addr ina;
- /*
- * dotted ip addresses
- */
- status = sscanf (pAddrString, " %hu.%hu.%hu.%hu:%hu",
- addr, addr+1u, addr+2u, addr+3u, &port);
- if (status>0) {
- if (status>=4) {
- if ( addrArrayToUL ( addr, NELEMENTS ( addr ), &ina ) < 0 ) {
- return -1;
- }
- if (status==4) {
- port = defaultPort;
- }
- return initIPAddr (ina, port, pIP);
- }
- else {
- return -1;
- }
- }
-
- /*
- * IP address as a raw number
- */
- status = sscanf ( pAddrString, " %lu:%hu", &rawAddr, &port );
- if (status>=1) {
- if ( rawAddr > 0xffffffff ) {
- return -1;
- }
- if ( status == 1 ) {
- port = defaultPort;
- }
- ina.s_addr = htonl ( rawAddr );
- return initIPAddr ( ina, port, pIP );
- }
-
- /*
- * check for a valid host name before giving up
- */
- status = sscanf ( pAddrString, " %511[^:]:%hu", hostName, &port );
- if ( status >= 1 ) {
- if ( status == 1 ) {
- port = defaultPort;
- }
- status = hostToIPAddr ( hostName, &ina );
- if ( status == 0 ) {
- return initIPAddr ( ina, port, pIP );
- }
- else {
- return -1;
- }
- }
- else {
+ /*
+ * Scan for a port number
+ */
+ status = sscanf( pAddrString, " %511[^:]:%u", hostName, &port );
+ if ( status == 0 ) {
return -1;
}
+ if ( status == 1 ) {
+ port = defaultPort;
+ }
+ else if (status == 2 && port > 65535) {
+ return -1;
+ }
+
+ /*
+ * Look for a valid host name or dotted quad
+ */
+ status = hostToIPAddr( hostName, &ina );
+ if ( status == 0 ) {
+ return initIPAddr( ina, port, pIP );
+ }
+
+ /*
+ * Try the IP address as a decimal integer
+ */
+ numaddr = strtoul( hostName, &endp, 10 );
+ if (*endp)
+ return -1;
+
+ ina.s_addr = htonl( numaddr );
+ return initIPAddr( ina, port, pIP );
}
diff --git a/src/libCom/osi/os/vxWorks/osdSock.c b/src/libCom/osi/os/vxWorks/osdSock.c
index dd6bab973..13798803b 100644
--- a/src/libCom/osi/os/vxWorks/osdSock.c
+++ b/src/libCom/osi/os/vxWorks/osdSock.c
@@ -27,7 +27,7 @@
int osiSockAttach()
{
- return 1;
+ return 1;
}
void osiSockRelease()
@@ -112,27 +112,25 @@ epicsShareFunc unsigned epicsShareAPI ipAddrToHostName
/*
* hostToIPAddr ()
*/
-epicsShareFunc int epicsShareAPI hostToIPAddr
- (const char *pHostName, struct in_addr *pIPA)
+epicsShareFunc int epicsShareAPI
+hostToIPAddr(const char *pHostName, struct in_addr *pIPA)
{
- int addr;
+ int addr;
- addr = hostGetByName ((char *)pHostName);
- if (addr==ERROR) {
- addr = inet_addr ((char *)pHostName);
- if (addr==ERROR) {
- /*
- * return indicating an error
- */
- return -1;
- }
+ addr = hostGetByName((char *)pHostName);
+ if (addr != ERROR) {
+ pIPA->s_addr = (unsigned long) addr;
+ }
+ else if (inet_aton((char *)pHostName, pIPA) == ERROR) {
+ /*
+ * return indicating an error
+ */
+ return -1;
}
- pIPA->s_addr = (unsigned long) addr;
-
- /*
- * success
- */
- return 0;
+ /*
+ * success
+ */
+ return 0;
}
diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile
index 9bf92f528..ef89f3875 100644
--- a/src/libCom/test/Makefile
+++ b/src/libCom/test/Makefile
@@ -47,6 +47,11 @@ epicsStdioTest_SRCS += epicsStdioTest.c
testHarness_SRCS += epicsStdioTest.c
TESTS += epicsStdioTest
+TESTPROD_HOST += epicsSockResolveTest
+epicsSockResolveTest_SRCS += epicsSockResolveTest.c
+testHarness_SRCS += epicsSockResolveTest.c
+TESTS += epicsSockResolveTest
+
TESTPROD_HOST += epicsStringTest
epicsStringTest_SRCS += epicsStringTest.c
testHarness_SRCS += epicsStringTest.c
diff --git a/src/libCom/test/epicsRunLibComTests.c b/src/libCom/test/epicsRunLibComTests.c
index 80ddbf3b3..7a6da1e66 100644
--- a/src/libCom/test/epicsRunLibComTests.c
+++ b/src/libCom/test/epicsRunLibComTests.c
@@ -38,6 +38,7 @@ int macEnvExpandTest(void);
int ringPointerTest(void);
int ringBytesTest(void);
int blockingSockTest(void);
+int epicsSockResolveTest(void);
int taskwdTest(void);
int epicsExitTest(void);
@@ -94,6 +95,8 @@ void epicsRunLibComTests(void)
runTest(ringBytesTest);
runTest(blockingSockTest);
+
+ runTest(epicsSockResolveTest);
runTest(taskwdTest);
diff --git a/src/libCom/test/epicsSockResolveTest.c b/src/libCom/test/epicsSockResolveTest.c
new file mode 100644
index 000000000..166a29b90
--- /dev/null
+++ b/src/libCom/test/epicsSockResolveTest.c
@@ -0,0 +1,92 @@
+/*************************************************************************\
+* Copyright (c) 2012 Brookhaven Science Associates as Operator of
+* Brookhaven National Lab.
+* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
+* National Laboratory.
+\*************************************************************************/
+
+#include "dbDefs.h"
+#include "osiSock.h"
+
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+#define DEFAULT_PORT 4000
+
+typedef struct {
+ const char *input;
+ unsigned long IP;
+ unsigned short port;
+} testData;
+
+static testData okdata[] = {
+ {"127.0.0.1", 0x7f000001, DEFAULT_PORT},
+ {"127.0.0.1:42", 0x7f000001, 42},
+ {"localhost", 0x7f000001, DEFAULT_PORT},
+ {"localhost:42", 0x7f000001, 42},
+ {"2424", 2424, DEFAULT_PORT},
+ {"2424:42", 2424, 42},
+ {"255.255.255.255", 0xffffffff, DEFAULT_PORT},
+ {"255.255.255.255:65535", 0xffffffff, 65535},
+};
+
+static const char * baddata[] = {
+ "127.0.0.hi",
+ "127.0.0.hi:42",
+ "16invalidhostname",
+ "16invalidhostname:42",
+ "256.255.255.255",
+ "255.256.255.255",
+ "255.255.256.255",
+ "255.255.255.256",
+ "255.255.255.255:65536",
+};
+
+MAIN(epicsSockResolveTest)
+{
+ int i;
+
+ testPlan(3*NELEMENTS(okdata) + NELEMENTS(baddata));
+
+ {
+ struct in_addr addr;
+
+ if (hostToIPAddr("obviously.invalid.host", &addr) == 0) {
+ testAbort("hostToIPAddr() is broken, testing not possible");
+ }
+ }
+
+ testDiag("Tests of aToIPAddr");
+
+ for (i=0; i %d",
+ okdata[i].input, DEFAULT_PORT, ret);
+ if (ret) {
+ testSkip(2, " aToIPAddr() failed");
+ }
+ else {
+ testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP), " IP correct");
+ testOk(addr.sin_port == htons(okdata[i].port), " Port correct");
+ }
+ }
+
+ for (i=0; i %d",
+ baddata[i], DEFAULT_PORT, ret);
+ if (ret==0) {
+ testDiag(" IP=0x%lx, port=%d",
+ (unsigned long) ntohl(addr.sin_addr.s_addr),
+ ntohs(addr.sin_port));
+ }
+ }
+
+ return testDone();
+}