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.

ENOBUFS Messages

@@ -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().

ca_create_channel()

#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.

ca_create_subscription()

#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.

ca_replace_printf_handler ()

#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" );

ca_replace_access_rights_event()

#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 );

ca_sg_block()

#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.

ca_client_status()

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(); +}